mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
C: support weak references
This commit is contained in:
parent
4c50ed8714
commit
2eafb902f4
|
@ -17,11 +17,6 @@ package org.teavm.classlib.java.lang.ref;
|
|||
|
||||
import org.teavm.classlib.java.lang.TObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
* @param <T> type of an object to which this reference points.
|
||||
*/
|
||||
public abstract class TReference<T> extends TObject {
|
||||
public T get() {
|
||||
return null;
|
||||
|
|
|
@ -15,11 +15,6 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.lang.ref;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
* @param <T>
|
||||
*/
|
||||
public class TReferenceQueue<T> {
|
||||
public TReference<T> poll() {
|
||||
return null;
|
||||
|
|
|
@ -35,4 +35,14 @@ public class TWeakReference<T> extends TReference<T> {
|
|||
public void clear() {
|
||||
value = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnqueued() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enqueue() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ import org.teavm.backend.c.generate.StringPoolGenerator;
|
|||
import org.teavm.backend.c.generators.ArrayGenerator;
|
||||
import org.teavm.backend.c.generators.Generator;
|
||||
import org.teavm.backend.c.generators.GeneratorFactory;
|
||||
import org.teavm.backend.c.generators.ReferenceQueueGenerator;
|
||||
import org.teavm.backend.c.generators.WeakReferenceGenerator;
|
||||
import org.teavm.backend.c.intrinsic.AddressIntrinsic;
|
||||
import org.teavm.backend.c.intrinsic.AllocatorIntrinsic;
|
||||
import org.teavm.backend.c.intrinsic.ConsoleIntrinsic;
|
||||
|
@ -72,7 +74,9 @@ import org.teavm.backend.c.intrinsic.ShadowStackIntrinsic;
|
|||
import org.teavm.backend.c.intrinsic.StringsIntrinsic;
|
||||
import org.teavm.backend.c.intrinsic.StructureIntrinsic;
|
||||
import org.teavm.backend.lowlevel.dependency.ExceptionHandlingDependencyListener;
|
||||
import org.teavm.backend.lowlevel.dependency.WeakReferenceDependencyListener;
|
||||
import org.teavm.backend.lowlevel.transform.CoroutineTransformation;
|
||||
import org.teavm.backend.lowlevel.transform.WeakReferenceTransformation;
|
||||
import org.teavm.dependency.ClassDependency;
|
||||
import org.teavm.dependency.DependencyAnalyzer;
|
||||
import org.teavm.dependency.DependencyListener;
|
||||
|
@ -163,12 +167,14 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
List<ClassHolderTransformer> transformers = new ArrayList<>();
|
||||
transformers.add(new ClassPatch());
|
||||
transformers.add(new CDependencyListener());
|
||||
transformers.add(new WeakReferenceTransformation());
|
||||
return transformers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DependencyListener> getDependencyListeners() {
|
||||
return Arrays.asList(new CDependencyListener(), exportDependencyListener, new InteropDependencyListener());
|
||||
return Arrays.asList(new CDependencyListener(), exportDependencyListener, new InteropDependencyListener(),
|
||||
new WeakReferenceDependencyListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -323,6 +329,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
|
||||
List<Generator> generators = new ArrayList<>();
|
||||
generators.add(new ArrayGenerator());
|
||||
generators.add(new WeakReferenceGenerator());
|
||||
generators.add(new ReferenceQueueGenerator());
|
||||
|
||||
stringPool = new SimpleStringPool();
|
||||
GenerationContext context = new GenerationContext(vtableProvider, characteristics,
|
||||
|
@ -355,10 +363,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
generateSpecialFunctions(context, runtimeWriter);
|
||||
OutputFileUtil.write(runtimeWriter, "runtime.c", buildTarget);
|
||||
OutputFileUtil.write(runtimeHeaderWriter, "runtime.h", buildTarget);
|
||||
BufferedCodeWriter stringhashWriter = new BufferedCodeWriter(false);
|
||||
emitResource(stringhashWriter, "stringhash.c");
|
||||
OutputFileUtil.write(stringhashWriter, "stringhash.c", buildTarget);
|
||||
|
||||
copyResource("stringhash.c", buildTarget);
|
||||
copyResource("references.c", buildTarget);
|
||||
generateCallSites(buildTarget, context, classes.getClassNames());
|
||||
generateStrings(buildTarget, context);
|
||||
|
||||
|
@ -369,6 +375,12 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
generateAllFile(classes, types, buildTarget);
|
||||
}
|
||||
|
||||
private void copyResource(String name, BuildTarget buildTarget) throws IOException {
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter(false);
|
||||
emitResource(writer, name);
|
||||
OutputFileUtil.write(writer, name, buildTarget);
|
||||
}
|
||||
|
||||
private void emitResource(CodeWriter writer, String resourceName) {
|
||||
ClassLoader classLoader = CTarget.class.getClassLoader();
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
package org.teavm.backend.c.generate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -64,11 +66,15 @@ import org.teavm.runtime.CallSite;
|
|||
import org.teavm.runtime.RuntimeArray;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.runtime.RuntimeObject;
|
||||
import org.teavm.runtime.RuntimeReference;
|
||||
import org.teavm.runtime.RuntimeReferenceQueue;
|
||||
|
||||
public class ClassGenerator {
|
||||
private static final Set<String> classesWithDeclaredStructures = new HashSet<>(Arrays.asList(
|
||||
"java.lang.Object", "java.lang.String", "java.lang.Class",
|
||||
RuntimeArray.class.getName(), RuntimeClass.class.getName(), RuntimeObject.class.getName()
|
||||
RuntimeArray.class.getName(), RuntimeClass.class.getName(), RuntimeObject.class.getName(),
|
||||
WeakReference.class.getName(), ReferenceQueue.class.getName(),
|
||||
RuntimeReferenceQueue.class.getName(), RuntimeReference.class.getName()
|
||||
));
|
||||
|
||||
private GenerationContext context;
|
||||
|
@ -566,6 +572,15 @@ public class ClassGenerator {
|
|||
superinterfaces = sb.append(" }").toString();
|
||||
}
|
||||
|
||||
switch (className) {
|
||||
case "java.lang.ref.WeakReference":
|
||||
flags |= RuntimeClass.VM_TYPE_WEAKREFERENCE << RuntimeClass.VM_TYPE_SHIFT;
|
||||
break;
|
||||
case "java.lang.ref.ReferenceQueue":
|
||||
flags |= RuntimeClass.VM_TYPE_REFERENCEQUEUE << RuntimeClass.VM_TYPE_SHIFT;
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (type instanceof ValueType.Array) {
|
||||
includes.includeClass("java.lang.Object");
|
||||
parent = "(TeaVM_Class*) &" + context.getNames().forClassInstance(ValueType.object("java.lang.Object"));
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package org.teavm.backend.c.generate;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
@ -25,6 +27,8 @@ import org.teavm.model.FieldReference;
|
|||
import org.teavm.runtime.RuntimeArray;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
import org.teavm.runtime.RuntimeObject;
|
||||
import org.teavm.runtime.RuntimeReference;
|
||||
import org.teavm.runtime.RuntimeReferenceQueue;
|
||||
|
||||
public class NameProvider extends LowLevelNameProvider {
|
||||
private static final Set<? extends String> keywords = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
|
||||
|
@ -41,12 +45,18 @@ public class NameProvider extends LowLevelNameProvider {
|
|||
occupiedTopLevelNames.add("TeaVM_Array");
|
||||
occupiedTopLevelNames.add("TeaVM_String");
|
||||
occupiedTopLevelNames.add("TeaVM_Class");
|
||||
occupiedTopLevelNames.add("TeaVM_Reference");
|
||||
occupiedTopLevelNames.add("TeaVM_ReferenceQueue");
|
||||
|
||||
classNames.put(RuntimeObject.class.getName(), "TeaVM_Object");
|
||||
classNames.put(Object.class.getName(), "TeaVM_Object");
|
||||
classNames.put(String.class.getName(), "TeaVM_String");
|
||||
classNames.put(RuntimeClass.class.getName(), "TeaVM_Class");
|
||||
classNames.put(RuntimeArray.class.getName(), "TeaVM_Array");
|
||||
classNames.put(WeakReference.class.getName(), "TeaVM_Reference");
|
||||
classNames.put(ReferenceQueue.class.getName(), "TeaVM_ReferenceQueue");
|
||||
classNames.put(RuntimeReference.class.getName(), "TeaVM_Reference");
|
||||
classNames.put(RuntimeReferenceQueue.class.getName(), "TeaVM_ReferenceQueue");
|
||||
|
||||
memberFieldNames.put(new FieldReference(RuntimeObject.class.getName(), "classReference"), "header");
|
||||
memberFieldNames.put(new FieldReference(RuntimeObject.class.getName(), "hashCode"), "hash");
|
||||
|
@ -54,17 +64,23 @@ public class NameProvider extends LowLevelNameProvider {
|
|||
memberFieldNames.put(new FieldReference(String.class.getName(), "characters"), "characters");
|
||||
memberFieldNames.put(new FieldReference(String.class.getName(), "hashCode"), "hashCode");
|
||||
|
||||
for (String name : new String[] { "size", "flags", "tag", "canary", "name", "itemType", "arrayType",
|
||||
"isSupertypeOf", "init", "enumValues", "layout", "simpleName", "superinterfaceCount",
|
||||
"superinterfaces" }) {
|
||||
memberFieldNames.put(new FieldReference(RuntimeClass.class.getName(), name), name);
|
||||
}
|
||||
preserveFieldNames(RuntimeClass.class.getName(), "size", "flags", "tag", "canary", "name", "itemType",
|
||||
"arrayType", "isSupertypeOf", "init", "enumValues", "layout", "simpleName", "superinterfaceCount",
|
||||
"superinterfaces");
|
||||
memberFieldNames.put(new FieldReference(RuntimeClass.class.getName(), "parent"), "superclass");
|
||||
preserveFieldNames(RuntimeReference.class.getName(), "queue", "object", "next");
|
||||
preserveFieldNames(RuntimeReferenceQueue.class.getName(), "first", "last");
|
||||
|
||||
occupiedClassNames.put(RuntimeObject.class.getName(), new HashSet<>(Arrays.asList("header")));
|
||||
occupiedClassNames.put(RuntimeArray.class.getName(), new HashSet<>(Arrays.asList("length")));
|
||||
}
|
||||
|
||||
private void preserveFieldNames(String className, String... fieldNames) {
|
||||
for (String name : fieldNames) {
|
||||
memberFieldNames.put(new FieldReference(className, name), name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<? extends String> getKeywords() {
|
||||
return keywords;
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2019 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.backend.c.generators;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class ReferenceQueueGenerator implements Generator {
|
||||
private static final MethodReference OBJECT_INIT = new MethodReference(
|
||||
Object.class, "<init>", void.class);
|
||||
|
||||
@Override
|
||||
public boolean canHandle(MethodReference method) {
|
||||
return method.getClassName().equals(ReferenceQueue.class.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(GeneratorContext context, MethodReference method) {
|
||||
switch (method.getName()) {
|
||||
case "<init>":
|
||||
context.includes().includeClass(OBJECT_INIT.getClassName());
|
||||
context.writer().print(context.names().forMethod(OBJECT_INIT)).print("(")
|
||||
.print(context.parameterName(0))
|
||||
.println(");");
|
||||
break;
|
||||
|
||||
case "poll":
|
||||
context.writer().print("return teavm_reference_poll(");
|
||||
context.writer().print("(TeaVM_ReferenceQueue*) ").print(context.parameterName(0));
|
||||
context.writer().println(");");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2019 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.backend.c.generators;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class WeakReferenceGenerator implements Generator {
|
||||
private static final MethodReference REFERENCE_INIT = new MethodReference(Reference.class, "<init>", void.class);
|
||||
@Override
|
||||
public boolean canHandle(MethodReference method) {
|
||||
return method.getClassName().equals(WeakReference.class.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(GeneratorContext context, MethodReference method) {
|
||||
switch (method.getName()) {
|
||||
case "<init>":
|
||||
context.includes().includeClass(REFERENCE_INIT.getClassName());
|
||||
context.writer().print(context.names().forMethod(REFERENCE_INIT)).print("(")
|
||||
.print(context.parameterName(0))
|
||||
.println(");");
|
||||
|
||||
context.writer().print("teavm_reference_init(");
|
||||
context.writer().print("(TeaVM_Reference*) ").print(context.parameterName(0)).print(", ");
|
||||
context.writer().print(context.parameterName(1)).print(", ");
|
||||
if (method.parameterCount() == 2) {
|
||||
context.writer().print(context.parameterName(2));
|
||||
} else {
|
||||
context.writer().print("NULL");
|
||||
}
|
||||
context.writer().println(");");
|
||||
break;
|
||||
|
||||
case "get":
|
||||
context.writer().print("return teavm_reference_get(");
|
||||
context.writer().print("(TeaVM_Reference*) ").print(context.parameterName(0));
|
||||
context.writer().println(");");
|
||||
break;
|
||||
|
||||
case "clear":
|
||||
context.writer().print("teavm_reference_clear(");
|
||||
context.writer().print("(TeaVM_Reference*) ").print(context.parameterName(0));
|
||||
context.writer().println(");");
|
||||
break;
|
||||
|
||||
case "isEnqueued":
|
||||
context.writer().print("return teavm_reference_isEnqueued(");
|
||||
context.writer().print("(TeaVM_Reference*) ").print(context.parameterName(0));
|
||||
context.writer().println(");");
|
||||
break;
|
||||
|
||||
case "enqueue":
|
||||
context.writer().print("return teavm_reference_enqueue(");
|
||||
context.writer().print("(TeaVM_Reference*) ").print(context.parameterName(0));
|
||||
context.writer().println(");");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2019 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.backend.lowlevel.dependency;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import org.teavm.dependency.AbstractDependencyListener;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyNode;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class WeakReferenceDependencyListener extends AbstractDependencyListener {
|
||||
private DependencyNode referentNode;
|
||||
private DependencyNode referenceNode;
|
||||
|
||||
@Override
|
||||
public void started(DependencyAgent agent) {
|
||||
referentNode = agent.createNode();
|
||||
referenceNode = agent.createNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodReached(DependencyAgent agent, MethodDependency method) {
|
||||
MethodReference methodRef = method.getReference();
|
||||
if (methodRef.getClassName().equals(WeakReference.class.getName())) {
|
||||
switch (methodRef.getName()) {
|
||||
case "<init>":
|
||||
reachReferenceInit(agent, method);
|
||||
break;
|
||||
case "get":
|
||||
reachReferenceGet(method);
|
||||
break;
|
||||
}
|
||||
} else if (methodRef.getClassName().equals(ReferenceQueue.class.getName())) {
|
||||
switch (methodRef.getName()) {
|
||||
case "<init>":
|
||||
reachQueueInit(agent, method);
|
||||
break;
|
||||
case "poll":
|
||||
reachQueuePoll(method);
|
||||
break;
|
||||
}
|
||||
}
|
||||
super.methodReached(agent, method);
|
||||
}
|
||||
|
||||
private void reachReferenceInit(DependencyAgent agent, MethodDependency method) {
|
||||
MethodDependency superMethod = agent.linkMethod(new MethodReference(Reference.class, "<init>", void.class));
|
||||
method.getVariable(0).connect(superMethod.getVariable(0));
|
||||
superMethod.use();
|
||||
|
||||
method.getVariable(0).connect(referenceNode);
|
||||
method.getVariable(1).connect(referentNode);
|
||||
}
|
||||
|
||||
private void reachReferenceGet(MethodDependency method) {
|
||||
referentNode.connect(method.getResult());
|
||||
}
|
||||
|
||||
private void reachQueuePoll(MethodDependency method) {
|
||||
referenceNode.connect(method.getResult());
|
||||
}
|
||||
|
||||
private void reachQueueInit(DependencyAgent agent, MethodDependency method) {
|
||||
MethodDependency superMethod = agent.linkMethod(new MethodReference(Object.class, "<init>", void.class));
|
||||
method.getVariable(0).connect(superMethod.getVariable(0));
|
||||
superMethod.use();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2019 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.backend.lowlevel.transform;
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassHolderTransformerContext;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldHolder;
|
||||
import org.teavm.model.MethodHolder;
|
||||
|
||||
public class WeakReferenceTransformation implements ClassHolderTransformer {
|
||||
@Override
|
||||
public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) {
|
||||
if (!cls.getName().equals(WeakReference.class.getName())
|
||||
&& !cls.getName().equals(ReferenceQueue.class.getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (FieldHolder field : cls.getFields().toArray(new FieldHolder[0])) {
|
||||
cls.removeField(field);
|
||||
}
|
||||
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
method.setProgram(null);
|
||||
method.getModifiers().add(ElementModifier.NATIVE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ public final class GC {
|
|||
static FreeChunkHolder currentChunkPointer;
|
||||
static int freeChunks;
|
||||
static int freeMemory = (int) availableBytes();
|
||||
static RuntimeReference firstWeakReference;
|
||||
|
||||
static native Address gcStorageAddress();
|
||||
|
||||
|
@ -122,12 +123,14 @@ public final class GC {
|
|||
|
||||
public static boolean collectGarbage(int size) {
|
||||
mark();
|
||||
processReferences();
|
||||
sweep();
|
||||
updateFreeMemory();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void mark() {
|
||||
firstWeakReference = null;
|
||||
Allocator.fillZero(regionsAddress().toAddress(), regionMaxCount() * Structure.sizeOf(Region.class));
|
||||
|
||||
Address staticRoots = Mutator.getStaticGCRoots();
|
||||
|
@ -176,7 +179,55 @@ public final class GC {
|
|||
|
||||
RuntimeClass cls = RuntimeClass.getClass(object);
|
||||
if (cls.itemType == null) {
|
||||
markObject(cls, object);
|
||||
} else {
|
||||
markArray(cls, (RuntimeArray) object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void markObject(RuntimeClass cls, RuntimeObject object) {
|
||||
while (cls != null) {
|
||||
int type = (cls.flags >> RuntimeClass.VM_TYPE_SHIFT) & RuntimeClass.VM_TYPE_MASK;
|
||||
switch (type) {
|
||||
case RuntimeClass.VM_TYPE_WEAKREFERENCE:
|
||||
markWeakReference((RuntimeReference) object);
|
||||
break;
|
||||
|
||||
case RuntimeClass.VM_TYPE_REFERENCEQUEUE:
|
||||
markReferenceQueue((RuntimeReferenceQueue) object);
|
||||
break;
|
||||
|
||||
default:
|
||||
markFields(cls, object);
|
||||
break;
|
||||
}
|
||||
cls = cls.parent;
|
||||
}
|
||||
}
|
||||
|
||||
private static void markWeakReference(RuntimeReference object) {
|
||||
if (object.queue != null) {
|
||||
mark(object.queue);
|
||||
if (object.next != null && object.object != null) {
|
||||
mark(object.object);
|
||||
}
|
||||
}
|
||||
if (object.next == null && object.object != null) {
|
||||
object.next = firstWeakReference;
|
||||
firstWeakReference = object;
|
||||
}
|
||||
}
|
||||
|
||||
private static void markReferenceQueue(RuntimeReferenceQueue object) {
|
||||
RuntimeReference reference = object.first;
|
||||
while (reference != null) {
|
||||
mark(reference);
|
||||
reference = reference.next;
|
||||
}
|
||||
}
|
||||
|
||||
private static void markFields(RuntimeClass cls, RuntimeObject object) {
|
||||
Address layout = cls.layout;
|
||||
if (layout != null) {
|
||||
short fieldCount = layout.getShort();
|
||||
|
@ -189,11 +240,12 @@ public final class GC {
|
|||
}
|
||||
}
|
||||
}
|
||||
cls = cls.parent;
|
||||
}
|
||||
} else {
|
||||
if ((cls.itemType.flags & RuntimeClass.PRIMITIVE) == 0) {
|
||||
RuntimeArray array = (RuntimeArray) object;
|
||||
|
||||
private static void markArray(RuntimeClass cls, RuntimeArray array) {
|
||||
if ((cls.itemType.flags & RuntimeClass.PRIMITIVE) != 0) {
|
||||
return;
|
||||
}
|
||||
Address base = Address.align(array.toAddress().add(RuntimeArray.class, 1), Address.sizeOf());
|
||||
for (int i = 0; i < array.size; ++i) {
|
||||
RuntimeObject reference = base.getAddress().toStructure();
|
||||
|
@ -203,7 +255,25 @@ public final class GC {
|
|||
base = base.add(Address.sizeOf());
|
||||
}
|
||||
}
|
||||
|
||||
private static void processReferences() {
|
||||
RuntimeReference reference = firstWeakReference;
|
||||
while (reference != null) {
|
||||
RuntimeReference next = reference.next;
|
||||
reference.next = null;
|
||||
if ((reference.object.classReference & RuntimeObject.GC_MARKED) == 0) {
|
||||
reference.object = null;
|
||||
RuntimeReferenceQueue queue = reference.queue;
|
||||
if (queue != null) {
|
||||
if (queue.first == null) {
|
||||
queue.first = reference;
|
||||
} else {
|
||||
queue.last.next = reference;
|
||||
}
|
||||
queue.last = reference;
|
||||
}
|
||||
}
|
||||
reference = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@ public class RuntimeClass extends RuntimeObject {
|
|||
|
||||
public static final int PRIMITIVE_SHIFT = 3;
|
||||
public static final int PRIMITIVE_MASK = 15;
|
||||
public static final int VM_TYPE_SHIFT = 7;
|
||||
public static final int VM_TYPE_MASK = 7;
|
||||
|
||||
public static final int BOOLEAN_PRIMITIVE = 0;
|
||||
public static final int BYTE_PRIMITIVE = 1;
|
||||
public static final int SHORT_PRIMITIVE = 2;
|
||||
|
@ -35,6 +38,10 @@ public class RuntimeClass extends RuntimeObject {
|
|||
public static final int DOUBLE_PRIMITIVE = 7;
|
||||
public static final int VOID_PRIMITIVE = 8;
|
||||
|
||||
public static final int VM_TYPE_REGULAR = 0;
|
||||
public static final int VM_TYPE_WEAKREFERENCE = 1;
|
||||
public static final int VM_TYPE_REFERENCEQUEUE = 2;
|
||||
|
||||
public int size;
|
||||
public int flags;
|
||||
public int tag;
|
||||
|
|
22
core/src/main/java/org/teavm/runtime/RuntimeReference.java
Normal file
22
core/src/main/java/org/teavm/runtime/RuntimeReference.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2019 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;
|
||||
|
||||
public class RuntimeReference extends RuntimeObject {
|
||||
public RuntimeReferenceQueue queue;
|
||||
public RuntimeObject object;
|
||||
public RuntimeReference next;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2019 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;
|
||||
|
||||
public class RuntimeReferenceQueue extends RuntimeObject {
|
||||
public RuntimeReference first;
|
||||
public RuntimeReference last;
|
||||
}
|
47
core/src/main/resources/org/teavm/backend/c/references.c
Normal file
47
core/src/main/resources/org/teavm/backend/c/references.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "runtime.h"
|
||||
|
||||
int32_t teavm_reference_enqueue(TeaVM_Reference* reference) {
|
||||
TeaVM_ReferenceQueue* queue = reference->queue;
|
||||
if (queue == NULL || reference->next != NULL) {
|
||||
return INT32_C(0);
|
||||
}
|
||||
|
||||
if (queue->last == NULL) {
|
||||
queue->first = reference;
|
||||
} else {
|
||||
queue->last->next = reference;
|
||||
}
|
||||
queue->last = reference;
|
||||
|
||||
return INT32_C(1);
|
||||
}
|
||||
|
||||
int32_t teavm_reference_isEnqueued(TeaVM_Reference* reference) {
|
||||
return reference->queue != NULL && reference->next != NULL ? INT32_C(1) : INT32_C(0);
|
||||
}
|
||||
|
||||
void teavm_reference_clear(TeaVM_Reference* reference) {
|
||||
reference->object = NULL;
|
||||
}
|
||||
|
||||
TeaVM_Object* teavm_reference_get(TeaVM_Reference* reference) {
|
||||
return reference->object;
|
||||
}
|
||||
|
||||
TeaVM_Reference* teavm_reference_poll(TeaVM_ReferenceQueue* queue) {
|
||||
if (queue->first == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TeaVM_Reference* reference = queue->first;
|
||||
queue->first = reference->next;
|
||||
if (queue->first == NULL) {
|
||||
queue->last = NULL;
|
||||
}
|
||||
return reference;
|
||||
}
|
||||
|
||||
void teavm_reference_init(TeaVM_Reference* reference, TeaVM_Object* object, TeaVM_ReferenceQueue* queue) {
|
||||
reference->object = object;
|
||||
reference->queue = queue;
|
||||
}
|
|
@ -249,3 +249,30 @@ extern TeaVM_String* teavm_registerString(TeaVM_String*);
|
|||
static inline TeaVM_Object* teavm_dereferenceNullable(TeaVM_Object** o) {
|
||||
return o != NULL ? *o : NULL;
|
||||
}
|
||||
|
||||
struct TeaVM_ReferenceQueue;
|
||||
|
||||
typedef struct TeaVM_Reference {
|
||||
TeaVM_Object parent;
|
||||
struct TeaVM_ReferenceQueue* queue;
|
||||
TeaVM_Object* object;
|
||||
struct TeaVM_Reference* next;
|
||||
} TeaVM_Reference;
|
||||
|
||||
typedef struct TeaVM_ReferenceQueue {
|
||||
TeaVM_Object parent;
|
||||
TeaVM_Reference* first;
|
||||
TeaVM_Reference* last;
|
||||
} TeaVM_ReferenceQueue;
|
||||
|
||||
extern int32_t teavm_reference_enqueue(TeaVM_Reference*);
|
||||
|
||||
extern int32_t teavm_reference_isEnqueued(TeaVM_Reference*);
|
||||
|
||||
extern void teavm_reference_clear(TeaVM_Reference*);
|
||||
|
||||
extern TeaVM_Object* teavm_reference_get(TeaVM_Reference*);
|
||||
|
||||
extern TeaVM_Reference* teavm_reference_poll(TeaVM_ReferenceQueue*);
|
||||
|
||||
extern void teavm_reference_init(TeaVM_Reference*, TeaVM_Object*, TeaVM_ReferenceQueue*);
|
Loading…
Reference in New Issue
Block a user