mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Add inlining of JSBody scripts
This commit is contained in:
parent
49f05cbb6e
commit
9b7760c639
|
@ -16,7 +16,7 @@
|
||||||
package org.teavm.jso.plugin;
|
package org.teavm.jso.plugin;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.mozilla.javascript.ast.AstRoot;
|
import org.mozilla.javascript.ast.AstNode;
|
||||||
import org.teavm.codegen.SourceWriter;
|
import org.teavm.codegen.SourceWriter;
|
||||||
import org.teavm.javascript.spi.GeneratorContext;
|
import org.teavm.javascript.spi.GeneratorContext;
|
||||||
import org.teavm.javascript.spi.InjectorContext;
|
import org.teavm.javascript.spi.InjectorContext;
|
||||||
|
@ -28,10 +28,10 @@ import org.teavm.model.MethodReference;
|
||||||
*/
|
*/
|
||||||
class JSBodyAstEmitter implements JSBodyEmitter {
|
class JSBodyAstEmitter implements JSBodyEmitter {
|
||||||
private boolean isStatic;
|
private boolean isStatic;
|
||||||
private AstRoot ast;
|
private AstNode ast;
|
||||||
private String[] parameterNames;
|
private String[] parameterNames;
|
||||||
|
|
||||||
public JSBodyAstEmitter(boolean isStatic, AstRoot ast, String[] parameterNames) {
|
public JSBodyAstEmitter(boolean isStatic, AstNode ast, String[] parameterNames) {
|
||||||
this.isStatic = isStatic;
|
this.isStatic = isStatic;
|
||||||
this.ast = ast;
|
this.ast = ast;
|
||||||
this.parameterNames = parameterNames;
|
this.parameterNames = parameterNames;
|
||||||
|
@ -51,7 +51,6 @@ class JSBodyAstEmitter implements JSBodyEmitter {
|
||||||
}
|
}
|
||||||
astWriter.hoist(ast);
|
astWriter.hoist(ast);
|
||||||
astWriter.print(ast);
|
astWriter.print(ast);
|
||||||
context.getWriter().softNewLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.jso.plugin;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.mozilla.javascript.Token;
|
||||||
|
import org.mozilla.javascript.ast.AstNode;
|
||||||
|
import org.mozilla.javascript.ast.AstRoot;
|
||||||
|
import org.mozilla.javascript.ast.ExpressionStatement;
|
||||||
|
import org.mozilla.javascript.ast.Name;
|
||||||
|
import org.mozilla.javascript.ast.NodeVisitor;
|
||||||
|
import org.mozilla.javascript.ast.ReturnStatement;
|
||||||
|
import org.mozilla.javascript.ast.ThrowStatement;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
final class JSBodyInlineUtil {
|
||||||
|
private static final int COMPLEXITY_THRESHOLD = 20;
|
||||||
|
private JSBodyInlineUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AstNode isSuitableForInlining(MethodReference method, String[] parameters, AstRoot ast) {
|
||||||
|
AstNode statement = isSingleStatement(ast);
|
||||||
|
if (statement == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AstNode expression = getExpression(method, statement);
|
||||||
|
if (expression == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComplexityCounter complexityCounter = new ComplexityCounter();
|
||||||
|
expression.visit(complexityCounter);
|
||||||
|
if (complexityCounter.getComplexity() > COMPLEXITY_THRESHOLD) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableUsageCounter usageCounter = new VariableUsageCounter();
|
||||||
|
expression.visit(usageCounter);
|
||||||
|
for (String param : parameters) {
|
||||||
|
if (usageCounter.getUsage(param) > 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AstNode getExpression(MethodReference method, AstNode statement) {
|
||||||
|
if (method.getReturnType() == ValueType.VOID) {
|
||||||
|
if (statement instanceof ExpressionStatement) {
|
||||||
|
return ((ExpressionStatement) statement).getExpression();
|
||||||
|
} else if (statement instanceof ThrowStatement) {
|
||||||
|
return ((ThrowStatement) statement).getExpression();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (statement instanceof ReturnStatement) {
|
||||||
|
return ((ReturnStatement) statement).getReturnValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AstNode isSingleStatement(AstNode ast) {
|
||||||
|
if (ast.getFirstChild() == null || ast.getFirstChild().getNext() != null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ast.getFirstChild().getType() == Token.BLOCK) {
|
||||||
|
return isSingleStatement((AstNode) ast.getFirstChild());
|
||||||
|
}
|
||||||
|
return (AstNode) ast.getFirstChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ComplexityCounter implements NodeVisitor {
|
||||||
|
private int complexity;
|
||||||
|
|
||||||
|
public int getComplexity() {
|
||||||
|
return complexity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(AstNode node) {
|
||||||
|
++complexity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class VariableUsageCounter implements NodeVisitor {
|
||||||
|
private Map<String, Integer> usages = new HashMap<>();
|
||||||
|
|
||||||
|
public int getUsage(String varName) {
|
||||||
|
return usages.computeIfAbsent(varName, i -> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean visit(AstNode node) {
|
||||||
|
if (node instanceof Name) {
|
||||||
|
Name name = (Name) node;
|
||||||
|
if (!name.isLocalName()) {
|
||||||
|
String id = name.getIdentifier();
|
||||||
|
usages.put(id, getUsage(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,4 +29,5 @@ class JSBodyRepository {
|
||||||
public final Map<MethodReference, JSBodyEmitter> emitters = new HashMap<>();
|
public final Map<MethodReference, JSBodyEmitter> emitters = new HashMap<>();
|
||||||
public final Map<MethodReference, MethodReference> methodMap = new HashMap<>();
|
public final Map<MethodReference, MethodReference> methodMap = new HashMap<>();
|
||||||
public final Set<MethodReference> processedMethods = new HashSet<>();
|
public final Set<MethodReference> processedMethods = new HashSet<>();
|
||||||
|
public final Set<MethodReference> inlineMethods = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,11 @@ import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import org.mozilla.javascript.CompilerEnvirons;
|
import org.mozilla.javascript.CompilerEnvirons;
|
||||||
import org.mozilla.javascript.Context;
|
import org.mozilla.javascript.Context;
|
||||||
|
import org.mozilla.javascript.ast.AstNode;
|
||||||
import org.mozilla.javascript.ast.AstRoot;
|
import org.mozilla.javascript.ast.AstRoot;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.javascript.spi.GeneratedBy;
|
import org.teavm.javascript.spi.GeneratedBy;
|
||||||
|
import org.teavm.javascript.spi.InjectedBy;
|
||||||
import org.teavm.javascript.spi.Sync;
|
import org.teavm.javascript.spi.Sync;
|
||||||
import org.teavm.jso.JSBody;
|
import org.teavm.jso.JSBody;
|
||||||
import org.teavm.jso.JSFunctor;
|
import org.teavm.jso.JSFunctor;
|
||||||
|
@ -570,8 +572,14 @@ class JavascriptNativeProcessor {
|
||||||
repository.emitters.put(proxyMethod, new JSBodyBloatedEmitter(isStatic, proxyMethod,
|
repository.emitters.put(proxyMethod, new JSBodyBloatedEmitter(isStatic, proxyMethod,
|
||||||
script, parameterNames));
|
script, parameterNames));
|
||||||
} else {
|
} else {
|
||||||
repository.emitters.put(proxyMethod, new JSBodyAstEmitter(isStatic, rootNode,
|
AstNode expr = JSBodyInlineUtil.isSuitableForInlining(methodToProcess.getReference(),
|
||||||
parameterNames));
|
parameterNames, rootNode);
|
||||||
|
if (expr != null) {
|
||||||
|
repository.inlineMethods.add(methodToProcess.getReference());
|
||||||
|
} else {
|
||||||
|
expr = rootNode;
|
||||||
|
}
|
||||||
|
repository.emitters.put(proxyMethod, new JSBodyAstEmitter(isStatic, expr, parameterNames));
|
||||||
}
|
}
|
||||||
repository.methodMap.put(methodToProcess.getReference(), proxyMethod);
|
repository.methodMap.put(methodToProcess.getReference(), proxyMethod);
|
||||||
}
|
}
|
||||||
|
@ -586,7 +594,9 @@ class JavascriptNativeProcessor {
|
||||||
MethodHolder proxyMethod = new MethodHolder(proxyRef.getDescriptor());
|
MethodHolder proxyMethod = new MethodHolder(proxyRef.getDescriptor());
|
||||||
proxyMethod.getModifiers().add(ElementModifier.NATIVE);
|
proxyMethod.getModifiers().add(ElementModifier.NATIVE);
|
||||||
proxyMethod.getModifiers().add(ElementModifier.STATIC);
|
proxyMethod.getModifiers().add(ElementModifier.STATIC);
|
||||||
AnnotationHolder generatorAnnot = new AnnotationHolder(GeneratedBy.class.getName());
|
boolean inline = repository.inlineMethods.contains(methodRef);
|
||||||
|
AnnotationHolder generatorAnnot = new AnnotationHolder(inline
|
||||||
|
? InjectedBy.class.getName() : GeneratedBy.class.getName());
|
||||||
generatorAnnot.getValues().put("value",
|
generatorAnnot.getValues().put("value",
|
||||||
new AnnotationValue(ValueType.parse(JSBodyGenerator.class)));
|
new AnnotationValue(ValueType.parse(JSBodyGenerator.class)));
|
||||||
proxyMethod.getAnnotations().add(generatorAnnot);
|
proxyMethod.getAnnotations().add(generatorAnnot);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user