Improve <clinit> elimination:

* Generate clinit instruction instead of calling <clinit>
  directly
* Rename annotation that indicates absence of side effects
* Don't apply this annotation automatically to all JSBody methods
This commit is contained in:
Alexey Andreev 2019-03-24 12:54:06 +03:00
parent b8c73ae00c
commit f33c90f778
19 changed files with 83 additions and 57 deletions

View File

@ -41,7 +41,7 @@ import org.teavm.classlib.java.lang.reflect.TModifier;
import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.Address;
import org.teavm.interop.DelegateTo;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Unmanaged;
import org.teavm.jso.core.JSArray;
import org.teavm.platform.Platform;
@ -210,7 +210,7 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
}
@GeneratedBy(ClassGenerator.class)
@DoesNotModifyStaticFields
@NoSideEffects
private static native void createMetadata();
public TField[] getFields() throws TSecurityException {

View File

@ -19,7 +19,7 @@ import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.classlib.impl.Base64Impl;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSIndexer;
import org.teavm.jso.JSObject;
@ -69,7 +69,7 @@ public abstract class TClassLoader extends TObject {
private static native String resourceToString(JSObject resource);
@InjectedBy(ClassLoaderNativeGenerator.class)
@DoesNotModifyStaticFields
@NoSideEffects
private static native ResourceContainer supplyResources();
interface ResourceContainer extends JSObject {

View File

@ -16,11 +16,11 @@
package org.teavm.classlib.java.lang;
import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.Import;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
@DoesNotModifyStaticFields
@NoSideEffects
public class TDouble extends TNumber implements TComparable<TDouble> {
public static final double POSITIVE_INFINITY = 1 / 0.0;
public static final double NEGATIVE_INFINITY = -POSITIVE_INFINITY;
@ -210,7 +210,7 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
return (int) (h >>> 32) ^ (int) h;
}
@DoesNotModifyStaticFields
@NoSideEffects
public static native int compare(double a, double b);
@Override
@ -228,18 +228,22 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
@JSBody(params = "v", script = "return isNaN(v);")
@Import(module = "teavm", name = "isnan")
@NoSideEffects
public static native boolean isNaN(double v);
@JSBody(script = "return NaN;")
@Import(module = "teavm", name = "TeaVM_getNaN")
@NoSideEffects
private static native double getNaN();
@JSBody(params = "v", script = "return !isFinite(v);")
@Import(module = "teavm", name = "isinf")
@NoSideEffects
public static native boolean isInfinite(double v);
@JSBody(params = "v", script = "return isFinite(v);")
@Import(module = "teavm", name = "isfinite")
@NoSideEffects
public static native boolean isFinite(double v);
public static long doubleToRawLongBits(double value) {
@ -248,10 +252,12 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
@InjectedBy(DoubleGenerator.class)
@Import(name = "teavm_reinterpretDoubleToLong")
@NoSideEffects
public static native long doubleToLongBits(double value);
@InjectedBy(DoubleGenerator.class)
@Import(name = "teavm_reinterpretLongToDouble")
@NoSideEffects
public static native double longBitsToDouble(long bits);
public static String toHexString(double d) {

View File

@ -15,8 +15,8 @@
*/
package org.teavm.classlib.java.lang;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.Import;
import org.teavm.interop.NoSideEffects;
import org.teavm.jso.JSBody;
public class TFloat extends TNumber implements TComparable<TFloat> {
@ -92,18 +92,22 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
@JSBody(params = "v", script = "return isNaN(v);")
@Import(module = "teavm", name = "isnan")
@NoSideEffects
public static native boolean isNaN(float v);
@JSBody(params = "v", script = "return !isFinite(v);")
@Import(module = "teavm", name = "isinf")
@NoSideEffects
public static native boolean isInfinite(float v);
@JSBody(params = "v", script = "return isFinite(v);")
@Import(module = "teavm", name = "isfinite")
@NoSideEffects
public static native boolean isFinite(float v);
@JSBody(script = "return NaN;")
@Import(module = "teavm", name = "TeaVM_getNaN")
@NoSideEffects
private static native float getNaN();
public static float parseFloat(TString string) throws TNumberFormatException {
@ -238,7 +242,7 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
return isInfinite(value);
}
@DoesNotModifyStaticFields
@NoSideEffects
public static native int compare(float f1, float f2);
@Override
@ -252,10 +256,12 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
@JSBody(params = "value", script = "return $rt_floatToIntBits(value);")
@Import(name = "teavm_reinterpretFloatToInt")
@NoSideEffects
public static native int floatToIntBits(float value);
@JSBody(params = "bits", script = "return $rt_intBitsToFloat(bits);")
@Import(name = "teavm_reinterpretIntToFloat")
@NoSideEffects
public static native float intBitsToFloat(int bits);
public static String toHexString(float f) {

View File

@ -17,7 +17,7 @@ package org.teavm.classlib.java.lang;
import static org.teavm.classlib.impl.IntegerUtil.toUnsignedLogRadixString;
import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.NoSideEffects;
public class TInteger extends TNumber implements TComparable<TInteger> {
public static final int SIZE = 32;
@ -252,7 +252,7 @@ public class TInteger extends TNumber implements TComparable<TInteger> {
return compare(value, other.value);
}
@DoesNotModifyStaticFields
@NoSideEffects
public static native int compare(int x, int y);
public static int numberOfLeadingZeros(int i) {
@ -358,10 +358,10 @@ public class TInteger extends TNumber implements TComparable<TInteger> {
}
@InjectedBy(IntegerNativeGenerator.class)
@DoesNotModifyStaticFields
@NoSideEffects
public static native int divideUnsigned(int dividend, int divisor);
@InjectedBy(IntegerNativeGenerator.class)
@DoesNotModifyStaticFields
@NoSideEffects
public static native int remainderUnsigned(int dividend, int divisor);
}

View File

@ -17,7 +17,7 @@ package org.teavm.classlib.java.lang;
import static org.teavm.classlib.impl.IntegerUtil.toUnsignedLogRadixString;
import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.NoSideEffects;
public class TLong extends TNumber implements TComparable<TLong> {
public static final long MIN_VALUE = -0x8000000000000000L;
@ -213,7 +213,7 @@ public class TLong extends TNumber implements TComparable<TLong> {
return other instanceof TLong && ((TLong) other).value == value;
}
@DoesNotModifyStaticFields
@NoSideEffects
public static native int compare(long a, long b);
@Override
@ -353,10 +353,10 @@ public class TLong extends TNumber implements TComparable<TLong> {
}
@GeneratedBy(LongNativeGenerator.class)
@DoesNotModifyStaticFields
@NoSideEffects
public static native long divideUnsigned(long dividend, long divisor);
@GeneratedBy(LongNativeGenerator.class)
@DoesNotModifyStaticFields
@NoSideEffects
public static native long remainderUnsigned(long dividend, long divisor);
}

View File

@ -16,10 +16,10 @@
package org.teavm.classlib.java.lang;
import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.Import;
import org.teavm.interop.NoSideEffects;
@DoesNotModifyStaticFields
@NoSideEffects
public final class TMath extends TObject {
public static final double E = 2.71828182845904523536;
public static final double PI = 3.14159265358979323846;

View File

@ -21,7 +21,7 @@ import org.teavm.interop.Address;
import org.teavm.interop.Async;
import org.teavm.interop.AsyncCallback;
import org.teavm.interop.DelegateTo;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Rename;
import org.teavm.interop.Structure;
import org.teavm.interop.Superclass;
@ -273,7 +273,7 @@ public class TObject {
}
@DelegateTo("hashCodeLowLevelImpl")
@DoesNotModifyStaticFields
@NoSideEffects
private static native int hashCodeLowLevel(TObject obj);
@Unmanaged
@ -282,7 +282,7 @@ public class TObject {
}
@DelegateTo("setHashCodeLowLevelImpl")
@DoesNotModifyStaticFields
@NoSideEffects
private static native void setHashCodeLowLevel(TObject obj, int value);
@Unmanaged
@ -303,7 +303,7 @@ public class TObject {
}
@DelegateTo("identityOrMonitorLowLevel")
@DoesNotModifyStaticFields
@NoSideEffects
private native int identityOrMonitor();
private static int identityOrMonitorLowLevel(RuntimeObject object) {
@ -311,7 +311,7 @@ public class TObject {
}
@DelegateTo("setIdentityLowLevel")
@DoesNotModifyStaticFields
@NoSideEffects
native void setIdentity(int id);
private static void setIdentityLowLevel(RuntimeObject object, int id) {

View File

@ -30,7 +30,7 @@ import org.teavm.classlib.java.util.TFormatter;
import org.teavm.classlib.java.util.TLocale;
import org.teavm.classlib.java.util.regex.TPattern;
import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.NoSideEffects;
public class TString extends TObject implements TSerializable, TComparable<TString>, TCharSequence {
public static final TComparator<TString> CASE_INSENSITIVE_ORDER = (o1, o2) -> o1.compareToIgnoreCase(o2);
@ -628,7 +628,7 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
@GeneratedBy(StringNativeGenerator.class)
@PluggableDependency(StringNativeGenerator.class)
@DoesNotModifyStaticFields
@NoSideEffects
public native TString intern();
public boolean matches(String regex) {

View File

@ -25,8 +25,8 @@ import org.teavm.classlib.java.io.TPrintStream;
import org.teavm.classlib.java.lang.reflect.TArray;
import org.teavm.interop.Address;
import org.teavm.interop.DelegateTo;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.Import;
import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Unmanaged;
import org.teavm.runtime.Allocator;
import org.teavm.runtime.GC;
@ -104,7 +104,7 @@ public final class TSystem extends TObject {
@GeneratedBy(SystemNativeGenerator.class)
@DelegateTo("doArrayCopyLowLevel")
@DoesNotModifyStaticFields
@NoSideEffects
private static native void doArrayCopy(Object src, int srcPos, Object dest, int destPos, int length);
@Unmanaged
@ -126,7 +126,7 @@ public final class TSystem extends TObject {
@DelegateTo("currentTimeMillisLowLevel")
@GeneratedBy(SystemNativeGenerator.class)
@DoesNotModifyStaticFields
@NoSideEffects
public static native long currentTimeMillis();
private static long currentTimeMillisLowLevel() {

View File

@ -24,7 +24,7 @@ import org.teavm.classlib.java.lang.TNullPointerException;
import org.teavm.classlib.java.lang.TObject;
import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.DelegateTo;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Unmanaged;
import org.teavm.platform.PlatformClass;
import org.teavm.runtime.Allocator;
@ -36,7 +36,7 @@ public final class TArray extends TObject {
@GeneratedBy(ArrayNativeGenerator.class)
@PluggableDependency(ArrayNativeGenerator.class)
@DelegateTo("getLengthLowLevel")
@DoesNotModifyStaticFields
@NoSideEffects
public static native int getLength(TObject array) throws TIllegalArgumentException;
@SuppressWarnings("unused")
@ -65,7 +65,7 @@ public final class TArray extends TObject {
@GeneratedBy(ArrayNativeGenerator.class)
@DelegateTo("newInstanceLowLevel")
@DoesNotModifyStaticFields
@NoSideEffects
private static native TObject newInstanceImpl(PlatformClass componentType, int length);
@SuppressWarnings("unused")
@ -92,11 +92,11 @@ public final class TArray extends TObject {
@GeneratedBy(ArrayNativeGenerator.class)
@PluggableDependency(ArrayNativeGenerator.class)
@DoesNotModifyStaticFields
@NoSideEffects
private static native TObject getImpl(TObject array, int index);
@GeneratedBy(ArrayNativeGenerator.class)
@PluggableDependency(ArrayNativeGenerator.class)
@DoesNotModifyStaticFields
@NoSideEffects
private static native void setImpl(TObject array, int index, TObject value);
}

View File

@ -379,7 +379,7 @@ public class Renderer implements RenderingManager {
try {
MethodReader clinit = classSource.get(cls.getName()).getMethod(CLINIT_METHOD);
if (clinit != null && context.isDynamicInitializer(cls.getName())) {
if (clinit != null) {
renderCallClinit(clinit, cls);
}
if (!cls.getClassHolder().getModifiers().contains(ElementModifier.INTERFACE)) {

View File

@ -27,7 +27,7 @@ import java.util.Set;
import org.teavm.dependency.DependencyInfo;
import org.teavm.dependency.MethodDependencyInfo;
import org.teavm.dependency.ValueDependencyInfo;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.NoSideEffects;
import org.teavm.model.BasicBlockReader;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassReader;
@ -155,15 +155,7 @@ public class ClassInitializerAnalysis implements ClassInitializerInfo {
InstructionAnalyzer reader = new InstructionAnalyzer(currentClass, methodInfo);
ProgramReader program = method.getProgram();
if (program == null) {
methodInfo.anyFieldModified = true;
if (method.getAnnotations().get(DoesNotModifyStaticFields.class.getName()) != null) {
methodInfo.anyFieldModified = false;
} else {
ClassReader containingClass = classes.get(method.getOwnerName());
if (containingClass.getAnnotations().get(DoesNotModifyStaticFields.class.getName()) != null) {
methodInfo.anyFieldModified = false;
}
}
methodInfo.anyFieldModified = hasSideEffects(method);
} else {
for (BasicBlockReader block : program.getBasicBlocks()) {
block.readAllInstructions(reader);
@ -180,6 +172,18 @@ public class ClassInitializerAnalysis implements ClassInitializerInfo {
return methodInfo;
}
private boolean hasSideEffects(MethodReader method) {
if (method.getAnnotations().get(NoSideEffects.class.getName()) != null) {
return false;
}
ClassReader containingClass = classes.get(method.getOwnerName());
if (containingClass.getAnnotations().get(NoSideEffects.class.getName()) != null) {
return false;
}
return true;
}
class InstructionAnalyzer extends AbstractInstructionReader {
String currentClass;
MethodInfo methodInfo;

View File

@ -75,7 +75,6 @@ import org.teavm.model.ValueType;
import org.teavm.model.analysis.ClassInitializerAnalysis;
import org.teavm.model.analysis.ClassInitializerInfo;
import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.optimization.ArrayUnwrapMotion;
import org.teavm.model.optimization.ClassInitElimination;
import org.teavm.model.optimization.ConstantConditionElimination;
@ -523,9 +522,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
BasicBlock block = program.basicBlockAt(0);
Instruction first = block.getFirstInstruction();
for (String className : classInitializerInfo.getInitializationOrder()) {
InvokeInstruction invoke = new InvokeInstruction();
invoke.setMethod(new MethodReference(className, "<clinit>", ValueType.VOID));
first.insertPrevious(invoke);
InitClassInstruction clinit = new InitClassInstruction();
clinit.setClassName(className);
first.insertPrevious(clinit);
}
}

View File

@ -22,5 +22,5 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface DoesNotModifyStaticFields {
public @interface NoSideEffects {
}

View File

@ -32,7 +32,7 @@ import org.mozilla.javascript.ast.FunctionNode;
import org.teavm.backend.javascript.rendering.JSParser;
import org.teavm.cache.IncrementalDependencyRegistration;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.NoSideEffects;
import org.teavm.interop.Sync;
import org.teavm.jso.JSBody;
import org.teavm.jso.JSByRef;
@ -654,7 +654,9 @@ class JSClassProcessor {
MethodHolder proxyMethod = new MethodHolder(proxyRef.getDescriptor());
proxyMethod.getModifiers().add(ElementModifier.NATIVE);
proxyMethod.getModifiers().add(ElementModifier.STATIC);
proxyMethod.getAnnotations().add(new AnnotationHolder(DoesNotModifyStaticFields.class.getName()));
if (method.getAnnotations().get(NoSideEffects.class.getName()) != null) {
proxyMethod.getAnnotations().add(new AnnotationHolder(NoSideEffects.class.getName()));
}
boolean inline = repository.inlineMethods.contains(methodRef);
AnnotationHolder generatorAnnot = new AnnotationHolder(inline
? DynamicInjector.class.getName() : DynamicGenerator.class.getName());

View File

@ -21,6 +21,7 @@ import org.teavm.backend.javascript.spi.InjectedBy;
import org.teavm.dependency.PluggableDependency;
import org.teavm.interop.Address;
import org.teavm.interop.DelegateTo;
import org.teavm.interop.NoSideEffects;
import org.teavm.interop.PlatformMarker;
import org.teavm.interop.PlatformMarkers;
import org.teavm.interop.Unmanaged;
@ -42,10 +43,12 @@ public final class Platform {
@InjectedBy(PlatformGenerator.class)
@Unmanaged
@NoSideEffects
public static native PlatformObject getPlatformObject(Object obj);
@GeneratedBy(PlatformGenerator.class)
@PluggableDependency(PlatformGenerator.class)
@NoSideEffects
public static native Object clone(Object obj);
@DelegateTo("isInstanceLowLevel")
@ -61,6 +64,7 @@ public final class Platform {
}
@JSBody(params = "object", script = "return typeof object === 'undefined';")
@NoSideEffects
private static native boolean isUndefined(JSObject object);
@DelegateTo("isAssignableLowLevel")
@ -86,9 +90,11 @@ public final class Platform {
@InjectedBy(PlatformGenerator.class)
@PluggableDependency(PlatformGenerator.class)
@Unmanaged
@NoSideEffects
public static native Class<?> asJavaClass(PlatformObject obj);
@JSBody(script = "return $rt_nextId();")
@NoSideEffects
public static native int nextObjectId();
public static <T> T newInstance(PlatformClass cls) {
@ -100,6 +106,7 @@ public final class Platform {
}
@GeneratedBy(PlatformGenerator.class)
@NoSideEffects
private static native void prepareNewInstance();
@GeneratedBy(PlatformGenerator.class)
@ -108,6 +115,7 @@ public final class Platform {
@GeneratedBy(PlatformGenerator.class)
@PluggableDependency(PlatformGenerator.class)
@NoSideEffects
public static native PlatformClass lookupClass(String name);
@PluggableDependency(PlatformGenerator.class)
@ -133,6 +141,7 @@ public final class Platform {
@GeneratedBy(PlatformGenerator.class)
@PluggableDependency(PlatformGenerator.class)
@DelegateTo("getEnumConstantsLowLevel")
@NoSideEffects
public static native Enum<?>[] getEnumConstants(PlatformClass cls);
private static Enum<?>[] getEnumConstantsLowLevel(PlatformClass cls) {
@ -194,7 +203,6 @@ public final class Platform {
Window.clearTimeout(id);
}
@JSBody(script = "return [];")
public static <T> PlatformQueue<T> createQueue() {
if (isLowLevel()) {
return new LowLevelQueue<>();
@ -204,6 +212,7 @@ public final class Platform {
}
@JSBody(script = "return [];")
@NoSideEffects
private static native <T> PlatformQueue<T> createQueueJs();
public static PlatformString stringFromCharCode(int charCode) {

View File

@ -18,7 +18,7 @@ package org.teavm.platform.plugin;
import java.util.HashSet;
import java.util.Set;
import org.teavm.backend.javascript.spi.GeneratedBy;
import org.teavm.interop.DoesNotModifyStaticFields;
import org.teavm.interop.NoSideEffects;
import org.teavm.model.AccessLevel;
import org.teavm.model.AnnotationHolder;
import org.teavm.model.AnnotationValue;
@ -68,8 +68,8 @@ class MetadataProviderTransformer implements ClassHolderTransformer {
MetadataProviderNativeGenerator.class.getName())));
createMethod.getAnnotations().add(genAnnot);
ModelUtils.copyAnnotations(method.getAnnotations(), createMethod.getAnnotations());
if (createMethod.getAnnotations().get(DoesNotModifyStaticFields.class.getName()) == null) {
createMethod.getAnnotations().add(new AnnotationHolder(DoesNotModifyStaticFields.class.getName()));
if (createMethod.getAnnotations().get(NoSideEffects.class.getName()) == null) {
createMethod.getAnnotations().add(new AnnotationHolder(NoSideEffects.class.getName()));
}
AnnotationHolder refAnnot = new AnnotationHolder(MetadataProviderRef.class.getName());

View File

@ -37,7 +37,7 @@ interface TeaVMTestConfiguration<T extends TeaVMTarget> {
@Override
public void apply(TeaVM vm) {
vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE);
vm.setOptimizationLevel(TeaVMOptimizationLevel.ADVANCED);
}
@Override