diff --git a/core/src/main/java/org/teavm/ast/ArrayType.java b/core/src/main/java/org/teavm/ast/ArrayType.java new file mode 100644 index 000000000..954d48a26 --- /dev/null +++ b/core/src/main/java/org/teavm/ast/ArrayType.java @@ -0,0 +1,27 @@ +/* + * Copyright 2016 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.ast; + +public enum ArrayType { + BYTE, + SHORT, + CHAR, + INT, + LONG, + FLOAT, + DOUBLE, + OBJECT +} diff --git a/core/src/main/java/org/teavm/ast/Expr.java b/core/src/main/java/org/teavm/ast/Expr.java index 4c6d70af2..d2dad0f31 100644 --- a/core/src/main/java/org/teavm/ast/Expr.java +++ b/core/src/main/java/org/teavm/ast/Expr.java @@ -75,10 +75,11 @@ public abstract class Expr implements Cloneable { return result; } - public static Expr subscript(Expr array, Expr index) { + public static Expr subscript(Expr array, Expr index, ArrayType type) { SubscriptExpr expr = new SubscriptExpr(); expr.setArray(array); expr.setIndex(index); + expr.setType(type); return expr; } diff --git a/core/src/main/java/org/teavm/ast/SubscriptExpr.java b/core/src/main/java/org/teavm/ast/SubscriptExpr.java index 49be6bf71..181b5e1ed 100644 --- a/core/src/main/java/org/teavm/ast/SubscriptExpr.java +++ b/core/src/main/java/org/teavm/ast/SubscriptExpr.java @@ -17,13 +17,10 @@ package org.teavm.ast; import java.util.Map; -/** - * - * @author Alexey Andreev - */ public class SubscriptExpr extends Expr { private Expr array; private Expr index; + private ArrayType type; public Expr getArray() { return array; @@ -41,6 +38,14 @@ public class SubscriptExpr extends Expr { this.index = index; } + public ArrayType getType() { + return type; + } + + public void setType(ArrayType type) { + this.type = type; + } + @Override public void acceptVisitor(ExprVisitor visitor) { visitor.visit(this); @@ -55,6 +60,7 @@ public class SubscriptExpr extends Expr { SubscriptExpr copy = new SubscriptExpr(); copy.setArray(array != null ? array.clone(cache) : null); copy.setIndex(index != null ? index.clone(cache) : null); + copy.setType(type); return copy; } } diff --git a/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java b/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java index c44781419..2ffdf8031 100644 --- a/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java +++ b/core/src/main/java/org/teavm/ast/decompilation/StatementGenerator.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.teavm.ast.ArrayType; import org.teavm.ast.AssignmentStatement; import org.teavm.ast.BinaryOperation; import org.teavm.ast.BreakStatement; @@ -49,6 +50,7 @@ import org.teavm.model.MethodReference; import org.teavm.model.Program; import org.teavm.model.ValueType; import org.teavm.model.Variable; +import org.teavm.model.instructions.ArrayElementType; import org.teavm.model.instructions.ArrayLengthInstruction; import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.BinaryBranchingInstruction; @@ -442,18 +444,42 @@ class StatementGenerator implements InstructionVisitor { @Override public void visit(GetElementInstruction insn) { - assign(Expr.subscript(Expr.var(insn.getArray().getIndex()), Expr.var(insn.getIndex().getIndex())), - insn.getReceiver()); + Expr subscript = Expr.subscript(Expr.var(insn.getArray().getIndex()), Expr.var(insn.getIndex().getIndex()), + map(insn.getType())); + assign(subscript, insn.getReceiver()); } @Override public void visit(PutElementInstruction insn) { - AssignmentStatement stmt = Statement.assign(Expr.subscript(Expr.var(insn.getArray().getIndex()), - Expr.var(insn.getIndex().getIndex())), Expr.var(insn.getValue().getIndex())); + Expr subscript = Expr.subscript(Expr.var(insn.getArray().getIndex()), + Expr.var(insn.getIndex().getIndex()), map(insn.getType())); + AssignmentStatement stmt = Statement.assign(subscript, Expr.var(insn.getValue().getIndex())); stmt.setLocation(currentLocation); statements.add(stmt); } + private static ArrayType map(ArrayElementType type) { + switch (type) { + case BYTE: + return ArrayType.BYTE; + case SHORT: + return ArrayType.SHORT; + case CHAR: + return ArrayType.SHORT; + case INT: + return ArrayType.INT; + case LONG: + return ArrayType.LONG; + case FLOAT: + return ArrayType.FLOAT; + case DOUBLE: + return ArrayType.DOUBLE; + case OBJECT: + return ArrayType.OBJECT; + } + throw new AssertionError(); + } + @Override public void visit(InvokeInstruction insn) { Expr[] exprArgs = new Expr[insn.getMethod().getParameterTypes().length]; diff --git a/core/src/main/java/org/teavm/cache/AstIO.java b/core/src/main/java/org/teavm/cache/AstIO.java index 724517f9a..fb6a7dfc2 100644 --- a/core/src/main/java/org/teavm/cache/AstIO.java +++ b/core/src/main/java/org/teavm/cache/AstIO.java @@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.teavm.ast.ArrayType; import org.teavm.ast.AssignmentStatement; import org.teavm.ast.AsyncMethodNode; import org.teavm.ast.AsyncMethodPart; @@ -509,6 +510,7 @@ public class AstIO { output.writeByte(11); writeExpr(expr.getArray()); writeExpr(expr.getIndex()); + output.writeByte(expr.getType().ordinal()); } catch (IOException e) { throw new IOExceptionWrapper(e); } @@ -899,6 +901,7 @@ public class AstIO { SubscriptExpr expr = new SubscriptExpr(); expr.setArray(readExpr(input)); expr.setIndex(readExpr(input)); + expr.setType(ArrayType.values()[input.readByte()]); return expr; } case 12: { diff --git a/core/src/main/java/org/teavm/cache/ProgramIO.java b/core/src/main/java/org/teavm/cache/ProgramIO.java index f34a2754a..53c2c7d5b 100644 --- a/core/src/main/java/org/teavm/cache/ProgramIO.java +++ b/core/src/main/java/org/teavm/cache/ProgramIO.java @@ -536,6 +536,7 @@ public class ProgramIO { public void visit(GetElementInstruction insn) { try { output.writeByte(31); + output.writeByte(insn.getType().ordinal()); output.writeShort(insn.getReceiver().getIndex()); output.writeShort(insn.getArray().getIndex()); output.writeShort(insn.getIndex().getIndex()); @@ -548,6 +549,7 @@ public class ProgramIO { public void visit(PutElementInstruction insn) { try { output.writeByte(32); + output.writeByte(insn.getType().ordinal()); output.writeShort(insn.getArray().getIndex()); output.writeShort(insn.getIndex().getIndex()); output.writeShort(insn.getValue().getIndex()); @@ -965,14 +967,14 @@ public class ProgramIO { return insn; } case 31: { - GetElementInstruction insn = new GetElementInstruction(); + GetElementInstruction insn = new GetElementInstruction(arrayElementTypes[input.readByte()]); insn.setReceiver(program.variableAt(input.readShort())); insn.setArray(program.variableAt(input.readShort())); insn.setIndex(program.variableAt(input.readShort())); return insn; } case 32: { - PutElementInstruction insn = new PutElementInstruction(); + PutElementInstruction insn = new PutElementInstruction(arrayElementTypes[input.readByte()]); insn.setArray(program.variableAt(input.readShort())); insn.setIndex(program.variableAt(input.readShort())); insn.setValue(program.variableAt(input.readShort())); diff --git a/core/src/main/java/org/teavm/dependency/DataFlowGraphBuilder.java b/core/src/main/java/org/teavm/dependency/DataFlowGraphBuilder.java index 1d0cff0f1..339362cc3 100644 --- a/core/src/main/java/org/teavm/dependency/DataFlowGraphBuilder.java +++ b/core/src/main/java/org/teavm/dependency/DataFlowGraphBuilder.java @@ -284,12 +284,13 @@ public class DataFlowGraphBuilder implements InstructionReader { } @Override - public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { builder.addEdge(array.getIndex(), receiver.getIndex()); } @Override - public void putElement(VariableReader array, VariableReader index, VariableReader value) { + public void putElement(VariableReader array, VariableReader index, VariableReader value, ArrayElementType type) { builder.addEdge(value.getIndex(), array.getIndex()); } diff --git a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java index 1038121b3..0145ee2a0 100644 --- a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -655,7 +655,8 @@ class DependencyGraphBuilder { } @Override - public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { DependencyNode arrayNode = nodes[array.getIndex()]; DependencyNode receiverNode = nodes[receiver.getIndex()]; if (arrayNode != null && receiverNode != null && receiverNode != arrayNode.getArrayItem()) { @@ -664,7 +665,8 @@ class DependencyGraphBuilder { } @Override - public void putElement(VariableReader array, VariableReader index, VariableReader value) { + public void putElement(VariableReader array, VariableReader index, VariableReader value, + ArrayElementType type) { DependencyNode valueNode = nodes[value.getIndex()]; DependencyNode arrayNode = nodes[array.getIndex()]; if (valueNode != null && arrayNode != null && valueNode != arrayNode.getArrayItem()) { diff --git a/core/src/main/java/org/teavm/model/InstructionReadVisitor.java b/core/src/main/java/org/teavm/model/InstructionReadVisitor.java index 236d63c2e..49610fd85 100644 --- a/core/src/main/java/org/teavm/model/InstructionReadVisitor.java +++ b/core/src/main/java/org/teavm/model/InstructionReadVisitor.java @@ -173,12 +173,12 @@ class InstructionReadVisitor implements InstructionVisitor { @Override public void visit(GetElementInstruction insn) { - reader.getElement(insn.getReceiver(), insn.getArray(), insn.getIndex()); + reader.getElement(insn.getReceiver(), insn.getArray(), insn.getIndex(), insn.getType()); } @Override public void visit(PutElementInstruction insn) { - reader.putElement(insn.getArray(), insn.getIndex(), insn.getValue()); + reader.putElement(insn.getArray(), insn.getIndex(), insn.getValue(), insn.getType()); } @Override diff --git a/core/src/main/java/org/teavm/model/Interpreter.java b/core/src/main/java/org/teavm/model/Interpreter.java index 46c1feac1..d4206757a 100644 --- a/core/src/main/java/org/teavm/model/Interpreter.java +++ b/core/src/main/java/org/teavm/model/Interpreter.java @@ -696,14 +696,16 @@ public class Interpreter { } @Override - public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { Object jvmArray = variables[array.getIndex()]; int indexValue = (Integer) variables[index.getIndex()]; variables[receiver.getIndex()] = Array.get(jvmArray, indexValue); } @Override - public void putElement(VariableReader array, VariableReader index, VariableReader value) { + public void putElement(VariableReader array, VariableReader index, VariableReader value, + ArrayElementType type) { Object jvmArray = variables[array.getIndex()]; int indexValue = (Integer) variables[index.getIndex()]; Array.set(jvmArray, indexValue, variables[value.getIndex()]); diff --git a/core/src/main/java/org/teavm/model/emit/ValueEmitter.java b/core/src/main/java/org/teavm/model/emit/ValueEmitter.java index 1b1e74023..a0925259a 100644 --- a/core/src/main/java/org/teavm/model/emit/ValueEmitter.java +++ b/core/src/main/java/org/teavm/model/emit/ValueEmitter.java @@ -844,7 +844,8 @@ public class ValueEmitter { ValueEmitter array = unwrapArray(); Variable result = pe.getProgram().createVariable(); - GetElementInstruction insn = new GetElementInstruction(); + ValueType.Array arrayType = (ValueType.Array) array.getType(); + GetElementInstruction insn = new GetElementInstruction(getArrayElementType(arrayType.getItemType())); insn.setArray(array.variable); insn.setIndex(index.widenToInteger().variable); insn.setReceiver(result); @@ -861,7 +862,7 @@ public class ValueEmitter { throw new EmitException("Can't set element of non-array type: " + type); } - PutElementInstruction insn = new PutElementInstruction(); + PutElementInstruction insn = new PutElementInstruction(getArrayElementType(value.getType())); insn.setArray(unwrapArray().variable); insn.setIndex(index.widenToInteger().variable); insn.setValue(value.variable); diff --git a/core/src/main/java/org/teavm/model/instructions/GetElementInstruction.java b/core/src/main/java/org/teavm/model/instructions/GetElementInstruction.java index ac3e7fac8..1f5df6f5e 100644 --- a/core/src/main/java/org/teavm/model/instructions/GetElementInstruction.java +++ b/core/src/main/java/org/teavm/model/instructions/GetElementInstruction.java @@ -18,15 +18,20 @@ package org.teavm.model.instructions; import org.teavm.model.Instruction; import org.teavm.model.Variable; -/** - * - * @author Alexey Andreev - */ public class GetElementInstruction extends Instruction { + private ArrayElementType type; private Variable array; private Variable index; private Variable receiver; + public GetElementInstruction(ArrayElementType type) { + this.type = type; + } + + public ArrayElementType getType() { + return type; + } + public Variable getArray() { return array; } diff --git a/core/src/main/java/org/teavm/model/instructions/InstructionReader.java b/core/src/main/java/org/teavm/model/instructions/InstructionReader.java index 2be0bd725..076c0e6c8 100644 --- a/core/src/main/java/org/teavm/model/instructions/InstructionReader.java +++ b/core/src/main/java/org/teavm/model/instructions/InstructionReader.java @@ -18,10 +18,6 @@ package org.teavm.model.instructions; import java.util.List; import org.teavm.model.*; -/** - * - * @author Alexey Andreev - */ public interface InstructionReader { void location(InstructionLocation location); @@ -87,9 +83,9 @@ public interface InstructionReader { void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType); - void getElement(VariableReader receiver, VariableReader array, VariableReader index); + void getElement(VariableReader receiver, VariableReader array, VariableReader index, ArrayElementType elementType); - void putElement(VariableReader array, VariableReader index, VariableReader value); + void putElement(VariableReader array, VariableReader index, VariableReader value, ArrayElementType elementType); void invoke(VariableReader receiver, VariableReader instance, MethodReference method, List arguments, InvocationType type); diff --git a/core/src/main/java/org/teavm/model/instructions/PutElementInstruction.java b/core/src/main/java/org/teavm/model/instructions/PutElementInstruction.java index d1c32ba45..11256ddf0 100644 --- a/core/src/main/java/org/teavm/model/instructions/PutElementInstruction.java +++ b/core/src/main/java/org/teavm/model/instructions/PutElementInstruction.java @@ -18,15 +18,20 @@ package org.teavm.model.instructions; import org.teavm.model.Instruction; import org.teavm.model.Variable; -/** - * - * @author Alexey Andreev - */ public class PutElementInstruction extends Instruction { + private ArrayElementType type; private Variable array; private Variable index; private Variable value; + public PutElementInstruction(ArrayElementType type) { + this.type = type; + } + + public ArrayElementType getType() { + return type; + } + public Variable getArray() { return array; } diff --git a/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java b/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java index 93340c43a..ebdfed648 100644 --- a/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java +++ b/core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java @@ -362,11 +362,13 @@ public class AsyncMethodFinder { } @Override - public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { } @Override - public void putElement(VariableReader array, VariableReader index, VariableReader value) { + public void putElement(VariableReader array, VariableReader index, VariableReader value, + ArrayElementType type) { } @Override diff --git a/core/src/main/java/org/teavm/model/util/InstructionCopyReader.java b/core/src/main/java/org/teavm/model/util/InstructionCopyReader.java index df0df1816..2d7d876fe 100644 --- a/core/src/main/java/org/teavm/model/util/InstructionCopyReader.java +++ b/core/src/main/java/org/teavm/model/util/InstructionCopyReader.java @@ -386,8 +386,9 @@ public class InstructionCopyReader implements InstructionReader { } @Override - public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { - GetElementInstruction insnCopy = new GetElementInstruction(); + public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { + GetElementInstruction insnCopy = new GetElementInstruction(type); insnCopy.setArray(copyVar(array)); insnCopy.setReceiver(copyVar(receiver)); insnCopy.setIndex(copyVar(index)); @@ -396,8 +397,8 @@ public class InstructionCopyReader implements InstructionReader { } @Override - public void putElement(VariableReader array, VariableReader index, VariableReader value) { - PutElementInstruction insnCopy = new PutElementInstruction(); + public void putElement(VariableReader array, VariableReader index, VariableReader value, ArrayElementType type) { + PutElementInstruction insnCopy = new PutElementInstruction(type); insnCopy.setArray(copyVar(array)); insnCopy.setValue(copyVar(value)); insnCopy.setIndex(copyVar(index)); diff --git a/core/src/main/java/org/teavm/model/util/InstructionStringifier.java b/core/src/main/java/org/teavm/model/util/InstructionStringifier.java index 382239cf7..a9ff79c47 100644 --- a/core/src/main/java/org/teavm/model/util/InstructionStringifier.java +++ b/core/src/main/java/org/teavm/model/util/InstructionStringifier.java @@ -307,13 +307,14 @@ public class InstructionStringifier implements InstructionReader { } @Override - public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { sb.append("@").append(receiver.getIndex()).append(" := @").append(array.getIndex()).append("[@") .append(index.getIndex()).append("]"); } @Override - public void putElement(VariableReader array, VariableReader index, VariableReader value) { + public void putElement(VariableReader array, VariableReader index, VariableReader value, ArrayElementType type) { sb.append("@").append(array.getIndex()).append("[@").append(index.getIndex()).append("] := @") .append(value.getIndex()); } diff --git a/core/src/main/java/org/teavm/model/util/TypeInferer.java b/core/src/main/java/org/teavm/model/util/TypeInferer.java index 2c4c23e4b..838d44c79 100644 --- a/core/src/main/java/org/teavm/model/util/TypeInferer.java +++ b/core/src/main/java/org/teavm/model/util/TypeInferer.java @@ -234,7 +234,8 @@ public class TypeInferer { } @Override - public void putElement(VariableReader array, VariableReader index, VariableReader value) { + public void putElement(VariableReader array, VariableReader index, VariableReader value, + ArrayElementType type) { } @Override @@ -325,7 +326,8 @@ public class TypeInferer { } @Override - public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { arrayElemBuilder.addEdge(array.getIndex(), receiver.getIndex()); } diff --git a/core/src/main/java/org/teavm/parsing/ProgramParser.java b/core/src/main/java/org/teavm/parsing/ProgramParser.java index 73a0c18be..89d59ea37 100644 --- a/core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -905,7 +905,7 @@ public class ProgramParser { unwrapInsn.setArray(getVariable(array)); unwrapInsn.setReceiver(unwrapInsn.getArray()); addInstruction(unwrapInsn); - GetElementInstruction insn = new GetElementInstruction(); + GetElementInstruction insn = new GetElementInstruction(type); insn.setArray(getVariable(array)); insn.setIndex(getVariable(arrIndex)); insn.setReceiver(getVariable(var)); @@ -920,7 +920,7 @@ public class ProgramParser { unwrapInsn.setArray(getVariable(array)); unwrapInsn.setReceiver(unwrapInsn.getArray()); addInstruction(unwrapInsn); - PutElementInstruction insn = new PutElementInstruction(); + PutElementInstruction insn = new PutElementInstruction(type); insn.setArray(getVariable(array)); insn.setIndex(getVariable(arrIndex)); insn.setValue(getVariable(value)); diff --git a/core/src/main/java/org/teavm/runtime/Allocator.java b/core/src/main/java/org/teavm/runtime/Allocator.java index 24ad57f25..95bbfe80f 100644 --- a/core/src/main/java/org/teavm/runtime/Allocator.java +++ b/core/src/main/java/org/teavm/runtime/Allocator.java @@ -33,16 +33,14 @@ public final class Allocator { return result; } - public static Address allocateArray(RuntimeClass tag, int size, byte depth) { + public static Address allocateArray(RuntimeClass tag, int size) { Address result = address; - int sizeInBytes = (size + 1) * 4 + Structure.sizeOf(RuntimeArray.class); + int sizeInBytes = tag.size * 4 + Structure.sizeOf(RuntimeArray.class); address = result.add(sizeInBytes); RuntimeArray array = result.toStructure(); - array.classReference = RuntimeClass.getArrayClass().toAddress().toInt() >> 3; - array.componentClassReference = tag.toAddress().toInt() >> 3; + array.classReference = tag.toAddress().toInt() >> 3; array.size = size; - address.add(Structure.sizeOf(RuntimeArray.class)).putByte(depth); return result; } diff --git a/core/src/main/java/org/teavm/runtime/RuntimeArray.java b/core/src/main/java/org/teavm/runtime/RuntimeArray.java index 1eca989c5..abcdab62e 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeArray.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeArray.java @@ -16,6 +16,5 @@ package org.teavm.runtime; public class RuntimeArray extends RuntimeObject { - public int componentClassReference; int size; } diff --git a/core/src/main/java/org/teavm/runtime/RuntimeClass.java b/core/src/main/java/org/teavm/runtime/RuntimeClass.java index bb95403c9..0e8301676 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeClass.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeClass.java @@ -19,20 +19,14 @@ import org.teavm.interop.Structure; public class RuntimeClass extends Structure { public static int INITIALIZED = 1; - - public static int BOOLEAN_CLASS = -1; - public static int BYTE_CLASS = -2; - public static int SHORT_CLASS = -3; - public static int CHAR_CLASS = -4; - public static int INT_CLASS = -5; - public static int LONG_CLASS = -6; - public static int FLOAT_CLASS = -7; - public static int DOUBLE_CLASS = -8; + public static int PRIMITIVE = 1; public int size; public int flags; public int tag; public int canary; + public RuntimeClass itemType; + public RuntimeClass arrayType; public static int computeCanary(int size, int tag) { return size ^ (tag << 8) ^ (tag >>> 24) ^ (0xAAAAAAAA); @@ -41,6 +35,4 @@ public class RuntimeClass extends Structure { public int computeCanary() { return computeCanary(size, tag); } - - public static native RuntimeClass getArrayClass(); } diff --git a/core/src/main/java/org/teavm/wasm/WasmTarget.java b/core/src/main/java/org/teavm/wasm/WasmTarget.java index 3efe86ace..9e102e800 100644 --- a/core/src/main/java/org/teavm/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/wasm/WasmTarget.java @@ -43,6 +43,7 @@ import org.teavm.model.MethodHolder; import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; import org.teavm.model.Program; +import org.teavm.model.ValueType; import org.teavm.model.classes.TagRegistry; import org.teavm.model.classes.VirtualTableProvider; import org.teavm.model.instructions.InvocationType; @@ -62,7 +63,6 @@ import org.teavm.wasm.generate.WasmGenerationContext; import org.teavm.wasm.generate.WasmGenerator; import org.teavm.wasm.generate.WasmMangling; import org.teavm.wasm.intrinsics.WasmAddressIntrinsic; -import org.teavm.wasm.intrinsics.WasmRuntimeClassIntrinsic; import org.teavm.wasm.intrinsics.WasmRuntimeIntrinsic; import org.teavm.wasm.intrinsics.WasmStructureIntrinsic; import org.teavm.wasm.model.WasmFunction; @@ -118,7 +118,7 @@ public class WasmTarget implements TeaVMTarget { dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocate", RuntimeClass.class, Address.class), null).use(); dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocateArray", - RuntimeClass.class, int.class, byte.class, Address.class), null).use(); + RuntimeClass.class, int.class, Address.class), null).use(); dependencyChecker.linkMethod(new MethodReference(Allocator.class, "", void.class), null).use(); } @@ -131,22 +131,14 @@ public class WasmTarget implements TeaVMTarget { VirtualTableProvider vtableProvider = createVirtualTableProvider(classes); TagRegistry tagRegistry = new TagRegistry(classes); BinaryWriter binaryWriter = new BinaryWriter(256); - WasmClassGenerator classGenerator = new WasmClassGenerator(classes, vtableProvider, tagRegistry, - binaryWriter); - for (String className : classes.getClassNames()) { - classGenerator.addClass(className); - if (controller.wasCancelled()) { - return; - } - } - classGenerator.addArrayClass(); + WasmClassGenerator classGenerator = new WasmClassGenerator(controller.getUnprocessedClassSource(), + vtableProvider, tagRegistry, binaryWriter); Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(), new HashSet<>()); WasmGenerationContext context = new WasmGenerationContext(classes, vtableProvider, tagRegistry); context.addIntrinsic(new WasmAddressIntrinsic()); - context.addIntrinsic(new WasmRuntimeClassIntrinsic(classGenerator)); context.addIntrinsic(new WasmStructureIntrinsic(classGenerator)); context.addIntrinsic(new WasmRuntimeIntrinsic()); @@ -263,7 +255,7 @@ public class WasmTarget implements TeaVMTarget { WasmBlock block = new WasmBlock(false); - int index = classGenerator.getClassPointer(className); + int index = classGenerator.getClassPointer(ValueType.object(className)); WasmExpression initFlag = new WasmLoadInt32(4, new WasmInt32Constant(index), WasmInt32Subtype.INT32); initFlag = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND, initFlag, new WasmInt32Constant(RuntimeClass.INITIALIZED)); diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java b/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java index 46877a1de..c83ca4ea8 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java @@ -45,8 +45,7 @@ import org.teavm.wasm.binary.DataValue; public class WasmClassGenerator { private ClassReaderSource classSource; - private Map binaryDataMap = new LinkedHashMap<>(); - private ClassBinaryData arrayClassData; + private Map binaryDataMap = new LinkedHashMap<>(); private BinaryWriter binaryWriter; private Map functions = new HashMap<>(); private List functionTable = new ArrayList<>(); @@ -57,7 +56,9 @@ public class WasmClassGenerator { DataPrimitives.INT, /* size */ DataPrimitives.INT, /* flags */ DataPrimitives.INT, /* tag */ - DataPrimitives.INT /* canary */); + DataPrimitives.INT, /* canary */ + DataPrimitives.ADDRESS, /* item type */ + DataPrimitives.ADDRESS /* array type */); public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter) { @@ -67,31 +68,69 @@ public class WasmClassGenerator { this.binaryWriter = binaryWriter; } - public void addClass(String className) { - if (binaryDataMap.containsKey(className)) { + private void addClass(ValueType type) { + if (binaryDataMap.containsKey(type)) { return; } - ClassReader cls = classSource.get(className); ClassBinaryData binaryData = new ClassBinaryData(); - binaryData.name = className; - binaryDataMap.put(className, binaryData); + binaryData.type = type; + binaryDataMap.put(type, binaryData); - calculateLayout(cls, binaryData); - if (binaryData.start < 0) { - return; + if (type instanceof ValueType.Primitive) { + int size = 0; + switch (((ValueType.Primitive) type).getKind()) { + case BOOLEAN: + case BYTE: + size = 1; + break; + case SHORT: + case CHARACTER: + size = 2; + break; + case INTEGER: + case FLOAT: + size = 4; + break; + case LONG: + case DOUBLE: + size = 5; + break; + } + + binaryData.data = createPrimitiveClassData(size); + binaryData.start = binaryWriter.append(binaryData.data); + } else if (type == ValueType.VOID) { + binaryData.data = createPrimitiveClassData(0); + binaryData.start = binaryWriter.append(binaryData.data); + } else if (type instanceof ValueType.Object) { + String className = ((ValueType.Object) type).getClassName(); + ClassReader cls = classSource.get(className); + + calculateLayout(cls, binaryData); + if (binaryData.start >= 0) { + binaryData.start = binaryWriter.append(createStructure(binaryData)); + } + } else if (type instanceof ValueType.Array) { + ValueType itemType = ((ValueType.Array) type).getItemType(); + addClass(itemType); + ClassBinaryData itemBinaryData = binaryDataMap.get(itemType); + + binaryData.size = 4; + binaryData.data = classStructure.createValue(); + binaryData.data.setInt(0, 4); + binaryData.data.setAddress(4, itemBinaryData.start); + binaryData.start = binaryWriter.append(binaryData.data); + + itemBinaryData.data.setAddress(5, binaryData.start); } - - binaryData.start = binaryWriter.append(createStructure(binaryData)); } - public void addArrayClass() { - if (arrayClassData != null) { - return; - } - - arrayClassData = new ClassBinaryData(); - arrayClassData.start = binaryWriter.append(classStructure.createValue()); + private DataValue createPrimitiveClassData(int size) { + DataValue value = classStructure.createValue(); + value.setInt(0, size); + value.setInt(1, RuntimeClass.PRIMITIVE); + return value; } public List getFunctionTable() { @@ -99,16 +138,19 @@ public class WasmClassGenerator { } private DataValue createStructure(ClassBinaryData binaryData) { - VirtualTable vtable = vtableProvider.lookup(binaryData.name); + String name = ((ValueType.Object) binaryData.type).getClassName(); + + VirtualTable vtable = vtableProvider.lookup(name); int vtableSize = vtable != null ? vtable.getEntries().size() : 0; DataType arrayType = new DataArray(DataPrimitives.INT, vtableSize); DataValue wrapper = new DataStructure((byte) 0, classStructure, arrayType).createValue(); DataValue array = wrapper.getValue(1); DataValue header = wrapper.getValue(0); + binaryData.data = header; header.setInt(0, binaryData.size); - List ranges = tagRegistry.getRanges(binaryData.name); + List ranges = tagRegistry.getRanges(name); int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0); header.setInt(2, tag); header.setInt(3, RuntimeClass.computeCanary(binaryData.size, tag)); @@ -135,27 +177,30 @@ public class WasmClassGenerator { return wrapper; } - public int getClassPointer(String className) { - ClassBinaryData data = binaryDataMap.get(className); + public int getClassPointer(ValueType type) { + addClass(type); + ClassBinaryData data = binaryDataMap.get(type); return data.start; } public int getFieldOffset(FieldReference field) { - ClassBinaryData data = binaryDataMap.get(field.getClassName()); + ValueType type = ValueType.object(field.getClassName()); + addClass(type); + ClassBinaryData data = binaryDataMap.get(type); return data.fieldLayout.get(field.getFieldName()); } public int getClassSize(String className) { - ClassBinaryData data = binaryDataMap.get(className); + ValueType type = ValueType.object(className); + addClass(type); + ClassBinaryData data = binaryDataMap.get(type); return data.size; } - public int getArrayClassPointer() { - return arrayClassData.start; - } - public boolean isStructure(String className) { - ClassBinaryData data = binaryDataMap.get(className); + ValueType type = ValueType.object(className); + addClass(type); + ClassBinaryData data = binaryDataMap.get(type); return data.start < 0; } @@ -164,8 +209,8 @@ public class WasmClassGenerator { data.size = 0; data.start = -1; } else if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) { - addClass(cls.getParent()); - ClassBinaryData parentData = binaryDataMap.get(cls.getParent()); + addClass(ValueType.object(cls.getParent())); + ClassBinaryData parentData = binaryDataMap.get(ValueType.object(cls.getParent())); data.size = parentData.size; if (parentData.start == -1) { data.start = -1; @@ -237,9 +282,10 @@ public class WasmClassGenerator { } private class ClassBinaryData { - String name; + ValueType type; int size; int start; ObjectIntMap fieldLayout = new ObjectIntOpenHashMap<>(); + DataValue data; } } diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java index be032f311..94b952032 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java @@ -528,7 +528,6 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { indexExpr.acceptVisitor(this); WasmExpression index = result; - classGenerator.addClass(RuntimeArray.class.getName()); int base = classGenerator.getClassSize(RuntimeArray.class.getName()); array = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, array, new WasmInt32Constant(base)); index = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, index, new WasmInt32Constant(2)); @@ -673,7 +672,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod()); WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, - getReferenceToClass(instance), new WasmInt32Constant(vtableEntry.getIndex() * 4 + 16)); + getReferenceToClass(instance), new WasmInt32Constant(vtableEntry.getIndex() * 4 + 24)); methodIndex = new WasmLoadInt32(4, methodIndex, WasmInt32Subtype.INT32); WasmIndirectCall call = new WasmIndirectCall(methodIndex); @@ -788,7 +787,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { @Override public void visit(NewExpr expr) { - int tag = classGenerator.getClassPointer(expr.getConstructedClass()); + int tag = classGenerator.getClassPointer(ValueType.object(expr.getConstructedClass())); String allocName = WasmMangling.mangleMethod(new MethodReference(Allocator.class, "allocate", RuntimeClass.class, Address.class)); WasmCall call = new WasmCall(allocName); @@ -799,21 +798,14 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { @Override public void visit(NewArrayExpr expr) { ValueType type = expr.getType(); - int depth = 0; - while (type instanceof ValueType.Array) { - ++depth; - type = ((ValueType.Array) type).getItemType(); - } - ValueType.Object cls = (ValueType.Object) type; - int classPointer = classGenerator.getClassPointer(cls.getClassName()); + int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(type)); String allocName = WasmMangling.mangleMethod(new MethodReference(Allocator.class, "allocateArray", - RuntimeClass.class, int.class, byte.class, Address.class)); + RuntimeClass.class, int.class, Address.class)); WasmCall call = new WasmCall(allocName); call.getArguments().add(new WasmInt32Constant(classPointer)); expr.getLength().acceptVisitor(this); call.getArguments().add(result); - call.getArguments().add(new WasmInt32Constant(depth)); result = call; } diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/WasmRuntimeClassIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/WasmRuntimeClassIntrinsic.java deleted file mode 100644 index dd4b43137..000000000 --- a/core/src/main/java/org/teavm/wasm/intrinsics/WasmRuntimeClassIntrinsic.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2016 Alexey Andreev. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.teavm.wasm.intrinsics; - -import org.teavm.ast.InvocationExpr; -import org.teavm.model.MethodReference; -import org.teavm.runtime.RuntimeClass; -import org.teavm.wasm.generate.WasmClassGenerator; -import org.teavm.wasm.model.expression.WasmExpression; -import org.teavm.wasm.model.expression.WasmInt32Constant; - -public class WasmRuntimeClassIntrinsic implements WasmIntrinsic { - private WasmClassGenerator classGenerator; - - public WasmRuntimeClassIntrinsic(WasmClassGenerator classGenerator) { - this.classGenerator = classGenerator; - } - - @Override - public boolean isApplicable(MethodReference methodReference) { - if (!methodReference.getClassName().equals(RuntimeClass.class.getName())) { - return false; - } - - switch (methodReference.getName()) { - case "getArrayClass": - return true; - } - - return false; - } - - @Override - public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) { - switch (invocation.getMethod().getName()) { - case "getArrayClass": - return new WasmInt32Constant(classGenerator.getArrayClassPointer()); - default: - throw new IllegalArgumentException(invocation.getMethod().toString()); - } - } -} diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/WasmStructureIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/WasmStructureIntrinsic.java index ecbd9bddd..527dc3224 100644 --- a/core/src/main/java/org/teavm/wasm/intrinsics/WasmStructureIntrinsic.java +++ b/core/src/main/java/org/teavm/wasm/intrinsics/WasmStructureIntrinsic.java @@ -34,7 +34,7 @@ public class WasmStructureIntrinsic implements WasmIntrinsic { @Override public boolean isApplicable(MethodReference methodReference) { return !methodReference.getClassName().equals(Address.class.getName()) - && classGenerator.getClassPointer(methodReference.getClassName()) < 0; + && classGenerator.getClassPointer(ValueType.object(methodReference.getClassName())) < 0; } @Override diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/AliasFinder.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/AliasFinder.java index 3b081345e..f11c71ad3 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/AliasFinder.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/AliasFinder.java @@ -266,7 +266,8 @@ class AliasFinder { } @Override - public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { ArrayElement elem = new ArrayElement(); elem.array = array.getIndex(); elem.index = index.getIndex(); @@ -274,7 +275,8 @@ class AliasFinder { } @Override - public void putElement(VariableReader array, VariableReader index, VariableReader value) { + public void putElement(VariableReader array, VariableReader index, VariableReader value, + ArrayElementType type) { } @Override diff --git a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java index 1ad8c2c74..6918a4451 100644 --- a/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java +++ b/metaprogramming/impl/src/main/java/org/teavm/metaprogramming/impl/CompositeMethodGenerator.java @@ -768,7 +768,8 @@ public class CompositeMethodGenerator { } @Override - public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { int arrayIndex = variableMapping[array.getIndex()]; AliasFinder.ArrayElement elem = arrayElements[receiver.getIndex()]; @@ -780,7 +781,7 @@ public class CompositeMethodGenerator { return; } - GetElementInstruction insn = new GetElementInstruction(); + GetElementInstruction insn = new GetElementInstruction(type); insn.setArray(var(array)); insn.setIndex(var(index)); insn.setReceiver(var(receiver)); @@ -788,8 +789,9 @@ public class CompositeMethodGenerator { } @Override - public void putElement(VariableReader array, VariableReader index, VariableReader value) { - PutElementInstruction insn = new PutElementInstruction(); + public void putElement(VariableReader array, VariableReader index, VariableReader value, + ArrayElementType type) { + PutElementInstruction insn = new PutElementInstruction(type); insn.setArray(var(array)); insn.setIndex(var(index)); insn.setValue(var(value)); @@ -1013,7 +1015,7 @@ public class CompositeMethodGenerator { return true; } case "getArrayElement": { - GetElementInstruction insn = new GetElementInstruction(); + GetElementInstruction insn = new GetElementInstruction(asArrayType(reflectClass.type)); insn.setArray(unwrapArray(reflectClass.type, var(arguments.get(0)))); insn.setIndex(var(arguments.get(1))); insn.setReceiver(program.createVariable()); @@ -1047,7 +1049,7 @@ public class CompositeMethodGenerator { indexInsn.setReceiver(program.createVariable()); add(indexInsn); - GetElementInstruction extractArgInsn = new GetElementInstruction(); + GetElementInstruction extractArgInsn = new GetElementInstruction(ArrayElementType.OBJECT); extractArgInsn.setArray(argumentsVar); extractArgInsn.setIndex(indexInsn.getReceiver()); extractArgInsn.setReceiver(program.createVariable()); diff --git a/tools/core/src/main/java/org/teavm/tooling/InstructionLocationReader.java b/tools/core/src/main/java/org/teavm/tooling/InstructionLocationReader.java index 94acdbc4c..16d87786b 100644 --- a/tools/core/src/main/java/org/teavm/tooling/InstructionLocationReader.java +++ b/tools/core/src/main/java/org/teavm/tooling/InstructionLocationReader.java @@ -162,11 +162,13 @@ class InstructionLocationReader implements InstructionReader { } @Override - public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { } @Override - public void putElement(VariableReader array, VariableReader index, VariableReader value) { + public void putElement(VariableReader array, VariableReader index, VariableReader value, + ArrayElementType type) { } @Override diff --git a/tools/core/src/main/java/org/teavm/tooling/sources/ProgramSourceAggregator.java b/tools/core/src/main/java/org/teavm/tooling/sources/ProgramSourceAggregator.java index b9e2170a0..8466ee2a3 100644 --- a/tools/core/src/main/java/org/teavm/tooling/sources/ProgramSourceAggregator.java +++ b/tools/core/src/main/java/org/teavm/tooling/sources/ProgramSourceAggregator.java @@ -20,10 +20,6 @@ import java.util.Set; import org.teavm.model.*; import org.teavm.model.instructions.*; -/** - * - * @author Alexey Andreev - */ class ProgramSourceAggregator implements InstructionReader { private Set sourceFiles; @@ -82,8 +78,10 @@ class ProgramSourceAggregator implements InstructionReader { @Override public void arrayLength(VariableReader receiver, VariableReader array) { } @Override public void cloneArray(VariableReader receiver, VariableReader array) { } @Override public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { } - @Override public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { } - @Override public void putElement(VariableReader array, VariableReader index, VariableReader value) { } + @Override public void getElement(VariableReader receiver, VariableReader array, VariableReader index, + ArrayElementType type) { } + @Override public void putElement(VariableReader array, VariableReader index, VariableReader value, + ArrayElementType type) { } @Override public void invoke(VariableReader receiver, VariableReader instance, MethodReference method, List arguments, InvocationType type) { } @Override public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,