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;
|
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 abstract class TReference<T> extends TObject {
|
||||||
public T get() {
|
public T get() {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -15,11 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.java.lang.ref;
|
package org.teavm.classlib.java.lang.ref;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
* @param <T>
|
|
||||||
*/
|
|
||||||
public class TReferenceQueue<T> {
|
public class TReferenceQueue<T> {
|
||||||
public TReference<T> poll() {
|
public TReference<T> poll() {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -35,4 +35,14 @@ public class TWeakReference<T> extends TReference<T> {
|
||||||
public void clear() {
|
public void clear() {
|
||||||
value = null;
|
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.ArrayGenerator;
|
||||||
import org.teavm.backend.c.generators.Generator;
|
import org.teavm.backend.c.generators.Generator;
|
||||||
import org.teavm.backend.c.generators.GeneratorFactory;
|
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.AddressIntrinsic;
|
||||||
import org.teavm.backend.c.intrinsic.AllocatorIntrinsic;
|
import org.teavm.backend.c.intrinsic.AllocatorIntrinsic;
|
||||||
import org.teavm.backend.c.intrinsic.ConsoleIntrinsic;
|
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.StringsIntrinsic;
|
||||||
import org.teavm.backend.c.intrinsic.StructureIntrinsic;
|
import org.teavm.backend.c.intrinsic.StructureIntrinsic;
|
||||||
import org.teavm.backend.lowlevel.dependency.ExceptionHandlingDependencyListener;
|
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.CoroutineTransformation;
|
||||||
|
import org.teavm.backend.lowlevel.transform.WeakReferenceTransformation;
|
||||||
import org.teavm.dependency.ClassDependency;
|
import org.teavm.dependency.ClassDependency;
|
||||||
import org.teavm.dependency.DependencyAnalyzer;
|
import org.teavm.dependency.DependencyAnalyzer;
|
||||||
import org.teavm.dependency.DependencyListener;
|
import org.teavm.dependency.DependencyListener;
|
||||||
|
@ -163,12 +167,14 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
||||||
List<ClassHolderTransformer> transformers = new ArrayList<>();
|
List<ClassHolderTransformer> transformers = new ArrayList<>();
|
||||||
transformers.add(new ClassPatch());
|
transformers.add(new ClassPatch());
|
||||||
transformers.add(new CDependencyListener());
|
transformers.add(new CDependencyListener());
|
||||||
|
transformers.add(new WeakReferenceTransformation());
|
||||||
return transformers;
|
return transformers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DependencyListener> getDependencyListeners() {
|
public List<DependencyListener> getDependencyListeners() {
|
||||||
return Arrays.asList(new CDependencyListener(), exportDependencyListener, new InteropDependencyListener());
|
return Arrays.asList(new CDependencyListener(), exportDependencyListener, new InteropDependencyListener(),
|
||||||
|
new WeakReferenceDependencyListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -323,6 +329,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
||||||
|
|
||||||
List<Generator> generators = new ArrayList<>();
|
List<Generator> generators = new ArrayList<>();
|
||||||
generators.add(new ArrayGenerator());
|
generators.add(new ArrayGenerator());
|
||||||
|
generators.add(new WeakReferenceGenerator());
|
||||||
|
generators.add(new ReferenceQueueGenerator());
|
||||||
|
|
||||||
stringPool = new SimpleStringPool();
|
stringPool = new SimpleStringPool();
|
||||||
GenerationContext context = new GenerationContext(vtableProvider, characteristics,
|
GenerationContext context = new GenerationContext(vtableProvider, characteristics,
|
||||||
|
@ -355,10 +363,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
||||||
generateSpecialFunctions(context, runtimeWriter);
|
generateSpecialFunctions(context, runtimeWriter);
|
||||||
OutputFileUtil.write(runtimeWriter, "runtime.c", buildTarget);
|
OutputFileUtil.write(runtimeWriter, "runtime.c", buildTarget);
|
||||||
OutputFileUtil.write(runtimeHeaderWriter, "runtime.h", buildTarget);
|
OutputFileUtil.write(runtimeHeaderWriter, "runtime.h", buildTarget);
|
||||||
BufferedCodeWriter stringhashWriter = new BufferedCodeWriter(false);
|
copyResource("stringhash.c", buildTarget);
|
||||||
emitResource(stringhashWriter, "stringhash.c");
|
copyResource("references.c", buildTarget);
|
||||||
OutputFileUtil.write(stringhashWriter, "stringhash.c", buildTarget);
|
|
||||||
|
|
||||||
generateCallSites(buildTarget, context, classes.getClassNames());
|
generateCallSites(buildTarget, context, classes.getClassNames());
|
||||||
generateStrings(buildTarget, context);
|
generateStrings(buildTarget, context);
|
||||||
|
|
||||||
|
@ -369,6 +375,12 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
||||||
generateAllFile(classes, types, buildTarget);
|
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) {
|
private void emitResource(CodeWriter writer, String resourceName) {
|
||||||
ClassLoader classLoader = CTarget.class.getClassLoader();
|
ClassLoader classLoader = CTarget.class.getClassLoader();
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
package org.teavm.backend.c.generate;
|
package org.teavm.backend.c.generate;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.ReferenceQueue;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -64,11 +66,15 @@ import org.teavm.runtime.CallSite;
|
||||||
import org.teavm.runtime.RuntimeArray;
|
import org.teavm.runtime.RuntimeArray;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
import org.teavm.runtime.RuntimeObject;
|
import org.teavm.runtime.RuntimeObject;
|
||||||
|
import org.teavm.runtime.RuntimeReference;
|
||||||
|
import org.teavm.runtime.RuntimeReferenceQueue;
|
||||||
|
|
||||||
public class ClassGenerator {
|
public class ClassGenerator {
|
||||||
private static final Set<String> classesWithDeclaredStructures = new HashSet<>(Arrays.asList(
|
private static final Set<String> classesWithDeclaredStructures = new HashSet<>(Arrays.asList(
|
||||||
"java.lang.Object", "java.lang.String", "java.lang.Class",
|
"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;
|
private GenerationContext context;
|
||||||
|
@ -566,6 +572,15 @@ public class ClassGenerator {
|
||||||
superinterfaces = sb.append(" }").toString();
|
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) {
|
} else if (type instanceof ValueType.Array) {
|
||||||
includes.includeClass("java.lang.Object");
|
includes.includeClass("java.lang.Object");
|
||||||
parent = "(TeaVM_Class*) &" + context.getNames().forClassInstance(ValueType.object("java.lang.Object"));
|
parent = "(TeaVM_Class*) &" + context.getNames().forClassInstance(ValueType.object("java.lang.Object"));
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.c.generate;
|
package org.teavm.backend.c.generate;
|
||||||
|
|
||||||
|
import java.lang.ref.ReferenceQueue;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -25,6 +27,8 @@ import org.teavm.model.FieldReference;
|
||||||
import org.teavm.runtime.RuntimeArray;
|
import org.teavm.runtime.RuntimeArray;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
import org.teavm.runtime.RuntimeObject;
|
import org.teavm.runtime.RuntimeObject;
|
||||||
|
import org.teavm.runtime.RuntimeReference;
|
||||||
|
import org.teavm.runtime.RuntimeReferenceQueue;
|
||||||
|
|
||||||
public class NameProvider extends LowLevelNameProvider {
|
public class NameProvider extends LowLevelNameProvider {
|
||||||
private static final Set<? extends String> keywords = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
|
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_Array");
|
||||||
occupiedTopLevelNames.add("TeaVM_String");
|
occupiedTopLevelNames.add("TeaVM_String");
|
||||||
occupiedTopLevelNames.add("TeaVM_Class");
|
occupiedTopLevelNames.add("TeaVM_Class");
|
||||||
|
occupiedTopLevelNames.add("TeaVM_Reference");
|
||||||
|
occupiedTopLevelNames.add("TeaVM_ReferenceQueue");
|
||||||
|
|
||||||
classNames.put(RuntimeObject.class.getName(), "TeaVM_Object");
|
classNames.put(RuntimeObject.class.getName(), "TeaVM_Object");
|
||||||
classNames.put(Object.class.getName(), "TeaVM_Object");
|
classNames.put(Object.class.getName(), "TeaVM_Object");
|
||||||
classNames.put(String.class.getName(), "TeaVM_String");
|
classNames.put(String.class.getName(), "TeaVM_String");
|
||||||
classNames.put(RuntimeClass.class.getName(), "TeaVM_Class");
|
classNames.put(RuntimeClass.class.getName(), "TeaVM_Class");
|
||||||
classNames.put(RuntimeArray.class.getName(), "TeaVM_Array");
|
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(), "classReference"), "header");
|
||||||
memberFieldNames.put(new FieldReference(RuntimeObject.class.getName(), "hashCode"), "hash");
|
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(), "characters"), "characters");
|
||||||
memberFieldNames.put(new FieldReference(String.class.getName(), "hashCode"), "hashCode");
|
memberFieldNames.put(new FieldReference(String.class.getName(), "hashCode"), "hashCode");
|
||||||
|
|
||||||
for (String name : new String[] { "size", "flags", "tag", "canary", "name", "itemType", "arrayType",
|
preserveFieldNames(RuntimeClass.class.getName(), "size", "flags", "tag", "canary", "name", "itemType",
|
||||||
"isSupertypeOf", "init", "enumValues", "layout", "simpleName", "superinterfaceCount",
|
"arrayType", "isSupertypeOf", "init", "enumValues", "layout", "simpleName", "superinterfaceCount",
|
||||||
"superinterfaces" }) {
|
"superinterfaces");
|
||||||
memberFieldNames.put(new FieldReference(RuntimeClass.class.getName(), name), name);
|
|
||||||
}
|
|
||||||
memberFieldNames.put(new FieldReference(RuntimeClass.class.getName(), "parent"), "superclass");
|
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(RuntimeObject.class.getName(), new HashSet<>(Arrays.asList("header")));
|
||||||
occupiedClassNames.put(RuntimeArray.class.getName(), new HashSet<>(Arrays.asList("length")));
|
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
|
@Override
|
||||||
protected Set<? extends String> getKeywords() {
|
protected Set<? extends String> getKeywords() {
|
||||||
return keywords;
|
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 FreeChunkHolder currentChunkPointer;
|
||||||
static int freeChunks;
|
static int freeChunks;
|
||||||
static int freeMemory = (int) availableBytes();
|
static int freeMemory = (int) availableBytes();
|
||||||
|
static RuntimeReference firstWeakReference;
|
||||||
|
|
||||||
static native Address gcStorageAddress();
|
static native Address gcStorageAddress();
|
||||||
|
|
||||||
|
@ -122,12 +123,14 @@ public final class GC {
|
||||||
|
|
||||||
public static boolean collectGarbage(int size) {
|
public static boolean collectGarbage(int size) {
|
||||||
mark();
|
mark();
|
||||||
|
processReferences();
|
||||||
sweep();
|
sweep();
|
||||||
updateFreeMemory();
|
updateFreeMemory();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void mark() {
|
private static void mark() {
|
||||||
|
firstWeakReference = null;
|
||||||
Allocator.fillZero(regionsAddress().toAddress(), regionMaxCount() * Structure.sizeOf(Region.class));
|
Allocator.fillZero(regionsAddress().toAddress(), regionMaxCount() * Structure.sizeOf(Region.class));
|
||||||
|
|
||||||
Address staticRoots = Mutator.getStaticGCRoots();
|
Address staticRoots = Mutator.getStaticGCRoots();
|
||||||
|
@ -176,37 +179,104 @@ public final class GC {
|
||||||
|
|
||||||
RuntimeClass cls = RuntimeClass.getClass(object);
|
RuntimeClass cls = RuntimeClass.getClass(object);
|
||||||
if (cls.itemType == null) {
|
if (cls.itemType == null) {
|
||||||
while (cls != null) {
|
markObject(cls, object);
|
||||||
Address layout = cls.layout;
|
|
||||||
if (layout != null) {
|
|
||||||
short fieldCount = layout.getShort();
|
|
||||||
while (fieldCount-- > 0) {
|
|
||||||
layout = layout.add(2);
|
|
||||||
int fieldOffset = layout.getShort();
|
|
||||||
RuntimeObject reference = object.toAddress().add(fieldOffset).getAddress().toStructure();
|
|
||||||
if (reference != null && !isMarked(reference)) {
|
|
||||||
MarkQueue.enqueue(reference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cls = cls.parent;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if ((cls.itemType.flags & RuntimeClass.PRIMITIVE) == 0) {
|
markArray(cls, (RuntimeArray) object);
|
||||||
RuntimeArray array = (RuntimeArray) object;
|
}
|
||||||
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();
|
|
||||||
if (reference != null && !isMarked(reference)) {
|
private static void markObject(RuntimeClass cls, RuntimeObject object) {
|
||||||
MarkQueue.enqueue(reference);
|
while (cls != null) {
|
||||||
}
|
int type = (cls.flags >> RuntimeClass.VM_TYPE_SHIFT) & RuntimeClass.VM_TYPE_MASK;
|
||||||
base = base.add(Address.sizeOf());
|
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();
|
||||||
|
while (fieldCount-- > 0) {
|
||||||
|
layout = layout.add(2);
|
||||||
|
int fieldOffset = layout.getShort();
|
||||||
|
RuntimeObject reference = object.toAddress().add(fieldOffset).getAddress().toStructure();
|
||||||
|
if (reference != null && !isMarked(reference)) {
|
||||||
|
MarkQueue.enqueue(reference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
if (reference != null && !isMarked(reference)) {
|
||||||
|
MarkQueue.enqueue(reference);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void sweep() {
|
private static void sweep() {
|
||||||
FreeChunkHolder freeChunkPtr = gcStorageAddress().toStructure();
|
FreeChunkHolder freeChunkPtr = gcStorageAddress().toStructure();
|
||||||
freeChunks = 0;
|
freeChunks = 0;
|
||||||
|
|
|
@ -25,6 +25,9 @@ public class RuntimeClass extends RuntimeObject {
|
||||||
|
|
||||||
public static final int PRIMITIVE_SHIFT = 3;
|
public static final int PRIMITIVE_SHIFT = 3;
|
||||||
public static final int PRIMITIVE_MASK = 15;
|
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 BOOLEAN_PRIMITIVE = 0;
|
||||||
public static final int BYTE_PRIMITIVE = 1;
|
public static final int BYTE_PRIMITIVE = 1;
|
||||||
public static final int SHORT_PRIMITIVE = 2;
|
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 DOUBLE_PRIMITIVE = 7;
|
||||||
public static final int VOID_PRIMITIVE = 8;
|
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 size;
|
||||||
public int flags;
|
public int flags;
|
||||||
public int tag;
|
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;
|
||||||
|
}
|
|
@ -248,4 +248,31 @@ extern TeaVM_String* teavm_registerString(TeaVM_String*);
|
||||||
|
|
||||||
static inline TeaVM_Object* teavm_dereferenceNullable(TeaVM_Object** o) {
|
static inline TeaVM_Object* teavm_dereferenceNullable(TeaVM_Object** o) {
|
||||||
return o != NULL ? *o : NULL;
|
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