mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
WASM: fix bugs in exception handling
This commit is contained in:
parent
cbd74d41f4
commit
f890680e90
|
@ -37,6 +37,7 @@ public final class Example {
|
||||||
testArrayCopy();
|
testArrayCopy();
|
||||||
testArrayIsObject();
|
testArrayIsObject();
|
||||||
testIsAssignableFrom();
|
testIsAssignableFrom();
|
||||||
|
testExceptions();
|
||||||
testBigInteger();
|
testBigInteger();
|
||||||
testGC();
|
testGC();
|
||||||
}
|
}
|
||||||
|
@ -186,6 +187,47 @@ public final class Example {
|
||||||
System.out.println("GC complete");
|
System.out.println("GC complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void testExceptions() {
|
||||||
|
try {
|
||||||
|
throwsException();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
System.out.println("Caught 1: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
try {
|
||||||
|
x = 1;
|
||||||
|
doesNotThrow();
|
||||||
|
x = 2;
|
||||||
|
throwsException();
|
||||||
|
x = 3;
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
System.out.println("Caught 2: " + e.getMessage());
|
||||||
|
System.out.println("x = " + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
throwsWithFinally();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
System.out.println("Caught 3: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doesNotThrow() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void throwsWithFinally() {
|
||||||
|
try {
|
||||||
|
throwsException();
|
||||||
|
} finally {
|
||||||
|
System.out.println("Finally reached");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void throwsException() {
|
||||||
|
throw new IllegalStateException("exception message");
|
||||||
|
}
|
||||||
|
|
||||||
private static Base instance(int index) {
|
private static Base instance(int index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
|
@ -272,11 +272,16 @@ public final class WasmRuntime {
|
||||||
return stackFrame.add(-size * 4);
|
return stackFrame.add(-size * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Address getExceptionHandlerPtr(Address stackFrame) {
|
||||||
|
int size = stackFrame.getInt();
|
||||||
|
return stackFrame.add(-size * 4 - 4);
|
||||||
|
}
|
||||||
|
|
||||||
public static int getCallSiteId(Address stackFrame) {
|
public static int getCallSiteId(Address stackFrame) {
|
||||||
return getStackRootPointer(stackFrame).getInt();
|
return getExceptionHandlerPtr(stackFrame).getInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setExceptionHandlerId(Address stackFrame, int id) {
|
public static void setExceptionHandlerId(Address stackFrame, int id) {
|
||||||
getStackRootPointer(stackFrame).putInt(id);
|
getExceptionHandlerPtr(stackFrame).putInt(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,6 +231,9 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
dependencyChecker.linkMethod(new MethodReference(ExceptionHandling.class, "throwException",
|
dependencyChecker.linkMethod(new MethodReference(ExceptionHandling.class, "throwException",
|
||||||
Throwable.class, void.class), null).use();
|
Throwable.class, void.class), null).use();
|
||||||
|
|
||||||
|
dependencyChecker.linkMethod(new MethodReference(ExceptionHandling.class, "catchException",
|
||||||
|
Throwable.class), null).use();
|
||||||
|
|
||||||
dependencyChecker.linkField(new FieldReference("java.lang.Object", "monitor"), null);
|
dependencyChecker.linkField(new FieldReference("java.lang.Object", "monitor"), null);
|
||||||
|
|
||||||
ClassDependency runtimeClassDep = dependencyChecker.linkClass(RuntimeClass.class.getName(), null);
|
ClassDependency runtimeClassDep = dependencyChecker.linkClass(RuntimeClass.class.getName(), null);
|
||||||
|
@ -501,7 +504,7 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
tagExpression = new WasmLoadInt32(4, tagExpression, WasmInt32Subtype.INT32);
|
tagExpression = new WasmLoadInt32(4, tagExpression, WasmInt32Subtype.INT32);
|
||||||
body.add(new WasmSetLocal(subtypeVar, tagExpression));
|
body.add(new WasmSetLocal(subtypeVar, tagExpression));
|
||||||
|
|
||||||
Collections.sort(ranges, Comparator.comparingInt(range -> range.lower));
|
ranges.sort(Comparator.comparingInt(range -> range.lower));
|
||||||
|
|
||||||
int lower = ranges.get(0).lower;
|
int lower = ranges.get(0).lower;
|
||||||
int upper = ranges.get(ranges.size() - 1).upper;
|
int upper = ranges.get(ranges.size() - 1).upper;
|
||||||
|
|
|
@ -107,8 +107,10 @@ public class BinaryWriter {
|
||||||
public byte[] getData() {
|
public byte[] getData() {
|
||||||
byte[] result = new byte[address];
|
byte[] result = new byte[address];
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
int index = 0;
|
||||||
for (DataValue value : values) {
|
for (DataValue value : values) {
|
||||||
offset = writeData(result, offset, value);
|
offset = writeData(result, offset, value);
|
||||||
|
++index;
|
||||||
}
|
}
|
||||||
return Arrays.copyOf(result, offset);
|
return Arrays.copyOf(result, offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class WasmGenerationContext {
|
||||||
private WasmStringPool stringPool;
|
private WasmStringPool stringPool;
|
||||||
private Map<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
|
private Map<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
|
||||||
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
|
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
|
||||||
private Map<MethodReference, WasmIntrinsic> intrinsicCache = new HashMap<>();
|
private Map<MethodReference, WasmIntrinsicHolder> intrinsicCache = new HashMap<>();
|
||||||
|
|
||||||
public WasmGenerationContext(ClassReaderSource classSource, Diagnostics diagnostics,
|
public WasmGenerationContext(ClassReaderSource classSource, Diagnostics diagnostics,
|
||||||
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool) {
|
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool) {
|
||||||
|
@ -58,9 +58,18 @@ public class WasmGenerationContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
public WasmIntrinsic getIntrinsic(MethodReference method) {
|
public WasmIntrinsic getIntrinsic(MethodReference method) {
|
||||||
return intrinsicCache.computeIfAbsent(method, key -> intrinsics.stream()
|
return intrinsicCache.computeIfAbsent(method, key -> new WasmIntrinsicHolder(intrinsics.stream()
|
||||||
.filter(intrinsic -> intrinsic.isApplicable(key))
|
.filter(intrinsic -> intrinsic.isApplicable(key))
|
||||||
.findFirst().orElse(null));
|
.findFirst().orElse(null)))
|
||||||
|
.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class WasmIntrinsicHolder {
|
||||||
|
WasmIntrinsic value;
|
||||||
|
|
||||||
|
public WasmIntrinsicHolder(WasmIntrinsic value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImportedMethod getImportedMethod(MethodReference reference) {
|
public ImportedMethod getImportedMethod(MethodReference reference) {
|
||||||
|
|
|
@ -23,6 +23,9 @@ import org.teavm.backend.wasm.generate.CallSiteBinaryGenerator;
|
||||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
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.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
||||||
import org.teavm.runtime.ExceptionHandling;
|
import org.teavm.runtime.ExceptionHandling;
|
||||||
|
@ -59,6 +62,11 @@ public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
|
||||||
WasmInt32Constant constant = new WasmInt32Constant(0);
|
WasmInt32Constant constant = new WasmInt32Constant(0);
|
||||||
constant.setLocation(invocation.getLocation());
|
constant.setLocation(invocation.getLocation());
|
||||||
constants.add(constant);
|
constants.add(constant);
|
||||||
return constant;
|
|
||||||
|
WasmExpression id = manager.generate(invocation.getArguments().get(0));
|
||||||
|
WasmExpression offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL,
|
||||||
|
id, new WasmInt32Constant(3));
|
||||||
|
|
||||||
|
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, constant, offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,9 +85,25 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
blockMapping[i] = i;
|
blockMapping[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Phi> allPhis = new ArrayList<>();
|
||||||
int blockCount = program.basicBlockCount();
|
int blockCount = program.basicBlockCount();
|
||||||
|
for (int i = 0; i < blockCount; ++i) {
|
||||||
|
allPhis.addAll(program.basicBlockAt(i).getPhis());
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < blockCount; ++i) {
|
for (int i = 0; i < blockCount; ++i) {
|
||||||
BasicBlock block = program.basicBlockAt(i);
|
BasicBlock block = program.basicBlockAt(i);
|
||||||
|
|
||||||
|
if (block.getExceptionVariable() != null) {
|
||||||
|
InvokeInstruction catchCall = new InvokeInstruction();
|
||||||
|
catchCall.setType(InvocationType.SPECIAL);
|
||||||
|
catchCall.setMethod(new MethodReference(ExceptionHandling.class, "catchException",
|
||||||
|
Throwable.class));
|
||||||
|
catchCall.setReceiver(block.getExceptionVariable());
|
||||||
|
block.getInstructions().add(0, catchCall);
|
||||||
|
block.setExceptionVariable(null);
|
||||||
|
}
|
||||||
|
|
||||||
int newIndex = contributeToBasicBlock(block);
|
int newIndex = contributeToBasicBlock(block);
|
||||||
if (newIndex != i) {
|
if (newIndex != i) {
|
||||||
blockMapping[i] = newIndex;
|
blockMapping[i] = newIndex;
|
||||||
|
@ -95,15 +111,12 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < blockCount; ++i) {
|
for (Phi phi : allPhis) {
|
||||||
BasicBlock block = program.basicBlockAt(i);
|
|
||||||
for (Phi phi : block.getPhis()) {
|
|
||||||
for (Incoming incoming : phi.getIncomings()) {
|
for (Incoming incoming : phi.getIncomings()) {
|
||||||
int mappedSource = blockMapping[incoming.getSource().getIndex()];
|
int mappedSource = blockMapping[incoming.getSource().getIndex()];
|
||||||
incoming.setSource(program.basicBlockAt(mappedSource));
|
incoming.setSource(program.basicBlockAt(mappedSource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return hasExceptionHandlers;
|
return hasExceptionHandlers;
|
||||||
}
|
}
|
||||||
|
@ -130,6 +143,8 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
}
|
}
|
||||||
|
|
||||||
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
||||||
|
List<BasicBlock> blocksToClearHandlers = new ArrayList<>();
|
||||||
|
blocksToClearHandlers.add(block);
|
||||||
|
|
||||||
for (int i = 0; i < instructions.size(); ++i) {
|
for (int i = 0; i < instructions.size(); ++i) {
|
||||||
Instruction insn = instructions.get(i);
|
Instruction insn = instructions.get(i);
|
||||||
|
@ -153,7 +168,7 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
} else {
|
} else {
|
||||||
next = program.createBasicBlock();
|
next = program.createBasicBlock();
|
||||||
next.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
|
next.getTryCatchBlocks().addAll(ProgramUtils.copyTryCatches(block, program));
|
||||||
block.getTryCatchBlocks().clear();
|
blocksToClearHandlers.add(next);
|
||||||
|
|
||||||
List<Instruction> remainingInstructions = instructions.subList(i + 1, instructions.size());
|
List<Instruction> remainingInstructions = instructions.subList(i + 1, instructions.size());
|
||||||
List<Instruction> instructionsToMove = new ArrayList<>(remainingInstructions);
|
List<Instruction> instructionsToMove = new ArrayList<>(remainingInstructions);
|
||||||
|
@ -175,7 +190,7 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
}
|
}
|
||||||
block = next;
|
block = next;
|
||||||
instructions = block.getInstructions();
|
instructions = block.getInstructions();
|
||||||
i = 0;
|
i = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
insn.acceptVisitor(defExtractor);
|
insn.acceptVisitor(defExtractor);
|
||||||
|
@ -185,7 +200,9 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
block.getTryCatchBlocks().clear();
|
for (BasicBlock blockToClear : blocksToClearHandlers) {
|
||||||
|
blockToClear.getTryCatchBlocks().clear();
|
||||||
|
}
|
||||||
|
|
||||||
return block.getIndex();
|
return block.getIndex();
|
||||||
}
|
}
|
||||||
|
@ -253,14 +270,14 @@ public class ExceptionHandlingShadowStackContributor {
|
||||||
boolean defaultExists = false;
|
boolean defaultExists = false;
|
||||||
int nextHandlerId = callSite.getId();
|
int nextHandlerId = callSite.getId();
|
||||||
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
||||||
if (tryCatch.getExceptionType() == null) {
|
|
||||||
defaultExists = true;
|
|
||||||
switchInsn.setDefaultTarget(tryCatch.getHandler());
|
|
||||||
} else {
|
|
||||||
ExceptionHandlerDescriptor handler = new ExceptionHandlerDescriptor(++nextHandlerId,
|
ExceptionHandlerDescriptor handler = new ExceptionHandlerDescriptor(++nextHandlerId,
|
||||||
tryCatch.getExceptionType());
|
tryCatch.getExceptionType());
|
||||||
callSite.getHandlers().add(handler);
|
callSite.getHandlers().add(handler);
|
||||||
|
|
||||||
|
if (tryCatch.getExceptionType() == null) {
|
||||||
|
defaultExists = true;
|
||||||
|
switchInsn.setDefaultTarget(tryCatch.getHandler());
|
||||||
|
} else {
|
||||||
SwitchTableEntry catchEntry = new SwitchTableEntry();
|
SwitchTableEntry catchEntry = new SwitchTableEntry();
|
||||||
catchEntry.setTarget(tryCatch.getHandler());
|
catchEntry.setTarget(tryCatch.getHandler());
|
||||||
catchEntry.setCondition(handler.getId());
|
catchEntry.setCondition(handler.getId());
|
||||||
|
|
|
@ -356,6 +356,7 @@ public class GCShadowStackContributor {
|
||||||
instructionsToAdd.add(slotConstant);
|
instructionsToAdd.add(slotConstant);
|
||||||
|
|
||||||
InvokeInstruction registerInvocation = new InvokeInstruction();
|
InvokeInstruction registerInvocation = new InvokeInstruction();
|
||||||
|
registerInvocation.setLocation(callInstruction.getLocation());
|
||||||
registerInvocation.setType(InvocationType.SPECIAL);
|
registerInvocation.setType(InvocationType.SPECIAL);
|
||||||
registerInvocation.getArguments().add(slotVar);
|
registerInvocation.getArguments().add(slotVar);
|
||||||
if (var >= 0) {
|
if (var >= 0) {
|
||||||
|
|
|
@ -28,7 +28,17 @@ public final class ExceptionHandling {
|
||||||
|
|
||||||
public static native CallSite findCallSiteById(int id);
|
public static native CallSite findCallSiteById(int id);
|
||||||
|
|
||||||
|
private static Throwable thrownException;
|
||||||
|
|
||||||
|
public static Throwable catchException() {
|
||||||
|
Throwable exception = thrownException;
|
||||||
|
thrownException = null;
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
public static void throwException(Throwable exception) {
|
public static void throwException(Throwable exception) {
|
||||||
|
thrownException = exception;
|
||||||
|
|
||||||
RuntimeObject exceptionPtr = Address.ofObject(exception).toStructure();
|
RuntimeObject exceptionPtr = Address.ofObject(exception).toStructure();
|
||||||
RuntimeClass exceptionClass = RuntimeClass.getClass(exceptionPtr);
|
RuntimeClass exceptionClass = RuntimeClass.getClass(exceptionPtr);
|
||||||
IsSupertypeFunction isExceptionSupertype = exceptionClass.isSupertypeOf;
|
IsSupertypeFunction isExceptionSupertype = exceptionClass.isSupertypeOf;
|
||||||
|
@ -40,7 +50,7 @@ public final class ExceptionHandling {
|
||||||
ExceptionHandler handler = callSite.firstHandler;
|
ExceptionHandler handler = callSite.firstHandler;
|
||||||
|
|
||||||
for (int i = 0; i < callSite.handlerCount; ++i) {
|
for (int i = 0; i < callSite.handlerCount; ++i) {
|
||||||
if (isExceptionSupertype.apply(handler.exceptionClass)) {
|
if (handler.exceptionClass == null || isExceptionSupertype.apply(handler.exceptionClass)) {
|
||||||
ShadowStack.setExceptionHandlerId(stackFrame, handler.id);
|
ShadowStack.setExceptionHandlerId(stackFrame, handler.id);
|
||||||
break stackLoop;
|
break stackLoop;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user