diff --git a/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java b/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java index fc0fb9f2d..fd09f18b9 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java @@ -1077,10 +1077,7 @@ public class ClassGenerator { public static boolean needsVirtualTable(Characteristics characteristics, ValueType type) { if (type instanceof ValueType.Object) { String className = ((ValueType.Object) type).getClassName(); - if (className.equals(Address.class.getName())) { - return false; - } - return !characteristics.isStructure(className); + return characteristics.isManaged(className); } else if (type instanceof ValueType.Array) { return needsVirtualTable(characteristics, ((ValueType.Array) type).getItemType()); } else { diff --git a/core/src/main/java/org/teavm/backend/c/generate/CodeGeneratorUtil.java b/core/src/main/java/org/teavm/backend/c/generate/CodeGeneratorUtil.java index dc85bd467..1315f52cc 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/CodeGeneratorUtil.java +++ b/core/src/main/java/org/teavm/backend/c/generate/CodeGeneratorUtil.java @@ -95,8 +95,14 @@ public final class CodeGeneratorUtil { } else if (value instanceof Character) { writeIntValue(writer, (char) value); } else if (value instanceof ValueType) { - includes.includeType((ValueType) value); - writer.print("&").print(context.getNames().forClassInstance((ValueType) value)); + ValueType type = (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)); + } } } diff --git a/core/src/main/java/org/teavm/backend/c/intrinsic/MutatorIntrinsic.java b/core/src/main/java/org/teavm/backend/c/intrinsic/MutatorIntrinsic.java index 87d792a4e..c3218df84 100644 --- a/core/src/main/java/org/teavm/backend/c/intrinsic/MutatorIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/c/intrinsic/MutatorIntrinsic.java @@ -28,6 +28,8 @@ public class MutatorIntrinsic implements Intrinsic { switch (method.getName()) { case "getStaticGCRoots": + case "getClasses": + case "getClassCount": return true; default: return false; @@ -40,6 +42,12 @@ public class MutatorIntrinsic implements Intrinsic { case "getStaticGCRoots": context.writer().print("teavm_gc_staticRoots"); break; + case "getClasses": + context.writer().print("teavm_classReferences"); + break; + case "getClassCount": + context.writer().print("teavm_classReferencesCount"); + break; } } } diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index eb8c757a9..43857d167 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -403,6 +403,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { generateIsSupertypeFunctions(tagRegistry, module, classGenerator); classGenerator.postProcess(); mutatorIntrinsic.setStaticGcRootsAddress(classGenerator.getStaticGcRootsAddress()); + mutatorIntrinsic.setClassesAddress(classGenerator.getClassesAddress()); + mutatorIntrinsic.setClassCount(classGenerator.getClassCount()); WasmMemorySegment dataSegment = new WasmMemorySegment(); dataSegment.setData(binaryWriter.getData()); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java index cda4b7676..3859c37ef 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java @@ -88,6 +88,8 @@ public class WasmClassGenerator { DataPrimitives.ADDRESS /* canonical name cache */); private IntegerArray staticGcRoots = new IntegerArray(1); private int staticGcRootsAddress; + private int classesAddress; + private int classCount; private static final int CLASS_SIZE = 1; private static final int CLASS_FLAGS = 2; @@ -618,12 +620,21 @@ public class WasmClassGenerator { } } writeStaticGcRoots(); + writeClasses(); } public int getStaticGcRootsAddress() { return staticGcRootsAddress; } + public int getClassesAddress() { + return classesAddress; + } + + public int getClassCount() { + return classCount; + } + private void writeStaticGcRoots() { DataValue sizeValue = DataPrimitives.LONG.createValue(); 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) { if (isStructure(className) || className.equals(Address.class.getName())) { return false; diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/MutatorIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/MutatorIntrinsic.java index 67cec60e9..52e87390e 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/MutatorIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/MutatorIntrinsic.java @@ -25,6 +25,8 @@ import org.teavm.runtime.Mutator; public class MutatorIntrinsic implements WasmIntrinsic { private List staticGcRootsExpressions = new ArrayList<>(); + private List classesExpressions = new ArrayList<>(); + private List classCountExpressions = new ArrayList<>(); public void setStaticGcRootsAddress(int address) { 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 public boolean isApplicable(MethodReference methodReference) { if (!methodReference.getClassName().equals(Mutator.class.getName())) { @@ -39,6 +53,8 @@ public class MutatorIntrinsic implements WasmIntrinsic { } switch (methodReference.getName()) { case "getStaticGCRoots": + case "getClasses": + case "getClassCount": return true; default: return false; @@ -53,6 +69,16 @@ public class MutatorIntrinsic implements WasmIntrinsic { staticGcRootsExpressions.add(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()); } diff --git a/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java b/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java index 39bd05a91..988d0fa96 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java +++ b/core/src/main/java/org/teavm/model/lowlevel/GCShadowStackContributor.java @@ -40,18 +40,14 @@ import org.teavm.model.MethodReference; import org.teavm.model.Phi; import org.teavm.model.Program; import org.teavm.model.Variable; -import org.teavm.model.instructions.CloneArrayInstruction; -import org.teavm.model.instructions.ConstructArrayInstruction; -import org.teavm.model.instructions.ConstructInstruction; -import org.teavm.model.instructions.ConstructMultiArrayInstruction; -import org.teavm.model.instructions.InitClassInstruction; +import org.teavm.model.instructions.AssignInstruction; +import org.teavm.model.instructions.ClassConstantInstruction; import org.teavm.model.instructions.IntegerConstantInstruction; import org.teavm.model.instructions.InvocationType; 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.RaiseInstruction; +import org.teavm.model.instructions.NullConstantInstruction; +import org.teavm.model.instructions.StringConstantInstruction; import org.teavm.model.util.DefinitionExtractor; import org.teavm.model.util.GraphColorer; import org.teavm.model.util.LivenessAnalyzer; @@ -128,6 +124,7 @@ public class GCShadowStackContributor { private List> findCallSiteLiveIns(Program program, MethodReader method) { boolean[] nativePointers = nativePointerFinder.findNativePointers(method.getReference(), program); + BitSet constants = findConstantRefVariables(program); TypeInferer typeInferer = new TypeInferer(); typeInferer.inferTypes(program, method.getReference()); @@ -153,20 +150,10 @@ public class GCShadowStackContributor { for (Variable definedVar : defExtractor.getDefinedVariables()) { currentLiveOut.clear(definedVar.getIndex()); } - if (insn instanceof InvokeInstruction || insn instanceof InitClassInstruction - || 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; - } - + if (ExceptionHandlingShadowStackContributor.isCallInstruction(characteristics, insn)) { BitSet csLiveIn = (BitSet) currentLiveOut.clone(); 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); } } @@ -410,4 +397,46 @@ public class GCShadowStackContributor { 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; + } } diff --git a/core/src/main/java/org/teavm/runtime/GC.java b/core/src/main/java/org/teavm/runtime/GC.java index 960429d70..acd9644b5 100644 --- a/core/src/main/java/org/teavm/runtime/GC.java +++ b/core/src/main/java/org/teavm/runtime/GC.java @@ -198,6 +198,19 @@ public final class GC { 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; stackRoots = ShadowStack.getNextStackFrame(stackRoots)) { int count = ShadowStack.getStackRootCount(stackRoots); @@ -414,6 +427,7 @@ public final class GC { markStackRoots(); calculateRelocationTargets(); updatePointersFromStaticRoots(); + updatePointersFromClasses(); updatePointersFromObjects(); restoreObjectHeaders(); 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() { Address start = heapAddress(); long heapSize = availableBytes(); diff --git a/core/src/main/java/org/teavm/runtime/Mutator.java b/core/src/main/java/org/teavm/runtime/Mutator.java index cc512a00e..ad99e5955 100644 --- a/core/src/main/java/org/teavm/runtime/Mutator.java +++ b/core/src/main/java/org/teavm/runtime/Mutator.java @@ -26,4 +26,8 @@ public final class Mutator { } public static native Address getStaticGCRoots(); + + public static native Address getClasses(); + + public static native int getClassCount(); }