mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
WASM: support stack traces
This commit is contained in:
parent
09b3f18a2c
commit
8330eae4ae
|
@ -21,10 +21,14 @@ import java.util.Map;
|
|||
import org.teavm.classlib.impl.DeclaringClassMetadataGenerator;
|
||||
import org.teavm.classlib.java.lang.annotation.TAnnotation;
|
||||
import org.teavm.classlib.java.lang.reflect.TAnnotatedElement;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DelegateTo;
|
||||
import org.teavm.platform.Platform;
|
||||
import org.teavm.platform.PlatformClass;
|
||||
import org.teavm.platform.metadata.ClassResource;
|
||||
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.runtime.RuntimeJavaObject;
|
||||
|
||||
public class TClass<T> extends TObject implements TAnnotatedElement {
|
||||
TString name;
|
||||
|
@ -61,6 +65,7 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
|
|||
return Platform.isAssignable(obj.getPlatformClass(), platformClass);
|
||||
}
|
||||
|
||||
@DelegateTo("getNameLowLevel")
|
||||
public TString getName() {
|
||||
if (name == null) {
|
||||
name = TString.wrap(Platform.getName(platformClass));
|
||||
|
@ -68,6 +73,11 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
|
|||
return name;
|
||||
}
|
||||
|
||||
private RuntimeJavaObject getNameLowLevel() {
|
||||
RuntimeClass runtimeClass = Address.ofObject(this).toStructure();
|
||||
return runtimeClass.name;
|
||||
}
|
||||
|
||||
public TString getSimpleName() {
|
||||
if (simpleName == null) {
|
||||
if (isArray()) {
|
||||
|
|
|
@ -19,10 +19,6 @@ import java.util.Objects;
|
|||
import org.teavm.classlib.java.io.TSerializable;
|
||||
import org.teavm.classlib.java.util.TObjects;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public final class TStackTraceElement extends TObject implements TSerializable {
|
||||
private TString declaringClass;
|
||||
private TString methodName;
|
||||
|
@ -89,6 +85,7 @@ public final class TStackTraceElement extends TObject implements TSerializable {
|
|||
} else {
|
||||
sb.append(TString.wrap("Unknown Source"));
|
||||
}
|
||||
sb.append(TString.wrap(")"));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@ package org.teavm.classlib.java.lang;
|
|||
|
||||
import org.teavm.classlib.java.io.TPrintStream;
|
||||
import org.teavm.classlib.java.util.TArrays;
|
||||
import org.teavm.interop.DelegateTo;
|
||||
import org.teavm.interop.Remove;
|
||||
import org.teavm.interop.Rename;
|
||||
import org.teavm.interop.Superclass;
|
||||
import org.teavm.runtime.ExceptionHandling;
|
||||
|
||||
@Superclass("java.lang.Object")
|
||||
public class TThrowable extends RuntimeException {
|
||||
|
@ -29,6 +31,7 @@ public class TThrowable extends RuntimeException {
|
|||
private boolean suppressionEnabled;
|
||||
private boolean writableStackTrace;
|
||||
private TThrowable[] suppressed = new TThrowable[0];
|
||||
private TStackTraceElement[] stackTrace;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Rename("fakeInit")
|
||||
|
@ -97,10 +100,18 @@ public class TThrowable extends RuntimeException {
|
|||
}
|
||||
|
||||
@Override
|
||||
@DelegateTo("fillInStackTraceLowLevel")
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private TThrowable fillInStackTraceLowLevel() {
|
||||
int stackSize = ExceptionHandling.callStackSize() - 1;
|
||||
stackTrace = new TStackTraceElement[stackSize];
|
||||
ExceptionHandling.fillStackTrace((StackTraceElement[]) (Object) stackTrace, 2);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Rename("getMessage")
|
||||
public TString getMessage0() {
|
||||
return message;
|
||||
|
@ -143,15 +154,25 @@ public class TThrowable extends RuntimeException {
|
|||
|
||||
public void printStackTrace(TPrintStream stream) {
|
||||
stream.println(TString.wrap(getClass().getName() + ": " + getMessage()));
|
||||
if (stackTrace != null) {
|
||||
for (TStackTraceElement element : stackTrace) {
|
||||
stream.print(TString.wrap(" at "));
|
||||
stream.println(element);
|
||||
}
|
||||
}
|
||||
if (cause != null && cause != this) {
|
||||
stream.print(TString.wrap("Caused by: "));
|
||||
cause.printStackTrace(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@Rename("getStackTrace")
|
||||
public TStackTraceElement[] getStackTrace0() {
|
||||
return new TStackTraceElement[0];
|
||||
return stackTrace != null ? stackTrace.clone() : new TStackTraceElement[0];
|
||||
}
|
||||
|
||||
public void setStackTrace(@SuppressWarnings("unused") TStackTraceElement[] stackTrace) {
|
||||
// do nothing
|
||||
this.stackTrace = stackTrace.clone();
|
||||
}
|
||||
|
||||
@Rename("getSuppressed")
|
||||
|
|
|
@ -282,7 +282,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
|
||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||
new HashSet<>());
|
||||
WasmStringPool stringPool = new WasmStringPool(classGenerator, binaryWriter);
|
||||
WasmStringPool stringPool = classGenerator.getStringPool();
|
||||
WasmGenerationContext context = new WasmGenerationContext(classes, module, controller.getDiagnostics(),
|
||||
vtableProvider, tagRegistry, stringPool);
|
||||
|
||||
|
@ -302,7 +302,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
context.addIntrinsic(mutatorIntrinsic);
|
||||
context.addIntrinsic(new ShadowStackIntrinsic());
|
||||
ExceptionHandlingIntrinsic exceptionHandlingIntrinsic = new ExceptionHandlingIntrinsic(binaryWriter,
|
||||
classGenerator);
|
||||
classGenerator, stringPool);
|
||||
context.addIntrinsic(exceptionHandlingIntrinsic);
|
||||
|
||||
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator, binaryWriter);
|
||||
|
|
|
@ -16,34 +16,50 @@
|
|||
package org.teavm.backend.wasm.generate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||
import org.teavm.backend.wasm.binary.DataPrimitives;
|
||||
import org.teavm.backend.wasm.binary.DataStructure;
|
||||
import org.teavm.backend.wasm.binary.DataValue;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
||||
import org.teavm.model.lowlevel.CallSiteLocation;
|
||||
import org.teavm.model.lowlevel.ExceptionHandlerDescriptor;
|
||||
|
||||
public class CallSiteBinaryGenerator {
|
||||
private static final int CALL_SITE_HANDLER_COUNT = 0;
|
||||
private static final int CALL_SITE_FIRST_HANDLER = 1;
|
||||
private static final int CALL_SITE_LOCATION = 2;
|
||||
private static final int EXCEPTION_HANDLER_ID = 0;
|
||||
private static final int EXCEPTION_HANDLER_CLASS = 1;
|
||||
private static final int LOCATION_FILE = 0;
|
||||
private static final int LOCATION_CLASS = 1;
|
||||
private static final int LOCATION_METHOD = 2;
|
||||
private static final int LOCATION_LINE_NUMBER = 3;
|
||||
|
||||
private DataStructure callSiteStructure = new DataStructure((byte) 0,
|
||||
DataPrimitives.INT,
|
||||
DataPrimitives.ADDRESS,
|
||||
DataPrimitives.ADDRESS);
|
||||
private DataStructure exceptionHandlerStructure = new DataStructure((byte) 0,
|
||||
DataPrimitives.INT,
|
||||
DataPrimitives.ADDRESS);
|
||||
private DataStructure locationStructure = new DataStructure((byte) 0,
|
||||
DataPrimitives.ADDRESS,
|
||||
DataPrimitives.ADDRESS,
|
||||
DataPrimitives.ADDRESS,
|
||||
DataPrimitives.INT);
|
||||
|
||||
private BinaryWriter writer;
|
||||
private WasmClassGenerator classGenerator;
|
||||
private WasmStringPool stringPool;
|
||||
|
||||
public CallSiteBinaryGenerator(BinaryWriter writer, WasmClassGenerator classGenerator) {
|
||||
public CallSiteBinaryGenerator(BinaryWriter writer, WasmClassGenerator classGenerator, WasmStringPool stringPool) {
|
||||
this.writer = writer;
|
||||
this.classGenerator = classGenerator;
|
||||
this.stringPool = stringPool;
|
||||
}
|
||||
|
||||
public int writeCallSites(List<CallSiteDescriptor> callSites) {
|
||||
|
@ -53,7 +69,7 @@ public class CallSiteBinaryGenerator {
|
|||
|
||||
int firstCallSite = -1;
|
||||
List<DataValue> binaryCallSites = new ArrayList<>();
|
||||
for (CallSiteDescriptor callSite : callSites) {
|
||||
for (int i = 0; i < callSites.size(); i++) {
|
||||
DataValue binaryCallSite = callSiteStructure.createValue();
|
||||
int address = writer.append(binaryCallSite);
|
||||
if (firstCallSite < 0) {
|
||||
|
@ -62,6 +78,8 @@ public class CallSiteBinaryGenerator {
|
|||
binaryCallSites.add(binaryCallSite);
|
||||
}
|
||||
|
||||
Map<CallSiteLocation, Integer> locationCache = new HashMap<>();
|
||||
|
||||
for (int callSiteId = 0; callSiteId < callSites.size(); ++callSiteId) {
|
||||
DataValue binaryCallSite = binaryCallSites.get(callSiteId);
|
||||
CallSiteDescriptor callSite = callSites.get(callSiteId);
|
||||
|
@ -91,6 +109,23 @@ public class CallSiteBinaryGenerator {
|
|||
binaryExceptionHandler.setAddress(EXCEPTION_HANDLER_CLASS, classPointer);
|
||||
}
|
||||
}
|
||||
|
||||
int locationAddress = locationCache.computeIfAbsent(callSite.getLocation(), location -> {
|
||||
DataValue binaryLocation = locationStructure.createValue();
|
||||
int address = writer.append(binaryLocation);
|
||||
if (location.getFileName() != null) {
|
||||
binaryLocation.setAddress(LOCATION_FILE, stringPool.getStringPointer(location.getFileName()));
|
||||
}
|
||||
if (location.getClassName() != null) {
|
||||
binaryLocation.setAddress(LOCATION_CLASS, stringPool.getStringPointer(location.getClassName()));
|
||||
}
|
||||
if (location.getMethodName() != null) {
|
||||
binaryLocation.setAddress(LOCATION_METHOD, stringPool.getStringPointer(location.getMethodName()));
|
||||
}
|
||||
binaryLocation.setInt(LOCATION_LINE_NUMBER, location.getLineNumber());
|
||||
return address;
|
||||
});
|
||||
binaryCallSite.setAddress(CALL_SITE_LOCATION, locationAddress);
|
||||
}
|
||||
|
||||
return firstCallSite;
|
||||
|
|
|
@ -57,6 +57,7 @@ public class WasmClassGenerator {
|
|||
private List<String> functionTable = new ArrayList<>();
|
||||
private VirtualTableProvider vtableProvider;
|
||||
private TagRegistry tagRegistry;
|
||||
private WasmStringPool stringPool;
|
||||
private DataStructure objectStructure = new DataStructure((byte) 0,
|
||||
DataPrimitives.INT, /* class */
|
||||
DataPrimitives.ADDRESS /* monitor/hash code */);
|
||||
|
@ -67,6 +68,7 @@ public class WasmClassGenerator {
|
|||
DataPrimitives.INT, /* flags */
|
||||
DataPrimitives.INT, /* tag */
|
||||
DataPrimitives.INT, /* canary */
|
||||
DataPrimitives.ADDRESS, /* name */
|
||||
DataPrimitives.ADDRESS, /* item type */
|
||||
DataPrimitives.ADDRESS, /* array type */
|
||||
DataPrimitives.INT, /* isInstance function */
|
||||
|
@ -79,11 +81,12 @@ public class WasmClassGenerator {
|
|||
private static final int CLASS_FLAGS = 2;
|
||||
private static final int CLASS_TAG = 3;
|
||||
private static final int CLASS_CANARY = 4;
|
||||
private static final int CLASS_ITEM_TYPE = 5;
|
||||
private static final int CLASS_ARRAY_TYPE = 6;
|
||||
private static final int CLASS_IS_INSTANCE = 7;
|
||||
private static final int CLASS_PARENT = 8;
|
||||
private static final int CLASS_LAYOUT = 9;
|
||||
private static final int CLASS_NAME = 5;
|
||||
private static final int CLASS_ITEM_TYPE = 6;
|
||||
private static final int CLASS_ARRAY_TYPE = 7;
|
||||
private static final int CLASS_IS_INSTANCE = 8;
|
||||
private static final int CLASS_PARENT = 9;
|
||||
private static final int CLASS_LAYOUT = 10;
|
||||
|
||||
public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
|
||||
TagRegistry tagRegistry, BinaryWriter binaryWriter) {
|
||||
|
@ -91,6 +94,11 @@ public class WasmClassGenerator {
|
|||
this.vtableProvider = vtableProvider;
|
||||
this.tagRegistry = tagRegistry;
|
||||
this.binaryWriter = binaryWriter;
|
||||
this.stringPool = new WasmStringPool(this, binaryWriter);
|
||||
}
|
||||
|
||||
public WasmStringPool getStringPool() {
|
||||
return stringPool;
|
||||
}
|
||||
|
||||
private void addClass(ValueType type) {
|
||||
|
@ -204,6 +212,7 @@ public class WasmClassGenerator {
|
|||
int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
|
||||
header.setInt(CLASS_TAG, tag);
|
||||
header.setInt(CLASS_CANARY, RuntimeClass.computeCanary(occupiedSize, tag));
|
||||
header.setAddress(CLASS_NAME, stringPool.getStringPointer(name));
|
||||
header.setInt(CLASS_IS_INSTANCE, functionTable.size());
|
||||
functionTable.add(WasmMangling.mangleIsSupertype(ValueType.object(name)));
|
||||
header.setAddress(CLASS_PARENT, parentPtr);
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.teavm.ast.InvocationExpr;
|
|||
import org.teavm.backend.wasm.binary.BinaryWriter;
|
||||
import org.teavm.backend.wasm.generate.CallSiteBinaryGenerator;
|
||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||
import org.teavm.backend.wasm.generate.WasmStringPool;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||
|
@ -28,14 +29,18 @@ 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.lowlevel.CallSiteDescriptor;
|
||||
import org.teavm.runtime.CallSite;
|
||||
import org.teavm.runtime.ExceptionHandling;
|
||||
|
||||
public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
|
||||
private CallSiteBinaryGenerator callSiteBinaryGenerator;
|
||||
private WasmClassGenerator classGenerator;
|
||||
private List<WasmInt32Constant> constants = new ArrayList<>();
|
||||
|
||||
public ExceptionHandlingIntrinsic(BinaryWriter binaryWriter, WasmClassGenerator classGenerator) {
|
||||
callSiteBinaryGenerator = new CallSiteBinaryGenerator(binaryWriter, classGenerator);
|
||||
public ExceptionHandlingIntrinsic(BinaryWriter binaryWriter, WasmClassGenerator classGenerator,
|
||||
WasmStringPool stringPool) {
|
||||
callSiteBinaryGenerator = new CallSiteBinaryGenerator(binaryWriter, classGenerator, stringPool);
|
||||
this.classGenerator = classGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,9 +68,10 @@ public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
|
|||
constant.setLocation(invocation.getLocation());
|
||||
constants.add(constant);
|
||||
|
||||
int callSiteSize = classGenerator.getClassSize(CallSite.class.getName());
|
||||
WasmExpression id = manager.generate(invocation.getArguments().get(0));
|
||||
WasmExpression offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL,
|
||||
id, new WasmInt32Constant(3));
|
||||
WasmExpression offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.MUL,
|
||||
id, new WasmInt32Constant(callSiteSize));
|
||||
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, constant, offset);
|
||||
}
|
||||
|
|
|
@ -21,15 +21,21 @@ import java.util.List;
|
|||
public class CallSiteDescriptor {
|
||||
private int id;
|
||||
private List<ExceptionHandlerDescriptor> handlers = new ArrayList<>();
|
||||
private CallSiteLocation location;
|
||||
|
||||
public CallSiteDescriptor(int id) {
|
||||
public CallSiteDescriptor(int id, CallSiteLocation location) {
|
||||
this.id = id;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public CallSiteLocation getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public List<ExceptionHandlerDescriptor> getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2017 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.model.lowlevel;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class CallSiteLocation {
|
||||
private String fileName;
|
||||
private String className;
|
||||
private String methodName;
|
||||
private int lineNumber;
|
||||
|
||||
public CallSiteLocation(String fileName, String className, String methodName, int lineNumber) {
|
||||
this.fileName = fileName;
|
||||
this.className = className;
|
||||
this.methodName = methodName;
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof CallSiteLocation)) {
|
||||
return false;
|
||||
}
|
||||
CallSiteLocation other = (CallSiteLocation) obj;
|
||||
return Objects.equals(fileName, other.fileName) && Objects.equals(className, other.className)
|
||||
&& Objects.equals(methodName, other.methodName) && lineNumber == other.lineNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(fileName, className, methodName, lineNumber);
|
||||
}
|
||||
}
|
|
@ -190,7 +190,11 @@ public class ExceptionHandlingShadowStackContributor {
|
|||
}
|
||||
}
|
||||
|
||||
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size());
|
||||
String fileName = insn.getLocation() != null ? insn.getLocation().getFileName() : null;
|
||||
int lineNumber = insn.getLocation() != null ? insn.getLocation().getLine() : -1;
|
||||
CallSiteLocation location = new CallSiteLocation(fileName, method.getClassName(), method.getName(),
|
||||
lineNumber);
|
||||
CallSiteDescriptor callSite = new CallSiteDescriptor(callSites.size(), location);
|
||||
callSites.add(callSite);
|
||||
List<Instruction> pre = setLocation(getInstructionsBeforeCallSite(callSite), insn.getLocation());
|
||||
List<Instruction> post = getInstructionsAfterCallSite(block, next, callSite, currentJointSources);
|
||||
|
|
|
@ -24,4 +24,5 @@ import org.teavm.interop.Unmanaged;
|
|||
public class CallSite extends Structure {
|
||||
public int handlerCount;
|
||||
public ExceptionHandler firstHandler;
|
||||
public CallSiteLocation location;
|
||||
}
|
||||
|
|
25
core/src/main/java/org/teavm/runtime/CallSiteLocation.java
Normal file
25
core/src/main/java/org/teavm/runtime/CallSiteLocation.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2017 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.runtime;
|
||||
|
||||
import org.teavm.interop.Structure;
|
||||
|
||||
public class CallSiteLocation extends Structure {
|
||||
public String fileName;
|
||||
public String className;
|
||||
public String methodName;
|
||||
public int lineNumber;
|
||||
}
|
|
@ -21,7 +21,6 @@ import org.teavm.interop.StaticInit;
|
|||
import org.teavm.interop.Structure;
|
||||
import org.teavm.interop.Unmanaged;
|
||||
|
||||
@Unmanaged
|
||||
@StaticInit
|
||||
public final class ExceptionHandling {
|
||||
private ExceptionHandling() {
|
||||
|
@ -32,12 +31,14 @@ public final class ExceptionHandling {
|
|||
private static Throwable thrownException;
|
||||
|
||||
@Export(name = "sys$catchException")
|
||||
@Unmanaged
|
||||
public static Throwable catchException() {
|
||||
Throwable exception = thrownException;
|
||||
thrownException = null;
|
||||
return exception;
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void throwException(Throwable exception) {
|
||||
thrownException = exception;
|
||||
|
||||
|
@ -64,4 +65,41 @@ public final class ExceptionHandling {
|
|||
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
||||
}
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static int callStackSize() {
|
||||
Address stackFrame = ShadowStack.getStackTop();
|
||||
int size = 0;
|
||||
while (stackFrame != null) {
|
||||
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
||||
size++;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static void fillStackTrace(StackTraceElement[] target, int skip) {
|
||||
Address stackFrame = ShadowStack.getNextStackFrame(ShadowStack.getNextStackFrame(ShadowStack.getStackTop()));
|
||||
int index = 0;
|
||||
while (stackFrame != null && index < target.length) {
|
||||
int callSiteId = ShadowStack.getCallSiteId(stackFrame);
|
||||
CallSite callSite = findCallSiteById(callSiteId);
|
||||
CallSiteLocation location = callSite.location;
|
||||
StackTraceElement element = createElement(location != null ? location.className : "",
|
||||
location != null ? location.methodName : "", location != null ? location.fileName : null,
|
||||
location != null ? location.lineNumber : -1);
|
||||
if (skip > 0) {
|
||||
skip--;
|
||||
} else {
|
||||
target[index++] = element;
|
||||
}
|
||||
|
||||
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
||||
}
|
||||
}
|
||||
|
||||
private static StackTraceElement createElement(String className, String methodName, String fileName,
|
||||
int lineNumber) {
|
||||
return new StackTraceElement(className, methodName, fileName, lineNumber);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ public class RuntimeClass extends RuntimeJavaObject {
|
|||
public int flags;
|
||||
public int tag;
|
||||
public int canary;
|
||||
public RuntimeJavaObject name;
|
||||
public RuntimeClass itemType;
|
||||
public RuntimeClass arrayType;
|
||||
public IsSupertypeFunction isSupertypeOf;
|
||||
|
|
|
@ -172,7 +172,6 @@ public final class Platform {
|
|||
return cls.itemType;
|
||||
}
|
||||
|
||||
@DelegateTo("getNameLowLevel")
|
||||
public static String getName(PlatformClass cls) {
|
||||
return cls.getMetadata().getName();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user