mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Don't generate call to <clinit> 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.
This commit is contained in:
parent
323911ffc9
commit
891e3b8ea9
|
@ -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<MethodReference> asyncMethods = new HashSet<>();
|
||||
private final Set<MethodReference> asyncFamilyMethods = new HashSet<>();
|
||||
private ClassInitializerInsertionTransformer clinitInsertionTransformer;
|
||||
|
||||
@Override
|
||||
public List<ClassHolderTransformer> 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) {
|
||||
|
|
|
@ -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("<clinit>"))
|
||||
|| method.getReference().getName().equals("<init>");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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("<clinit>", 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("<clinit>")) {
|
||||
return false;
|
||||
}
|
||||
if (method.getName().equals("<init>")) {
|
||||
return true;
|
||||
}
|
||||
return method.hasModifier(ElementModifier.STATIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName)
|
||||
throws IOException {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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("<clinit>", 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("<clinit>")) {
|
||||
return false;
|
||||
}
|
||||
if (method.getName().equals("<init>")) {
|
||||
return true;
|
||||
}
|
||||
return method.hasModifier(ElementModifier.STATIC);
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user