C/Wasm: fix bugs in GC

This commit is contained in:
Alexey Andreev 2019-10-22 19:05:37 +03:00
parent 70cb67c8f0
commit f7620704fc
9 changed files with 153 additions and 26 deletions

View File

@ -1077,10 +1077,7 @@ public class ClassGenerator {
public static boolean needsVirtualTable(Characteristics characteristics, ValueType type) { public static boolean needsVirtualTable(Characteristics characteristics, ValueType type) {
if (type instanceof ValueType.Object) { if (type instanceof ValueType.Object) {
String className = ((ValueType.Object) type).getClassName(); String className = ((ValueType.Object) type).getClassName();
if (className.equals(Address.class.getName())) { return characteristics.isManaged(className);
return false;
}
return !characteristics.isStructure(className);
} else if (type instanceof ValueType.Array) { } else if (type instanceof ValueType.Array) {
return needsVirtualTable(characteristics, ((ValueType.Array) type).getItemType()); return needsVirtualTable(characteristics, ((ValueType.Array) type).getItemType());
} else { } else {

View File

@ -95,8 +95,14 @@ public final class CodeGeneratorUtil {
} else if (value instanceof Character) { } else if (value instanceof Character) {
writeIntValue(writer, (char) value); writeIntValue(writer, (char) value);
} else if (value instanceof ValueType) { } else if (value instanceof ValueType) {
includes.includeType((ValueType) value); ValueType type = (ValueType) value;
writer.print("&").print(context.getNames().forClassInstance((ValueType) value)); if (type instanceof ValueType.Object
&& !context.getCharacteristics().isManaged(((ValueType.Object) type).getClassName())) {
writer.print("NULL");
} else {
includes.includeType(type);
writer.print("&").print(context.getNames().forClassInstance(type));
}
} }
} }

View File

@ -28,6 +28,8 @@ public class MutatorIntrinsic implements Intrinsic {
switch (method.getName()) { switch (method.getName()) {
case "getStaticGCRoots": case "getStaticGCRoots":
case "getClasses":
case "getClassCount":
return true; return true;
default: default:
return false; return false;
@ -40,6 +42,12 @@ public class MutatorIntrinsic implements Intrinsic {
case "getStaticGCRoots": case "getStaticGCRoots":
context.writer().print("teavm_gc_staticRoots"); context.writer().print("teavm_gc_staticRoots");
break; break;
case "getClasses":
context.writer().print("teavm_classReferences");
break;
case "getClassCount":
context.writer().print("teavm_classReferencesCount");
break;
} }
} }
} }

View File

@ -403,6 +403,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
generateIsSupertypeFunctions(tagRegistry, module, classGenerator); generateIsSupertypeFunctions(tagRegistry, module, classGenerator);
classGenerator.postProcess(); classGenerator.postProcess();
mutatorIntrinsic.setStaticGcRootsAddress(classGenerator.getStaticGcRootsAddress()); mutatorIntrinsic.setStaticGcRootsAddress(classGenerator.getStaticGcRootsAddress());
mutatorIntrinsic.setClassesAddress(classGenerator.getClassesAddress());
mutatorIntrinsic.setClassCount(classGenerator.getClassCount());
WasmMemorySegment dataSegment = new WasmMemorySegment(); WasmMemorySegment dataSegment = new WasmMemorySegment();
dataSegment.setData(binaryWriter.getData()); dataSegment.setData(binaryWriter.getData());

View File

