mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
JS: optimize case when JS method returns java.lang.Object and then treated as JS object
This commit is contained in:
parent
35f1284ac5
commit
b9f5e9be1c
|
@ -160,6 +160,10 @@ public abstract class BaseTypeInference<T> {
|
|||
|
||||
protected abstract T elementType(T t);
|
||||
|
||||
protected T methodReturnType(MethodReference methodRef) {
|
||||
return mapType(methodRef.getReturnType());
|
||||
}
|
||||
|
||||
private class InitialTypeVisitor extends AbstractInstructionVisitor {
|
||||
private GraphBuilder graphBuilder;
|
||||
private GraphBuilder arrayGraphBuilder;
|
||||
|
@ -280,7 +284,7 @@ public abstract class BaseTypeInference<T> {
|
|||
|
||||
@Override
|
||||
public void visit(InvokeInstruction insn) {
|
||||
type(insn.getReceiver(), insn.getMethod().getReturnType());
|
||||
type(insn.getReceiver(), methodReturnType(insn.getMethod()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -338,5 +342,11 @@ public abstract class BaseTypeInference<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void type(Variable target, T type) {
|
||||
if (target != null && type != null) {
|
||||
types[target.getIndex()] = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@ class JSClassProcessor {
|
|||
|
||||
void processProgram(MethodHolder methodToProcess) {
|
||||
setCurrentProgram(methodToProcess.getProgram());
|
||||
types = new JSTypeInference(typeHelper, program, methodToProcess.getReference());
|
||||
types = new JSTypeInference(typeHelper, classSource, program, methodToProcess.getReference());
|
||||
types.ensure();
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
var block = program.basicBlockAt(i);
|
||||
|
@ -565,7 +565,8 @@ class JSClassProcessor {
|
|||
newInvoke.setArguments(newArgs.toArray(new Variable[0]));
|
||||
replacement.add(newInvoke);
|
||||
if (result != null) {
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), returnByRef);
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), returnByRef,
|
||||
canBeOnlyJava(invoke.getReceiver()));
|
||||
copyVar(result, invoke.getReceiver(), invoke.getLocation());
|
||||
}
|
||||
|
||||
|
@ -585,7 +586,8 @@ class JSClassProcessor {
|
|||
Variable result = invoke.getReceiver() != null ? program.createVariable() : null;
|
||||
addPropertyGet(propertyName, invoke.getInstance(), result, invoke.getLocation(), pure);
|
||||
if (result != null) {
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), false);
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), false,
|
||||
canBeOnlyJava(invoke.getReceiver()));
|
||||
copyVar(result, invoke.getReceiver(), invoke.getLocation());
|
||||
}
|
||||
return true;
|
||||
|
@ -617,7 +619,8 @@ class JSClassProcessor {
|
|||
addIndexerGet(invoke.getInstance(), marshaller.wrapArgument(callLocation, invoke.getArguments().get(0),
|
||||
method.parameterType(0), false), result, invoke.getLocation());
|
||||
if (result != null) {
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), false);
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), false,
|
||||
canBeOnlyJava(invoke.getReceiver()));
|
||||
copyVar(result, invoke.getReceiver(), invoke.getLocation());
|
||||
}
|
||||
return true;
|
||||
|
@ -665,6 +668,11 @@ class JSClassProcessor {
|
|||
return true;
|
||||
}
|
||||
|
||||
private boolean canBeOnlyJava(Variable variable) {
|
||||
var type = types.typeOf(variable);
|
||||
return type != JSType.JS && type != JSType.MIXED;
|
||||
}
|
||||
|
||||
private boolean processMethod(MethodReader method, CallLocation callLocation, InvokeInstruction invoke) {
|
||||
String name = method.getName();
|
||||
|
||||
|
@ -699,7 +707,8 @@ class JSClassProcessor {
|
|||
newInvoke.setArguments(newArguments.toArray(new Variable[0]));
|
||||
replacement.add(newInvoke);
|
||||
if (result != null) {
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), false);
|
||||
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), false,
|
||||
canBeOnlyJava(invoke.getReceiver()));
|
||||
copyVar(result, invoke.getReceiver(), invoke.getLocation());
|
||||
}
|
||||
|
||||
|
@ -880,12 +889,12 @@ class JSClassProcessor {
|
|||
replacement.clear();
|
||||
if (!callee.hasModifier(ElementModifier.STATIC)) {
|
||||
insn.setInstance(marshaller.unwrapReturnValue(location, program.variableAt(paramIndex++),
|
||||
ValueType.object(calleeRef.getClassName()), false));
|
||||
ValueType.object(calleeRef.getClassName()), false, true));
|
||||
}
|
||||
Variable[] args = new Variable[callee.parameterCount()];
|
||||
for (int i = 0; i < callee.parameterCount(); ++i) {
|
||||
args[i] = marshaller.unwrapReturnValue(location, program.variableAt(paramIndex++),
|
||||
callee.parameterType(i), false);
|
||||
callee.parameterType(i), false, true);
|
||||
}
|
||||
insn.setArguments(args);
|
||||
if (callee.getResultType() != ValueType.VOID) {
|
||||
|
|
|
@ -130,7 +130,7 @@ class JSObjectClassTransformer implements ClassHolderTransformer {
|
|||
|
||||
for (int i = 0; i < method.parameterCount(); ++i) {
|
||||
variablesToPass[i] = marshaller.unwrapReturnValue(callLocation, variablesToPass[i],
|
||||
method.parameterType(i), false);
|
||||
method.parameterType(i), false, true);
|
||||
}
|
||||
|
||||
basicBlock.addAll(marshallInstructions);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package org.teavm.jso.impl;
|
||||
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.ValueType;
|
||||
|
@ -22,10 +24,12 @@ import org.teavm.model.analysis.BaseTypeInference;
|
|||
|
||||
class JSTypeInference extends BaseTypeInference<JSType> {
|
||||
private JSTypeHelper typeHelper;
|
||||
private ClassReaderSource classes;
|
||||
|
||||
JSTypeInference(JSTypeHelper typeHelper, Program program, MethodReference reference) {
|
||||
JSTypeInference(JSTypeHelper typeHelper, ClassReaderSource classes, Program program, MethodReference reference) {
|
||||
super(program, reference);
|
||||
this.typeHelper = typeHelper;
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,4 +83,20 @@ class JSTypeInference extends BaseTypeInference<JSType> {
|
|||
protected JSType elementType(JSType jsType) {
|
||||
return jsType instanceof JSType.ArrayType ? ((JSType.ArrayType) jsType).elementType : JSType.MIXED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JSType methodReturnType(MethodReference methodRef) {
|
||||
if (!methodRef.getReturnType().isObject(Object.class)) {
|
||||
return mapType(methodRef.getReturnType());
|
||||
}
|
||||
return isJsMethod(methodRef) ? JSType.MIXED : JSType.JAVA;
|
||||
}
|
||||
|
||||
private boolean isJsMethod(MethodReference methodRef) {
|
||||
if (typeHelper.isJavaScriptClass(methodRef.getClassName())) {
|
||||
return true;
|
||||
}
|
||||
var method = classes.resolveImplementation(methodRef);
|
||||
return method != null && method.getAnnotations().get(JSBody.class.getName()) != null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,10 @@ import org.teavm.model.instructions.InvokeInstruction;
|
|||
import org.teavm.model.instructions.StringConstantInstruction;
|
||||
|
||||
class JSValueMarshaller {
|
||||
private static final MethodReference JS_TO_JAVA = new MethodReference(JSWrapper.class, "jsToJava",
|
||||
JSObject.class, Object.class);
|
||||
private static final MethodReference LIGHTWEIGHT_JS_TO_JAVA = new MethodReference(JSWrapper.class,
|
||||
"dependencyJsToJava", JSObject.class, Object.class);
|
||||
private static final ValueType stringType = ValueType.parse(String.class);
|
||||
private ReferenceCache referenceCache = new ReferenceCache();
|
||||
private Diagnostics diagnostics;
|
||||
|
@ -225,7 +229,8 @@ class JSValueMarshaller {
|
|||
return JSMethods.ARRAY_WRAPPER;
|
||||
}
|
||||
|
||||
Variable unwrapReturnValue(CallLocation location, Variable var, ValueType type, boolean byRef) {
|
||||
Variable unwrapReturnValue(CallLocation location, Variable var, ValueType type, boolean byRef,
|
||||
boolean strictJava) {
|
||||
if (byRef) {
|
||||
return unwrapByRef(location, var, type);
|
||||
}
|
||||
|
@ -237,7 +242,7 @@ class JSValueMarshaller {
|
|||
return unwrapFunctor(location, var, cls);
|
||||
}
|
||||
}
|
||||
return unwrap(location, var, type);
|
||||
return unwrap(location, var, type, strictJava);
|
||||
}
|
||||
|
||||
private Variable unwrapByRef(CallLocation location, Variable var, ValueType type) {
|
||||
|
@ -263,7 +268,7 @@ class JSValueMarshaller {
|
|||
return invokeMethod(location, JSMethods.DATA_TO_ARRAY, var);
|
||||
}
|
||||
|
||||
Variable unwrap(CallLocation location, Variable var, ValueType type) {
|
||||
Variable unwrap(CallLocation location, Variable var, ValueType type, boolean strictJava) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
|
@ -296,7 +301,7 @@ class JSValueMarshaller {
|
|||
var wrapNative = new InvokeInstruction();
|
||||
wrapNative.setLocation(location.getSourceLocation());
|
||||
wrapNative.setType(InvocationType.SPECIAL);
|
||||
wrapNative.setMethod(new MethodReference(JSWrapper.class, "jsToJava", JSObject.class, Object.class));
|
||||
wrapNative.setMethod(strictJava ? JS_TO_JAVA : LIGHTWEIGHT_JS_TO_JAVA);
|
||||
wrapNative.setArguments(var);
|
||||
wrapNative.setReceiver(program.createVariable());
|
||||
replacement.add(wrapNative);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.jso.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.backend.javascript.rendering.Precedence;
|
||||
import org.teavm.backend.javascript.spi.Injector;
|
||||
import org.teavm.backend.javascript.spi.InjectorContext;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
|
@ -36,11 +37,17 @@ public class JSWrapperGenerator implements Injector, DependencyPlugin {
|
|||
case "dependencyJsToJava":
|
||||
case "wrapperToJs":
|
||||
case "jsToWrapper":
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.writeExpr(context.getArgument(0), context.getPrecedence());
|
||||
break;
|
||||
case "isJava":
|
||||
if (context.getPrecedence().ordinal() >= Precedence.COMPARISON.ordinal()) {
|
||||
context.getWriter().append("(");
|
||||
}
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append(" instanceof ").append("$rt_objcls").append("()");
|
||||
if (context.getPrecedence().ordinal() >= Precedence.COMPARISON.ordinal()) {
|
||||
context.getWriter().append(")");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -232,10 +232,12 @@ public class JSWrapperTest {
|
|||
@Test
|
||||
public void passJavaToJS() {
|
||||
var a = processObject(new A(23));
|
||||
assertEquals("A(23)", a.toString());
|
||||
assertTrue(a instanceof A);
|
||||
assertEquals(23, ((A) a).getX());
|
||||
|
||||
a = processObject(JSString.valueOf("qwe"));
|
||||
assertEquals("qwe", a.toString());
|
||||
assertTrue(a instanceof JSString);
|
||||
assertEquals("qwe", ((JSString) a).stringValue());
|
||||
|
||||
|
@ -263,5 +265,10 @@ public class JSWrapperTest {
|
|||
int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "A(" + x + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user