1 /*
   2  * Copyright (c) 2013, 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 com.oracle.graal.hotspot.replacements;
  24 
  25 import com.oracle.graal.api.meta.*;
  26 import com.oracle.graal.graph.*;
  27 import com.oracle.graal.hotspot.meta.*;
  28 import com.oracle.graal.nodes.*;
  29 import com.oracle.graal.nodes.spi.*;
  30 import com.oracle.graal.phases.*;
  31 import com.oracle.graal.replacements.nodes.*;
  32 
  33 public class ReflectionGetCallerClassNode extends MacroNode implements Canonicalizable, Lowerable {
  34 
  35     public ReflectionGetCallerClassNode(Invoke invoke) {
  36         super(invoke);
  37     }
  38 
  39     @Override
  40     public ValueNode canonical(CanonicalizerTool tool) {
  41         ConstantNode callerClassNode = getCallerClassNode(tool.runtime());
  42         if (callerClassNode != null) {
  43             return callerClassNode;
  44         }
  45         return this;
  46     }
  47 
  48     @Override
  49     public void lower(LoweringTool tool, LoweringType loweringType) {
  50         StructuredGraph graph = (StructuredGraph) graph();
  51 
  52         ConstantNode callerClassNode = getCallerClassNode(tool.getRuntime());
  53 
  54         if (callerClassNode != null) {
  55             graph.replaceFixedWithFloating(this, callerClassNode);
  56         } else {
  57             graph.replaceFixedWithFixed(this, createInvoke());
  58         }
  59     }
  60 
  61     /**
  62      * If inlining is deep enough this method returns a {@link ConstantNode} of the caller class by
  63      * walking the the stack.
  64      * 
  65      * @param runtime
  66      * @return ConstantNode of the caller class, or null
  67      */
  68     private ConstantNode getCallerClassNode(MetaAccessProvider runtime) {
  69         if (!GraalOptions.IntrinsifyReflectionMethods) {
  70             return null;
  71         }
  72 
  73         // Walk back up the frame states to find the caller at the required depth.
  74         FrameState state = stateAfter();
  75 
  76         // Cf. JVM_GetCallerClass
  77         // NOTE: Start the loop at depth 1 because the current frame state does
  78         // not include the Reflection.getCallerClass() frame.
  79         for (int n = 1; state != null; state = state.outerFrameState(), n++) {
  80             HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) state.method();
  81             switch (n) {
  82                 case 0:
  83                     throw GraalInternalError.shouldNotReachHere("current frame state does not include the Reflection.getCallerClass frame");
  84                 case 1:
  85                     // Frame 0 and 1 must be caller sensitive (see JVM_GetCallerClass).
  86                     if (!method.isCallerSensitive()) {
  87                         return null;  // bail-out; let JVM_GetCallerClass do the work
  88                     }
  89                     break;
  90                 default:
  91                     if (!method.ignoredBySecurityStackWalk()) {
  92                         // We have reached the desired frame; return the holder class.
  93                         HotSpotResolvedObjectType callerClass = (HotSpotResolvedObjectType) method.getDeclaringClass();
  94                         return ConstantNode.forObject(callerClass.mirror(), runtime, graph());
  95                     }
  96                     break;
  97             }
  98         }
  99         return null;  // bail-out; let JVM_GetCallerClass do the work
 100     }
 101 
 102 }