mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -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 IncrementalDependencyRegistration incrementalCache;
|
||||
private JSImportAnnotationCache annotationCache;
|
||||
private ClassReader objectClass;
|
||||
|
||||
JSClassProcessor(ClassReaderSource classSource, JSTypeHelper typeHelper, JSBodyRepository repository,
|
||||
Diagnostics diagnostics, IncrementalDependencyRegistration incrementalCache) {
|
||||
|
@ -286,13 +287,16 @@ class JSClassProcessor {
|
|||
processIsInstance((IsInstanceInstruction) insn);
|
||||
} else if (insn instanceof InvokeInstruction) {
|
||||
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());
|
||||
processInvokeArgs(invoke, method);
|
||||
if (method == null) {
|
||||
continue;
|
||||
}
|
||||
processInvokeArgs(invoke, method);
|
||||
var callLocation = new CallLocation(methodToProcess.getReference(), insn.getLocation());
|
||||
replacement.clear();
|
||||
if (processInvocation(method, callLocation, invoke, methodToProcess)) {
|
||||
insn.insertNextAll(replacement);
|
||||
|
@ -337,10 +341,18 @@ class JSClassProcessor {
|
|||
}
|
||||
|
||||
private void processInvokeArgs(InvokeInstruction invoke, MethodReader methodToInvoke) {
|
||||
if (typeHelper.isJavaScriptClass(invoke.getMethod().getClassName())
|
||||
|| methodToInvoke.getAnnotations().get(JSBody.class.getName()) != null) {
|
||||
if (methodToInvoke != null && methodToInvoke.getAnnotations().get(JSBody.class.getName()) != null) {
|
||||
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;
|
||||
for (var i = 0; i < invoke.getArguments().size(); ++i) {
|
||||
var type = invoke.getMethod().parameterType(i);
|
||||
|
@ -358,8 +370,7 @@ class JSClassProcessor {
|
|||
}
|
||||
|
||||
if (invoke.getInstance() != null) {
|
||||
invoke.setInstance(wrapJsAsJava(invoke, invoke.getInstance(),
|
||||
ValueType.object(invoke.getMethod().getClassName())));
|
||||
invoke.setInstance(wrapJsAsJava(invoke, invoke.getInstance(), ValueType.object(className)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,6 +557,39 @@ class JSClassProcessor {
|
|||
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,
|
||||
MethodHolder methodToProcess) {
|
||||
if (method.getAnnotations().get(JSBody.class.getName()) != null) {
|
||||
|
@ -837,6 +881,13 @@ class JSClassProcessor {
|
|||
return true;
|
||||
}
|
||||
|
||||
private ClassReader getObjectClass() {
|
||||
if (objectClass == null) {
|
||||
objectClass = classSource.get("java.lang.Object");
|
||||
}
|
||||
return objectClass;
|
||||
}
|
||||
|
||||
private Variable getCallTarget(InvokeInstruction invoke) {
|
||||
return invoke.getInstance() != null
|
||||
? invoke.getInstance()
|
||||
|
|
|
@ -321,6 +321,15 @@ public class JSWrapperTest {
|
|||
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) {
|
||||
setProperty(instance, "foo", o);
|
||||
}
|
||||
|
@ -401,4 +410,7 @@ public class JSWrapperTest {
|
|||
interface JArraySupplier extends JSObject {
|
||||
J[] get();
|
||||
}
|
||||
|
||||
@JSBody(params = "s", script = "return { toString: () => s };")
|
||||
private static native JSObject createWithToString(String s);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user