1 /* 2 * Copyright (c) 2016, 2018, 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 24 25 package org.graalvm.compiler.hotspot.meta; 26 27 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; 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.OptionValues; 36 import org.graalvm.compiler.replacements.SnippetCounter; 37 38 import jdk.vm.ci.meta.JavaConstant; 39 import jdk.vm.ci.meta.MetaAccessProvider; 40 import jdk.vm.ci.meta.ResolvedJavaField; 41 import jdk.vm.ci.meta.ResolvedJavaType; 42 43 /** 44 * Extends {@link HotSpotConstantFieldProvider} to override the implementation of 45 * {@link #readConstantField} with Graal specific semantics. 46 */ 47 public class HotSpotGraalConstantFieldProvider extends HotSpotConstantFieldProvider { 48 49 public HotSpotGraalConstantFieldProvider(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) { 50 super(config, metaAccess); 51 this.metaAccess = metaAccess; 52 } 53 54 @Override 55 protected boolean isStaticFieldConstant(ResolvedJavaField field, OptionValues options) { 56 return super.isStaticFieldConstant(field, options) && (!ImmutableCode.getValue(options) || isEmbeddableField(field)); 57 } 58 59 /** 60 * The set of fields whose values cannot be constant folded in ImmutableCode mode. This is 61 * volatile to support double-checked locking lazy initialization. 62 */ 63 private volatile List<ResolvedJavaField> nonEmbeddableFields; 64 65 protected boolean isEmbeddableField(ResolvedJavaField field) { 66 if (nonEmbeddableFields == null) { 67 synchronized (this) { 68 if (nonEmbeddableFields == null) { 69 List<ResolvedJavaField> fields = new ArrayList<>(); 70 try { 71 fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE"))); 72 fields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE"))); 73 74 Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0]; 75 assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); 76 fields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache"))); 77 78 Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0]; 79 assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); 80 fields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache"))); 81 82 Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0]; 83 assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); 84 fields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache"))); 85 86 Class<?> integerCacheClass = Integer.class.getDeclaredClasses()[0]; 87 assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); 88 fields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache"))); 89 90 Class<?> longCacheClass = Long.class.getDeclaredClasses()[0]; 91 assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); 92 fields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache"))); 93 94 fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK"))); 95 fields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL"))); 96 } catch (SecurityException | NoSuchFieldException e) { 97 throw new GraalError(e); 98 } 99 nonEmbeddableFields = fields; 100 } 101 } 102 } 103 return !nonEmbeddableFields.contains(field); 104 } 105 106 @Override 107 protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) { 108 if (super.isFinalFieldValueConstant(field, value, tool)) { 109 return true; 110 } 111 112 if (!field.isStatic()) { 113 JavaConstant receiver = tool.getReceiver(); 114 if (getSnippetCounterType().isInstance(receiver) || getNodeClassType().isInstance(receiver)) { 115 return true; 116 } 117 } 118 119 return false; 120 } 121 122 @Override 123 protected boolean isStableFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) { 124 if (super.isStableFieldValueConstant(field, value, tool)) { 125 return true; 126 } 127 128 if (!field.isStatic()) { 129 JavaConstant receiver = tool.getReceiver(); 130 if (getHotSpotVMConfigType().isInstance(receiver)) { 131 return true; 132 } 133 } 134 135 return false; 136 } 137 138 private final MetaAccessProvider metaAccess; 139 140 private ResolvedJavaType cachedHotSpotVMConfigType; 141 private ResolvedJavaType cachedSnippetCounterType; 142 private ResolvedJavaType cachedNodeClassType; 143 144 private ResolvedJavaType getHotSpotVMConfigType() { 145 if (cachedHotSpotVMConfigType == null) { 146 cachedHotSpotVMConfigType = metaAccess.lookupJavaType(GraalHotSpotVMConfig.class); 147 } 148 return cachedHotSpotVMConfigType; 149 } 150 151 private ResolvedJavaType getSnippetCounterType() { 152 if (cachedSnippetCounterType == null) { 153 cachedSnippetCounterType = metaAccess.lookupJavaType(SnippetCounter.class); 154 } 155 return cachedSnippetCounterType; 156 } 157 158 private ResolvedJavaType getNodeClassType() { 159 if (cachedNodeClassType == null) { 160 cachedNodeClassType = metaAccess.lookupJavaType(NodeClass.class); 161 } 162 return cachedNodeClassType; 163 } 164 }