From 891e3b8ea924511b94d6d11a1bfffb987ee8cf44 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 22 Feb 2017 23:05:58 +0300 Subject: [PATCH] Don't generate call to on each static method during AST rendering. Instead, extract from WASM transformation that adds InitClassInstruction to beginning of each method and reuse in in JS. This fixes some issues in async methods, without making AST renderer much more complicated. --- .../backend/javascript/JavaScriptTarget.java | 4 ++ .../javascript/rendering/Renderer.java | 13 +---- .../org/teavm/backend/wasm/WasmTarget.java | 25 ++------- .../instructions/InitClassInstruction.java | 4 -- .../ClassInitializerInsertionTransformer.java | 55 +++++++++++++++++++ .../model/util/AsyncProgramSplitter.java | 5 +- 6 files changed, 69 insertions(+), 37 deletions(-) create mode 100644 core/src/main/java/org/teavm/model/transformation/ClassInitializerInsertionTransformer.java 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) {