Refactoring RTTI, add type annotation to array subscription instructions

This commit is contained in:
Alexey Andreev 2016-08-15 18:49:24 +03:00
parent 73d4a389b7
commit 164ebeb629
31 changed files with 246 additions and 195 deletions

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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];

View File

@ -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: {

View File

@ -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()));

View File

@ -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());
}

View File

@ -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()) {

View File

@ -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

View File

@ -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()]);

View File

@ -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);

View File

@ -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;
}

View File

@ -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<? extends VariableReader> arguments, InvocationType type);

View File

@ -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;
}

View File

@ -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

View File

@ -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));

View File

@ -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());
}

View File

@ -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());
}

View File

@ -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));

View File

@ -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;
}

View File

@ -16,6 +16,5 @@
package org.teavm.runtime;
public class RuntimeArray extends RuntimeObject {
public int componentClassReference;
int size;
}

View File

@ -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();
}

View File

@ -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, "<clinit>", 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));

View File

@ -45,8 +45,7 @@ import org.teavm.wasm.binary.DataValue;
public class WasmClassGenerator {
private ClassReaderSource classSource;
private Map<String, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
private ClassBinaryData arrayClassData;
private Map<ValueType, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
private BinaryWriter binaryWriter;
private Map<MethodReference, Integer> functions = new HashMap<>();
private List<String> 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<String> 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<TagRegistry.Range> ranges = tagRegistry.getRanges(binaryData.name);
List<TagRegistry.Range> 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<String> fieldLayout = new ObjectIntOpenHashMap<>();
DataValue data;
}
}

View File

@ -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;
}

View File

@ -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());
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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());

View File

@ -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

View File

@ -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<String> 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<? extends VariableReader> arguments, InvocationType type) { }
@Override public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,