mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Remove call to initializer from wasm generator, put it into IR transformer. Add intrinsic to check whether class has been initializer. Add IR transformer that guards call to initializer with this intrinsic
This commit is contained in:
parent
eaf31c1309
commit
f7e39e6a4d
|
@ -232,7 +232,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
context.addIntrinsic(new StructureIntrinsic(classGenerator));
|
||||
context.addIntrinsic(new FunctionIntrinsic(classGenerator));
|
||||
context.addIntrinsic(new WasmRuntimeIntrinsic());
|
||||
context.addIntrinsic(new AllocatorIntrinsic());
|
||||
context.addIntrinsic(new AllocatorIntrinsic(classGenerator));
|
||||
context.addIntrinsic(new PlatformIntrinsic());
|
||||
context.addIntrinsic(new PlatformClassIntrinsic());
|
||||
context.addIntrinsic(new PlatformObjectIntrinsic(classGenerator));
|
||||
|
|
|
@ -21,23 +21,16 @@ import org.teavm.ast.decompilation.Decompiler;
|
|||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConditional;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Subtype;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||
import org.teavm.model.BasicBlock;
|
||||
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.Program;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.model.instructions.InitClassInstruction;
|
||||
import org.teavm.model.lowlevel.ClassInitializerTransformer;
|
||||
|
||||
public class WasmGenerator {
|
||||
private Decompiler decompiler;
|
||||
|
@ -56,6 +49,16 @@ public class WasmGenerator {
|
|||
public WasmFunction generate(MethodReference methodReference, MethodHolder bodyMethod) {
|
||||
ClassHolder cls = classSource.get(methodReference.getClassName());
|
||||
MethodHolder method = cls.getMethod(methodReference.getDescriptor());
|
||||
Program program = bodyMethod.getProgram();
|
||||
|
||||
if (needsClinitCall(method) && classGenerator.hasClinit(method.getOwnerName())) {
|
||||
BasicBlock entryBlock = program.basicBlockAt(0);
|
||||
InitClassInstruction initInsn = new InitClassInstruction();
|
||||
initInsn.setClassName(bodyMethod.getOwnerName());
|
||||
entryBlock.getInstructions().add(0, initInsn);
|
||||
}
|
||||
|
||||
new ClassInitializerTransformer().transform(program);
|
||||
|
||||
RegularMethodNode methodAst = decompiler.decompileRegular(bodyMethod);
|
||||
WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(methodReference));
|
||||
|
@ -75,19 +78,6 @@ 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);
|
||||
conditional.getThenBlock().getBody().add(new WasmCall(
|
||||
WasmMangling.mangleInitializer(method.getOwnerName())));
|
||||
function.getBody().add(conditional);
|
||||
}
|
||||
|
||||
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, function, methodReference,
|
||||
firstVariable);
|
||||
methodAst.getBody().acceptVisitor(visitor);
|
||||
|
|
|
@ -16,15 +16,35 @@
|
|||
package org.teavm.backend.wasm.intrinsics;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.ast.ConstantExpr;
|
||||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||
import org.teavm.backend.wasm.generate.WasmMangling;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Subtype;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
|
||||
public class AllocatorIntrinsic implements WasmIntrinsic {
|
||||
private static final FieldReference flagsField = new FieldReference(RuntimeClass.class.getName(), "flags");
|
||||
private WasmClassGenerator classGenerator;
|
||||
private int flagsFieldOffset;
|
||||
|
||||
public AllocatorIntrinsic(WasmClassGenerator classGenerator) {
|
||||
this.classGenerator = classGenerator;
|
||||
flagsFieldOffset = classGenerator.getFieldOffset(flagsField);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(MethodReference methodReference) {
|
||||
if (!methodReference.getClassName().equals(Allocator.class.getName())) {
|
||||
|
@ -33,6 +53,7 @@ public class AllocatorIntrinsic implements WasmIntrinsic {
|
|||
switch (methodReference.getName()) {
|
||||
case "fillZero":
|
||||
case "moveMemoryBlock":
|
||||
case "isInitialized":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -44,14 +65,23 @@ public class AllocatorIntrinsic implements WasmIntrinsic {
|
|||
switch (invocation.getMethod().getName()) {
|
||||
case "fillZero":
|
||||
case "moveMemoryBlock": {
|
||||
MethodReference delegateMetod = new MethodReference(WasmRuntime.class.getName(),
|
||||
MethodReference delegateMethod = new MethodReference(WasmRuntime.class.getName(),
|
||||
invocation.getMethod().getDescriptor());
|
||||
WasmCall call = new WasmCall(WasmMangling.mangleMethod(delegateMetod));
|
||||
WasmCall call = new WasmCall(WasmMangling.mangleMethod(delegateMethod));
|
||||
call.getArguments().addAll(invocation.getArguments().stream()
|
||||
.map(manager::generate)
|
||||
.collect(Collectors.toList()));
|
||||
return call;
|
||||
}
|
||||
case "isInitialized": {
|
||||
ConstantExpr argument = (ConstantExpr) invocation.getArguments().get(0);
|
||||
ValueType type = (ValueType) argument.getValue();
|
||||
int pointer = classGenerator.getClassPointer(type) + flagsFieldOffset;
|
||||
WasmExpression flags = new WasmLoadInt32(4, new WasmInt32Constant(pointer), WasmInt32Subtype.INT32);
|
||||
WasmExpression flag = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.AND, flags,
|
||||
new WasmInt32Constant(RuntimeClass.INITIALIZED));
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ, flag, new WasmInt32Constant(0));
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright 2016 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.lowlevel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.Incoming;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Phi;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.Variable;
|
||||
import org.teavm.model.instructions.BranchingCondition;
|
||||
import org.teavm.model.instructions.BranchingInstruction;
|
||||
import org.teavm.model.instructions.ClassConstantInstruction;
|
||||
import org.teavm.model.instructions.InitClassInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.JumpInstruction;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
import org.teavm.runtime.Allocator;
|
||||
|
||||
public class ClassInitializerTransformer {
|
||||
public void transform(Program program) {
|
||||
int[] basicBlockMap = new int[program.basicBlockCount()];
|
||||
for (int i = 0; i < basicBlockMap.length; ++i) {
|
||||
basicBlockMap[i] = i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < basicBlockMap.length; ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
List<Instruction> instructions = block.getInstructions();
|
||||
for (int j = 0; j < instructions.size(); ++j) {
|
||||
Instruction instruction = instructions.get(j);
|
||||
if (instruction instanceof InitClassInstruction) {
|
||||
String className = ((InitClassInstruction) instruction).getClassName();
|
||||
|
||||
BasicBlock continueBlock = program.createBasicBlock();
|
||||
List<Instruction> instructionsToMove = instructions.subList(j + 1, instructions.size());
|
||||
List<Instruction> instructionsToMoveCopy = new ArrayList<>(instructionsToMove);
|
||||
instructionsToMove.clear();
|
||||
continueBlock.getInstructions().addAll(instructionsToMoveCopy);
|
||||
continueBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
|
||||
|
||||
BasicBlock initBlock = program.createBasicBlock();
|
||||
instructions.remove(j);
|
||||
initBlock.getInstructions().add(instruction);
|
||||
JumpInstruction jumpToContinue = new JumpInstruction();
|
||||
jumpToContinue.setTarget(continueBlock);
|
||||
initBlock.getInstructions().add(jumpToContinue);
|
||||
|
||||
createInitCheck(program, block, className, continueBlock, initBlock);
|
||||
|
||||
basicBlockMap[i] = continueBlock.getIndex();
|
||||
block = continueBlock;
|
||||
instructions = block.getInstructions();
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < basicBlockMap.length; ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
for (Phi phi : block.getPhis()) {
|
||||
for (Incoming incoming : phi.getIncomings()) {
|
||||
int source = incoming.getSource().getIndex();
|
||||
BasicBlock mappedSource = program.basicBlockAt(basicBlockMap[source]);
|
||||
incoming.setSource(mappedSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createInitCheck(Program program, BasicBlock block, String className, BasicBlock continueBlock,
|
||||
BasicBlock initBlock) {
|
||||
Variable clsVariable = program.createVariable();
|
||||
Variable initializedVariable = program.createVariable();
|
||||
|
||||
ClassConstantInstruction clsConstant = new ClassConstantInstruction();
|
||||
clsConstant.setReceiver(clsVariable);
|
||||
clsConstant.setConstant(ValueType.object(className));
|
||||
block.getInstructions().add(clsConstant);
|
||||
|
||||
InvokeInstruction checkInitialized = new InvokeInstruction();
|
||||
checkInitialized.setType(InvocationType.SPECIAL);
|
||||
checkInitialized.setMethod(new MethodReference(Allocator.class, "isInitialized",
|
||||
Class.class, boolean.class));
|
||||
checkInitialized.getArguments().add(clsVariable);
|
||||
checkInitialized.setReceiver(initializedVariable);
|
||||
block.getInstructions().add(checkInitialized);
|
||||
|
||||
BranchingInstruction branching = new BranchingInstruction(BranchingCondition.EQUAL);
|
||||
branching.setOperand(initializedVariable);
|
||||
branching.setConsequent(continueBlock);
|
||||
branching.setAlternative(initBlock);
|
||||
block.getInstructions().add(branching);
|
||||
}
|
||||
}
|
|
@ -53,4 +53,6 @@ public final class Allocator {
|
|||
public static native void fillZero(Address address, int count);
|
||||
|
||||
public static native void moveMemoryBlock(Address source, Address target, int count);
|
||||
|
||||
public static native boolean isInitialized(Class<?> cls);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user