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.meta.HotSpotGraalConstantReflectionProvider.*;
027import jdk.internal.jvmci.meta.*;
028
029import com.oracle.graal.api.replacements.*;
030import com.oracle.graal.compiler.common.type.*;
031import com.oracle.graal.graph.Node.*;
032import com.oracle.graal.graphbuilderconf.*;
033import com.oracle.graal.nodes.*;
034import com.oracle.graal.nodes.calc.*;
035import com.oracle.graal.replacements.*;
036import com.oracle.graal.word.*;
037
038/**
039 * This plugin handles the HotSpot-specific customizations of bytecode parsing:
040 * <p>
041 * {@link Word}-type rewriting for {@link GraphBuilderContext#parsingIntrinsic intrinsic} functions
042 * (snippets and method substitutions), by forwarding to the {@link WordOperationPlugin}. Note that
043 * we forward the {@link NodePlugin} and {@link ParameterPlugin} methods, but not the
044 * {@link InlineInvokePlugin} methods implemented by {@link WordOperationPlugin}. The latter is not
045 * necessary because HotSpot only uses the {@link Word} type in methods that are force-inlined,
046 * i.e., there are never non-inlined invokes that involve the {@link Word} type.
047 * <p>
048 * Handling of {@link Fold} and {@link NodeIntrinsic} annotated methods, by forwarding to the
049 * {@link NodeIntrinsificationPlugin} when parsing intrinsic functions.
050 * <p>
051 * Constant folding of field loads.
052 */
053public final class HotSpotNodePlugin implements NodePlugin, ParameterPlugin {
054    protected final WordOperationPlugin wordOperationPlugin;
055    protected final NodeIntrinsificationPlugin nodeIntrinsificationPlugin;
056
057    public HotSpotNodePlugin(WordOperationPlugin wordOperationPlugin, NodeIntrinsificationPlugin nodeIntrinsificationPlugin) {
058        this.wordOperationPlugin = wordOperationPlugin;
059        this.nodeIntrinsificationPlugin = nodeIntrinsificationPlugin;
060    }
061
062    @Override
063    public boolean canChangeStackKind(GraphBuilderContext b) {
064        if (b.parsingIntrinsic()) {
065            return wordOperationPlugin.canChangeStackKind(b) || nodeIntrinsificationPlugin.canChangeStackKind(b);
066        }
067        return false;
068    }
069
070    @Override
071    public FloatingNode interceptParameter(GraphBuilderContext b, int index, Stamp stamp) {
072        if (b.parsingIntrinsic()) {
073            return wordOperationPlugin.interceptParameter(b, index, stamp);
074        }
075        return null;
076    }
077
078    @Override
079    public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
080        if (b.parsingIntrinsic() && wordOperationPlugin.handleInvoke(b, method, args)) {
081            return true;
082        }
083        if (b.parsingIntrinsic() && nodeIntrinsificationPlugin.handleInvoke(b, method, args)) {
084            return true;
085        }
086        return false;
087    }
088
089    @Override
090    public boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) {
091        if (!ImmutableCode.getValue() || b.parsingIntrinsic()) {
092            if (object.isConstant()) {
093                JavaConstant asJavaConstant = object.asJavaConstant();
094                if (tryReadField(b, field, asJavaConstant)) {
095                    return true;
096                }
097            }
098        }
099        if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadField(b, object, field)) {
100            return true;
101        }
102        return false;
103    }
104
105    @Override
106    public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) {
107        if (!ImmutableCode.getValue() || b.parsingIntrinsic()) {
108            if (tryReadField(b, field, null)) {
109                return true;
110            }
111        }
112        if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) {
113            return true;
114        }
115        return false;
116    }
117
118    private static boolean tryReadField(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) {
119        // FieldReadEnabledInImmutableCode is non null only if assertions are enabled
120        if (FieldReadEnabledInImmutableCode != null && ImmutableCode.getValue()) {
121            FieldReadEnabledInImmutableCode.set(Boolean.TRUE);
122            try {
123                return tryConstantFold(b, field, object);
124            } finally {
125                FieldReadEnabledInImmutableCode.set(null);
126            }
127        } else {
128            return tryConstantFold(b, field, object);
129        }
130    }
131
132    private static boolean tryConstantFold(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) {
133        JavaConstant result = b.getConstantReflection().readConstantFieldValue(field, object);
134        if (result != null) {
135            ConstantNode constantNode = ConstantNode.forConstant(result, b.getMetaAccess(), b.getGraph());
136            b.push(field.getKind(), constantNode);
137            return true;
138        }
139        return false;
140    }
141
142    @Override
143    public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
144        if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreField(b, object, field, value)) {
145            return true;
146        }
147        return false;
148    }
149
150    @Override
151    public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) {
152        if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreStaticField(b, field, value)) {
153            return true;
154        }
155        return false;
156    }
157
158    @Override
159    public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind) {
160        if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadIndexed(b, array, index, elementKind)) {
161            return true;
162        }
163        return false;
164    }
165
166    @Override
167    public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, Kind elementKind, ValueNode value) {
168        if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreIndexed(b, array, index, elementKind, value)) {
169            return true;
170        }
171        return false;
172    }
173
174    @Override
175    public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
176        if (b.parsingIntrinsic() && wordOperationPlugin.handleCheckCast(b, object, type, profile)) {
177            return true;
178        }
179        return false;
180    }
181
182    @Override
183    public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
184        if (b.parsingIntrinsic() && wordOperationPlugin.handleInstanceOf(b, object, type, profile)) {
185            return true;
186        }
187        return false;
188    }
189}