# HG changeset patch # User Jaroslav Tulach # Date 1392793804 -3600 # Node ID 4ce73c83c77518f4e8463cfb77ba08a052746822 # Parent ef506621d1eed1ec610499ccfd2bb07a13bd833f# Parent b012365f8fb7f27dc2e04d8bfed9c1ce19f8842f Reduced stack seems to be stable enough to be merged into default branch diff -r ef506621d1ee -r 4ce73c83c775 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Wed Feb 19 08:10:04 2014 +0100 @@ -250,6 +250,17 @@ } } + @Compare public int callAbst() throws Exception { + class Impl extends Abst { + @Override + public int abst() { + return 10; + } + } + Abst impl = new Impl(); + return (int) Abst.class.getMethod("abst").invoke(impl); + } + @Compare public String componentGetNameForObjectArray() { return (new Object[3]).getClass().getComponentType().getName(); } @@ -296,4 +307,7 @@ return VMTest.create(ReflectionTest.class); } + public static abstract class Abst { + public abstract int abst(); + } } diff -r ef506621d1ee -r 4ce73c83c775 rt/emul/mini/src/main/java/java/lang/Object.java --- a/rt/emul/mini/src/main/java/java/lang/Object.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Object.java Wed Feb 19 08:10:04 2014 +0100 @@ -43,7 +43,7 @@ private static void registerNatives() { boolean assertsOn = false; - assert assertsOn = false; + // assert assertsOn = true; if (assertsOn) try { Array.get(null, 0); } catch (Throwable ex) { diff -r ef506621d1ee -r 4ce73c83c775 rt/emul/mini/src/main/java/java/lang/reflect/Method.java --- a/rt/emul/mini/src/main/java/java/lang/reflect/Method.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Method.java Wed Feb 19 08:10:04 2014 +0100 @@ -528,15 +528,17 @@ } @JavaScriptBody(args = { "st", "method", "self", "args" }, body = - "var p;\n" + "var p; var cll;\n" + "if (st) {\n" + + " cll = self[method._name() + '__' + method._sig()];\n" + " p = new Array(1);\n" + " p[0] = self;\n" + " p = p.concat(args);\n" + "} else {\n" + " p = args;\n" + + " cll = method._data();" + "}\n" - + "return method._data().apply(self, p);\n" + + "return cll.apply(self, p);\n" ) private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args); diff -r ef506621d1ee -r 4ce73c83c775 rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Wed Feb 19 08:10:04 2014 +0100 @@ -51,12 +51,12 @@ } @JavaScriptBody(args = { "arr", "expectedSize" }, body = - "while (expectedSize-- > arr.length) { arr.push(0); }; return arr;" + "while (expectedSize > arr.length) { arr.push(0); }; return arr;" ) public static native byte[] expandArray(byte[] arr, int expectedSize); @JavaScriptBody(args = { "arr", "expectedSize" }, body = - "while (expectedSize-- > arr.length) { arr.push(0); }; return arr;" + "while (expectedSize > arr.length) { arr.push(0); }; return arr;" ) public static native char[] expandArray(char[] arr, int expectedSize); diff -r ef506621d1ee -r 4ce73c83c775 rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js --- a/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Wed Feb 19 08:10:04 2014 +0100 @@ -224,6 +224,14 @@ return hi.next32(low); } }; + + numberPrototype.compare = function(x) { + if (this == x) { + return 0; + } else { + return (this < x) ? -1 : 1; + } + }; numberPrototype.compare64 = function(x) { if (this.high32() === x.high32()) { diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Wed Feb 19 08:10:04 2014 +0100 @@ -39,37 +39,6 @@ final class ByteCodeParser { private ByteCodeParser() { } - /* Signature Characters */ - public static final char SIGC_VOID = 'V'; - public static final String SIG_VOID = "V"; - public static final char SIGC_BOOLEAN = 'Z'; - public static final String SIG_BOOLEAN = "Z"; - public static final char SIGC_BYTE = 'B'; - public static final String SIG_BYTE = "B"; - public static final char SIGC_CHAR = 'C'; - public static final String SIG_CHAR = "C"; - public static final char SIGC_SHORT = 'S'; - public static final String SIG_SHORT = "S"; - public static final char SIGC_INT = 'I'; - public static final String SIG_INT = "I"; - public static final char SIGC_LONG = 'J'; - public static final String SIG_LONG = "J"; - public static final char SIGC_FLOAT = 'F'; - public static final String SIG_FLOAT = "F"; - public static final char SIGC_DOUBLE = 'D'; - public static final String SIG_DOUBLE = "D"; - public static final char SIGC_ARRAY = '['; - public static final String SIG_ARRAY = "["; - public static final char SIGC_CLASS = 'L'; - public static final String SIG_CLASS = "L"; - public static final char SIGC_METHOD = '('; - public static final String SIG_METHOD = "("; - public static final char SIGC_ENDCLASS = ';'; - public static final String SIG_ENDCLASS = ";"; - public static final char SIGC_ENDMETHOD = ')'; - public static final String SIG_ENDMETHOD = ")"; - public static final char SIGC_PACKAGE = '/'; - public static final String SIG_PACKAGE = "/"; /* Class File Constants */ public static final int JAVA_MAGIC = 0xcafebabe; @@ -107,17 +76,6 @@ public static final int ACC_EXPLICIT = 0x00001000; public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute - /* Type codes */ - public static final int T_CLASS = 0x00000002; - public static final int T_BOOLEAN = 0x00000004; - public static final int T_CHAR = 0x00000005; - public static final int T_FLOAT = 0x00000006; - public static final int T_DOUBLE = 0x00000007; - public static final int T_BYTE = 0x00000008; - public static final int T_SHORT = 0x00000009; - public static final int T_INT = 0x0000000a; - public static final int T_LONG = 0x0000000b; - /* Type codes for StackMap attribute */ public static final int ITEM_Bogus =0; // an unknown or uninitialized value public static final int ITEM_Integer =1; // a 32-bit integer @@ -358,7 +316,7 @@ public static final int opc_nonpriv = 254; public static final int opc_priv = 255; - /* Wide instructions */ + /* Wide instructions * public static final int opc_iload_w = (opc_wide<<8)|opc_iload; public static final int opc_lload_w = (opc_wide<<8)|opc_lload; public static final int opc_fload_w = (opc_wide<<8)|opc_fload; @@ -371,762 +329,7 @@ public static final int opc_astore_w = (opc_wide<<8)|opc_astore; public static final int opc_ret_w = (opc_wide<<8)|opc_ret; public static final int opc_iinc_w = (opc_wide<<8)|opc_iinc; - - /* Opcode Names */ - public static final String opcNamesTab[] = { - "nop", - "aconst_null", - "iconst_m1", - "iconst_0", - "iconst_1", - "iconst_2", - "iconst_3", - "iconst_4", - "iconst_5", - "lconst_0", - "lconst_1", - "fconst_0", - "fconst_1", - "fconst_2", - "dconst_0", - "dconst_1", - "bipush", - "sipush", - "ldc", - "ldc_w", - "ldc2_w", - "iload", - "lload", - "fload", - "dload", - "aload", - "iload_0", - "iload_1", - "iload_2", - "iload_3", - "lload_0", - "lload_1", - "lload_2", - "lload_3", - "fload_0", - "fload_1", - "fload_2", - "fload_3", - "dload_0", - "dload_1", - "dload_2", - "dload_3", - "aload_0", - "aload_1", - "aload_2", - "aload_3", - "iaload", - "laload", - "faload", - "daload", - "aaload", - "baload", - "caload", - "saload", - "istore", - "lstore", - "fstore", - "dstore", - "astore", - "istore_0", - "istore_1", - "istore_2", - "istore_3", - "lstore_0", - "lstore_1", - "lstore_2", - "lstore_3", - "fstore_0", - "fstore_1", - "fstore_2", - "fstore_3", - "dstore_0", - "dstore_1", - "dstore_2", - "dstore_3", - "astore_0", - "astore_1", - "astore_2", - "astore_3", - "iastore", - "lastore", - "fastore", - "dastore", - "aastore", - "bastore", - "castore", - "sastore", - "pop", - "pop2", - "dup", - "dup_x1", - "dup_x2", - "dup2", - "dup2_x1", - "dup2_x2", - "swap", - "iadd", - "ladd", - "fadd", - "dadd", - "isub", - "lsub", - "fsub", - "dsub", - "imul", - "lmul", - "fmul", - "dmul", - "idiv", - "ldiv", - "fdiv", - "ddiv", - "irem", - "lrem", - "frem", - "drem", - "ineg", - "lneg", - "fneg", - "dneg", - "ishl", - "lshl", - "ishr", - "lshr", - "iushr", - "lushr", - "iand", - "land", - "ior", - "lor", - "ixor", - "lxor", - "iinc", - "i2l", - "i2f", - "i2d", - "l2i", - "l2f", - "l2d", - "f2i", - "f2l", - "f2d", - "d2i", - "d2l", - "d2f", - "i2b", - "i2c", - "i2s", - "lcmp", - "fcmpl", - "fcmpg", - "dcmpl", - "dcmpg", - "ifeq", - "ifne", - "iflt", - "ifge", - "ifgt", - "ifle", - "if_icmpeq", - "if_icmpne", - "if_icmplt", - "if_icmpge", - "if_icmpgt", - "if_icmple", - "if_acmpeq", - "if_acmpne", - "goto", - "jsr", - "ret", - "tableswitch", - "lookupswitch", - "ireturn", - "lreturn", - "freturn", - "dreturn", - "areturn", - "return", - "getstatic", - "putstatic", - "getfield", - "putfield", - "invokevirtual", - "invokespecial", // was "invokenonvirtual", - "invokestatic", - "invokeinterface", - "bytecode 186", //"xxxunusedxxx", - "new", - "newarray", - "anewarray", - "arraylength", - "athrow", - "checkcast", - "instanceof", - "monitorenter", - "monitorexit", - null, // "wide", - "multianewarray", - "ifnull", - "ifnonnull", - "goto_w", - "jsr_w", - "bytecode 202", // "breakpoint", - "bytecode", - "try", - "endtry", - "catch", - "var", - "endvar", - "locals_map", - "stack_map" - }; - - /* Opcode Lengths */ - public static final int opcLengthsTab[] = { - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 2, - 3, - 2, - 3, - 3, - 2, - 2, - 2, - 2, - 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 2, - 99, - 99, - 1, - 1, - 1, - 1, - 1, - 1, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 5, - 0, - 3, - 2, - 3, - 1, - 1, - 3, - 3, - 1, - 1, - 0, // wide - 4, - 3, - 3, - 5, - 5, - 1, - 1, 0, 0, 0, 0, 0 // pseudo - }; - - /** - * End of input - */ - public static final int EOF = -1; - - /* - * Flags - */ - public static final int F_VERBOSE = 1 << 0; - public static final int F_DUMP = 1 << 1; - public static final int F_WARNINGS = 1 << 2; - public static final int F_DEBUG = 1 << 3; - public static final int F_OPTIMIZE = 1 << 4; - public static final int F_DEPENDENCIES = 1 << 5; - - /* - * Type codes - */ - public static final int TC_BOOLEAN = 0; - public static final int TC_BYTE = 1; - public static final int TC_CHAR = 2; - public static final int TC_SHORT = 3; - public static final int TC_INT = 4; - public static final int TC_LONG = 5; - public static final int TC_FLOAT = 6; - public static final int TC_DOUBLE = 7; - public static final int TC_NULL = 8; - public static final int TC_ARRAY = 9; - public static final int TC_CLASS = 10; - public static final int TC_VOID = 11; - public static final int TC_METHOD = 12; - public static final int TC_ERROR = 13; - - /* - * Type Masks - */ - public static final int TM_NULL = 1 << TC_NULL; - public static final int TM_VOID = 1 << TC_VOID; - public static final int TM_BOOLEAN = 1 << TC_BOOLEAN; - public static final int TM_BYTE = 1 << TC_BYTE; - public static final int TM_CHAR = 1 << TC_CHAR; - public static final int TM_SHORT = 1 << TC_SHORT; - public static final int TM_INT = 1 << TC_INT; - public static final int TM_LONG = 1 << TC_LONG; - public static final int TM_FLOAT = 1 << TC_FLOAT; - public static final int TM_DOUBLE = 1 << TC_DOUBLE; - public static final int TM_ARRAY = 1 << TC_ARRAY; - public static final int TM_CLASS = 1 << TC_CLASS; - public static final int TM_METHOD = 1 << TC_METHOD; - public static final int TM_ERROR = 1 << TC_ERROR; - - public static final int TM_INT32 = TM_BYTE | TM_SHORT | TM_CHAR | TM_INT; - public static final int TM_NUM32 = TM_INT32 | TM_FLOAT; - public static final int TM_NUM64 = TM_LONG | TM_DOUBLE; - public static final int TM_INTEGER = TM_INT32 | TM_LONG; - public static final int TM_REAL = TM_FLOAT | TM_DOUBLE; - public static final int TM_NUMBER = TM_INTEGER | TM_REAL; - public static final int TM_REFERENCE = TM_ARRAY | TM_CLASS | TM_NULL; - - /* - * Class status - */ - public static final int CS_UNDEFINED = 0; - public static final int CS_UNDECIDED = 1; - public static final int CS_BINARY = 2; - public static final int CS_SOURCE = 3; - public static final int CS_PARSED = 4; - public static final int CS_COMPILED = 5; - public static final int CS_NOTFOUND = 6; - - /* - * Attributes - */ - public static final int ATT_ALL = -1; - public static final int ATT_CODE = 1; - - /* - * Number of bits used in file offsets - */ - public static final int OFFSETBITS = 19; - public static final int MAXFILESIZE = (1 << OFFSETBITS) - 1; - public static final int MAXLINENUMBER = (1 << (32 - OFFSETBITS)) - 1; - - /* - * Operators - */ - public final int COMMA = 0; - public final int ASSIGN = 1; - - public final int ASGMUL = 2; - public final int ASGDIV = 3; - public final int ASGREM = 4; - public final int ASGADD = 5; - public final int ASGSUB = 6; - public final int ASGLSHIFT = 7; - public final int ASGRSHIFT = 8; - public final int ASGURSHIFT = 9; - public final int ASGBITAND = 10; - public final int ASGBITOR = 11; - public final int ASGBITXOR = 12; - - public final int COND = 13; - public final int OR = 14; - public final int AND = 15; - public final int BITOR = 16; - public final int BITXOR = 17; - public final int BITAND = 18; - public final int NE = 19; - public final int EQ = 20; - public final int GE = 21; - public final int GT = 22; - public final int LE = 23; - public final int LT = 24; - public final int INSTANCEOF = 25; - public final int LSHIFT = 26; - public final int RSHIFT = 27; - public final int URSHIFT = 28; - public final int ADD = 29; - public final int SUB = 30; - public final int DIV = 31; - public final int REM = 32; - public final int MUL = 33; - public final int CAST = 34; // (x)y - public final int POS = 35; // +x - public final int NEG = 36; // -x - public final int NOT = 37; - public final int BITNOT = 38; - public final int PREINC = 39; // ++x - public final int PREDEC = 40; // --x - public final int NEWARRAY = 41; - public final int NEWINSTANCE = 42; - public final int NEWFROMNAME = 43; - public final int POSTINC = 44; // x++ - public final int POSTDEC = 45; // x-- - public final int FIELD = 46; - public final int METHOD = 47; // x(y) - public final int ARRAYACCESS = 48; // x[y] - public final int NEW = 49; - public final int INC = 50; - public final int DEC = 51; - - public final int CONVERT = 55; // implicit conversion - public final int EXPR = 56; // (x) - public final int ARRAY = 57; // {x, y, ...} - public final int GOTO = 58; - - /* - * Value tokens - */ - public final int IDENT = 60; - public final int BOOLEANVAL = 61; - public final int BYTEVAL = 62; - public final int CHARVAL = 63; - public final int SHORTVAL = 64; - public final int INTVAL = 65; - public final int LONGVAL = 66; - public final int FLOATVAL = 67; - public final int DOUBLEVAL = 68; - public final int STRINGVAL = 69; - - /* - * Type keywords - */ - public final int BYTE = 70; - public final int CHAR = 71; - public final int SHORT = 72; - public final int INT = 73; - public final int LONG = 74; - public final int FLOAT = 75; - public final int DOUBLE = 76; - public final int VOID = 77; - public final int BOOLEAN = 78; - - /* - * Expression keywords - */ - public final int TRUE = 80; - public final int FALSE = 81; - public final int THIS = 82; - public final int SUPER = 83; - public final int NULL = 84; - - /* - * Statement keywords - */ - public final int IF = 90; - public final int ELSE = 91; - public final int FOR = 92; - public final int WHILE = 93; - public final int DO = 94; - public final int SWITCH = 95; - public final int CASE = 96; - public final int DEFAULT = 97; - public final int BREAK = 98; - public final int CONTINUE = 99; - public final int RETURN = 100; - public final int TRY = 101; - public final int CATCH = 102; - public final int FINALLY = 103; - public final int THROW = 104; - public final int STAT = 105; - public final int EXPRESSION = 106; - public final int DECLARATION = 107; - public final int VARDECLARATION = 108; - - /* - * Declaration keywords - */ - public final int IMPORT = 110; - public final int CLASS = 111; - public final int EXTENDS = 112; - public final int IMPLEMENTS = 113; - public final int INTERFACE = 114; - public final int PACKAGE = 115; - - /* - * Modifier keywords - */ - public final int PRIVATE = 120; - public final int PUBLIC = 121; - public final int PROTECTED = 122; - public final int CONST = 123; - public final int STATIC = 124; - public final int TRANSIENT = 125; - public final int SYNCHRONIZED = 126; - public final int NATIVE = 127; - public final int FINAL = 128; - public final int VOLATILE = 129; - public final int ABSTRACT = 130; - public final int STRICT = 165; - - /* - * Punctuation - */ - public final int SEMICOLON = 135; - public final int COLON = 136; - public final int QUESTIONMARK = 137; - public final int LBRACE = 138; - public final int RBRACE = 139; - public final int LPAREN = 140; - public final int RPAREN = 141; - public final int LSQBRACKET = 142; - public final int RSQBRACKET = 143; - public final int THROWS = 144; - - /* - * Special tokens - */ - public final int ERROR = 145; // an error - public final int COMMENT = 146; // not used anymore. - public final int TYPE = 147; - public final int LENGTH = 148; - public final int INLINERETURN = 149; - public final int INLINEMETHOD = 150; - public final int INLINENEWINSTANCE = 151; - - /* - * Added for jasm - */ - public final int METHODREF = 152; - public final int FIELDREF = 153; - public final int STACK = 154; - public final int LOCAL = 155; - public final int CPINDEX = 156; - public final int CPNAME = 157; - public final int SIGN = 158; - public final int BITS = 159; - public final int INF = 160; - public final int NAN = 161; - public final int INNERCLASS = 162; - public final int OF = 163; - public final int SYNTHETIC = 164; -// last used=165; - - /* - * Operator precedence - */ - public static final int opPrecedence[] = { - 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 12, 13, 14, 15, 16, 17, 18, - 18, 19, 19, 19, 19, 19, 20, 20, 20, 21, - 21, 22, 22, 22, 23, 24, 24, 24, 24, 24, - 24, 25, 25, 26, 26, 26, 26, 26, 26 - }; - - /* - * Operator names - */ - public static final String opNames[] = { - ",", "=", "*=", "/=", "%=", - "+=", "-=", "<<=", ">>=", "<<<=", - "&=", "|=", "^=", "?:", "||", - "&&", "|", "^", "&", "!=", - "==", ">=", ">", "<=", "<", - "instanceof", "<<", ">>", "<<<", "+", - "-", "/", "%", "*", "cast", - "+", "-", "!", "~", "++", - "--", "new", "new", "new", "++", - "--", "field", "method", "[]", "new", - "++", "--", null, null, null, - - "convert", "expr", "array", "goto", null, - - "Identifier", "Boolean", "Byte", "Char", "Short", - "Integer", "Long", "Float", "Double", "String", - - "byte", "char", "short", "int", "long", - "float", "double", "void", "boolean", null, - - "true", "false", "this", "super", "null", - null, null, null, null, null, - - "if", "else", "for", "while", "do", - "switch", "case", "default", "break", "continue", - "return", "try", "catch", "finally", "throw", - "stat", "expression", "declaration", "declaration", null, - - "import", "class", "extends", "implements", "interface", - "package", null, null, null, null, - - "private", "public", "protected", "const", "static", - "transient", "synchronized", "native", "final", "volatile", - "abstract", null, null, null, null, - - ";", ":", "?", "{", "}", - "(", ")", "[", "]", "throws", - "error", "comment", "type", "length", "inline-return", - "inline-method", "inline-new", - "method", "field", "stack", "locals", "CPINDEX", "CPName", "SIGN", - "bits", "INF", "NaN", "InnerClass", "of", "synthetic" - }; - +*/ static class AnnotationParser { private final boolean textual; @@ -1332,15 +535,11 @@ private int super_class; private int interfaces_count; private int[] interfaces = new int[0]; - private int fields_count; private FieldData[] fields; - private int methods_count; private MethodData[] methods; private InnerClassData[] innerClasses; private int attributes_count; private AttrData[] attrs; - private String classname; - private String superclassname; private int source_cpx = 0; private byte tags[]; private Hashtable indexHashAscii = new Hashtable(); @@ -2062,7 +1261,7 @@ int name_index; int descriptor_index; int attributes_count; - int value_cpx = 0; + int value_cpx = -1; boolean isSynthetic = false; boolean isDeprecated = false; Vector attrs; @@ -2183,11 +1382,8 @@ return isDeprecated; } - /** - * Returns index of constant value in cpool. - */ - public int getConstantValueIndex() { - return (value_cpx); + public boolean hasConstantValue() { + return value_cpx != -1; } /** @@ -2806,6 +2002,10 @@ lastFrameByteCodeOffset = -1; advanceBy(0); } + + public boolean isEmpty() { + return stackMapTable.length == 0; + } public String getFrameAsString() { return (nextFrameIndex == 0) diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Wed Feb 19 08:10:04 2014 +0100 @@ -153,6 +153,11 @@ } for (FieldData v : jc.getFields()) { if (v.isStatic()) { + if ((v.access & ACC_FINAL) != 0 && v.hasConstantValue()) { + if (v.getInternalSig().length() == 1 || v.getInternalSig().equals("Ljava/lang/String;")) { + continue; + } + } out.append("\n CLS.fld_").append(v.getName()).append(initField(v)); out.append("\n c._").append(v.getName()).append(" = function (v) {") .append(" if (arguments.length == 1) CLS.fld_").append(v.getName()) @@ -322,11 +327,19 @@ out.append(" var ").append(" lcA0 = this;\n"); } - int lastStackFrame = -1; + int lastStackFrame; TrapData[] previousTrap = null; boolean wide = false; + boolean didBranches; + if (stackMapIterator.isEmpty()) { + didBranches = false; + lastStackFrame = 0; + } else { + didBranches = true; + lastStackFrame = -1; + out.append("\n var gt = 0;\n"); + } - out.append("\n var gt = 0;\n"); int openBraces = 0; int topMostLabel = 0; for (int i = 0; i < byteCodes.length; i++) { @@ -340,6 +353,7 @@ } } if (lastStackFrame != stackMapIterator.getFrameIndex()) { + smapper.flush(out); if (i != 0) { out.append(" }\n"); } @@ -367,72 +381,71 @@ final int c = readUByte(byteCodes, i); switch (c) { case opc_aload_0: - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(0)); + smapper.assign(out, VarType.REFERENCE, lmapper.getA(0)); break; case opc_iload_0: - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(0)); + smapper.assign(out, VarType.INTEGER, lmapper.getI(0)); break; case opc_lload_0: - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(0)); + smapper.assign(out, VarType.LONG, lmapper.getL(0)); break; case opc_fload_0: - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(0)); + smapper.assign(out, VarType.FLOAT, lmapper.getF(0)); break; case opc_dload_0: - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(0)); + smapper.assign(out, VarType.DOUBLE, lmapper.getD(0)); break; case opc_aload_1: - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(1)); + smapper.assign(out, VarType.REFERENCE, lmapper.getA(1)); break; case opc_iload_1: - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(1)); + smapper.assign(out, VarType.INTEGER, lmapper.getI(1)); break; case opc_lload_1: - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(1)); + smapper.assign(out, VarType.LONG, lmapper.getL(1)); break; case opc_fload_1: - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(1)); + smapper.assign(out, VarType.FLOAT, lmapper.getF(1)); break; case opc_dload_1: - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(1)); + smapper.assign(out, VarType.DOUBLE, lmapper.getD(1)); break; case opc_aload_2: - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(2)); + smapper.assign(out, VarType.REFERENCE, lmapper.getA(2)); break; case opc_iload_2: - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(2)); + smapper.assign(out, VarType.INTEGER, lmapper.getI(2)); break; case opc_lload_2: - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(2)); + smapper.assign(out, VarType.LONG, lmapper.getL(2)); break; case opc_fload_2: - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(2)); + smapper.assign(out, VarType.FLOAT, lmapper.getF(2)); break; case opc_dload_2: - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(2)); + smapper.assign(out, VarType.DOUBLE, lmapper.getD(2)); break; case opc_aload_3: - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(3)); + smapper.assign(out, VarType.REFERENCE, lmapper.getA(3)); break; case opc_iload_3: - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(3)); + smapper.assign(out, VarType.INTEGER, lmapper.getI(3)); break; case opc_lload_3: - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(3)); + smapper.assign(out, VarType.LONG, lmapper.getL(3)); break; case opc_fload_3: - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(3)); + smapper.assign(out, VarType.FLOAT, lmapper.getF(3)); break; case opc_dload_3: - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(3)); + smapper.assign(out, VarType.DOUBLE, lmapper.getD(3)); break; case opc_iload: { ++i; final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", - smapper.pushI(), lmapper.getI(indx)); + smapper.assign(out, VarType.INTEGER, lmapper.getI(indx)); break; } case opc_lload: { @@ -440,8 +453,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", - smapper.pushL(), lmapper.getL(indx)); + smapper.assign(out, VarType.LONG, lmapper.getL(indx)); break; } case opc_fload: { @@ -449,8 +461,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", - smapper.pushF(), lmapper.getF(indx)); + smapper.assign(out, VarType.FLOAT, lmapper.getF(indx)); break; } case opc_dload: { @@ -458,8 +469,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", - smapper.pushD(), lmapper.getD(indx)); + smapper.assign(out, VarType.DOUBLE, lmapper.getD(indx)); break; } case opc_aload: { @@ -467,8 +477,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", - smapper.pushA(), lmapper.getA(indx)); + smapper.assign(out, VarType.REFERENCE, lmapper.getA(indx)); break; } case opc_istore: { @@ -476,7 +485,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", + emit(smapper, out, "var @1 = @2;", lmapper.setI(indx), smapper.popI()); break; } @@ -485,7 +494,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", + emit(smapper, out, "var @1 = @2;", lmapper.setL(indx), smapper.popL()); break; } @@ -494,7 +503,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", + emit(smapper, out, "var @1 = @2;", lmapper.setF(indx), smapper.popF()); break; } @@ -503,7 +512,7 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", + emit(smapper, out, "var @1 = @2;", lmapper.setD(indx), smapper.popD()); break; } @@ -512,181 +521,181 @@ final int indx = wide ? readUShort(byteCodes, i++) : readUByte(byteCodes, i); wide = false; - emit(out, "var @1 = @2;", + emit(smapper, out, "var @1 = @2;", lmapper.setA(indx), smapper.popA()); break; } case opc_astore_0: - emit(out, "var @1 = @2;", lmapper.setA(0), smapper.popA()); + emit(smapper, out, "var @1 = @2;", lmapper.setA(0), smapper.popA()); break; case opc_istore_0: - emit(out, "var @1 = @2;", lmapper.setI(0), smapper.popI()); + emit(smapper, out, "var @1 = @2;", lmapper.setI(0), smapper.popI()); break; case opc_lstore_0: - emit(out, "var @1 = @2;", lmapper.setL(0), smapper.popL()); + emit(smapper, out, "var @1 = @2;", lmapper.setL(0), smapper.popL()); break; case opc_fstore_0: - emit(out, "var @1 = @2;", lmapper.setF(0), smapper.popF()); + emit(smapper, out, "var @1 = @2;", lmapper.setF(0), smapper.popF()); break; case opc_dstore_0: - emit(out, "var @1 = @2;", lmapper.setD(0), smapper.popD()); + emit(smapper, out, "var @1 = @2;", lmapper.setD(0), smapper.popD()); break; case opc_astore_1: - emit(out, "var @1 = @2;", lmapper.setA(1), smapper.popA()); + emit(smapper, out, "var @1 = @2;", lmapper.setA(1), smapper.popA()); break; case opc_istore_1: - emit(out, "var @1 = @2;", lmapper.setI(1), smapper.popI()); + emit(smapper, out, "var @1 = @2;", lmapper.setI(1), smapper.popI()); break; case opc_lstore_1: - emit(out, "var @1 = @2;", lmapper.setL(1), smapper.popL()); + emit(smapper, out, "var @1 = @2;", lmapper.setL(1), smapper.popL()); break; case opc_fstore_1: - emit(out, "var @1 = @2;", lmapper.setF(1), smapper.popF()); + emit(smapper, out, "var @1 = @2;", lmapper.setF(1), smapper.popF()); break; case opc_dstore_1: - emit(out, "var @1 = @2;", lmapper.setD(1), smapper.popD()); + emit(smapper, out, "var @1 = @2;", lmapper.setD(1), smapper.popD()); break; case opc_astore_2: - emit(out, "var @1 = @2;", lmapper.setA(2), smapper.popA()); + emit(smapper, out, "var @1 = @2;", lmapper.setA(2), smapper.popA()); break; case opc_istore_2: - emit(out, "var @1 = @2;", lmapper.setI(2), smapper.popI()); + emit(smapper, out, "var @1 = @2;", lmapper.setI(2), smapper.popI()); break; case opc_lstore_2: - emit(out, "var @1 = @2;", lmapper.setL(2), smapper.popL()); + emit(smapper, out, "var @1 = @2;", lmapper.setL(2), smapper.popL()); break; case opc_fstore_2: - emit(out, "var @1 = @2;", lmapper.setF(2), smapper.popF()); + emit(smapper, out, "var @1 = @2;", lmapper.setF(2), smapper.popF()); break; case opc_dstore_2: - emit(out, "var @1 = @2;", lmapper.setD(2), smapper.popD()); + emit(smapper, out, "var @1 = @2;", lmapper.setD(2), smapper.popD()); break; case opc_astore_3: - emit(out, "var @1 = @2;", lmapper.setA(3), smapper.popA()); + emit(smapper, out, "var @1 = @2;", lmapper.setA(3), smapper.popA()); break; case opc_istore_3: - emit(out, "var @1 = @2;", lmapper.setI(3), smapper.popI()); + emit(smapper, out, "var @1 = @2;", lmapper.setI(3), smapper.popI()); break; case opc_lstore_3: - emit(out, "var @1 = @2;", lmapper.setL(3), smapper.popL()); + emit(smapper, out, "var @1 = @2;", lmapper.setL(3), smapper.popL()); break; case opc_fstore_3: - emit(out, "var @1 = @2;", lmapper.setF(3), smapper.popF()); + emit(smapper, out, "var @1 = @2;", lmapper.setF(3), smapper.popF()); break; case opc_dstore_3: - emit(out, "var @1 = @2;", lmapper.setD(3), smapper.popD()); + emit(smapper, out, "var @1 = @2;", lmapper.setD(3), smapper.popD()); break; case opc_iadd: - emit(out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI()); + smapper.replace(out, VarType.INTEGER, "(@1).add32(@2)", smapper.getI(1), smapper.popI()); break; case opc_ladd: - emit(out, "@1 = @1.add64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(out, VarType.LONG, "(@1).add64(@2)", smapper.getL(1), smapper.popL()); break; case opc_fadd: - emit(out, "@1 += @2;", smapper.getF(1), smapper.popF()); + smapper.replace(out, VarType.FLOAT, "(@1 + @2)", smapper.getF(1), smapper.popF()); break; case opc_dadd: - emit(out, "@1 += @2;", smapper.getD(1), smapper.popD()); + smapper.replace(out, VarType.DOUBLE, "(@1 + @2)", smapper.getD(1), smapper.popD()); break; case opc_isub: - emit(out, "@1 = @1.sub32(@2);", smapper.getI(1), smapper.popI()); + smapper.replace(out, VarType.INTEGER, "(@1).sub32(@2)", smapper.getI(1), smapper.popI()); break; case opc_lsub: - emit(out, "@1 = @1.sub64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(out, VarType.LONG, "(@1).sub64(@2)", smapper.getL(1), smapper.popL()); break; case opc_fsub: - emit(out, "@1 -= @2;", smapper.getF(1), smapper.popF()); + smapper.replace(out, VarType.FLOAT, "(@1 - @2)", smapper.getF(1), smapper.popF()); break; case opc_dsub: - emit(out, "@1 -= @2;", smapper.getD(1), smapper.popD()); + smapper.replace(out, VarType.DOUBLE, "(@1 - @2)", smapper.getD(1), smapper.popD()); break; case opc_imul: - emit(out, "@1 = @1.mul32(@2);", smapper.getI(1), smapper.popI()); + smapper.replace(out, VarType.INTEGER, "(@1).mul32(@2)", smapper.getI(1), smapper.popI()); break; case opc_lmul: - emit(out, "@1 = @1.mul64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(out, VarType.LONG, "(@1).mul64(@2)", smapper.getL(1), smapper.popL()); break; case opc_fmul: - emit(out, "@1 *= @2;", smapper.getF(1), smapper.popF()); + smapper.replace(out, VarType.FLOAT, "(@1 * @2)", smapper.getF(1), smapper.popF()); break; case opc_dmul: - emit(out, "@1 *= @2;", smapper.getD(1), smapper.popD()); + smapper.replace(out, VarType.DOUBLE, "(@1 * @2)", smapper.getD(1), smapper.popD()); break; case opc_idiv: - emit(out, "@1 = @1.div32(@2);", + smapper.replace(out, VarType.INTEGER, "(@1).div32(@2)", smapper.getI(1), smapper.popI()); break; case opc_ldiv: - emit(out, "@1 = @1.div64(@2);", + smapper.replace(out, VarType.LONG, "(@1).div64(@2)", smapper.getL(1), smapper.popL()); break; case opc_fdiv: - emit(out, "@1 /= @2;", smapper.getF(1), smapper.popF()); + smapper.replace(out, VarType.FLOAT, "(@1 / @2)", smapper.getF(1), smapper.popF()); break; case opc_ddiv: - emit(out, "@1 /= @2;", smapper.getD(1), smapper.popD()); + smapper.replace(out, VarType.DOUBLE, "(@1 / @2)", smapper.getD(1), smapper.popD()); break; case opc_irem: - emit(out, "@1 = @1.mod32(@2);", + smapper.replace(out, VarType.INTEGER, "(@1).mod32(@2)", smapper.getI(1), smapper.popI()); break; case opc_lrem: - emit(out, "@1 = @1.mod64(@2);", + smapper.replace(out, VarType.LONG, "(@1).mod64(@2)", smapper.getL(1), smapper.popL()); break; case opc_frem: - emit(out, "@1 %= @2;", smapper.getF(1), smapper.popF()); + smapper.replace(out, VarType.FLOAT, "(@1 % @2)", smapper.getF(1), smapper.popF()); break; case opc_drem: - emit(out, "@1 %= @2;", smapper.getD(1), smapper.popD()); + smapper.replace(out, VarType.DOUBLE, "(@1 % @2)", smapper.getD(1), smapper.popD()); break; case opc_iand: - emit(out, "@1 &= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(out, VarType.INTEGER, "(@1 & @2)", smapper.getI(1), smapper.popI()); break; case opc_land: - emit(out, "@1 = @1.and64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(out, VarType.LONG, "(@1).and64(@2)", smapper.getL(1), smapper.popL()); break; case opc_ior: - emit(out, "@1 |= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(out, VarType.INTEGER, "(@1 | @2)", smapper.getI(1), smapper.popI()); break; case opc_lor: - emit(out, "@1 = @1.or64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(out, VarType.LONG, "(@1).or64(@2)", smapper.getL(1), smapper.popL()); break; case opc_ixor: - emit(out, "@1 ^= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(out, VarType.INTEGER, "(@1 ^ @2)", smapper.getI(1), smapper.popI()); break; case opc_lxor: - emit(out, "@1 = @1.xor64(@2);", smapper.getL(1), smapper.popL()); + smapper.replace(out, VarType.LONG, "(@1).xor64(@2)", smapper.getL(1), smapper.popL()); break; case opc_ineg: - emit(out, "@1 = @1.neg32();", smapper.getI(0)); + smapper.replace(out, VarType.INTEGER, "(@1).neg32()", smapper.getI(0)); break; case opc_lneg: - emit(out, "@1 = @1.neg64();", smapper.getL(0)); + smapper.replace(out, VarType.LONG, "(@1).neg64()", smapper.getL(0)); break; case opc_fneg: - emit(out, "@1 = -@1;", smapper.getF(0)); + smapper.replace(out, VarType.FLOAT, "(-@1)", smapper.getF(0)); break; case opc_dneg: - emit(out, "@1 = -@1;", smapper.getD(0)); + smapper.replace(out, VarType.DOUBLE, "(-@1)", smapper.getD(0)); break; case opc_ishl: - emit(out, "@1 <<= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(out, VarType.INTEGER, "(@1 << @2)", smapper.getI(1), smapper.popI()); break; case opc_lshl: - emit(out, "@1 = @1.shl64(@2);", smapper.getL(1), smapper.popI()); + smapper.replace(out, VarType.LONG, "(@1).shl64(@2)", smapper.getL(1), smapper.popI()); break; case opc_ishr: - emit(out, "@1 >>= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(out, VarType.INTEGER, "(@1 >> @2)", smapper.getI(1), smapper.popI()); break; case opc_lshr: - emit(out, "@1 = @1.shr64(@2);", smapper.getL(1), smapper.popI()); + smapper.replace(out, VarType.LONG, "(@1).shr64(@2)", smapper.getL(1), smapper.popI()); break; case opc_iushr: - emit(out, "@1 >>>= @2;", smapper.getI(1), smapper.popI()); + smapper.replace(out, VarType.INTEGER, "(@1 >>> @2)", smapper.getI(1), smapper.popI()); break; case opc_lushr: - emit(out, "@1 = @1.ushr64(@2);", smapper.getL(1), smapper.popI()); + smapper.replace(out, VarType.LONG, "(@1).ushr64(@2)", smapper.getL(1), smapper.popI()); break; case opc_iinc: { ++i; @@ -697,132 +706,132 @@ : byteCodes[i]; wide = false; if (incrBy == 1) { - emit(out, "@1++;", lmapper.getI(varIndx)); + emit(smapper, out, "@1++;", lmapper.getI(varIndx)); } else { - emit(out, "@1 += @2;", + emit(smapper, out, "@1 += @2;", lmapper.getI(varIndx), Integer.toString(incrBy)); } break; } case opc_return: - emit(out, "return;"); + emit(smapper, out, "return;"); break; case opc_ireturn: - emit(out, "return @1;", smapper.popI()); + emit(smapper, out, "return @1;", smapper.popI()); break; case opc_lreturn: - emit(out, "return @1;", smapper.popL()); + emit(smapper, out, "return @1;", smapper.popL()); break; case opc_freturn: - emit(out, "return @1;", smapper.popF()); + emit(smapper, out, "return @1;", smapper.popF()); break; case opc_dreturn: - emit(out, "return @1;", smapper.popD()); + emit(smapper, out, "return @1;", smapper.popD()); break; case opc_areturn: - emit(out, "return @1;", smapper.popA()); + emit(smapper, out, "return @1;", smapper.popA()); break; case opc_i2l: - emit(out, "var @2 = @1;", smapper.popI(), smapper.pushL()); + smapper.replace(out, VarType.LONG, "@1", smapper.getI(0)); break; case opc_i2f: - emit(out, "var @2 = @1;", smapper.popI(), smapper.pushF()); + smapper.replace(out, VarType.FLOAT, "@1", smapper.getI(0)); break; case opc_i2d: - emit(out, "var @2 = @1;", smapper.popI(), smapper.pushD()); + smapper.replace(out, VarType.DOUBLE, "@1", smapper.getI(0)); break; case opc_l2i: - emit(out, "var @2 = @1.toInt32();", smapper.popL(), smapper.pushI()); + smapper.replace(out, VarType.INTEGER, "(@1).toInt32()", smapper.getL(0)); break; // max int check? case opc_l2f: - emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushF()); + smapper.replace(out, VarType.FLOAT, "(@1).toFP()", smapper.getL(0)); break; case opc_l2d: - emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushD()); + smapper.replace(out, VarType.DOUBLE, "(@1).toFP()", smapper.getL(0)); break; case opc_f2d: - emit(out, "var @2 = @1;", smapper.popF(), smapper.pushD()); + smapper.replace(out, VarType.DOUBLE, "@1", + smapper.getF(0)); break; case opc_d2f: - emit(out, "var @2 = @1;", smapper.popD(), smapper.pushF()); + smapper.replace(out, VarType.FLOAT, "@1", + smapper.getD(0)); break; case opc_f2i: - emit(out, "var @2 = @1.toInt32();", - smapper.popF(), smapper.pushI()); + smapper.replace(out, VarType.INTEGER, "(@1).toInt32()", + smapper.getF(0)); break; case opc_f2l: - emit(out, "var @2 = @1.toLong();", - smapper.popF(), smapper.pushL()); + smapper.replace(out, VarType.LONG, "(@1).toLong()", + smapper.getF(0)); break; case opc_d2i: - emit(out, "var @2 = @1.toInt32();", - smapper.popD(), smapper.pushI()); + smapper.replace(out, VarType.INTEGER, "(@1).toInt32()", + smapper.getD(0)); break; case opc_d2l: - emit(out, "var @2 = @1.toLong();", - smapper.popD(), smapper.pushL()); + smapper.replace(out, VarType.LONG, "(@1).toLong()", smapper.getD(0)); break; case opc_i2b: - emit(out, "var @1 = @1.toInt8();", smapper.getI(0)); + smapper.replace(out, VarType.INTEGER, "(@1).toInt8()", smapper.getI(0)); break; case opc_i2c: - out.append("{ /* number conversion */ }"); break; case opc_i2s: - emit(out, "var @1 = @1.toInt16();", smapper.getI(0)); + smapper.replace(out, VarType.INTEGER, "(@1).toInt16()", smapper.getI(0)); break; case opc_aconst_null: - emit(out, "var @1 = null;", smapper.pushA()); + smapper.assign(out, VarType.REFERENCE, "null"); break; case opc_iconst_m1: - emit(out, "var @1 = -1;", smapper.pushI()); + smapper.assign(out, VarType.INTEGER, "-1"); break; case opc_iconst_0: - emit(out, "var @1 = 0;", smapper.pushI()); + smapper.assign(out, VarType.INTEGER, "0"); break; case opc_dconst_0: - emit(out, "var @1 = 0;", smapper.pushD()); + smapper.assign(out, VarType.DOUBLE, "0"); break; case opc_lconst_0: - emit(out, "var @1 = 0;", smapper.pushL()); + smapper.assign(out, VarType.LONG, "0"); break; case opc_fconst_0: - emit(out, "var @1 = 0;", smapper.pushF()); + smapper.assign(out, VarType.FLOAT, "0"); break; case opc_iconst_1: - emit(out, "var @1 = 1;", smapper.pushI()); + smapper.assign(out, VarType.INTEGER, "1"); break; case opc_lconst_1: - emit(out, "var @1 = 1;", smapper.pushL()); + smapper.assign(out, VarType.LONG, "1"); break; case opc_fconst_1: - emit(out, "var @1 = 1;", smapper.pushF()); + smapper.assign(out, VarType.FLOAT, "1"); break; case opc_dconst_1: - emit(out, "var @1 = 1;", smapper.pushD()); + smapper.assign(out, VarType.DOUBLE, "1"); break; case opc_iconst_2: - emit(out, "var @1 = 2;", smapper.pushI()); + smapper.assign(out, VarType.INTEGER, "2"); break; case opc_fconst_2: - emit(out, "var @1 = 2;", smapper.pushF()); + smapper.assign(out, VarType.FLOAT, "2"); break; case opc_iconst_3: - emit(out, "var @1 = 3;", smapper.pushI()); + smapper.assign(out, VarType.INTEGER, "3"); break; case opc_iconst_4: - emit(out, "var @1 = 4;", smapper.pushI()); + smapper.assign(out, VarType.INTEGER, "4"); break; case opc_iconst_5: - emit(out, "var @1 = 5;", smapper.pushI()); + smapper.assign(out, VarType.INTEGER, "5"); break; case opc_ldc: { int indx = readUByte(byteCodes, ++i); String v = encodeConstant(indx); int type = VarType.fromConstantType(jc.getTag(indx)); - emit(out, "var @1 = @2;", smapper.pushT(type), v); + smapper.assign(out, type, v); break; } case opc_ldc_w: @@ -835,116 +844,120 @@ final Long lv = new Long(v); final int low = (int)(lv.longValue() & 0xFFFFFFFF); final int hi = (int)(lv.longValue() >> 32); - emit(out, "var @1 = 0x@3.next32(0x@2);", smapper.pushL(), - Integer.toHexString(low), Integer.toHexString(hi)); + if (hi == 0) { + smapper.assign(out, VarType.LONG, "0x" + Integer.toHexString(low)); + } else { + smapper.assign(out, VarType.LONG, + "0x" + Integer.toHexString(hi) + ".next32(0x" + + Integer.toHexString(low) + ")" + ); + } } else { - emit(out, "var @1 = @2;", smapper.pushT(type), v); + smapper.assign(out, type, v); } break; } case opc_lcmp: - emit(out, "var @3 = @2.compare64(@1);", - smapper.popL(), smapper.popL(), smapper.pushI()); + smapper.replace(out, VarType.INTEGER, "(@2).compare64(@1)", smapper.popL(), smapper.getL(0)); break; case opc_fcmpl: case opc_fcmpg: - emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", - smapper.popF(), smapper.popF(), smapper.pushI()); + smapper.replace(out, VarType.INTEGER, "(@2).compare(@1)", smapper.popF(), smapper.getF(0)); break; case opc_dcmpl: case opc_dcmpg: - emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", - smapper.popD(), smapper.popD(), smapper.pushI()); + smapper.replace(out, VarType.INTEGER, "(@2).compare(@1)", smapper.popD(), smapper.getD(0)); break; case opc_if_acmpeq: - i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(), + i = generateIf(smapper, byteCodes, i, smapper.popA(), smapper.popA(), "===", topMostLabel); break; case opc_if_acmpne: - i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(), + i = generateIf(smapper, byteCodes, i, smapper.popA(), smapper.popA(), "!==", topMostLabel); break; case opc_if_icmpeq: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), "==", topMostLabel); break; case opc_ifeq: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 == 0) ", + emitIf(smapper, out, "if ((@1) == 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifne: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 != 0) ", + emitIf(smapper, out, "if ((@1) != 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_iflt: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 < 0) ", + emitIf(smapper, out, "if ((@1) < 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifle: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 <= 0) ", + emitIf(smapper, out, "if ((@1) <= 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifgt: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 > 0) ", + emitIf(smapper, out, "if ((@1) > 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifge: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 >= 0) ", + emitIf(smapper, out, "if ((@1) >= 0) ", smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifnonnull: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 !== null) ", + emitIf(smapper, out, "if ((@1) !== null) ", smapper.popA(), i, indx, topMostLabel); i += 2; break; } case opc_ifnull: { int indx = i + readShortArg(byteCodes, i); - emitIf(out, "if (@1 === null) ", + emitIf(smapper, out, "if ((@1) === null) ", smapper.popA(), i, indx, topMostLabel); i += 2; break; } case opc_if_icmpne: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), "!=", topMostLabel); break; case opc_if_icmplt: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), "<", topMostLabel); break; case opc_if_icmple: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), "<=", topMostLabel); break; case opc_if_icmpgt: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), ">", topMostLabel); break; case opc_if_icmpge: - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(), ">=", topMostLabel); break; case opc_goto: { + smapper.flush(out); int indx = i + readShortArg(byteCodes, i); goTo(out, i, indx, topMostLabel); i += 2; @@ -974,7 +987,7 @@ case opc_new: { int indx = readUShortArg(byteCodes, i); String ci = jc.getClassName(indx); - emit(out, "var @1 = new @2;", + emit(smapper, out, "var @1 = new @2;", smapper.pushA(), accessClass(mangleClassName(ci))); addReference(ci); i += 2; @@ -997,54 +1010,53 @@ break; } case opc_arraylength: - emit(out, "var @2 = @1.length;", - smapper.popA(), smapper.pushI()); + smapper.replace(out, VarType.INTEGER, "(@1).length", smapper.getA(0)); break; case opc_lastore: - emit(out, "Array.at(@3, @2, @1);", + emit(smapper, out, "Array.at(@3, @2, @1);", smapper.popL(), smapper.popI(), smapper.popA()); break; case opc_fastore: - emit(out, "Array.at(@3, @2, @1);", + emit(smapper, out, "Array.at(@3, @2, @1);", smapper.popF(), smapper.popI(), smapper.popA()); break; case opc_dastore: - emit(out, "Array.at(@3, @2, @1);", + emit(smapper, out, "Array.at(@3, @2, @1);", smapper.popD(), smapper.popI(), smapper.popA()); break; case opc_aastore: - emit(out, "Array.at(@3, @2, @1);", + emit(smapper, out, "Array.at(@3, @2, @1);", smapper.popA(), smapper.popI(), smapper.popA()); break; case opc_iastore: case opc_bastore: case opc_castore: case opc_sastore: - emit(out, "Array.at(@3, @2, @1);", + emit(smapper, out, "Array.at(@3, @2, @1);", smapper.popI(), smapper.popI(), smapper.popA()); break; case opc_laload: - emit(out, "var @3 = Array.at(@2, @1);", - smapper.popI(), smapper.popA(), smapper.pushL()); + smapper.replace(out, VarType.LONG, "Array.at(@2, @1)", + smapper.popI(), smapper.getA(0)); break; case opc_faload: - emit(out, "var @3 = Array.at(@2, @1);", - smapper.popI(), smapper.popA(), smapper.pushF()); + smapper.replace(out, VarType.FLOAT, "Array.at(@2, @1)", + smapper.popI(), smapper.getA(0)); break; case opc_daload: - emit(out, "var @3 = Array.at(@2, @1);", - smapper.popI(), smapper.popA(), smapper.pushD()); + smapper.replace(out, VarType.DOUBLE, "Array.at(@2, @1)", + smapper.popI(), smapper.getA(0)); break; case opc_aaload: - emit(out, "var @3 = Array.at(@2, @1);", - smapper.popI(), smapper.popA(), smapper.pushA()); + smapper.replace(out, VarType.REFERENCE, "Array.at(@2, @1)", + smapper.popI(), smapper.getA(0)); break; case opc_iaload: case opc_baload: case opc_caload: case opc_saload: - emit(out, "var @3 = Array.at(@2, @1);", - smapper.popI(), smapper.popA(), smapper.pushI()); + smapper.replace(out, VarType.INTEGER, "Array.at(@2, @1)", + smapper.popI(), smapper.getA(0)); break; case opc_pop: case opc_pop2: @@ -1053,86 +1065,86 @@ break; case opc_dup: { final Variable v = smapper.get(0); - emit(out, "var @1 = @2;", smapper.pushT(v.getType()), v); + emit(smapper, out, "var @1 = @2;", smapper.pushT(v.getType()), v); break; } case opc_dup2: { final Variable vi1 = smapper.get(0); if (vi1.isCategory2()) { - emit(out, "var @1 = @2;", + emit(smapper, out, "var @1 = @2;", smapper.pushT(vi1.getType()), vi1); } else { final Variable vi2 = smapper.get(1); - emit(out, "var @1 = @2, @3 = @4;", + emit(smapper, out, "var @1 = @2, @3 = @4;", smapper.pushT(vi2.getType()), vi2, smapper.pushT(vi1.getType()), vi1); } break; } case opc_dup_x1: { - final Variable vi1 = smapper.pop(); - final Variable vi2 = smapper.pop(); + final Variable vi1 = smapper.pop(out); + final Variable vi2 = smapper.pop(out); final Variable vo3 = smapper.pushT(vi1.getType()); final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6;", + emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); break; } case opc_dup2_x1: { - final Variable vi1 = smapper.pop(); - final Variable vi2 = smapper.pop(); + final Variable vi1 = smapper.pop(out); + final Variable vi2 = smapper.pop(out); if (vi1.isCategory2()) { final Variable vo3 = smapper.pushT(vi1.getType()); final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6;", + emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); } else { - final Variable vi3 = smapper.pop(); + final Variable vi3 = smapper.pop(out); final Variable vo5 = smapper.pushT(vi2.getType()); final Variable vo4 = smapper.pushT(vi1.getType()); final Variable vo3 = smapper.pushT(vi3.getType()); final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6,", + emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6,", vo1, vi1, vo2, vi2, vo3, vi3); - emit(out, " @1 = @2, @3 = @4;", + emit(smapper, out, " @1 = @2, @3 = @4;", vo4, vo1, vo5, vo2); } break; } case opc_dup_x2: { - final Variable vi1 = smapper.pop(); - final Variable vi2 = smapper.pop(); + final Variable vi1 = smapper.pop(out); + final Variable vi2 = smapper.pop(out); if (vi2.isCategory2()) { final Variable vo3 = smapper.pushT(vi1.getType()); final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6;", + emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); } else { - final Variable vi3 = smapper.pop(); + final Variable vi3 = smapper.pop(out); final Variable vo4 = smapper.pushT(vi1.getType()); final Variable vo3 = smapper.pushT(vi3.getType()); final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", + emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1); } break; } case opc_dup2_x2: { - final Variable vi1 = smapper.pop(); - final Variable vi2 = smapper.pop(); + final Variable vi1 = smapper.pop(out); + final Variable vi2 = smapper.pop(out); if (vi1.isCategory2()) { if (vi2.isCategory2()) { @@ -1140,20 +1152,20 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6;", + emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6;", vo1, vi1, vo2, vi2, vo3, vo1); } else { - final Variable vi3 = smapper.pop(); + final Variable vi3 = smapper.pop(out); final Variable vo4 = smapper.pushT(vi1.getType()); final Variable vo3 = smapper.pushT(vi3.getType()); final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", + emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1); } } else { - final Variable vi3 = smapper.pop(); + final Variable vi3 = smapper.pop(out); if (vi3.isCategory2()) { final Variable vo5 = smapper.pushT(vi2.getType()); @@ -1162,12 +1174,12 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6,", + emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6,", vo1, vi1, vo2, vi2, vo3, vi3); - emit(out, " @1 = @2, @3 = @4;", + emit(smapper, out, " @1 = @2, @3 = @4;", vo4, vo1, vo5, vo2); } else { - final Variable vi4 = smapper.pop(); + final Variable vi4 = smapper.pop(out); final Variable vo6 = smapper.pushT(vi2.getType()); final Variable vo5 = smapper.pushT(vi1.getType()); final Variable vo4 = smapper.pushT(vi4.getType()); @@ -1175,9 +1187,9 @@ final Variable vo2 = smapper.pushT(vi2.getType()); final Variable vo1 = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,", + emit(smapper, out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,", vo1, vi1, vo2, vi2, vo3, vi3, vo4, vi4); - emit(out, " @1 = @2, @3 = @4;", + emit(smapper, out, " @1 = @2, @3 = @4;", vo5, vo1, vo6, vo2); } } @@ -1190,7 +1202,7 @@ if (vi1.getType() == vi2.getType()) { final Variable tmp = smapper.pushT(vi1.getType()); - emit(out, "var @1 = @2, @2 = @3, @3 = @1;", + emit(smapper, out, "var @1 = @2, @2 = @3, @3 = @1;", tmp, vi1, vi2); smapper.pop(1); } else { @@ -1201,13 +1213,13 @@ break; } case opc_bipush: - emit(out, "var @1 = @2;", - smapper.pushI(), Integer.toString(byteCodes[++i])); + smapper.assign(out, VarType.INTEGER, + "(" + Integer.toString(byteCodes[++i]) + ")"); break; case opc_sipush: - emit(out, "var @1 = @2;", - smapper.pushI(), - Integer.toString(readShortArg(byteCodes, i))); + smapper.assign(out, VarType.INTEGER, + "(" + Integer.toString(readShortArg(byteCodes, i)) + ")" + ); i += 2; break; case opc_getfield: { @@ -1216,9 +1228,9 @@ final int type = VarType.fromFieldType(fi[2].charAt(0)); final String mangleClass = mangleClassName(fi[0]); final String mangleClassAccess = accessClass(mangleClass); - emit(out, "var @2 = @4(false)._@3.call(@1);", - smapper.popA(), - smapper.pushT(type), fi[1], mangleClassAccess + smapper.replace(out, type, "@3(false)._@2.call(@1)", + smapper.getA(0), + fi[1], mangleClassAccess ); i += 2; break; @@ -1229,7 +1241,7 @@ final int type = VarType.fromFieldType(fi[2].charAt(0)); final String mangleClass = mangleClassName(fi[0]); final String mangleClassAccess = accessClass(mangleClass); - emit(out, "@4(false)._@3.call(@2, @1);", + emit(smapper, out, "@4(false)._@3.call(@2, @1);", smapper.popT(type), smapper.popA(), fi[1], mangleClassAccess @@ -1241,9 +1253,8 @@ int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - emit(out, "var @1 = @2(false)._@3();", - smapper.pushT(type), - accessClass(mangleClassName(fi[0])), fi[1]); + String ac = accessClass(mangleClassName(fi[0])); + smapper.assign(out, type, ac + "(false)._" + fi[1] + "()"); i += 2; addReference(fi[0]); break; @@ -1252,7 +1263,7 @@ int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); - emit(out, "@1(false)._@2(@3);", + emit(smapper, out, "@1(false)._@2(@3);", accessClass(mangleClassName(fi[0])), fi[1], smapper.popT(type)); i += 2; @@ -1272,22 +1283,22 @@ break; } case opc_athrow: { - final Variable v = smapper.popA(); + final CharSequence v = smapper.popA(); smapper.clear(); - emit(out, "{ var @1 = @2; throw @2; }", + emit(smapper, out, "{ var @1 = @2; throw @2; }", smapper.pushA(), v); break; } case opc_monitorenter: { - out.append("/* monitor enter */"); + debug("/* monitor enter */"); smapper.popA(); break; } case opc_monitorexit: { - out.append("/* monitor exit */"); + debug("/* monitor exit */"); smapper.popA(); break; } @@ -1298,7 +1309,7 @@ default: { wide = false; - emit(out, "throw 'unknown bytecode @1';", + emit(smapper, out, "throw 'unknown bytecode @1';", Integer.toString(c)); } } @@ -1310,18 +1321,24 @@ if (previousTrap != null) { generateCatch(previousTrap, byteCodes.length, topMostLabel); } - out.append("\n }\n"); + if (didBranches) { + out.append("\n }\n"); + } while (openBraces-- > 0) { out.append('}'); } out.append("\n};"); } - private int generateIf(byte[] byteCodes, int i, final Variable v2, final Variable v1, final String test, int topMostLabel) throws IOException { + private int generateIf(StackMapper mapper, byte[] byteCodes, + int i, final CharSequence v2, final CharSequence v1, + final String test, int topMostLabel + ) throws IOException { + mapper.flush(out); int indx = i + readShortArg(byteCodes, i); - out.append("if (").append(v1) - .append(' ').append(test).append(' ') - .append(v2).append(") "); + out.append("if ((").append(v1) + .append(") ").append(test).append(" (") + .append(v2).append(")) "); goTo(out, i, indx, topMostLabel); return i + 2; } @@ -1502,10 +1519,10 @@ String mn = findMethodName(mi, cnt, returnType); final int numArguments = isStatic ? cnt.length() : cnt.length() + 1; - final Variable[] vars = new Variable[numArguments]; + final CharSequence[] vars = new CharSequence[numArguments]; for (int j = numArguments - 1; j >= 0; --j) { - vars[j] = mapper.pop(); + vars[j] = mapper.popValue(); } if (returnType[0] != 'V') { @@ -1547,10 +1564,10 @@ String mn = findMethodName(mi, cnt, returnType); final int numArguments = cnt.length() + 1; - final Variable[] vars = new Variable[numArguments]; + final CharSequence[] vars = new CharSequence[numArguments]; for (int j = numArguments - 1; j >= 0; --j) { - vars[j] = mapper.pop(); + vars[j] = mapper.popValue(); } if (returnType[0] != 'V') { @@ -1598,7 +1615,7 @@ String s = jc.stringValue(entryIndex, classRef); if (classRef[0] != null) { if (classRef[0].startsWith("[")) { - s = accessClass("java_lang_Class") + "(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('" + classRef[0] + "');"; + s = accessClass("java_lang_Class") + "(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('" + classRef[0] + "')"; } else { addReference(classRef[0]); s = accessClass(mangleClassName(s)) + "(false).constructor.$class"; @@ -1935,7 +1952,22 @@ return ","; } - private static void emit(final Appendable out, + final void emitNoFlush( + StackMapper sm, + final Appendable out, + final String format, final CharSequence... params + ) throws IOException { + emitImpl(out, format, params); + } + final void emit( + StackMapper sm, + final Appendable out, + final String format, final CharSequence... params + ) throws IOException { + sm.flush(out); + emitImpl(out, format, params); + } + static void emitImpl(final Appendable out, final String format, final CharSequence... params) throws IOException { final int length = format.length(); @@ -2001,10 +2033,13 @@ } private static void emitIf( - Appendable out, String pattern, Variable param, + StackMapper sm, + Appendable out, String pattern, + CharSequence param, int current, int to, int canBack ) throws IOException { - emit(out, pattern, param); + sm.flush(out); + emitImpl(out, pattern, param); goTo(out, current, to, canBack); } @@ -2021,7 +2056,7 @@ case 11: jvmType = "[J"; break; default: throw new IllegalStateException("Array type: " + atype); } - emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);", + emit(smapper, out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);", smapper.popI(), smapper.pushA(), jvmType); } @@ -2032,7 +2067,7 @@ } else { typeName = "[L" + typeName + ";"; } - emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);", + emit(smapper, out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);", smapper.popI(), smapper.pushA(), typeName); } @@ -2048,7 +2083,7 @@ dims.insert(1, smapper.popI()); } dims.append(']'); - emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);", + emit(smapper, out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);", dims.toString(), smapper.pushA(), typeName); return i; } @@ -2061,7 +2096,9 @@ table += 4; int high = readInt4(byteCodes, table); table += 4; - out.append("switch (").append(smapper.popI()).append(") {\n"); + final CharSequence swVar = smapper.popValue(); + smapper.flush(out); + out.append("switch (").append(swVar).append(") {\n"); while (low <= high) { int offset = i + readInt4(byteCodes, table); table += 4; @@ -2081,7 +2118,9 @@ table += 4; int n = readInt4(byteCodes, table); table += 4; - out.append("switch (").append(smapper.popI()).append(") {\n"); + final CharSequence swVar = smapper.popValue(); + smapper.flush(out); + out.append("switch (").append(swVar).append(") {\n"); while (n-- > 0) { int cnstnt = readInt4(byteCodes, table); table += 4; @@ -2099,11 +2138,11 @@ private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException { final String type = jc.getClassName(indx); if (!type.startsWith("[")) { - emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;", + emit(smapper, out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;", smapper.popA(), smapper.pushI(), type.replace('/', '_')); } else { - emit(out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);", + emit(smapper, out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);", smapper.popA(), smapper.pushI(), type ); @@ -2113,12 +2152,12 @@ private void generateCheckcast(int indx, final StackMapper smapper) throws IOException { final String type = jc.getClassName(indx); if (!type.startsWith("[")) { - emit(out, + emitNoFlush(smapper, out, "if (@1 !== null && !@1.$instOf_@2) throw vm.java_lang_ClassCastException(true);", - smapper.getA(0), type.replace('/', '_')); + smapper.getT(0, VarType.REFERENCE, false), type.replace('/', '_')); } else { - emit(out, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);", - smapper.getA(0), type + emitNoFlush(smapper, out, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);", + smapper.getT(0, VarType.REFERENCE, false), type ); } } diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ClosureWrapper.java Wed Feb 19 08:10:04 2014 +0100 @@ -254,6 +254,7 @@ "shr64", "ushr64", "compare64", + "compare", "neg64", "div32", "mod32", diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java Wed Feb 19 08:10:04 2014 +0100 @@ -17,24 +17,21 @@ */ package org.apidesign.vm4brwsr; +import java.io.IOException; import org.apidesign.vm4brwsr.ByteCodeParser.TypeArray; final class StackMapper { private final TypeArray stackTypeIndexPairs; - private int[] typeCounters; - private int[] typeMaxCounters; + private final StringArray stackValues; public StackMapper() { stackTypeIndexPairs = new TypeArray(); - typeCounters = new int[VarType.LAST + 1]; - typeMaxCounters = new int[VarType.LAST + 1]; + stackValues = new StringArray(); } public void clear() { - for (int type = 0; type <= VarType.LAST; ++type) { - typeCounters[type] = 0; - } stackTypeIndexPairs.clear(); + stackValues.clear(); } public void syncWithFrameStack(final TypeArray frameStack) { @@ -70,33 +67,66 @@ return getVariable(pushTypeImpl(type)); } - public Variable popI() { + void assign(Appendable out, int varType, CharSequence s) throws IOException { + pushTypeAndValue(varType, s); + } + + void replace(Appendable out, int varType, String format, CharSequence... arr) + throws IOException { + StringBuilder sb = new StringBuilder(); + ByteCodeToJavaScript.emitImpl(sb, format, arr); + String[] values = stackValues.toArray(); + final int last = stackTypeIndexPairs.getSize() - 1; + values[last] = sb.toString(); + final int value = (last << 8) | (varType & 0xff); + stackTypeIndexPairs.set(last, value); + } + + void flush(Appendable out) throws IOException { + int count = stackTypeIndexPairs.getSize(); + for (int i = 0; i < count; i++) { + String val = stackValues.getAndClear(i, true); + if (val == null) { + continue; + } + CharSequence var = getVariable(stackTypeIndexPairs.get(i)); + ByteCodeToJavaScript.emitImpl(out, "var @1 = @2;", var, val); + } + } + + public CharSequence popI() { return popT(VarType.INTEGER); } - public Variable popL() { + public CharSequence popL() { return popT(VarType.LONG); } - public Variable popF() { + public CharSequence popF() { return popT(VarType.FLOAT); } - public Variable popD() { + public CharSequence popD() { return popT(VarType.DOUBLE); } - public Variable popA() { + public CharSequence popA() { return popT(VarType.REFERENCE); } - public Variable popT(final int type) { - final Variable variable = getT(0, type); + public CharSequence popT(final int type) { + final CharSequence variable = getT(0, type); popImpl(1); return variable; } - public Variable pop() { + public CharSequence popValue() { + final CharSequence variable = getT(0, -1); + popImpl(1); + return variable; + } + public Variable pop(Appendable out) throws IOException { + flush(out); final Variable variable = get(0); popImpl(1); return variable; @@ -110,37 +140,44 @@ popImpl(count); } - public Variable getI(final int indexFromTop) { + public CharSequence getI(final int indexFromTop) { return getT(indexFromTop, VarType.INTEGER); } - public Variable getL(final int indexFromTop) { + public CharSequence getL(final int indexFromTop) { return getT(indexFromTop, VarType.LONG); } - public Variable getF(final int indexFromTop) { + public CharSequence getF(final int indexFromTop) { return getT(indexFromTop, VarType.FLOAT); } - public Variable getD(final int indexFromTop) { + public CharSequence getD(final int indexFromTop) { return getT(indexFromTop, VarType.DOUBLE); } - public Variable getA(final int indexFromTop) { + public CharSequence getA(final int indexFromTop) { return getT(indexFromTop, VarType.REFERENCE); } - public Variable getT(final int indexFromTop, final int type) { + public CharSequence getT(final int indexFromTop, final int type) { + return getT(indexFromTop, type, true); + } + public CharSequence getT(final int indexFromTop, final int type, boolean clear) { final int stackSize = stackTypeIndexPairs.getSize(); if (indexFromTop >= stackSize) { throw new IllegalStateException("Stack underflow"); } final int stackValue = stackTypeIndexPairs.get(stackSize - indexFromTop - 1); - if ((stackValue & 0xff) != type) { + if (type != -1 && (stackValue & 0xff) != type) { throw new IllegalStateException("Type mismatch"); } - + String value = + stackValues.getAndClear(stackSize - indexFromTop - 1, clear); + if (value != null) { + return value; + } return getVariable(stackValue); } @@ -156,35 +193,36 @@ } private int pushTypeImpl(final int type) { - final int count = typeCounters[type]; + final int count = stackTypeIndexPairs.getSize(); final int value = (count << 8) | (type & 0xff); - incCounter(type); stackTypeIndexPairs.add(value); + + addStackValue(count, null); + return value; + } - return value; + private void pushTypeAndValue(final int type, CharSequence v) { + final int count = stackTypeIndexPairs.getSize(); + final int value = (count << 8) | (type & 0xff); + stackTypeIndexPairs.add(value); + final String val = v.toString(); + addStackValue(count, val); + } + + private void addStackValue(int at, final String val) { + final String[] arr = stackValues.toArray(); + if (arr.length > at) { + arr[at] = val; + } else { + stackValues.add(val); + } } private void popImpl(final int count) { final int stackSize = stackTypeIndexPairs.getSize(); - for (int i = stackSize - count; i < stackSize; ++i) { - final int value = stackTypeIndexPairs.get(i); - decCounter(value & 0xff); - } - stackTypeIndexPairs.setSize(stackSize - count); } - private void incCounter(final int type) { - final int newValue = ++typeCounters[type]; - if (typeMaxCounters[type] < newValue) { - typeMaxCounters[type] = newValue; - } - } - - private void decCounter(final int type) { - --typeCounters[type]; - } - public Variable getVariable(final int typeAndIndex) { final int type = typeAndIndex & 0xff; final int index = typeAndIndex >> 8; diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Wed Feb 19 08:10:04 2014 +0100 @@ -105,11 +105,23 @@ } int indexOf(String ic) { - for (int i = 0; i < arr.length; i++) { + if (arr != null) for (int i = 0; i < arr.length; i++) { if (ic.equals(arr[i])) { return i; } } return -1; } + + String getAndClear(int count, boolean clear) { + String s = arr[count]; + if (clear) { + arr[count] = null; + } + return s; + } + + void clear() { + arr = null; + } } diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/test/java/org/apidesign/vm4brwsr/Instance.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Instance.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Instance.java Wed Feb 19 08:10:04 2014 +0100 @@ -137,4 +137,8 @@ @JavaScriptBody(args = { "instance" }, body = "return instance.getByte__B();") private static native int jsgetbytes(Instance instance); + + int sum(int i, int i0) { + return i + i0; + } } diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/test/java/org/apidesign/vm4brwsr/InstanceSub.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/InstanceSub.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/InstanceSub.java Wed Feb 19 08:10:04 2014 +0100 @@ -31,7 +31,7 @@ @Override public void setByte(byte b) { - super.setByte((byte) (b + 1)); + super.setByte((byte) (b + StaticMethod.MISSING_CONSTANT)); } public static double recallDbl() { diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/test/java/org/apidesign/vm4brwsr/NoStringCnstntsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/NoStringCnstntsTest.java Wed Feb 19 08:10:04 2014 +0100 @@ -0,0 +1,62 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 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 static org.testng.Assert.assertEquals; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class NoStringCnstntsTest { + private static String code; + + + @Test public void dontGeneratePrimitiveFinalConstants() { + assertEquals(code.indexOf("HELLO"), -1, "MISSING_CONSTANT field should not be generated"); + } + + @BeforeClass + public static void compileTheCode() throws Exception { + final String res = "org/apidesign/vm4brwsr/StringSample"; + StringBuilder sb = new StringBuilder(); + class JustStaticMethod implements Bck2Brwsr.Resources { + @Override + public InputStream get(String resource) throws IOException { + final String cn = res + ".class"; + if (resource.equals(cn)) { + return getClass().getClassLoader().getResourceAsStream(cn); + } + return null; + } + } + Bck2Brwsr.generate(sb, new JustStaticMethod(), res); + code = sb.toString(); + } + @AfterClass + public static void releaseTheCode() { + code = null; + } + +} diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Wed Feb 19 08:10:04 2014 +0100 @@ -117,6 +117,12 @@ double f = 3.0; assertExec("Should be the same", Numbers.class, "deserDouble__D", f); } + + @Test public void bytesToLong() throws Exception { + long exp = Numbers.bytesToLong((byte)30, (byte)20, 32); + assertExec("Should be the same", Numbers.class, "bytesToLong__JBBI", + Double.valueOf(exp), 30, 20, 32); + } /* @Test public void serDouble() throws IOException { double f = 3.0; diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Wed Feb 19 08:10:04 2014 +0100 @@ -64,6 +64,10 @@ DataInputStream dis = new DataInputStream(is); return dis.readInt(); } + static long bytesToLong(byte b1, byte b2, int shift) { + return (((long)b1 << 56) + + ((long)b2 & 255) << 48) >> shift; + } static String intToString() { return new Integer(5).toString().toString(); diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/test/java/org/apidesign/vm4brwsr/SizeOfAMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/SizeOfAMethodTest.java Wed Feb 19 08:10:04 2014 +0100 @@ -0,0 +1,96 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 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. + */ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package org.apidesign.vm4brwsr; + +import java.io.IOException; +import java.io.InputStream; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * + * @author Jaroslav Tulach + */ +public class SizeOfAMethodTest { + private static String code; + + @Test public void sumXYShouldBeSmall() { + String s = code; + int beg = s.indexOf("c.sum__III"); + int end = s.indexOf("c.sum__III.access"); + + assertTrue(beg > 0, "Found sum method in " + code); + assertTrue(beg < end, "Found end of sum method in " + code); + + String method = s.substring(beg, end); + + + assertEquals(method.indexOf("st"), -1, "There should be no stack operations:\n" + method); + } + + @Test public void emptyConstructorRequiresNoStack() { + String s = code; + int beg = s.indexOf("CLS.cons__V"); + int end = s.indexOf("CLS.cons__V.access"); + + assertTrue(beg > 0, "Found constructor in " + code); + assertTrue(beg < end, "Found end of constructor in " + code); + + String method = s.substring(beg, end); + method = method.replace("constructor", "CNSTR"); + + assertEquals(method.indexOf("st"), -1, "There should be no stack operations:\n" + method); + assertEquals(method.indexOf("for"), -1, "There should be no for blocks:\n" + method); + } + + @Test public void dontGeneratePrimitiveFinalConstants() { + assertEquals(code.indexOf("MISSING_CONSTANT"), -1, "MISSING_CONSTANT field should not be generated"); + } + + @BeforeClass + public static void compileTheCode() throws Exception { + final String res = "org/apidesign/vm4brwsr/StaticMethod"; + StringBuilder sb = new StringBuilder(); + class JustStaticMethod implements Bck2Brwsr.Resources { + @Override + public InputStream get(String resource) throws IOException { + final String cn = res + ".class"; + if (resource.equals(cn)) { + return getClass().getClassLoader().getResourceAsStream(cn); + } + return null; + } + } + Bck2Brwsr.generate(sb, new JustStaticMethod(), res); + code = sb.toString(); + } + @AfterClass + public static void releaseTheCode() { + code = null; + } + +} diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethod.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethod.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethod.java Wed Feb 19 08:10:04 2014 +0100 @@ -24,6 +24,7 @@ * @author Jaroslav Tulach */ public class StaticMethod { + public static final int MISSING_CONSTANT = 1; private static int cnt; private static Object NULL; @@ -82,7 +83,7 @@ if (n <= 1) { return 1; } else { - return n * factRec(n - 1); + return n * factRec(n - MISSING_CONSTANT); } } public static long factIter(int n) { @@ -99,6 +100,10 @@ return cnt; } + public static int helloWorldLength(String x) { + return (StringSample.HELLO + x).length(); + } + @JavaScriptBody( args={"i","j"}, body="\n\r\treturn (i + j).toString();" ) @@ -128,6 +133,62 @@ } } + public static int castString(Object o) { + return ((String)o).length(); + } + + public static int initInflater(int w, boolean nowrap) { + Instance i = new Instance(w, 0.0); + return i.sum(nowrap?-w:w, 1); + } + + public static String toStringArr() { + class N implements Next { + int idx = 0; + + @Override + public boolean hasNext() { + return idx < 5; + } + + @Override + public String next() { + switch (idx++) { + case 0: return "Zero"; + case 1: return "One"; + case 2: return "Two"; + case 3: return "Three"; + case 4: return "Four"; + } + throw new IllegalStateException(); + } + } + return toString(null, new N()).toString(); + } + + static String toString(Object thiz, Next it) { + if (!it.hasNext()) { + return "[]"; + } + + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (;;) { + String e = it.next(); + sb.append(e == thiz ? "(this Collection)" : e); + if (!it.hasNext()) { + return sb.append(']').toString(); + } + sb.append(',').append(' '); + } + } + + static interface Next { + boolean hasNext(); + String next(); + } + + static { // check order of initializers StaticUse.NON_NULL.equals(new Object()); diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Wed Feb 19 08:10:04 2014 +0100 @@ -36,6 +36,15 @@ ); } + @Test public void cast() throws Exception { + assertExec( + "Length is four", + StaticMethod.class, "castString__ILjava_lang_Object_2", + Double.valueOf(4), + "Ahoj" + ); + } + @Test public void checkReallyInitializedValues() throws Exception { assertExec( "Return true", @@ -161,6 +170,25 @@ 3, 3.75 ); } + + @Test public void inflaterInit() throws Exception { + assertExec( + "Down and minus", + StaticMethod.class, "initInflater__IIZ", + Double.valueOf(-9), + 10, true + ); + } + + @Test public void inflaterInitNoNeg() throws Exception { + assertExec( + "One up", + StaticMethod.class, "initInflater__IIZ", + Double.valueOf(11), + 10, false + ); + } + @Test public void mixedMethodFourParams() throws Exception { assertExec( "Should be two", @@ -196,6 +224,15 @@ ); } + @Test public void collectionToString() throws Exception { + String exp = StaticMethod.toStringArr(); + assertExec( + "0 to 4", + StaticMethod.class, "toStringArr__Ljava_lang_String_2", + exp + ); + } + @Test public void or() throws Exception { assertExec( "Or will be 7", @@ -322,6 +359,13 @@ ); } + @Test public void stringConstantIsCopied() throws Exception { + assertExec("String constants are copied between class pools", + StaticMethod.class, "helloWorldLength__ILjava_lang_String_2", + 17, "Jardo" + ); + } + private static TestVM code; @BeforeClass diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Wed Feb 19 08:10:04 2014 +0100 @@ -164,7 +164,10 @@ return ex.toString(); } } - + + final CharSequence codeSeq() { + return codeSeq; + } private static class EmulationResources implements Bck2Brwsr.Resources { @Override diff -r ef506621d1ee -r 4ce73c83c775 rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Sun Feb 16 20:06:03 2014 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Wed Feb 19 08:10:04 2014 +0100 @@ -79,7 +79,7 @@ } } w.append("\n];\n"); - w.append(code.toString()); + w.append(code.codeSeq()); w.close(); throw new Exception(ex.getMessage() + " file: " + f, ex); }