1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.hotspot.meta; 24 25 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; 26 import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.ImmutableCodeLazy.isCalledForSnippets; 27 import static org.graalvm.compiler.hotspot.stubs.SnippetStub.SnippetGraphUnderConstruction; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 32 import org.graalvm.compiler.debug.GraalError; 33 import org.graalvm.compiler.graph.NodeClass; 34 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 35 import org.graalvm.compiler.options.StableOptionValue; 36 import org.graalvm.compiler.replacements.ReplacementsImpl; 37 import org.graalvm.compiler.replacements.SnippetCounter; 38 import org.graalvm.compiler.replacements.SnippetTemplate; 39 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; 40 41 import jdk.vm.ci.meta.JavaConstant; 42 import jdk.vm.ci.meta.MetaAccessProvider; 43 import jdk.vm.ci.meta.ResolvedJavaField; 44 import jdk.vm.ci.meta.ResolvedJavaMethod; 45 import jdk.vm.ci.meta.ResolvedJavaType; 46 import jdk.vm.ci.runtime.JVMCI; 47 48 /** 49 * Extends {@link HotSpotConstantFieldProvider} to override the implementation of 50 * {@link #readConstantField} with Graal specific semantics. 51 */ 52 public class HotSpotGraalConstantFieldProvider extends HotSpotConstantFieldProvider { 53 54 public HotSpotGraalConstantFieldProvider(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) { 55 super(config, metaAccess); 56 this.metaAccess = metaAccess; 57 } 58 59 @Override 60 public <T> T readConstantField(ResolvedJavaField field, ConstantFieldTool<T> tool) { 61 assert !ImmutableCode.getValue() || isCalledForSnippets(metaAccess) || SnippetGraphUnderConstruction.get() != null || 62 FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : tool.getReceiver(); 63 if (!field.isStatic() && field.getName().equals("value")) { 64 if (getStableOptionValueType().isInstance(tool.getReceiver())) { 65 JavaConstant ret = tool.readValue(); 66 return tool.foldConstant(ret); 67 } 68 } 69 70 return super.readConstantField(field, tool); 71 } 72 73 /** 74 * In AOT mode, some fields should never be embedded even for snippets/replacements. 75 */ 76 @Override 77 protected boolean isStaticFieldConstant(ResolvedJavaField field) { 78 return super.isStaticFieldConstant(field) && (!ImmutableCode.getValue() || ImmutableCodeLazy.isEmbeddable(field)); 79 } 80 81 @Override 82 protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) { 83 if (super.isFinalFieldValueConstant(field, value, tool)) { 84 return true; 85 } 86 87 if (!field.isStatic()) { 88 JavaConstant receiver = tool.getReceiver(); 89 if (getSnippetCounterType().isInstance(receiver) || getNodeClassType().isInstance(receiver)) { 90 return true; 91 } 92 } 93 94 return false; 95 } 96 97 @Override 98 protected boolean isStableFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) { 99 if (super.isStableFieldValueConstant(field, value, tool)) { 100 return true; 101 } 102 103 if (!field.isStatic()) { 104 JavaConstant receiver = tool.getReceiver(); 105 if (getHotSpotVMConfigType().isInstance(receiver)) { 106 return true; 107 } 108 } 109 110 return false; 111 } 112 113 private final MetaAccessProvider metaAccess; 114 115 private ResolvedJavaType cachedStableOptionValueType; 116 private ResolvedJavaType cachedHotSpotVMConfigType; 117 private ResolvedJavaType cachedSnippetCounterType; 118 private ResolvedJavaType cachedNodeClassType; 119 120 private ResolvedJavaType getStableOptionValueType() { 121 if (cachedStableOptionValueType == null) { 122 cachedStableOptionValueType = metaAccess.lookupJavaType(StableOptionValue.class); 123 } 124 return cachedStableOptionValueType; 125 } 126 127 private ResolvedJavaType getHotSpotVMConfigType() { 128 if (cachedHotSpotVMConfigType == null) { 129 cachedHotSpotVMConfigType = metaAccess.lookupJavaType(GraalHotSpotVMConfig.class); 130 } 131 return cachedHotSpotVMConfigType; 132 } 133 134 private ResolvedJavaType getSnippetCounterType() { 135 if (cachedSnippetCounterType == null) { 136 cachedSnippetCounterType = metaAccess.lookupJavaType(SnippetCounter.class); 137 } 138 return cachedSnippetCounterType; 139 } 140 141 private ResolvedJavaType getNodeClassType() { 142 if (cachedNodeClassType == null) { 143 cachedNodeClassType = metaAccess.lookupJavaType(NodeClass.class); 144 } 145 return cachedNodeClassType; 146 } 147 148 @SuppressWarnings("all") 149 private static boolean assertionsEnabled() { 150 boolean enabled = false; 151 assert enabled = true; 152 return enabled; 153 } 154 155 public static final ThreadLocal<Boolean> FieldReadEnabledInImmutableCode = assertionsEnabled() ? new ThreadLocal<>() : null; 156 157 /** 158 * Compares two {@link StackTraceElement}s for equality, ignoring differences in 159 * {@linkplain StackTraceElement#getLineNumber() line number}. 160 */ 161 private static boolean equalsIgnoringLine(StackTraceElement left, StackTraceElement right) { 162 return left.getClassName().equals(right.getClassName()) && left.getMethodName().equals(right.getMethodName()) && left.getFileName().equals(right.getFileName()); 163 } 164 165 /** 166 * Separate out the static initialization of {@linkplain #isEmbeddable(ResolvedJavaField) 167 * embeddable fields} to eliminate cycles between clinit and other locks that could lead to 168 * deadlock. Static code that doesn't call back into type or field machinery is probably ok but 169 * anything else should be made lazy. 170 */ 171 static class ImmutableCodeLazy { 172 173 /** 174 * If the compiler is configured for AOT mode, {@link #readConstantField} should be only 175 * called for snippets or replacements. 176 */ 177 static boolean isCalledForSnippets(MetaAccessProvider metaAccess) { 178 assert ImmutableCode.getValue(); 179 ResolvedJavaMethod makeGraphMethod = null; 180 ResolvedJavaMethod initMethod = null; 181 try { 182 Class<?> rjm = ResolvedJavaMethod.class; 183 makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm)); 184 initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); 185 } catch (NoSuchMethodException | SecurityException e) { 186 throw new GraalError(e); 187 } 188 StackTraceElement makeGraphSTE = makeGraphMethod.asStackTraceElement(0); 189 StackTraceElement initSTE = initMethod.asStackTraceElement(0); 190 191 StackTraceElement[] stackTrace = new Exception().getStackTrace(); 192 for (StackTraceElement element : stackTrace) { 193 // Ignoring line numbers should not weaken this check too much while at 194 // the same time making it more robust against source code changes 195 if (equalsIgnoringLine(makeGraphSTE, element) || equalsIgnoringLine(initSTE, element)) { 196 return true; 197 } 198 } 199 return false; 200 } 201 202 /** 203 * Determine if it's ok to embed the value of {@code field}. 204 */ 205 static boolean isEmbeddable(ResolvedJavaField field) { 206 assert ImmutableCode.getValue(); 207 return !embeddableFields.contains(field); 208 } 209 210 private static final List<ResolvedJavaField> embeddableFields = new ArrayList<>(); 211 static { 212 try { 213 MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); 214 embeddableFields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE"))); 215 embeddableFields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE"))); 216 217 Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0]; 218 assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); 219 embeddableFields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache"))); 220 221 Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0]; 222 assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); 223 embeddableFields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache"))); 224 225 Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0]; 226 assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); 227 embeddableFields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache"))); 228 229 Class<?> integerCacheClass = Integer.class.getDeclaredClasses()[0]; 230 assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); 231 embeddableFields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache"))); 232 233 Class<?> longCacheClass = Long.class.getDeclaredClasses()[0]; 234 assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); 235 embeddableFields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache"))); 236 237 embeddableFields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK"))); 238 embeddableFields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL"))); 239 } catch (SecurityException | NoSuchFieldException e) { 240 throw new GraalError(e); 241 } 242 } 243 } 244 245 }