@ -88,6 +88,8 @@ public class WasmClassGenerator {
DataPrimitives.ADDRESS /* canonical name cache */); DataPrimitives.ADDRESS /* canonical name cache */);
private IntegerArray staticGcRoots = new IntegerArray(1); private IntegerArray staticGcRoots = new IntegerArray(1);
private int staticGcRootsAddress; private int staticGcRootsAddress;
private int classesAddress;
private int classCount;
private static final int CLASS_SIZE = 1; private static final int CLASS_SIZE = 1;
private static final int CLASS_FLAGS = 2; private static final int CLASS_FLAGS = 2;
@ -618,12 +620,21 @@ public class WasmClassGenerator {
} }
} }
writeStaticGcRoots(); writeStaticGcRoots();
writeClasses();
} }
public int getStaticGcRootsAddress() { public int getStaticGcRootsAddress() {
return staticGcRootsAddress; return staticGcRootsAddress;
} }
public int getClassesAddress() {
return classesAddress;
}
public int getClassCount() {
return classCount;
}
private void writeStaticGcRoots() { private void writeStaticGcRoots() {
DataValue sizeValue = DataPrimitives.LONG.createValue(); DataValue sizeValue = DataPrimitives.LONG.createValue();
sizeValue.setLong(0, staticGcRoots.size()); sizeValue.setLong(0, staticGcRoots.size());
@ -635,6 +646,21 @@ public class WasmClassGenerator {
} }
} }
private void writeClasses() {
for (ClassBinaryData cls : binaryDataMap.values()) {
if (cls.start < 0) {
continue;
}
DataValue value = DataPrimitives.ADDRESS.createValue();
value.setAddress(0, cls.start);
int address = binaryWriter.append(value);
if (classesAddress == 0) {
classesAddress = address;
}
++classCount;
}
}
public boolean hasClinit(String className) { public boolean hasClinit(String className) {
if (isStructure(className) || className.equals(Address.class.getName())) { if (isStructure(className) || className.equals(Address.class.getName())) {
return false; return false;

View File

@ -25,6 +25,8 @@ import org.teavm.runtime.Mutator;
public class MutatorIntrinsic implements WasmIntrinsic { public class MutatorIntrinsic implements WasmIntrinsic {
private List<WasmInt32Constant> staticGcRootsExpressions = new ArrayList<>(); private List<WasmInt32Constant> staticGcRootsExpressions = new ArrayList<>();
private List<WasmInt32Constant> classesExpressions = new ArrayList<>();
private List<WasmInt32Constant> classCountExpressions = new ArrayList<>();
public void setStaticGcRootsAddress(int address) { public void setStaticGcRootsAddress(int address) {
for (WasmInt32Constant constant : staticGcRootsExpressions) { for (WasmInt32Constant constant : staticGcRootsExpressions) {
@ -32,6 +34,18 @@ public class MutatorIntrinsic implements WasmIntrinsic {
} }
} }
public void setClassesAddress(int address) {
for (WasmInt32Constant constant : classesExpressions) {
constant.setValue(address);
}
}
public void setClassCount(int count) {
for (WasmInt32Constant constant : classCountExpressions) {
constant.setValue(count);
}
}
@Override @Override
public boolean isApplicable(MethodReference methodReference) { public boolean isApplicable(MethodReference methodReference) {
if (!methodReference.getClassName().equals(Mutator.class.getName())) { if (!methodReference.getClassName().equals(Mutator.class.getName())) {
@ -39,6 +53,8 @@ public class MutatorIntrinsic implements WasmIntrinsic {
} }
switch (methodReference.getName()) { switch (methodReference.getName()) {
case "getStaticGCRoots": case "getStaticGCRoots":
case "getClasses":
case "getClassCount":
return true; return true;
default: default:
return false; return false;
@ -53,6 +69,16 @@ public class MutatorIntrinsic implements WasmIntrinsic {
staticGcRootsExpressions.add(constant); staticGcRootsExpressions.add(constant);
return constant; return constant;
} }
case "getClasses": {
WasmInt32Constant constant = new WasmInt32Constant(0);
classesExpressions.add(constant);
return constant;
}
case "getClassCount": {
WasmInt32Constant constant = new WasmInt32Constant(0);
classCountExpressions.add(constant);
return constant;
}
} }
throw new IllegalArgumentException(invocation.getMethod().toString()); throw new IllegalArgumentException(invocation.getMethod().toString());
} }

View File

@ -40,18 +40,14 @@ import org.teavm.model.MethodReference;
import org.teavm.model.Phi; import org.teavm.model.Phi;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.Variable; import org.teavm.model.Variable;
import org.teavm.model.instructions.CloneArrayInstruction; import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.ConstructArrayInstruction; import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.ConstructInstruction;
import org.teavm.model.instructions.ConstructMultiArrayInstruction;
import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.IntegerConstantInstruction; import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.MonitorEnterInstruction;
import org.teavm.model.instructions.MonitorExitInstruction;
import org.teavm.model.instructions.NullCheckInstruction; import org.teavm.model.instructions.NullCheckInstruction;
import org.teavm.model.instructions.RaiseInstruction; import org.teavm.model.instructions.NullConstantInstruction;
import org.teavm.model.instructions.StringConstantInstruction;
import org.teavm.model.util.DefinitionExtractor; import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.GraphColorer; import org.teavm.model.util.GraphColorer;
import org.teavm.model.util.LivenessAnalyzer; import org.teavm.model.util.LivenessAnalyzer;
@ -128,6 +124,7 @@ public class GCShadowStackContributor {
private List<Map<Instruction, BitSet>> findCallSiteLiveIns(Program program, MethodReader method) { private List<Map<Instruction, BitSet>> findCallSiteLiveIns(Program program, MethodReader method) {
boolean[] nativePointers = nativePointerFinder.findNativePointers(method.getReference(), program); boolean[] nativePointers = nativePointerFinder.findNativePointers(method.getReference(), program);
BitSet constants = findConstantRefVariables(program);
TypeInferer typeInferer = new TypeInferer(); TypeInferer typeInferer = new TypeInferer();
typeInferer.inferTypes(program, method.getReference()); typeInferer.inferTypes(program, method.getReference());
@ -153,20 +150,10 @@ public class GCShadowStackContributor {
for (Variable definedVar : defExtractor.getDefinedVariables()) { for (Variable definedVar : defExtractor.getDefinedVariables()) {
currentLiveOut.clear(definedVar.getIndex()); currentLiveOut.clear(definedVar.getIndex());
} }
if (insn instanceof InvokeInstruction || insn instanceof InitClassInstruction if (ExceptionHandlingShadowStackContributor.isCallInstruction(characteristics, insn)) {
|| insn instanceof ConstructInstruction || insn instanceof ConstructArrayInstruction
|| insn instanceof ConstructMultiArrayInstruction
|| insn instanceof CloneArrayInstruction || insn instanceof RaiseInstruction
|| insn instanceof NullCheckInstruction
|| insn instanceof MonitorEnterInstruction || insn instanceof MonitorExitInstruction) {
if (insn instanceof InvokeInstruction
&& !characteristics.isManaged(((InvokeInstruction) insn).getMethod())) {
continue;
}
BitSet csLiveIn = (BitSet) currentLiveOut.clone(); BitSet csLiveIn = (BitSet) currentLiveOut.clone();
for (int v = csLiveIn.nextSetBit(0); v >= 0; v = csLiveIn.nextSetBit(v + 1)) { for (int v = csLiveIn.nextSetBit(0); v >= 0; v = csLiveIn.nextSetBit(v + 1)) {
if (!isReference(typeInferer, v) || nativePointers[v]) { if (!isReference(typeInferer, v) || nativePointers[v] || constants.get(v)) {
csLiveIn.clear(v); csLiveIn.clear(v);
} }
} }
@ -410,4 +397,46 @@ public class GCShadowStackContributor {
return false; return false;
} }
} }
private BitSet findConstantRefVariables(Program program) {
BitSet constantClasses = new BitSet();
DisjointSet classes = new DisjointSet();
for (int i = 0; i < program.variableCount(); ++i) {
classes.create();
}
for (BasicBlock block : program.getBasicBlocks()) {
for (Instruction instruction : block) {
Variable variable;
if (instruction instanceof ClassConstantInstruction) {
variable = ((ClassConstantInstruction) instruction).getReceiver();
} else if (instruction instanceof StringConstantInstruction) {
variable = ((StringConstantInstruction) instruction).getReceiver();
} else if (instruction instanceof NullConstantInstruction) {
variable = ((NullConstantInstruction) instruction).getReceiver();
} else if (instruction instanceof AssignInstruction) {
AssignInstruction assign = (AssignInstruction) instruction;
boolean wasConstant = constantClasses.get(classes.find(assign.getAssignee().getIndex()));
int newClass = classes.union(assign.getAssignee().getIndex(), assign.getReceiver().getIndex());
if (wasConstant) {
constantClasses.set(newClass);
}
continue;
} else {
continue;
}
constantClasses.set(classes.find(variable.getIndex()));
}
}
BitSet result = new BitSet();
for (int i = 0; i < program.variableCount(); ++i) {
if (constantClasses.get(classes.find(i))) {
result.set(i);
}
}
return result;
}
} }

View File

@ -198,6 +198,19 @@ public final class GC {
staticRoots = staticRoots.add(Address.sizeOf()); staticRoots = staticRoots.add(Address.sizeOf());
} }
int classCount = Mutator.getClassCount();
Address classPtr = Mutator.getClasses();
for (int i = 0; i < classCount; ++i) {
RuntimeClass cls = classPtr.getAddress().toStructure();
if (cls.simpleNameCache != null) {
mark(cls.simpleNameCache);
}
if (cls.canonicalName != null) {
mark(cls.canonicalName);
}
classPtr = classPtr.add(Address.sizeOf());
}
for (Address stackRoots = ShadowStack.getStackTop(); stackRoots != null; for (Address stackRoots = ShadowStack.getStackTop(); stackRoots != null;
stackRoots = ShadowStack.getNextStackFrame(stackRoots)) { stackRoots = ShadowStack.getNextStackFrame(stackRoots)) {
int count = ShadowStack.getStackRootCount(stackRoots); int count = ShadowStack.getStackRootCount(stackRoots);
@ -414,6 +427,7 @@ public final class GC {
markStackRoots(); markStackRoots();
calculateRelocationTargets(); calculateRelocationTargets();
updatePointersFromStaticRoots(); updatePointersFromStaticRoots();
updatePointersFromClasses();
updatePointersFromObjects(); updatePointersFromObjects();
restoreObjectHeaders(); restoreObjectHeaders();
relocateObjects(); relocateObjects();
@ -557,6 +571,21 @@ public final class GC {
} }
} }
private static void updatePointersFromClasses() {
int classCount = Mutator.getClassCount();
Address classPtr = Mutator.getClasses();
for (int i = 0; i < classCount; ++i) {
RuntimeClass cls = classPtr.getAddress().toStructure();
if (cls.simpleNameCache != null) {
cls.simpleNameCache = updatePointer(cls.simpleNameCache.toAddress()).toStructure();
}
if (cls.canonicalName != null) {
cls.canonicalName = updatePointer(cls.canonicalName.toAddress()).toStructure();
}
classPtr = classPtr.add(Address.sizeOf());
}
}
private static void updatePointersFromObjects() { private static void updatePointersFromObjects() {
Address start = heapAddress(); Address start = heapAddress();
long heapSize = availableBytes(); long heapSize = availableBytes();

View File

@ -26,4 +26,8 @@ public final class Mutator {
} }
public static native Address getStaticGCRoots(); public static native Address getStaticGCRoots();
public static native Address getClasses();
public static native int getClassCount();
} }