From 8c6cf1840b9eaba67a6200abb95aab2353c2fe51 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 19 Aug 2016 00:08:39 +0300 Subject: [PATCH] Add support of clinit --- .../src/main/java/org/teavm/wasm/Example.java | 14 ++++++++ .../main/java/org/teavm/wasm/WasmTarget.java | 3 +- .../wasm/generate/WasmClassGenerator.java | 12 +++++++ .../wasm/generate/WasmGenerationContext.java | 1 + .../wasm/generate/WasmGenerationVisitor.java | 13 +------ .../teavm/wasm/generate/WasmGenerator.java | 35 +++++++++++++++++++ .../wasm/render/WasmRenderingVisitor.java | 6 ++-- 7 files changed, 69 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/teavm/wasm/Example.java b/core/src/main/java/org/teavm/wasm/Example.java index 0c19f1805..61adbdc93 100644 --- a/core/src/main/java/org/teavm/wasm/Example.java +++ b/core/src/main/java/org/teavm/wasm/Example.java @@ -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); + } + } } diff --git a/core/src/main/java/org/teavm/wasm/WasmTarget.java b/core/src/main/java/org/teavm/wasm/WasmTarget.java index 7db413a0a..ad0fe8eaa 100644 --- a/core/src/main/java/org/teavm/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/wasm/WasmTarget.java @@ -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)); 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 c83ca4ea8..c04da4efc 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java @@ -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("", ValueType.VOID)) != null; + } + private class ClassBinaryData { ValueType type; int size; diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java index 48ab011b7..dc6811263 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java @@ -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; 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 26bd79ef4..61212b61b 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java @@ -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("", ValueType.VOID)) != null; - } - @Override public void visit(PrimitiveCastExpr expr) { expr.getValue().acceptVisitor(this); diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java b/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java index e46f29f85..7413748dd 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java @@ -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(), + "", 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("")) { + return false; + } + if (method.getName().equals("")) { + 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) { diff --git a/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java b/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java index 8f8572588..c8b6df58b 100644 --- a/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java +++ b/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java @@ -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(); }