mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 16:04:10 -08:00
JS: merge let statements to get better minification; rewrite some Array methods to generate less dependencies on runtime
This commit is contained in:
parent
717bbf4a57
commit
21137c57a3
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.java.lang.reflect;
|
package org.teavm.classlib.java.lang.reflect;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.Set;
|
||||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||||
import org.teavm.backend.javascript.spi.Generator;
|
import org.teavm.backend.javascript.spi.Generator;
|
||||||
import org.teavm.backend.javascript.spi.GeneratorContext;
|
import org.teavm.backend.javascript.spi.GeneratorContext;
|
||||||
|
@ -31,6 +33,55 @@ public class ArrayNativeGenerator implements Generator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
|
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
|
||||||
|
if (methodRef.getName().equals("newInstanceImpl")) {
|
||||||
|
generateNewInstance(context, writer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
template.builder(methodRef.getName()).withContext(context).build().write(writer, 0);
|
template.builder(methodRef.getName()).withContext(context).build().write(writer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateNewInstance(GeneratorContext context, SourceWriter writer) {
|
||||||
|
var dependency = context.getDependency().getMethod(new MethodReference(Array.class, "newInstance", Class.class,
|
||||||
|
int.class, Object.class));
|
||||||
|
template.builder("newInstanceImpl")
|
||||||
|
.withContext(context)
|
||||||
|
.withFragment("primitiveArrays", (w, p) -> {
|
||||||
|
w.append("switch").ws().append("(").append(context.getParameterName(1)).append(")")
|
||||||
|
.appendBlockStart();
|
||||||
|
var length = context.getParameterName(2);
|
||||||
|
var types = Set.of(dependency.getResult().getTypes());
|
||||||
|
if (types.contains("[Z")) {
|
||||||
|
writeArrayClause(w, "$rt_booleanArrayCls", "$rt_createBooleanArray", length);
|
||||||
|
}
|
||||||
|
if (types.contains("[B")) {
|
||||||
|
writeArrayClause(w, "$rt_byteArrayCls", "$rt_createByteArray", length);
|
||||||
|
}
|
||||||
|
if (types.contains("[C")) {
|
||||||
|
writeArrayClause(w, "$rt_charArrayCls", "$rt_createCharArray", length);
|
||||||
|
}
|
||||||
|
if (types.contains("[S")) {
|
||||||
|
writeArrayClause(w, "$rt_shortArrayCls", "$rt_createShortArray", length);
|
||||||
|
}
|
||||||
|
if (types.contains("[I")) {
|
||||||
|
writeArrayClause(w, "$rt_intArrayCls", "$rt_createIntArray", length);
|
||||||
|
}
|
||||||
|
if (types.contains("[J")) {
|
||||||
|
writeArrayClause(w, "$rt_longArrayCls", "$rt_createLongArray", length);
|
||||||
|
}
|
||||||
|
if (types.contains("~F")) {
|
||||||
|
writeArrayClause(w, "$rt_floatArrayCls", "$rt_createFloatArray", length);
|
||||||
|
}
|
||||||
|
if (types.contains("~D")) {
|
||||||
|
writeArrayClause(w, "$rt_doubleArrayCls", "$rt_createDoubleArray", length);
|
||||||
|
}
|
||||||
|
w.appendBlockEnd();
|
||||||
|
})
|
||||||
|
.build()
|
||||||
|
.write(writer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeArrayClause(SourceWriter writer, String test, String construct, String length) {
|
||||||
|
writer.append("case ").appendFunction(test).append(":").ws().append("return ")
|
||||||
|
.appendFunction(construct).append("(").append(length).append(");").softNewLine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,16 +23,7 @@ function getLength(array) {
|
||||||
|
|
||||||
function newInstanceImpl(type, length) {
|
function newInstanceImpl(type, length) {
|
||||||
if (type.$meta.primitive) {
|
if (type.$meta.primitive) {
|
||||||
switch (type) {
|
teavm_fragment("primitiveArrays");
|
||||||
case $rt_booleanArrayCls: return $rt_createBooleanArray(length);
|
|
||||||
case $rt_byteArrayCls: return $rt_createByteArray(length);
|
|
||||||
case $rt_shortArrayCls: return $rt_createShortArray(length);
|
|
||||||
case $rt_charArrayCls: return $rt_createCharArray(length);
|
|
||||||
case $rt_intArrayCls: return $rt_createIntArray(length);
|
|
||||||
case $rt_longArrayCls: return $rt_createLongArray(length);
|
|
||||||
case $rt_floatArrayCls: return $rt_createFloatArray(length);
|
|
||||||
case $rt_doubleArrayCls: return $rt_createDoubleArray(length);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $rt_createArray(type, length);
|
return $rt_createArray(type, length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -343,17 +343,9 @@ public class Renderer implements RenderingManager {
|
||||||
if (clinit != null && context.isDynamicInitializer(cls.getName())) {
|
if (clinit != null && context.isDynamicInitializer(cls.getName())) {
|
||||||
renderCallClinit(clinit, cls);
|
renderCallClinit(clinit, cls);
|
||||||
}
|
}
|
||||||
if (!cls.hasModifier(ElementModifier.INTERFACE)
|
|
||||||
&& !cls.hasModifier(ElementModifier.ABSTRACT)) {
|
|
||||||
for (var method : cls.getMethods()) {
|
|
||||||
if (!method.hasModifier(ElementModifier.STATIC)) {
|
|
||||||
if (method.getName().equals("<init>")) {
|
|
||||||
renderInitializer(method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var needsInitializers = !cls.hasModifier(ElementModifier.INTERFACE)
|
||||||
|
&& !cls.hasModifier(ElementModifier.ABSTRACT);
|
||||||
var hasLet = false;
|
var hasLet = false;
|
||||||
for (var method : cls.getMethods()) {
|
for (var method : cls.getMethods()) {
|
||||||
if (!filterMethod(method)) {
|
if (!filterMethod(method)) {
|
||||||
|
@ -366,6 +358,11 @@ public class Renderer implements RenderingManager {
|
||||||
writer.append(",").newLine();
|
writer.append(",").newLine();
|
||||||
}
|
}
|
||||||
renderBody(method, decompiler);
|
renderBody(method, decompiler);
|
||||||
|
if (needsInitializers && !method.hasModifier(ElementModifier.STATIC)
|
||||||
|
&& method.getName().equals("<init>")) {
|
||||||
|
writer.append(",").newLine();
|
||||||
|
renderInitializer(method);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (hasLet) {
|
if (hasLet) {
|
||||||
writer.append(";").newLine();
|
writer.append(";").newLine();
|
||||||
|
@ -699,7 +696,7 @@ public class Renderer implements RenderingManager {
|
||||||
private void renderInitializer(MethodReader method) {
|
private void renderInitializer(MethodReader method) {
|
||||||
MethodReference ref = method.getReference();
|
MethodReference ref = method.getReference();
|
||||||
writer.emitMethod(ref.getDescriptor());
|
writer.emitMethod(ref.getDescriptor());
|
||||||
writer.append("let ").appendInit(ref).ws().append("=").ws();
|
writer.appendInit(ref).ws().append("=").ws();
|
||||||
if (ref.parameterCount() != 1) {
|
if (ref.parameterCount() != 1) {
|
||||||
writer.append("(");
|
writer.append("(");
|
||||||
}
|
}
|
||||||
|
@ -724,8 +721,7 @@ public class Renderer implements RenderingManager {
|
||||||
}
|
}
|
||||||
writer.append(");").softNewLine();
|
writer.append(");").softNewLine();
|
||||||
writer.append("return " + instanceName + ";").softNewLine();
|
writer.append("return " + instanceName + ";").softNewLine();
|
||||||
writer.outdent().append("};");
|
writer.outdent().append("}");
|
||||||
writer.newLine();
|
|
||||||
writer.emitMethod(null);
|
writer.emitMethod(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.mozilla.javascript.ast.AstRoot;
|
||||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||||
import org.teavm.backend.javascript.codegen.SourceWriterSink;
|
import org.teavm.backend.javascript.codegen.SourceWriterSink;
|
||||||
import org.teavm.backend.javascript.templating.AstRemoval;
|
import org.teavm.backend.javascript.templating.AstRemoval;
|
||||||
|
import org.teavm.backend.javascript.templating.LetJoiner;
|
||||||
import org.teavm.backend.javascript.templating.RemovablePartsFinder;
|
import org.teavm.backend.javascript.templating.RemovablePartsFinder;
|
||||||
import org.teavm.backend.javascript.templating.TemplatingAstTransformer;
|
import org.teavm.backend.javascript.templating.TemplatingAstTransformer;
|
||||||
import org.teavm.backend.javascript.templating.TemplatingAstWriter;
|
import org.teavm.backend.javascript.templating.TemplatingAstWriter;
|
||||||
|
@ -105,11 +106,14 @@ public class RuntimeRenderer {
|
||||||
|
|
||||||
public void removeUnusedParts() {
|
public void removeUnusedParts() {
|
||||||
var removal = new AstRemoval(removablePartsFinder.getAllRemovableParts());
|
var removal = new AstRemoval(removablePartsFinder.getAllRemovableParts());
|
||||||
|
var letJoiner = new LetJoiner();
|
||||||
for (var part : runtimeAstParts) {
|
for (var part : runtimeAstParts) {
|
||||||
removal.visit(part);
|
removal.visit(part);
|
||||||
|
letJoiner.visit(part);
|
||||||
}
|
}
|
||||||
for (var part : epilogueAstParts) {
|
for (var part : epilogueAstParts) {
|
||||||
removal.visit(part);
|
removal.visit(part);
|
||||||
|
letJoiner.visit(part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 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.backend.javascript.templating;
|
||||||
|
|
||||||
|
import org.mozilla.javascript.ast.AstNode;
|
||||||
|
import org.mozilla.javascript.ast.AstRoot;
|
||||||
|
import org.mozilla.javascript.ast.Block;
|
||||||
|
import org.mozilla.javascript.ast.FunctionNode;
|
||||||
|
import org.mozilla.javascript.ast.IfStatement;
|
||||||
|
import org.mozilla.javascript.ast.Scope;
|
||||||
|
import org.mozilla.javascript.ast.VariableDeclaration;
|
||||||
|
import org.teavm.backend.javascript.ast.AstVisitor;
|
||||||
|
|
||||||
|
public class LetJoiner extends AstVisitor {
|
||||||
|
@Override
|
||||||
|
public void visit(Block node) {
|
||||||
|
visitMany(node);
|
||||||
|
super.visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Scope node) {
|
||||||
|
visitMany(node);
|
||||||
|
super.visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(AstRoot node) {
|
||||||
|
visitMany(node);
|
||||||
|
super.visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(FunctionNode node) {
|
||||||
|
visitMany(node.getBody());
|
||||||
|
super.visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visitMany(AstNode node) {
|
||||||
|
VariableDeclaration previous = null;
|
||||||
|
for (var childNode = node.getFirstChild(); childNode != null; ) {
|
||||||
|
var nextNode = childNode.getNext();
|
||||||
|
var child = (AstNode) childNode;
|
||||||
|
if (child instanceof VariableDeclaration) {
|
||||||
|
var decl = (VariableDeclaration) childNode;
|
||||||
|
if (previous != null && previous.getType() == decl.getType()) {
|
||||||
|
previous.getVariables().addAll(decl.getVariables());
|
||||||
|
node.removeChild(decl);
|
||||||
|
} else {
|
||||||
|
previous = decl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
previous = null;
|
||||||
|
}
|
||||||
|
childNode = nextNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -145,7 +145,7 @@ let $rt_arraycls = cls => {
|
||||||
str += "]";
|
str += "]";
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
$rt_setCloneMethod(JavaArray.prototype, function() {
|
JavaArray.prototype[teavm_javaVirtualMethod('clone()Ljava/lang/Object;')] = function() {
|
||||||
let dataCopy;
|
let dataCopy;
|
||||||
if ('slice' in this.data) {
|
if ('slice' in this.data) {
|
||||||
dataCopy = this.data.slice();
|
dataCopy = this.data.slice();
|
||||||
|
@ -156,7 +156,7 @@ let $rt_arraycls = cls => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ($rt_arraycls(this.type))(dataCopy);
|
return new ($rt_arraycls(this.type))(dataCopy);
|
||||||
});
|
};
|
||||||
let name = "[" + cls.$meta.binaryName;
|
let name = "[" + cls.$meta.binaryName;
|
||||||
JavaArray.$meta = {
|
JavaArray.$meta = {
|
||||||
item: cls,
|
item: cls,
|
||||||
|
@ -694,22 +694,8 @@ let $dbg_class = obj => {
|
||||||
cls = cls.$meta.item;
|
cls = cls.$meta.item;
|
||||||
}
|
}
|
||||||
let clsName = "";
|
let clsName = "";
|
||||||
if (cls === $rt_booleancls) {
|
if (cls.$meta.primitive) {
|
||||||
clsName = "boolean";
|
clsName = cls.$meta.name;
|
||||||
} else if (cls === $rt_bytecls) {
|
|
||||||
clsName = "byte";
|
|
||||||
} else if (cls === $rt_shortcls) {
|
|
||||||
clsName = "short";
|
|
||||||
} else if (cls === $rt_charcls) {
|
|
||||||
clsName = "char";
|
|
||||||
} else if (cls === $rt_intcls) {
|
|
||||||
clsName = "int";
|
|
||||||
} else if (cls === $rt_longcl) {
|
|
||||||
clsName = "long";
|
|
||||||
} else if (cls === $rt_floatcls) {
|
|
||||||
clsName = "float";
|
|
||||||
} else if (cls === $rt_doublecls) {
|
|
||||||
clsName = "double";
|
|
||||||
} else {
|
} else {
|
||||||
clsName = cls.$meta ? (cls.$meta.name || ("a/" + cls.name)) : "@" + cls.name;
|
clsName = cls.$meta ? (cls.$meta.name || ("a/" + cls.name)) : "@" + cls.name;
|
||||||
}
|
}
|
||||||
|
@ -853,8 +839,6 @@ let $rt_substring = (string, start, end) => {
|
||||||
}
|
}
|
||||||
let $rt_substringSink = 0;
|
let $rt_substringSink = 0;
|
||||||
|
|
||||||
let $rt_setCloneMethod = (target, method) => target[teavm_javaVirtualMethod('clone()Ljava/lang/Object;')] = method;
|
|
||||||
|
|
||||||
let $rt_cls = (cls) => teavm_javaMethod("java.lang.Class",
|
let $rt_cls = (cls) => teavm_javaMethod("java.lang.Class",
|
||||||
"getClass(Lorg/teavm/platform/PlatformClass;)Ljava/lang/Class;")(cls);
|
"getClass(Lorg/teavm/platform/PlatformClass;)Ljava/lang/Class;")(cls);
|
||||||
let $rt_str = str => str === null ? null : teavm_javaConstructor("java.lang.String", "(Ljava/lang/Object;)V")(str);
|
let $rt_str = str => str === null ? null : teavm_javaConstructor("java.lang.String", "(Ljava/lang/Object;)V")(str);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user