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;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.mozilla.javascript.ast.AstRoot;
|
||||
import org.mozilla.javascript.ast.AstNode;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.javascript.spi.GeneratorContext;
|
||||
import org.teavm.javascript.spi.InjectorContext;
|
||||
|
@ -28,10 +28,10 @@ import org.teavm.model.MethodReference;
|
|||
*/
|
||||
class JSBodyAstEmitter implements JSBodyEmitter {
|
||||
private boolean isStatic;
|
||||
private AstRoot ast;
|
||||
private AstNode ast;
|
||||
private String[] parameterNames;
|
||||
|
||||
public JSBodyAstEmitter(boolean isStatic, AstRoot ast, String[] parameterNames) {
|
||||
public JSBodyAstEmitter(boolean isStatic, AstNode ast, String[] parameterNames) {
|
||||
this.isStatic = isStatic;
|
||||
this.ast = ast;
|
||||
this.parameterNames = parameterNames;
|
||||
|
@ -51,7 +51,6 @@ class JSBodyAstEmitter implements JSBodyEmitter {
|
|||
}
|
||||
astWriter.hoist(ast);
|
||||
astWriter.print(ast);
|
||||
context.getWriter().softNewLine();
|
||||
}
|
||||
|
||||
@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, MethodReference> methodMap = new HashMap<>();
|
||||
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 org.mozilla.javascript.CompilerEnvirons;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.ast.AstNode;
|
||||
import org.mozilla.javascript.ast.AstRoot;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.javascript.spi.GeneratedBy;
|
||||
import org.teavm.javascript.spi.InjectedBy;
|
||||
import org.teavm.javascript.spi.Sync;
|
||||
import org.teavm.jso.JSBody;
|
||||
import org.teavm.jso.JSFunctor;
|
||||
|
@ -570,8 +572,14 @@ class JavascriptNativeProcessor {
|
|||
repository.emitters.put(proxyMethod, new JSBodyBloatedEmitter(isStatic, proxyMethod,
|
||||
script, parameterNames));
|
||||
} else {
|
||||
repository.emitters.put(proxyMethod, new JSBodyAstEmitter(isStatic, rootNode,
|
||||
parameterNames));
|
||||
AstNode expr = JSBodyInlineUtil.isSuitableForInlining(methodToProcess.getReference(),
|
||||
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);
|
||||
}
|
||||
|
@ -586,7 +594,9 @@ class JavascriptNativeProcessor {
|
|||
MethodHolder proxyMethod = new MethodHolder(proxyRef.getDescriptor());
|
||||
proxyMethod.getModifiers().add(ElementModifier.NATIVE);
|
||||
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",
|
||||
new AnnotationValue(ValueType.parse(JSBodyGenerator.class)));
|
||||
proxyMethod.getAnnotations().add(generatorAnnot);
|
||||
|
|
Loading…
Reference in New Issue
Block a user