changeset 15063:36e1a11a72b3

new StackIntrospection interface to allow access to stack contents
author Lukas Stadler <lukas.stadler@oracle.com>
date Fri, 11 Apr 2014 11:52:19 +0200
parents 10b0b01a4a61
children f675818d9ad0
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrame.java graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotStackFrameReference.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java src/share/vm/classfile/systemDictionary.hpp src/share/vm/classfile/vmSymbols.hpp src/share/vm/graal/graalCompilerToVM.cpp src/share/vm/graal/graalJavaAccess.hpp src/share/vm/oops/method.cpp src/share/vm/runtime/deoptimization.hpp
diffstat 14 files changed, 518 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/InspectedFrame.java	Fri Apr 11 11:52:19 2014 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.graal.api.code.stack;
+
+import com.oracle.graal.api.meta.*;
+
+public interface InspectedFrame {
+
+    /**
+     * Returns the value of the local at the given index. Currently only works for object values.
+     * This value is a copy iff {@link #isVirtual(int)} is true.
+     */
+    Object getLocal(int index);
+
+    /**
+     * Returns whether the local at the given index is a virtual object, and therefore the object
+     * returned by {@link #getLocal(int)} is a copy.
+     */
+    boolean isVirtual(int index);
+
+    /**
+     * Returns true if the stack frame is a compiled stack frame and there are virtual objects
+     * anywhere in the current state of the compiled method. This can return true even if
+     * {@link #isVirtual(int)} return false for all locals.
+     */
+    boolean hasVirtualObjects();
+
+    /**
+     * This method will materialize all virtual objects, deoptimize the stack frame and make sure
+     * that subsequent execution of the deoptimized frame uses the materialized values.
+     */
+    void materializeVirtualObjects(boolean invalidateCode);
+
+    /**
+     * @return the current bytecode index
+     */
+    int getBytecodeIndex();
+
+    /**
+     * @return the current method
+     */
+    ResolvedJavaMethod getMethod();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/stack/StackIntrospection.java	Fri Apr 11 11:52:19 2014 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.graal.api.code.stack;
+
+import com.oracle.graal.api.meta.*;
+
+public interface StackIntrospection {
+
+    /**
+     * Accesses the current stack, returning a collection of {@long InspectedFrame}s that can be
+     * used to inspect the stack frames' contents.
+     *
+     * @param initialMethod if this is non-{@code null}, then the stack trace will start at this
+     *            method
+     * @param matchingMethod if this is non-{@code null}, then only matching stack frames are
+     *            returned
+     */
+    Iterable<InspectedFrame> getStackTrace(ResolvedJavaMethod initialMethod, ResolvedJavaMethod matchingMethod);
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri Apr 11 13:41:16 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri Apr 11 11:52:19 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.target;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.stack.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.gen.*;
@@ -96,6 +97,8 @@
 
     public abstract boolean shouldAllocateRegisters();
 
+    public abstract StackIntrospection getStackIntrospection();
+
     /**
      * Emits the code for a given graph.
      *
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri Apr 11 13:41:16 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Fri Apr 11 11:52:19 2014 +0200
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.stack.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -96,7 +97,7 @@
 
     /**
      * Finds all the registers that are defined by some given LIR.
-     * 
+     *
      * @param lir the LIR to examine
      * @return the registers that are defined by or used as temps for any instruction in {@code lir}
      */
@@ -134,7 +135,7 @@
      * {@linkplain SaveRegistersOp#remove(Set) removed} as these registers are declared as
      * temporaries in the stub's {@linkplain ForeignCallLinkage linkage} (and thus will be saved by
      * the stub's caller).
-     * 
+     *
      * @param stub the stub to update
      * @param destroyedRegisters the registers destroyed by the stub
      * @param calleeSaveInfo a map from debug infos to the operations that provide their
@@ -158,6 +159,11 @@
     }
 
     @Override
+    public StackIntrospection getStackIntrospection() {
+        return runtime;
+    }
+
+    @Override
     public HotSpotProviders getProviders() {
         return (HotSpotProviders) super.getProviders();
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Fri Apr 11 13:41:16 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Fri Apr 11 11:52:19 2014 +0200
@@ -33,6 +33,7 @@
 import sun.reflect.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.stack.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
@@ -49,7 +50,7 @@
 /**
  * Singleton class holding the instance of the {@link GraalRuntime}.
  */
-public final class HotSpotGraalRuntime implements GraalRuntime, RuntimeProvider {
+public final class HotSpotGraalRuntime implements GraalRuntime, RuntimeProvider, StackIntrospection {
 
     private static final HotSpotGraalRuntime instance = new HotSpotGraalRuntime();
     static {
@@ -363,6 +364,8 @@
     public <T> T getCapability(Class<T> clazz) {
         if (clazz == RuntimeProvider.class) {
             return (T) this;
+        } else if (clazz == StackIntrospection.class) {
+            return (T) this;
         } else if (clazz == SnippetReflectionProvider.class) {
             return (T) getHostProviders().getSnippetReflection();
         }
@@ -441,4 +444,36 @@
                 throw GraalInternalError.shouldNotReachHere();
         }
     }
+
+    public Iterable<InspectedFrame> getStackTrace(final ResolvedJavaMethod initialMethod, final ResolvedJavaMethod matchingMethod) {
+        class StackFrameIterator implements Iterator<InspectedFrame> {
+
+            private HotSpotStackFrameReference current = compilerToVm.getNextStackFrame(null, (HotSpotResolvedJavaMethod) initialMethod);
+            // we don't want to read ahead if hasNext isn't called
+            private boolean advanced = true;
+
+            public boolean hasNext() {
+                update();
+                return current != null;
+            }
+
+            public InspectedFrame next() {
+                update();
+                advanced = false;
+                return current;
+            }
+
+            private void update() {
+                if (!advanced) {
+                    current = compilerToVm.getNextStackFrame(current, (HotSpotResolvedJavaMethod) matchingMethod);
+                    advanced = true;
+                }
+            }
+        }
+        return new Iterable<InspectedFrame>() {
+            public Iterator<InspectedFrame> iterator() {
+                return new StackFrameIterator();
+            }
+        };
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotStackFrameReference.java	Fri Apr 11 11:52:19 2014 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.graal.hotspot;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.stack.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.hotspot.meta.*;
+
+public class HotSpotStackFrameReference implements InspectedFrame {
+
+    private CompilerToVM compilerToVM;
+
+    // information used to find the stack frame
+    private long stackPointer;
+    private int frameNumber;
+
+    // information about the stack frame's contents
+    private int bci;
+    private long metaspaceMethod;
+    private Object[] locals;
+    private boolean[] localIsVirtual;
+
+    public long getStackPointer() {
+        return stackPointer;
+    }
+
+    public int getFrameNumber() {
+        return frameNumber;
+    }
+
+    public Object getLocal(int index) {
+        return locals[index];
+    }
+
+    public boolean isVirtual(int index) {
+        return localIsVirtual == null ? false : localIsVirtual[index];
+    }
+
+    public void materializeVirtualObjects(boolean invalidateCode) {
+        compilerToVM.materializeVirtualObjects(this, invalidateCode);
+    }
+
+    public int getBytecodeIndex() {
+        return bci;
+    }
+
+    public ResolvedJavaMethod getMethod() {
+        return HotSpotResolvedJavaMethod.fromMetaspace(metaspaceMethod);
+    }
+
+    public boolean hasVirtualObjects() {
+        return localIsVirtual != null;
+    }
+
+    @Override
+    public String toString() {
+        return "HotSpotStackFrameReference [stackPointer=" + stackPointer + ", frameNumber=" + frameNumber + ", bci=" + bci + ", method=" + getMethod() + ", locals=" + Arrays.toString(locals) +
+                        ", localIsVirtual=" + Arrays.toString(localIsVirtual) + "]";
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri Apr 11 13:41:16 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri Apr 11 11:52:19 2014 +0200
@@ -334,4 +334,22 @@
      * @return milliseconds since VM start
      */
     long getTimeStamp();
+
+    /**
+     * Looks for the next Java stack frame with the given method.
+     *
+     * @param frame the starting point of the search, where {@code null} refers to the topmost frame
+     * @param method the method to look for, where {@code null} means that any frame is returned
+     * @return the frame, or {@code null} if the end of the stack was reached during the search
+     */
+    HotSpotStackFrameReference getNextStackFrame(HotSpotStackFrameReference frame, HotSpotResolvedJavaMethod method);
+
+    /**
+     * Materialized all virtual objects within the given stack frame and update the locals within
+     * the given stackFrame object.
+     *
+     * @param invalidate if {@code true}, the compiled method for the stack frame will be
+     *            invalidated.
+     */
+    void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri Apr 11 13:41:16 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri Apr 11 11:52:19 2014 +0200
@@ -179,5 +179,9 @@
 
     public native boolean hasCompiledCodeForOSR(long metaspaceMethod, int entryBCI, int level);
 
+    public native HotSpotStackFrameReference getNextStackFrame(HotSpotStackFrameReference frame, HotSpotResolvedJavaMethod method);
+
+    public native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate);
+
     public native long getTimeStamp();
 }
--- a/src/share/vm/classfile/systemDictionary.hpp	Fri Apr 11 13:41:16 2014 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp	Fri Apr 11 11:52:19 2014 +0200
@@ -206,6 +206,7 @@
   do_klass(HotSpotMonitorValue_klass,             com_oracle_graal_hotspot_meta_HotSpotMonitorValue,            Opt) \
   do_klass(HotSpotObjectConstant_klass,           com_oracle_graal_hotspot_meta_HotSpotObjectConstant,          Opt) \
   do_klass(HotSpotMetaspaceConstant_klass,        com_oracle_graal_hotspot_meta_HotSpotMetaspaceConstant,       Opt) \
+  do_klass(HotSpotStackFrameReference_klass,      com_oracle_graal_hotspot_HotSpotStackFrameReference,          Opt) \
   /* graal.api.code */                                                                                               \
   do_klass(Assumptions_klass,                     com_oracle_graal_api_code_Assumptions,                        Opt) \
   do_klass(Assumptions_ConcreteMethod_klass,      com_oracle_graal_api_code_Assumptions_ConcreteMethod,         Opt) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Fri Apr 11 13:41:16 2014 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Fri Apr 11 11:52:19 2014 +0200
@@ -317,10 +317,11 @@
   template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue,        "com/oracle/graal/hotspot/meta/HotSpotMonitorValue")             \
   template(com_oracle_graal_hotspot_meta_HotSpotObjectConstant,      "com/oracle/graal/hotspot/meta/HotSpotObjectConstant")           \
   template(com_oracle_graal_hotspot_meta_HotSpotMetaspaceConstant,   "com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstant")        \
+  template(com_oracle_graal_hotspot_HotSpotStackFrameReference,      "com/oracle/graal/hotspot/HotSpotStackFrameReference")           \
   /* graal.api.meta */                                                                                                                \
   template(com_oracle_graal_api_meta_Constant,                       "com/oracle/graal/api/meta/Constant")                            \
   template(com_oracle_graal_api_meta_PrimitiveConstant,              "com/oracle/graal/api/meta/PrimitiveConstant")                   \
-  template(com_oracle_graal_api_meta_NullConstant,                   "com/oracle/graal/api/meta/NullConstant")                   \
+  template(com_oracle_graal_api_meta_NullConstant,                   "com/oracle/graal/api/meta/NullConstant")                        \
   template(com_oracle_graal_api_meta_ConstantPool,                   "com/oracle/graal/api/meta/ConstantPool")                        \
   template(com_oracle_graal_api_meta_ExceptionHandler,               "com/oracle/graal/api/meta/ExceptionHandler")                    \
   template(com_oracle_graal_api_meta_JavaMethod,                     "com/oracle/graal/api/meta/JavaMethod")                          \
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri Apr 11 13:41:16 2014 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Fri Apr 11 11:52:19 2014 +0200
@@ -22,6 +22,7 @@
  */
 
 #include "precompiled.hpp"
+#include "code/scopeDesc.hpp"
 #include "memory/oopFactory.hpp"
 #include "oops/generateOopMap.hpp"
 #include "oops/fieldStreams.hpp"
@@ -39,6 +40,9 @@
 #include "graal/graalVMToCompiler.hpp"
 #include "gc_implementation/g1/heapRegion.hpp"
 #include "runtime/javaCalls.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/vframe.hpp"
+#include "runtime/vframe_hp.hpp"
 #include "runtime/vmStructs.hpp"
 #include "runtime/gpu.hpp"
 
@@ -782,6 +786,239 @@
   return tty->time_stamp().milliseconds();
 C2V_END
 
+// public native HotSpotStackFrameReference getNextStackFrame(HotSpotStackFrameReference frame, ResolvedJavaMethod method);
+C2V_VMENTRY(jobject, getNextStackFrame, (JNIEnv *env, jobject compilerToVM, jobject hs_frame, jobject hs_method))
+  ResourceMark rm;
+
+  if (!thread->has_last_Java_frame()) return NULL;
+  methodHandle method = hs_method == NULL ? NULL : asMethod(HotSpotResolvedJavaMethod::metaspaceMethod(hs_method));
+  Handle result = InstanceKlass::cast(HotSpotStackFrameReference::klass())->allocate_instance(thread);
+  HotSpotStackFrameReference::klass()->initialize(thread);
+
+  StackFrameStream fst(thread);
+  if (hs_frame != NULL) {
+    // look for the correct stack frame if one is given
+    intptr_t* stack_pointer = (intptr_t*) HotSpotStackFrameReference::stackPointer(hs_frame);
+    while (fst.current()->sp() != stack_pointer && !fst.is_done()) {
+      fst.next();
+    }
+    if (fst.current()->sp() != stack_pointer) {
+      THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "stack frame not found")
+    }
+  }
+
+  int frame_number = 0;
+  vframe* vf = vframe::new_vframe(fst.current(), fst.register_map(), thread);
+  if (hs_frame != NULL) {
+    // look for the correct vframe within the stack frame if one is given
+    int last_frame_number = HotSpotStackFrameReference::frameNumber(hs_frame);
+    while (frame_number < last_frame_number) {
+      if (vf->is_top()) {
+        THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "invalid frame number")
+      }
+      vf = vf->sender();
+      frame_number ++;
+    }
+    // move one frame forward
+    if (vf->is_top()) {
+      if (fst.is_done()) {
+        return NULL;
+      }
+      fst.next();
+      vf = vframe::new_vframe(fst.current(), fst.register_map(), thread);
+      frame_number = 0;
+    } else {
+      vf = vf->sender();
+      frame_number++;
+    }
+  }
+
+  while (true) {
+    // look for the given method
+    while (true) {
+      StackValueCollection* locals = NULL;
+      if (vf->is_compiled_frame()) {
+        // compiled method frame
+        compiledVFrame* cvf = compiledVFrame::cast(vf);
+        if (method == NULL || cvf->method() == method()) {
+          GrowableArray<ScopeValue*>* objects = cvf->scope()->objects();
+          bool reallocated = false;
+          if (objects != NULL) {
+            reallocated = Deoptimization::realloc_objects(thread, fst.current(), objects, THREAD);
+            if (reallocated) {
+              Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects);
+            }
+
+            GrowableArray<ScopeValue*>* local_values = cvf->scope()->locals();
+            typeArrayHandle array = oopFactory::new_boolArray(local_values->length(), thread);
+            for (int i = 0; i < local_values->length(); i++) {
+              ScopeValue* value = local_values->at(i);
+              if (value->is_object()) {
+                array->bool_at_put(i, true);
+              }
+            }
+            HotSpotStackFrameReference::set_localIsVirtual(result, array());
+          } else {
+            HotSpotStackFrameReference::set_localIsVirtual(result, NULL);
+          }
+
+          locals = cvf->locals();
+          HotSpotStackFrameReference::set_bci(result, cvf->bci());
+          if (hs_method == NULL) {
+            HotSpotStackFrameReference::set_metaspaceMethod(result, (jlong) cvf->method());
+          } else {
+            HotSpotStackFrameReference::set_metaspaceMethod(result, (jlong) method());
+          }
+        }
+      } else if (vf->is_interpreted_frame()) {
+        // interpreted method frame
+        interpretedVFrame* ivf = interpretedVFrame::cast(vf);
+        if (method == NULL || ivf->method() == method()) {
+          locals = ivf->locals();
+          HotSpotStackFrameReference::set_bci(result, ivf->bci());
+          if (hs_method == NULL) {
+            HotSpotStackFrameReference::set_metaspaceMethod(result, (jlong) ivf->method());
+          } else {
+            HotSpotStackFrameReference::set_metaspaceMethod(result, (jlong) method());
+          }
+          HotSpotStackFrameReference::set_localIsVirtual(result, NULL);
+        }
+      }
+
+      // locals != NULL means that we found a matching frame and result is already partially initialized
+      if (locals != NULL) {
+        HotSpotStackFrameReference::set_compilerToVM(result, JNIHandles::resolve(compilerToVM));
+        HotSpotStackFrameReference::set_stackPointer(result, (jlong) fst.current()->sp());
+        HotSpotStackFrameReference::set_frameNumber(result, frame_number);
+
+        // initialize the locals array
+        objArrayHandle array = oopFactory::new_objectArray(locals->size(), thread);
+        for (int i = 0; i < locals->size(); i++) {
+          StackValue* var = locals->at(i);
+          if (var->type() == T_OBJECT) {
+            array->obj_at_put(i, locals->at(i)->get_obj()());
+          }
+        }
+        HotSpotStackFrameReference::set_locals(result, array());
+
+        return JNIHandles::make_local(thread, result());
+      }
+
+      if (vf->is_top()) {
+        break;
+      }
+      frame_number++;
+      vf = vf->sender();
+    } // end of vframe loop
+
+    if (fst.is_done()) {
+      break;
+    }
+    fst.next();
+    vf = vframe::new_vframe(fst.current(), fst.register_map(), thread);
+    frame_number = 0;
+  } // end of frame loop
+
+  // the end was reached without finding a matching method
+  return NULL;
+C2V_END
+
+
+
+// public native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate);
+C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv *env, jobject, jobject hs_frame, bool invalidate))
+  ResourceMark rm;
+
+  if (hs_frame == NULL) {
+    THROW_MSG(vmSymbols::java_lang_NullPointerException(), "stack frame is null")
+  }
+
+  HotSpotStackFrameReference::klass()->initialize(thread);
+
+  // look for the given stack frame
+  StackFrameStream fst(thread);
+  intptr_t* stack_pointer = (intptr_t*) HotSpotStackFrameReference::stackPointer(hs_frame);
+  while (fst.current()->sp() != stack_pointer && !fst.is_done()) {
+    fst.next();
+  }
+  if (fst.current()->sp() != stack_pointer) {
+    THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "stack frame not found")
+  }
+
+  if (invalidate) {
+    assert(fst.current()->cb()->is_nmethod(), "nmethod expected");
+    ((nmethod*) fst.current()->cb())->make_not_entrant();
+  }
+  Deoptimization::deoptimize(thread, *fst.current(), fst.register_map(), Deoptimization::Reason_none);
+
+  vframe* vf = vframe::new_vframe(fst.current(), fst.register_map(), thread);
+  if (!vf->is_compiled_frame()) {
+    THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "compiled stack frame expected")
+  }
+
+  GrowableArray<compiledVFrame*>* virtualFrames = new GrowableArray<compiledVFrame*>(10);
+  while (true) {
+    assert(vf->is_compiled_frame(), "Wrong frame type");
+    virtualFrames->push(compiledVFrame::cast(vf));
+    if (vf->is_top()) {
+      break;
+    }
+    vf = vf->sender();
+  }
+
+  int last_frame_number = HotSpotStackFrameReference::frameNumber(hs_frame);
+  if (last_frame_number >= virtualFrames->length()) {
+    THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "invalid frame number")
+  }
+
+  // Reallocate the non-escaping objects and restore their fields.
+  assert (virtualFrames->at(last_frame_number)->scope() != NULL,"invalid scope");
+  GrowableArray<ScopeValue*>* objects = virtualFrames->at(last_frame_number)->scope()->objects();
+
+  if (objects == NULL) {
+    // no objects to materialize
+    return;
+  }
+
+  bool reallocated = Deoptimization::realloc_objects(thread, fst.current(), objects, THREAD);
+  if (reallocated) {
+    Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects);
+
+    for (int frame_index = 0; frame_index < virtualFrames->length(); frame_index++) {
+      compiledVFrame* cvf = virtualFrames->at(frame_index);
+
+      GrowableArray<ScopeValue*>* scopeLocals = cvf->scope()->locals();
+      StackValueCollection* locals = cvf->locals();
+
+      if (locals != NULL) {
+        for (int i2 = 0; i2 < locals->size(); i2++) {
+          StackValue* var = locals->at(i2);
+          if (var->type() == T_OBJECT && scopeLocals->at(i2)->is_object()) {
+            jvalue val;
+            val.l = (jobject) locals->at(i2)->get_obj()();
+            cvf->update_local(T_OBJECT, i2, val);
+          }
+        }
+      }
+    }
+
+    // all locals are materialized by now
+    HotSpotStackFrameReference::set_localIsVirtual(hs_frame, NULL);
+
+    // update the locals array
+    objArrayHandle array = (objArrayOop) HotSpotStackFrameReference::locals(hs_frame);
+    StackValueCollection* locals = virtualFrames->at(last_frame_number)->locals();
+    for (int i = 0; i < locals->size(); i++) {
+      StackValue* var = locals->at(i);
+      if (var->type() == T_OBJECT) {
+        array->obj_at_put(i, locals->at(i)->get_obj()());
+      }
+    }
+  }
+C2V_END
+
+
+
 #define CC (char*)  /*cast a literal from (const char*)*/
 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f))
 
