mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: fully support exporting classes to JS
This commit is contained in:
parent
0dcc25d66b
commit
f61d893b6d
|
@ -93,17 +93,12 @@ class JSAliasRenderer implements RendererListener, MethodContributor {
|
||||||
private boolean exportClassInstanceMembers(ClassReader classReader) {
|
private boolean exportClassInstanceMembers(ClassReader classReader) {
|
||||||
var members = collectMembers(classReader, AliasCollector::isInstanceMember);
|
var members = collectMembers(classReader, AliasCollector::isInstanceMember);
|
||||||
|
|
||||||
var isJsClassImpl = typeHelper.isJavaScriptImplementation(classReader.getName());
|
if (members.methods.isEmpty() && members.properties.isEmpty()) {
|
||||||
if (members.methods.isEmpty() && members.properties.isEmpty() && !isJsClassImpl) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.append("c").ws().append("=").ws().appendClass(classReader.getName()).append(".prototype;")
|
writer.append("c").ws().append("=").ws().appendClass(classReader.getName()).append(".prototype;")
|
||||||
.softNewLine();
|
.softNewLine();
|
||||||
if (isJsClassImpl) {
|
|
||||||
writer.append("c[").appendFunction("$rt_jso_marker").append("]").ws().append("=").ws().append("true;")
|
|
||||||
.softNewLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var aliasEntry : members.methods.entrySet()) {
|
for (var aliasEntry : members.methods.entrySet()) {
|
||||||
if (classReader.getMethod(aliasEntry.getValue().getDescriptor()) == null) {
|
if (classReader.getMethod(aliasEntry.getValue().getDescriptor()) == null) {
|
||||||
|
@ -253,9 +248,6 @@ class JSAliasRenderer implements RendererListener, MethodContributor {
|
||||||
private boolean hasClassesToExpose() {
|
private boolean hasClassesToExpose() {
|
||||||
for (String className : classSource.getClassNames()) {
|
for (String className : classSource.getClassNames()) {
|
||||||
ClassReader cls = classSource.get(className);
|
ClassReader cls = classSource.get(className);
|
||||||
if (typeHelper.isJavaScriptImplementation(className)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (var method : cls.getMethods()) {
|
for (var method : cls.getMethods()) {
|
||||||
if (getPublicAlias(method) != null) {
|
if (getPublicAlias(method) != null) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -348,6 +340,4 @@ class JSAliasRenderer implements RendererListener, MethodContributor {
|
||||||
MethodReader methodReader = classReader.getMethod(methodRef.getDescriptor());
|
MethodReader methodReader = classReader.getMethod(methodRef.getDescriptor());
|
||||||
return methodReader != null && getPublicAlias(methodReader) != null;
|
return methodReader != null && getPublicAlias(methodReader) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,5 @@ public class JSOPlugin implements TeaVMPlugin {
|
||||||
wrapperGenerator);
|
wrapperGenerator);
|
||||||
jsHost.add(new MethodReference(JSWrapper.class, "jsToWrapper", JSObject.class, JSWrapper.class),
|
jsHost.add(new MethodReference(JSWrapper.class, "jsToWrapper", JSObject.class, JSWrapper.class),
|
||||||
wrapperGenerator);
|
wrapperGenerator);
|
||||||
jsHost.add(new MethodReference(JSWrapper.class, "isJSImplementation", Object.class, boolean.class),
|
|
||||||
wrapperGenerator);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
|
||||||
processor.setClassFilter(classFilter);
|
processor.setClassFilter(classFilter);
|
||||||
}
|
}
|
||||||
processor.processClass(cls);
|
processor.processClass(cls);
|
||||||
if (isJavaScriptClass(cls)) {
|
if (isJavaScriptClass(cls) && !isJavaScriptImplementation(cls)) {
|
||||||
processor.processMemberMethods(cls);
|
processor.processMemberMethods(cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,44 +99,48 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
|
||||||
}
|
}
|
||||||
processor.createJSMethods(cls);
|
processor.createJSMethods(cls);
|
||||||
|
|
||||||
if (cls.hasModifier(ElementModifier.ABSTRACT)
|
if (isJavaScriptClass(cls) && !isJavaScriptImplementation(cls)) {
|
||||||
|| cls.getAnnotations().get(JSClass.class.getName()) != null && isJavaScriptClass(cls)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodReference functorMethod = processor.isFunctor(cls.getName());
|
var hasStaticMethods = false;
|
||||||
if (functorMethod != null) {
|
var hasMemberMethods = false;
|
||||||
if (processor.isFunctor(cls.getParent()) != null) {
|
|
||||||
functorMethod = null;
|
if (!cls.hasModifier(ElementModifier.ABSTRACT)) {
|
||||||
|
MethodReference functorMethod = processor.isFunctor(cls.getName());
|
||||||
|
if (functorMethod != null) {
|
||||||
|
if (processor.isFunctor(cls.getParent()) != null) {
|
||||||
|
functorMethod = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassReader originalClass = hierarchy.getClassSource().get(cls.getName());
|
||||||
|
ExposedClass exposedClass;
|
||||||
|
if (originalClass != null) {
|
||||||
|
exposedClass = getExposedClass(cls.getName());
|
||||||
|
} else {
|
||||||
|
exposedClass = new ExposedClass();
|
||||||
|
createExposedClass(cls, exposedClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
exposeMethods(cls, exposedClass, context.getDiagnostics(), functorMethod);
|
||||||
|
if (!exposedClass.methods.isEmpty()) {
|
||||||
|
hasMemberMethods = true;
|
||||||
|
cls.getAnnotations().add(new AnnotationHolder(JSClassToExpose.class.getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hasStaticMethods = exportStaticMethods(cls, context.getDiagnostics());
|
||||||
ClassReader originalClass = hierarchy.getClassSource().get(cls.getName());
|
if (hasMemberMethods || hasStaticMethods) {
|
||||||
ExposedClass exposedClass;
|
|
||||||
if (originalClass != null) {
|
|
||||||
exposedClass = getExposedClass(cls.getName());
|
|
||||||
} else {
|
|
||||||
exposedClass = new ExposedClass();
|
|
||||||
createExposedClass(cls, exposedClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
exposeMethods(cls, exposedClass, context.getDiagnostics(), functorMethod);
|
|
||||||
var hasStaticMethods = exportStaticMethods(cls, context.getDiagnostics());
|
|
||||||
|
|
||||||
if (isJavaScriptImplementation(cls) || !exposedClass.methods.isEmpty()) {
|
|
||||||
cls.getAnnotations().add(new AnnotationHolder(JSClassToExpose.class.getName()));
|
|
||||||
}
|
|
||||||
if (isJavaScriptImplementation(cls) || !exposedClass.methods.isEmpty() || hasStaticMethods) {
|
|
||||||
cls.getAnnotations().add(new AnnotationHolder(JSClassObjectToExpose.class.getName()));
|
cls.getAnnotations().add(new AnnotationHolder(JSClassObjectToExpose.class.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wasmGC && (!exposedClass.methods.isEmpty() || isJavaScriptClass(cls))) {
|
if (wasmGC && hasMemberMethods) {
|
||||||
var createWrapperMethod = new MethodHolder(JSMethods.MARSHALL_TO_JS);
|
var createWrapperMethod = new MethodHolder(JSMethods.MARSHALL_TO_JS);
|
||||||
createWrapperMethod.setLevel(AccessLevel.PUBLIC);
|
createWrapperMethod.setLevel(AccessLevel.PUBLIC);
|
||||||
createWrapperMethod.getModifiers().add(ElementModifier.NATIVE);
|
createWrapperMethod.getModifiers().add(ElementModifier.NATIVE);
|
||||||
cls.addMethod(createWrapperMethod);
|
cls.addMethod(createWrapperMethod);
|
||||||
|
|
||||||
if (!isJavaScriptClass(cls) || isJavaScriptImplementation(cls)) {
|
if (!isJavaScriptClass(cls)) {
|
||||||
cls.getInterfaces().add(JSMethods.JS_MARSHALLABLE);
|
cls.getInterfaces().add(JSMethods.JS_MARSHALLABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -429,7 +433,7 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
|
||||||
if (typeHelper.isJavaScriptImplementation(cls.getName())) {
|
if (typeHelper.isJavaScriptImplementation(cls.getName())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (cls.getAnnotations().get(JSClass.class.getName()) != null) {
|
if (cls.getAnnotations().get(JSClass.class.getName()) != null || cls.hasModifier(ElementModifier.ABSTRACT)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (cls.getParent() != null) {
|
if (cls.getParent() != null) {
|
||||||
|
|
|
@ -84,7 +84,8 @@ public class JSTypeHelper {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ClassReader cls = classSource.get(className);
|
ClassReader cls = classSource.get(className);
|
||||||
if (cls == null || cls.getAnnotations().get(JSClass.class.getName()) != null) {
|
if (cls == null || cls.getAnnotations().get(JSClass.class.getName()) != null
|
||||||
|
|| cls.hasModifier(ElementModifier.ABSTRACT)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (cls.getParent() != null) {
|
if (cls.getParent() != null) {
|
||||||
|
|
|
@ -188,14 +188,11 @@ public final class JSWrapper {
|
||||||
@NoSideEffects
|
@NoSideEffects
|
||||||
public static native boolean isJava(JSObject obj);
|
public static native boolean isJava(JSObject obj);
|
||||||
|
|
||||||
@NoSideEffects
|
|
||||||
private static native boolean isJSImplementation(Object obj);
|
|
||||||
|
|
||||||
public static JSObject unwrap(Object o) {
|
public static JSObject unwrap(Object o) {
|
||||||
if (o == null) {
|
if (o == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return isJSImplementation(o) ? marshallJavaToJs(o) : ((JSWrapper) o).js;
|
return (!(o instanceof JSWrapper)) ? marshallJavaToJs(o) : ((JSWrapper) o).js;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSObject maybeUnwrap(Object o) {
|
public static JSObject maybeUnwrap(Object o) {
|
||||||
|
|
|
@ -50,17 +50,6 @@ public class JSWrapperGenerator implements Injector, DependencyPlugin {
|
||||||
context.getWriter().append(")");
|
context.getWriter().append(")");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "isJSImplementation":
|
|
||||||
if (context.getPrecedence().ordinal() >= Precedence.EQUALITY.ordinal()) {
|
|
||||||
context.getWriter().append("(");
|
|
||||||
}
|
|
||||||
context.writeExpr(context.getArgument(0), Precedence.MEMBER_ACCESS);
|
|
||||||
context.getWriter().append("[").appendFunction("$rt_jso_marker").append("]")
|
|
||||||
.ws().append("===").ws().append("true");
|
|
||||||
if (context.getPrecedence().ordinal() >= Precedence.EQUALITY.ordinal()) {
|
|
||||||
context.getWriter().append(")");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ import org.teavm.model.ClassHolderTransformerContext;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodHolder;
|
import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.ValueType;
|
|
||||||
import org.teavm.model.emit.ProgramEmitter;
|
import org.teavm.model.emit.ProgramEmitter;
|
||||||
|
|
||||||
class WasmGCJSWrapperTransformer implements ClassHolderTransformer {
|
class WasmGCJSWrapperTransformer implements ClassHolderTransformer {
|
||||||
|
@ -35,8 +34,6 @@ class WasmGCJSWrapperTransformer implements ClassHolderTransformer {
|
||||||
transformMarshallMethod(cls.getMethod(new MethodDescriptor("marshallJavaToJs", Object.class,
|
transformMarshallMethod(cls.getMethod(new MethodDescriptor("marshallJavaToJs", Object.class,
|
||||||
JSObject.class)), context);
|
JSObject.class)), context);
|
||||||
transformWrapMethod(cls.getMethod(new MethodDescriptor("wrap", JSObject.class, Object.class)));
|
transformWrapMethod(cls.getMethod(new MethodDescriptor("wrap", JSObject.class, Object.class)));
|
||||||
transformIsJsImplementation(cls.getMethod(new MethodDescriptor("isJSImplementation",
|
|
||||||
Object.class, boolean.class)), context);
|
|
||||||
transformIsJava(cls.getMethod(new MethodDescriptor("isJava", Object.class, boolean.class)), context);
|
transformIsJava(cls.getMethod(new MethodDescriptor("isJava", Object.class, boolean.class)), context);
|
||||||
addCreateWrapperMethod(cls, context);
|
addCreateWrapperMethod(cls, context);
|
||||||
}
|
}
|
||||||
|
@ -54,13 +51,6 @@ class WasmGCJSWrapperTransformer implements ClassHolderTransformer {
|
||||||
method.setProgram(null);
|
method.setProgram(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void transformIsJsImplementation(MethodHolder method, ClassHolderTransformerContext context) {
|
|
||||||
method.getModifiers().remove(ElementModifier.NATIVE);
|
|
||||||
var pe = ProgramEmitter.create(method, context.getHierarchy());
|
|
||||||
var obj = pe.var(1, JSObject.class);
|
|
||||||
obj.instanceOf(ValueType.parse(JSMarshallable.class)).returnValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addCreateWrapperMethod(ClassHolder cls, ClassHolderTransformerContext context) {
|
private void addCreateWrapperMethod(ClassHolder cls, ClassHolderTransformerContext context) {
|
||||||
var method = new MethodHolder(new MethodDescriptor("createWrapper", JSObject.class, Object.class));
|
var method = new MethodHolder(new MethodDescriptor("createWrapper", JSObject.class, Object.class));
|
||||||
method.getModifiers().add(ElementModifier.STATIC);
|
method.getModifiers().add(ElementModifier.STATIC);
|
||||||
|
|
|
@ -97,7 +97,7 @@ public class ExportTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void exportClassMembers() {
|
public void exportClassMembers() {
|
||||||
testExport("exportClassMembers", ModuleWithExportedClassMembers.class, true);
|
testExport("exportClassMembers", ModuleWithExportedClassMembers.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -107,23 +107,19 @@ public class ExportTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void exportClasses() {
|
public void exportClasses() {
|
||||||
testExport("exportClasses", ModuleWithExportedClasses.class, true);
|
testExport("exportClasses", ModuleWithExportedClasses.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void varargs() {
|
public void varargs() {
|
||||||
testExport("varargs", ModuleWithVararg.class, true);
|
testExport("varargs", ModuleWithVararg.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testExport(String name, Class<?> moduleClass) {
|
private void testExport(String name, Class<?> moduleClass) {
|
||||||
testExport(name, moduleClass, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testExport(String name, Class<?> moduleClass, boolean skipWasm) {
|
|
||||||
if (jsNeeded) {
|
if (jsNeeded) {
|
||||||
testExportJs(name, moduleClass);
|
testExportJs(name, moduleClass);
|
||||||
}
|
}
|
||||||
if (wasmGCNeeded && !skipWasm) {
|
if (wasmGCNeeded) {
|
||||||
testExportWasmGC(name, moduleClass);
|
testExportWasmGC(name, moduleClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user