JavaConstantFieldProvider.java revision 12657:6ef01bd40ce2
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 */
23package org.graalvm.compiler.core.common.spi;
24
25import org.graalvm.compiler.debug.GraalError;
26import org.graalvm.compiler.options.Option;
27import org.graalvm.compiler.options.OptionValue;
28
29import jdk.vm.ci.meta.JavaConstant;
30import jdk.vm.ci.meta.JavaType;
31import jdk.vm.ci.meta.MetaAccessProvider;
32import jdk.vm.ci.meta.ResolvedJavaField;
33import jdk.vm.ci.meta.ResolvedJavaType;
34
35/**
36 * Utility for default constant folding semantics for Java fields.
37 */
38public 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}
148