@@ -798,6 +1035,7 @@
 #define HS_CONFIG             "Lcom/oracle/graal/hotspot/HotSpotVMConfig;"
 #define HS_INSTALLED_CODE     "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;"
 #define NODE_CLASS            "Lcom/oracle/graal/graph/NodeClass;"
+#define HS_STACK_FRAME_REF    "Lcom/oracle/graal/hotspot/HotSpotStackFrameReference;"
 #define METASPACE_KLASS       "J"
 #define METASPACE_METHOD      "J"
 #define METASPACE_METHOD_DATA "J"
@@ -855,6 +1093,8 @@
   {CC"isMature",                                     CC"("METASPACE_METHOD_DATA")Z",                                   FN_PTR(isMature)},
   {CC"hasCompiledCodeForOSR",                        CC"("METASPACE_METHOD"II)Z",                                      FN_PTR(hasCompiledCodeForOSR)},
   {CC"getTimeStamp",                                 CC"()J",                                                          FN_PTR(getTimeStamp)},
+  {CC"getNextStackFrame",                            CC"("HS_STACK_FRAME_REF HS_RESOLVED_METHOD")"HS_STACK_FRAME_REF,  FN_PTR(getNextStackFrame)},
+  {CC"materializeVirtualObjects",                    CC"("HS_STACK_FRAME_REF"Z)V",                                     FN_PTR(materializeVirtualObjects)},
 };
 
 int CompilerToVM_methods_count() {
--- a/src/share/vm/graal/graalJavaAccess.hpp	Fri Apr 11 13:41:16 2014 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Fri Apr 11 11:52:19 2014 +0200
@@ -202,17 +202,17 @@
   start_class(Constant)                                                                                                                                        \
     oop_field(Constant, kind, "Lcom/oracle/graal/api/meta/Kind;")                                                                                              \
   end_class                                                                                                                                                    \
-  start_class(PrimitiveConstant)                                                                                                                                        \
-    long_field(PrimitiveConstant, primitive)                                                                                                                            \
+  start_class(PrimitiveConstant)                                                                                                                               \
+    long_field(PrimitiveConstant, primitive)                                                                                                                   \
   end_class                                                                                                                                                    \
-  start_class(NullConstant)                                                                                                                                        \
+  start_class(NullConstant)                                                                                                                                    \
   end_class                                                                                                                                                    \
-  start_class(HotSpotObjectConstant)                                                                                                                                        \
-    oop_field(HotSpotObjectConstant, object, "Ljava/lang/Object;")                                                                                                          \
+  start_class(HotSpotObjectConstant)                                                                                                                           \
+    oop_field(HotSpotObjectConstant, object, "Ljava/lang/Object;")                                                                                             \
   end_class                                                                                                                                                    \
-  start_class(HotSpotMetaspaceConstant)                                                                                                                                        \
-    long_field(HotSpotMetaspaceConstant, primitive)                                                                                                                            \
-    oop_field(HotSpotMetaspaceConstant, metaspaceObject, "Ljava/lang/Object;")                                                                                                          \
+  start_class(HotSpotMetaspaceConstant)                                                                                                                        \
+    long_field(HotSpotMetaspaceConstant, primitive)                                                                                                            \
+    oop_field(HotSpotMetaspaceConstant, metaspaceObject, "Ljava/lang/Object;")                                                                                 \
   end_class                                                                                                                                                    \
   start_class(Kind)                                                                                                                                            \
     char_field(Kind, typeChar)                                                                                                                                 \
@@ -249,7 +249,16 @@
   end_class                                                                                                                                                    \
   start_class(SpeculationLog)                                                                                                                                  \
     oop_field(SpeculationLog, lastFailed, "Ljava/lang/Object;")                                                                                                \
-  end_class
+  end_class                                                                                                                                                    \
+  start_class(HotSpotStackFrameReference)                                                                                                                      \
+    oop_field(HotSpotStackFrameReference, compilerToVM, "Lcom/oracle/graal/hotspot/bridge/CompilerToVM;")                                                      \
+    long_field(HotSpotStackFrameReference, stackPointer)                                                                                                       \
+    int_field(HotSpotStackFrameReference, frameNumber)                                                                                                         \
+    int_field(HotSpotStackFrameReference, bci)                                                                                                                 \
+    long_field(HotSpotStackFrameReference, metaspaceMethod)                                                                                                    \
+    oop_field(HotSpotStackFrameReference, locals, "[Ljava/lang/Object;")                                                                                       \
+    oop_field(HotSpotStackFrameReference, localIsVirtual, "[Z")                                                                                                \
+  end_class                                                                                                                                                    \
   /* end*/
 
 #define START_CLASS(name)                                                                                                                                      \
--- a/src/share/vm/oops/method.cpp	Fri Apr 11 13:41:16 2014 +0200
+++ b/src/share/vm/oops/method.cpp	Fri Apr 11 11:52:19 2014 +0200
@@ -216,7 +216,7 @@
 
   Thread* myThread    = Thread::current();
   methodHandle h_this(myThread, this);
-#ifdef ASSERT
+#if defined(ASSERT) && !defined(GRAAL)
   bool has_capability = myThread->is_VM_thread() ||
                         myThread->is_ConcurrentGC_thread() ||
                         myThread->is_GC_task_thread();
--- a/src/share/vm/runtime/deoptimization.hpp	Fri Apr 11 13:41:16 2014 +0200
+++ b/src/share/vm/runtime/deoptimization.hpp	Fri Apr 11 11:52:19 2014 +0200
@@ -139,6 +139,8 @@
   static void revoke_biases_of_monitors(CodeBlob* cb);
 
 #if defined(COMPILER2) || defined(GRAAL)
+GRAAL_ONLY(public:)
+
   // Support for restoring non-escaping objects
   static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS);
   static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type);