mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
jso: properly support JSWrapper generation when java.lang.Object method is called with receiver type of JSObject interface; add optimization for JSObject.toString call.
Fix #898
This commit is contained in:
parent
005765aa6e
commit
f668e27daa
|
@ -100,6 +100,7 @@ class JSClassProcessor {
|
||||||
private JSValueMarshaller marshaller;
|
private JSValueMarshaller marshaller;
|
||||||
private IncrementalDependencyRegistration incrementalCache;
|
private IncrementalDependencyRegistration incrementalCache;
|
||||||
private JSImportAnnotationCache annotationCache;
|
private JSImportAnnotationCache annotationCache;
|
||||||
|
private ClassReader objectClass;
|
||||||
|
|
||||||
JSClassProcessor(ClassReaderSource classSource, JSTypeHelper typeHelper, JSBodyRepository repository,
|
JSClassProcessor(ClassReaderSource classSource, JSTypeHelper typeHelper, JSBodyRepository repository,
|
||||||
Diagnostics diagnostics, IncrementalDependencyRegistration incrementalCache) {
|
Diagnostics diagnostics, IncrementalDependencyRegistration incrementalCache) {
|
||||||
|
@ -286,13 +287,16 @@ class JSClassProcessor {
|
||||||
processIsInstance((IsInstanceInstruction) insn);
|
processIsInstance((IsInstanceInstruction) insn);
|
||||||
} else if (insn instanceof InvokeInstruction) {
|
} else if (insn instanceof InvokeInstruction) {
|
||||||
var invoke = (InvokeInstruction) insn;
|
var invoke = (InvokeInstruction) insn;
|
||||||
|
var callLocation = new CallLocation(methodToProcess.getReference(), insn.getLocation());
|
||||||
|
if (processToString(invoke, callLocation)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var method = getMethod(invoke.getMethod().getClassName(), invoke.getMethod().getDescriptor());
|
var method = getMethod(invoke.getMethod().getClassName(), invoke.getMethod().getDescriptor());
|
||||||
|
processInvokeArgs(invoke, method);
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
processInvokeArgs(invoke, method);
|
|
||||||
var callLocation = new CallLocation(methodToProcess.getReference(), insn.getLocation());
|
|
||||||
replacement.clear();
|
replacement.clear();
|
||||||
if (processInvocation(method, callLocation, invoke, methodToProcess)) {
|
if (processInvocation(method, callLocation, invoke, methodToProcess)) {
|
||||||
insn.insertNextAll(replacement);
|
insn.insertNextAll(replacement);
|
||||||
|
@ -337,10 +341,18 @@ class JSClassProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processInvokeArgs(InvokeInstruction invoke, MethodReader methodToInvoke) {
|
private void processInvokeArgs(InvokeInstruction invoke, MethodReader methodToInvoke) {
|
||||||
if (typeHelper.isJavaScriptClass(invoke.getMethod().getClassName())
|
if (methodToInvoke != null && methodToInvoke.getAnnotations().get(JSBody.class.getName()) != null) {
|
||||||
|| methodToInvoke.getAnnotations().get(JSBody.class.getName()) != null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var className = invoke.getMethod().getClassName();
|
||||||
|
if (typeHelper.isJavaScriptClass(invoke.getMethod().getClassName())) {
|
||||||
|
if (invoke.getMethod().getName().equals("<init>")
|
||||||
|
|| getObjectClass().getMethod(invoke.getMethod().getDescriptor()) == null) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
className = "java.lang.Object";
|
||||||
|
}
|
||||||
|
}
|
||||||
Variable[] newArgs = null;
|
Variable[] newArgs = null;
|
||||||
for (var i = 0; i < invoke.getArguments().size(); ++i) {
|
for (var i = 0; i < invoke.getArguments().size(); ++i) {
|
||||||
var type = invoke.getMethod().parameterType(i);
|
var type = invoke.getMethod().parameterType(i);
|
||||||
|
@ -358,8 +370,7 @@ class JSClassProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invoke.getInstance() != null) {
|
if (invoke.getInstance() != null) {
|
||||||
invoke.setInstance(wrapJsAsJava(invoke, invoke.getInstance(),
|
invoke.setInstance(wrapJsAsJava(invoke, invoke.getInstance(), ValueType.object(className)));
|
||||||
ValueType.object(invoke.getMethod().getClassName())));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,6 +557,39 @@ class JSClassProcessor {
|
||||||
return unwrap.getReceiver();
|
return unwrap.getReceiver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean processToString(InvokeInstruction invoke, CallLocation location) {
|
||||||
|
if (!invoke.getMethod().getName().equals("toString") || !invoke.getArguments().isEmpty()
|
||||||
|
|| invoke.getInstance() == null || !invoke.getMethod().getReturnType().isObject(String.class)
|
||||||
|
|| types.typeOf(invoke.getInstance()) != JSType.JS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
replacement.clear();
|
||||||
|
var methodName = marshaller.addStringWrap(marshaller.addString("toString", invoke.getLocation()),
|
||||||
|
invoke.getLocation());
|
||||||
|
|
||||||
|
var jsInvoke = new InvokeInstruction();
|
||||||
|
jsInvoke.setType(InvocationType.SPECIAL);
|
||||||
|
jsInvoke.setMethod(JSMethods.invoke(0));
|
||||||
|
jsInvoke.setReceiver(program.createVariable());
|
||||||
|
jsInvoke.setLocation(invoke.getLocation());
|
||||||
|
jsInvoke.setArguments(invoke.getInstance(), methodName);
|
||||||
|
replacement.add(jsInvoke);
|
||||||
|
|
||||||
|
var assign = new AssignInstruction();
|
||||||
|
assign.setAssignee(marshaller.unwrapReturnValue(location, jsInvoke.getReceiver(),
|
||||||
|
invoke.getMethod().getReturnType(), false, canBeOnlyJava(invoke.getReceiver())));
|
||||||
|
assign.setReceiver(invoke.getReceiver());
|
||||||
|
assign.setLocation(invoke.getLocation());
|
||||||
|
replacement.add(assign);
|
||||||
|
|
||||||
|
invoke.insertNextAll(replacement);
|
||||||
|
replacement.clear();
|
||||||
|
invoke.delete();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean processInvocation(MethodReader method, CallLocation callLocation, InvokeInstruction invoke,
|
private boolean processInvocation(MethodReader method, CallLocation callLocation, InvokeInstruction invoke,
|
||||||
MethodHolder methodToProcess) {
|
MethodHolder methodToProcess) {
|
||||||
if (method.getAnnotations().get(JSBody.class.getName()) != null) {
|
if (method.getAnnotations().get(JSBody.class.getName()) != null) {
|
||||||
|
@ -837,6 +881,13 @@ class JSClassProcessor {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ClassReader getObjectClass() {
|
||||||
|
if (objectClass == null) {
|
||||||
|
objectClass = classSource.get("java.lang.Object");
|
||||||
|
}
|
||||||
|
return objectClass;
|
||||||
|
}
|
||||||
|
|
||||||
private Variable getCallTarget(InvokeInstruction invoke) {
|
private Variable getCallTarget(InvokeInstruction invoke) {
|
||||||
return invoke.getInstance() != null
|
return invoke.getInstance() != null
|
||||||
? invoke.getInstance()
|
? invoke.getInstance()
|
||||||
|
|
|
@ -321,6 +321,15 @@ public class JSWrapperTest {
|
||||||
assertTrue(JSObjects.isUndefined(field1));
|
assertTrue(JSObjects.isUndefined(field1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void jsToString() {
|
||||||
|
var a = createWithToString("foo");
|
||||||
|
assertEquals("foo", a.toString());
|
||||||
|
|
||||||
|
Object b = createWithToString("bar");
|
||||||
|
assertEquals("bar", b.toString());
|
||||||
|
}
|
||||||
|
|
||||||
private void callSetProperty(Object instance, Object o) {
|
private void callSetProperty(Object instance, Object o) {
|
||||||
setProperty(instance, "foo", o);
|
setProperty(instance, "foo", o);
|
||||||
}
|
}
|
||||||
|
@ -401,4 +410,7 @@ public class JSWrapperTest {
|
||||||
interface JArraySupplier extends JSObject {
|
interface JArraySupplier extends JSObject {
|
||||||
J[] get();
|
J[] get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JSBody(params = "s", script = "return { toString: () => s };")
|
||||||
|
private static native JSObject createWithToString(String s);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user