mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
C/Wasm: fix bugs in GC
This commit is contained in:
parent
70cb67c8f0
commit
f7620704fc
|
@ -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 {
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user