001/* 002 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.hotspot.meta; 024 025import static com.oracle.graal.compiler.common.GraalOptions.*; 026import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; 027import static com.oracle.graal.hotspot.meta.HotSpotGraalConstantReflectionProvider.ImmutableCodeLazy.*; 028import static com.oracle.graal.hotspot.stubs.SnippetStub.*; 029 030import java.util.*; 031 032import jdk.internal.jvmci.common.*; 033import jdk.internal.jvmci.hotspot.*; 034import jdk.internal.jvmci.meta.*; 035 036import com.oracle.graal.graph.*; 037import com.oracle.graal.replacements.*; 038import com.oracle.graal.replacements.SnippetTemplate.Arguments; 039 040/** 041 * Extends {@link HotSpotConstantReflectionProvider} to override the implementation of 042 * {@link #readConstantFieldValue(JavaField, JavaConstant)} with Graal specific semantics. 043 */ 044public class HotSpotGraalConstantReflectionProvider extends HotSpotConstantReflectionProvider { 045 046 public HotSpotGraalConstantReflectionProvider(HotSpotJVMCIRuntimeProvider runtime) { 047 super(runtime); 048 } 049 050 @Override 051 public JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver) { 052 assert !ImmutableCode.getValue() || isCalledForSnippets() || SnippetGraphUnderConstruction.get() != null || FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : receiver; 053 return super.readConstantFieldValue(field, receiver); 054 } 055 056 /** 057 * In AOT mode, some fields should never be embedded even for snippets/replacements. 058 */ 059 @Override 060 protected boolean isStaticFieldConstant(HotSpotResolvedJavaField field) { 061 return super.isStaticFieldConstant(field) && (!ImmutableCode.getValue() || ImmutableCodeLazy.isEmbeddable(field)); 062 063 } 064 065 @SuppressWarnings("all") 066 private static boolean assertionsEnabled() { 067 boolean enabled = false; 068 assert enabled = true; 069 return enabled; 070 } 071 072 public static final ThreadLocal<Boolean> FieldReadEnabledInImmutableCode = assertionsEnabled() ? new ThreadLocal<>() : null; 073 074 /** 075 * Compares two {@link StackTraceElement}s for equality, ignoring differences in 076 * {@linkplain StackTraceElement#getLineNumber() line number}. 077 */ 078 private static boolean equalsIgnoringLine(StackTraceElement left, StackTraceElement right) { 079 return left.getClassName().equals(right.getClassName()) && left.getMethodName().equals(right.getMethodName()) && left.getFileName().equals(right.getFileName()); 080 } 081 082 @Override 083 protected boolean isFinalInstanceFieldValueConstant(JavaConstant value, Class<?> receiverClass) { 084 return super.isFinalInstanceFieldValueConstant(value, receiverClass) || receiverClass == SnippetCounter.class || receiverClass == NodeClass.class; 085 } 086 087 /** 088 * {@inheritDoc} 089 * 090 * {@link HotSpotVMConfig} has a lot of zero-value fields which we know are stable and want to 091 * be considered as constants. 092 */ 093 @Override 094 protected boolean isStableInstanceFieldValueConstant(JavaConstant value, Class<? extends Object> receiverClass) { 095 return super.isStableInstanceFieldValueConstant(value, receiverClass) || receiverClass == HotSpotVMConfig.class; 096 } 097 098 /** 099 * Separate out the static initialization of 100 * {@linkplain #isEmbeddable(HotSpotResolvedJavaField) embeddable fields} to eliminate cycles 101 * between clinit and other locks that could lead to deadlock. Static code that doesn't call 102 * back into type or field machinery is probably ok but anything else should be made lazy. 103 */ 104 static class ImmutableCodeLazy { 105 106 /** 107 * If the compiler is configured for AOT mode, 108 * {@link #readConstantFieldValue(JavaField, JavaConstant)} should be only called for 109 * snippets or replacements. 110 */ 111 static boolean isCalledForSnippets() { 112 assert ImmutableCode.getValue(); 113 MetaAccessProvider metaAccess = runtime().getHostProviders().getMetaAccess(); 114 ResolvedJavaMethod makeGraphMethod = null; 115 ResolvedJavaMethod initMethod = null; 116 try { 117 Class<?> rjm = ResolvedJavaMethod.class; 118 makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm)); 119 initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class)); 120 } catch (NoSuchMethodException | SecurityException e) { 121 throw new JVMCIError(e); 122 } 123 StackTraceElement makeGraphSTE = makeGraphMethod.asStackTraceElement(0); 124 StackTraceElement initSTE = initMethod.asStackTraceElement(0); 125 126 StackTraceElement[] stackTrace = new Exception().getStackTrace(); 127 for (StackTraceElement element : stackTrace) { 128 // Ignoring line numbers should not weaken this check too much while at 129 // the same time making it more robust against source code changes 130 if (equalsIgnoringLine(makeGraphSTE, element) || equalsIgnoringLine(initSTE, element)) { 131 return true; 132 } 133 } 134 return false; 135 } 136 137 /** 138 * Determine if it's ok to embed the value of {@code field}. 139 */ 140 static boolean isEmbeddable(HotSpotResolvedJavaField field) { 141 assert ImmutableCode.getValue(); 142 return !embeddableFields.contains(field); 143 } 144 145 private static final List<ResolvedJavaField> embeddableFields = new ArrayList<>(); 146 static { 147 try { 148 MetaAccessProvider metaAccess = runtime().getHostProviders().getMetaAccess(); 149 embeddableFields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("TRUE"))); 150 embeddableFields.add(metaAccess.lookupJavaField(Boolean.class.getDeclaredField("FALSE"))); 151 152 Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0]; 153 assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); 154 embeddableFields.add(metaAccess.lookupJavaField(characterCacheClass.getDeclaredField("cache"))); 155 156 Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0]; 157 assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); 158 embeddableFields.add(metaAccess.lookupJavaField(byteCacheClass.getDeclaredField("cache"))); 159 160 Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0]; 161 assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); 162 embeddableFields.add(metaAccess.lookupJavaField(shortCacheClass.getDeclaredField("cache"))); 163 164 Class<?> integerCacheClass = Integer.class.getDeclaredClasses()[0]; 165 assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); 166 embeddableFields.add(metaAccess.lookupJavaField(integerCacheClass.getDeclaredField("cache"))); 167 168 Class<?> longCacheClass = Long.class.getDeclaredClasses()[0]; 169 assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); 170 embeddableFields.add(metaAccess.lookupJavaField(longCacheClass.getDeclaredField("cache"))); 171 172 embeddableFields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("UNASSIGNED_STACK"))); 173 embeddableFields.add(metaAccess.lookupJavaField(Throwable.class.getDeclaredField("SUPPRESSED_SENTINEL"))); 174 } catch (SecurityException | NoSuchFieldException e) { 175 throw new JVMCIError(e); 176 } 177 } 178 } 179 180}