Add support of clinit

This commit is contained in:
Alexey Andreev 2016-08-19 00:08:39 +03:00
parent d2cdd5e1e9
commit 8c6cf1840b
7 changed files with 69 additions and 15 deletions

View File

@ -56,6 +56,10 @@ public final class Example {
for (int i = 0; i < str.length(); ++i) {
WasmRuntime.print(str.charAt(i));
}
Initialized.foo();
Initialized.foo();
Initialized.foo();
}
private static Base instance(int index) {
@ -110,4 +114,14 @@ public final class Example {
return 123;
}
}
static class Initialized {
static {
WasmRuntime.print(9999);
}
public static void foo() {
WasmRuntime.print(8888);
}
}
}

View File

@ -264,7 +264,8 @@ public class WasmTarget implements TeaVMTarget {
WasmBlock block = new WasmBlock(false);
int index = classGenerator.getClassPointer(ValueType.object(className));
int index = classGenerator.getClassPointer(ValueType.object(className))
+ classGenerator.getFieldOffset(new FieldReference(RuntimeClass.class.getName(), "flags"));
WasmExpression initFlag = new WasmLoadInt32(4, new WasmInt32Constant(index), WasmInt32Subtype.INT32);
initFlag = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND, initFlag,
new WasmInt32Constant(RuntimeClass.INITIALIZED));

View File

@ -29,6 +29,7 @@ import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReader;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.model.classes.TagRegistry;
@ -281,6 +282,17 @@ public class WasmClassGenerator {
return 4;
}
public boolean hasClinit(String className) {
if (isStructure(className)) {
return false;
}
ClassReader cls = classSource.get(className);
if (cls == null) {
return false;
}
return cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null;
}
private class ClassBinaryData {
ValueType type;
int size;

View File

@ -33,6 +33,7 @@ import org.teavm.model.classes.TagRegistry;
import org.teavm.model.classes.VirtualTableProvider;
import org.teavm.wasm.binary.BinaryWriter;
import org.teavm.wasm.intrinsics.WasmIntrinsic;
import org.teavm.wasm.model.expression.WasmExpression;
public class WasmGenerationContext {
private ClassReaderSource classSource;

View File

@ -962,24 +962,13 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
@Override
public void visit(InitClassStatement statement) {
if (hasClinit(statement.getClassName())) {
if (classGenerator.hasClinit(statement.getClassName())) {
result = new WasmCall(WasmMangling.mangleInitializer(statement.getClassName()));
} else {
result = null;
}
}
private boolean hasClinit(String className) {
if (classGenerator.isStructure(className)) {
return false;
}
ClassReader cls = context.getClassSource().get(className);
if (cls == null) {
return false;
}
return cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null;
}
@Override
public void visit(PrimitiveCastExpr expr) {
expr.getValue().acceptVisitor(this);

View File

@ -21,11 +21,22 @@ import org.teavm.ast.decompilation.Decompiler;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.runtime.RuntimeClass;
import org.teavm.wasm.model.WasmFunction;
import org.teavm.wasm.model.WasmLocal;
import org.teavm.wasm.model.expression.WasmCall;
import org.teavm.wasm.model.expression.WasmConditional;
import org.teavm.wasm.model.expression.WasmExpression;
import org.teavm.wasm.model.expression.WasmInt32Constant;
import org.teavm.wasm.model.expression.WasmInt32Subtype;
import org.teavm.wasm.model.expression.WasmIntBinary;
import org.teavm.wasm.model.expression.WasmIntBinaryOperation;
import org.teavm.wasm.model.expression.WasmIntType;
import org.teavm.wasm.model.expression.WasmLoadInt32;
public class WasmGenerator {
private Decompiler decompiler;
@ -60,6 +71,20 @@ public class WasmGenerator {
function.setResult(WasmGeneratorUtil.mapType(methodReference.getReturnType()));
}
if (needsClinitCall(method) && classGenerator.hasClinit(method.getOwnerName())) {
int index = classGenerator.getClassPointer(ValueType.object(method.getOwnerName()))
+ classGenerator.getFieldOffset(new FieldReference(RuntimeClass.class.getName(), "flags"));
WasmExpression initFlag = new WasmLoadInt32(4, new WasmInt32Constant(index), WasmInt32Subtype.INT32);
initFlag = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND, initFlag,
new WasmInt32Constant(RuntimeClass.INITIALIZED));
WasmConditional conditional = new WasmConditional(initFlag);
MethodReference clinit = new MethodReference(method.getOwnerName(),
"<clinit>", ValueType.VOID);
conditional.getThenBlock().getBody().add(new WasmCall(WasmMangling.mangleMethod(clinit)));
function.getBody().add(conditional);
}
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, function, firstVariable);
methodAst.getBody().acceptVisitor(visitor);
function.getBody().add(visitor.result);
@ -67,6 +92,16 @@ public class WasmGenerator {
return function;
}
private static boolean needsClinitCall(MethodHolder method) {
if (method.getName().equals("<clinit>")) {
return false;
}
if (method.getName().equals("<init>")) {
return true;
}
return method.hasModifier(ElementModifier.STATIC);
}
public WasmFunction generateNative(MethodReference methodReference) {
WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(methodReference));
for (int i = 0; i < methodReference.parameterCount(); ++i) {

View File

@ -183,8 +183,10 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
lf();
renderBlock(expression.getThenBlock(), "then");
lf();
renderBlock(expression.getElseBlock(), "else");
if (!expression.getElseBlock().getBody().isEmpty()) {
lf();
renderBlock(expression.getElseBlock(), "else");
}
close();
}