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