--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java 2016-12-09 00:49:55.563470094 -0800 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.replacements; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_20; + +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.FrameState; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.replacements.nodes.MacroStateSplitNode; + +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "This node can be lowered to a call", size = SIZE_20) +public final class ReflectionGetCallerClassNode extends MacroStateSplitNode implements Canonicalizable, Lowerable { + + public static final NodeClass TYPE = NodeClass.create(ReflectionGetCallerClassNode.class); + + public ReflectionGetCallerClassNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) { + super(TYPE, invokeKind, targetMethod, bci, returnStamp, arguments); + } + + @Override + public Node canonical(CanonicalizerTool tool) { + ConstantNode callerClassNode = getCallerClassNode(tool.getMetaAccess(), tool.getConstantReflection()); + if (callerClassNode != null) { + return callerClassNode; + } + return this; + } + + @Override + public void lower(LoweringTool tool) { + ConstantNode callerClassNode = getCallerClassNode(tool.getMetaAccess(), tool.getConstantReflection()); + + if (callerClassNode != null) { + graph().replaceFixedWithFloating(this, graph().addOrUniqueWithInputs(callerClassNode)); + } else { + InvokeNode invoke = createInvoke(); + graph().replaceFixedWithFixed(this, invoke); + invoke.lower(tool); + } + } + + /** + * If inlining is deep enough this method returns a {@link ConstantNode} of the caller class by + * walking the the stack. + * + * @param metaAccess + * @return ConstantNode of the caller class, or null + */ + private ConstantNode getCallerClassNode(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { + // Walk back up the frame states to find the caller at the required depth. + FrameState state = stateAfter(); + + // Cf. JVM_GetCallerClass + // NOTE: Start the loop at depth 1 because the current frame state does + // not include the Reflection.getCallerClass() frame. + for (int n = 1; state != null; state = state.outerFrameState(), n++) { + HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) state.getMethod(); + switch (n) { + case 0: + throw GraalError.shouldNotReachHere("current frame state does not include the Reflection.getCallerClass frame"); + case 1: + // Frame 0 and 1 must be caller sensitive (see JVM_GetCallerClass). + if (!method.isCallerSensitive()) { + return null; // bail-out; let JVM_GetCallerClass do the work + } + break; + default: + if (!method.ignoredBySecurityStackWalk()) { + // We have reached the desired frame; return the holder class. + HotSpotResolvedObjectType callerClass = method.getDeclaringClass(); + return ConstantNode.forConstant(constantReflection.asJavaClass(callerClass), metaAccess); + } + break; + } + } + return null; // bail-out; let JVM_GetCallerClass do the work + } + +}