mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
WASM: add transformation that converts exception handling to explicit guard checks
This commit is contained in:
parent
8af1e3e66d
commit
b67d243ad4
|
@ -15,17 +15,16 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||
import org.teavm.classlib.java.io.TConsole;
|
||||
import org.teavm.classlib.java.io.TInputStream;
|
||||
import org.teavm.classlib.java.io.TPrintStream;
|
||||
import org.teavm.classlib.java.lang.reflect.TArray;
|
||||
import org.teavm.dependency.PluggableDependency;
|
||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DelegateTo;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.interop.NoGC;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.RuntimeArray;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
|
@ -81,7 +80,7 @@ public final class TSystem extends TObject {
|
|||
@DelegateTo("doArrayCopyLowLevel")
|
||||
private static native void doArrayCopy(Object src, int srcPos, Object dest, int destPos, int length);
|
||||
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
static void doArrayCopyLowLevel(RuntimeArray src, int srcPos, RuntimeArray dest, int destPos, int length) {
|
||||
RuntimeClass type = RuntimeClass.getClass(src);
|
||||
int itemSize = type.itemType.size;
|
||||
|
@ -99,7 +98,7 @@ public final class TSystem extends TObject {
|
|||
}
|
||||
|
||||
@GeneratedBy(SystemNativeGenerator.class)
|
||||
@DelegateTo(("currentTimeMillisLowLevel"))
|
||||
@DelegateTo("currentTimeMillisLowLevel")
|
||||
public static native long currentTimeMillis();
|
||||
|
||||
private static long currentTimeMillisLowLevel() {
|
||||
|
|
|
@ -15,11 +15,16 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.lang.reflect;
|
||||
|
||||
import org.teavm.classlib.java.lang.*;
|
||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||
import org.teavm.classlib.java.lang.TArrayIndexOutOfBoundsException;
|
||||
import org.teavm.classlib.java.lang.TClass;
|
||||
import org.teavm.classlib.java.lang.TIllegalArgumentException;
|
||||
import org.teavm.classlib.java.lang.TNegativeArraySizeException;
|
||||
import org.teavm.classlib.java.lang.TNullPointerException;
|
||||
import org.teavm.classlib.java.lang.TObject;
|
||||
import org.teavm.dependency.PluggableDependency;
|
||||
import org.teavm.interop.DelegateTo;
|
||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||
import org.teavm.interop.NoGC;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
import org.teavm.platform.PlatformClass;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.RuntimeArray;
|
||||
|
@ -61,7 +66,7 @@ public final class TArray extends TObject {
|
|||
private static native TObject newInstanceImpl(PlatformClass componentType, int length);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
private static RuntimeObject newInstanceLowLevel(RuntimeClass cls, int length) {
|
||||
return Allocator.allocateArray(cls.arrayType, length).toStructure();
|
||||
}
|
||||
|
|
|
@ -17,11 +17,11 @@ package org.teavm.backend.wasm;
|
|||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Import;
|
||||
import org.teavm.interop.NoGC;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
@StaticInit
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
public final class WasmRuntime {
|
||||
public static Address stack = initStack();
|
||||
|
||||
|
@ -245,7 +245,7 @@ public final class WasmRuntime {
|
|||
|
||||
public static Address allocStack(int size) {
|
||||
Address result = stack.add(4);
|
||||
stack = result.add(size << 2);
|
||||
stack = result.add((size << 2) + 4);
|
||||
stack.putInt(size);
|
||||
return result;
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ public final class WasmRuntime {
|
|||
}
|
||||
|
||||
public static Address getNextStackRoots(Address address) {
|
||||
int size = address.getInt() + 1;
|
||||
int size = address.getInt() + 2;
|
||||
Address result = address.add(-size * 4);
|
||||
if (result == initStack()) {
|
||||
result = null;
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.teavm.backend.wasm.generate.WasmStringPool;
|
|||
import org.teavm.backend.wasm.intrinsics.AddressIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.AllocatorIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.ClassIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.ExceptionHandlingIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.FunctionIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.GCIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.PlatformClassIntrinsic;
|
||||
|
@ -107,7 +108,7 @@ import org.teavm.model.instructions.InvokeInstruction;
|
|||
import org.teavm.model.instructions.MutatorIntrinsic;
|
||||
import org.teavm.model.lowlevel.ClassInitializerEliminator;
|
||||
import org.teavm.model.lowlevel.ClassInitializerTransformer;
|
||||
import org.teavm.model.lowlevel.GcRootMaintainingTransformer;
|
||||
import org.teavm.model.lowlevel.ShadowStackTransformer;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.RuntimeArray;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
|
@ -126,7 +127,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
private boolean cEmitted;
|
||||
private ClassInitializerEliminator classInitializerEliminator;
|
||||
private ClassInitializerTransformer classInitializerTransformer;
|
||||
private GcRootMaintainingTransformer gcRootMaintainingTransformer;
|
||||
private ShadowStackTransformer shadowStackTransformer;
|
||||
private MethodDescriptor clinitDescriptor = new MethodDescriptor("<clinit>", void.class);
|
||||
|
||||
@Override
|
||||
|
@ -134,7 +135,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
this.controller = controller;
|
||||
classInitializerEliminator = new ClassInitializerEliminator(controller.getUnprocessedClassSource());
|
||||
classInitializerTransformer = new ClassInitializerTransformer();
|
||||
gcRootMaintainingTransformer = new GcRootMaintainingTransformer(controller.getUnprocessedClassSource());
|
||||
shadowStackTransformer = new ShadowStackTransformer(controller.getUnprocessedClassSource());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -248,7 +249,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
|
||||
classInitializerEliminator.apply(program);
|
||||
classInitializerTransformer.transform(program);
|
||||
gcRootMaintainingTransformer.apply(program, method);
|
||||
shadowStackTransformer.apply(program, method);
|
||||
}
|
||||
|
||||
private static boolean needsClinitCall(MethodReader method) {
|
||||
|
@ -293,6 +294,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
context.addIntrinsic(gcIntrinsic);
|
||||
MutatorIntrinsic mutatorIntrinsic = new MutatorIntrinsic();
|
||||
context.addIntrinsic(mutatorIntrinsic);
|
||||
context.addIntrinsic(new ExceptionHandlingIntrinsic());
|
||||
|
||||
WasmGenerator generator = new WasmGenerator(decompiler, classes,
|
||||
context, classGenerator);
|
||||
|
@ -326,12 +328,13 @@ public class WasmTarget implements TeaVMTarget {
|
|||
initFunction.getBody().add(new WasmCall(WasmMangling.mangleInitializer(className)));
|
||||
}
|
||||
module.add(initFunction);
|
||||
module.setStartFunction(initFunction);
|
||||
//module.setStartFunction(initFunction);
|
||||
|
||||
for (TeaVMEntryPoint entryPoint : controller.getEntryPoints().values()) {
|
||||
String mangledName = WasmMangling.mangleMethod(entryPoint.getReference());
|
||||
WasmFunction function = module.getFunctions().get(mangledName);
|
||||
if (function != null) {
|
||||
function.getBody().add(0, new WasmCall(initFunction.getName()));
|
||||
function.setExportName(entryPoint.getPublicName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ import org.teavm.model.ValueType;
|
|||
import org.teavm.model.classes.TagRegistry;
|
||||
import org.teavm.model.classes.VirtualTableEntry;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.ExceptionHandling;
|
||||
import org.teavm.runtime.Mutator;
|
||||
import org.teavm.runtime.RuntimeArray;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
|
@ -797,6 +798,15 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
generateRemoveGcRoot(expr.getArguments().get(0));
|
||||
return;
|
||||
}
|
||||
} else if (expr.getMethod().getClassName().equals(ExceptionHandling.class.getName())) {
|
||||
switch (expr.getMethod().getName()) {
|
||||
case "registerCallSite":
|
||||
generateRegisterCallSite(expr.getArguments().get(0));
|
||||
return;
|
||||
case "getHandlerId":
|
||||
generateGetHandlerId();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WasmIntrinsic intrinsic = context.getIntrinsic(expr.getMethod());
|
||||
|
@ -912,6 +922,27 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
result = new WasmStoreInt32(4, new WasmInt32Constant(offset), oldValue, WasmInt32Subtype.INT32);
|
||||
}
|
||||
|
||||
private void generateRegisterCallSite(Expr callSiteExpr) {
|
||||
if (stackVariable == null) {
|
||||
throw new IllegalStateException("Call to ExceptionHandling.registerCallSite must be dominated by "
|
||||
+ "Mutator.allocStack");
|
||||
}
|
||||
|
||||
callSiteExpr.acceptVisitor(this);
|
||||
WasmExpression callSite = result;
|
||||
|
||||
result = new WasmStoreInt32(4, new WasmGetLocal(stackVariable), callSite, WasmInt32Subtype.INT32);
|
||||
}
|
||||
|
||||
private void generateGetHandlerId() {
|
||||
if (stackVariable == null) {
|
||||
throw new IllegalStateException("Call to ExceptionHandling.getHandlerId must be dominated by "
|
||||
+ "Mutator.allocStack");
|
||||
}
|
||||
|
||||
result = new WasmLoadInt32(4, new WasmGetLocal(stackVariable), WasmInt32Subtype.INT32);
|
||||
}
|
||||
|
||||
private void generateRegisterGcRoot(Expr slotExpr, Expr gcRootExpr) {
|
||||
if (stackVariable == null) {
|
||||
throw new IllegalStateException("Call to Mutator.registerGcRoot must be dominated by "
|
||||
|
@ -946,9 +977,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
private WasmExpression getSlotOffset(WasmExpression slot) {
|
||||
if (slot instanceof WasmInt32Constant) {
|
||||
int slotConstant = ((WasmInt32Constant) slot).getValue();
|
||||
return new WasmInt32Constant(slotConstant << 2);
|
||||
return new WasmInt32Constant((slotConstant << 2) + 4);
|
||||
} else {
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, slot, new WasmInt32Constant(2));
|
||||
slot = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, slot, new WasmInt32Constant(2));
|
||||
slot = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, slot, new WasmInt32Constant(4));
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.backend.wasm.intrinsics;
|
||||
|
||||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.runtime.ExceptionHandling;
|
||||
|
||||
public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
|
||||
@Override
|
||||
public boolean isApplicable(MethodReference methodReference) {
|
||||
if (!methodReference.getClassName().equals(ExceptionHandling.class.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (methodReference.getName()) {
|
||||
case "registerCallSite":
|
||||
case "getHandlerId":
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "registerCallSite":
|
||||
break;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||
}
|
||||
}
|
|
@ -20,6 +20,9 @@ import org.teavm.ast.InvocationExpr;
|
|||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||
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.interop.Structure;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
@ -46,6 +49,19 @@ public class StructureIntrinsic implements WasmIntrinsic {
|
|||
ValueType.Object type = (ValueType.Object) ((ConstantExpr) invocation.getArguments().get(0)).getValue();
|
||||
return new WasmInt32Constant(classGenerator.getClassSize(type.getClassName()));
|
||||
}
|
||||
case "add": {
|
||||
WasmExpression base = manager.generate(invocation.getArguments().get(1));
|
||||
WasmExpression offset = manager.generate(invocation.getArguments().get(2));
|
||||
Object type = ((ConstantExpr) invocation.getArguments().get(0)).getValue();
|
||||
String className = ((ValueType.Object) type).getClassName();
|
||||
int size = classGenerator.getClassSize(className);
|
||||
int alignment = classGenerator.getClassAlignment(className);
|
||||
size = WasmClassGenerator.align(size, alignment);
|
||||
|
||||
offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.MUL, offset,
|
||||
new WasmInt32Constant(size));
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, base, offset);
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public class CallSiteDescriptor {
|
||||
private int id;
|
||||
private List<ExceptionHandlerDescriptor> handlers = new ArrayList<>();
|
||||
|
||||
public CallSiteDescriptor(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<ExceptionHandlerDescriptor> getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public class ExceptionHandlerDescriptor {
|
||||
private int id;
|
||||
private String className;
|
||||
|
||||
public ExceptionHandlerDescriptor(int id, String className) {
|
||||
this.id = id;
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* 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.Arrays;
|
||||
import java.util.List;
|
||||
import org.teavm.common.DominatorTree;
|
||||
import org.teavm.common.Graph;
|
||||
import org.teavm.common.GraphUtils;
|
||||
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.TextLocation;
|
||||
import org.teavm.model.TryCatchBlock;
|
||||
import org.teavm.model.TryCatchJoint;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.Variable;
|
||||
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||
import org.teavm.model.instructions.ConstructArrayInstruction;
|
||||
import org.teavm.model.instructions.ConstructInstruction;
|
||||
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||
import org.teavm.model.instructions.ExitInstruction;
|
||||
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||
import org.teavm.model.instructions.InitClassInstruction;
|
||||
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.LongConstantInstruction;
|
||||
import org.teavm.model.instructions.NullConstantInstruction;
|
||||
import org.teavm.model.instructions.RaiseInstruction;
|
||||
import org.teavm.model.instructions.SwitchInstruction;
|
||||
import org.teavm.model.instructions.SwitchTableEntry;
|
||||
import org.teavm.model.util.DefinitionExtractor;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
import org.teavm.runtime.ExceptionHandling;
|
||||
|
||||
public class ExceptionHandlingShadowStackContributor {
|
||||
private ManagedMethodRepository managedMethodRepository;
|
||||
private List<CallSiteDescriptor> callSites;
|
||||
private BasicBlock defaultExceptionHandler;
|
||||
private MethodReference method;
|
||||
private Program program;
|
||||
private DominatorTree dom;
|
||||
private BasicBlock[] variableDefinitionPlaces;
|
||||
private Phi[] jointPhis;
|
||||
|
||||
public ExceptionHandlingShadowStackContributor(ManagedMethodRepository managedMethodRepository,
|
||||
List<CallSiteDescriptor> callSites, MethodReference method, Program program) {
|
||||
this.managedMethodRepository = managedMethodRepository;
|
||||
this.callSites = callSites;
|
||||
this.method = method;
|
||||
this.program = program;
|
||||
|
||||
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
|
||||
dom = GraphUtils.buildDominatorTree(cfg);
|
||||
variableDefinitionPlaces = ProgramUtils.getVariableDefinitionPlaces(program);
|
||||
jointPhis = new Phi[program.variableCount()];
|
||||
}
|
||||
|
||||
public boolean contribute() {
|
||||
boolean hasExceptionHandlers = false;
|
||||
int[] blockMapping = new int[program.basicBlockCount()];
|
||||
for (int i = 0; i < blockMapping.length; ++i) {
|
||||
blockMapping[i] = i;
|
||||
}
|
||||
|
||||
int blockCount = program.basicBlockCount();
|
||||
for (int i = 0; i < blockCount; ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
int newIndex = contributeToBasicBlock(block);
|
||||
if (newIndex != i) {
|
||||
blockMapping[i] = newIndex;
|
||||
hasExceptionHandlers = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < blockCount; ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
for (Phi phi : block.getPhis()) {
|
||||
for (Incoming incoming : phi.getIncomings()) {
|
||||
int mappedSource = blockMapping[incoming.getSource().getIndex()];
|
||||
incoming.setSource(program.basicBlockAt(mappedSource));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasExceptionHandlers;
|
||||
}
|
||||
|
||||
private int contributeToBasicBlock(BasicBlock block) {
|
||||
List<Instruction> instructions = block.getInstructions();
|
||||
|
||||
int[] currentJointSources = new int[program.variableCount()];
|
||||
int[] jointReceiverMap = new int[program.variableCount()];
|
||||
Arrays.fill(currentJointSources, -1);
|
||||
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
||||
for (TryCatchJoint joint : tryCatch.getJoints()) {
|
||||
for (Variable sourceVar : joint.getSourceVariables()) {
|
||||
BasicBlock sourceVarDefinedAt = variableDefinitionPlaces[sourceVar.getIndex()];
|
||||
if (dom.dominates(sourceVarDefinedAt.getIndex(), block.getIndex())) {
|
||||
currentJointSources[joint.getReceiver().getIndex()] = sourceVar.getIndex();
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (Variable sourceVar : joint.getSourceVariables()) {
|
||||
jointReceiverMap[sourceVar.getIndex()] = joint.getReceiver().getIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
||||
|
||||
for (int i = 0; i < instructions.size(); ++i) {
|
||||
Instruction insn = instructions.get(i);
|
||||
|
||||
if (isCallInstruction(insn)) {
|
||||
BasicBlock next = program.createBasicBlock();
|
||||
next.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
|
||||
block.getTryCatchBlocks().clear();
|
||||
|
||||
List<Instruction> remainingInstructions = instructions.subList(i + 1, instructions.size());
|
||||
List<Instruction> instructionsToMove = new ArrayList<>(remainingInstructions);
|
||||
remainingInstructions.clear();
|
||||
next.getInstructions().addAll(instructionsToMove);
|
||||
|
||||
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size());
|
||||
callSites.add(callSite);
|
||||
List<Instruction> pre = setLocation(getInstructionsBeforeCallSite(callSite), insn.getLocation());
|
||||
List<Instruction> post = setLocation(
|
||||
getInstructionsAfterCallSite(block, next, callSite, currentJointSources),
|
||||
insn.getLocation());
|
||||
instructions.addAll(instructions.size() - 1, pre);
|
||||
instructions.addAll(post);
|
||||
|
||||
block = next;
|
||||
instructions = block.getInstructions();
|
||||
i = 0;
|
||||
} else if (insn instanceof RaiseInstruction) {
|
||||
InvokeInstruction raise = new InvokeInstruction();
|
||||
raise.setMethod(new MethodReference(ExceptionHandling.class, "throwException", Throwable.class,
|
||||
void.class));
|
||||
raise.setType(InvocationType.SPECIAL);
|
||||
raise.getArguments().add(((RaiseInstruction) insn).getException());
|
||||
raise.setLocation(insn.getLocation());
|
||||
instructions.add(i++, raise);
|
||||
}
|
||||
|
||||
insn.acceptVisitor(defExtractor);
|
||||
for (Variable definedVar : defExtractor.getDefinedVariables()) {
|
||||
int jointReceiver = jointReceiverMap[definedVar.getIndex()];
|
||||
currentJointSources[jointReceiver] = definedVar.getIndex();
|
||||
}
|
||||
}
|
||||
|
||||
block.getTryCatchBlocks().clear();
|
||||
|
||||
return block.getIndex();
|
||||
}
|
||||
|
||||
private boolean isCallInstruction(Instruction insn) {
|
||||
if (insn instanceof InitClassInstruction || insn instanceof ConstructInstruction
|
||||
|| insn instanceof ConstructArrayInstruction || insn instanceof CloneArrayInstruction) {
|
||||
return true;
|
||||
} else if (insn instanceof InvokeInstruction) {
|
||||
return managedMethodRepository.isManaged(((InvokeInstruction) insn).getMethod());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<Instruction> getInstructionsBeforeCallSite(CallSiteDescriptor callSite) {
|
||||
List<Instruction> instructions = new ArrayList<>();
|
||||
|
||||
Variable idVariable = program.createVariable();
|
||||
IntegerConstantInstruction idInsn = new IntegerConstantInstruction();
|
||||
idInsn.setConstant(callSite.getId());
|
||||
idInsn.setReceiver(idVariable);
|
||||
instructions.add(idInsn);
|
||||
|
||||
InvokeInstruction registerInsn = new InvokeInstruction();
|
||||
registerInsn.setMethod(new MethodReference(ExceptionHandling.class, "registerCallSite",
|
||||
int.class, void.class));
|
||||
registerInsn.setType(InvocationType.SPECIAL);
|
||||
registerInsn.getArguments().add(idVariable);
|
||||
instructions.add(registerInsn);
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
private List<Instruction> setLocation(List<Instruction> instructions, TextLocation location) {
|
||||
if (location != null) {
|
||||
for (Instruction instruction : instructions) {
|
||||
instruction.setLocation(location);
|
||||
}
|
||||
}
|
||||
return instructions;
|
||||
}
|
||||
|
||||
private List<Instruction> getInstructionsAfterCallSite(BasicBlock block, BasicBlock next,
|
||||
CallSiteDescriptor callSite, int[] currentJointSources) {
|
||||
Program program = block.getProgram();
|
||||
List<Instruction> instructions = new ArrayList<>();
|
||||
|
||||
Variable handlerIdVariable = program.createVariable();
|
||||
InvokeInstruction getHandlerIdInsn = new InvokeInstruction();
|
||||
getHandlerIdInsn.setMethod(new MethodReference(ExceptionHandling.class, "getHandlerId", int.class));
|
||||
getHandlerIdInsn.setType(InvocationType.SPECIAL);
|
||||
getHandlerIdInsn.setReceiver(handlerIdVariable);
|
||||
instructions.add(getHandlerIdInsn);
|
||||
|
||||
SwitchInstruction switchInsn = new SwitchInstruction();
|
||||
switchInsn.setCondition(handlerIdVariable);
|
||||
SwitchTableEntry continueExecutionEntry = new SwitchTableEntry();
|
||||
continueExecutionEntry.setCondition(callSite.getId());
|
||||
continueExecutionEntry.setTarget(next);
|
||||
switchInsn.getEntries().add(continueExecutionEntry);
|
||||
instructions.add(switchInsn);
|
||||
|
||||
boolean defaultExists = false;
|
||||
int nextHandlerId = callSite.getId();
|
||||
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
||||
if (tryCatch.getExceptionType() == null) {
|
||||
defaultExists = true;
|
||||
switchInsn.setDefaultTarget(tryCatch.getHandler());
|
||||
} else {
|
||||
ExceptionHandlerDescriptor handler = new ExceptionHandlerDescriptor(++nextHandlerId,
|
||||
tryCatch.getExceptionType());
|
||||
callSite.getHandlers().add(handler);
|
||||
|
||||
SwitchTableEntry catchEntry = new SwitchTableEntry();
|
||||
catchEntry.setTarget(tryCatch.getHandler());
|
||||
catchEntry.setCondition(handler.getId());
|
||||
switchInsn.getEntries().add(catchEntry);
|
||||
}
|
||||
|
||||
for (TryCatchJoint joint : tryCatch.getJoints()) {
|
||||
Phi phi = getJointPhi(joint);
|
||||
Incoming incoming = new Incoming();
|
||||
incoming.setSource(block);
|
||||
int value = currentJointSources[joint.getReceiver().getIndex()];
|
||||
incoming.setValue(program.variableAt(value));
|
||||
phi.getIncomings().add(incoming);
|
||||
}
|
||||
}
|
||||
|
||||
if (!defaultExists) {
|
||||
switchInsn.setDefaultTarget(getDefaultExceptionHandler());
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
private BasicBlock getDefaultExceptionHandler() {
|
||||
if (defaultExceptionHandler == null) {
|
||||
defaultExceptionHandler = program.createBasicBlock();
|
||||
Variable result = createReturnValueInstructions(defaultExceptionHandler.getInstructions());
|
||||
ExitInstruction exit = new ExitInstruction();
|
||||
exit.setValueToReturn(result);
|
||||
defaultExceptionHandler.getInstructions().add(exit);
|
||||
}
|
||||
return defaultExceptionHandler;
|
||||
}
|
||||
|
||||
private Phi getJointPhi(TryCatchJoint joint) {
|
||||
Phi phi = jointPhis[joint.getReceiver().getIndex()];
|
||||
if (phi == null) {
|
||||
phi = new Phi();
|
||||
phi.setReceiver(joint.getReceiver());
|
||||
BasicBlock handler = program.basicBlockAt(joint.getBlock().getHandler().getIndex());
|
||||
handler.getPhis().add(phi);
|
||||
jointPhis[joint.getReceiver().getIndex()] = phi;
|
||||
}
|
||||
return phi;
|
||||
}
|
||||
|
||||
private Variable createReturnValueInstructions(List<Instruction> instructions) {
|
||||
ValueType returnType = method.getReturnType();
|
||||
if (returnType == ValueType.VOID) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Variable variable = program.createVariable();
|
||||
|
||||
if (returnType instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) returnType).getKind()) {
|
||||
case BOOLEAN:
|
||||
case BYTE:
|
||||
case SHORT:
|
||||
case CHARACTER:
|
||||
case INTEGER:
|
||||
IntegerConstantInstruction intConstant = new IntegerConstantInstruction();
|
||||
intConstant.setReceiver(variable);
|
||||
instructions.add(intConstant);
|
||||
return variable;
|
||||
case LONG:
|
||||
LongConstantInstruction longConstant = new LongConstantInstruction();
|
||||
longConstant.setReceiver(variable);
|
||||
instructions.add(longConstant);
|
||||
return variable;
|
||||
case FLOAT:
|
||||
FloatConstantInstruction floatConstant = new FloatConstantInstruction();
|
||||
floatConstant.setReceiver(variable);
|
||||
instructions.add(floatConstant);
|
||||
return variable;
|
||||
case DOUBLE:
|
||||
DoubleConstantInstruction doubleConstant = new DoubleConstantInstruction();
|
||||
doubleConstant.setReceiver(variable);
|
||||
instructions.add(doubleConstant);
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
|
||||
NullConstantInstruction nullConstant = new NullConstantInstruction();
|
||||
nullConstant.setReceiver(variable);
|
||||
instructions.add(nullConstant);
|
||||
|
||||
return variable;
|
||||
}
|
||||
}
|
|
@ -30,10 +30,7 @@ import org.teavm.common.DominatorTree;
|
|||
import org.teavm.common.Graph;
|
||||
import org.teavm.common.GraphBuilder;
|
||||
import org.teavm.common.GraphUtils;
|
||||
import org.teavm.interop.NoGC;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.Incoming;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.MethodReader;
|
||||
|
@ -44,12 +41,10 @@ import org.teavm.model.Variable;
|
|||
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||
import org.teavm.model.instructions.ConstructArrayInstruction;
|
||||
import org.teavm.model.instructions.ConstructInstruction;
|
||||
import org.teavm.model.instructions.ExitInstruction;
|
||||
import org.teavm.model.instructions.InitClassInstruction;
|
||||
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.JumpInstruction;
|
||||
import org.teavm.model.instructions.RaiseInstruction;
|
||||
import org.teavm.model.util.DefinitionExtractor;
|
||||
import org.teavm.model.util.GraphColorer;
|
||||
|
@ -60,17 +55,14 @@ import org.teavm.model.util.UsageExtractor;
|
|||
import org.teavm.model.util.VariableType;
|
||||
import org.teavm.runtime.Mutator;
|
||||
|
||||
public class GcRootMaintainingTransformer {
|
||||
private ClassReaderSource classSource;
|
||||
public class GCShadowStackContributor {
|
||||
private ManagedMethodRepository managedMethodRepository;
|
||||
|
||||
public GcRootMaintainingTransformer(ClassReaderSource classSource) {
|
||||
this.classSource = classSource;
|
||||
public GCShadowStackContributor(ManagedMethodRepository managedMethodRepository) {
|
||||
this.managedMethodRepository = managedMethodRepository;
|
||||
}
|
||||
|
||||
public void apply(Program program, MethodReader method) {
|
||||
if (!requiresGC(method.getReference())) {
|
||||
return;
|
||||
}
|
||||
public int contribute(Program program, MethodReader method) {
|
||||
List<IntObjectMap<BitSet>> liveInInformation = findCallSiteLiveIns(program, method);
|
||||
|
||||
Graph interferenceGraph = buildInterferenceGraph(liveInInformation, program);
|
||||
|
@ -87,7 +79,7 @@ public class GcRootMaintainingTransformer {
|
|||
}
|
||||
}
|
||||
if (usedColors == 0) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If a variable is spilled to stack, then phi which input this variable also spilled to stack
|
||||
|
@ -103,8 +95,8 @@ public class GcRootMaintainingTransformer {
|
|||
List<IntObjectMap<int[]>> liveInStores = reduceGcRootStores(program, usedColors, liveInInformation,
|
||||
colors, autoSpilled);
|
||||
putLiveInGcRoots(program, liveInStores);
|
||||
addStackAllocation(program, usedColors);
|
||||
addStackRelease(program, usedColors);
|
||||
|
||||
return usedColors;
|
||||
}
|
||||
|
||||
private void findAutoSpilledPhis(boolean[] spilled, List<Set<Phi>> destinationPhis, int[] inputCount,
|
||||
|
@ -158,7 +150,8 @@ public class GcRootMaintainingTransformer {
|
|||
if (insn instanceof InvokeInstruction || insn instanceof InitClassInstruction
|
||||
|| insn instanceof ConstructInstruction || insn instanceof ConstructArrayInstruction
|
||||
|| insn instanceof CloneArrayInstruction || insn instanceof RaiseInstruction) {
|
||||
if (insn instanceof InvokeInstruction && !requiresGC(((InvokeInstruction) insn).getMethod())) {
|
||||
if (insn instanceof InvokeInstruction
|
||||
&& !managedMethodRepository.isManaged(((InvokeInstruction) insn).getMethod())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -379,86 +372,6 @@ public class GcRootMaintainingTransformer {
|
|||
instructions.addAll(index, instructionsToAdd);
|
||||
}
|
||||
|
||||
private void addStackAllocation(Program program, int maxDepth) {
|
||||
BasicBlock block = program.basicBlockAt(0);
|
||||
List<Instruction> instructionsToAdd = new ArrayList<>();
|
||||
Variable sizeVariable = program.createVariable();
|
||||
|
||||
IntegerConstantInstruction sizeConstant = new IntegerConstantInstruction();
|
||||
sizeConstant.setReceiver(sizeVariable);
|
||||
sizeConstant.setConstant(maxDepth);
|
||||
instructionsToAdd.add(sizeConstant);
|
||||
|
||||
InvokeInstruction invocation = new InvokeInstruction();
|
||||
invocation.setType(InvocationType.SPECIAL);
|
||||
invocation.setMethod(new MethodReference(Mutator.class, "allocStack", int.class, void.class));
|
||||
invocation.getArguments().add(sizeVariable);
|
||||
instructionsToAdd.add(invocation);
|
||||
|
||||
block.getInstructions().addAll(0, instructionsToAdd);
|
||||
}
|
||||
|
||||
private void addStackRelease(Program program, int maxDepth) {
|
||||
List<BasicBlock> blocks = new ArrayList<>();
|
||||
boolean hasResult = false;
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
Instruction instruction = block.getLastInstruction();
|
||||
if (instruction instanceof ExitInstruction) {
|
||||
blocks.add(block);
|
||||
if (((ExitInstruction) instruction).getValueToReturn() != null) {
|
||||
hasResult = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicBlock exitBlock;
|
||||
if (blocks.size() == 1) {
|
||||
exitBlock = blocks.get(0);
|
||||
} else {
|
||||
exitBlock = program.createBasicBlock();
|
||||
ExitInstruction exit = new ExitInstruction();
|
||||
exitBlock.getInstructions().add(exit);
|
||||
|
||||
if (hasResult) {
|
||||
Phi phi = new Phi();
|
||||
phi.setReceiver(program.createVariable());
|
||||
exitBlock.getPhis().add(phi);
|
||||
exit.setValueToReturn(phi.getReceiver());
|
||||
|
||||
for (BasicBlock block : blocks) {
|
||||
ExitInstruction oldExit = (ExitInstruction) block.getLastInstruction();
|
||||
Incoming incoming = new Incoming();
|
||||
incoming.setSource(block);
|
||||
incoming.setValue(oldExit.getValueToReturn());
|
||||
phi.getIncomings().add(incoming);
|
||||
|
||||
JumpInstruction jumpToExit = new JumpInstruction();
|
||||
jumpToExit.setTarget(exitBlock);
|
||||
jumpToExit.setLocation(oldExit.getLocation());
|
||||
|
||||
block.getInstructions().set(block.getInstructions().size() - 1, jumpToExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Instruction> instructionsToAdd = new ArrayList<>();
|
||||
Variable sizeVariable = program.createVariable();
|
||||
|
||||
IntegerConstantInstruction sizeConstant = new IntegerConstantInstruction();
|
||||
sizeConstant.setReceiver(sizeVariable);
|
||||
sizeConstant.setConstant(maxDepth);
|
||||
instructionsToAdd.add(sizeConstant);
|
||||
|
||||
InvokeInstruction invocation = new InvokeInstruction();
|
||||
invocation.setType(InvocationType.SPECIAL);
|
||||
invocation.setMethod(new MethodReference(Mutator.class, "releaseStack", int.class, void.class));
|
||||
invocation.getArguments().add(sizeVariable);
|
||||
instructionsToAdd.add(invocation);
|
||||
|
||||
exitBlock.getInstructions().addAll(exitBlock.getInstructions().size() - 1, instructionsToAdd);
|
||||
}
|
||||
|
||||
private boolean isReference(TypeInferer typeInferer, int var) {
|
||||
VariableType liveType = typeInferer.typeOf(var);
|
||||
switch (liveType) {
|
||||
|
@ -476,16 +389,4 @@ public class GcRootMaintainingTransformer {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requiresGC(MethodReference methodReference) {
|
||||
ClassReader cls = classSource.get(methodReference.getClassName());
|
||||
if (cls == null) {
|
||||
return true;
|
||||
}
|
||||
if (cls.getAnnotations().get(NoGC.class.getName()) != null) {
|
||||
return false;
|
||||
}
|
||||
MethodReader method = cls.getMethod(methodReference.getDescriptor());
|
||||
return method.getAnnotations().get(NoGC.class.getName()) == null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class ManagedMethodRepository {
|
||||
private ClassReaderSource classSource;
|
||||
private Map<MethodReference, Boolean> cache = new HashMap<>();
|
||||
|
||||
public ManagedMethodRepository(ClassReaderSource classSource) {
|
||||
this.classSource = classSource;
|
||||
}
|
||||
|
||||
public boolean isManaged(MethodReference methodReference) {
|
||||
return cache.computeIfAbsent(methodReference, this::computeIsManaged);
|
||||
}
|
||||
|
||||
private boolean computeIsManaged(MethodReference methodReference) {
|
||||
ClassReader cls = classSource.get(methodReference.getClassName());
|
||||
if (cls == null) {
|
||||
return true;
|
||||
}
|
||||
if (cls.getAnnotations().get(Unmanaged.class.getName()) != null) {
|
||||
return false;
|
||||
}
|
||||
MethodReader method = cls.getMethod(methodReference.getDescriptor());
|
||||
return method.getAnnotations().get(Unmanaged.class.getName()) == null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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.ClassReaderSource;
|
||||
import org.teavm.model.Incoming;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Phi;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.Variable;
|
||||
import org.teavm.model.instructions.ExitInstruction;
|
||||
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.JumpInstruction;
|
||||
import org.teavm.runtime.Mutator;
|
||||
|
||||
public class ShadowStackTransformer {
|
||||
private ManagedMethodRepository managedMethodRepository;
|
||||
private GCShadowStackContributor gcContributor;
|
||||
private List<CallSiteDescriptor> callSites = new ArrayList<>();
|
||||
|
||||
public ShadowStackTransformer(ClassReaderSource classSource) {
|
||||
managedMethodRepository = new ManagedMethodRepository(classSource);
|
||||
gcContributor = new GCShadowStackContributor(managedMethodRepository);
|
||||
}
|
||||
|
||||
public void apply(Program program, MethodReader method) {
|
||||
if (!managedMethodRepository.isManaged(method.getReference())) {
|
||||
return;
|
||||
}
|
||||
|
||||
int shadowStackSize = gcContributor.contribute(program, method);
|
||||
boolean exceptions = new ExceptionHandlingShadowStackContributor(managedMethodRepository, callSites,
|
||||
method.getReference(), program).contribute();
|
||||
|
||||
if (shadowStackSize > 0 || exceptions) {
|
||||
addStackAllocation(program, shadowStackSize);
|
||||
addStackRelease(program, shadowStackSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void addStackAllocation(Program program, int maxDepth) {
|
||||
BasicBlock block = program.basicBlockAt(0);
|
||||
List<Instruction> instructionsToAdd = new ArrayList<>();
|
||||
Variable sizeVariable = program.createVariable();
|
||||
|
||||
IntegerConstantInstruction sizeConstant = new IntegerConstantInstruction();
|
||||
sizeConstant.setReceiver(sizeVariable);
|
||||
sizeConstant.setConstant(maxDepth);
|
||||
instructionsToAdd.add(sizeConstant);
|
||||
|
||||
InvokeInstruction invocation = new InvokeInstruction();
|
||||
invocation.setType(InvocationType.SPECIAL);
|
||||
invocation.setMethod(new MethodReference(Mutator.class, "allocStack", int.class, void.class));
|
||||
invocation.getArguments().add(sizeVariable);
|
||||
instructionsToAdd.add(invocation);
|
||||
|
||||
block.getInstructions().addAll(0, instructionsToAdd);
|
||||
}
|
||||
|
||||
private void addStackRelease(Program program, int maxDepth) {
|
||||
List<BasicBlock> blocks = new ArrayList<>();
|
||||
boolean hasResult = false;
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlock block = program.basicBlockAt(i);
|
||||
Instruction instruction = block.getLastInstruction();
|
||||
if (instruction instanceof ExitInstruction) {
|
||||
blocks.add(block);
|
||||
if (((ExitInstruction) instruction).getValueToReturn() != null) {
|
||||
hasResult = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicBlock exitBlock;
|
||||
if (blocks.size() == 1) {
|
||||
exitBlock = blocks.get(0);
|
||||
} else {
|
||||
exitBlock = program.createBasicBlock();
|
||||
ExitInstruction exit = new ExitInstruction();
|
||||
exitBlock.getInstructions().add(exit);
|
||||
|
||||
if (hasResult) {
|
||||
Phi phi = new Phi();
|
||||
phi.setReceiver(program.createVariable());
|
||||
exitBlock.getPhis().add(phi);
|
||||
exit.setValueToReturn(phi.getReceiver());
|
||||
|
||||
for (BasicBlock block : blocks) {
|
||||
ExitInstruction oldExit = (ExitInstruction) block.getLastInstruction();
|
||||
Incoming incoming = new Incoming();
|
||||
incoming.setSource(block);
|
||||
incoming.setValue(oldExit.getValueToReturn());
|
||||
phi.getIncomings().add(incoming);
|
||||
}
|
||||
}
|
||||
|
||||
for (BasicBlock block : blocks) {
|
||||
ExitInstruction oldExit = (ExitInstruction) block.getLastInstruction();
|
||||
JumpInstruction jumpToExit = new JumpInstruction();
|
||||
jumpToExit.setTarget(exitBlock);
|
||||
jumpToExit.setLocation(oldExit.getLocation());
|
||||
jumpToExit.setLocation(oldExit.getLocation());
|
||||
|
||||
block.getInstructions().set(block.getInstructions().size() - 1, jumpToExit);
|
||||
}
|
||||
}
|
||||
|
||||
List<Instruction> instructionsToAdd = new ArrayList<>();
|
||||
Variable sizeVariable = program.createVariable();
|
||||
|
||||
IntegerConstantInstruction sizeConstant = new IntegerConstantInstruction();
|
||||
sizeConstant.setReceiver(sizeVariable);
|
||||
sizeConstant.setConstant(maxDepth);
|
||||
instructionsToAdd.add(sizeConstant);
|
||||
|
||||
InvokeInstruction invocation = new InvokeInstruction();
|
||||
invocation.setType(InvocationType.SPECIAL);
|
||||
invocation.setMethod(new MethodReference(Mutator.class, "releaseStack", int.class, void.class));
|
||||
invocation.getArguments().add(sizeVariable);
|
||||
instructionsToAdd.add(invocation);
|
||||
|
||||
exitBlock.getInstructions().addAll(exitBlock.getInstructions().size() - 1, instructionsToAdd);
|
||||
}
|
||||
}
|
|
@ -29,8 +29,6 @@ import org.teavm.model.MethodReader;
|
|||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Phi;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.TryCatchBlock;
|
||||
import org.teavm.model.TryCatchJoint;
|
||||
import org.teavm.model.instructions.AssignInstruction;
|
||||
import org.teavm.model.instructions.BinaryBranchingInstruction;
|
||||
import org.teavm.model.instructions.BranchingInstruction;
|
||||
|
@ -42,7 +40,6 @@ import org.teavm.model.instructions.InvokeInstruction;
|
|||
import org.teavm.model.instructions.JumpInstruction;
|
||||
import org.teavm.model.instructions.SwitchInstruction;
|
||||
import org.teavm.model.util.BasicBlockMapper;
|
||||
import org.teavm.model.util.InstructionCopyReader;
|
||||
import org.teavm.model.util.InstructionTransitionExtractor;
|
||||
import org.teavm.model.util.InstructionVariableMapper;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
|
@ -82,7 +79,7 @@ public class Inlining {
|
|||
List<Instruction> instructionsToMove = new ArrayList<>(movedInstructions);
|
||||
movedInstructions.clear();
|
||||
splitBlock.getInstructions().addAll(instructionsToMove);
|
||||
copyTryCatchBlocks(block, splitBlock);
|
||||
splitBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
|
||||
|
||||
block.getInstructions().remove(block.getInstructions().size() - 1);
|
||||
if (invoke.getInstance() == null || invoke.getMethod().getName().equals("<init>")) {
|
||||
|
@ -97,7 +94,7 @@ public class Inlining {
|
|||
for (int i = 0; i < inlineProgram.basicBlockCount(); ++i) {
|
||||
BasicBlock blockToInline = inlineProgram.basicBlockAt(i);
|
||||
BasicBlock inlineBlock = program.basicBlockAt(firstInlineBlock.getIndex() + i);
|
||||
copyInlinedBlock(blockToInline, inlineBlock);
|
||||
ProgramUtils.copyBasicBlock(blockToInline, inlineBlock);
|
||||
}
|
||||
|
||||
BasicBlockMapper blockMapper = new BasicBlockMapper(index -> index + firstInlineBlock.getIndex());
|
||||
|
@ -116,7 +113,7 @@ public class Inlining {
|
|||
BasicBlock mappedBlock = program.basicBlockAt(firstInlineBlock.getIndex() + i);
|
||||
blockMapper.transform(mappedBlock);
|
||||
variableMapper.apply(mappedBlock);
|
||||
copyTryCatchBlocks(block, mappedBlock);
|
||||
mappedBlock.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
|
||||
Instruction lastInsn = mappedBlock.getLastInstruction();
|
||||
if (lastInsn instanceof ExitInstruction) {
|
||||
ExitInstruction exit = (ExitInstruction) lastInsn;
|
||||
|
@ -165,58 +162,6 @@ public class Inlining {
|
|||
execPlan(program, planEntry.innerPlan, firstInlineBlock.getIndex());
|
||||
}
|
||||
|
||||
private void copyInlinedBlock(BasicBlock source, BasicBlock target) {
|
||||
if (source.getExceptionVariable() != null) {
|
||||
target.setExceptionVariable(source.getExceptionVariable());
|
||||
}
|
||||
|
||||
InstructionCopyReader insnCopier = new InstructionCopyReader(target.getProgram());
|
||||
for (int i = 0; i < source.instructionCount(); ++i) {
|
||||
source.readInstruction(i, insnCopier);
|
||||
Instruction insn = insnCopier.getCopy();
|
||||
target.getInstructions().add(insn);
|
||||
}
|
||||
|
||||
for (Phi phi : source.getPhis()) {
|
||||
Phi phiCopy = new Phi();
|
||||
phiCopy.setReceiver(phi.getReceiver());
|
||||
for (Incoming incoming : phi.getIncomings()) {
|
||||
Incoming incomingCopy = new Incoming();
|
||||
int sourceIndex = incoming.getSource().getIndex();
|
||||
incomingCopy.setSource(target.getProgram().basicBlockAt(sourceIndex));
|
||||
incomingCopy.setValue(incoming.getValue());
|
||||
phiCopy.getIncomings().add(incomingCopy);
|
||||
}
|
||||
target.getPhis().add(phiCopy);
|
||||
}
|
||||
|
||||
for (TryCatchBlock tryCatch : source.getTryCatchBlocks()) {
|
||||
TryCatchBlock tryCatchCopy = new TryCatchBlock();
|
||||
int handler = tryCatch.getHandler().getIndex();
|
||||
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
|
||||
tryCatchCopy.setHandler(target.getProgram().basicBlockAt(handler));
|
||||
target.getTryCatchBlocks().add(tryCatchCopy);
|
||||
|
||||
for (TryCatchJoint joint : tryCatch.getJoints()) {
|
||||
TryCatchJoint jointCopy = new TryCatchJoint();
|
||||
jointCopy.setReceiver(joint.getReceiver());
|
||||
jointCopy.getSourceVariables().addAll(joint.getSourceVariables());
|
||||
tryCatchCopy.getJoints().add(joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyTryCatchBlocks(BasicBlock source, BasicBlock target) {
|
||||
List<TryCatchBlock> copiedTryCatches = new ArrayList<>();
|
||||
for (TryCatchBlock tryCatch : source.getTryCatchBlocks()) {
|
||||
TryCatchBlock tryCatchCopy = new TryCatchBlock();
|
||||
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
|
||||
tryCatchCopy.setHandler(tryCatch.getHandler());
|
||||
copiedTryCatches.add(tryCatchCopy);
|
||||
}
|
||||
target.getTryCatchBlocks().addAll(copiedTryCatches);
|
||||
}
|
||||
|
||||
private List<PlanEntry> buildPlan(Program program, ClassReaderSource classSource, int depth) {
|
||||
if (depth >= MAX_DEPTH) {
|
||||
return Collections.emptyList();
|
||||
|
|
|
@ -78,16 +78,22 @@ public final class ProgramUtils {
|
|||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlockReader block = program.basicBlockAt(i);
|
||||
BasicBlock blockCopy = copy.basicBlockAt(i);
|
||||
if (block.getExceptionVariable() != null) {
|
||||
blockCopy.setExceptionVariable(copy.variableAt(block.getExceptionVariable().getIndex()));
|
||||
}
|
||||
blockCopy.getInstructions().addAll(copyInstructions(block, 0, block.instructionCount(), copy));
|
||||
blockCopy.getPhis().addAll(copyPhis(block, copy));
|
||||
blockCopy.getTryCatchBlocks().addAll(copyTryCatches(block, copy));
|
||||
copyBasicBlock(block, blockCopy);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
public static void copyBasicBlock(BasicBlockReader block, BasicBlock target) {
|
||||
Program targetProgram = target.getProgram();
|
||||
|
||||
if (block.getExceptionVariable() != null) {
|
||||
target.setExceptionVariable(targetProgram.variableAt(block.getExceptionVariable().getIndex()));
|
||||
}
|
||||
target.getInstructions().addAll(copyInstructions(block, 0, block.instructionCount(), targetProgram));
|
||||
target.getPhis().addAll(copyPhis(block, targetProgram));
|
||||
target.getTryCatchBlocks().addAll(copyTryCatches(block, targetProgram));
|
||||
}
|
||||
|
||||
public static List<Instruction> copyInstructions(BasicBlockReader block, int from, int to, Program target) {
|
||||
List<Instruction> result = new ArrayList<>();
|
||||
InstructionCopyReader copyReader = new InstructionCopyReader(target);
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
package org.teavm.runtime;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.NoGC;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
@StaticInit
|
||||
public final class Allocator {
|
||||
|
@ -47,12 +47,12 @@ public final class Allocator {
|
|||
return result;
|
||||
}
|
||||
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
public static native void fillZero(Address address, int count);
|
||||
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
public static native void moveMemoryBlock(Address source, Address target, int count);
|
||||
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
public static native boolean isInitialized(Class<?> cls);
|
||||
}
|
||||
|
|
27
core/src/main/java/org/teavm/runtime/CallSite.java
Normal file
27
core/src/main/java/org/teavm/runtime/CallSite.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.runtime;
|
||||
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
@Unmanaged
|
||||
@StaticInit
|
||||
public class CallSite extends Structure {
|
||||
public int handlerCount;
|
||||
public ExceptionHandler firstHandler;
|
||||
}
|
27
core/src/main/java/org/teavm/runtime/ExceptionHandler.java
Normal file
27
core/src/main/java/org/teavm/runtime/ExceptionHandler.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.runtime;
|
||||
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
@Unmanaged
|
||||
@StaticInit
|
||||
public class ExceptionHandler extends Structure {
|
||||
public int id;
|
||||
public RuntimeClass exceptionClass;
|
||||
}
|
69
core/src/main/java/org/teavm/runtime/ExceptionHandling.java
Normal file
69
core/src/main/java/org/teavm/runtime/ExceptionHandling.java
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.runtime;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
@Unmanaged
|
||||
@StaticInit
|
||||
public final class ExceptionHandling {
|
||||
private ExceptionHandling() {
|
||||
}
|
||||
|
||||
public static native void registerCallSite(int id);
|
||||
|
||||
public static native int callSiteResult();
|
||||
|
||||
public static native Address getStackTop();
|
||||
|
||||
public static native Address getNextStackFrame(Address stackFrame);
|
||||
|
||||
public static native int getCallSiteId(Address stackFrame);
|
||||
|
||||
public static native void setHandlerId(Address stackFrame, int id);
|
||||
|
||||
public static native int getHandlerId();
|
||||
|
||||
public static native CallSite findCallSiteById(int id);
|
||||
|
||||
public static void throwException(Throwable exception) {
|
||||
RuntimeObject exceptionPtr = Address.ofObject(exception).toStructure();
|
||||
RuntimeClass exceptionClass = RuntimeClass.getClass(exceptionPtr);
|
||||
IsSupertypeFunction isExceptionSupertype = exceptionClass.isSupertypeOf;
|
||||
|
||||
Address stackFrame = getStackTop();
|
||||
stackLoop: while (stackFrame != null) {
|
||||
int callSiteId = getCallSiteId(stackFrame);
|
||||
CallSite callSite = findCallSiteById(callSiteId);
|
||||
ExceptionHandler handler = callSite.firstHandler;
|
||||
|
||||
for (int i = 0; i < callSite.handlerCount; ++i) {
|
||||
if (isExceptionSupertype.apply(handler.exceptionClass)) {
|
||||
setHandlerId(stackFrame, handler.id);
|
||||
break stackLoop;
|
||||
}
|
||||
|
||||
handler = Structure.add(ExceptionHandler.class, handler, 1);
|
||||
}
|
||||
|
||||
setHandlerId(stackFrame, callSiteId - 1);
|
||||
stackFrame = getNextStackFrame(stackFrame);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,11 +16,11 @@
|
|||
package org.teavm.runtime;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.NoGC;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
@StaticInit
|
||||
public final class GC {
|
||||
private GC() {
|
||||
|
@ -93,7 +93,7 @@ public final class GC {
|
|||
if (--freeChunks == 0) {
|
||||
return false;
|
||||
}
|
||||
currentChunkPointer = currentChunkPointer.toAddress().add(FreeChunkHolder.class, 1).toStructure();
|
||||
currentChunkPointer = Structure.add(FreeChunkHolder.class, currentChunkPointer, 1);
|
||||
currentChunk = currentChunkPointer.value;
|
||||
currentChunkLimit = currentChunk.toAddress().add(currentChunk.size);
|
||||
}
|
||||
|
@ -147,8 +147,7 @@ public final class GC {
|
|||
object.classReference |= RuntimeObject.GC_MARKED;
|
||||
|
||||
long offset = object.toAddress().toLong() - heapAddress().toLong();
|
||||
Region region = regionsAddress().toAddress().add(Region.class, (int) (offset / regionSize()))
|
||||
.toStructure();
|
||||
Region region = Structure.add(Region.class, regionsAddress(), (int) (offset / regionSize()));
|
||||
short relativeOffset = (short) (offset % regionSize() + 1);
|
||||
if (region.start == 0 || region.start > relativeOffset) {
|
||||
region.start = relativeOffset;
|
||||
|
@ -221,16 +220,14 @@ public final class GC {
|
|||
|
||||
if (!object.toAddress().isLessThan(currentRegionEnd)) {
|
||||
currentRegionIndex = (int) ((object.toAddress().toLong() - heapAddress().toLong()) / regionSize());
|
||||
Region currentRegion = regionsAddress().toAddress().add(Region.class, currentRegionIndex)
|
||||
.toStructure();
|
||||
Region currentRegion = Structure.add(Region.class, regionsAddress(), currentRegionIndex);
|
||||
if (currentRegion.start == 0) {
|
||||
do {
|
||||
if (++currentRegionIndex == regionsCount) {
|
||||
object = limit.toStructure();
|
||||
break loop;
|
||||
}
|
||||
currentRegion = regionsAddress().toAddress().add(Region.class, currentRegionIndex)
|
||||
.toStructure();
|
||||
currentRegion = Structure.add(Region.class, regionsAddress(), currentRegionIndex);
|
||||
} while (currentRegion.start == 0);
|
||||
}
|
||||
currentRegionEnd = currentRegion.toAddress().add(regionSize());
|
||||
|
@ -239,7 +236,7 @@ public final class GC {
|
|||
if (lastFreeSpace != null) {
|
||||
lastFreeSpace.size = (int) (object.toAddress().toLong() - lastFreeSpace.toAddress().toLong());
|
||||
freeChunkPtr.value = lastFreeSpace;
|
||||
freeChunkPtr = freeChunkPtr.toAddress().add(FreeChunkHolder.class, 1).toStructure();
|
||||
freeChunkPtr = Structure.add(FreeChunkHolder.class, freeChunkPtr, 1);
|
||||
freeChunks++;
|
||||
reclaimedSpace += lastFreeSpace.size;
|
||||
if (maxFreeChunk < lastFreeSpace.size) {
|
||||
|
@ -257,7 +254,7 @@ public final class GC {
|
|||
int freeSize = (int) (object.toAddress().toLong() - lastFreeSpace.toAddress().toLong());
|
||||
lastFreeSpace.size = freeSize;
|
||||
freeChunkPtr.value = lastFreeSpace;
|
||||
freeChunkPtr = freeChunkPtr.toAddress().add(FreeChunkHolder.class, 1).toStructure();
|
||||
freeChunkPtr = Structure.add(FreeChunkHolder.class, freeChunkPtr, 1);
|
||||
freeChunks++;
|
||||
reclaimedSpace += freeSize;
|
||||
if (maxFreeChunk < freeSize) {
|
||||
|
@ -310,7 +307,7 @@ public final class GC {
|
|||
}
|
||||
|
||||
private static FreeChunkHolder getFreeChunk(int index) {
|
||||
return currentChunkPointer.toAddress().add(FreeChunkHolder.class, index).toStructure();
|
||||
return Structure.add(FreeChunkHolder.class, currentChunkPointer, index);
|
||||
}
|
||||
|
||||
private static int objectSize(RuntimeObject object) {
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
package org.teavm.runtime;
|
||||
|
||||
import org.teavm.interop.Function;
|
||||
import org.teavm.interop.NoGC;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
public abstract class IsSupertypeFunction extends Function {
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
public abstract boolean apply(RuntimeClass superType);
|
||||
}
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
package org.teavm.runtime;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.NoGC;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
@StaticInit
|
||||
public final class Mutator {
|
||||
private Mutator() {
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
package org.teavm.runtime;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.NoGC;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
public class RuntimeClass extends RuntimeJavaObject {
|
||||
public static final int INITIALIZED = 1;
|
||||
|
@ -32,17 +32,17 @@ public class RuntimeClass extends RuntimeJavaObject {
|
|||
public RuntimeClass parent;
|
||||
public Address layout;
|
||||
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
public static int computeCanary(int size, int tag) {
|
||||
return size ^ (tag << 8) ^ (tag >>> 24) ^ 0xAAAAAAAA;
|
||||
}
|
||||
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
public int computeCanary() {
|
||||
return computeCanary(size, tag);
|
||||
}
|
||||
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
public static RuntimeClass getClass(RuntimeObject object) {
|
||||
return Address.fromInt(object.classReference << 3).toStructure();
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
package org.teavm.interop;
|
||||
|
||||
@StaticInit
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
public final class Address {
|
||||
public native Address add(int offset);
|
||||
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
*/
|
||||
package org.teavm.interop;
|
||||
|
||||
@NoGC
|
||||
@Unmanaged
|
||||
public class Structure {
|
||||
public final native <T extends Structure> T cast();
|
||||
|
||||
public final native Address toAddress();
|
||||
|
||||
public static native int sizeOf(Class<? extends Structure> type);
|
||||
|
||||
public static native <T extends Structure> T add(Class<T> type, T base, int offset);
|
||||
}
|
||||
|
|
|
@ -22,5 +22,5 @@ import java.lang.annotation.Target;
|
|||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface NoGC {
|
||||
public @interface Unmanaged {
|
||||
}
|
Loading…
Reference in New Issue
Block a user