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