Improve <clinit> elimination. Improve inlining in ADVANCED optimization mode

This commit is contained in:
Alexey Andreev 2020-02-14 12:46:57 +03:00
parent fecdd6613a
commit d76eeb9be3
12 changed files with 86 additions and 8 deletions

View File

@ -174,6 +174,9 @@ public class ClassInitializerAnalysis implements ClassInitializerInfo {
} }
private boolean hasSideEffects(MethodReader method) { private boolean hasSideEffects(MethodReader method) {
if (method.hasModifier(ElementModifier.ABSTRACT)) {
return false;
}
if (method.getAnnotations().get(NoSideEffects.class.getName()) != null) { if (method.getAnnotations().get(NoSideEffects.class.getName()) != null) {
return false; return false;
} }

View File

@ -71,11 +71,11 @@ public class ClassInitElimination implements MethodOptimization {
return false; return false;
} }
class Step { static class Step {
int node; int node;
Set<String> initializedClasses = new HashSet<>(); Set<String> initializedClasses = new HashSet<>();
public Step(int node) { Step(int node) {
this.node = node; this.node = node;
} }
} }

View File

@ -115,6 +115,11 @@ public class DefaultInliningStrategy implements InliningStrategy {
complexity--; complexity--;
} }
@Override
public void assign(VariableReader receiver, VariableReader assignee) {
complexity--;
}
@Override @Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method, public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) { List<? extends VariableReader> arguments, InvocationType type) {

View File

@ -15,14 +15,17 @@
*/ */
package org.teavm.jso.core; package org.teavm.jso.core;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSIndexer; import org.teavm.jso.JSIndexer;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty; import org.teavm.jso.JSProperty;
public interface JSArrayReader<T extends JSObject> extends JSObject { public interface JSArrayReader<T extends JSObject> extends JSObject {
@JSProperty @JSProperty
@NoSideEffects
int getLength(); int getLength();
@JSIndexer @JSIndexer
@NoSideEffects
T get(int index); T get(int index);
} }

View File

@ -20,6 +20,7 @@ import java.util.function.Function;
import org.teavm.backend.javascript.spi.GeneratedBy; import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.backend.javascript.spi.InjectedBy; import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.dependency.PluggableDependency; import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody; import org.teavm.jso.JSBody;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.core.JSArray; import org.teavm.jso.core.JSArray;
@ -33,83 +34,107 @@ final class JS {
} }
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject arrayData(Object array); public static native JSObject arrayData(Object array);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class) @PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native byte[] dataToByteArray(JSObject obj); public static native byte[] dataToByteArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class) @PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native char[] dataToCharArray(JSObject obj); public static native char[] dataToCharArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class) @PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native short[] dataToShortArray(JSObject obj); public static native short[] dataToShortArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class) @PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native int[] dataToIntArray(JSObject obj); public static native int[] dataToIntArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class) @PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native float[] dataToFloatArray(JSObject obj); public static native float[] dataToFloatArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class) @PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native double[] dataToDoubleArray(JSObject obj); public static native double[] dataToDoubleArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class) @PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject[] dataToArray(JSObject obj); public static native JSObject[] dataToArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(byte value); public static native JSObject wrap(byte value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(short value); public static native JSObject wrap(short value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(int value); public static native JSObject wrap(int value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(char value); public static native JSObject wrap(char value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(float value); public static native JSObject wrap(float value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(double value); public static native JSObject wrap(double value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(boolean value); public static native JSObject wrap(boolean value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(String value); public static native JSObject wrap(String value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native byte unwrapByte(JSObject value); public static native byte unwrapByte(JSObject value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native char unwrapCharacter(JSObject value); public static native char unwrapCharacter(JSObject value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native short unwrapShort(JSObject value); public static native short unwrapShort(JSObject value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native int unwrapInt(JSObject value); public static native int unwrapInt(JSObject value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native float unwrapFloat(JSObject value); public static native float unwrapFloat(JSObject value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native double unwrapDouble(JSObject value); public static native double unwrapDouble(JSObject value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native boolean unwrapBoolean(JSObject value); public static native boolean unwrapBoolean(JSObject value);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class) @PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native String unwrapString(JSObject value); public static native String unwrapString(JSObject value);
public static <T extends JSObject> JSArray<T> wrap(T[] array) { public static <T extends JSObject> JSArray<T> wrap(T[] array) {
@ -486,10 +511,20 @@ final class JS {
@JSBody(params = { "instance", "index" }, script = "return instance[index];") @JSBody(params = { "instance", "index" }, script = "return instance[index];")
public static native JSObject get(JSObject instance, JSObject index); public static native JSObject get(JSObject instance, JSObject index);
@InjectedBy(JSNativeGenerator.class)
@JSBody(params = { "instance", "index" }, script = "return instance[index];")
@NoSideEffects
public static native JSObject getPure(JSObject instance, JSObject index);
@InjectedBy(JSNativeGenerator.class) @InjectedBy(JSNativeGenerator.class)
@JSBody(params = { "instance", "index", "obj" }, script = "instance[index] = obj;") @JSBody(params = { "instance", "index", "obj" }, script = "instance[index] = obj;")
public static native void set(JSObject instance, JSObject index, JSObject obj); public static native void set(JSObject instance, JSObject index, JSObject obj);
@InjectedBy(JSNativeGenerator.class)
@JSBody(params = { "instance", "index", "obj" }, script = "instance[index] = obj;")
@NoSideEffects
public static native void setPure(JSObject instance, JSObject index, JSObject obj);
@GeneratedBy(JSNativeGenerator.class) @GeneratedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class) @PluggableDependency(JSNativeGenerator.class)
public static native JSObject function(JSObject instance, JSObject property); public static native JSObject function(JSObject instance, JSObject property);

View File

@ -69,6 +69,7 @@ import org.teavm.model.util.ModelUtils;
import org.teavm.model.util.ProgramUtils; import org.teavm.model.util.ProgramUtils;
class JSClassProcessor { class JSClassProcessor {
private static final String NO_SIDE_EFFECTS = NoSideEffects.class.getName();
private final ClassReaderSource classSource; private final ClassReaderSource classSource;
private final JSBodyRepository repository; private final JSBodyRepository repository;
private final JavaInvocationProcessor javaInvocationProcessor; private final JavaInvocationProcessor javaInvocationProcessor;
@ -359,6 +360,7 @@ class JSClassProcessor {
} }
private boolean processProperty(MethodReader method, CallLocation callLocation, InvokeInstruction invoke) { private boolean processProperty(MethodReader method, CallLocation callLocation, InvokeInstruction invoke) {
boolean pure = method.getAnnotations().get(NO_SIDE_EFFECTS) != null;
if (isProperGetter(method)) { if (isProperGetter(method)) {
String propertyName = extractSuggestedPropertyName(method); String propertyName = extractSuggestedPropertyName(method);
if (propertyName == null) { if (propertyName == null) {
@ -366,7 +368,7 @@ class JSClassProcessor {
: cutPrefix(method.getName(), 3); : cutPrefix(method.getName(), 3);
} }
Variable result = invoke.getReceiver() != null ? program.createVariable() : null; Variable result = invoke.getReceiver() != null ? program.createVariable() : null;
addPropertyGet(propertyName, invoke.getInstance(), result, invoke.getLocation()); 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);
copyVar(result, invoke.getReceiver(), invoke.getLocation()); copyVar(result, invoke.getReceiver(), invoke.getLocation());
@ -380,7 +382,7 @@ class JSClassProcessor {
} }
Variable wrapped = marshaller.wrapArgument(callLocation, invoke.getArguments().get(0), Variable wrapped = marshaller.wrapArgument(callLocation, invoke.getArguments().get(0),
method.parameterType(0), false); method.parameterType(0), false);
addPropertySet(propertyName, invoke.getInstance(), wrapped, invoke.getLocation()); addPropertySet(propertyName, invoke.getInstance(), wrapped, invoke.getLocation(), pure);
return true; return true;
} }
diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript property " diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript property "
@ -674,22 +676,23 @@ class JSClassProcessor {
} }
private void addPropertyGet(String propertyName, Variable instance, Variable receiver, private void addPropertyGet(String propertyName, Variable instance, Variable receiver,
TextLocation location) { TextLocation location, boolean pure) {
Variable nameVar = marshaller.addStringWrap(marshaller.addString(propertyName, location), location); Variable nameVar = marshaller.addStringWrap(marshaller.addString(propertyName, location), location);
InvokeInstruction insn = new InvokeInstruction(); InvokeInstruction insn = new InvokeInstruction();
insn.setType(InvocationType.SPECIAL); insn.setType(InvocationType.SPECIAL);
insn.setMethod(JSMethods.GET); insn.setMethod(pure ? JSMethods.GET_PURE : JSMethods.GET);
insn.setReceiver(receiver); insn.setReceiver(receiver);
insn.setArguments(instance, nameVar); insn.setArguments(instance, nameVar);
insn.setLocation(location); insn.setLocation(location);
replacement.add(insn); replacement.add(insn);
} }
private void addPropertySet(String propertyName, Variable instance, Variable value, TextLocation location) { private void addPropertySet(String propertyName, Variable instance, Variable value, TextLocation location,
boolean pure) {
Variable nameVar = marshaller.addStringWrap(marshaller.addString(propertyName, location), location); Variable nameVar = marshaller.addStringWrap(marshaller.addString(propertyName, location), location);
InvokeInstruction insn = new InvokeInstruction(); InvokeInstruction insn = new InvokeInstruction();
insn.setType(InvocationType.SPECIAL); insn.setType(InvocationType.SPECIAL);
insn.setMethod(JSMethods.SET); insn.setMethod(pure ? JSMethods.SET_PURE : JSMethods.SET);
insn.setArguments(instance, nameVar, value); insn.setArguments(instance, nameVar, value);
insn.setLocation(location); insn.setLocation(location);
replacement.add(insn); replacement.add(insn);

View File

@ -26,8 +26,12 @@ import org.teavm.model.ValueType;
final class JSMethods { final class JSMethods {
public static final MethodReference GET = new MethodReference(JS.class, "get", JSObject.class, public static final MethodReference GET = new MethodReference(JS.class, "get", JSObject.class,
JSObject.class, JSObject.class); JSObject.class, JSObject.class);
public static final MethodReference GET_PURE = new MethodReference(JS.class, "getPure", JSObject.class,
JSObject.class, JSObject.class);
public static final MethodReference SET = new MethodReference(JS.class, "set", JSObject.class, JSObject.class, public static final MethodReference SET = new MethodReference(JS.class, "set", JSObject.class, JSObject.class,
JSObject.class, void.class); JSObject.class, void.class);
public static final MethodReference SET_PURE = new MethodReference(JS.class, "setPure", JSObject.class,
JSObject.class, JSObject.class, void.class);
public static final MethodReference FUNCTION = new MethodReference(JS.class, "function", JSObject.class, public static final MethodReference FUNCTION = new MethodReference(JS.class, "function", JSObject.class,
JSObject.class, JSObject.class); JSObject.class, JSObject.class);
public static final MethodReference ARRAY_DATA = new MethodReference(JS.class, "arrayData", public static final MethodReference ARRAY_DATA = new MethodReference(JS.class, "arrayData",

View File

@ -98,10 +98,12 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
writer.append(".data"); writer.append(".data");
break; break;
case "get": case "get":
case "getPure":
context.writeExpr(context.getArgument(0), Precedence.MEMBER_ACCESS); context.writeExpr(context.getArgument(0), Precedence.MEMBER_ACCESS);
renderProperty(context.getArgument(1), context); renderProperty(context.getArgument(1), context);
break; break;
case "set": case "set":
case "setPure":
context.writeExpr(context.getArgument(0), Precedence.ASSIGNMENT.next()); context.writeExpr(context.getArgument(0), Precedence.ASSIGNMENT.next());
renderProperty(context.getArgument(1), context); renderProperty(context.getArgument(1), context);
writer.ws().append('=').ws(); writer.ws().append('=').ws();

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.platform; package org.teavm.platform;
import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Unmanaged; import org.teavm.interop.Unmanaged;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty; import org.teavm.jso.JSProperty;
@ -22,13 +23,16 @@ import org.teavm.jso.JSProperty;
public interface PlatformClass extends JSObject { public interface PlatformClass extends JSObject {
@JSProperty("$meta") @JSProperty("$meta")
@Unmanaged @Unmanaged
@NoSideEffects
PlatformClassMetadata getMetadata(); PlatformClassMetadata getMetadata();
@JSProperty("classObject") @JSProperty("classObject")
@Unmanaged @Unmanaged
@NoSideEffects
void setJavaClass(PlatformObject obj); void setJavaClass(PlatformObject obj);
@JSProperty("classObject") @JSProperty("classObject")
@Unmanaged @Unmanaged
@NoSideEffects
PlatformObject getJavaClass(); PlatformObject getJavaClass();
} }

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.platform; package org.teavm.platform;
import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Unmanaged; import org.teavm.interop.Unmanaged;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty; import org.teavm.jso.JSProperty;
@ -22,40 +23,51 @@ import org.teavm.jso.JSProperty;
public interface PlatformClassMetadata extends JSObject { public interface PlatformClassMetadata extends JSObject {
@JSProperty("item") @JSProperty("item")
@Unmanaged @Unmanaged
@NoSideEffects
PlatformClass getArrayItem(); PlatformClass getArrayItem();
@JSProperty @JSProperty
@NoSideEffects
PlatformSequence<PlatformClass> getSupertypes(); PlatformSequence<PlatformClass> getSupertypes();
@JSProperty @JSProperty
@Unmanaged @Unmanaged
@NoSideEffects
PlatformClass getSuperclass(); PlatformClass getSuperclass();
@JSProperty @JSProperty
@Unmanaged @Unmanaged
@NoSideEffects
String getName(); String getName();
@JSProperty @JSProperty
@NoSideEffects
boolean isPrimitive(); boolean isPrimitive();
@JSProperty @JSProperty
@NoSideEffects
boolean isEnum(); boolean isEnum();
@JSProperty @JSProperty
@NoSideEffects
int getFlags(); int getFlags();
@JSProperty @JSProperty
@NoSideEffects
int getAccessLevel(); int getAccessLevel();
@JSProperty @JSProperty
@Unmanaged @Unmanaged
@NoSideEffects
String getSimpleName(); String getSimpleName();
@JSProperty @JSProperty
@Unmanaged @Unmanaged
@NoSideEffects
PlatformClass getEnclosingClass(); PlatformClass getEnclosingClass();
@JSProperty @JSProperty
@Unmanaged @Unmanaged
@NoSideEffects
PlatformClass getDeclaringClass(); PlatformClass getDeclaringClass();
} }

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.platform; package org.teavm.platform;
import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Unmanaged; import org.teavm.interop.Unmanaged;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty; import org.teavm.jso.JSProperty;
@ -22,13 +23,16 @@ import org.teavm.jso.JSProperty;
public interface PlatformObject extends JSObject { public interface PlatformObject extends JSObject {
@JSProperty("constructor") @JSProperty("constructor")
@Unmanaged @Unmanaged
@NoSideEffects
PlatformClass getPlatformClass(); PlatformClass getPlatformClass();
@JSProperty("$id$") @JSProperty("$id$")
@Unmanaged @Unmanaged
@NoSideEffects
int getId(); int getId();
@JSProperty("$id$") @JSProperty("$id$")
@Unmanaged @Unmanaged
@NoSideEffects
void setId(int id); void setId(int id);
} }

View File

@ -17,12 +17,14 @@ package org.teavm.platform;
import org.teavm.backend.javascript.spi.InjectedBy; import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.dependency.PluggableDependency; import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSObject; import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty; import org.teavm.jso.JSProperty;
import org.teavm.platform.plugin.PlatformQueueGenerator; import org.teavm.platform.plugin.PlatformQueueGenerator;
public abstract class PlatformQueue<T> implements JSObject { public abstract class PlatformQueue<T> implements JSObject {
@JSProperty @JSProperty
@NoSideEffects
public abstract int getLength(); public abstract int getLength();
public final boolean isEmpty() { public final boolean isEmpty() {
@ -47,5 +49,6 @@ public abstract class PlatformQueue<T> implements JSObject {
@InjectedBy(PlatformQueueGenerator.class) @InjectedBy(PlatformQueueGenerator.class)
@PluggableDependency(PlatformQueueGenerator.class) @PluggableDependency(PlatformQueueGenerator.class)
@NoSideEffects
private static native <S> S unwrap(PlatformObject obj); private static native <S> S unwrap(PlatformObject obj);
} }