WASM: refactoring shadow stack

This commit is contained in:
Alexey Andreev 2016-09-22 19:02:53 +03:00
parent b67d243ad4
commit 4e431e2f77
12 changed files with 128 additions and 123 deletions

View File

@ -250,11 +250,11 @@ public final class WasmRuntime {
return result;
}
public static Address getStackGcRoots() {
public static Address getStackTop() {
return stack != initStack() ? stack : null;
}
public static Address getNextStackRoots(Address address) {
public static Address getNextStackFrame(Address address) {
int size = address.getInt() + 2;
Address result = address.add(-size * 4);
if (result == initStack()) {

View File

@ -38,12 +38,13 @@ 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.MutatorIntrinsic;
import org.teavm.backend.wasm.intrinsics.PlatformClassIntrinsic;
import org.teavm.backend.wasm.intrinsics.PlatformIntrinsic;
import org.teavm.backend.wasm.intrinsics.PlatformObjectIntrinsic;
import org.teavm.backend.wasm.intrinsics.ShadowStackIntrinsic;
import org.teavm.backend.wasm.intrinsics.StructureIntrinsic;
import org.teavm.backend.wasm.intrinsics.WasmRuntimeIntrinsic;
import org.teavm.backend.wasm.model.WasmFunction;
@ -105,7 +106,6 @@ import org.teavm.model.instructions.CloneArrayInstruction;
import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.MutatorIntrinsic;
import org.teavm.model.lowlevel.ClassInitializerEliminator;
import org.teavm.model.lowlevel.ClassInitializerTransformer;
import org.teavm.model.lowlevel.ShadowStackTransformer;
@ -206,9 +206,9 @@ public class WasmTarget implements TeaVMTarget {
Address.class, int.class, void.class), null).use();
dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "allocStack",
int.class, Address.class), null).use();
dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "getStackGcRoots", Address.class),
dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "getStackTop", Address.class),
null) .use();
dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "getNextStackRoots", Address.class,
dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "getNextStackFrame", Address.class,
Address.class), null).use();
dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "getStackRootCount", Address.class,
int.class), null).use();
@ -294,7 +294,7 @@ public class WasmTarget implements TeaVMTarget {
context.addIntrinsic(gcIntrinsic);
MutatorIntrinsic mutatorIntrinsic = new MutatorIntrinsic();
context.addIntrinsic(mutatorIntrinsic);
context.addIntrinsic(new ExceptionHandlingIntrinsic());
context.addIntrinsic(new ShadowStackIntrinsic());
WasmGenerator generator = new WasmGenerator(decompiler, classes,
context, classGenerator);

View File

@ -113,10 +113,9 @@ 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;
import org.teavm.runtime.ShadowStack;
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private static FieldReference tagField = new FieldReference(RuntimeClass.class.getName(), "tag");
@ -783,7 +782,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
@Override
public void visit(InvocationExpr expr) {
if (expr.getMethod().getClassName().equals(Mutator.class.getName())) {
if (expr.getMethod().getClassName().equals(ShadowStack.class.getName())) {
switch (expr.getMethod().getName()) {
case "allocStack":
generateAllocStack(expr.getArguments().get(0));
@ -791,19 +790,16 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
case "releaseStack":
generateReleaseStack();
return;
case "registerGcRoot":
case "registerGCRoot":
generateRegisterGcRoot(expr.getArguments().get(0), expr.getArguments().get(1));
return;
case "removeGcRoot":
case "removeGCRoot":
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":
case "getExceptionHandlerId":
generateGetHandlerId();
return;
}
@ -896,7 +892,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private void generateAllocStack(Expr sizeExpr) {
if (stackVariable != null) {
throw new IllegalStateException("Call to Mutator.allocStack must be done only once");
throw new IllegalStateException("Call to ShadowStack.allocStack must be done only once");
}
stackVariable = getTemporary(WasmType.INT32);
stackVariable.setName("__stack__");
@ -911,7 +907,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private void generateReleaseStack() {
if (stackVariable == null) {
throw new IllegalStateException("Call to Mutator.releaseStack must be dominated by "
throw new IllegalStateException("Call to ShadowStack.releaseStack must be dominated by "
+ "Mutator.allocStack");
}
@ -924,7 +920,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private void generateRegisterCallSite(Expr callSiteExpr) {
if (stackVariable == null) {
throw new IllegalStateException("Call to ExceptionHandling.registerCallSite must be dominated by "
throw new IllegalStateException("Call to ShadowStack.registerCallSite must be dominated by "
+ "Mutator.allocStack");
}
@ -936,7 +932,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private void generateGetHandlerId() {
if (stackVariable == null) {
throw new IllegalStateException("Call to ExceptionHandling.getHandlerId must be dominated by "
throw new IllegalStateException("Call to ShadowStack.getHandlerId must be dominated by "
+ "Mutator.allocStack");
}
@ -945,7 +941,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private void generateRegisterGcRoot(Expr slotExpr, Expr gcRootExpr) {
if (stackVariable == null) {
throw new IllegalStateException("Call to Mutator.registerGcRoot must be dominated by "
throw new IllegalStateException("Call to ShadowStack.registerGCRoot must be dominated by "
+ "Mutator.allocStack");
}
@ -962,7 +958,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private void generateRemoveGcRoot(Expr slotExpr) {
if (stackVariable == null) {
throw new IllegalStateException("Call to Mutator.removeGcRoot must be dominated by "
throw new IllegalStateException("Call to ShadowStack.removeGCRoot must be dominated by "
+ "Mutator.allocStack");
}

View File

@ -13,15 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.model.instructions;
package org.teavm.backend.wasm.intrinsics;
import java.util.ArrayList;
import java.util.List;
import org.teavm.ast.*;
import org.teavm.ast.InvocationType;
import org.teavm.backend.wasm.WasmRuntime;
import org.teavm.backend.wasm.intrinsics.WasmIntrinsic;
import org.teavm.backend.wasm.intrinsics.WasmIntrinsicManager;
import org.teavm.ast.InvocationExpr;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
import org.teavm.model.MethodReference;
@ -30,46 +26,34 @@ import org.teavm.runtime.Mutator;
public class MutatorIntrinsic implements WasmIntrinsic {
private List<WasmInt32Constant> staticGcRootsExpressions = new ArrayList<>();
@Override
public boolean isApplicable(MethodReference methodReference) {
if (!methodReference.getClassName().equals(Mutator.class.getName())) {
return false;
}
switch (methodReference.getName()) {
case "getStaticGcRoots":
case "getStackGcRoots":
case "getNextStackRoots":
case "getStackRootCount":
case "getStackRootPointer":
return true;
default:
return false;
}
}
public void setStaticGcRootsAddress(int address) {
for (WasmInt32Constant constant : staticGcRootsExpressions) {
constant.setValue(address);
}
}
@Override
public boolean isApplicable(MethodReference methodReference) {
if (!methodReference.getClassName().equals(Mutator.class.getName())) {
return false;
}
switch (methodReference.getName()) {
case "getStaticGCRoots":
return true;
default:
return false;
}
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
switch (invocation.getMethod().getName()) {
case "getStaticGcRoots": {
case "getStaticGCRoots": {
WasmInt32Constant constant = new WasmInt32Constant(0);
staticGcRootsExpressions.add(constant);
return constant;
}
default: {
InvocationExpr expr = new InvocationExpr();
MethodReference method = new MethodReference(WasmRuntime.class.getName(),
invocation.getMethod().getDescriptor());
expr.setMethod(method);
expr.setType(InvocationType.SPECIAL);
expr.getArguments().addAll(invocation.getArguments());
return manager.generate(expr);
}
}
throw new IllegalArgumentException(invocation.getMethod().toString());
}
}

View File

@ -16,33 +16,37 @@
package org.teavm.backend.wasm.intrinsics;
import org.teavm.ast.InvocationExpr;
import org.teavm.ast.InvocationType;
import org.teavm.backend.wasm.WasmRuntime;
import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.model.MethodReference;
import org.teavm.runtime.ExceptionHandling;
import org.teavm.runtime.ShadowStack;
public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
public class ShadowStackIntrinsic implements WasmIntrinsic {
@Override
public boolean isApplicable(MethodReference methodReference) {
if (!methodReference.getClassName().equals(ExceptionHandling.class.getName())) {
if (!methodReference.getClassName().equals(ShadowStack.class.getName())) {
return false;
}
switch (methodReference.getName()) {
case "registerCallSite":
case "getHandlerId":
case "getStackTop":
case "getNextStackFrame":
case "getStackRootCount":
case "getStackRootPointer":
return true;
default:
return false;
}
return false;
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
switch (invocation.getMethod().getName()) {
case "registerCallSite":
break;
}
throw new IllegalArgumentException(invocation.getMethod().toString());
InvocationExpr expr = new InvocationExpr();
MethodReference method = new MethodReference(WasmRuntime.class.getName(),
invocation.getMethod().getDescriptor());
expr.setMethod(method);
expr.setType(InvocationType.SPECIAL);
expr.getArguments().addAll(invocation.getArguments());
return manager.generate(expr);
}
}

View File

@ -50,6 +50,7 @@ import org.teavm.model.instructions.SwitchTableEntry;
import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.ProgramUtils;
import org.teavm.runtime.ExceptionHandling;
import org.teavm.runtime.ShadowStack;
public class ExceptionHandlingShadowStackContributor {
private ManagedMethodRepository managedMethodRepository;
@ -194,8 +195,7 @@ public class ExceptionHandlingShadowStackContributor {
instructions.add(idInsn);
InvokeInstruction registerInsn = new InvokeInstruction();
registerInsn.setMethod(new MethodReference(ExceptionHandling.class, "registerCallSite",
int.class, void.class));
registerInsn.setMethod(new MethodReference(ShadowStack.class, "registerCallSite", int.class, void.class));
registerInsn.setType(InvocationType.SPECIAL);
registerInsn.getArguments().add(idVariable);
instructions.add(registerInsn);
@ -219,7 +219,7 @@ public class ExceptionHandlingShadowStackContributor {
Variable handlerIdVariable = program.createVariable();
InvokeInstruction getHandlerIdInsn = new InvokeInstruction();
getHandlerIdInsn.setMethod(new MethodReference(ExceptionHandling.class, "getHandlerId", int.class));
getHandlerIdInsn.setMethod(new MethodReference(ShadowStack.class, "getExceptionHandlerId", int.class));
getHandlerIdInsn.setType(InvocationType.SPECIAL);
getHandlerIdInsn.setReceiver(handlerIdVariable);
instructions.add(getHandlerIdInsn);

View File

@ -53,7 +53,7 @@ import org.teavm.model.util.ProgramUtils;
import org.teavm.model.util.TypeInferer;
import org.teavm.model.util.UsageExtractor;
import org.teavm.model.util.VariableType;
import org.teavm.runtime.Mutator;
import org.teavm.runtime.ShadowStack;
public class GCShadowStackContributor {
private ManagedMethodRepository managedMethodRepository;
@ -92,9 +92,9 @@ public class GCShadowStackContributor {
findAutoSpilledPhis(spilled, destinationPhis, inputCount, autoSpilled, i);
}
List<IntObjectMap<int[]>> liveInStores = reduceGcRootStores(program, usedColors, liveInInformation,
List<IntObjectMap<int[]>> liveInStores = reduceGCRootStores(program, usedColors, liveInInformation,
colors, autoSpilled);
putLiveInGcRoots(program, liveInStores);
putLiveInGCRoots(program, liveInStores);
return usedColors;
}
@ -241,7 +241,7 @@ public class GCShadowStackContributor {
return inputCount;
}
private List<IntObjectMap<int[]>> reduceGcRootStores(Program program, int usedColors,
private List<IntObjectMap<int[]>> reduceGCRootStores(Program program, int usedColors,
List<IntObjectMap<BitSet>> liveInInformation, int[] colors, boolean[] autoSpilled) {
class Step {
private final int node;
@ -322,7 +322,7 @@ public class GCShadowStackContributor {
return comparison;
}
private void putLiveInGcRoots(Program program, List<IntObjectMap<int[]>> updateInformation) {
private void putLiveInGCRoots(Program program, List<IntObjectMap<int[]>> updateInformation) {
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
IntObjectMap<int[]> updatesByIndex = updateInformation.get(i);
@ -359,11 +359,11 @@ public class GCShadowStackContributor {
registerInvocation.setType(InvocationType.SPECIAL);
registerInvocation.getArguments().add(slotVar);
if (var >= 0) {
registerInvocation.setMethod(new MethodReference(Mutator.class, "registerGcRoot", int.class,
registerInvocation.setMethod(new MethodReference(ShadowStack.class, "registerGCRoot", int.class,
Object.class, void.class));
registerInvocation.getArguments().add(program.variableAt(var));
} else {
registerInvocation.setMethod(new MethodReference(Mutator.class, "removeGcRoot", int.class,
registerInvocation.setMethod(new MethodReference(ShadowStack.class, "removeGCRoot", int.class,
void.class));
}
instructionsToAdd.add(registerInvocation);

View File

@ -31,7 +31,7 @@ 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;
import org.teavm.runtime.ShadowStack;
public class ShadowStackTransformer {
private ManagedMethodRepository managedMethodRepository;
@ -70,7 +70,7 @@ public class ShadowStackTransformer {
InvokeInstruction invocation = new InvokeInstruction();
invocation.setType(InvocationType.SPECIAL);
invocation.setMethod(new MethodReference(Mutator.class, "allocStack", int.class, void.class));
invocation.setMethod(new MethodReference(ShadowStack.class, "allocStack", int.class, void.class));
invocation.getArguments().add(sizeVariable);
instructionsToAdd.add(invocation);
@ -135,7 +135,7 @@ public class ShadowStackTransformer {
InvokeInstruction invocation = new InvokeInstruction();
invocation.setType(InvocationType.SPECIAL);
invocation.setMethod(new MethodReference(Mutator.class, "releaseStack", int.class, void.class));
invocation.setMethod(new MethodReference(ShadowStack.class, "releaseStack", int.class, void.class));
invocation.getArguments().add(sizeVariable);
instructionsToAdd.add(invocation);

View File

@ -26,20 +26,6 @@ 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) {
@ -47,23 +33,23 @@ public final class ExceptionHandling {
RuntimeClass exceptionClass = RuntimeClass.getClass(exceptionPtr);
IsSupertypeFunction isExceptionSupertype = exceptionClass.isSupertypeOf;
Address stackFrame = getStackTop();
Address stackFrame = ShadowStack.getStackTop();
stackLoop: while (stackFrame != null) {
int callSiteId = getCallSiteId(stackFrame);
int callSiteId = ShadowStack.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);
ShadowStack.setExceptionHandlerId(stackFrame, handler.id);
break stackLoop;
}
handler = Structure.add(ExceptionHandler.class, handler, 1);
}
setHandlerId(stackFrame, callSiteId - 1);
stackFrame = getNextStackFrame(stackFrame);
ShadowStack.setExceptionHandlerId(stackFrame, callSiteId - 1);
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
}
}
}

View File

@ -109,7 +109,7 @@ public final class GC {
private static void mark() {
Allocator.fillZero(regionsAddress().toAddress(), regionMaxCount() * Structure.sizeOf(Region.class));
Address staticRoots = Mutator.getStaticGcRoots();
Address staticRoots = Mutator.getStaticGCRoots();
int staticCount = staticRoots.getInt();
staticRoots.add(8);
while (staticCount-- > 0) {
@ -120,10 +120,10 @@ public final class GC {
staticRoots = staticRoots.add(Address.sizeOf());
}
for (Address stackRoots = Mutator.getStackGcRoots(); stackRoots != null;
stackRoots = Mutator.getNextStackRoots(stackRoots)) {
int count = Mutator.getStackRootCount(stackRoots);
Address stackRootsPtr = Mutator.getStackRootPointer(stackRoots);
for (Address stackRoots = ShadowStack.getStackTop(); stackRoots != null;
stackRoots = ShadowStack.getNextStackFrame(stackRoots)) {
int count = ShadowStack.getStackRootCount(stackRoots);
Address stackRootsPtr = ShadowStack.getStackRootPointer(stackRoots);
while (count-- > 0) {
RuntimeObject obj = stackRootsPtr.getAddress().toStructure();
mark(obj);

View File

@ -25,21 +25,5 @@ public final class Mutator {
private Mutator() {
}
public static native void allocStack(int size);
public static native void registerGcRoot(int index, Object object);
public static native void removeGcRoot(int index);
public static native void releaseStack(int size);
public static native Address getStaticGcRoots();
public static native Address getStackGcRoots();
public static native Address getNextStackRoots(Address address);
public static native int getStackRootCount(Address address);
public static native Address getStackRootPointer(Address address);
public static native Address getStaticGCRoots();
}

View File

@ -0,0 +1,51 @@
/*
* 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.Unmanaged;
@Unmanaged
@StaticInit
public final class ShadowStack {
private ShadowStack() {
}
public static native void allocStack(int size);
public static native void registerGCRoot(int index, Object object);
public static native void removeGCRoot(int index);
public static native void releaseStack(int size);
public static native Address getStackTop();
public static native Address getNextStackFrame(Address stackFrame);
public static native int getStackRootCount(Address stackFrame);
public static native Address getStackRootPointer(Address stackFrame);
public static native int getCallSiteId(Address stackFrame);
public static native void registerCallSite(int id);
public static native int getExceptionHandlerId();
public static native void setExceptionHandlerId(Address stackFrame, int id);
}