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.core.common.spi; 26 27 import org.graalvm.compiler.debug.GraalError; 28 import org.graalvm.compiler.options.Option; 29 import org.graalvm.compiler.options.OptionKey; 30 31 import jdk.vm.ci.meta.JavaConstant; 32 import jdk.vm.ci.meta.JavaType; 33 import jdk.vm.ci.meta.MetaAccessProvider; 34 import jdk.vm.ci.meta.ResolvedJavaField; 35 import jdk.vm.ci.meta.ResolvedJavaType; 36 37 /** 38 * Utility for default constant folding semantics for Java fields. 39 */ 40 public abstract class JavaConstantFieldProvider implements ConstantFieldProvider { 41 42 static class Options { 43 @Option(help = "Determines whether to treat final fields with default values as constant.")// 44 public static final OptionKey<Boolean> TrustFinalDefaultFields = new OptionKey<>(true); 45 } 46 47 protected JavaConstantFieldProvider(MetaAccessProvider metaAccess) { 48 try { 49 this.stringValueField = metaAccess.lookupJavaField(String.class.getDeclaredField("value")); 50 this.stringHashField = metaAccess.lookupJavaField(String.class.getDeclaredField("hash")); 51 } catch (NoSuchFieldException | SecurityException e) { 52 throw new GraalError(e); 53 } 54 } 55 56 @Override 57 public <T> T readConstantField(ResolvedJavaField field, ConstantFieldTool<T> tool) { 58 if (isStableField(field, tool)) { 59 JavaConstant value = tool.readValue(); 60 if (value != null && isStableFieldValueConstant(field, value, tool)) { 61 return foldStableArray(value, field, tool); 62 } 63 } 64 if (isFinalField(field, tool)) { 65 JavaConstant value = tool.readValue(); 66 if (value != null && isFinalFieldValueConstant(field, value, tool)) { 67 return tool.foldConstant(value); 68 } 69 } 70 return null; 71 } 72 73 protected <T> T foldStableArray(JavaConstant value, ResolvedJavaField field, ConstantFieldTool<T> tool) { 74 return tool.foldStableArray(value, getArrayDimension(field.getType()), isDefaultStableField(field, tool)); 75 } 76 77 private static int getArrayDimension(JavaType type) { 78 int dimensions = 0; 79 JavaType componentType = type; 80 while ((componentType = componentType.getComponentType()) != null) { 81 dimensions++; 82 } 83 return dimensions; 84 } 85 86 private static boolean isArray(ResolvedJavaField field) { 87 JavaType fieldType = field.getType(); 88 return fieldType instanceof ResolvedJavaType && ((ResolvedJavaType) fieldType).isArray(); 89 } 90 91 @SuppressWarnings("unused") 92 protected boolean isStableFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) { 93 return !value.isDefaultForKind(); 94 } 95 96 @SuppressWarnings("unused") 97 protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) { 98 return !value.isDefaultForKind() || Options.TrustFinalDefaultFields.getValue(tool.getOptions()); 99 } 100 101 @SuppressWarnings("unused") 102 protected boolean isStableField(ResolvedJavaField field, ConstantFieldTool<?> tool) { 103 if (isSyntheticEnumSwitchMap(field)) { 104 return true; 105 } 106 if (isWellKnownImplicitStableField(field)) { 107 return true; 108 } 109 if (field.equals(stringHashField)) { 110 return true; 111 } 112 return false; 113 } 114 115 protected boolean isDefaultStableField(ResolvedJavaField field, ConstantFieldTool<?> tool) { 116 assert isStableField(field, tool); 117 if (isSyntheticEnumSwitchMap(field)) { 118 return true; 119 } 120 return false; 121 } 122 123 @SuppressWarnings("unused") 124 protected boolean isFinalField(ResolvedJavaField field, ConstantFieldTool<?> tool) { 125 return field.isFinal(); 126 } 127 128 protected boolean isSyntheticEnumSwitchMap(ResolvedJavaField field) { 129 if (field.isSynthetic() && field.isStatic() && isArray(field)) { 130 String name = field.getName(); 131 if (field.isFinal() && name.equals("$VALUES") || name.equals("ENUM$VALUES")) { 132 // generated int[] field for EnumClass::values() 133 return true; 134 } else if (name.startsWith("$SwitchMap$") || name.startsWith("$SWITCH_TABLE$")) { 135 // javac and ecj generate a static field in an inner class for a switch on an enum 136 // named $SwitchMap$p$k$g$EnumClass and $SWITCH_TABLE$p$k$g$EnumClass, respectively 137 return true; 138 } 139 } 140 return false; 141 } 142 143 private final ResolvedJavaField stringValueField; 144 private final ResolvedJavaField stringHashField; 145 146 protected boolean isWellKnownImplicitStableField(ResolvedJavaField field) { 147 return field.equals(stringValueField); 148 } 149 }