From d196eb98642378a5fcc53a346d0968fead5389e7 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 5 Jun 2016 20:58:23 +0300 Subject: [PATCH] Further work on incremental phi updater --- classlib/teavm-classlib.iml | 1 + core/pom.xml | 5 + .../java/org/teavm/model/IncomingReader.java | 4 - .../org/teavm/model/InterpretException.java | 35 + .../java/org/teavm/model/Interpreter.java | 838 ++++++++++++++++++ core/teavm-core.iml | 1 + extras-slf4j/teavm-extras-slf4j.iml | 1 + html4j/teavm-html4j.iml | 1 + jso/impl/teavm-jso-impl.iml | 1 + .../impl/teavm-metaprogramming-impl.iml | 1 + platform/teavm-platform.iml | 1 + samples/async/teavm-samples-async.iml | 1 + samples/benchmark/teavm-samples-benchmark.iml | 1 + samples/hello/teavm-samples-hello.iml | 1 + samples/kotlin/teavm-samples-kotlin.iml | 1 + samples/scala/teavm-samples-scala.iml | 1 + samples/storage/teavm-samples-storage.iml | 1 + samples/video/teavm-samples-video.iml | 1 + tests/teavm-tests.iml | 1 + tools/chrome-rdp/teavm-chrome-rdp.iml | 1 + tools/cli/teavm-cli.iml | 1 + tools/core/teavm-tooling.iml | 1 + tools/junit/teavm-junit.iml | 1 + tools/maven/plugin/teavm-maven-plugin.iml | 1 + 24 files changed, 898 insertions(+), 4 deletions(-) create mode 100644 core/src/main/java/org/teavm/model/InterpretException.java create mode 100644 core/src/main/java/org/teavm/model/Interpreter.java diff --git a/classlib/teavm-classlib.iml b/classlib/teavm-classlib.iml index ead5bc4ab..c1979e489 100644 --- a/classlib/teavm-classlib.iml +++ b/classlib/teavm-classlib.iml @@ -38,6 +38,7 @@ + diff --git a/core/pom.xml b/core/pom.xml index 27ccebc97..858dfdf9d 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -58,6 +58,11 @@ jackson-annotations true + + org.objenesis + objenesis + 2.4 + diff --git a/core/src/main/java/org/teavm/model/IncomingReader.java b/core/src/main/java/org/teavm/model/IncomingReader.java index 1098a532f..d02de8e83 100644 --- a/core/src/main/java/org/teavm/model/IncomingReader.java +++ b/core/src/main/java/org/teavm/model/IncomingReader.java @@ -15,10 +15,6 @@ */ package org.teavm.model; -/** - * - * @author Alexey Andreev - */ public interface IncomingReader { VariableReader getValue(); diff --git a/core/src/main/java/org/teavm/model/InterpretException.java b/core/src/main/java/org/teavm/model/InterpretException.java new file mode 100644 index 000000000..f9ab23833 --- /dev/null +++ b/core/src/main/java/org/teavm/model/InterpretException.java @@ -0,0 +1,35 @@ +/* + * 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.model; + +public class InterpretException extends Exception { + private final BasicBlockReader block; + private final int index; + + public InterpretException(BasicBlockReader block, int index, Throwable cause) { + super(cause); + this.block = block; + this.index = index; + } + + public BasicBlockReader getBlock() { + return block; + } + + public int getIndex() { + return index; + } +} diff --git a/core/src/main/java/org/teavm/model/Interpreter.java b/core/src/main/java/org/teavm/model/Interpreter.java new file mode 100644 index 000000000..46c1feac1 --- /dev/null +++ b/core/src/main/java/org/teavm/model/Interpreter.java @@ -0,0 +1,838 @@ +/* + * 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.model; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.objenesis.Objenesis; +import org.objenesis.ObjenesisStd; +import org.teavm.model.instructions.ArrayElementType; +import org.teavm.model.instructions.BinaryBranchingCondition; +import org.teavm.model.instructions.BinaryOperation; +import org.teavm.model.instructions.BranchingCondition; +import org.teavm.model.instructions.CastIntegerDirection; +import org.teavm.model.instructions.InstructionReader; +import org.teavm.model.instructions.IntegerSubtype; +import org.teavm.model.instructions.InvocationType; +import org.teavm.model.instructions.NumericOperandType; +import org.teavm.model.instructions.SwitchTableEntryReader; + +public class Interpreter { + private ClassLoader classLoader; + private BasicBlockReader currentBlock; + private List> outgoings; + private Object[] variables; + private Object result; + private State state; + + public Interpreter(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public Object interpret(ProgramReader program, Object[] parameters) throws InterpretException { + variables = new Object[program.variableCount()]; + System.arraycopy(parameters, 0, variables, 0, parameters.length); + currentBlock = program.basicBlockAt(0); + state = State.EXECUTING; + + outgoings = new ArrayList<>(); + for (int i = 0; i < program.basicBlockCount(); ++i) { + outgoings.add(new ArrayList<>()); + } + for (int i = 0; i < program.basicBlockCount(); ++i) { + BasicBlockReader block = program.basicBlockAt(i); + for (PhiReader phi : block.readPhis()) { + for (IncomingReader incoming : phi.readIncomings()) { + outgoings.get(incoming.getSource().getIndex()).add(incoming); + } + } + } + + try { + while (true) { + int instructionIndex = 0; + try { + while (instructionIndex < currentBlock.instructionCount()) { + currentBlock.readInstruction(instructionIndex++, reader); + } + } catch (RuntimeException e) { + if (!pickExceptionHandler(e)) { + throw new InterpretException(currentBlock, instructionIndex, e); + } + } + switch (state) { + case EXITED: { + return result; + } + case THROWN: { + Throwable ex = (Throwable) result; + throw new InterpretException(currentBlock, currentBlock.instructionCount() - 1, ex); + } + case EXECUTING: + break; + } + } + + } finally { + currentBlock = null; + variables = null; + outgoings = null; + result = null; + } + } + + private boolean pickExceptionHandler(Throwable e) { + for (TryCatchBlockReader tryCatch : currentBlock.readTryCatchBlocks()) { + Class exceptionType; + try { + exceptionType = tryCatch.getExceptionType() != null + ? Class.forName(tryCatch.getExceptionType(), false, classLoader) + : null; + } catch (ClassNotFoundException cnfe) { + throw new RuntimeException("Can't find exception class " + tryCatch.getExceptionType()); + } + if (exceptionType == null || exceptionType.isInstance(e)) { + currentBlock = tryCatch.getProtectedBlock(); + return true; + } + } + return false; + } + + private InstructionReader reader = new InstructionReader() { + private Objenesis objenesis = new ObjenesisStd(); + + @Override + public void location(InstructionLocation location) { + } + + @Override + public void nop() { + } + + @Override + public void classConstant(VariableReader receiver, ValueType cst) { + variables[receiver.getIndex()] = asJvmClass(cst); + } + + @Override + public void nullConstant(VariableReader receiver) { + variables[receiver.getIndex()] = null; + } + + @Override + public void integerConstant(VariableReader receiver, int cst) { + variables[receiver.getIndex()] = cst; + } + + @Override + public void longConstant(VariableReader receiver, long cst) { + variables[receiver.getIndex()] = cst; + } + + @Override + public void floatConstant(VariableReader receiver, float cst) { + variables[receiver.getIndex()] = cst; + } + + @Override + public void doubleConstant(VariableReader receiver, double cst) { + variables[receiver.getIndex()] = cst; + } + + @Override + public void stringConstant(VariableReader receiver, String cst) { + variables[receiver.getIndex()] = cst; + } + + @Override + public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second, + NumericOperandType type) { + switch (type) { + case INT: { + int a = (Integer) variables[first.getIndex()]; + int b = (Integer) variables[second.getIndex()]; + int result; + switch (op) { + case ADD: + result = a + b; + break; + case SUBTRACT: + result = a - b; + break; + case MULTIPLY: + result = a * b; + break; + case DIVIDE: + result = a * b; + break; + case MODULO: + result = a % b; + break; + case COMPARE: + result = Integer.compare(a, b); + break; + case AND: + result = a & b; + break; + case OR: + result = a | b; + break; + case XOR: + result = a ^ b; + break; + default: + throw new IllegalArgumentException("Unknown operation: " + op); + } + variables[receiver.getIndex()] = result; + break; + } + case LONG: { + long a = (Long) variables[first.getIndex()]; + long b = (Long) variables[second.getIndex()]; + long result; + switch (op) { + case ADD: + result = a + b; + break; + case SUBTRACT: + result = a - b; + break; + case MULTIPLY: + result = a * b; + break; + case DIVIDE: + result = a * b; + break; + case MODULO: + result = a % b; + break; + case COMPARE: + result = Long.compare(a, b); + break; + case AND: + result = a & b; + break; + case OR: + result = a | b; + break; + case XOR: + result = a ^ b; + break; + default: + throw new IllegalArgumentException("Unknown operation: " + op); + } + variables[receiver.getIndex()] = result; + break; + } + case FLOAT: { + float a = (Float) variables[first.getIndex()]; + float b = (Float) variables[second.getIndex()]; + float result; + switch (op) { + case ADD: + result = a + b; + break; + case SUBTRACT: + result = a - b; + break; + case MULTIPLY: + result = a * b; + break; + case DIVIDE: + result = a * b; + break; + case MODULO: + result = a % b; + break; + case COMPARE: + result = Float.compare(a, b); + break; + case AND: + case OR: + case XOR: + throw new IllegalArgumentException("Unsupported operation " + op + + " for operands of type" + type); + default: + throw new IllegalArgumentException("Unknown operation: " + op); + } + variables[receiver.getIndex()] = result; + break; + } + case DOUBLE: { + double a = (Double) variables[first.getIndex()]; + double b = (Double) variables[second.getIndex()]; + double result; + switch (op) { + case ADD: + result = a + b; + break; + case SUBTRACT: + result = a - b; + break; + case MULTIPLY: + result = a * b; + break; + case DIVIDE: + result = a * b; + break; + case MODULO: + result = a % b; + break; + case COMPARE: + result = Double.compare(a, b); + break; + case AND: + case OR: + case XOR: + throw new IllegalArgumentException("Unsupported operation " + op + + " for operands of type" + type); + default: + throw new IllegalArgumentException("Unknown operation: " + op); + } + variables[receiver.getIndex()] = result; + break; + } + } + } + + @Override + public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) { + Object result; + Object a = variables[operand.getIndex()]; + switch (type) { + case INT: + result = -(Integer) a; + break; + case LONG: + result = -(Long) a; + break; + case FLOAT: + result = -(Float) a; + break; + case DOUBLE: + result = -(Double) a; + break; + default: + throw new IllegalArgumentException("Unknown type: " + type); + } + variables[receiver.getIndex()] = result; + } + + @Override + public void assign(VariableReader receiver, VariableReader assignee) { + variables[receiver.getIndex()] = variables[assignee.getIndex()]; + } + + @Override + public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { + variables[receiver.getIndex()] = asJvmClass(targetType).cast(variables[value.getIndex()]); + } + + @Override + public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType, + NumericOperandType targetType) { + Object result; + switch (sourceType) { + case INT: { + int a = (Integer) variables[value.getIndex()]; + switch (targetType) { + case INT: + result = a; + break; + case LONG: + result = (long) a; + break; + case FLOAT: + result = (float) a; + break; + case DOUBLE: + result = (double) a; + break; + default: + throw new IllegalArgumentException("Can't cast " + sourceType + " to " + targetType); + } + break; + } + case LONG: { + long a = (Long) variables[value.getIndex()]; + switch (targetType) { + case INT: + result = (int) a; + break; + case LONG: + result = a; + break; + case FLOAT: + result = (float) a; + break; + case DOUBLE: + result = (double) a; + break; + default: + throw new IllegalArgumentException("Can't cast " + sourceType + " to " + targetType); + } + break; + } + case FLOAT: { + float a = (Float) variables[value.getIndex()]; + switch (targetType) { + case INT: + result = (int) a; + break; + case LONG: + result = (long) a; + break; + case FLOAT: + result = a; + break; + case DOUBLE: + result = (double) a; + break; + default: + throw new IllegalArgumentException("Can't cast " + sourceType + " to " + targetType); + } + break; + } + case DOUBLE: { + double a = (Double) variables[value.getIndex()]; + switch (targetType) { + case INT: + result = (int) a; + break; + case LONG: + result = (long) a; + break; + case FLOAT: + result = (float) a; + break; + case DOUBLE: + result = a; + break; + default: + throw new IllegalArgumentException("Can't cast " + sourceType + " to " + targetType); + } + break; + } + default: + throw new IllegalArgumentException("Can't cast " + sourceType + " to " + targetType); + } + variables[receiver.getIndex()] = result; + } + + @Override + public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type, + CastIntegerDirection direction) { + switch (direction) { + case FROM_INTEGER: { + int a = (Integer) variables[value.getIndex()]; + Object result; + switch (type) { + case BYTE: + result = (byte) a; + break; + case SHORT: + result = (short) a; + break; + case CHARACTER: + result = (char) a; + break; + default: + throw new IllegalArgumentException("Unknown type: " + type); + } + variables[receiver.getIndex()] = result; + break; + } + case TO_INTEGER: { + Object a = variables[value.getIndex()]; + int result; + switch (type) { + case BYTE: + result = (Byte) a; + break; + case SHORT: + result = (Short) a; + break; + case CHARACTER: + result = (Character) a; + break; + default: + throw new IllegalArgumentException("Unknown type: " + type); + } + variables[receiver.getIndex()] = result; + break; + } + } + } + + @Override + public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent, + BasicBlockReader alternative) { + Object a = variables[operand.getIndex()]; + boolean c; + switch (cond) { + case EQUAL: + c = (Integer) a == 0; + break; + case NOT_EQUAL: + c = (Integer) a != 0; + break; + case LESS: + c = (Integer) a < 0; + break; + case LESS_OR_EQUAL: + c = (Integer) a <= 0; + break; + case GREATER: + c = (Integer) a > 0; + break; + case GREATER_OR_EQUAL: + c = (Integer) a >= 0; + break; + case NULL: + c = a == null; + break; + case NOT_NULL: + c = a != null; + break; + default: + throw new IllegalArgumentException("Unknown condition: " + cond); + } + jump(c ? consequent : alternative); + } + + @Override + public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second, + BasicBlockReader consequent, BasicBlockReader alternative) { + Object a = variables[first.getIndex()]; + Object b = variables[second.getIndex()]; + boolean c; + switch (cond) { + case EQUAL: + c = ((Integer) a).intValue() == (Integer) b; + break; + case NOT_EQUAL: + c = ((Integer) a).intValue() != (Integer) b; + break; + case REFERENCE_EQUAL: + c = a == b; + break; + case REFERENCE_NOT_EQUAL: + c = a != b; + break; + default: + throw new IllegalArgumentException("Unknown condition: " + cond); + } + jump(c ? consequent : alternative); + } + + @Override + public void jump(BasicBlockReader target) { + Object[] newVariables = variables.clone(); + + for (IncomingReader outgoing : outgoings.get(currentBlock.getIndex())) { + if (outgoing.getPhi().getBasicBlock() != target) { + continue; + } + newVariables[outgoing.getPhi().getReceiver().getIndex()] = variables[outgoing.getValue().getIndex()]; + } + + variables = newVariables; + currentBlock = target; + } + + @Override + public void choose(VariableReader condition, List table, + BasicBlockReader defaultTarget) { + int value = (Integer) variables[condition.getIndex()]; + for (SwitchTableEntryReader entry : table) { + if (value == entry.getCondition()) { + jump(entry.getTarget()); + return; + } + } + jump(defaultTarget); + } + + @Override + public void exit(VariableReader valueToReturn) { + state = State.EXITED; + result = variables[valueToReturn.getIndex()]; + } + + @Override + public void raise(VariableReader exception) { + Throwable e = (Throwable) variables[exception.getIndex()]; + if (!pickExceptionHandler(e)) { + state = State.EXITED; + result = e; + } + } + + @Override + public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) { + Class itemJvmType = asJvmClass(itemType); + int sizeValue = (int) variables[size.getIndex()]; + variables[receiver.getIndex()] = Array.newInstance(itemJvmType, sizeValue); + } + + @Override + public void createArray(VariableReader receiver, ValueType itemType, + List dimensions) { + Class itemJvmType = asJvmClass(itemType); + for (int i = 1; i < dimensions.size(); ++i) { + itemJvmType = Array.newInstance(itemJvmType, 0).getClass(); + } + variables[receiver.getIndex()] = createArray(itemJvmType, dimensions, 0); + } + + private Object createArray(Class itemType, List dimensions, int dimensionIndex) { + int dimensionValue = (int) variables[dimensions.get(dimensionIndex).getIndex()]; + Object result = Array.newInstance(itemType, dimensionValue); + if (dimensionIndex < dimensions.size() - 1) { + for (int i = 0; i < dimensionValue; ++i) { + Array.set(result, i, createArray(itemType.getComponentType(), dimensions, dimensionIndex + 1)); + } + } + return result; + } + + @Override + public void create(VariableReader receiver, String type) { + Class cls; + try { + cls = Class.forName(type, false, classLoader); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Class not found: " + type); + } + variables[receiver.getIndex()] = objenesis.newInstance(cls); + } + + @Override + public void getField(VariableReader receiver, VariableReader instance, FieldReference field, + ValueType fieldType) { + Field jvmField = getJvmField(field); + + Object jvmInstance = instance != null ? variables[instance.getIndex()] : null; + Object result; + try { + result = jvmField.get(jvmInstance); + } catch (IllegalAccessException e) { + throw new RuntimeException("Can't get field value: " + field); + } + + variables[receiver.getIndex()] = result; + } + + @Override + public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) { + Field jvmField = getJvmField(field); + + Object jvmInstance = instance != null ? variables[instance.getIndex()] : null; + try { + jvmField.set(jvmInstance, variables[value.getIndex()]); + } catch (IllegalAccessException e) { + throw new RuntimeException("Can't get field value: " + field); + } + } + + private Field getJvmField(FieldReference field) { + Class cls; + try { + cls = Class.forName(field.getClassName(), false, classLoader); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Class not found: " + field.getClassName()); + } + + Field jvmField; + try { + jvmField = cls.getDeclaredField(field.getFieldName()); + } catch (NoSuchFieldException e) { + throw new RuntimeException("Field not found: " + field); + } + + jvmField.setAccessible(true); + return jvmField; + } + + @Override + public void arrayLength(VariableReader receiver, VariableReader array) { + int value = Array.getLength(variables[array.getIndex()]); + variables[receiver.getIndex()] = value; + } + + @Override + public void cloneArray(VariableReader receiver, VariableReader array) { + Object jvmArray = variables[array.getIndex()]; + int length = Array.getLength(jvmArray); + Object copy = Array.newInstance(jvmArray.getClass().getComponentType(), length); + for (int i = 0; i < length; ++i) { + Array.set(copy, i, Array.get(array, i)); + } + variables[receiver.getIndex()] = copy; + } + + @Override + public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { + variables[receiver.getIndex()] = variables[array.getIndex()]; + } + + @Override + public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + 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) { + Object jvmArray = variables[array.getIndex()]; + int indexValue = (Integer) variables[index.getIndex()]; + Array.set(jvmArray, indexValue, variables[value.getIndex()]); + } + + @Override + public void invoke(VariableReader receiver, VariableReader instance, MethodReference method, + List arguments, InvocationType type) { + Method jvmMethod = asJvmMethod(method); + Object[] jvmArgs = new Object[arguments.size()]; + for (int i = 0; i < jvmArgs.length; ++i) { + jvmArgs[i] = variables[arguments.get(i).getIndex()]; + } + Object jvmInstance = instance != null ? variables[instance.getIndex()] : null; + Object result; + try { + result = jvmMethod.invoke(jvmInstance, jvmArgs); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Error calling method " + method, e); + } + if (receiver != null) { + variables[receiver.getIndex()] = result; + } + } + + private Method asJvmMethod(MethodReference method) { + Class cls; + try { + cls = Class.forName(method.getClassName(), false, classLoader); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Can't find class " + method.getClassName()); + } + + Class[] jvmParameters = new Class[method.parameterCount()]; + for (int i = 0; i < method.parameterCount(); ++i) { + jvmParameters[i] = asJvmClass(method.parameterType(i)); + } + Class jvmReturnType = asJvmClass(method.getReturnType()); + for (Method jvmMethod : cls.getDeclaredMethods()) { + if (Arrays.equals(jvmMethod.getParameterTypes(), jvmParameters) + && jvmReturnType.equals(jvmMethod.getReturnType())) { + return jvmMethod; + } + } + + throw new RuntimeException("Method not found: " + method); + } + + @Override + public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method, + List arguments, MethodHandle bootstrapMethod, + List bootstrapArguments) { + throw new RuntimeException("InvokeDynamic is not supported"); + } + + @Override + public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { + Object jvmValue = variables[value.getIndex()]; + Class jvmType = asJvmClass(type); + variables[receiver.getIndex()] = jvmType.isInstance(jvmValue); + } + + @Override + public void initClass(String className) { + try { + Class.forName(className); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Class not found: " + className); + } + } + + @Override + public void nullCheck(VariableReader receiver, VariableReader value) { + Object jvmValue = variables[value.getIndex()]; + if (jvmValue == null) { + throw new NullPointerException(); + } + variables[receiver.getIndex()] = jvmValue; + } + + @Override + public void monitorEnter(VariableReader objectRef) { + } + + @Override + public void monitorExit(VariableReader objectRef) { + } + + private Class asJvmClass(ValueType type) { + if (type instanceof ValueType.Primitive) { + switch (((ValueType.Primitive) type).getKind()) { + case BOOLEAN: + return boolean.class; + case BYTE: + return byte.class; + case SHORT: + return short.class; + case CHARACTER: + return char.class; + case INTEGER: + return int.class; + case LONG: + return long.class; + case FLOAT: + return float.class; + case DOUBLE: + return double.class; + default: + break; + } + } else if (type instanceof ValueType.Void) { + return void.class; + } else if (type instanceof ValueType.Array) { + Class itemJvmClass = asJvmClass(((ValueType.Array) type).getItemType()); + return Array.newInstance(itemJvmClass, 0).getClass(); + } else if (type instanceof ValueType.Object) { + try { + Class.forName(((ValueType.Object) type).getClassName(), false, classLoader); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Class not found: " + type); + } + } + throw new IllegalArgumentException("Unknown type: " + type); + } + }; + + private enum State { + EXECUTING, + EXITED, + THROWN + } +} diff --git a/core/teavm-core.iml b/core/teavm-core.iml index f97c35bec..f17c7919e 100644 --- a/core/teavm-core.iml +++ b/core/teavm-core.iml @@ -32,5 +32,6 @@ + \ No newline at end of file diff --git a/extras-slf4j/teavm-extras-slf4j.iml b/extras-slf4j/teavm-extras-slf4j.iml index c0b542c8e..7a2455365 100644 --- a/extras-slf4j/teavm-extras-slf4j.iml +++ b/extras-slf4j/teavm-extras-slf4j.iml @@ -15,6 +15,7 @@ + diff --git a/html4j/teavm-html4j.iml b/html4j/teavm-html4j.iml index d94d778d1..51e5d7983 100644 --- a/html4j/teavm-html4j.iml +++ b/html4j/teavm-html4j.iml @@ -24,6 +24,7 @@ + diff --git a/jso/impl/teavm-jso-impl.iml b/jso/impl/teavm-jso-impl.iml index 28870086b..1a7a66562 100644 --- a/jso/impl/teavm-jso-impl.iml +++ b/jso/impl/teavm-jso-impl.iml @@ -16,6 +16,7 @@ + diff --git a/metaprogramming/impl/teavm-metaprogramming-impl.iml b/metaprogramming/impl/teavm-metaprogramming-impl.iml index ba78f6942..7a00afce3 100644 --- a/metaprogramming/impl/teavm-metaprogramming-impl.iml +++ b/metaprogramming/impl/teavm-metaprogramming-impl.iml @@ -28,6 +28,7 @@ + diff --git a/platform/teavm-platform.iml b/platform/teavm-platform.iml index edf328ac2..42e576e8f 100644 --- a/platform/teavm-platform.iml +++ b/platform/teavm-platform.iml @@ -28,6 +28,7 @@ + diff --git a/samples/async/teavm-samples-async.iml b/samples/async/teavm-samples-async.iml index afff7f298..8f024ece9 100644 --- a/samples/async/teavm-samples-async.iml +++ b/samples/async/teavm-samples-async.iml @@ -28,6 +28,7 @@ + diff --git a/samples/benchmark/teavm-samples-benchmark.iml b/samples/benchmark/teavm-samples-benchmark.iml index cdcbc7296..a9218567c 100644 --- a/samples/benchmark/teavm-samples-benchmark.iml +++ b/samples/benchmark/teavm-samples-benchmark.iml @@ -38,6 +38,7 @@ + diff --git a/samples/hello/teavm-samples-hello.iml b/samples/hello/teavm-samples-hello.iml index 08f923ab9..ae6580c94 100644 --- a/samples/hello/teavm-samples-hello.iml +++ b/samples/hello/teavm-samples-hello.iml @@ -28,6 +28,7 @@ + diff --git a/samples/kotlin/teavm-samples-kotlin.iml b/samples/kotlin/teavm-samples-kotlin.iml index da681ff4e..d85add9ff 100644 --- a/samples/kotlin/teavm-samples-kotlin.iml +++ b/samples/kotlin/teavm-samples-kotlin.iml @@ -32,6 +32,7 @@ + diff --git a/samples/scala/teavm-samples-scala.iml b/samples/scala/teavm-samples-scala.iml index 9d3abcbc8..ee90882ee 100644 --- a/samples/scala/teavm-samples-scala.iml +++ b/samples/scala/teavm-samples-scala.iml @@ -28,6 +28,7 @@ + diff --git a/samples/storage/teavm-samples-storage.iml b/samples/storage/teavm-samples-storage.iml index ce450beb1..a14ad037d 100644 --- a/samples/storage/teavm-samples-storage.iml +++ b/samples/storage/teavm-samples-storage.iml @@ -28,6 +28,7 @@ + diff --git a/samples/video/teavm-samples-video.iml b/samples/video/teavm-samples-video.iml index ce450beb1..a14ad037d 100644 --- a/samples/video/teavm-samples-video.iml +++ b/samples/video/teavm-samples-video.iml @@ -28,6 +28,7 @@ + diff --git a/tests/teavm-tests.iml b/tests/teavm-tests.iml index eb265e73c..d806c3b07 100644 --- a/tests/teavm-tests.iml +++ b/tests/teavm-tests.iml @@ -15,6 +15,7 @@ + diff --git a/tools/chrome-rdp/teavm-chrome-rdp.iml b/tools/chrome-rdp/teavm-chrome-rdp.iml index 995dfdf10..d50747558 100644 --- a/tools/chrome-rdp/teavm-chrome-rdp.iml +++ b/tools/chrome-rdp/teavm-chrome-rdp.iml @@ -49,6 +49,7 @@ + diff --git a/tools/cli/teavm-cli.iml b/tools/cli/teavm-cli.iml index e67285d0e..431354a90 100644 --- a/tools/cli/teavm-cli.iml +++ b/tools/cli/teavm-cli.iml @@ -15,6 +15,7 @@ + \ No newline at end of file diff --git a/tools/core/teavm-tooling.iml b/tools/core/teavm-tooling.iml index cfd432be7..a636e0d00 100644 --- a/tools/core/teavm-tooling.iml +++ b/tools/core/teavm-tooling.iml @@ -28,6 +28,7 @@ + \ No newline at end of file diff --git a/tools/junit/teavm-junit.iml b/tools/junit/teavm-junit.iml index cbd5028f7..b99d88a1a 100644 --- a/tools/junit/teavm-junit.iml +++ b/tools/junit/teavm-junit.iml @@ -18,6 +18,7 @@ + diff --git a/tools/maven/plugin/teavm-maven-plugin.iml b/tools/maven/plugin/teavm-maven-plugin.iml index bfb311088..f65ba1b46 100644 --- a/tools/maven/plugin/teavm-maven-plugin.iml +++ b/tools/maven/plugin/teavm-maven-plugin.iml @@ -45,6 +45,7 @@ +