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