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) {
if (method.hasModifier(ElementModifier.ABSTRACT)) {
return false;
}
if (method.getAnnotations().get(NoSideEffects.class.getName()) != null) {
return false;
}

View File

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

View File

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

View File

@ -15,14 +15,17 @@
*/
package org.teavm.jso.core;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSIndexer;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
public interface JSArrayReader<T extends JSObject> extends JSObject {
@JSProperty
@NoSideEffects
int getLength();
@JSIndexer
@NoSideEffects
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.InjectedBy;
import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSObject;
import org.teavm.jso.core.JSArray;
@ -33,83 +34,107 @@ final class JS {
}
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject arrayData(Object array);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native byte[] dataToByteArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native char[] dataToCharArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native short[] dataToShortArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native int[] dataToIntArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native float[] dataToFloatArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native double[] dataToDoubleArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject[] dataToArray(JSObject obj);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(byte value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(short value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(int value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(char value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(float value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(double value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(boolean value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native JSObject wrap(String value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native byte unwrapByte(JSObject value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native char unwrapCharacter(JSObject value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native short unwrapShort(JSObject value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native int unwrapInt(JSObject value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native float unwrapFloat(JSObject value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native double unwrapDouble(JSObject value);
@InjectedBy(JSNativeGenerator.class)
@NoSideEffects
public static native boolean unwrapBoolean(JSObject value);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
@NoSideEffects
public static native String unwrapString(JSObject value);
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];")
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)
@JSBody(params = { "instance", "index", "obj" }, script = "instance[index] = 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)
@PluggableDependency(JSNativeGenerator.class)
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;
class JSClassProcessor {
private static final String NO_SIDE_EFFECTS = NoSideEffects.class.getName();
private final ClassReaderSource classSource;
private final JSBodyRepository repository;
private final JavaInvocationProcessor javaInvocationProcessor;
@ -359,6 +360,7 @@ class JSClassProcessor {
}
private boolean processProperty(MethodReader method, CallLocation callLocation, InvokeInstruction invoke) {
boolean pure = method.getAnnotations().get(NO_SIDE_EFFECTS) != null;
if (isProperGetter(method)) {
String propertyName = extractSuggestedPropertyName(method);
if (propertyName == null) {
@ -366,7 +368,7 @@ class JSClassProcessor {
: cutPrefix(method.getName(), 3);
}
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) {
result = marshaller.unwrapReturnValue(callLocation, result, method.getResultType(), false);
copyVar(result, invoke.getReceiver(), invoke.getLocation());
@ -380,7 +382,7 @@ class JSClassProcessor {
}
Variable wrapped = marshaller.wrapArgument(callLocation, invoke.getArguments().get(0),
method.parameterType(0), false);
addPropertySet(propertyName, invoke.getInstance(), wrapped, invoke.getLocation());
addPropertySet(propertyName, invoke.getInstance(), wrapped, invoke.getLocation(), pure);
return true;
}
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,
TextLocation location) {
TextLocation location, boolean pure) {
Variable nameVar = marshaller.addStringWrap(marshaller.addString(propertyName, location), location);
InvokeInstruction insn = new InvokeInstruction();
insn.setType(InvocationType.SPECIAL);
insn.setMethod(JSMethods.GET);
insn.setMethod(pure ? JSMethods.GET_PURE : JSMethods.GET);
insn.setReceiver(receiver);
insn.setArguments(instance, nameVar);
insn.setLocation(location);
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);
InvokeInstruction insn = new InvokeInstruction();
insn.setType(InvocationType.SPECIAL);
insn.setMethod(JSMethods.SET);
insn.setMethod(pure ? JSMethods.SET_PURE : JSMethods.SET);
insn.setArguments(instance, nameVar, value);
insn.setLocation(location);
replacement.add(insn);

View File

@ -26,8 +26,12 @@ import org.teavm.model.ValueType;
final class JSMethods {
public static final MethodReference GET = new MethodReference(JS.class, "get", 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,
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,
JSObject.class, JSObject.class);
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");
break;
case "get":
case "getPure":
context.writeExpr(context.getArgument(0), Precedence.MEMBER_ACCESS);
renderProperty(context.getArgument(1), context);
break;
case "set":
case "setPure":
context.writeExpr(context.getArgument(0), Precedence.ASSIGNMENT.next());
renderProperty(context.getArgument(1), context);
writer.ws().append('=').ws();

View File

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

View File

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

View File

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

View File

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