Mercurial > hg > truffle
changeset 18465:f0a8b72315c1
Move ResolvedJavaField#read[Constant]Value and getMethodHandleAccess() to ConstantReflectionProvider
line wrap: on
line diff
--- a/CHANGELOG.md Wed Nov 19 16:06:49 2014 +0100 +++ b/CHANGELOG.md Wed Nov 19 17:00:12 2014 +0100 @@ -4,6 +4,7 @@ ### Graal * Changed name suite specification from `mx/projects.py` to `mx/suite.py`. * Changed semantics (and signature) of `ResolvedJavaType#resolveMethod()` (old behavior available via `resolveConcreteMethod()`). +* Moved `ResolvedJavaField#read[Constant]Value` and `getMethodHandleAccess()` to `ConstantReflectionProvider`. * ... ### Truffle
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaField.java Wed Nov 19 17:00:12 2014 +0100 @@ -78,7 +78,7 @@ if (isStatic(field.getModifiers())) { try { Object expected = field.get(null); - Object actual = snippetReflection.asBoxedValue(e.getValue().readConstantValue(null)); + Object actual = snippetReflection.asBoxedValue(constantReflection.readConstantFieldValue(e.getValue(), null)); assertEquals(expected, actual); } catch (IllegalArgumentException | IllegalAccessException e1) { } @@ -86,7 +86,7 @@ try { Object receiver = field.getDeclaringClass().newInstance(); Object expected = field.get(receiver); - Object actual = snippetReflection.asBoxedValue(e.getValue().readConstantValue(snippetReflection.forObject(receiver))); + Object actual = snippetReflection.asBoxedValue(constantReflection.readConstantFieldValue(e.getValue(), snippetReflection.forObject(receiver))); assertEquals(expected, actual); } catch (InstantiationException | IllegalArgumentException | IllegalAccessException e1) { } @@ -95,13 +95,13 @@ ResolvedJavaField field = metaAccess.lookupJavaField(getClass().getDeclaredField("stringField")); for (Object receiver : new Object[]{this, null, new String()}) { - JavaConstant value = field.readConstantValue(snippetReflection.forObject(receiver)); + JavaConstant value = constantReflection.readConstantFieldValue(field, snippetReflection.forObject(receiver)); assertNull(value); } ResolvedJavaField constField = metaAccess.lookupJavaField(getClass().getDeclaredField("constantStringField")); for (Object receiver : new Object[]{this, null, new String()}) { - JavaConstant value = constField.readConstantValue(snippetReflection.forObject(receiver)); + JavaConstant value = constantReflection.readConstantFieldValue(constField, snippetReflection.forObject(receiver)); if (value != null) { Object expected = "constantField"; assertTrue(snippetReflection.asObject(value) == expected); @@ -117,7 +117,7 @@ if (isStatic(field.getModifiers())) { try { Object expected = field.get(null); - Object actual = snippetReflection.asBoxedValue(e.getValue().readValue(null)); + Object actual = snippetReflection.asBoxedValue(constantReflection.readFieldValue(e.getValue(), null)); assertEquals(expected, actual); } catch (IllegalArgumentException | IllegalAccessException e1) { } @@ -131,7 +131,7 @@ ResolvedJavaField rf = metaAccess.lookupJavaField(f); Object receiver = isStatic(f.getModifiers()) ? null : testString; Object expected = f.get(receiver); - Object actual = snippetReflection.asBoxedValue(rf.readValue(receiver == null ? null : snippetReflection.forObject(receiver))); + Object actual = snippetReflection.asBoxedValue(constantReflection.readFieldValue(rf, receiver == null ? null : snippetReflection.forObject(receiver))); assertEquals(expected, actual); } }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantReflectionProvider.java Wed Nov 19 17:00:12 2014 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.api.meta; +import java.lang.invoke.*; + /** * Reflection operations on values represented as {@linkplain JavaConstant constants}. All methods * in this interface require the VM to access the actual object encapsulated in {@link Kind#Object @@ -54,6 +56,31 @@ JavaConstant readArrayElement(JavaConstant array, int index); /** + * Gets the constant value of this field. Note that a {@code static final} field may not be + * considered constant if its declaring class is not yet initialized or if it is a well known + * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}). + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @return the constant value of this field or {@code null} if this field is not considered + * constant by the runtime + */ + JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver); + + /** + * Gets the current value of this field for a given object, if available. There is no guarantee + * that the same value will be returned by this method for a field unless the field is + * considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant) constant} by + * the runtime. + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @return the value of this field or {@code null} if the value is not available (e.g., because + * the field holder is not yet initialized). + */ + JavaConstant readFieldValue(JavaField field, JavaConstant receiver); + + /** * Reads a value of this kind using a base address and a displacement. No bounds checking or * type checking is performed. Returns {@code null} if the value is not available at this point. * @@ -112,4 +139,9 @@ * constant does not encapsulate a class, or if the type is not available at this point. */ ResolvedJavaType asJavaType(JavaConstant constant); + + /** + * Gets access to the internals of {@link MethodHandle}. + */ + MethodHandleAccessProvider getMethodHandleAccess(); }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Wed Nov 19 17:00:12 2014 +0100 @@ -22,7 +22,6 @@ */ package com.oracle.graal.api.meta; -import java.lang.invoke.*; import java.lang.reflect.*; /** @@ -79,11 +78,6 @@ long getMemorySize(JavaConstant constant); /** - * Gets access to the internals of {@link MethodHandle}. - */ - MethodHandleAccessProvider getMethodHandleAccess(); - - /** * Parses a <a * href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3">method * descriptor</a> into a {@link Signature}. The behavior of this method is undefined if the
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Wed Nov 19 17:00:12 2014 +0100 @@ -83,7 +83,7 @@ ResolvedJavaField[] instanceFields = type.getInstanceFields(true); for (ResolvedJavaField f : instanceFields) { if (f.getKind() == Kind.Object) { - JavaConstant value = f.readValue(c); + JavaConstant value = constantReflection.readFieldValue(f, c); pushConstant(marked, stack, value); } }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaField.java Wed Nov 19 17:00:12 2014 +0100 @@ -51,30 +51,6 @@ boolean isSynthetic(); /** - * Gets the constant value of this field. Note that a {@code static final} field may not be - * considered constant if its declaring class is not yet initialized or if it is a well known - * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}). - * - * @param receiver object from which this field's value is to be read. This value is ignored if - * this field is static. - * @return the constant value of this field or {@code null} if this field is not considered - * constant by the runtime - */ - JavaConstant readConstantValue(JavaConstant receiver); - - /** - * Gets the current value of this field for a given object, if available. There is no guarantee - * that the same value will be returned by this method for a field unless the field is - * considered to be {@linkplain #readConstantValue(JavaConstant) constant} by the runtime. - * - * @param receiver object from which this field's value is to be read. This value is ignored if - * this field is static. - * @return the value of this field or {@code null} if the value is not available (e.g., because - * the field holder is not yet initialized). - */ - JavaConstant readValue(JavaConstant receiver); - - /** * Returns the {@link ResolvedJavaType} object representing the class or interface that declares * this field. */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Wed Nov 19 17:00:12 2014 +0100 @@ -98,7 +98,7 @@ * the VM replicates them for every signature that they are actually used for. * Therefore, we cannot use the usual annotation-driven mechanism to define the */ - if (MethodHandleNode.lookupMethodHandleIntrinsic(method, providers.getMetaAccess().getMethodHandleAccess()) != null) { + if (MethodHandleNode.lookupMethodHandleIntrinsic(method, providers.getConstantReflection().getMethodHandleAccess()) != null) { return MethodHandleNode.class; } } @@ -119,8 +119,8 @@ @Override protected void afterParsing(StructuredGraph graph) { MetaAccessProvider metaAccess = replacements.providers.getMetaAccess(); - new WordTypeVerificationPhase(metaAccess, replacements.snippetReflection, replacements.target.wordKind).apply(graph); - new HotSpotWordTypeRewriterPhase(metaAccess, replacements.snippetReflection, replacements.target.wordKind).apply(graph); + new WordTypeVerificationPhase(metaAccess, replacements.snippetReflection, replacements.providers.getConstantReflection(), replacements.target.wordKind).apply(graph); + new HotSpotWordTypeRewriterPhase(metaAccess, replacements.snippetReflection, replacements.providers.getConstantReflection(), replacements.target.wordKind).apply(graph); } } }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Wed Nov 19 17:00:12 2014 +0100 @@ -22,24 +22,39 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.compiler.common.UnsafeAccess.*; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import java.lang.reflect.*; +import java.util.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.options.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; +import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; /** * HotSpot implementation of {@link ConstantReflectionProvider}. */ public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider { + private static final String SystemClassName = "Ljava/lang/System;"; protected final HotSpotGraalRuntime runtime; + protected final HotSpotMethodHandleAccessProvider methodHandleAccess; public HotSpotConstantReflectionProvider(HotSpotGraalRuntime runtime) { this.runtime = runtime; + this.methodHandleAccess = new HotSpotMethodHandleAccessProvider(this); + } + + public MethodHandleAccessProvider getMethodHandleAccess() { + return methodHandleAccess; } @Override @@ -251,4 +266,195 @@ } return null; } + + /** + * {@inheritDoc} + * <p> + * The {@code value} field in {@link OptionValue} is considered constant if the type of + * {@code receiver} is (assignable to) {@link StableOptionValue}. + */ + public JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver) { + assert !ImmutableCode.getValue() || isCalledForSnippets() : receiver; + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + + if (receiver == null) { + assert hotspotField.isStatic(); + if (hotspotField.isFinal()) { + ResolvedJavaType holder = hotspotField.getDeclaringClass(); + if (holder.isInitialized() && !holder.getName().equals(SystemClassName) && isEmbeddable(hotspotField)) { + return readFieldValue(field, receiver); + } + } + } else { + /* + * for non-static final fields, we must assume that they are only initialized if they + * have a non-default value. + */ + assert !hotspotField.isStatic(); + Object object = receiver.isNull() ? null : ((HotSpotObjectConstantImpl) receiver).object(); + + // Canonicalization may attempt to process an unsafe read before + // processing a guard (e.g. a null check or a type check) for this read + // so we need to check the object being read + if (object != null) { + if (hotspotField.isFinal()) { + if (hotspotField.isInObject(object)) { + JavaConstant value = readFieldValue(field, receiver); + if (!value.isDefaultForKind() || assumeNonStaticFinalDefaultFieldsAsFinal(object.getClass())) { + return value; + } + } + } else if (hotspotField.isStable()) { + if (hotspotField.isInObject(object)) { + JavaConstant value = readFieldValue(field, receiver); + if (assumeDefaultStableFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) { + return value; + } + } + } else { + Class<?> clazz = object.getClass(); + if (StableOptionValue.class.isAssignableFrom(clazz)) { + if (hotspotField.isInObject(object)) { + assert hotspotField.getName().equals("value") : "Unexpected field in " + StableOptionValue.class.getName() + " hierarchy:" + this; + StableOptionValue<?> option = (StableOptionValue<?>) object; + return HotSpotObjectConstantImpl.forObject(option.getValue()); + } + } + } + } + } + return null; + } + + public JavaConstant readFieldValue(JavaField field, JavaConstant receiver) { + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + + if (receiver == null) { + assert hotspotField.isStatic(); + HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass(); + if (holder.isInitialized()) { + return readUnsafeConstant(hotspotField.getKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset()); + } + return null; + } else { + assert !hotspotField.isStatic(); + assert receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object()); + return readUnsafeConstant(hotspotField.getKind(), receiver, hotspotField.offset()); + } + } + + /** + * Compares two {@link StackTraceElement}s for equality, ignoring differences in + * {@linkplain StackTraceElement#getLineNumber() line number}. + */ + private static boolean equalsIgnoringLine(StackTraceElement left, StackTraceElement right) { + return left.getClassName().equals(right.getClassName()) && left.getMethodName().equals(right.getMethodName()) && left.getFileName().equals(right.getFileName()); + } + + /** + * If the compiler is configured for AOT mode, + * {@link #readConstantFieldValue(JavaField, JavaConstant)} should be only called for snippets + * or replacements. + */ + private static boolean isCalledForSnippets() { + MetaAccessProvider metaAccess = runtime().getHostProviders().getMetaAccess(); + ResolvedJavaMethod makeGraphMethod = null; + ResolvedJavaMethod initMethod = null; + try { + Class<?> rjm = ResolvedJavaMethod.class; + makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, SnippetInliningPolicy.class, FrameStateProcessing.class)); + initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); + } catch (NoSuchMethodException | SecurityException e) { + throw new GraalInternalError(e); + } + StackTraceElement makeGraphSTE = makeGraphMethod.asStackTraceElement(0); + StackTraceElement initSTE = initMethod.asStackTraceElement(0); + + StackTraceElement[] stackTrace = new Exception().getStackTrace(); + for (StackTraceElement element : stackTrace) { + // Ignoring line numbers should not weaken this check too much while at + // the same time making it more robust against source code changes + if (equalsIgnoringLine(makeGraphSTE, element) || equalsIgnoringLine(initSTE, element)) { + return true; + } + } + return false; + } + + private static boolean assumeNonStaticFinalDefaultFieldsAsFinal(Class<?> clazz) { + if (TrustFinalDefaultFields.getValue()) { + return true; + } + return clazz == SnippetCounter.class || clazz == NodeClass.class; + } + + /** + * Usually {@link Stable} fields are not considered constant if the value is the + * {@link JavaConstant#isDefaultForKind default value}. For some special classes we want to + * override this behavior. + */ + private static boolean assumeDefaultStableFieldsAsFinal(Class<?> clazz) { + // HotSpotVMConfig has a lot of zero-value fields which we know are stable and want to be + // considered as constants. + if (clazz == HotSpotVMConfig.class) { + return true; + } + return false; + } + + /** + * in AOT mode, some fields should never be embedded even for snippets/replacements. + */ + private static boolean isEmbeddable(HotSpotResolvedJavaField field) { + return Embeddable.test(field); + } + + /** + * Separate out the static initialization to eliminate cycles between clinit and other locks + * that could lead to deadlock. Static code that doesn't call back into type or field machinery + * is probably ok but anything else should be made lazy. + */ + static class Embeddable { + + /** + * @return Return true if it's ok to embed the value of {@code field}. + */ + public static boolean test(HotSpotResolvedJavaField field) { + return !ImmutableCode.getValue() || !fields.contains(field); + } + + private static final List<ResolvedJavaField> fields = new ArrayList<>(); + static { + try { + MetaAccessProvider metaAccess = runtime().getHostProviders().getMetaAccess(); + fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE"))); + fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE"))); + + Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0]; + assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); + fields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache"))); + + Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0]; + assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); + fields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache"))); + + Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0]; + assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); + fields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache"))); + + Class<?> integerCacheClass = Integer.class.getDeclaredClasses()[0]; + assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); + fields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache"))); + + Class<?> longCacheClass = Long.class.getDeclaredClasses()[0]; + assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); + fields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache"))); + + fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK"))); + fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL"))); + } catch (SecurityException | NoSuchFieldException e) { + throw new GraalInternalError(e); + } + } + } }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMetaAccessProvider.java Wed Nov 19 17:00:12 2014 +0100 @@ -40,15 +40,9 @@ public class HotSpotMetaAccessProvider implements MetaAccessProvider { protected final HotSpotGraalRuntime runtime; - protected final HotSpotMethodHandleAccessProvider methodHandleAccess; public HotSpotMetaAccessProvider(HotSpotGraalRuntime runtime) { this.runtime = runtime; - methodHandleAccess = new HotSpotMethodHandleAccessProvider(); - } - - public MethodHandleAccessProvider getMethodHandleAccess() { - return methodHandleAccess; } public HotSpotResolvedJavaType lookupJavaType(Class<?> clazz) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java Wed Nov 19 17:00:12 2014 +0100 @@ -32,6 +32,12 @@ public class HotSpotMethodHandleAccessProvider implements MethodHandleAccessProvider { + private final ConstantReflectionProvider constantReflection; + + public HotSpotMethodHandleAccessProvider(ConstantReflectionProvider constantReflection) { + this.constantReflection = constantReflection; + } + /** * Lazy initialization to break class initialization cycle. Field and method lookup is only * possible after the {@link HotSpotGraalRuntime} is fully initialized. @@ -115,7 +121,7 @@ } /* Load non-public field: LambdaForm MethodHandle.form */ - JavaConstant lambdaForm = LazyInitialization.methodHandleFormField.readValue(methodHandle); + JavaConstant lambdaForm = constantReflection.readFieldValue(LazyInitialization.methodHandleFormField, methodHandle); if (lambdaForm.isNull()) { return null; } @@ -126,7 +132,7 @@ memberName = LazyInitialization.lambdaFormCompileToBytecodeMethod.invoke(lambdaForm, new JavaConstant[0]); } else { /* Load non-public field: MemberName LambdaForm.vmentry */ - memberName = LazyInitialization.lambdaFormVmentryField.readValue(lambdaForm); + memberName = constantReflection.readFieldValue(LazyInitialization.lambdaFormVmentryField, lambdaForm); } return getTargetMethod(memberName); } @@ -139,13 +145,13 @@ /** * Returns the {@link ResolvedJavaMethod} for the vmtarget of a java.lang.invoke.MemberName. */ - private static ResolvedJavaMethod getTargetMethod(JavaConstant memberName) { + private ResolvedJavaMethod getTargetMethod(JavaConstant memberName) { if (memberName.isNull()) { return null; } /* Load injected field: JVM_Method* MemberName.vmtarget */ - JavaConstant vmtarget = LazyInitialization.memberNameVmtargetField.readValue(memberName); + JavaConstant vmtarget = constantReflection.readFieldValue(LazyInitialization.memberNameVmtargetField, memberName); /* Create a method from the vmtarget method pointer. */ return HotSpotResolvedJavaMethodImpl.fromMetaspace(vmtarget.asLong()); }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Wed Nov 19 17:00:12 2014 +0100 @@ -22,23 +22,14 @@ */ package com.oracle.graal.hotspot.meta; -import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.hotspot.meta.HotSpotResolvedObjectTypeImpl.*; import java.lang.annotation.*; import java.lang.reflect.*; -import java.util.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.options.*; -import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; -import com.oracle.graal.replacements.SnippetTemplate.Arguments; /** * Represents a field in a HotSpot type. @@ -94,159 +85,6 @@ } /** - * Compares two {@link StackTraceElement}s for equality, ignoring differences in - * {@linkplain StackTraceElement#getLineNumber() line number}. - */ - private static boolean equalsIgnoringLine(StackTraceElement left, StackTraceElement right) { - return left.getClassName().equals(right.getClassName()) && left.getMethodName().equals(right.getMethodName()) && left.getFileName().equals(right.getFileName()); - } - - /** - * If the compiler is configured for AOT mode, {@link #readConstantValue(JavaConstant)} should - * be only called for snippets or replacements. - */ - private static boolean isCalledForSnippets() { - MetaAccessProvider metaAccess = runtime().getHostProviders().getMetaAccess(); - ResolvedJavaMethod makeGraphMethod = null; - ResolvedJavaMethod initMethod = null; - try { - Class<?> rjm = ResolvedJavaMethod.class; - makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, SnippetInliningPolicy.class, FrameStateProcessing.class)); - initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); - } catch (NoSuchMethodException | SecurityException e) { - throw new GraalInternalError(e); - } - StackTraceElement makeGraphSTE = makeGraphMethod.asStackTraceElement(0); - StackTraceElement initSTE = initMethod.asStackTraceElement(0); - - StackTraceElement[] stackTrace = new Exception().getStackTrace(); - for (StackTraceElement element : stackTrace) { - // Ignoring line numbers should not weaken this check too much while at - // the same time making it more robust against source code changes - if (equalsIgnoringLine(makeGraphSTE, element) || equalsIgnoringLine(initSTE, element)) { - return true; - } - } - return false; - } - - /** - * Separate out the static initialization to eliminate cycles between clinit and other locks - * that could lead to deadlock. Static code that doesn't call back into type or field machinery - * is probably ok but anything else should be made lazy. - */ - static class Embeddable { - - /** - * @return Return true if it's ok to embed the value of {@code field}. - */ - public static boolean test(HotSpotResolvedJavaField field) { - return !ImmutableCode.getValue() || !fields.contains(field); - } - - private static final List<ResolvedJavaField> fields = new ArrayList<>(); - static { - try { - MetaAccessProvider metaAccess = runtime().getHostProviders().getMetaAccess(); - fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE"))); - fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE"))); - - Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0]; - assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); - fields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache"))); - - Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0]; - assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); - fields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache"))); - - Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0]; - assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); - fields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache"))); - - Class<?> integerCacheClass = Integer.class.getDeclaredClasses()[0]; - assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); - fields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache"))); - - Class<?> longCacheClass = Long.class.getDeclaredClasses()[0]; - assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); - fields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache"))); - - fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK"))); - fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL"))); - } catch (SecurityException | NoSuchFieldException e) { - throw new GraalInternalError(e); - } - } - } - - /** - * in AOT mode, some fields should never be embedded even for snippets/replacements. - */ - private boolean isEmbeddable() { - return Embeddable.test(this); - } - - private static final String SystemClassName = "Ljava/lang/System;"; - - /** - * {@inheritDoc} - * <p> - * The {@code value} field in {@link OptionValue} is considered constant if the type of - * {@code receiver} is (assignable to) {@link StableOptionValue}. - */ - @Override - public JavaConstant readConstantValue(JavaConstant receiver) { - assert !ImmutableCode.getValue() || isCalledForSnippets() : receiver; - - if (receiver == null) { - assert isStatic(); - if (isFinal()) { - if (holder.isInitialized() && !holder.getName().equals(SystemClassName) && isEmbeddable()) { - return readValue(receiver); - } - } - } else { - /* - * for non-static final fields, we must assume that they are only initialized if they - * have a non-default value. - */ - assert !isStatic(); - Object object = receiver.isNull() ? null : ((HotSpotObjectConstantImpl) receiver).object(); - - // Canonicalization may attempt to process an unsafe read before - // processing a guard (e.g. a null check or a type check) for this read - // so we need to check the object being read - if (object != null) { - if (isFinal()) { - if (isInObject(object)) { - JavaConstant value = readValue(receiver); - if (!value.isDefaultForKind() || assumeNonStaticFinalDefaultFieldsAsFinal(object.getClass())) { - return value; - } - } - } else if (isStable()) { - if (isInObject(object)) { - JavaConstant value = readValue(receiver); - if (assumeDefaultStableFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) { - return value; - } - } - } else { - Class<?> clazz = object.getClass(); - if (StableOptionValue.class.isAssignableFrom(clazz)) { - if (isInObject(object)) { - assert getName().equals("value") : "Unexpected field in " + StableOptionValue.class.getName() + " hierarchy:" + this; - StableOptionValue<?> option = (StableOptionValue<?>) object; - return HotSpotObjectConstantImpl.forObject(option.getValue()); - } - } - } - } - } - return null; - } - - /** * Determines if a given object contains this field. * * @return true iff this is a non-static field and its declaring class is assignable from @@ -260,42 +98,6 @@ } @Override - public JavaConstant readValue(JavaConstant receiver) { - if (receiver == null) { - assert isStatic(); - if (holder.isInitialized()) { - return runtime().getHostProviders().getConstantReflection().readUnsafeConstant(getKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), offset); - } - return null; - } else { - assert !isStatic(); - assert receiver.isNonNull() && isInObject(((HotSpotObjectConstantImpl) receiver).object()); - return runtime().getHostProviders().getConstantReflection().readUnsafeConstant(getKind(), receiver, offset); - } - } - - private static boolean assumeNonStaticFinalDefaultFieldsAsFinal(Class<?> clazz) { - if (TrustFinalDefaultFields.getValue()) { - return true; - } - return clazz == SnippetCounter.class || clazz == NodeClass.class; - } - - /** - * Usually {@link Stable} fields are not considered constant if the value is the - * {@link JavaConstant#isDefaultForKind default value}. For some special classes we want to - * override this behavior. - */ - private static boolean assumeDefaultStableFieldsAsFinal(Class<?> clazz) { - // HotSpotVMConfig has a lot of zero-value fields which we know are stable and want to be - // considered as constants. - if (clazz == HotSpotVMConfig.class) { - return true; - } - return false; - } - - @Override public HotSpotResolvedObjectTypeImpl getDeclaringClass() { return holder; }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java Wed Nov 19 17:00:12 2014 +0100 @@ -91,7 +91,7 @@ ReturnNode returnNode = g.add(ReturnNode.create(boxedResult)); callNode.setNext(returnNode); - (new HotSpotWordTypeRewriterPhase(providers.getMetaAccess(), providers.getSnippetReflection(), Kind.Long)).apply(g); + (new HotSpotWordTypeRewriterPhase(providers.getMetaAccess(), providers.getSnippetReflection(), providers.getConstantReflection(), Kind.Long)).apply(g); return g; } catch (NoSuchMethodException e) { throw GraalInternalError.shouldNotReachHere("Call Stub method not found");
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java Wed Nov 19 17:00:12 2014 +0100 @@ -82,7 +82,7 @@ @Override public void simplify(SimplifierTool tool) { InvokeNode invoke; - IntrinsicMethod intrinsicMethod = lookupMethodHandleIntrinsic(targetMethod, tool.getMetaAccess().getMethodHandleAccess()); + IntrinsicMethod intrinsicMethod = lookupMethodHandleIntrinsic(targetMethod, tool.getConstantReflection().getMethodHandleAccess()); switch (intrinsicMethod) { case INVOKE_BASIC: invoke = getInvokeBasicTarget(tool, intrinsicMethod); @@ -131,7 +131,7 @@ protected InvokeNode getInvokeBasicTarget(SimplifierTool tool, IntrinsicMethod intrinsicMethod) { ValueNode methodHandleNode = getReceiver(); if (methodHandleNode.isConstant()) { - return getTargetInvokeNode(tool.getMetaAccess().getMethodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), false), intrinsicMethod); + return getTargetInvokeNode(tool.getConstantReflection().getMethodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), false), intrinsicMethod); } return null; } @@ -147,7 +147,7 @@ protected InvokeNode getLinkToTarget(SimplifierTool tool, IntrinsicMethod intrinsicMethod) { ValueNode memberNameNode = getMemberName(); if (memberNameNode.isConstant()) { - return getTargetInvokeNode(tool.getMetaAccess().getMethodHandleAccess().resolveLinkToTarget(memberNameNode.asJavaConstant()), intrinsicMethod); + return getTargetInvokeNode(tool.getConstantReflection().getMethodHandleAccess().resolveLinkToTarget(memberNameNode.asJavaConstant()), intrinsicMethod); } return null; }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java Wed Nov 19 17:00:12 2014 +0100 @@ -223,7 +223,7 @@ @Override public void rewriteWordTypes(SnippetReflectionProvider snippetReflection) { - new HotSpotWordTypeRewriterPhase(providers.getMetaAccess(), snippetReflection, providers.getCodeCache().getTarget().wordKind).apply(graph); + new HotSpotWordTypeRewriterPhase(providers.getMetaAccess(), snippetReflection, providers.getConstantReflection(), providers.getCodeCache().getTarget().wordKind).apply(graph); } }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/HotSpotWordTypeRewriterPhase.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/HotSpotWordTypeRewriterPhase.java Wed Nov 19 17:00:12 2014 +0100 @@ -43,8 +43,8 @@ private final ResolvedJavaType klassPointerType; private final ResolvedJavaType methodPointerType; - public HotSpotWordTypeRewriterPhase(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, Kind wordKind) { - super(metaAccess, snippetReflection, wordKind); + public HotSpotWordTypeRewriterPhase(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ConstantReflectionProvider constantReflection, Kind wordKind) { + super(metaAccess, snippetReflection, constantReflection, wordKind); this.klassPointerType = metaAccess.lookupJavaType(KlassPointer.class); this.methodPointerType = metaAccess.lookupJavaType(MethodPointer.class); }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java Wed Nov 19 17:00:12 2014 +0100 @@ -71,12 +71,13 @@ return null; } MetaAccessProvider metaAccess = tool.getMetaAccess(); + ConstantReflectionProvider constantReflection = tool.getConstantReflection(); if (tool.canonicalizeReads() && metaAccess != null) { - ConstantNode constant = asConstant(metaAccess, forObject); + ConstantNode constant = asConstant(metaAccess, constantReflection, forObject); if (constant != null) { return constant; } - PhiNode phi = asPhi(metaAccess, forObject); + PhiNode phi = asPhi(metaAccess, constantReflection, forObject); if (phi != null) { return phi; } @@ -90,12 +91,12 @@ /** * Gets a constant value for this load if possible. */ - public ConstantNode asConstant(MetaAccessProvider metaAccess, ValueNode forObject) { + public ConstantNode asConstant(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ValueNode forObject) { JavaConstant constant = null; if (isStatic()) { - constant = field().readConstantValue(null); + constant = constantReflection.readConstantFieldValue(field(), null); } else if (forObject.isConstant() && !forObject.isNullConstant()) { - constant = field().readConstantValue(forObject.asJavaConstant()); + constant = constantReflection.readConstantFieldValue(field(), forObject.asJavaConstant()); } if (constant != null) { return ConstantNode.forConstant(constant, metaAccess); @@ -103,12 +104,12 @@ return null; } - private PhiNode asPhi(MetaAccessProvider metaAccess, ValueNode forObject) { + private PhiNode asPhi(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ValueNode forObject) { if (!isStatic() && field.isFinal() && forObject instanceof ValuePhiNode && ((ValuePhiNode) forObject).values().filter(isNotA(ConstantNode.class)).isEmpty()) { PhiNode phi = (PhiNode) forObject; JavaConstant[] constants = new JavaConstant[phi.valueCount()]; for (int i = 0; i < phi.valueCount(); i++) { - JavaConstant constantValue = field().readConstantValue(phi.valueAt(i).asJavaConstant()); + JavaConstant constantValue = constantReflection.readConstantFieldValue(field(), phi.valueAt(i).asJavaConstant()); if (constantValue == null) { return null; }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Wed Nov 19 17:00:12 2014 +0100 @@ -182,7 +182,7 @@ * Rewrite all word types in the graph. */ public void rewriteWordTypes(SnippetReflectionProvider snippetReflection) { - new WordTypeRewriterPhase(providers.getMetaAccess(), snippetReflection, providers.getCodeCache().getTarget().wordKind).apply(graph); + new WordTypeRewriterPhase(providers.getMetaAccess(), snippetReflection, providers.getConstantReflection(), providers.getCodeCache().getTarget().wordKind).apply(graph); } /**
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Wed Nov 19 17:00:12 2014 +0100 @@ -591,8 +591,8 @@ protected void afterParsing(StructuredGraph graph) { MetaAccessProvider metaAccess = replacements.providers.getMetaAccess(); - new WordTypeVerificationPhase(metaAccess, replacements.snippetReflection, replacements.target.wordKind).apply(graph); - new WordTypeRewriterPhase(metaAccess, replacements.snippetReflection, replacements.target.wordKind).apply(graph); + new WordTypeVerificationPhase(metaAccess, replacements.snippetReflection, replacements.providers.getConstantReflection(), replacements.target.wordKind).apply(graph); + new WordTypeRewriterPhase(metaAccess, replacements.snippetReflection, replacements.providers.getConstantReflection(), replacements.target.wordKind).apply(graph); } protected Object beforeInline(@SuppressWarnings("unused") MethodCallTargetNode callTarget, @SuppressWarnings("unused") StructuredGraph callee) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java Wed Nov 19 17:00:12 2014 +0100 @@ -58,7 +58,7 @@ JavaType fieldType = field.getType(); if (field.isFinal() || field.getAnnotation(CompilationFinal.class) != null || (fieldType.getKind() == Kind.Object && (field.getAnnotation(Child.class) != null || field.getAnnotation(Children.class) != null))) { - JavaConstant constant = field.readValue(loadFieldNode.object().asJavaConstant()); + JavaConstant constant = constantReflection.readFieldValue(field, loadFieldNode.object().asJavaConstant()); assert verifyFieldValue(field, constant); if (constant.isNonNull() && fieldType.getKind() == Kind.Object && fieldType.getComponentType() != null && (field.getAnnotation(CompilationFinal.class) != null || field.getAnnotation(Children.class) != null)) {
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Wed Nov 19 17:00:12 2014 +0100 @@ -54,15 +54,17 @@ protected final MetaAccessProvider metaAccess; protected final SnippetReflectionProvider snippetReflection; + protected final ConstantReflectionProvider constantReflection; protected final ResolvedJavaType wordBaseType; protected final ResolvedJavaType wordImplType; protected final ResolvedJavaType objectAccessType; protected final ResolvedJavaType barrieredAccessType; protected final Kind wordKind; - public WordTypeRewriterPhase(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, Kind wordKind) { + public WordTypeRewriterPhase(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ConstantReflectionProvider constantReflection, Kind wordKind) { this.metaAccess = metaAccess; this.snippetReflection = snippetReflection; + this.constantReflection = constantReflection; this.wordKind = wordKind; this.wordBaseType = metaAccess.lookupJavaType(WordBase.class); this.wordImplType = metaAccess.lookupJavaType(Word.class); @@ -134,7 +136,7 @@ * Fold constant field reads, e.g. enum constants. */ protected void rewriteLoadField(StructuredGraph graph, LoadFieldNode node) { - ConstantNode constant = node.asConstant(metaAccess, node.object()); + ConstantNode constant = node.asConstant(metaAccess, constantReflection, node.object()); if (constant != null) { node.replaceAtUsages(graph.unique(constant)); graph.removeFixed(node);
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Wed Nov 19 16:06:49 2014 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Wed Nov 19 17:00:12 2014 +0100 @@ -44,8 +44,8 @@ private final WordTypeRewriterPhase wordAccess; - public WordTypeVerificationPhase(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, Kind wordKind) { - this.wordAccess = new WordTypeRewriterPhase(metaAccess, snippetReflection, wordKind); + public WordTypeVerificationPhase(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ConstantReflectionProvider constantReflection, Kind wordKind) { + this.wordAccess = new WordTypeRewriterPhase(metaAccess, snippetReflection, constantReflection, wordKind); } @Override