diff --git a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java index c5c135ccb..49407c0c2 100644 --- a/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java +++ b/core/src/main/java/org/teavm/backend/javascript/JavaScriptTarget.java @@ -67,6 +67,7 @@ import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.RaiseInstruction; import org.teavm.model.instructions.StringConstantInstruction; +import org.teavm.model.transformation.ClassInitializerInsertionTransformer; import org.teavm.model.util.AsyncMethodFinder; import org.teavm.model.util.ProgramUtils; import org.teavm.vm.BuildTarget; @@ -87,6 +88,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { private MethodNodeCache astCache = new EmptyRegularMethodNodeCache(); private final Set asyncMethods = new HashSet<>(); private final Set asyncFamilyMethods = new HashSet<>(); + private ClassInitializerInsertionTransformer clinitInsertionTransformer; @Override public List getTransformers() { @@ -101,6 +103,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { @Override public void setController(TeaVMTargetController controller) { this.controller = controller; + clinitInsertionTransformer = new ClassInitializerInsertionTransformer(controller.getUnprocessedClassSource()); } @Override @@ -213,6 +216,7 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { @Override public void afterOptimizations(Program program, MethodReader method, ListableClassReaderSource classSource) { + clinitInsertionTransformer.apply(method, program); } private void emit(ListableClassHolderSource classes, Writer writer, BuildTarget target) { diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index 9a499acad..a0a08b2d0 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -365,7 +365,7 @@ public class Renderer implements RenderingManager { } for (MethodNode method : cls.getMethods()) { - renderBody(method, clinit != null); + renderBody(method); } } catch (NamingException e) { throw new RenderingException("Error rendering class " + cls.getName() + ". See a cause for details", e); @@ -589,11 +589,7 @@ public class Renderer implements RenderingManager { writer.append(");").ws().append("}"); } - private void renderBody(MethodNode method, boolean clinitNeeded) throws IOException { - boolean isClinit = (method.getModifiers().contains(ElementModifier.STATIC) - && !method.getReference().getName().equals("")) - || method.getReference().getName().equals(""); - + private void renderBody(MethodNode method) throws IOException { StatementRenderer statementRenderer = new StatementRenderer(context, writer); statementRenderer.setCurrentMethod(method); @@ -614,9 +610,6 @@ public class Renderer implements RenderingManager { } writer.append(")").ws().append("{").softNewLine().indent(); - if (isClinit & clinitNeeded) { - writer.appendClass(method.getReference().getClassName()).append("_$callClinit();").softNewLine(); - } method.acceptVisitor(new MethodBodyRenderer(statementRenderer)); writer.outdent().append("}"); @@ -640,7 +633,7 @@ public class Renderer implements RenderingManager { private boolean async; private StatementRenderer statementRenderer; - public MethodBodyRenderer(StatementRenderer statementRenderer) { + MethodBodyRenderer(StatementRenderer statementRenderer) { this.statementRenderer = statementRenderer; } diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index 1b158a225..f149e7a39 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -104,12 +104,12 @@ import org.teavm.model.ValueType; import org.teavm.model.classes.TagRegistry; import org.teavm.model.classes.VirtualTableProvider; import org.teavm.model.instructions.CloneArrayInstruction; -import org.teavm.model.instructions.InitClassInstruction; import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.lowlevel.ClassInitializerEliminator; import org.teavm.model.lowlevel.ClassInitializerTransformer; import org.teavm.model.lowlevel.ShadowStackTransformer; +import org.teavm.model.transformation.ClassInitializerInsertionTransformer; import org.teavm.runtime.Allocator; import org.teavm.runtime.ExceptionHandling; import org.teavm.runtime.RuntimeArray; @@ -127,10 +127,10 @@ public class WasmTarget implements TeaVMTarget { private boolean debugging; private boolean wastEmitted; private boolean cEmitted; + private ClassInitializerInsertionTransformer clinitInsertionTransformer; private ClassInitializerEliminator classInitializerEliminator; private ClassInitializerTransformer classInitializerTransformer; private ShadowStackTransformer shadowStackTransformer; - private MethodDescriptor clinitDescriptor = new MethodDescriptor("", void.class); private WasmBinaryVersion version = WasmBinaryVersion.V_0xC; @Override @@ -139,6 +139,7 @@ public class WasmTarget implements TeaVMTarget { classInitializerEliminator = new ClassInitializerEliminator(controller.getUnprocessedClassSource()); classInitializerTransformer = new ClassInitializerTransformer(); shadowStackTransformer = new ShadowStackTransformer(controller.getUnprocessedClassSource()); + clinitInsertionTransformer = new ClassInitializerInsertionTransformer(controller.getUnprocessedClassSource()); } @Override @@ -261,30 +262,12 @@ public class WasmTarget implements TeaVMTarget { @Override public void afterOptimizations(Program program, MethodReader method, ListableClassReaderSource classes) { - ClassReader cls = classes.get(method.getOwnerName()); - boolean hasClinit = cls.getMethod(clinitDescriptor) != null; - if (needsClinitCall(method) && hasClinit) { - BasicBlock entryBlock = program.basicBlockAt(0); - InitClassInstruction initInsn = new InitClassInstruction(); - initInsn.setClassName(method.getOwnerName()); - entryBlock.addFirst(initInsn); - } - + clinitInsertionTransformer.apply(method, program); classInitializerEliminator.apply(program); classInitializerTransformer.transform(program); shadowStackTransformer.apply(program, method); } - private static boolean needsClinitCall(MethodReader method) { - if (method.getName().equals("")) { - return false; - } - if (method.getName().equals("")) { - return true; - } - return method.hasModifier(ElementModifier.STATIC); - } - @Override public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException { diff --git a/core/src/main/java/org/teavm/model/instructions/InitClassInstruction.java b/core/src/main/java/org/teavm/model/instructions/InitClassInstruction.java index adc286696..2e8ab02be 100644 --- a/core/src/main/java/org/teavm/model/instructions/InitClassInstruction.java +++ b/core/src/main/java/org/teavm/model/instructions/InitClassInstruction.java @@ -17,10 +17,6 @@ package org.teavm.model.instructions; import org.teavm.model.Instruction; -/** - * - * @author Alexey Andreev - */ public class InitClassInstruction extends Instruction { private String className; diff --git a/core/src/main/java/org/teavm/model/transformation/ClassInitializerInsertionTransformer.java b/core/src/main/java/org/teavm/model/transformation/ClassInitializerInsertionTransformer.java new file mode 100644 index 000000000..e66575bb4 --- /dev/null +++ b/core/src/main/java/org/teavm/model/transformation/ClassInitializerInsertionTransformer.java @@ -0,0 +1,55 @@ +/* + * Copyright 2017 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.transformation; + +import org.teavm.model.BasicBlock; +import org.teavm.model.ClassReader; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.ElementModifier; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodReader; +import org.teavm.model.Program; +import org.teavm.model.instructions.InitClassInstruction; + +public class ClassInitializerInsertionTransformer { + private static final MethodDescriptor clinitDescriptor = new MethodDescriptor("", void.class); + private ClassReaderSource classes; + + public ClassInitializerInsertionTransformer(ClassReaderSource classes) { + this.classes = classes; + } + + public void apply(MethodReader method, Program program) { + ClassReader cls = classes.get(method.getOwnerName()); + boolean hasClinit = cls.getMethod(clinitDescriptor) != null; + if (needsClinitCall(method) && hasClinit) { + BasicBlock entryBlock = program.basicBlockAt(0); + InitClassInstruction initInsn = new InitClassInstruction(); + initInsn.setClassName(method.getOwnerName()); + entryBlock.addFirst(initInsn); + } + } + + private static boolean needsClinitCall(MethodReader method) { + if (method.getName().equals("")) { + return false; + } + if (method.getName().equals("")) { + return true; + } + return method.hasModifier(ElementModifier.STATIC); + } +} diff --git a/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java b/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java index 9b2780fa7..de649e28f 100644 --- a/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java +++ b/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java @@ -63,7 +63,6 @@ public class AsyncProgramSplitter { Part initialPart = new Part(program.basicBlockCount()); initialPart.program = initialProgram; parts.add(initialPart); - partMap.put(program.basicBlockAt(0).getFirstInstruction(), 0); Step initialStep = new Step(); initialStep.source = 0; initialStep.targetPart = initialPart; @@ -134,7 +133,7 @@ public class AsyncProgramSplitter { // Continue with a new block in the new part targetBlock = nextProgram.createBasicBlock(); - if (step.source > 0) { + if (targetBlock.getIndex() > 0) { JumpInstruction jumpToNextBlock = new JumpInstruction(); jumpToNextBlock.setTarget(targetBlock); nextProgram.basicBlockAt(0).add(jumpToNextBlock); @@ -143,6 +142,8 @@ public class AsyncProgramSplitter { } step.targetPart = part; part.originalBlocks[targetBlock.getIndex()] = step.source; + + partMap.put(program.basicBlockAt(0).getFirstInstruction(), 0); } if (sourceBlock.getExceptionVariable() != null) {