# HG changeset patch # User Jaroslav Tulach # Date 1348477658 -7200 # Node ID b9318fe303cd4578519e763f7649651003d41051 # Parent d8807b6a636afeecd9504af21a636a7771a421ea Getting ready for multiple projects inside one Hg repository diff -r d8807b6a636a -r b9318fe303cd nb-configuration.xml --- a/nb-configuration.xml Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ - - - - - - all - - diff -r d8807b6a636a -r b9318fe303cd pom.xml --- a/pom.xml Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ - - 4.0.0 - - org.apidesign - java4browser - 0.1-SNAPSHOT - jar - - java4browser - http://java4browser.apidesign.org - - - UTF-8 - Jaroslav Tulach - jaroslav.tulach@apidesign.org - - - - - netbeans - NetBeans - http://bits.netbeans.org/maven2/ - - - - - mc-release - Local Maven repository of releases - http://mc-repo.googlecode.com/svn/maven2/releases - - false - - - true - - - - - scm:hg:http://source.apidesign.org/hg/quoridor - http://source.apidesign.org/hg/quoridor - - - - GPL-2.0 - http://opensource.org/licenses/GPL-2.0 - repo - - - - API Design - http://apidesign.org - - - - - com.mycila.maven-license-plugin - maven-license-plugin - 1.9.0 - -
src/header.txt
-
-
-
-
- - - org.testng - testng - 6.7 - test - - - junit - junit - - - - - org.netbeans.api - org-netbeans-modules-classfile - RELEASE72 - jar - - -
diff -r d8807b6a636a -r b9318fe303cd src/header.txt --- a/src/header.txt Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -Java 4 Browser Bytecode Translator -Copyright (C) 2012-${year} Jaroslav Tulach - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. Look for COPYING file in the top folder. -If not, see http://opensource.org/licenses/GPL-2.0. diff -r d8807b6a636a -r b9318fe303cd src/main/java/org/apidesign/java4browser/ByteCodeToJavaScript.java --- a/src/main/java/org/apidesign/java4browser/ByteCodeToJavaScript.java Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,793 +0,0 @@ -/* -Java 4 Browser Bytecode Translator -Copyright (C) 2012-2012 Jaroslav Tulach - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. Look for COPYING file in the top folder. -If not, see http://opensource.org/licenses/GPL-2.0. -*/ -package org.apidesign.java4browser; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import static org.netbeans.modules.classfile.ByteCodes.*; -import org.netbeans.modules.classfile.CPClassInfo; -import org.netbeans.modules.classfile.CPEntry; -import org.netbeans.modules.classfile.CPFieldInfo; -import org.netbeans.modules.classfile.CPMethodInfo; -import org.netbeans.modules.classfile.CPStringInfo; -import org.netbeans.modules.classfile.ClassFile; -import org.netbeans.modules.classfile.ClassName; -import org.netbeans.modules.classfile.Code; -import org.netbeans.modules.classfile.Method; -import org.netbeans.modules.classfile.Parameter; -import org.netbeans.modules.classfile.Variable; - -/** Translator of the code inside class files to JavaScript. - * - * @author Jaroslav Tulach - */ -public final class ByteCodeToJavaScript { - private final ClassFile jc; - private final Appendable out; - private final Collection references; - - private ByteCodeToJavaScript( - ClassFile jc, Appendable out, Collection references - ) { - this.jc = jc; - this.out = out; - this.references = references; - } - - /** - * Converts a given class file to a JavaScript version. - * - * @param classFile input stream with code of the .class file - * @param out a {@link StringBuilder} or similar to generate the output to - * @param references a write only collection where the system adds list of - * other classes that were referenced and should be loaded in order the - * generated JavaScript code works properly. The names are in internal - * JVM form so String is java/lang/String. Can be null - * if one is not interested in knowing references - * @throws IOException if something goes wrong during read or write or translating - */ - - public static void compile( - InputStream classFile, Appendable out, - Collection references - ) throws IOException { - ClassFile jc = new ClassFile(classFile, true); - ByteCodeToJavaScript compiler = new ByteCodeToJavaScript( - jc, out, references - ); - List toInitilize = new ArrayList(); - for (Method m : jc.getMethods()) { - if (m.isStatic()) { - compiler.generateStaticMethod(m, toInitilize); - } else { - compiler.generateInstanceMethod(m); - } - } - for (Variable v : jc.getVariables()) { - if (v.isStatic()) { - compiler.generateStaticField(v); - } - } - - final String className = jc.getName().getInternalName().replace('/', '_'); - out.append("\nfunction ").append(className); - out.append("() {"); - for (Method m : jc.getMethods()) { - if (!m.isStatic()) { - compiler.generateMethodReference(m); - } - } - for (Variable v : jc.getVariables()) { - if (!v.isStatic()) { - out.append("\n this." + v.getName() + " = 0;"); - } - } - out.append("\n this.$instOf_").append(className).append(" = true;"); - out.append("\n}"); - ClassName sc = jc.getSuperClass(); - if (sc != null) { - out.append("\n").append(className) - .append(".prototype = new ").append(sc.getInternalName().replace('/', '_')); - } - for (String init : toInitilize) { - out.append("\n").append(init).append("();"); - } - } - private void generateStaticMethod(Method m, List toInitilize) throws IOException { - final String mn = findMethodName(m); - out.append("\nfunction ").append( - jc.getName().getInternalName().replace('/', '_') - ).append('_').append(mn); - if (mn.equals("classV")) { - toInitilize.add(jc.getName().getInternalName().replace('/', '_') + '_' + mn); - } - out.append('('); - String space = ""; - List args = m.getParameters(); - for (int index = 0, i = 0; i < args.size(); i++) { - out.append(space); - out.append("arg").append(String.valueOf(index)); - space = ","; - final String desc = args.get(i).getDescriptor(); - if ("D".equals(desc) || "J".equals(desc)) { - index += 2; - } else { - index++; - } - } - out.append(") {").append("\n"); - final Code code = m.getCode(); - if (code != null) { - int len = code.getMaxLocals(); - for (int index = args.size(), i = args.size(); i < len; i++) { - out.append(" var "); - out.append("arg").append(String.valueOf(i)).append(";\n"); - } - out.append(" var stack = new Array();\n"); - produceCode(code.getByteCodes()); - } else { - out.append(" /* no code found for ").append(m.getTypeSignature()).append(" */\n"); - } - out.append("}"); - } - - private void generateMethodReference(Method m) throws IOException { - final String name = findMethodName(m); - out.append("\n this.").append(name).append(" = ") - .append(jc.getName().getInternalName().replace('/', '_')) - .append('_').append(name).append(";"); - } - - private void generateInstanceMethod(Method m) throws IOException { - out.append("\nfunction ").append( - jc.getName().getInternalName().replace('/', '_') - ).append('_').append(findMethodName(m)); - out.append("(arg0"); - String space = ","; - List args = m.getParameters(); - for (int index = 1, i = 0; i < args.size(); i++) { - out.append(space); - out.append("arg").append(String.valueOf(index)); - final String desc = args.get(i).getDescriptor(); - if ("D".equals(desc) || "J".equals(desc)) { - index += 2; - } else { - index++; - } - } - out.append(") {").append("\n"); - final Code code = m.getCode(); - if (code != null) { - int len = code.getMaxLocals(); - for (int index = args.size(), i = args.size(); i < len; i++) { - out.append(" var "); - out.append("arg").append(String.valueOf(i + 1)).append(";\n"); - } - out.append(";\n var stack = new Array("); - out.append(Integer.toString(code.getMaxStack())); - out.append(");\n"); - produceCode(code.getByteCodes()); - } else { - out.append(" /* no code found for ").append(m.getTypeSignature()).append(" */\n"); - } - out.append("}"); - } - - private void produceCode(byte[] byteCodes) throws IOException { - out.append("\n var gt = 0;\n for(;;) switch(gt) {\n"); - for (int i = 0; i < byteCodes.length; i++) { - int prev = i; - out.append(" case " + i).append(": "); - final int c = (byteCodes[i] + 256) % 256; - switch (c) { - case bc_aload_0: - case bc_iload_0: - case bc_lload_0: - case bc_fload_0: - case bc_dload_0: - out.append("stack.push(arg0);"); - break; - case bc_aload_1: - case bc_iload_1: - case bc_lload_1: - case bc_fload_1: - case bc_dload_1: - out.append("stack.push(arg1);"); - break; - case bc_aload_2: - case bc_iload_2: - case bc_lload_2: - case bc_fload_2: - case bc_dload_2: - out.append("stack.push(arg2);"); - break; - case bc_aload_3: - case bc_iload_3: - case bc_lload_3: - case bc_fload_3: - case bc_dload_3: - out.append("stack.push(arg3);"); - break; - case bc_iload: - case bc_lload: - case bc_fload: - case bc_dload: - case bc_aload: { - final int indx = (byteCodes[++i] + 256) % 256; - out.append("stack.push(arg").append(indx + ");"); - break; - } - case bc_astore_0: - case bc_istore_0: - case bc_lstore_0: - case bc_fstore_0: - case bc_dstore_0: - out.append("arg0 = stack.pop();"); - break; - case bc_astore_1: - case bc_istore_1: - case bc_lstore_1: - case bc_fstore_1: - case bc_dstore_1: - out.append("arg1 = stack.pop();"); - break; - case bc_astore_2: - case bc_istore_2: - case bc_lstore_2: - case bc_fstore_2: - case bc_dstore_2: - out.append("arg2 = stack.pop();"); - break; - case bc_astore_3: - case bc_istore_3: - case bc_lstore_3: - case bc_fstore_3: - case bc_dstore_3: - out.append("arg3 = stack.pop();"); - break; - case bc_iadd: - case bc_ladd: - case bc_fadd: - case bc_dadd: - out.append("stack.push(stack.pop() + stack.pop());"); - break; - case bc_isub: - case bc_lsub: - case bc_fsub: - case bc_dsub: - out.append("{ var tmp = stack.pop(); stack.push(stack.pop() - tmp); }"); - break; - case bc_imul: - case bc_lmul: - case bc_fmul: - case bc_dmul: - out.append("stack.push(stack.pop() * stack.pop());"); - break; - case bc_idiv: - case bc_ldiv: - out.append("{ var tmp = stack.pop(); stack.push(Math.floor(stack.pop() / tmp)); }"); - break; - case bc_fdiv: - case bc_ddiv: - out.append("{ var tmp = stack.pop(); stack.push(stack.pop() / tmp); }"); - break; - case bc_iand: - case bc_land: - out.append("stack.push(stack.pop() & stack.pop());"); - break; - case bc_ior: - case bc_lor: - out.append("stack.push(stack.pop() | stack.pop());"); - break; - case bc_ixor: - case bc_lxor: - out.append("stack.push(stack.pop() ^ stack.pop());"); - break; - case bc_iinc: { - final int varIndx = (byteCodes[++i] + 256) % 256; - final int incrBy = (byteCodes[++i] + 256) % 256; - if (incrBy == 1) { - out.append("arg" + varIndx).append("++;"); - } else { - out.append("arg" + varIndx).append(" += " + incrBy).append(";"); - } - break; - } - case bc_return: - out.append("return;"); - break; - case bc_ireturn: - case bc_lreturn: - case bc_freturn: - case bc_dreturn: - case bc_areturn: - out.append("return stack.pop();"); - break; - case bc_i2l: - case bc_i2f: - case bc_i2d: - case bc_l2i: - // max int check? - case bc_l2f: - case bc_l2d: - case bc_f2d: - case bc_d2f: - out.append("/* number conversion */"); - break; - case bc_f2i: - case bc_f2l: - case bc_d2i: - case bc_d2l: - out.append("stack.push(Math.floor(stack.pop()));"); - break; - case bc_i2b: - case bc_i2c: - case bc_i2s: - out.append("/* number conversion */"); - break; - case bc_iconst_0: - case bc_dconst_0: - case bc_lconst_0: - case bc_fconst_0: - out.append("stack.push(0);"); - break; - case bc_iconst_1: - case bc_lconst_1: - case bc_fconst_1: - case bc_dconst_1: - out.append("stack.push(1);"); - break; - case bc_iconst_2: - case bc_fconst_2: - out.append("stack.push(2);"); - break; - case bc_iconst_3: - out.append("stack.push(3);"); - break; - case bc_iconst_4: - out.append("stack.push(4);"); - break; - case bc_iconst_5: - out.append("stack.push(5);"); - break; - case bc_ldc: { - int indx = byteCodes[++i]; - CPEntry entry = jc.getConstantPool().get(indx); - String v = encodeConstant(entry); - out.append("stack.push(").append(v).append(");"); - break; - } - case bc_ldc_w: - case bc_ldc2_w: { - int indx = readIntArg(byteCodes, i); - CPEntry entry = jc.getConstantPool().get(indx); - i += 2; - String v = encodeConstant(entry); - out.append("stack.push(").append(v).append(");"); - break; - } - case bc_lcmp: - case bc_fcmpl: - case bc_fcmpg: - case bc_dcmpl: - case bc_dcmpg: { - out.append("{ var delta = stack.pop() - stack.pop(); stack.push(delta < 0 ?-1 : (delta == 0 ? 0 : 1)); }"); - break; - } - case bc_if_icmpeq: { - i = generateIf(byteCodes, i, "=="); - break; - } - case bc_ifeq: { - int indx = i + readIntArg(byteCodes, i); - out.append("if (stack.pop() == 0) { gt = " + indx); - out.append("; continue; }"); - i += 2; - break; - } - case bc_ifne: { - int indx = i + readIntArg(byteCodes, i); - out.append("if (stack.pop() != 0) { gt = " + indx); - out.append("; continue; }"); - i += 2; - break; - } - case bc_iflt: { - int indx = i + readIntArg(byteCodes, i); - out.append("if (stack.pop() < 0) { gt = " + indx); - out.append("; continue; }"); - i += 2; - break; - } - case bc_ifle: { - int indx = i + readIntArg(byteCodes, i); - out.append("if (stack.pop() <= 0) { gt = " + indx); - out.append("; continue; }"); - i += 2; - break; - } - case bc_ifgt: { - int indx = i + readIntArg(byteCodes, i); - out.append("if (stack.pop() > 0) { gt = " + indx); - out.append("; continue; }"); - i += 2; - break; - } - case bc_ifge: { - int indx = i + readIntArg(byteCodes, i); - out.append("if (stack.pop() >= 0) { gt = " + indx); - out.append("; continue; }"); - i += 2; - break; - } - case bc_ifnonnull: { - int indx = i + readIntArg(byteCodes, i); - out.append("if (stack.pop()) { gt = " + indx); - out.append("; continue; }"); - i += 2; - break; - } - case bc_ifnull: { - int indx = i + readIntArg(byteCodes, i); - out.append("if (!stack.pop()) { gt = " + indx); - out.append("; continue; }"); - i += 2; - break; - } - case bc_if_icmpne: - i = generateIf(byteCodes, i, "!="); - break; - case bc_if_icmplt: - i = generateIf(byteCodes, i, ">"); - break; - case bc_if_icmple: - i = generateIf(byteCodes, i, ">="); - break; - case bc_if_icmpgt: - i = generateIf(byteCodes, i, "<"); - break; - case bc_if_icmpge: - i = generateIf(byteCodes, i, "<="); - break; - case bc_goto: { - int indx = i + readIntArg(byteCodes, i); - out.append("gt = " + indx).append("; continue;"); - i += 2; - break; - } - case bc_invokeinterface: - case bc_invokevirtual: - i = invokeVirtualMethod(byteCodes, i); - break; - case bc_invokespecial: - i = invokeStaticMethod(byteCodes, i, false); - break; - case bc_invokestatic: - i = invokeStaticMethod(byteCodes, i, true); - break; - case bc_new: { - int indx = readIntArg(byteCodes, i); - CPClassInfo ci = jc.getConstantPool().getClass(indx); - out.append("stack.push("); - out.append("new ").append(ci.getClassName().getInternalName().replace('/','_')); - out.append(");"); - addReference(ci.getClassName().getInternalName()); - i += 2; - break; - } - case bc_newarray: { - int type = byteCodes[i++]; - out.append("stack.push(new Array(stack.pop()));"); - break; - } - case bc_anewarray: { - i += 2; // skip type of array - out.append("stack.push(new Array(stack.pop()));"); - break; - } - case bc_arraylength: - out.append("stack.push(stack.pop().length);"); - break; - case bc_iastore: - case bc_lastore: - case bc_fastore: - case bc_dastore: - case bc_aastore: - case bc_bastore: - case bc_castore: - case bc_sastore: { - out.append("{ var value = stack.pop(); var indx = stack.pop(); stack.pop()[indx] = value; }"); - break; - } - case bc_iaload: - case bc_laload: - case bc_faload: - case bc_daload: - case bc_aaload: - case bc_baload: - case bc_caload: - case bc_saload: { - out.append("{ var indx = stack.pop(); stack.push(stack.pop()[indx]); }"); - break; - } - case bc_dup: - out.append("stack.push(stack[stack.length - 1]);"); - break; - case bc_bipush: - out.append("stack.push(" + byteCodes[++i] + ");"); - break; - case bc_getfield: { - int indx = readIntArg(byteCodes, i); - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); - out.append("stack.push(stack.pop().").append(fi.getFieldName()).append(");"); - i += 2; - break; - } - case bc_getstatic: { - int indx = readIntArg(byteCodes, i); - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); - final String in = fi.getClassName().getInternalName(); - out.append("stack.push(").append(in.replace('/', '_')); - out.append('_').append(fi.getFieldName()).append(");"); - i += 2; - addReference(in); - break; - } - case bc_putstatic: { - int indx = readIntArg(byteCodes, i); - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); - final String in = fi.getClassName().getInternalName(); - out.append(in.replace('/', '_')); - out.append('_').append(fi.getFieldName()).append(" = stack.pop();"); - i += 2; - addReference(in); - break; - } - case bc_putfield: { - int indx = readIntArg(byteCodes, i); - CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); - out.append("{ var v = stack.pop(); stack.pop().") - .append(fi.getFieldName()).append(" = v; }"); - i += 2; - break; - } - case bc_instanceof: { - int indx = readIntArg(byteCodes, i); - CPClassInfo ci = jc.getConstantPool().getClass(indx); - out.append("stack.push(stack.pop().$instOf_") - .append(ci.getClassName().getInternalName().replace('/', '_')) - .append(" ? 1 : 0);"); - i += 2; - } - - } - out.append(" /*"); - for (int j = prev; j <= i; j++) { - out.append(" "); - final int cc = (byteCodes[j] + 256) % 256; - out.append(Integer.toString(cc)); - } - out.append("*/\n"); - } - out.append(" }\n"); - } - - private int generateIf(byte[] byteCodes, int i, final String test) throws IOException { - int indx = i + readIntArg(byteCodes, i); - out.append("if (stack.pop() ").append(test).append(" stack.pop()) { gt = " + indx); - out.append("; continue; }"); - return i + 2; - } - - private int readIntArg(byte[] byteCodes, int offsetInstruction) { - final int indxHi = byteCodes[offsetInstruction + 1] << 8; - final int indxLo = byteCodes[offsetInstruction + 2]; - return (indxHi & 0xffffff00) | (indxLo & 0xff); - } - - private static int countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig) { - int cnt = 0; - int i = 0; - Boolean count = null; - int firstPos = sig.length(); - while (i < descriptor.length()) { - char ch = descriptor.charAt(i++); - switch (ch) { - case '(': - count = true; - continue; - case ')': - count = false; - continue; - case 'B': - case 'C': - case 'D': - case 'F': - case 'I': - case 'J': - case 'S': - case 'Z': - if (count) { - cnt++; - sig.append(ch); - } else { - hasReturnType[0] = true; - sig.insert(firstPos, ch); - } - continue; - case 'V': - assert !count; - hasReturnType[0] = false; - sig.insert(firstPos, 'V'); - continue; - case 'L': - int next = descriptor.indexOf(';', i); - if (count) { - cnt++; - sig.append(ch); - sig.append(descriptor.substring(i, next).replace('/', '_')); - } else { - sig.insert(firstPos, descriptor.substring(i, next).replace('/', '_')); - sig.insert(firstPos, ch); - hasReturnType[0] = true; - } - i = next + 1; - continue; - case '[': - //arrays++; - continue; - default: - break; // invalid character - } - } - return cnt; - } - - private void generateStaticField(Variable v) throws IOException { - out.append("\nvar ") - .append(jc.getName().getInternalName().replace('/', '_')) - .append('_').append(v.getName()).append(" = 0;"); - } - - private String findMethodName(Method m) { - StringBuilder tmp = new StringBuilder(); - if ("".equals(m.getName())) { // NOI18N - tmp.append("consV"); // NOI18N - } else if ("".equals(m.getName())) { // NOI18N - tmp.append("classV"); // NOI18N - } else { - tmp.append(m.getName()); - outType(m.getReturnType(), tmp); - } - List args = m.getParameters(); - for (Parameter t : args) { - outType(t.getDescriptor(), tmp); - } - return tmp.toString(); - } - - private String findMethodName(CPMethodInfo mi, int[] cnt, boolean[] hasReturn) { - StringBuilder name = new StringBuilder(); - if ("".equals(mi.getName())) { // NOI18N - name.append("cons"); // NOI18N - } else { - name.append(mi.getName()); - } - cnt[0] = countArgs(mi.getDescriptor(), hasReturn, name); - return name.toString(); - } - - private int invokeStaticMethod(byte[] byteCodes, int i, boolean isStatic) - throws IOException { - int methodIndex = readIntArg(byteCodes, i); - CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex); - boolean[] hasReturn = { false }; - int[] cnt = { 0 }; - String mn = findMethodName(mi, cnt, hasReturn); - out.append("{ "); - for (int j = cnt[0] - 1; j >= 0; j--) { - out.append("var v" + j).append(" = stack.pop(); "); - } - - if (hasReturn[0]) { - out.append("stack.push("); - } - final String in = mi.getClassName().getInternalName(); - out.append(in.replace('/', '_')); - out.append('_'); - out.append(mn); - out.append('('); - String sep = ""; - if (!isStatic) { - out.append("stack.pop()"); - sep = ", "; - } - for (int j = 0; j < cnt[0]; j++) { - out.append(sep); - out.append("v" + j); - sep = ", "; - } - out.append(")"); - if (hasReturn[0]) { - out.append(")"); - } - out.append("; }"); - i += 2; - addReference(in); - return i; - } - private int invokeVirtualMethod(byte[] byteCodes, int i) - throws IOException { - int methodIndex = readIntArg(byteCodes, i); - CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex); - boolean[] hasReturn = { false }; - int[] cnt = { 0 }; - String mn = findMethodName(mi, cnt, hasReturn); - out.append("{ "); - for (int j = cnt[0] - 1; j >= 0; j--) { - out.append("var v" + j).append(" = stack.pop(); "); - } - out.append("var self = stack.pop(); "); - if (hasReturn[0]) { - out.append("stack.push("); - } - out.append("self."); - out.append(mn); - out.append('('); - out.append("self"); - for (int j = 0; j < cnt[0]; j++) { - out.append(", "); - out.append("v" + j); - } - out.append(")"); - if (hasReturn[0]) { - out.append(")"); - } - out.append("; }"); - i += 2; - return i; - } - - private void addReference(String cn) { - if (references != null) { - references.add(cn); - } - } - - private void outType(final String d, StringBuilder out) { - if (d.charAt(0) == 'L') { - assert d.charAt(d.length() - 1) == ';'; - out.append(d.replace('/', '_').substring(0, d.length() - 1)); - } else { - out.append(d); - } - } - - private String encodeConstant(CPEntry entry) { - final String v; - if (entry instanceof CPStringInfo) { - v = "\"" + entry.getValue().toString().replace("\"", "\\\"") + "\""; - } else { - v = entry.getValue().toString(); - } - return v; - } -} diff -r d8807b6a636a -r b9318fe303cd src/test/java/org/apidesign/java4browser/Array.java --- a/src/test/java/org/apidesign/java4browser/Array.java Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* -Java 4 Browser Bytecode Translator -Copyright (C) 2012-2012 Jaroslav Tulach - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. Look for COPYING file in the top folder. -If not, see http://opensource.org/licenses/GPL-2.0. -*/ -package org.apidesign.java4browser; - -/** - * - * @author Jaroslav Tulach - */ -public class Array { - byte[] bytes = { 1 }; - short[] shorts = { 2, 3 }; - int[] ints = { 4, 5, 6 }; - float[] floats = { 7, 8, 9, 10 }; - double[][] doubles = { {11}, {12}, {13}, {14}, {15} }; - char[] chars = { 'a', 'b' }; - - private Array() { - } - - byte bytes() { - return bytes[0]; - } - short shorts() { - return shorts[1]; - } - - int ints() { - return ints[2]; - } - - float floats() { - return floats[3]; - } - - double doubles() { - return doubles[4][0]; - } - - private static final Array[] ARR = { new Array(), new Array(), new Array() }; - - public static double sum() { - double sum = 0.0; - for (int i = 0; i < ARR.length; i++) { - sum += ARR[i].bytes(); - sum += ARR[i].shorts(); - sum += ARR[i].ints(); - sum += ARR[i].floats(); - sum += ARR[i].doubles(); - } - return sum; - } - public static int simple() { - int[] arr = { 0, 1, 2, 3, 4, 5 }; - - int sum = 0; - for (int i = 0; i < arr.length; i++) { - sum += arr[i]; - } - return sum; - } -} diff -r d8807b6a636a -r b9318fe303cd src/test/java/org/apidesign/java4browser/ArrayTest.java --- a/src/test/java/org/apidesign/java4browser/ArrayTest.java Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* -Java 4 Browser Bytecode Translator -Copyright (C) 2012-2012 Jaroslav Tulach - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. Look for COPYING file in the top folder. -If not, see http://opensource.org/licenses/GPL-2.0. -*/ -package org.apidesign.java4browser; - -import javax.script.Invocable; -import javax.script.ScriptException; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/** - * - * @author Jaroslav Tulach - */ -public class ArrayTest { - @Test public void verifySimpleIntOperation() throws Exception { - assertExec("CheckTheSum", "org_apidesign_java4browser_Array_simpleI", - Double.valueOf(15) - ); - } - @Test public void verifyOperationsOnArrays() throws Exception { - assertExec("The sum is 105", "org_apidesign_java4browser_Array_sumD", - Double.valueOf(105) - ); - } - - private static void assertExec(String msg, String methodName, Object expRes, Object... args) throws Exception { - StringBuilder sb = new StringBuilder(); - Invocable i = StaticMethodTest.compileClass(sb, - "org/apidesign/java4browser/Array" - ); - - Object ret = null; - try { - ret = i.invokeFunction(methodName, args); - } catch (ScriptException ex) { - fail("Execution failed in " + sb, ex); - } catch (NoSuchMethodException ex) { - fail("Cannot find method in " + sb, ex); - } - if (ret == null && expRes == null) { - return; - } - if (expRes.equals(ret)) { - return; - } - assertEquals(ret, expRes, msg + "was: " + ret + "\n" + sb); - } -} diff -r d8807b6a636a -r b9318fe303cd src/test/java/org/apidesign/java4browser/GetByte.java --- a/src/test/java/org/apidesign/java4browser/GetByte.java Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.apidesign.java4browser; - -public interface GetByte { - public byte getByte(); -} diff -r d8807b6a636a -r b9318fe303cd src/test/java/org/apidesign/java4browser/Instance.java --- a/src/test/java/org/apidesign/java4browser/Instance.java Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.apidesign.java4browser; - -/** - * - * @author Jaroslav Tulach - */ -public class Instance { - private int i; - protected short s; - public double d; - private float f; - protected byte b = (byte)31; - - private Instance() { - } - - public Instance(int i, double d) { - this.i = i; - this.d = d; - } - public byte getByte() { - return b; - } - - public void setByte(byte b) { - this.b = b; - } - public static double defaultDblValue() { - Instance create = new Instance(); - return create.d; - } - - public static byte assignedByteValue() { - return new Instance().b; - } - public static double magicOne() { - Instance i = new Instance(10, 3.3d); - i.b = (byte)0x09; - return (i.i - i.b) * i.d; - } - public static int virtualBytes() { - Instance i = new InstanceSub(7, 2.2d); - i.setByte((byte)0x0a); - Instance i2 = new Instance(3, 333.0d); - i2.setByte((byte)44); - return i.getByte() + i2.getByte(); - } - public static float interfaceBytes() { - GetByte i = new InstanceSub(7, 2.2d); - return i.getByte(); - } - public static boolean instanceOf(boolean sub) { - Instance i = createInstance(sub); - return isInstanceSubOf(i); - } - private static boolean isInstanceSubOf(Instance instance) { - return instance instanceof InstanceSub; - } - private static Instance createInstance(boolean sub) { - return sub ? new InstanceSub(3, 0) : new Instance(); - } - private static boolean isNull() { - return createInstance(true) == null; - } -} diff -r d8807b6a636a -r b9318fe303cd src/test/java/org/apidesign/java4browser/InstanceSub.java --- a/src/test/java/org/apidesign/java4browser/InstanceSub.java Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.apidesign.java4browser; - -/** - * - * @author Jaroslav Tulach - */ -public class InstanceSub extends Instance implements GetByte { - public InstanceSub(int i, double d) { - super(i, d); - } - - @Override - public void setByte(byte b) { - super.setByte((byte) (b + 1)); - } -} diff -r d8807b6a636a -r b9318fe303cd src/test/java/org/apidesign/java4browser/InstanceTest.java --- a/src/test/java/org/apidesign/java4browser/InstanceTest.java Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.apidesign.java4browser; - -import javax.script.Invocable; -import javax.script.ScriptException; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/** - * - * @author Jaroslav Tulach - */ -public class InstanceTest { - @Test public void verifyDefaultDoubleValue() throws Exception { - assertExec( - "Will be zero", - "org_apidesign_java4browser_Instance_defaultDblValueD", - Double.valueOf(0) - ); - } - @Test public void verifyAssignedByteValue() throws Exception { - assertExec( - "Will one thirty one", - "org_apidesign_java4browser_Instance_assignedByteValueB", - Double.valueOf(31) - ); - } - @Test public void verifyMagicOne() throws Exception { - assertExec( - "Should be three and something", - "org_apidesign_java4browser_Instance_magicOneD", - Double.valueOf(3.3) - ); - } - @Test public void verifyInstanceMethods() throws Exception { - assertExec( - "Should be eleven as we invoke overwritten method, plus 44", - "org_apidesign_java4browser_Instance_virtualBytesI", - Double.valueOf(55) - ); - } - @Test public void verifyInterfaceMethods() throws Exception { - assertExec( - "Retruns default value", - "org_apidesign_java4browser_Instance_interfaceBytesF", - Double.valueOf(31) - ); - } - - @Test public void isNull() throws Exception { - assertExec( - "Yes, we are instance", - "org_apidesign_java4browser_Instance_isNullZ", - Double.valueOf(0.0) - ); - } - - @Test public void isInstanceOf() throws Exception { - assertExec( - "Yes, we are instance", - "org_apidesign_java4browser_Instance_instanceOfZZ", - Double.valueOf(1.0), true - ); - } - - @Test public void notInstanceOf() throws Exception { - assertExec( - "No, we are not an instance", - "org_apidesign_java4browser_Instance_instanceOfZZ", - Double.valueOf(0.0), false - ); - } - - private static void assertExec(String msg, String methodName, Object expRes, Object... args) throws Exception { - StringBuilder sb = new StringBuilder(); - Invocable i = StaticMethodTest.compileClass(sb, - "org/apidesign/java4browser/Instance" - ); - - Object ret = null; - try { - ret = i.invokeFunction(methodName, args); - } catch (ScriptException ex) { - fail("Execution failed in " + sb, ex); - } catch (NoSuchMethodException ex) { - fail("Cannot find method in " + sb, ex); - } - if (ret == null && expRes == null) { - return; - } - if (expRes.equals(ret)) { - return; - } - assertEquals(ret, expRes, msg + "was: " + ret + "\n" + sb); - - } - -} diff -r d8807b6a636a -r b9318fe303cd src/test/java/org/apidesign/java4browser/StaticMethod.java --- a/src/test/java/org/apidesign/java4browser/StaticMethod.java Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* -Java 4 Browser Bytecode Translator -Copyright (C) 2012-2012 Jaroslav Tulach - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. Look for COPYING file in the top folder. -If not, see http://opensource.org/licenses/GPL-2.0. -*/ -package org.apidesign.java4browser; - -/** - * - * @author Jaroslav Tulach - */ -public class StaticMethod { - private static int cnt; - - public static int sum(int x, int y) { - return x + y; - } - public static float power(float x) { - return x * x; - } - public static double minus(double x, long y) { - return x - y; - } - public static int div(byte c, double d) { - return (int)(d / c); - } - public static int mix(int a, long b, byte c, double d) { - return (int)((b / a + c) * d); - } - public static long xor(int a, long b) { - return a ^ b; - } - public static long orOrAnd(boolean doOr, int a, int b) { - return doOr ? a | b : a & b; - } - public static long factRec(int n) { - if (n <= 1) { - return 1; - } else { - return n * factRec(n - 1); - } - } - public static long factIter(int n) { - long res = 1; - for (int i = 2; i <= n; i++) { - res *= i; - } - return res; - } - public static int inc4() { - cnt++; - cnt+=2; - cnt++; - return cnt; - } -} diff -r d8807b6a636a -r b9318fe303cd src/test/java/org/apidesign/java4browser/StaticMethodTest.java --- a/src/test/java/org/apidesign/java4browser/StaticMethodTest.java Mon Sep 24 09:35:00 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/* -Java 4 Browser Bytecode Translator -Copyright (C) 2012-2012 Jaroslav Tulach - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. Look for COPYING file in the top folder. -If not, see http://opensource.org/licenses/GPL-2.0. -*/ -package org.apidesign.java4browser; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Set; -import java.util.TreeSet; -import javax.script.Invocable; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; -import static org.testng.Assert.*; -import org.testng.annotations.Test; - -/** Checks the basic behavior of the translator. - * - * @author Jaroslav Tulach - */ -public class StaticMethodTest { - @Test public void threePlusFour() throws Exception { - assertExec( - "Should be seven", - "org_apidesign_java4browser_StaticMethod_sumIII", - Double.valueOf(7), - 3, 4 - ); - } - - @Test public void powerOfThree() throws Exception { - assertExec( - "Should be nine", - "org_apidesign_java4browser_StaticMethod_powerFF", - Double.valueOf(9), - 3.0f - ); - } - - @Test public void doubleWithoutLong() throws Exception { - assertExec( - "Should be two", - "org_apidesign_java4browser_StaticMethod_minusDDJ", - Double.valueOf(2), - 3.0d, 1l - ); - } - - @Test public void divAndRound() throws Exception { - assertExec( - "Should be rounded to one", - "org_apidesign_java4browser_StaticMethod_divIBD", - Double.valueOf(1), - 3, 3.75 - ); - } - @Test public void mixedMethodFourParams() throws Exception { - assertExec( - "Should be two", - "org_apidesign_java4browser_StaticMethod_mixIIJBD", - Double.valueOf(20), - 2, 10l, 5, 2.0 - ); - } - @Test public void factRec() throws Exception { - assertExec( - "Factorial of 5 is 120", - "org_apidesign_java4browser_StaticMethod_factRecJI", - Double.valueOf(120), - 5 - ); - } - @Test public void factIter() throws Exception { - assertExec( - "Factorial of 5 is 120", - "org_apidesign_java4browser_StaticMethod_factIterJI", - Double.valueOf(120), - 5 - ); - } - - @Test public void xor() throws Exception { - assertExec( - "Xor is 4", - "org_apidesign_java4browser_StaticMethod_xorJIJ", - Double.valueOf(4), - 7, - 3 - ); - } - - @Test public void or() throws Exception { - assertExec( - "Or will be 7", - "org_apidesign_java4browser_StaticMethod_orOrAndJZII", - Double.valueOf(7), - true, - 4, - 3 - ); - } - @Test public void and() throws Exception { - assertExec( - "And will be 3", - "org_apidesign_java4browser_StaticMethod_orOrAndJZII", - Double.valueOf(3), - false, - 7, - 3 - ); - } - @Test public void inc4() throws Exception { - assertExec( - "It will be 4", - "org_apidesign_java4browser_StaticMethod_inc4I", - Double.valueOf(4) - ); - } - - private static void assertExec(String msg, String methodName, Object expRes, Object... args) throws Exception { - StringBuilder sb = new StringBuilder(); - Invocable i = compileClass(sb, "org/apidesign/java4browser/StaticMethod"); - - Object ret = null; - try { - ret = i.invokeFunction(methodName, args); - } catch (ScriptException ex) { - fail("Execution failed in " + sb, ex); - } catch (NoSuchMethodException ex) { - fail("Cannot find method in " + sb, ex); - } - if (ret == null && expRes == null) { - return; - } - if (expRes.equals(ret)) { - return; - } - assertEquals(ret, expRes, msg + "was: " + ret + "\n" + sb); - - } - - static Invocable compileClass(StringBuilder sb, String... names) throws ScriptException, IOException { - if (sb == null) { - sb = new StringBuilder(); - } - Set processed = new HashSet(); - - LinkedList toProcess = new LinkedList(Arrays.asList(names)); - for (;;) { - toProcess.removeAll(processed); - if (toProcess.isEmpty()) { - break; - } - String name = toProcess.getFirst(); - processed.add(name); - if (name.startsWith("java/") && !name.equals("java/lang/Object")) { - continue; - } - InputStream is = StaticMethodTest.class.getClassLoader().getResourceAsStream(name + ".class"); - assertNotNull(is, "Class file found"); - try { - ByteCodeToJavaScript.compile(is, sb, toProcess); - } catch (RuntimeException ex) { - int lastBlock = sb.lastIndexOf("{"); - throw new IllegalStateException( - "Error while compiling " + name + "\n" + - sb.substring(0, sb.length()), - ex - ); - } - } - ScriptEngineManager sem = new ScriptEngineManager(); - ScriptEngine js = sem.getEngineByExtension("js"); - try { - Object res = js.eval(sb.toString()); - assertTrue(js instanceof Invocable, "It is invocable object: " + res); - return (Invocable)js; - } catch (ScriptException ex) { - fail("Could not compile:\n" + sb, ex); - return null; - } - } -} diff -r d8807b6a636a -r b9318fe303cd vm/nb-configuration.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/nb-configuration.xml Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,18 @@ + + + + + + all + + diff -r d8807b6a636a -r b9318fe303cd vm/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/pom.xml Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,75 @@ + + 4.0.0 + + org.apidesign + vm4brwsr + 0.1-SNAPSHOT + jar + + Java VM for Browser + http://bck2brwsr.apidesign.org + + + UTF-8 + Jaroslav Tulach + jaroslav.tulach@apidesign.org + + + + + netbeans + NetBeans + http://bits.netbeans.org/maven2/ + + + + + mc-release + Local Maven repository of releases + http://mc-repo.googlecode.com/svn/maven2/releases + + false + + + true + + + + + scm:hg:http://source.apidesign.org/hg/bck2brwsr + http://source.apidesign.org/hg/bck2brwsr + + + + + com.mycila.maven-license-plugin + maven-license-plugin + 1.9.0 + +
src/header.txt
+
+
+
+
+ + + org.testng + testng + 6.7 + test + + + junit + junit + + + + + org.netbeans.api + org-netbeans-modules-classfile + RELEASE72 + jar + + +
diff -r d8807b6a636a -r b9318fe303cd vm/src/header.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/header.txt Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,15 @@ +Java 4 Browser Bytecode Translator +Copyright (C) 2012-${year} Jaroslav Tulach + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. Look for COPYING file in the top folder. +If not, see http://opensource.org/licenses/GPL-2.0. diff -r d8807b6a636a -r b9318fe303cd vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,793 @@ +/* +Java 4 Browser Bytecode Translator +Copyright (C) 2012-2012 Jaroslav Tulach + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. Look for COPYING file in the top folder. +If not, see http://opensource.org/licenses/GPL-2.0. +*/ +package org.apidesign.vm4brwsr; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import static org.netbeans.modules.classfile.ByteCodes.*; +import org.netbeans.modules.classfile.CPClassInfo; +import org.netbeans.modules.classfile.CPEntry; +import org.netbeans.modules.classfile.CPFieldInfo; +import org.netbeans.modules.classfile.CPMethodInfo; +import org.netbeans.modules.classfile.CPStringInfo; +import org.netbeans.modules.classfile.ClassFile; +import org.netbeans.modules.classfile.ClassName; +import org.netbeans.modules.classfile.Code; +import org.netbeans.modules.classfile.Method; +import org.netbeans.modules.classfile.Parameter; +import org.netbeans.modules.classfile.Variable; + +/** Translator of the code inside class files to JavaScript. + * + * @author Jaroslav Tulach + */ +public final class ByteCodeToJavaScript { + private final ClassFile jc; + private final Appendable out; + private final Collection references; + + private ByteCodeToJavaScript( + ClassFile jc, Appendable out, Collection references + ) { + this.jc = jc; + this.out = out; + this.references = references; + } + + /** + * Converts a given class file to a JavaScript version. + * + * @param classFile input stream with code of the .class file + * @param out a {@link StringBuilder} or similar to generate the output to + * @param references a write only collection where the system adds list of + * other classes that were referenced and should be loaded in order the + * generated JavaScript code works properly. The names are in internal + * JVM form so String is java/lang/String. Can be null + * if one is not interested in knowing references + * @throws IOException if something goes wrong during read or write or translating + */ + + public static void compile( + InputStream classFile, Appendable out, + Collection references + ) throws IOException { + ClassFile jc = new ClassFile(classFile, true); + ByteCodeToJavaScript compiler = new ByteCodeToJavaScript( + jc, out, references + ); + List toInitilize = new ArrayList(); + for (Method m : jc.getMethods()) { + if (m.isStatic()) { + compiler.generateStaticMethod(m, toInitilize); + } else { + compiler.generateInstanceMethod(m); + } + } + for (Variable v : jc.getVariables()) { + if (v.isStatic()) { + compiler.generateStaticField(v); + } + } + + final String className = jc.getName().getInternalName().replace('/', '_'); + out.append("\nfunction ").append(className); + out.append("() {"); + for (Method m : jc.getMethods()) { + if (!m.isStatic()) { + compiler.generateMethodReference(m); + } + } + for (Variable v : jc.getVariables()) { + if (!v.isStatic()) { + out.append("\n this." + v.getName() + " = 0;"); + } + } + out.append("\n this.$instOf_").append(className).append(" = true;"); + out.append("\n}"); + ClassName sc = jc.getSuperClass(); + if (sc != null) { + out.append("\n").append(className) + .append(".prototype = new ").append(sc.getInternalName().replace('/', '_')); + } + for (String init : toInitilize) { + out.append("\n").append(init).append("();"); + } + } + private void generateStaticMethod(Method m, List toInitilize) throws IOException { + final String mn = findMethodName(m); + out.append("\nfunction ").append( + jc.getName().getInternalName().replace('/', '_') + ).append('_').append(mn); + if (mn.equals("classV")) { + toInitilize.add(jc.getName().getInternalName().replace('/', '_') + '_' + mn); + } + out.append('('); + String space = ""; + List args = m.getParameters(); + for (int index = 0, i = 0; i < args.size(); i++) { + out.append(space); + out.append("arg").append(String.valueOf(index)); + space = ","; + final String desc = args.get(i).getDescriptor(); + if ("D".equals(desc) || "J".equals(desc)) { + index += 2; + } else { + index++; + } + } + out.append(") {").append("\n"); + final Code code = m.getCode(); + if (code != null) { + int len = code.getMaxLocals(); + for (int index = args.size(), i = args.size(); i < len; i++) { + out.append(" var "); + out.append("arg").append(String.valueOf(i)).append(";\n"); + } + out.append(" var stack = new Array();\n"); + produceCode(code.getByteCodes()); + } else { + out.append(" /* no code found for ").append(m.getTypeSignature()).append(" */\n"); + } + out.append("}"); + } + + private void generateMethodReference(Method m) throws IOException { + final String name = findMethodName(m); + out.append("\n this.").append(name).append(" = ") + .append(jc.getName().getInternalName().replace('/', '_')) + .append('_').append(name).append(";"); + } + + private void generateInstanceMethod(Method m) throws IOException { + out.append("\nfunction ").append( + jc.getName().getInternalName().replace('/', '_') + ).append('_').append(findMethodName(m)); + out.append("(arg0"); + String space = ","; + List args = m.getParameters(); + for (int index = 1, i = 0; i < args.size(); i++) { + out.append(space); + out.append("arg").append(String.valueOf(index)); + final String desc = args.get(i).getDescriptor(); + if ("D".equals(desc) || "J".equals(desc)) { + index += 2; + } else { + index++; + } + } + out.append(") {").append("\n"); + final Code code = m.getCode(); + if (code != null) { + int len = code.getMaxLocals(); + for (int index = args.size(), i = args.size(); i < len; i++) { + out.append(" var "); + out.append("arg").append(String.valueOf(i + 1)).append(";\n"); + } + out.append(";\n var stack = new Array("); + out.append(Integer.toString(code.getMaxStack())); + out.append(");\n"); + produceCode(code.getByteCodes()); + } else { + out.append(" /* no code found for ").append(m.getTypeSignature()).append(" */\n"); + } + out.append("}"); + } + + private void produceCode(byte[] byteCodes) throws IOException { + out.append("\n var gt = 0;\n for(;;) switch(gt) {\n"); + for (int i = 0; i < byteCodes.length; i++) { + int prev = i; + out.append(" case " + i).append(": "); + final int c = (byteCodes[i] + 256) % 256; + switch (c) { + case bc_aload_0: + case bc_iload_0: + case bc_lload_0: + case bc_fload_0: + case bc_dload_0: + out.append("stack.push(arg0);"); + break; + case bc_aload_1: + case bc_iload_1: + case bc_lload_1: + case bc_fload_1: + case bc_dload_1: + out.append("stack.push(arg1);"); + break; + case bc_aload_2: + case bc_iload_2: + case bc_lload_2: + case bc_fload_2: + case bc_dload_2: + out.append("stack.push(arg2);"); + break; + case bc_aload_3: + case bc_iload_3: + case bc_lload_3: + case bc_fload_3: + case bc_dload_3: + out.append("stack.push(arg3);"); + break; + case bc_iload: + case bc_lload: + case bc_fload: + case bc_dload: + case bc_aload: { + final int indx = (byteCodes[++i] + 256) % 256; + out.append("stack.push(arg").append(indx + ");"); + break; + } + case bc_astore_0: + case bc_istore_0: + case bc_lstore_0: + case bc_fstore_0: + case bc_dstore_0: + out.append("arg0 = stack.pop();"); + break; + case bc_astore_1: + case bc_istore_1: + case bc_lstore_1: + case bc_fstore_1: + case bc_dstore_1: + out.append("arg1 = stack.pop();"); + break; + case bc_astore_2: + case bc_istore_2: + case bc_lstore_2: + case bc_fstore_2: + case bc_dstore_2: + out.append("arg2 = stack.pop();"); + break; + case bc_astore_3: + case bc_istore_3: + case bc_lstore_3: + case bc_fstore_3: + case bc_dstore_3: + out.append("arg3 = stack.pop();"); + break; + case bc_iadd: + case bc_ladd: + case bc_fadd: + case bc_dadd: + out.append("stack.push(stack.pop() + stack.pop());"); + break; + case bc_isub: + case bc_lsub: + case bc_fsub: + case bc_dsub: + out.append("{ var tmp = stack.pop(); stack.push(stack.pop() - tmp); }"); + break; + case bc_imul: + case bc_lmul: + case bc_fmul: + case bc_dmul: + out.append("stack.push(stack.pop() * stack.pop());"); + break; + case bc_idiv: + case bc_ldiv: + out.append("{ var tmp = stack.pop(); stack.push(Math.floor(stack.pop() / tmp)); }"); + break; + case bc_fdiv: + case bc_ddiv: + out.append("{ var tmp = stack.pop(); stack.push(stack.pop() / tmp); }"); + break; + case bc_iand: + case bc_land: + out.append("stack.push(stack.pop() & stack.pop());"); + break; + case bc_ior: + case bc_lor: + out.append("stack.push(stack.pop() | stack.pop());"); + break; + case bc_ixor: + case bc_lxor: + out.append("stack.push(stack.pop() ^ stack.pop());"); + break; + case bc_iinc: { + final int varIndx = (byteCodes[++i] + 256) % 256; + final int incrBy = (byteCodes[++i] + 256) % 256; + if (incrBy == 1) { + out.append("arg" + varIndx).append("++;"); + } else { + out.append("arg" + varIndx).append(" += " + incrBy).append(";"); + } + break; + } + case bc_return: + out.append("return;"); + break; + case bc_ireturn: + case bc_lreturn: + case bc_freturn: + case bc_dreturn: + case bc_areturn: + out.append("return stack.pop();"); + break; + case bc_i2l: + case bc_i2f: + case bc_i2d: + case bc_l2i: + // max int check? + case bc_l2f: + case bc_l2d: + case bc_f2d: + case bc_d2f: + out.append("/* number conversion */"); + break; + case bc_f2i: + case bc_f2l: + case bc_d2i: + case bc_d2l: + out.append("stack.push(Math.floor(stack.pop()));"); + break; + case bc_i2b: + case bc_i2c: + case bc_i2s: + out.append("/* number conversion */"); + break; + case bc_iconst_0: + case bc_dconst_0: + case bc_lconst_0: + case bc_fconst_0: + out.append("stack.push(0);"); + break; + case bc_iconst_1: + case bc_lconst_1: + case bc_fconst_1: + case bc_dconst_1: + out.append("stack.push(1);"); + break; + case bc_iconst_2: + case bc_fconst_2: + out.append("stack.push(2);"); + break; + case bc_iconst_3: + out.append("stack.push(3);"); + break; + case bc_iconst_4: + out.append("stack.push(4);"); + break; + case bc_iconst_5: + out.append("stack.push(5);"); + break; + case bc_ldc: { + int indx = byteCodes[++i]; + CPEntry entry = jc.getConstantPool().get(indx); + String v = encodeConstant(entry); + out.append("stack.push(").append(v).append(");"); + break; + } + case bc_ldc_w: + case bc_ldc2_w: { + int indx = readIntArg(byteCodes, i); + CPEntry entry = jc.getConstantPool().get(indx); + i += 2; + String v = encodeConstant(entry); + out.append("stack.push(").append(v).append(");"); + break; + } + case bc_lcmp: + case bc_fcmpl: + case bc_fcmpg: + case bc_dcmpl: + case bc_dcmpg: { + out.append("{ var delta = stack.pop() - stack.pop(); stack.push(delta < 0 ?-1 : (delta == 0 ? 0 : 1)); }"); + break; + } + case bc_if_icmpeq: { + i = generateIf(byteCodes, i, "=="); + break; + } + case bc_ifeq: { + int indx = i + readIntArg(byteCodes, i); + out.append("if (stack.pop() == 0) { gt = " + indx); + out.append("; continue; }"); + i += 2; + break; + } + case bc_ifne: { + int indx = i + readIntArg(byteCodes, i); + out.append("if (stack.pop() != 0) { gt = " + indx); + out.append("; continue; }"); + i += 2; + break; + } + case bc_iflt: { + int indx = i + readIntArg(byteCodes, i); + out.append("if (stack.pop() < 0) { gt = " + indx); + out.append("; continue; }"); + i += 2; + break; + } + case bc_ifle: { + int indx = i + readIntArg(byteCodes, i); + out.append("if (stack.pop() <= 0) { gt = " + indx); + out.append("; continue; }"); + i += 2; + break; + } + case bc_ifgt: { + int indx = i + readIntArg(byteCodes, i); + out.append("if (stack.pop() > 0) { gt = " + indx); + out.append("; continue; }"); + i += 2; + break; + } + case bc_ifge: { + int indx = i + readIntArg(byteCodes, i); + out.append("if (stack.pop() >= 0) { gt = " + indx); + out.append("; continue; }"); + i += 2; + break; + } + case bc_ifnonnull: { + int indx = i + readIntArg(byteCodes, i); + out.append("if (stack.pop()) { gt = " + indx); + out.append("; continue; }"); + i += 2; + break; + } + case bc_ifnull: { + int indx = i + readIntArg(byteCodes, i); + out.append("if (!stack.pop()) { gt = " + indx); + out.append("; continue; }"); + i += 2; + break; + } + case bc_if_icmpne: + i = generateIf(byteCodes, i, "!="); + break; + case bc_if_icmplt: + i = generateIf(byteCodes, i, ">"); + break; + case bc_if_icmple: + i = generateIf(byteCodes, i, ">="); + break; + case bc_if_icmpgt: + i = generateIf(byteCodes, i, "<"); + break; + case bc_if_icmpge: + i = generateIf(byteCodes, i, "<="); + break; + case bc_goto: { + int indx = i + readIntArg(byteCodes, i); + out.append("gt = " + indx).append("; continue;"); + i += 2; + break; + } + case bc_invokeinterface: + case bc_invokevirtual: + i = invokeVirtualMethod(byteCodes, i); + break; + case bc_invokespecial: + i = invokeStaticMethod(byteCodes, i, false); + break; + case bc_invokestatic: + i = invokeStaticMethod(byteCodes, i, true); + break; + case bc_new: { + int indx = readIntArg(byteCodes, i); + CPClassInfo ci = jc.getConstantPool().getClass(indx); + out.append("stack.push("); + out.append("new ").append(ci.getClassName().getInternalName().replace('/','_')); + out.append(");"); + addReference(ci.getClassName().getInternalName()); + i += 2; + break; + } + case bc_newarray: { + int type = byteCodes[i++]; + out.append("stack.push(new Array(stack.pop()));"); + break; + } + case bc_anewarray: { + i += 2; // skip type of array + out.append("stack.push(new Array(stack.pop()));"); + break; + } + case bc_arraylength: + out.append("stack.push(stack.pop().length);"); + break; + case bc_iastore: + case bc_lastore: + case bc_fastore: + case bc_dastore: + case bc_aastore: + case bc_bastore: + case bc_castore: + case bc_sastore: { + out.append("{ var value = stack.pop(); var indx = stack.pop(); stack.pop()[indx] = value; }"); + break; + } + case bc_iaload: + case bc_laload: + case bc_faload: + case bc_daload: + case bc_aaload: + case bc_baload: + case bc_caload: + case bc_saload: { + out.append("{ var indx = stack.pop(); stack.push(stack.pop()[indx]); }"); + break; + } + case bc_dup: + out.append("stack.push(stack[stack.length - 1]);"); + break; + case bc_bipush: + out.append("stack.push(" + byteCodes[++i] + ");"); + break; + case bc_getfield: { + int indx = readIntArg(byteCodes, i); + CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); + out.append("stack.push(stack.pop().").append(fi.getFieldName()).append(");"); + i += 2; + break; + } + case bc_getstatic: { + int indx = readIntArg(byteCodes, i); + CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); + final String in = fi.getClassName().getInternalName(); + out.append("stack.push(").append(in.replace('/', '_')); + out.append('_').append(fi.getFieldName()).append(");"); + i += 2; + addReference(in); + break; + } + case bc_putstatic: { + int indx = readIntArg(byteCodes, i); + CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); + final String in = fi.getClassName().getInternalName(); + out.append(in.replace('/', '_')); + out.append('_').append(fi.getFieldName()).append(" = stack.pop();"); + i += 2; + addReference(in); + break; + } + case bc_putfield: { + int indx = readIntArg(byteCodes, i); + CPFieldInfo fi = (CPFieldInfo) jc.getConstantPool().get(indx); + out.append("{ var v = stack.pop(); stack.pop().") + .append(fi.getFieldName()).append(" = v; }"); + i += 2; + break; + } + case bc_instanceof: { + int indx = readIntArg(byteCodes, i); + CPClassInfo ci = jc.getConstantPool().getClass(indx); + out.append("stack.push(stack.pop().$instOf_") + .append(ci.getClassName().getInternalName().replace('/', '_')) + .append(" ? 1 : 0);"); + i += 2; + } + + } + out.append(" /*"); + for (int j = prev; j <= i; j++) { + out.append(" "); + final int cc = (byteCodes[j] + 256) % 256; + out.append(Integer.toString(cc)); + } + out.append("*/\n"); + } + out.append(" }\n"); + } + + private int generateIf(byte[] byteCodes, int i, final String test) throws IOException { + int indx = i + readIntArg(byteCodes, i); + out.append("if (stack.pop() ").append(test).append(" stack.pop()) { gt = " + indx); + out.append("; continue; }"); + return i + 2; + } + + private int readIntArg(byte[] byteCodes, int offsetInstruction) { + final int indxHi = byteCodes[offsetInstruction + 1] << 8; + final int indxLo = byteCodes[offsetInstruction + 2]; + return (indxHi & 0xffffff00) | (indxLo & 0xff); + } + + private static int countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig) { + int cnt = 0; + int i = 0; + Boolean count = null; + int firstPos = sig.length(); + while (i < descriptor.length()) { + char ch = descriptor.charAt(i++); + switch (ch) { + case '(': + count = true; + continue; + case ')': + count = false; + continue; + case 'B': + case 'C': + case 'D': + case 'F': + case 'I': + case 'J': + case 'S': + case 'Z': + if (count) { + cnt++; + sig.append(ch); + } else { + hasReturnType[0] = true; + sig.insert(firstPos, ch); + } + continue; + case 'V': + assert !count; + hasReturnType[0] = false; + sig.insert(firstPos, 'V'); + continue; + case 'L': + int next = descriptor.indexOf(';', i); + if (count) { + cnt++; + sig.append(ch); + sig.append(descriptor.substring(i, next).replace('/', '_')); + } else { + sig.insert(firstPos, descriptor.substring(i, next).replace('/', '_')); + sig.insert(firstPos, ch); + hasReturnType[0] = true; + } + i = next + 1; + continue; + case '[': + //arrays++; + continue; + default: + break; // invalid character + } + } + return cnt; + } + + private void generateStaticField(Variable v) throws IOException { + out.append("\nvar ") + .append(jc.getName().getInternalName().replace('/', '_')) + .append('_').append(v.getName()).append(" = 0;"); + } + + private String findMethodName(Method m) { + StringBuilder tmp = new StringBuilder(); + if ("".equals(m.getName())) { // NOI18N + tmp.append("consV"); // NOI18N + } else if ("".equals(m.getName())) { // NOI18N + tmp.append("classV"); // NOI18N + } else { + tmp.append(m.getName()); + outType(m.getReturnType(), tmp); + } + List args = m.getParameters(); + for (Parameter t : args) { + outType(t.getDescriptor(), tmp); + } + return tmp.toString(); + } + + private String findMethodName(CPMethodInfo mi, int[] cnt, boolean[] hasReturn) { + StringBuilder name = new StringBuilder(); + if ("".equals(mi.getName())) { // NOI18N + name.append("cons"); // NOI18N + } else { + name.append(mi.getName()); + } + cnt[0] = countArgs(mi.getDescriptor(), hasReturn, name); + return name.toString(); + } + + private int invokeStaticMethod(byte[] byteCodes, int i, boolean isStatic) + throws IOException { + int methodIndex = readIntArg(byteCodes, i); + CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex); + boolean[] hasReturn = { false }; + int[] cnt = { 0 }; + String mn = findMethodName(mi, cnt, hasReturn); + out.append("{ "); + for (int j = cnt[0] - 1; j >= 0; j--) { + out.append("var v" + j).append(" = stack.pop(); "); + } + + if (hasReturn[0]) { + out.append("stack.push("); + } + final String in = mi.getClassName().getInternalName(); + out.append(in.replace('/', '_')); + out.append('_'); + out.append(mn); + out.append('('); + String sep = ""; + if (!isStatic) { + out.append("stack.pop()"); + sep = ", "; + } + for (int j = 0; j < cnt[0]; j++) { + out.append(sep); + out.append("v" + j); + sep = ", "; + } + out.append(")"); + if (hasReturn[0]) { + out.append(")"); + } + out.append("; }"); + i += 2; + addReference(in); + return i; + } + private int invokeVirtualMethod(byte[] byteCodes, int i) + throws IOException { + int methodIndex = readIntArg(byteCodes, i); + CPMethodInfo mi = (CPMethodInfo) jc.getConstantPool().get(methodIndex); + boolean[] hasReturn = { false }; + int[] cnt = { 0 }; + String mn = findMethodName(mi, cnt, hasReturn); + out.append("{ "); + for (int j = cnt[0] - 1; j >= 0; j--) { + out.append("var v" + j).append(" = stack.pop(); "); + } + out.append("var self = stack.pop(); "); + if (hasReturn[0]) { + out.append("stack.push("); + } + out.append("self."); + out.append(mn); + out.append('('); + out.append("self"); + for (int j = 0; j < cnt[0]; j++) { + out.append(", "); + out.append("v" + j); + } + out.append(")"); + if (hasReturn[0]) { + out.append(")"); + } + out.append("; }"); + i += 2; + return i; + } + + private void addReference(String cn) { + if (references != null) { + references.add(cn); + } + } + + private void outType(final String d, StringBuilder out) { + if (d.charAt(0) == 'L') { + assert d.charAt(d.length() - 1) == ';'; + out.append(d.replace('/', '_').substring(0, d.length() - 1)); + } else { + out.append(d); + } + } + + private String encodeConstant(CPEntry entry) { + final String v; + if (entry instanceof CPStringInfo) { + v = "\"" + entry.getValue().toString().replace("\"", "\\\"") + "\""; + } else { + v = entry.getValue().toString(); + } + return v; + } +} diff -r d8807b6a636a -r b9318fe303cd vm/src/test/java/org/apidesign/vm4brwsr/Array.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Array.java Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,76 @@ +/* +Java 4 Browser Bytecode Translator +Copyright (C) 2012-2012 Jaroslav Tulach + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. Look for COPYING file in the top folder. +If not, see http://opensource.org/licenses/GPL-2.0. +*/ +package org.apidesign.vm4brwsr; + +/** + * + * @author Jaroslav Tulach + */ +public class Array { + byte[] bytes = { 1 }; + short[] shorts = { 2, 3 }; + int[] ints = { 4, 5, 6 }; + float[] floats = { 7, 8, 9, 10 }; + double[][] doubles = { {11}, {12}, {13}, {14}, {15} }; + char[] chars = { 'a', 'b' }; + + private Array() { + } + + byte bytes() { + return bytes[0]; + } + short shorts() { + return shorts[1]; + } + + int ints() { + return ints[2]; + } + + float floats() { + return floats[3]; + } + + double doubles() { + return doubles[4][0]; + } + + private static final Array[] ARR = { new Array(), new Array(), new Array() }; + + public static double sum() { + double sum = 0.0; + for (int i = 0; i < ARR.length; i++) { + sum += ARR[i].bytes(); + sum += ARR[i].shorts(); + sum += ARR[i].ints(); + sum += ARR[i].floats(); + sum += ARR[i].doubles(); + } + return sum; + } + public static int simple() { + int[] arr = { 0, 1, 2, 3, 4, 5 }; + + int sum = 0; + for (int i = 0; i < arr.length; i++) { + sum += arr[i]; + } + return sum; + } +} diff -r d8807b6a636a -r b9318fe303cd vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ArrayTest.java Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,63 @@ +/* +Java 4 Browser Bytecode Translator +Copyright (C) 2012-2012 Jaroslav Tulach + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. Look for COPYING file in the top folder. +If not, see http://opensource.org/licenses/GPL-2.0. +*/ +package org.apidesign.vm4brwsr; + +import javax.script.Invocable; +import javax.script.ScriptException; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * + * @author Jaroslav Tulach + */ +public class ArrayTest { + @Test public void verifySimpleIntOperation() throws Exception { + assertExec("CheckTheSum", "org_apidesign_vm4brwsr_Array_simpleI", + Double.valueOf(15) + ); + } + @Test public void verifyOperationsOnArrays() throws Exception { + assertExec("The sum is 105", "org_apidesign_vm4brwsr_Array_sumD", + Double.valueOf(105) + ); + } + + private static void assertExec(String msg, String methodName, Object expRes, Object... args) throws Exception { + StringBuilder sb = new StringBuilder(); + Invocable i = StaticMethodTest.compileClass(sb, + "org/apidesign/vm4brwsr/Array" + ); + + Object ret = null; + try { + ret = i.invokeFunction(methodName, args); + } catch (ScriptException ex) { + fail("Execution failed in " + sb, ex); + } catch (NoSuchMethodException ex) { + fail("Cannot find method in " + sb, ex); + } + if (ret == null && expRes == null) { + return; + } + if (expRes.equals(ret)) { + return; + } + assertEquals(ret, expRes, msg + "was: " + ret + "\n" + sb); + } +} diff -r d8807b6a636a -r b9318fe303cd vm/src/test/java/org/apidesign/vm4brwsr/GetByte.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/GetByte.java Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,9 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.apidesign.vm4brwsr; + +public interface GetByte { + public byte getByte(); +} diff -r d8807b6a636a -r b9318fe303cd vm/src/test/java/org/apidesign/vm4brwsr/Instance.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Instance.java Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,69 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.apidesign.vm4brwsr; + +/** + * + * @author Jaroslav Tulach + */ +public class Instance { + private int i; + protected short s; + public double d; + private float f; + protected byte b = (byte)31; + + private Instance() { + } + + public Instance(int i, double d) { + this.i = i; + this.d = d; + } + public byte getByte() { + return b; + } + + public void setByte(byte b) { + this.b = b; + } + public static double defaultDblValue() { + Instance create = new Instance(); + return create.d; + } + + public static byte assignedByteValue() { + return new Instance().b; + } + public static double magicOne() { + Instance i = new Instance(10, 3.3d); + i.b = (byte)0x09; + return (i.i - i.b) * i.d; + } + public static int virtualBytes() { + Instance i = new InstanceSub(7, 2.2d); + i.setByte((byte)0x0a); + Instance i2 = new Instance(3, 333.0d); + i2.setByte((byte)44); + return i.getByte() + i2.getByte(); + } + public static float interfaceBytes() { + GetByte i = new InstanceSub(7, 2.2d); + return i.getByte(); + } + public static boolean instanceOf(boolean sub) { + Instance i = createInstance(sub); + return isInstanceSubOf(i); + } + private static boolean isInstanceSubOf(Instance instance) { + return instance instanceof InstanceSub; + } + private static Instance createInstance(boolean sub) { + return sub ? new InstanceSub(3, 0) : new Instance(); + } + private static boolean isNull() { + return createInstance(true) == null; + } +} diff -r d8807b6a636a -r b9318fe303cd vm/src/test/java/org/apidesign/vm4brwsr/InstanceSub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/InstanceSub.java Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,20 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.apidesign.vm4brwsr; + +/** + * + * @author Jaroslav Tulach + */ +public class InstanceSub extends Instance implements GetByte { + public InstanceSub(int i, double d) { + super(i, d); + } + + @Override + public void setByte(byte b) { + super.setByte((byte) (b + 1)); + } +} diff -r d8807b6a636a -r b9318fe303cd vm/src/test/java/org/apidesign/vm4brwsr/InstanceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/InstanceTest.java Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,101 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.apidesign.vm4brwsr; + +import javax.script.Invocable; +import javax.script.ScriptException; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * + * @author Jaroslav Tulach + */ +public class InstanceTest { + @Test public void verifyDefaultDoubleValue() throws Exception { + assertExec( + "Will be zero", + "org_apidesign_vm4brwsr_Instance_defaultDblValueD", + Double.valueOf(0) + ); + } + @Test public void verifyAssignedByteValue() throws Exception { + assertExec( + "Will one thirty one", + "org_apidesign_vm4brwsr_Instance_assignedByteValueB", + Double.valueOf(31) + ); + } + @Test public void verifyMagicOne() throws Exception { + assertExec( + "Should be three and something", + "org_apidesign_vm4brwsr_Instance_magicOneD", + Double.valueOf(3.3) + ); + } + @Test public void verifyInstanceMethods() throws Exception { + assertExec( + "Should be eleven as we invoke overwritten method, plus 44", + "org_apidesign_vm4brwsr_Instance_virtualBytesI", + Double.valueOf(55) + ); + } + @Test public void verifyInterfaceMethods() throws Exception { + assertExec( + "Retruns default value", + "org_apidesign_vm4brwsr_Instance_interfaceBytesF", + Double.valueOf(31) + ); + } + + @Test public void isNull() throws Exception { + assertExec( + "Yes, we are instance", + "org_apidesign_vm4brwsr_Instance_isNullZ", + Double.valueOf(0.0) + ); + } + + @Test public void isInstanceOf() throws Exception { + assertExec( + "Yes, we are instance", + "org_apidesign_vm4brwsr_Instance_instanceOfZZ", + Double.valueOf(1.0), true + ); + } + + @Test public void notInstanceOf() throws Exception { + assertExec( + "No, we are not an instance", + "org_apidesign_vm4brwsr_Instance_instanceOfZZ", + Double.valueOf(0.0), false + ); + } + + private static void assertExec(String msg, String methodName, Object expRes, Object... args) throws Exception { + StringBuilder sb = new StringBuilder(); + Invocable i = StaticMethodTest.compileClass(sb, + "org/apidesign/vm4brwsr/Instance" + ); + + Object ret = null; + try { + ret = i.invokeFunction(methodName, args); + } catch (ScriptException ex) { + fail("Execution failed in " + sb, ex); + } catch (NoSuchMethodException ex) { + fail("Cannot find method in " + sb, ex); + } + if (ret == null && expRes == null) { + return; + } + if (expRes.equals(ret)) { + return; + } + assertEquals(ret, expRes, msg + "was: " + ret + "\n" + sb); + + } + +} diff -r d8807b6a636a -r b9318fe303cd vm/src/test/java/org/apidesign/vm4brwsr/StaticMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethod.java Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,68 @@ +/* +Java 4 Browser Bytecode Translator +Copyright (C) 2012-2012 Jaroslav Tulach + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. Look for COPYING file in the top folder. +If not, see http://opensource.org/licenses/GPL-2.0. +*/ +package org.apidesign.vm4brwsr; + +/** + * + * @author Jaroslav Tulach + */ +public class StaticMethod { + private static int cnt; + + public static int sum(int x, int y) { + return x + y; + } + public static float power(float x) { + return x * x; + } + public static double minus(double x, long y) { + return x - y; + } + public static int div(byte c, double d) { + return (int)(d / c); + } + public static int mix(int a, long b, byte c, double d) { + return (int)((b / a + c) * d); + } + public static long xor(int a, long b) { + return a ^ b; + } + public static long orOrAnd(boolean doOr, int a, int b) { + return doOr ? a | b : a & b; + } + public static long factRec(int n) { + if (n <= 1) { + return 1; + } else { + return n * factRec(n - 1); + } + } + public static long factIter(int n) { + long res = 1; + for (int i = 2; i <= n; i++) { + res *= i; + } + return res; + } + public static int inc4() { + cnt++; + cnt+=2; + cnt++; + return cnt; + } +} diff -r d8807b6a636a -r b9318fe303cd vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Mon Sep 24 11:07:38 2012 +0200 @@ -0,0 +1,202 @@ +/* +Java 4 Browser Bytecode Translator +Copyright (C) 2012-2012 Jaroslav Tulach + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. Look for COPYING file in the top folder. +If not, see http://opensource.org/licenses/GPL-2.0. +*/ +package org.apidesign.vm4brwsr; + +import org.apidesign.vm4brwsr.ByteCodeToJavaScript; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Set; +import java.util.TreeSet; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** Checks the basic behavior of the translator. + * + * @author Jaroslav Tulach + */ +public class StaticMethodTest { + @Test public void threePlusFour() throws Exception { + assertExec( + "Should be seven", + "org_apidesign_vm4brwsr_StaticMethod_sumIII", + Double.valueOf(7), + 3, 4 + ); + } + + @Test public void powerOfThree() throws Exception { + assertExec( + "Should be nine", + "org_apidesign_vm4brwsr_StaticMethod_powerFF", + Double.valueOf(9), + 3.0f + ); + } + + @Test public void doubleWithoutLong() throws Exception { + assertExec( + "Should be two", + "org_apidesign_vm4brwsr_StaticMethod_minusDDJ", + Double.valueOf(2), + 3.0d, 1l + ); + } + + @Test public void divAndRound() throws Exception { + assertExec( + "Should be rounded to one", + "org_apidesign_vm4brwsr_StaticMethod_divIBD", + Double.valueOf(1), + 3, 3.75 + ); + } + @Test public void mixedMethodFourParams() throws Exception { + assertExec( + "Should be two", + "org_apidesign_vm4brwsr_StaticMethod_mixIIJBD", + Double.valueOf(20), + 2, 10l, 5, 2.0 + ); + } + @Test public void factRec() throws Exception { + assertExec( + "Factorial of 5 is 120", + "org_apidesign_vm4brwsr_StaticMethod_factRecJI", + Double.valueOf(120), + 5 + ); + } + @Test public void factIter() throws Exception { + assertExec( + "Factorial of 5 is 120", + "org_apidesign_vm4brwsr_StaticMethod_factIterJI", + Double.valueOf(120), + 5 + ); + } + + @Test public void xor() throws Exception { + assertExec( + "Xor is 4", + "org_apidesign_vm4brwsr_StaticMethod_xorJIJ", + Double.valueOf(4), + 7, + 3 + ); + } + + @Test public void or() throws Exception { + assertExec( + "Or will be 7", + "org_apidesign_vm4brwsr_StaticMethod_orOrAndJZII", + Double.valueOf(7), + true, + 4, + 3 + ); + } + @Test public void and() throws Exception { + assertExec( + "And will be 3", + "org_apidesign_vm4brwsr_StaticMethod_orOrAndJZII", + Double.valueOf(3), + false, + 7, + 3 + ); + } + @Test public void inc4() throws Exception { + assertExec( + "It will be 4", + "org_apidesign_vm4brwsr_StaticMethod_inc4I", + Double.valueOf(4) + ); + } + + private static void assertExec(String msg, String methodName, Object expRes, Object... args) throws Exception { + StringBuilder sb = new StringBuilder(); + Invocable i = compileClass(sb, "org/apidesign/vm4brwsr/StaticMethod"); + + Object ret = null; + try { + ret = i.invokeFunction(methodName, args); + } catch (ScriptException ex) { + fail("Execution failed in " + sb, ex); + } catch (NoSuchMethodException ex) { + fail("Cannot find method in " + sb, ex); + } + if (ret == null && expRes == null) { + return; + } + if (expRes.equals(ret)) { + return; + } + assertEquals(ret, expRes, msg + "was: " + ret + "\n" + sb); + + } + + static Invocable compileClass(StringBuilder sb, String... names) throws ScriptException, IOException { + if (sb == null) { + sb = new StringBuilder(); + } + Set processed = new HashSet(); + + LinkedList toProcess = new LinkedList(Arrays.asList(names)); + for (;;) { + toProcess.removeAll(processed); + if (toProcess.isEmpty()) { + break; + } + String name = toProcess.getFirst(); + processed.add(name); + if (name.startsWith("java/") && !name.equals("java/lang/Object")) { + continue; + } + InputStream is = StaticMethodTest.class.getClassLoader().getResourceAsStream(name + ".class"); + assertNotNull(is, "Class file found"); + try { + ByteCodeToJavaScript.compile(is, sb, toProcess); + } catch (RuntimeException ex) { + int lastBlock = sb.lastIndexOf("{"); + throw new IllegalStateException( + "Error while compiling " + name + "\n" + + sb.substring(0, sb.length()), + ex + ); + } + } + ScriptEngineManager sem = new ScriptEngineManager(); + ScriptEngine js = sem.getEngineByExtension("js"); + try { + Object res = js.eval(sb.toString()); + assertTrue(js instanceof Invocable, "It is invocable object: " + res); + return (Invocable)js; + } catch (ScriptException ex) { + fail("Could not compile:\n" + sb, ex); + return null; + } + } +}