# HG changeset patch # User Lubomir Nerad # Date 1354888955 -3600 # Node ID f2352e0b713e3a3c728f3ea662e653effe72703c # Parent 8bd4adaf6590706525297c7013289856cfa10afd Type specific stack variables diff -r 8bd4adaf6590 -r f2352e0b713e javap/src/main/java/org/apidesign/javap/StackMapIterator.java --- a/javap/src/main/java/org/apidesign/javap/StackMapIterator.java Mon Dec 03 14:44:49 2012 +0100 +++ b/javap/src/main/java/org/apidesign/javap/StackMapIterator.java Fri Dec 07 15:02:35 2012 +0100 @@ -29,17 +29,21 @@ private static final StackMapTableData INITIAL_FRAME = new StackMapTableData(-1) { @Override - int getStackItemsCount() { - return 0; + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + localTypes.clear(); + stackTypes.clear(); } @Override public String toString() { - return "INITIAL(0)"; + return toString("INITIAL", 0, null, null); } + }; private final StackMapTableData[] stackMapTable; + private final TypeArray localTypes; + private final TypeArray stackTypes; private int nextFrameIndex; private int lastFrameByteCodeOffset; @@ -50,7 +54,10 @@ this.stackMapTable = (stackMapTable != null) ? stackMapTable : new StackMapTableData[0]; - this.lastFrameByteCodeOffset = -1; + + localTypes = new TypeArray(); + stackTypes = new TypeArray(); + lastFrameByteCodeOffset = -1; advanceBy(0); } @@ -62,8 +69,8 @@ return nextFrameIndex; } - public int getFrameStackItemsCount() { - return getCurrentFrame().getStackItemsCount(); + public TypeArray getFrameStack() { + return stackTypes; } public void advanceBy(final int numByteCodes) { @@ -76,8 +83,11 @@ && ((byteCodeOffset - lastFrameByteCodeOffset) >= (stackMapTable[nextFrameIndex].offsetDelta + 1))) { - lastFrameByteCodeOffset += - stackMapTable[nextFrameIndex].offsetDelta + 1; + final StackMapTableData nextFrame = stackMapTable[nextFrameIndex]; + + lastFrameByteCodeOffset += nextFrame.offsetDelta + 1; + nextFrame.applyTo(localTypes, stackTypes); + ++nextFrameIndex; } } diff -r 8bd4adaf6590 -r f2352e0b713e javap/src/main/java/org/apidesign/javap/StackMapTableData.java --- a/javap/src/main/java/org/apidesign/javap/StackMapTableData.java Mon Dec 03 14:44:49 2012 +0100 +++ b/javap/src/main/java/org/apidesign/javap/StackMapTableData.java Fri Dec 07 15:02:35 2012 +0100 @@ -40,7 +40,75 @@ this.frameType = frameType; } - abstract int getStackItemsCount(); + abstract void applyTo(TypeArray localTypes, TypeArray stackTypes); + + protected static String toString( + final String frameType, + final int offset, + final int[] localTypes, + final int[] stackTypes) { + final StringBuilder sb = new StringBuilder(frameType); + + sb.append("(off: +").append(offset); + if (localTypes != null) { + sb.append(", locals: "); + appendTypes(sb, localTypes); + } + if (stackTypes != null) { + sb.append(", stack: "); + appendTypes(sb, stackTypes); + } + sb.append(')'); + + return sb.toString(); + } + + private static void appendTypes(final StringBuilder sb, final int[] types) { + sb.append('['); + if (types.length > 0) { + appendType(sb, types[0]); + for (int i = 1; i < types.length; ++i) { + sb.append(", "); + appendType(sb, types[i]); + } + } + sb.append(']'); + } + + private static void appendType(final StringBuilder sb, final int type) { + switch (type & 0xff) { + case ITEM_Bogus: + sb.append("_top_"); + break; + case ITEM_Integer: + sb.append("_int_"); + break; + case ITEM_Float: + sb.append("_float_"); + break; + case ITEM_Double: + sb.append("_double_"); + break; + case ITEM_Long: + sb.append("_long_"); + break; + case ITEM_Null: + sb.append("_null_"); + break; + case ITEM_InitObject: // UninitializedThis + sb.append("_init_"); + break; + case ITEM_Object: + sb.append("_object_"); + break; + case ITEM_NewObject: // Uninitialized + sb.append("_new_"); + break; + default: + sb.append("_unknown_"); + break; + } + } static class SameFrame extends StackMapTableData { SameFrame(int frameType, int offsetDelta) { @@ -49,16 +117,16 @@ } @Override - int getStackItemsCount() { - return 0; + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + stackTypes.clear(); } @Override public String toString() { - return "SAME" - + ((frameType == SAME_FRAME_EXTENDED) - ? "_FRAME_EXTENDED" : "") - + "(" + offsetDelta + ")"; + return toString("SAME" + ((frameType == SAME_FRAME_EXTENDED) + ? "_FRAME_EXTENDED" : ""), + offsetDelta, + null, null); } } @@ -71,16 +139,18 @@ } @Override - int getStackItemsCount() { - return 1; + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + stackTypes.setAll(stack); } @Override public String toString() { - return "SAME_LOCALS_1_STACK_ITEM" - + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) - ? "_EXTENDED" : "") - + "(" + offsetDelta + ")"; + return toString( + "SAME_LOCALS_1_STACK_ITEM" + + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) + ? "_EXTENDED" : ""), + offsetDelta, + null, stack); } } @@ -91,13 +161,15 @@ } @Override - int getStackItemsCount() { - return 0; + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + localTypes.setSize(localTypes.getSize() + - (SAME_FRAME_EXTENDED - frameType)); + stackTypes.clear(); } @Override public String toString() { - return "CHOP(" + offsetDelta + ")"; + return toString("CHOP", offsetDelta, null, null); } } @@ -110,13 +182,14 @@ } @Override - int getStackItemsCount() { - return 0; + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + localTypes.addAll(locals); + stackTypes.clear(); } @Override public String toString() { - return "APPEND(" + offsetDelta + ")"; + return toString("APPEND", offsetDelta, locals, null); } } @@ -131,13 +204,14 @@ } @Override - int getStackItemsCount() { - return stack.length; + void applyTo(TypeArray localTypes, TypeArray stackTypes) { + localTypes.setAll(locals); + stackTypes.setAll(stack); } @Override public String toString() { - return "FULL(" + offsetDelta + ")"; + return toString("FULL", offsetDelta, locals, stack); } } diff -r 8bd4adaf6590 -r f2352e0b713e javap/src/main/java/org/apidesign/javap/TypeArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javap/src/main/java/org/apidesign/javap/TypeArray.java Fri Dec 07 15:02:35 2012 +0100 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apidesign.javap; + +public class TypeArray { + private static final int CAPACITY_INCREMENT = 16; + + private int[] types; + private int size; + + public void add(final int newType) { + ensureCapacity(size + 1); + types[size++] = newType; + } + + public void addAll(final int[] newTypes) { + if (newTypes.length > 0) { + ensureCapacity(size + newTypes.length); + arraycopy(newTypes, 0, types, size, newTypes.length); + size += newTypes.length; + } + } + + public void setAll(final int[] newTypes) { + if (newTypes.length > 0) { + ensureCapacity(newTypes.length); + arraycopy(newTypes, 0, types, 0, newTypes.length); + size = newTypes.length; + } else { + clear(); + } + } + + public void setSize(final int newSize) { + ensureCapacity(newSize); + size = newSize; + } + + public void clear() { + size = 0; + } + + public int getSize() { + return size; + } + + public int get(final int index) { + return types[index]; + } + + private void ensureCapacity(final int minCapacity) { + if ((minCapacity == 0) + || (types != null) && (minCapacity <= types.length)) { + return; + } + + final int newCapacity = + ((minCapacity + CAPACITY_INCREMENT - 1) / CAPACITY_INCREMENT) + * CAPACITY_INCREMENT; + final int[] newTypes = new int[newCapacity]; + + if (size > 0) { + arraycopy(types, 0, newTypes, 0, size); + } + + types = newTypes; + } + + // no System.arraycopy + private void arraycopy(final int[] src, final int srcPos, + final int[] dest, final int destPos, + final int length) { + for (int i = 0; i < length; ++i) { + dest[destPos + i] = src[srcPos + i]; + } + } +} diff -r 8bd4adaf6590 -r f2352e0b713e vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Dec 03 14:44:49 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Fri Dec 07 15:02:35 2012 +0100 @@ -241,12 +241,15 @@ // so this might generate more stack variables than we need final int maxStack = m.getMaxStack(); if (maxStack > 0) { - out.append("\n var ").append(mapper.constructVariableName(0)); - for (int i = 1; i < maxStack; ++i) { - out.append(", "); - out.append(mapper.constructVariableName(i)); + // TODO: generate only used stack variables + for (int j = 0; j <= Variable.LAST_TYPE; ++j) { + out.append("\n var ").append(Variable.getStackVariable(j, 0)); + for (int i = 1; i < maxStack; ++i) { + out.append(", "); + out.append(Variable.getStackVariable(j, i)); + } + out.append(';'); } - out.append(';'); } int lastStackFrame = -1; @@ -257,7 +260,7 @@ stackMapIterator.advanceTo(i); if (lastStackFrame != stackMapIterator.getFrameIndex()) { lastStackFrame = stackMapIterator.getFrameIndex(); - mapper.reset(stackMapIterator.getFrameStackItemsCount()); + mapper.syncWithFrameStack(stackMapIterator.getFrameStack()); out.append(" case " + i).append(": "); } else { out.append(" /* " + i).append(" */ "); @@ -265,162 +268,330 @@ final int c = readByte(byteCodes, i); switch (c) { case opc_aload_0: + out.append(mapper.pushA()).append(" = arg0;"); + break; case opc_iload_0: + out.append(mapper.pushI()).append(" = arg0;"); + break; case opc_lload_0: + out.append(mapper.pushL()).append(" = arg0;"); + break; case opc_fload_0: + out.append(mapper.pushF()).append(" = arg0;"); + break; case opc_dload_0: - out.append(mapper.push()).append(" = arg0;"); + out.append(mapper.pushD()).append(" = arg0;"); break; case opc_aload_1: + out.append(mapper.pushA()).append(" = arg1;"); + break; case opc_iload_1: + out.append(mapper.pushI()).append(" = arg1;"); + break; case opc_lload_1: + out.append(mapper.pushL()).append(" = arg1;"); + break; case opc_fload_1: + out.append(mapper.pushF()).append(" = arg1;"); + break; case opc_dload_1: - out.append(mapper.push()).append(" = arg1;"); + out.append(mapper.pushD()).append(" = arg1;"); break; case opc_aload_2: + out.append(mapper.pushA()).append(" = arg2;"); + break; case opc_iload_2: + out.append(mapper.pushI()).append(" = arg2;"); + break; case opc_lload_2: + out.append(mapper.pushL()).append(" = arg2;"); + break; case opc_fload_2: + out.append(mapper.pushF()).append(" = arg2;"); + break; case opc_dload_2: - out.append(mapper.push()).append(" = arg2;"); + out.append(mapper.pushD()).append(" = arg2;"); break; case opc_aload_3: + out.append(mapper.pushA()).append(" = arg3;"); + break; case opc_iload_3: + out.append(mapper.pushI()).append(" = arg3;"); + break; case opc_lload_3: + out.append(mapper.pushL()).append(" = arg3;"); + break; case opc_fload_3: + out.append(mapper.pushF()).append(" = arg3;"); + break; case opc_dload_3: - out.append(mapper.push()).append(" = arg3;"); + out.append(mapper.pushD()).append(" = arg3;"); break; - case opc_iload: - case opc_lload: - case opc_fload: - case opc_dload: + case opc_iload: { + final int indx = readByte(byteCodes, ++i); + out.append(mapper.pushI()).append(" = ") + .append("arg").append(indx + ";"); + break; + } + case opc_lload: { + final int indx = readByte(byteCodes, ++i); + out.append(mapper.pushL()).append(" = ") + .append("arg").append(indx + ";"); + break; + } + case opc_fload: { + final int indx = readByte(byteCodes, ++i); + out.append(mapper.pushF()).append(" = ") + .append("arg").append(indx + ";"); + break; + } + case opc_dload: { + final int indx = readByte(byteCodes, ++i); + out.append(mapper.pushD()).append(" = ") + .append("arg").append(indx + ";"); + break; + } case opc_aload: { final int indx = readByte(byteCodes, ++i); - out.append(mapper.push()) - .append(" = arg") - .append(indx + ";"); + out.append(mapper.pushA()).append(" = ") + .append("arg").append(indx + ";"); break; } - case opc_istore: - case opc_lstore: - case opc_fstore: - case opc_dstore: + case opc_istore: { + final int indx = readByte(byteCodes, ++i); + out.append("arg" + indx).append(" = ") + .append(mapper.popI()).append(';'); + break; + } + case opc_lstore: { + final int indx = readByte(byteCodes, ++i); + out.append("arg" + indx).append(" = ") + .append(mapper.popL()).append(';'); + break; + } + case opc_fstore: { + final int indx = readByte(byteCodes, ++i); + out.append("arg" + indx).append(" = ") + .append(mapper.popF()).append(';'); + break; + } + case opc_dstore: { + final int indx = readByte(byteCodes, ++i); + out.append("arg" + indx).append(" = ") + .append(mapper.popD()).append(';'); + break; + } case opc_astore: { final int indx = readByte(byteCodes, ++i); - out.append("arg" + indx) - .append(" = ") - .append(mapper.pop()) - .append(';'); + out.append("arg" + indx).append(" = ") + .append(mapper.popA()).append(';'); break; } case opc_astore_0: + out.append("arg0 = ").append(mapper.popA()).append(';'); + break; case opc_istore_0: + out.append("arg0 = ").append(mapper.popI()).append(';'); + break; case opc_lstore_0: + out.append("arg0 = ").append(mapper.popL()).append(';'); + break; case opc_fstore_0: + out.append("arg0 = ").append(mapper.popF()).append(';'); + break; case opc_dstore_0: - out.append("arg0 = ").append(mapper.pop()).append(';'); + out.append("arg0 = ").append(mapper.popD()).append(';'); break; case opc_astore_1: + out.append("arg1 = ").append(mapper.popA()).append(';'); + break; case opc_istore_1: + out.append("arg1 = ").append(mapper.popI()).append(';'); + break; case opc_lstore_1: + out.append("arg1 = ").append(mapper.popL()).append(';'); + break; case opc_fstore_1: + out.append("arg1 = ").append(mapper.popF()).append(';'); + break; case opc_dstore_1: - out.append("arg1 = ").append(mapper.pop()).append(';'); + out.append("arg1 = ").append(mapper.popD()).append(';'); break; case opc_astore_2: + out.append("arg2 = ").append(mapper.popA()).append(';'); + break; case opc_istore_2: + out.append("arg2 = ").append(mapper.popI()).append(';'); + break; case opc_lstore_2: + out.append("arg2 = ").append(mapper.popL()).append(';'); + break; case opc_fstore_2: + out.append("arg2 = ").append(mapper.popF()).append(';'); + break; case opc_dstore_2: - out.append("arg2 = ").append(mapper.pop()).append(';'); + out.append("arg2 = ").append(mapper.popD()).append(';'); break; case opc_astore_3: + out.append("arg3 = ").append(mapper.popA()).append(';'); + break; case opc_istore_3: + out.append("arg3 = ").append(mapper.popI()).append(';'); + break; case opc_lstore_3: + out.append("arg3 = ").append(mapper.popL()).append(';'); + break; case opc_fstore_3: + out.append("arg3 = ").append(mapper.popF()).append(';'); + break; case opc_dstore_3: - out.append("arg3 = ").append(mapper.pop()).append(';'); + out.append("arg3 = ").append(mapper.popD()).append(';'); break; case opc_iadd: + out.append(mapper.getI(1)).append(" += ") + .append(mapper.popI()).append(';'); + break; case opc_ladd: + out.append(mapper.getL(1)).append(" += ") + .append(mapper.popL()).append(';'); + break; case opc_fadd: + out.append(mapper.getF(1)).append(" += ") + .append(mapper.popF()).append(';'); + break; case opc_dadd: - out.append(mapper.get(1)).append(" += ") - .append(mapper.pop()).append(';'); + out.append(mapper.getD(1)).append(" += ") + .append(mapper.popD()).append(';'); break; case opc_isub: + out.append(mapper.getI(1)).append(" -= ") + .append(mapper.popI()).append(';'); + break; case opc_lsub: + out.append(mapper.getL(1)).append(" -= ") + .append(mapper.popL()).append(';'); + break; case opc_fsub: + out.append(mapper.getF(1)).append(" -= ") + .append(mapper.popF()).append(';'); + break; case opc_dsub: - out.append(mapper.get(1)).append(" -= ") - .append(mapper.pop()).append(';'); + out.append(mapper.getD(1)).append(" -= ") + .append(mapper.popD()).append(';'); break; case opc_imul: + out.append(mapper.getI(1)).append(" *= ") + .append(mapper.popI()).append(';'); + break; case opc_lmul: + out.append(mapper.getL(1)).append(" *= ") + .append(mapper.popL()).append(';'); + break; case opc_fmul: + out.append(mapper.getF(1)).append(" *= ") + .append(mapper.popF()).append(';'); + break; case opc_dmul: - out.append(mapper.get(1)).append(" *= ") - .append(mapper.pop()).append(';'); + out.append(mapper.getD(1)).append(" *= ") + .append(mapper.popD()).append(';'); break; case opc_idiv: + out.append(mapper.getI(1)).append(" = ") + .append("Math.floor(").append(mapper.getI(1)) + .append(" / ").append(mapper.popI()).append(");"); + break; case opc_ldiv: - out.append(mapper.get(1)) - .append(" = Math.floor(") - .append(mapper.get(1)) - .append(" / ") - .append(mapper.pop()) - .append(");"); + out.append(mapper.getL(1)).append(" = ") + .append("Math.floor(").append(mapper.getL(1)) + .append(" / ").append(mapper.popL()).append(");"); break; case opc_fdiv: + out.append(mapper.getF(1)).append(" /= ") + .append(mapper.popF()).append(';'); + break; case opc_ddiv: - out.append(mapper.get(1)).append(" /= ") - .append(mapper.pop()).append(';'); + out.append(mapper.getD(1)).append(" /= ") + .append(mapper.popD()).append(';'); break; case opc_irem: + out.append(mapper.getI(1)).append(" %= ") + .append(mapper.popI()).append(';'); + break; case opc_lrem: + out.append(mapper.getL(1)).append(" %= ") + .append(mapper.popL()).append(';'); + break; case opc_frem: + out.append(mapper.getF(1)).append(" %= ") + .append(mapper.popF()).append(';'); + break; case opc_drem: - out.append(mapper.get(1)).append(" %= ") - .append(mapper.pop()).append(';'); + out.append(mapper.getD(1)).append(" %= ") + .append(mapper.popD()).append(';'); break; case opc_iand: + out.append(mapper.getI(1)).append(" &= ") + .append(mapper.popI()).append(';'); + break; case opc_land: - out.append(mapper.get(1)).append(" &= ") - .append(mapper.pop()).append(';'); + out.append(mapper.getL(1)).append(" &= ") + .append(mapper.popL()).append(';'); break; case opc_ior: + out.append(mapper.getI(1)).append(" |= ") + .append(mapper.popI()).append(';'); + break; case opc_lor: - out.append(mapper.get(1)).append(" |= ") - .append(mapper.pop()).append(';'); + out.append(mapper.getL(1)).append(" |= ") + .append(mapper.popL()).append(';'); break; case opc_ixor: + out.append(mapper.getI(1)).append(" ^= ") + .append(mapper.popI()).append(';'); + break; case opc_lxor: - out.append(mapper.get(1)).append(" ^= ") - .append(mapper.pop()).append(';'); + out.append(mapper.getL(1)).append(" ^= ") + .append(mapper.popL()).append(';'); break; case opc_ineg: + out.append(mapper.getI(0)).append(" = -") + .append(mapper.getI(0)).append(';'); + break; case opc_lneg: + out.append(mapper.getL(0)).append(" = -") + .append(mapper.getL(0)).append(';'); + break; case opc_fneg: + out.append(mapper.getF(0)).append(" = -") + .append(mapper.getF(0)).append(';'); + break; case opc_dneg: - out.append(mapper.get(0)).append(" = -") - .append(mapper.get(0)).append(';'); + out.append(mapper.getD(0)).append(" = -") + .append(mapper.getD(0)).append(';'); break; case opc_ishl: + out.append(mapper.getI(1)).append(" <<= ") + .append(mapper.popI()).append(';'); + break; case opc_lshl: - out.append(mapper.get(1)).append(" <<= ") - .append(mapper.pop()).append(';'); + out.append(mapper.getL(1)).append(" <<= ") + .append(mapper.popI()).append(';'); break; case opc_ishr: + out.append(mapper.getI(1)).append(" >>= ") + .append(mapper.popI()).append(';'); + break; case opc_lshr: - out.append(mapper.get(1)).append(" >>= ") - .append(mapper.pop()).append(';'); + out.append(mapper.getL(1)).append(" >>= ") + .append(mapper.popI()).append(';'); break; case opc_iushr: + out.append(mapper.getI(1)).append(" >>>= ") + .append(mapper.popI()).append(';'); + break; case opc_lushr: - out.append(mapper.get(1)).append(" >>>= ") - .append(mapper.pop()).append(';'); + out.append(mapper.getL(1)).append(" >>>= ") + .append(mapper.popI()).append(';'); break; case opc_iinc: { final int varIndx = readByte(byteCodes, ++i); @@ -436,75 +607,149 @@ out.append("return;"); break; case opc_ireturn: + out.append("return ").append(mapper.popI()).append(';'); + break; case opc_lreturn: + out.append("return ").append(mapper.popL()).append(';'); + break; case opc_freturn: + out.append("return ").append(mapper.popF()).append(';'); + break; case opc_dreturn: + out.append("return ").append(mapper.popD()).append(';'); + break; case opc_areturn: - out.append("return ").append(mapper.pop()).append(';'); + out.append("return ").append(mapper.popA()).append(';'); break; - case opc_i2l: - case opc_i2f: - case opc_i2d: - case opc_l2i: + case opc_i2l: { + final Variable v = mapper.popI(); + out.append(mapper.pushL()).append(" = ") + .append(v).append(';'); + break; + } + case opc_i2f: { + final Variable v = mapper.popI(); + out.append(mapper.pushF()).append(" = ") + .append(v).append(';'); + break; + } + case opc_i2d: { + final Variable v = mapper.popI(); + out.append(mapper.pushD()).append(" = ") + .append(v).append(';'); + break; + } + case opc_l2i: { + final Variable v = mapper.popL(); + out.append(mapper.pushI()).append(" = ") + .append(v).append(';'); + break; + } // max int check? - case opc_l2f: - case opc_l2d: - case opc_f2d: - case opc_d2f: - out.append("/* number conversion */"); + case opc_l2f: { + final Variable v = mapper.popL(); + out.append(mapper.pushF()).append(" = ") + .append(v).append(';'); break; - case opc_f2i: - case opc_f2l: - case opc_d2i: - case opc_d2l: - out.append(mapper.get(0)) - .append(" = Math.floor(") - .append(mapper.get(0)) - .append(");"); + } + case opc_l2d: { + final Variable v = mapper.popL(); + out.append(mapper.pushD()).append(" = ") + .append(v).append(';'); break; + } + case opc_f2d: { + final Variable v = mapper.popF(); + out.append(mapper.pushD()).append(" = ") + .append(v).append(';'); + break; + } + case opc_d2f: { + final Variable v = mapper.popD(); + out.append(mapper.pushF()).append(" = ") + .append(v).append(';'); + break; + } + case opc_f2i: { + final Variable v = mapper.popF(); + out.append(mapper.pushI()).append(" = ") + .append("Math.floor(").append(v).append(");"); + break; + } + case opc_f2l: { + final Variable v = mapper.popF(); + out.append(mapper.pushL()).append(" = ") + .append("Math.floor(").append(v).append(");"); + break; + } + case opc_d2i: { + final Variable v = mapper.popD(); + out.append(mapper.pushI()).append(" = ") + .append("Math.floor(").append(v).append(");"); + break; + } + case opc_d2l: { + final Variable v = mapper.popD(); + out.append(mapper.pushL()).append(" = ") + .append("Math.floor(").append(v).append(");"); + break; + } case opc_i2b: case opc_i2c: case opc_i2s: out.append("/* number conversion */"); break; case opc_aconst_null: - out.append(mapper.push()).append(" = null;"); + out.append(mapper.pushA()).append(" = null;"); break; case opc_iconst_m1: - out.append(mapper.push()).append(" = -1;"); + out.append(mapper.pushI()).append(" = -1;"); break; case opc_iconst_0: + out.append(mapper.pushI()).append(" = 0;"); + break; case opc_dconst_0: + out.append(mapper.pushD()).append(" = 0;"); + break; case opc_lconst_0: + out.append(mapper.pushL()).append(" = 0;"); + break; case opc_fconst_0: - out.append(mapper.push()).append(" = 0;"); + out.append(mapper.pushF()).append(" = 0;"); break; case opc_iconst_1: + out.append(mapper.pushI()).append(" = 1;"); + break; case opc_lconst_1: + out.append(mapper.pushL()).append(" = 1;"); + break; case opc_fconst_1: + out.append(mapper.pushF()).append(" = 1;"); + break; case opc_dconst_1: - out.append(mapper.push()).append(" = 1;"); + out.append(mapper.pushD()).append(" = 1;"); break; case opc_iconst_2: + out.append(mapper.pushI()).append(" = 2;"); + break; case opc_fconst_2: - out.append(mapper.push()).append(" = 2;"); + out.append(mapper.pushF()).append(" = 2;"); break; case opc_iconst_3: - out.append(mapper.push()).append(" = 3;"); + out.append(mapper.pushI()).append(" = 3;"); break; case opc_iconst_4: - out.append(mapper.push()).append(" = 4;"); + out.append(mapper.pushI()).append(" = 4;"); break; case opc_iconst_5: - out.append(mapper.push()).append(" = 5;"); + out.append(mapper.pushI()).append(" = 5;"); break; case opc_ldc: { int indx = readByte(byteCodes, ++i); String v = encodeConstant(indx); - out.append(mapper.push()) - .append(" = ") - .append(v) - .append(';'); + int type = constantToVariableType(jc.getTag(indx)); + out.append(mapper.pushT(type)).append(" = ") + .append(v).append(';'); break; } case opc_ldc_w: @@ -512,44 +757,38 @@ int indx = readIntArg(byteCodes, i); i += 2; String v = encodeConstant(indx); - out.append(mapper.push()) - .append(" = ") - .append(v) - .append(';'); + int type = constantToVariableType(jc.getTag(indx)); + out.append(mapper.pushT(type)).append(" = ") + .append(v).append(';'); break; } case opc_lcmp: + generateCmp(mapper.popL(), mapper.popL(), mapper.pushI()); + break; case opc_fcmpl: case opc_fcmpg: + generateCmp(mapper.popF(), mapper.popF(), mapper.pushI()); + break; case opc_dcmpl: - case opc_dcmpg: { - out.append(mapper.get(1)) - .append(" = (") - .append(mapper.get(1)) - .append(" == ") - .append(mapper.get(0)) - .append(") ? 0 : ((") - .append(mapper.get(1)) - .append(" < ") - .append(mapper.get(0)) - .append(") ? -1 : 1);"); - - mapper.pop(1); + case opc_dcmpg: + generateCmp(mapper.popD(), mapper.popD(), mapper.pushI()); break; - } case opc_if_acmpeq: - i = generateIf(byteCodes, i, mapper, "==="); + i = generateIf(byteCodes, i, mapper.popA(), mapper.popA(), + "==="); break; case opc_if_acmpne: - i = generateIf(byteCodes, i, mapper, "!="); + i = generateIf(byteCodes, i, mapper.popA(), mapper.popA(), + "!="); break; case opc_if_icmpeq: { - i = generateIf(byteCodes, i, mapper, "=="); + i = generateIf(byteCodes, i, mapper.popI(), mapper.popI(), + "=="); break; } case opc_ifeq: { int indx = i + readIntArg(byteCodes, i); - out.append("if (").append(mapper.pop()) + out.append("if (").append(mapper.popI()) .append(" == 0) { gt = " + indx); out.append("; continue; }"); i += 2; @@ -557,7 +796,7 @@ } case opc_ifne: { int indx = i + readIntArg(byteCodes, i); - out.append("if (").append(mapper.pop()) + out.append("if (").append(mapper.popI()) .append(" != 0) { gt = " + indx); out.append("; continue; }"); i += 2; @@ -565,7 +804,7 @@ } case opc_iflt: { int indx = i + readIntArg(byteCodes, i); - out.append("if (").append(mapper.pop()) + out.append("if (").append(mapper.popI()) .append(" < 0) { gt = " + indx); out.append("; continue; }"); i += 2; @@ -573,7 +812,7 @@ } case opc_ifle: { int indx = i + readIntArg(byteCodes, i); - out.append("if (").append(mapper.pop()) + out.append("if (").append(mapper.popI()) .append(" <= 0) { gt = " + indx); out.append("; continue; }"); i += 2; @@ -581,7 +820,7 @@ } case opc_ifgt: { int indx = i + readIntArg(byteCodes, i); - out.append("if (").append(mapper.pop()) + out.append("if (").append(mapper.popI()) .append(" > 0) { gt = " + indx); out.append("; continue; }"); i += 2; @@ -589,7 +828,7 @@ } case opc_ifge: { int indx = i + readIntArg(byteCodes, i); - out.append("if (").append(mapper.pop()) + out.append("if (").append(mapper.popI()) .append(" >= 0) { gt = " + indx); out.append("; continue; }"); i += 2; @@ -597,7 +836,7 @@ } case opc_ifnonnull: { int indx = i + readIntArg(byteCodes, i); - out.append("if (").append(mapper.pop()) + out.append("if (").append(mapper.popA()) .append(" !== null) { gt = " + indx); out.append("; continue; }"); i += 2; @@ -605,26 +844,31 @@ } case opc_ifnull: { int indx = i + readIntArg(byteCodes, i); - out.append("if (").append(mapper.pop()) + out.append("if (").append(mapper.popA()) .append(" === null) { gt = " + indx); out.append("; continue; }"); i += 2; break; } case opc_if_icmpne: - i = generateIf(byteCodes, i, mapper, "!="); + i = generateIf(byteCodes, i, mapper.popI(), mapper.popI(), + "!="); break; case opc_if_icmplt: - i = generateIf(byteCodes, i, mapper, "<"); + i = generateIf(byteCodes, i, mapper.popI(), mapper.popI(), + "<"); break; case opc_if_icmple: - i = generateIf(byteCodes, i, mapper, "<="); + i = generateIf(byteCodes, i, mapper.popI(), mapper.popI(), + "<="); break; case opc_if_icmpgt: - i = generateIf(byteCodes, i, mapper, ">"); + i = generateIf(byteCodes, i, mapper.popI(), mapper.popI(), + ">"); break; case opc_if_icmpge: - i = generateIf(byteCodes, i, mapper, ">="); + i = generateIf(byteCodes, i, mapper.popI(), mapper.popI(), + ">="); break; case opc_goto: { int indx = i + readIntArg(byteCodes, i); @@ -638,7 +882,7 @@ table += 4; int n = readInt4(byteCodes, table); table += 4; - out.append("switch (").append(mapper.pop()).append(") {\n"); + out.append("switch (").append(mapper.popI()).append(") {\n"); while (n-- > 0) { int cnstnt = readInt4(byteCodes, table); table += 4; @@ -658,7 +902,7 @@ table += 4; int high = readInt4(byteCodes, table); table += 4; - out.append("switch (").append(mapper.pop()).append(") {\n"); + out.append("switch (").append(mapper.popI()).append(") {\n"); while (low <= high) { int offset = i + readInt4(byteCodes, table); table += 4; @@ -685,7 +929,7 @@ case opc_new: { int indx = readIntArg(byteCodes, i); String ci = jc.getClassName(indx); - out.append(mapper.push()).append(" = "); + out.append(mapper.pushA()).append(" = "); out.append("new ").append(ci.replace('/','_')); out.append(';'); addReference(ci); @@ -694,28 +938,26 @@ } case opc_newarray: { ++i; // skip type of array - out.append(mapper.get(0)) - .append(" = new Array(") - .append(mapper.get(0)) - .append(").fillNulls();"); + final Variable v = mapper.popI(); + out.append(mapper.pushA()).append(" = ") + .append("new Array(").append(v).append(").fillNulls();"); break; } case opc_anewarray: { i += 2; // skip type of array - out.append(mapper.get(0)) - .append(" = new Array(") - .append(mapper.get(0)) - .append(").fillNulls();"); + final Variable v = mapper.popI(); + out.append(mapper.pushA()).append(" = ") + .append("new Array(").append(v).append(").fillNulls();"); break; } case opc_multianewarray: { i += 2; int dim = readByte(byteCodes, ++i); - out.append("{ var a0 = new Array(").append(mapper.pop()) + out.append("{ var a0 = new Array(").append(mapper.popI()) .append(").fillNulls();"); for (int d = 1; d < dim; d++) { out.append("\n var l" + d).append(" = ") - .append(mapper.pop()).append(';'); + .append(mapper.popI()).append(';'); out.append("\n for (var i" + d).append (" = 0; i" + d). append(" < a" + (d - 1)). append(".length; i" + d).append("++) {"); @@ -727,41 +969,94 @@ for (int d = 1; d < dim; d++) { out.append("\n }"); } - out.append("\n").append(mapper.push()).append(" = a0; }"); + out.append("\n").append(mapper.pushA()).append(" = a0; }"); break; } - case opc_arraylength: - out.append(mapper.get(0)).append(" = ") - .append(mapper.get(0)).append(".length;"); + case opc_arraylength: { + final Variable v = mapper.popA(); + out.append(mapper.pushI()).append(" = ") + .append(v).append(".length;"); break; + } + case opc_lastore: { + out.append(mapper.getA(2)).append('[') + .append(mapper.getI(1)) + .append(']') + .append(" = ").append(mapper.getL(0)).append(';'); + mapper.pop(3); + break; + } + case opc_fastore: { + out.append(mapper.getA(2)).append('[') + .append(mapper.getI(1)) + .append(']') + .append(" = ").append(mapper.getF(0)).append(';'); + mapper.pop(3); + break; + } + case opc_dastore: { + out.append(mapper.getA(2)).append('[') + .append(mapper.getI(1)) + .append(']') + .append(" = ").append(mapper.getD(0)).append(';'); + mapper.pop(3); + break; + } + case opc_aastore: { + out.append(mapper.getA(2)).append('[') + .append(mapper.getI(1)) + .append(']') + .append(" = ").append(mapper.getA(0)).append(';'); + mapper.pop(3); + break; + } case opc_iastore: - case opc_lastore: - case opc_fastore: - case opc_dastore: - case opc_aastore: case opc_bastore: case opc_castore: case opc_sastore: { - out.append(mapper.get(2)) - .append('[').append(mapper.get(1)).append(']') - .append(" = ") - .append(mapper.get(0)) - .append(';'); + out.append(mapper.getA(2)).append('[') + .append(mapper.getI(1)) + .append(']') + .append(" = ").append(mapper.getI(0)).append(';'); mapper.pop(3); break; } + case opc_laload: { + final Variable vidx = mapper.popI(); + final Variable varr = mapper.popA(); + out.append(mapper.pushL()).append(" = ") + .append(varr).append('[').append(vidx).append("];"); + break; + } + case opc_faload: { + final Variable vidx = mapper.popI(); + final Variable varr = mapper.popA(); + out.append(mapper.pushF()).append(" = ") + .append(varr).append('[').append(vidx).append("];"); + break; + } + case opc_daload: { + final Variable vidx = mapper.popI(); + final Variable varr = mapper.popA(); + out.append(mapper.pushD()).append(" = ") + .append(varr).append('[').append(vidx).append("];"); + break; + } + case opc_aaload: { + final Variable vidx = mapper.popI(); + final Variable varr = mapper.popA(); + out.append(mapper.pushA()).append(" = ") + .append(varr).append('[').append(vidx).append("];"); + break; + } case opc_iaload: - case opc_laload: - case opc_faload: - case opc_daload: - case opc_aaload: case opc_baload: case opc_caload: case opc_saload: { - out.append(mapper.get(1)) - .append(" = ") - .append(mapper.get(1)) - .append('[').append(mapper.pop()).append("];"); + final Variable vidx = mapper.popI(); + final Variable varr = mapper.popA(); + out.append(mapper.pushI()).append(" = ") + .append(varr).append('[').append(vidx).append("];"); break; } case opc_pop: @@ -769,38 +1064,80 @@ mapper.pop(1); out.append("/* pop */"); break; - case opc_dup: - out.append(mapper.push()).append(" = ") - .append(mapper.get(1)).append(';'); + case opc_dup: { + final Variable v = mapper.get(0); + out.append(mapper.pushT(v.getType())).append(" = ") + .append(v).append(';'); break; - case opc_dup_x1: + } + case opc_dup2: { + if (mapper.get(0).isCategory2()) { + final Variable v = mapper.get(0); + out.append(mapper.pushT(v.getType())).append(" = ") + .append(v).append(';'); + } else { + final Variable v1 = mapper.get(0); + final Variable v2 = mapper.get(1); + out.append("{ "); + out.append(mapper.pushT(v2.getType())).append(" = ") + .append(v2).append("; "); + out.append(mapper.pushT(v1.getType())).append(" = ") + .append(v1).append("; "); + out.append('}'); + } + break; + } + case opc_dup_x1: { + final Variable vi1 = mapper.pop(); + final Variable vi2 = mapper.pop(); + final Variable vo3 = mapper.pushT(vi1.getType()); + final Variable vo2 = mapper.pushT(vi2.getType()); + final Variable vo1 = mapper.pushT(vi1.getType()); + out.append("{ "); - out.append(mapper.push()).append(" = ") - .append(mapper.get(1)).append("; "); - out.append(mapper.get(1)).append(" = ") - .append(mapper.get(2)).append("; "); - out.append(mapper.get(2)).append(" = ") - .append(mapper.get(0)).append("; "); + out.append(vo1).append(" = ").append(vi1).append("; "); + out.append(vo2).append(" = ").append(vi2).append("; "); + out.append(vo3).append(" = ").append(vo1).append("; "); out.append('}'); break; - case opc_dup_x2: - out.append("{ "); - out.append(mapper.push()).append(" = ") - .append(mapper.get(1)).append("; "); - out.append(mapper.get(1)).append(" = ") - .append(mapper.get(2)).append("; "); - out.append(mapper.get(2)).append(" = ") - .append(mapper.get(3)).append("; "); - out.append(mapper.get(3)).append(" = ") - .append(mapper.get(0)).append("; "); - out.append('}'); + } + case opc_dup_x2: { + if (mapper.get(1).isCategory2()) { + final Variable vi1 = mapper.pop(); + final Variable vi2 = mapper.pop(); + final Variable vo3 = mapper.pushT(vi1.getType()); + final Variable vo2 = mapper.pushT(vi2.getType()); + final Variable vo1 = mapper.pushT(vi1.getType()); + + out.append("{ "); + out.append(vo1).append(" = ").append(vi1).append("; "); + out.append(vo2).append(" = ").append(vi2).append("; "); + out.append(vo3).append(" = ").append(vo1).append("; "); + out.append('}'); + } else { + final Variable vi1 = mapper.pop(); + final Variable vi2 = mapper.pop(); + final Variable vi3 = mapper.pop(); + final Variable vo4 = mapper.pushT(vi1.getType()); + final Variable vo3 = mapper.pushT(vi3.getType()); + final Variable vo2 = mapper.pushT(vi2.getType()); + final Variable vo1 = mapper.pushT(vi1.getType()); + + out.append("{ "); + out.append(vo1).append(" = ").append(vi1).append("; "); + out.append(vo2).append(" = ").append(vi2).append("; "); + out.append(vo3).append(" = ").append(vi3).append("; "); + out.append(vo4).append(" = ").append(vo1).append("; "); + out.append('}'); + } break; + } case opc_bipush: - out.append(mapper.push()).append(" = ") + out.append(mapper.pushI()).append(" = ") .append(Integer.toString(byteCodes[++i])).append(';'); break; case opc_sipush: - out.append(mapper.push()).append(" = ") + out.append(mapper.pushI()).append(" = ") .append(Integer.toString(readIntArg(byteCodes, i))) .append(';'); i += 2; @@ -808,48 +1145,51 @@ case opc_getfield: { int indx = readIntArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); - out.append(mapper.get(0)).append(" = ") - .append(mapper.get(0)).append(".fld_") - .append(fi[1]).append(';'); + final int type = fieldToVariableType(fi[2].charAt(0)); + final Variable v = mapper.popA(); + out.append(mapper.pushT(type)).append(" = ") + .append(v).append(".fld_").append(fi[1]).append(';'); i += 2; break; } case opc_getstatic: { int indx = readIntArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); - out.append(mapper.push()).append(" = ") + final int type = fieldToVariableType(fi[2].charAt(0)); + out.append(mapper.pushT(type)).append(" = ") .append(fi[0].replace('/', '_')) .append('.').append(fi[1]).append(';'); i += 2; addReference(fi[0]); break; } - case opc_putstatic: { - int indx = readIntArg(byteCodes, i); - String[] fi = jc.getFieldInfoName(indx); - out.append(fi[0].replace('/', '_')); - out.append('.').append(fi[1]).append(" = ") - .append(mapper.pop()).append(';'); - i += 2; - addReference(fi[0]); - break; - } case opc_putfield: { int indx = readIntArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); - out.append(mapper.get(1)).append(".fld_").append(fi[1]) - .append(" = ") - .append(mapper.get(0)).append(';'); - mapper.pop(2); + final int type = fieldToVariableType(fi[2].charAt(0)); + final Variable v = mapper.popT(type); + out.append(mapper.popA()).append(".fld_").append(fi[1]) + .append(" = ").append(v).append(';'); i += 2; break; } + case opc_putstatic: { + int indx = readIntArg(byteCodes, i); + String[] fi = jc.getFieldInfoName(indx); + final int type = fieldToVariableType(fi[2].charAt(0)); + out.append(fi[0].replace('/', '_')); + out.append('.').append(fi[1]).append(" = ") + .append(mapper.popT(type)).append(';'); + i += 2; + addReference(fi[0]); + break; + } case opc_checkcast: { int indx = readIntArg(byteCodes, i); final String type = jc.getClassName(indx); if (!type.startsWith("[")) { // no way to check arrays right now - out.append("if (").append(mapper.get(0)) + out.append("if (").append(mapper.getA(0)) .append(".$instOf_").append(type.replace('/', '_')) .append(" != 1) throw {};"); // XXX proper exception } @@ -859,33 +1199,36 @@ case opc_instanceof: { int indx = readIntArg(byteCodes, i); final String type = jc.getClassName(indx); - out.append(mapper.get(0)).append(" = ") - .append(mapper.get(0)).append(".$instOf_") - .append(type.replace('/', '_')) + final Variable v = mapper.popA(); + out.append(mapper.pushI()).append(" = ") + .append(v).append(".$instOf_") + .append(type.replace('/', '_')) .append(" ? 1 : 0;"); i += 2; break; } case opc_athrow: { + final Variable v = mapper.popA(); + mapper.clear(); + out.append("{ "); - out.append(mapper.bottom()).append(" = ") - .append(mapper.top()).append("; "); - out.append("throw ").append(mapper.bottom()).append("; "); + out.append(mapper.pushA()).append(" = ") + .append(v).append("; "); + out.append("throw ").append(v).append("; "); out.append('}'); - mapper.reset(1); break; } case opc_monitorenter: { out.append("/* monitor enter */"); - mapper.pop(1); + mapper.popA(); break; } case opc_monitorexit: { out.append("/* monitor exit */"); - mapper.pop(1); + mapper.popA(); break; } @@ -903,22 +1246,28 @@ out.append("\n"); } out.append(" }\n"); - - if (mapper.getMaxStackSize() > maxStack) { - throw new IllegalStateException("Incorrect stack usage"); - } } - private int generateIf(byte[] byteCodes, int i, final StackToVariableMapper mapper, final String test) throws IOException { + private int generateIf(byte[] byteCodes, int i, + final Variable v2, final Variable v1, + final String test) throws IOException { int indx = i + readIntArg(byteCodes, i); - out.append("if (").append(mapper.get(1)) + out.append("if (").append(v1) .append(' ').append(test).append(' ') - .append(mapper.get(0)).append(") { gt = " + indx) + .append(v2).append(") { gt = " + indx) .append("; continue; }"); - mapper.pop(2); return i + 2; } + private void generateCmp(Variable v2, Variable v1, Variable vr) + throws IOException { + out.append(vr).append(" = ") + .append('(').append(v1).append(" == ").append(v2).append(')') + .append(" ? 0") + .append(" : ((").append(v1).append(" < ").append(v2).append(')') + .append(" ? -1 : 1);"); + } + private int readIntArg(byte[] byteCodes, int offsetInstruction) { final int indxHi = byteCodes[offsetInstruction + 1] << 8; final int indxLo = byteCodes[offsetInstruction + 2]; @@ -935,7 +1284,7 @@ return byteCodes[offsetInstruction] & 0xff; } - private static void countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig, StringBuilder cnt) { + private static void countArgs(String descriptor, char[] returnType, StringBuilder sig, StringBuilder cnt) { int i = 0; Boolean count = null; boolean array = false; @@ -971,17 +1320,19 @@ cnt.append('0'); } } else { - hasReturnType[0] = true; sig.insert(firstPos, ch); if (array) { + returnType[0] = '['; sig.insert(firstPos, 'A'); + } else { + returnType[0] = ch; } } array = false; continue; case 'V': assert !count; - hasReturnType[0] = false; + returnType[0] = 'V'; sig.insert(firstPos, 'V'); continue; case 'L': @@ -999,7 +1350,7 @@ if (array) { sig.insert(firstPos, 'A'); } - hasReturnType[0] = true; + returnType[0] = 'L'; } i = next + 1; continue; @@ -1022,12 +1373,11 @@ name.append(m.getName()); } - boolean hasReturn[] = { false }; - countArgs(findDescriptor(m.getInternalSig()), hasReturn, name, cnt); + countArgs(findDescriptor(m.getInternalSig()), new char[1], name, cnt); return name.toString(); } - private String findMethodName(String[] mi, StringBuilder cnt, boolean[] hasReturn) { + private String findMethodName(String[] mi, StringBuilder cnt, char[] returnType) { StringBuilder name = new StringBuilder(); String descr = mi[2];//mi.getDescriptor(); String nm= mi[1]; @@ -1036,7 +1386,7 @@ } else { name.append(nm); } - countArgs(findDescriptor(descr), hasReturn, name, cnt); + countArgs(findDescriptor(descr), returnType, name, cnt); return name.toString(); } @@ -1044,15 +1394,20 @@ throws IOException { int methodIndex = readIntArg(byteCodes, i); String[] mi = jc.getFieldInfoName(methodIndex); - boolean[] hasReturn = { false }; + char[] returnType = { 'V' }; StringBuilder cnt = new StringBuilder(); - String mn = findMethodName(mi, cnt, hasReturn); + String mn = findMethodName(mi, cnt, returnType); final int numArguments = isStatic ? cnt.length() : cnt.length() + 1; + final Variable[] vars = new Variable[numArguments]; - if (hasReturn[0]) { - out.append((numArguments > 0) ? mapper.get(numArguments - 1) - : mapper.push()).append(" = "); + for (int j = numArguments - 1; j >= 0; --j) { + vars[j] = mapper.pop(); + } + + if (returnType[0] != 'V') { + out.append(mapper.pushT(fieldToVariableType(returnType[0]))) + .append(" = "); } final String in = mi[0]; @@ -1061,16 +1416,13 @@ out.append(mn); out.append('('); if (numArguments > 0) { - out.append(mapper.get(numArguments - 1)); - for (int j = numArguments - 2; j >= 0; --j) { + out.append(vars[0]); + for (int j = 1; j < numArguments; ++j) { out.append(", "); - out.append(mapper.get(j)); + out.append(vars[j]); } } out.append(");"); - if (numArguments > 0) { - mapper.pop(hasReturn[0] ? numArguments - 1 : numArguments); - } i += 2; addReference(in); return i; @@ -1079,26 +1431,31 @@ throws IOException { int methodIndex = readIntArg(byteCodes, i); String[] mi = jc.getFieldInfoName(methodIndex); - boolean[] hasReturn = { false }; + char[] returnType = { 'V' }; StringBuilder cnt = new StringBuilder(); - String mn = findMethodName(mi, cnt, hasReturn); + String mn = findMethodName(mi, cnt, returnType); - final int numArguments = cnt.length(); + final int numArguments = cnt.length() + 1; + final Variable[] vars = new Variable[numArguments]; - if (hasReturn[0]) { - out.append(mapper.get(numArguments)).append(" = "); + for (int j = numArguments - 1; j >= 0; --j) { + vars[j] = mapper.pop(); } - out.append(mapper.get(numArguments)).append('.'); + if (returnType[0] != 'V') { + out.append(mapper.pushT(fieldToVariableType(returnType[0]))) + .append(" = "); + } + + out.append(vars[0]).append('.'); out.append(mn); out.append('('); - out.append(mapper.get(numArguments)); - for (int j = numArguments - 1; j >= 0; --j) { + out.append(vars[0]); + for (int j = 1; j < numArguments; ++j) { out.append(", "); - out.append(mapper.get(j)); + out.append(vars[j]); } out.append(");"); - mapper.pop(hasReturn[0] ? numArguments : numArguments + 1); i += 2; return i; } @@ -1236,4 +1593,54 @@ } return " = null;"; } + + private static int constantToVariableType(final byte constantTag) { + switch (constantTag) { + case CONSTANT_INTEGER: + return Variable.TYPE_INT; + case CONSTANT_FLOAT: + return Variable.TYPE_FLOAT; + case CONSTANT_LONG: + return Variable.TYPE_LONG; + case CONSTANT_DOUBLE: + return Variable.TYPE_DOUBLE; + + case CONSTANT_CLASS: + case CONSTANT_UTF8: + case CONSTANT_UNICODE: + case CONSTANT_STRING: + return Variable.TYPE_REF; + + case CONSTANT_FIELD: + case CONSTANT_METHOD: + case CONSTANT_INTERFACEMETHOD: + case CONSTANT_NAMEANDTYPE: + /* unclear how to handle for now */ + default: + throw new IllegalStateException("Unhandled constant tag"); + } + } + + private static int fieldToVariableType(final char fieldType) { + switch (fieldType) { + case 'B': + case 'C': + case 'S': + case 'Z': + case 'I': + return Variable.TYPE_INT; + case 'J': + return Variable.TYPE_LONG; + case 'F': + return Variable.TYPE_FLOAT; + case 'D': + return Variable.TYPE_DOUBLE; + case 'L': + case '[': + return Variable.TYPE_REF; + + default: + throw new IllegalStateException("Unhandled field type"); + } + } } diff -r 8bd4adaf6590 -r f2352e0b713e vm/src/main/java/org/apidesign/vm4brwsr/Main.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Mon Dec 03 14:44:49 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Fri Dec 07 15:02:35 2012 +0100 @@ -39,7 +39,10 @@ Writer w = new BufferedWriter(new FileWriter(args[0])); StringArray classes = StringArray.asList(args); classes.delete(0); - GenJS.compile(w, classes); - w.close(); + try { + GenJS.compile(w, classes); + } finally { + w.close(); + } } } diff -r 8bd4adaf6590 -r f2352e0b713e vm/src/main/java/org/apidesign/vm4brwsr/StackToVariableMapper.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/StackToVariableMapper.java Mon Dec 03 14:44:49 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/StackToVariableMapper.java Fri Dec 07 15:02:35 2012 +0100 @@ -17,77 +17,214 @@ */ package org.apidesign.vm4brwsr; +import org.apidesign.javap.TypeArray; + +import static org.apidesign.javap.RuntimeConstants.ITEM_Bogus; +import static org.apidesign.javap.RuntimeConstants.ITEM_Integer; +import static org.apidesign.javap.RuntimeConstants.ITEM_Float; +import static org.apidesign.javap.RuntimeConstants.ITEM_Double; +import static org.apidesign.javap.RuntimeConstants.ITEM_Long; +import static org.apidesign.javap.RuntimeConstants.ITEM_Null; +import static org.apidesign.javap.RuntimeConstants.ITEM_InitObject; +import static org.apidesign.javap.RuntimeConstants.ITEM_Object; +import static org.apidesign.javap.RuntimeConstants.ITEM_NewObject; + public final class StackToVariableMapper { - private static final String VAR_NAME_PREFIX = "stack"; - - private int stackSize; - private StringBuilder varNameBuilder; - - private int maxStackSize; + private final TypeArray stackTypeIndexPairs; + private int[] typeCounters; + private int[] typeMaxCounters; public StackToVariableMapper() { - varNameBuilder = new StringBuilder(VAR_NAME_PREFIX); + stackTypeIndexPairs = new TypeArray(); + typeCounters = new int[Variable.LAST_TYPE + 1]; + typeMaxCounters = new int[Variable.LAST_TYPE + 1]; } - public void reset(final int newStackSize) { - stackSize = newStackSize; - if (maxStackSize < stackSize) { - maxStackSize = stackSize; + public void clear() { + for (int type = 0; type <= Variable.LAST_TYPE; ++type) { + typeCounters[type] = 0; + } + stackTypeIndexPairs.clear(); + } + + public void syncWithFrameStack(final TypeArray frameStack) { + clear(); + + final int size = frameStack.getSize(); + for (int i = 0; i < size; ++i) { + final int frameStackValue = frameStack.get(i); + switch (frameStackValue & 0xff) { + case ITEM_Integer: + pushTypeImpl(Variable.TYPE_INT); + break; + case ITEM_Float: + pushTypeImpl(Variable.TYPE_FLOAT); + break; + case ITEM_Double: + pushTypeImpl(Variable.TYPE_DOUBLE); + break; + case ITEM_Long: + pushTypeImpl(Variable.TYPE_LONG); + break; + case ITEM_Object: + pushTypeImpl(Variable.TYPE_REF); + break; + + case ITEM_Bogus: + case ITEM_Null: + case ITEM_InitObject: + case ITEM_NewObject: + /* unclear how to handle for now */ + default: + throw new IllegalStateException( + "Unhandled frame stack type"); + } } } - public void push(final int numOfElements) { - stackSize += numOfElements; - if (maxStackSize < stackSize) { - maxStackSize = stackSize; + public Variable pushI() { + return pushT(Variable.TYPE_INT); + } + + public Variable pushL() { + return pushT(Variable.TYPE_LONG); + } + + public Variable pushF() { + return pushT(Variable.TYPE_FLOAT); + } + + public Variable pushD() { + return pushT(Variable.TYPE_DOUBLE); + } + + public Variable pushA() { + return pushT(Variable.TYPE_REF); + } + + public Variable pushT(final int type) { + return getVariable(pushTypeImpl(type)); + } + + public Variable popI() { + return popT(Variable.TYPE_INT); + } + + public Variable popL() { + return popT(Variable.TYPE_LONG); + } + + public Variable popF() { + return popT(Variable.TYPE_FLOAT); + } + + public Variable popD() { + return popT(Variable.TYPE_DOUBLE); + } + + public Variable popA() { + return popT(Variable.TYPE_REF); + } + + public Variable popT(final int type) { + final Variable variable = getT(0, type); + popImpl(1); + return variable; + } + + public Variable pop() { + final Variable variable = get(0); + popImpl(1); + return variable; + } + + public void pop(final int count) { + final int stackSize = stackTypeIndexPairs.getSize(); + if (count > stackSize) { + throw new IllegalStateException("Stack underflow"); + } + popImpl(count); + } + + public Variable getI(final int indexFromTop) { + return getT(indexFromTop, Variable.TYPE_INT); + } + + public Variable getL(final int indexFromTop) { + return getT(indexFromTop, Variable.TYPE_LONG); + } + + public Variable getF(final int indexFromTop) { + return getT(indexFromTop, Variable.TYPE_FLOAT); + } + + public Variable getD(final int indexFromTop) { + return getT(indexFromTop, Variable.TYPE_DOUBLE); + } + + public Variable getA(final int indexFromTop) { + return getT(indexFromTop, Variable.TYPE_REF); + } + + public Variable getT(final int indexFromTop, final int type) { + 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) { + throw new IllegalStateException("Type mismatch"); + } + + return getVariable(stackValue); + } + + public Variable get(final int indexFromTop) { + final int stackSize = stackTypeIndexPairs.getSize(); + if (indexFromTop >= stackSize) { + throw new IllegalStateException("Stack underflow"); + } + final int stackValue = + stackTypeIndexPairs.get(stackSize - indexFromTop - 1); + + return getVariable(stackValue); + } + + private int pushTypeImpl(final int type) { + final int count = typeCounters[type]; + final int value = (count << 8) | (type & 0xff); + incCounter(type); + stackTypeIndexPairs.add(value); + + return value; + } + + 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; } } - public String push() { - push(1); - return get(0); + private void decCounter(final int type) { + --typeCounters[type]; } - public void pop(final int numOfElements) { - if (numOfElements > stackSize) { - throw new IllegalStateException("Stack underflow"); - } - stackSize -= numOfElements; - } + public Variable getVariable(final int typeAndIndex) { + final int type = typeAndIndex & 0xff; + final int index = typeAndIndex >> 8; - public String pop() { - final String variableName = get(0); - pop(1); - return variableName; - } - - public String get(final int indexFromTop) { - if (indexFromTop >= stackSize) { - throw new IllegalStateException("Stack underflow"); - } - - return constructVariableName(stackSize - indexFromTop - 1); - } - - public String top() { - return get(0); - } - - public String bottom() { - if (stackSize == 0) { - throw new IllegalStateException("Stack underflow"); - } - - return constructVariableName(0); - } - - public int getMaxStackSize() { - return maxStackSize; - } - - public String constructVariableName(final int index) { - varNameBuilder.setLength(VAR_NAME_PREFIX.length()); - varNameBuilder.append(index); - return varNameBuilder.toString(); + return Variable.getStackVariable(type, index); } } diff -r 8bd4adaf6590 -r f2352e0b713e vm/src/main/java/org/apidesign/vm4brwsr/Variable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Variable.java Fri Dec 07 15:02:35 2012 +0100 @@ -0,0 +1,101 @@ +/** + * 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; + +public final class Variable implements CharSequence { + public static final int TYPE_INT = 0; + public static final int TYPE_LONG = 1; + public static final int TYPE_FLOAT = 2; + public static final int TYPE_DOUBLE = 3; + public static final int TYPE_REF = 4; + + public static final int LAST_TYPE = TYPE_REF; + + private static final String STACK_VAR_PREFIX = "st"; + + private final String name; + private final int type; + private final int index; + + private static final char[] TYPE_IDS = { 'I', 'L', 'F', 'D', 'A' }; + + private Variable(final String prefix, final int type, final int index) { + this.name = prefix + TYPE_IDS[type] + index; + this.type = type; + this.index = index; + } + + public static Variable getStackVariable( + final int type, final int index) { + // TODO: precreate frequently used variables + return new Variable(STACK_VAR_PREFIX, type, index); + } + + public String getName() { + return name; + } + + public int getType() { + return type; + } + + public int getIndex() { + return index; + } + + public boolean isCategory2() { + return (type == TYPE_LONG) || (type == TYPE_DOUBLE); + } + + @Override + public int length() { + return name.length(); + } + + @Override + public char charAt(final int index) { + return name.charAt(index); + } + + @Override + public CharSequence subSequence(final int start, final int end) { + return name.subSequence(start, end); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } + if (!(other instanceof Variable)) { + return false; + } + + return name.equals(((Variable) other).name); + } + + @Override + public String toString() { + return name; + } +}