Support for deoptimization needed for debugging.
The deoptimization code is untested, and some sanity checks in the
instrumentation are disabled because they need debugging.
Change-Id: I1b60a65a60bddc9b107ad4659da097b55ce901c3
diff --git a/src/asm_support.h b/src/asm_support.h
index b2f8126..0a8489c 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -27,7 +27,6 @@
#if defined(__arm__)
#define rSUSPEND r4
#define rSELF r9
-#define rLR r14
// Offset of field Thread::suspend_count_ verified in InitCpu
#define THREAD_FLAGS_OFFSET 0
// Offset of field Thread::exception_ verified in InitCpu
diff --git a/src/debugger.cc b/src/debugger.cc
index a75cd8c..77a9252 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -1558,7 +1558,7 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
struct CountStackDepthVisitor : public StackVisitor {
CountStackDepthVisitor(const ManagedStack* stack,
- const std::vector<InstrumentationStackFrame>* instrumentation_stack)
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack)
: StackVisitor(stack, instrumentation_stack, NULL), depth(0) {}
bool VisitFrame() {
@@ -1585,10 +1585,12 @@
return GetStackDepth(DecodeThread(soa, threadId));
}
-JDWP::JdwpError Dbg::GetThreadFrames(JDWP::ObjectId thread_id, size_t start_frame, size_t frame_count, JDWP::ExpandBuf* buf) {
+JDWP::JdwpError Dbg::GetThreadFrames(JDWP::ObjectId thread_id, size_t start_frame,
+ size_t frame_count, JDWP::ExpandBuf* buf) {
class GetFrameVisitor : public StackVisitor {
public:
- GetFrameVisitor(const ManagedStack* stack, const std::vector<InstrumentationStackFrame>* instrumentation_stack,
+ GetFrameVisitor(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack,
size_t start_frame, size_t frame_count, JDWP::ExpandBuf* buf)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: StackVisitor(stack, instrumentation_stack, NULL), depth_(0),
@@ -1627,7 +1629,8 @@
ScopedObjectAccessUnchecked soa(Thread::Current());
MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
Thread* thread = DecodeThread(soa, thread_id); // Caller already checked thread is suspended.
- GetFrameVisitor visitor(thread->GetManagedStack(), thread->GetInstrumentationStack(), start_frame, frame_count, buf);
+ GetFrameVisitor visitor(thread->GetManagedStack(), thread->GetInstrumentationStack(),
+ start_frame, frame_count, buf);
visitor.WalkStack();
return JDWP::ERR_NONE;
}
@@ -1695,7 +1698,8 @@
}
struct GetThisVisitor : public StackVisitor {
- GetThisVisitor(const ManagedStack* stack, const std::vector<InstrumentationStackFrame>* instrumentation_stack,
+ GetThisVisitor(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack,
Context* context, JDWP::FrameId frameId)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: StackVisitor(stack, instrumentation_stack, context), this_object(NULL), frame_id(frameId) {}
@@ -1758,7 +1762,8 @@
void Dbg::GetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag,
uint8_t* buf, size_t width) {
struct GetLocalVisitor : public StackVisitor {
- GetLocalVisitor(const ManagedStack* stack, const std::vector<InstrumentationStackFrame>* instrumentation_stack,
+ GetLocalVisitor(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack,
Context* context, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag,
uint8_t* buf, size_t width)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -1894,7 +1899,7 @@
void Dbg::SetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag,
uint64_t value, size_t width) {
struct SetLocalVisitor : public StackVisitor {
- SetLocalVisitor(const ManagedStack* stack, const std::vector<InstrumentationStackFrame>* instrumentation_stack, Context* context,
+ SetLocalVisitor(const ManagedStack* stack, const std::deque<InstrumentationStackFrame>* instrumentation_stack, Context* context,
JDWP::FrameId frame_id, int slot, JDWP::JdwpTag tag, uint64_t value,
size_t width)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -2193,7 +2198,7 @@
struct SingleStepStackVisitor : public StackVisitor {
SingleStepStackVisitor(const ManagedStack* stack,
- const std::vector<InstrumentationStackFrame>* instrumentation_stack)
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack)
EXCLUSIVE_LOCKS_REQUIRED(Locks::breakpoint_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: StackVisitor(stack, instrumentation_stack, NULL) {
@@ -3179,7 +3184,8 @@
struct AllocRecordStackVisitor : public StackVisitor {
AllocRecordStackVisitor(const ManagedStack* stack,
- const std::vector<InstrumentationStackFrame>* instrumentation_stack, AllocRecord* record)
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack,
+ AllocRecord* record)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: StackVisitor(stack, instrumentation_stack, NULL), record(record), depth(0) {}
diff --git a/src/instrumentation.cc b/src/instrumentation.cc
index 28f8cb2..bcf7c5d 100644
--- a/src/instrumentation.cc
+++ b/src/instrumentation.cc
@@ -72,28 +72,83 @@
return true;
}
-static void InstrumentationRestoreStack(Thread* self, void*) NO_THREAD_SAFETY_ANALYSIS {
- struct RestoreStackVisitor : public StackVisitor {
- RestoreStackVisitor(Thread* self)
- : StackVisitor(self->GetManagedStack(), self->GetInstrumentationStack(), NULL), self_(self) {}
+void InstrumentationInstallStack(Thread* self, void* arg)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ struct InstallStackVisitor : public StackVisitor {
+ InstallStackVisitor(Thread* self, uintptr_t instrumentation_exit_pc)
+ : StackVisitor(self->GetManagedStack(), self->GetInstrumentationStack(), NULL),
+ self_(self), instrumentation_exit_pc_(instrumentation_exit_pc) {}
- virtual bool VisitFrame() {
+ virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (GetCurrentQuickFrame() == NULL) {
+ return true; // Ignore shadow frames.
+ }
+ AbstractMethod* m = GetMethod();
+ if (m == NULL) {
+ return true; // Ignore upcalls.
+ }
+ if (m->GetDexMethodIndex() == DexFile::kDexNoIndex16) {
+ return true; // Ignore unresolved methods since they will be instrumented after resolution.
+ }
+ uintptr_t pc = GetReturnPc();
+ InstrumentationStackFrame instrumentation_frame(m, pc, GetFrameId());
+ self_->PushBackInstrumentationStackFrame(instrumentation_frame);
+ SetReturnPc(instrumentation_exit_pc_);
+ return true; // Continue.
+ }
+ Thread* const self_;
+ const uintptr_t instrumentation_exit_pc_;
+ };
+ uintptr_t instrumentation_exit_pc = GetInstrumentationExitPc();
+ InstallStackVisitor visitor(self, instrumentation_exit_pc);
+ visitor.WalkStack(true);
+ Trace* trace = reinterpret_cast<Trace*>(arg);
+ if (trace != NULL) {
+ std::deque<InstrumentationStackFrame>::const_reverse_iterator it =
+ self->GetInstrumentationStack()->rbegin();
+ std::deque<InstrumentationStackFrame>::const_reverse_iterator end =
+ self->GetInstrumentationStack()->rend();
+ for (; it != end; ++it) {
+ trace->LogMethodTraceEvent(self, (*it).method_, Trace::kMethodTraceEnter);
+ }
+ }
+}
+
+static void InstrumentationRestoreStack(Thread* self, void*)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ struct RestoreStackVisitor : public StackVisitor {
+ RestoreStackVisitor(Thread* self, uintptr_t instrumentation_exit_pc)
+ : StackVisitor(self->GetManagedStack(), self->GetInstrumentationStack(), NULL),
+ self_(self), instrumentation_exit_pc_(instrumentation_exit_pc) {}
+
+ virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (self_->IsInstrumentationStackEmpty()) {
return false; // Stop.
}
+ AbstractMethod* m = GetMethod();
+ if (m == NULL) {
+ return true; // Ignore upcalls.
+ }
uintptr_t pc = GetReturnPc();
- if (IsInstrumentationExitPc(pc)) {
+ if (pc == instrumentation_exit_pc_) {
InstrumentationStackFrame instrumentation_frame = self_->PopInstrumentationStackFrame();
SetReturnPc(instrumentation_frame.return_pc_);
- CHECK(GetMethod() == instrumentation_frame.method_);
+ CHECK(m == instrumentation_frame.method_);
+ CHECK_EQ(GetFrameId(), instrumentation_frame.frame_id_);
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsMethodTracingActive()) {
+ Trace* trace = runtime->GetInstrumentation()->GetTrace();
+ trace->LogMethodTraceEvent(self_, m, Trace::kMethodTraceExit);
+ }
}
return true; // Continue.
}
-
- Thread* self_;
+ Thread* const self_;
+ const uintptr_t instrumentation_exit_pc_;
};
- RestoreStackVisitor visitor(self);
- visitor.WalkStack();
+ uintptr_t instrumentation_exit_pc = GetInstrumentationExitPc();
+ RestoreStackVisitor visitor(self, instrumentation_exit_pc);
+ visitor.WalkStack(true);
}
Instrumentation::~Instrumentation() {
@@ -101,7 +156,11 @@
}
void Instrumentation::InstallStubs() {
+ Thread* self = Thread::Current();
+ Locks::thread_list_lock_->AssertNotHeld(self);
Runtime::Current()->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, NULL);
+ MutexLock mu(self, *Locks::thread_list_lock_);
+ Runtime::Current()->GetThreadList()->ForEach(InstrumentationInstallStack, GetTrace());
}
void Instrumentation::UninstallStubs() {
diff --git a/src/instrumentation.h b/src/instrumentation.h
index b17e020..00060ce 100644
--- a/src/instrumentation.h
+++ b/src/instrumentation.h
@@ -35,12 +35,13 @@
uint32_t InstrumentationMethodUnwindFromCode(Thread* self);
struct InstrumentationStackFrame {
- InstrumentationStackFrame(AbstractMethod* method, uintptr_t return_pc)
- : method_(method), return_pc_(return_pc) {
+ InstrumentationStackFrame() : method_(NULL), return_pc_(0), frame_id_(0) {}
+ InstrumentationStackFrame(AbstractMethod* method, uintptr_t return_pc, size_t frame_id)
+ : method_(method), return_pc_(return_pc), frame_id_(frame_id) {
}
-
AbstractMethod* method_;
uintptr_t return_pc_;
+ size_t frame_id_;
};
class Instrumentation {
@@ -49,7 +50,7 @@
~Instrumentation();
// Replaces code of each method with a pointer to a stub for method tracing.
- void InstallStubs();
+ void InstallStubs() LOCKS_EXCLUDED(Locks::thread_list_lock_);
// Restores original code for each method and fixes the return values of each thread's stack.
void UninstallStubs() LOCKS_EXCLUDED(Locks::thread_list_lock_);
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index e425ee8..bff9f37 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -546,11 +546,11 @@
}
static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ShadowFrame& shadow_frame, JValue result_register)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
const uint16_t* insns = code_item->insns_;
const Instruction* inst = Instruction::At(insns + shadow_frame.GetDexPC());
bool entry = (inst->GetDexPc(insns) == 0);
- JValue result_register;
while (true) {
CheckSuspend(self);
uint32_t dex_pc = inst->GetDexPc(insns);
@@ -1846,7 +1846,7 @@
}
}
if (LIKELY(!method->IsNative())) {
- JValue r = Execute(self, mh, code_item, *shadow_frame.get());
+ JValue r = Execute(self, mh, code_item, *shadow_frame.get(), JValue());
if (result != NULL) {
*result = r;
}
@@ -1862,5 +1862,12 @@
self->PopShadowFrame();
}
+JValue EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame& shadow_frame, JValue ret_val)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ MethodHelper mh(shadow_frame.GetMethod());
+ const DexFile::CodeItem* code_item = mh.GetCodeItem();
+ return Execute(self, mh, code_item, shadow_frame, ret_val);
+}
+
} // namespace interpreter
} // namespace art
diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h
index ea07ce8..ec6832d 100644
--- a/src/interpreter/interpreter.h
+++ b/src/interpreter/interpreter.h
@@ -24,6 +24,7 @@
class AbstractMethod;
union JValue;
class Object;
+class ShadowFrame;
class Thread;
namespace interpreter {
@@ -32,6 +33,10 @@
JValue* args, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+extern JValue EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame& shadow_frame,
+ JValue ret_val)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
} // namespace interpreter
} // namespace art
diff --git a/src/jvalue.h b/src/jvalue.h
new file mode 100644
index 0000000..a7a1795
--- /dev/null
+++ b/src/jvalue.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_JVALUE_H_
+#define ART_SRC_JVALUE_H_
+
+#include "base/macros.h"
+
+namespace art {
+
+class Object;
+
+union PACKED(4) JValue {
+ // We default initialize JValue instances to all-zeros.
+ JValue() : j(0) {}
+
+ int8_t GetB() const { return b; }
+ void SetB(int8_t new_b) {
+ i = ((static_cast<int32_t>(new_b) << 24) >> 24); // Sign-extend.
+ }
+
+ uint16_t GetC() const { return c; }
+ void SetC(uint16_t new_c) { c = new_c; }
+
+ double GetD() const { return d; }
+ void SetD(double new_d) { d = new_d; }
+
+ float GetF() const { return f; }
+ void SetF(float new_f) { f = new_f; }
+
+ int32_t GetI() const { return i; }
+ void SetI(int32_t new_i) { i = new_i; }
+
+ int64_t GetJ() const { return j; }
+ void SetJ(int64_t new_j) { j = new_j; }
+
+ Object* GetL() const { return l; }
+ void SetL(Object* new_l) { l = new_l; }
+
+ int16_t GetS() const { return s; }
+ void SetS(int16_t new_s) {
+ i = ((static_cast<int32_t>(new_s) << 16) >> 16); // Sign-extend.
+ }
+
+ uint8_t GetZ() const { return z; }
+ void SetZ(uint8_t new_z) { z = new_z; }
+
+ private:
+ uint8_t z;
+ int8_t b;
+ uint16_t c;
+ int16_t s;
+ int32_t i;
+ int64_t j;
+ float f;
+ double d;
+ Object* l;
+};
+
+} // namespace art
+
+#endif // ART_SRC_JVALUE_H_
diff --git a/src/native/dalvik_system_VMStack.cc b/src/native/dalvik_system_VMStack.cc
index 0e6e675..8ce022d 100644
--- a/src/native/dalvik_system_VMStack.cc
+++ b/src/native/dalvik_system_VMStack.cc
@@ -51,7 +51,8 @@
}
}
-static jint VMStack_fillStackTraceElements(JNIEnv* env, jclass, jobject javaThread, jobjectArray javaSteArray) {
+static jint VMStack_fillStackTraceElements(JNIEnv* env, jclass, jobject javaThread,
+ jobjectArray javaSteArray) {
jobject trace = GetThreadStack(env, javaThread);
if (trace == NULL) {
return 0;
@@ -69,10 +70,11 @@
return soa.AddLocalReference<jobject>(visitor.caller->GetDeclaringClass()->GetClassLoader());
}
-static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass, jobject javaBootstrap, jobject javaSystem) {
+static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass, jobject javaBootstrap,
+ jobject javaSystem) {
struct ClosestUserClassLoaderVisitor : public StackVisitor {
ClosestUserClassLoaderVisitor(const ManagedStack* stack,
- const std::vector<InstrumentationStackFrame>* instrumentation_stack,
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack,
Object* bootstrap, Object* system)
: StackVisitor(stack, instrumentation_stack, NULL),
bootstrap(bootstrap), system(system), class_loader(NULL) {}
diff --git a/src/nth_caller_visitor.h b/src/nth_caller_visitor.h
index 3c1f2e0..15e62e2 100644
--- a/src/nth_caller_visitor.h
+++ b/src/nth_caller_visitor.h
@@ -24,7 +24,7 @@
// Walks up the stack 'n' callers, when used with Thread::WalkStack.
struct NthCallerVisitor : public StackVisitor {
- NthCallerVisitor(const ManagedStack* stack, const std::vector<InstrumentationStackFrame>* instrumentation_stack, size_t n)
+ NthCallerVisitor(const ManagedStack* stack, const std::deque<InstrumentationStackFrame>* instrumentation_stack, size_t n)
: StackVisitor(stack, instrumentation_stack, NULL), n(n), count(0), caller(NULL) {}
bool VisitFrame() {
diff --git a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
index f30ce24..041e12b 100644
--- a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
+++ b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
@@ -138,6 +138,7 @@
// Instrumentation entrypoints.
extern "C" void art_instrumentation_entry_from_code(void*);
extern "C" void art_instrumentation_exit_from_code();
+extern "C" void art_deoptimize();
void InitEntryPoints(EntryPoints* points) {
// Alloc
@@ -251,9 +252,12 @@
points->pUpdateDebuggerFromCode = (enabled ? art_update_debugger : NULL);
}
-bool IsInstrumentationExitPc(uintptr_t pc) {
- uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_instrumentation_exit_from_code);
- return pc == trace_exit;
+uintptr_t GetInstrumentationExitPc() {
+ return reinterpret_cast<uintptr_t>(art_instrumentation_exit_from_code);
+}
+
+uintptr_t GetDeoptimizationEntryPoint() {
+ return reinterpret_cast<uintptr_t>(art_deoptimize);
}
void* GetInstrumentationEntryPoint() {
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 34caeac..7901c5f 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -743,7 +743,7 @@
ldrh r0, [rSELF, #THREAD_FLAGS_OFFSET]
mov rSUSPEND, #SUSPEND_CHECK_INTERVAL @ reset rSUSPEND to SUSPEND_CHECK_INTERVAL
cmp r0, #0 @ check Thread::Current()->suspend_count_ == 0
- bxeq rLR @ return if suspend_count_ == 0
+ bxeq lr @ return if suspend_count_ == 0
mov r0, rSELF
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves for stack crawl
mov r1, sp
@@ -780,19 +780,54 @@
*/
ALIGN_FUNCTION_ENTRY
art_instrumentation_entry_from_code:
+ mov r12, sp @ remember bottom of caller's frame
push {r0-r3} @ save arguments (4 words)
mov r1, r9 @ pass Thread::Current
- mov r2, lr @ pass LR
- blx artInstrumentationMethodEntryFromCode @ (Method*, Thread*, LR)
+ mov r2, r12 @ pass SP
+ mov r3, lr @ pass LR
+ blx artInstrumentationMethodEntryFromCode @ (Method*, Thread*, SP, LR)
mov r12, r0 @ r12 holds reference to code
pop {r0-r3} @ restore arguments
blx r12 @ call method
art_instrumentation_exit_from_code:
+ mov r12, sp @ remember bottom of caller's frame
push {r0-r1} @ save return value
- blx artInstrumentationMethodExitFromCode @ ()
- mov lr, r0 @ restore link register
+ sub sp, #8 @ align stack
+ mov r0, r9 @ pass Thread::Current
+ mov r1, r12 @ pass SP
+ blx artInstrumentationMethodExitFromCode @ (Thread*, SP)
+ add sp, #8
+ mov r2, r0 @ link register saved by instrumentation
+ mov lr, r1 @ r1 is holding link register if we're to bounce to deoptimize
pop {r0, r1} @ restore return value
- bx lr @ return
+ bx r2 @ return
+
+ .global art_deoptimize
+ .extern artDeoptimize
+ .extern artEnterInterpreterFromDeoptimize
+ /*
+ * The thread's enter interpreter flag is set and so we should transition to the interpreter
+ * rather than allow execution to continue in the frame below. There may be live results in
+ * registers depending on how complete the operation is when we safepoint - for example, a
+ * set operation may have completed while a get operation needs writing back into the vregs.
+ */
+ ALIGN_FUNCTION_ENTRY
+art_deoptimize:
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ mov r2, r9 @ Set up args.
+ mov r3, sp
+ blx artDeoptimize @ artDeoptimize(return value, Thread*, SP)
+ @ Returns caller method's frame size.
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+ cmp r0, #0 @ Was the caller an upcall?
+ bxeq lr @ Return if caller was upcall.
+ add r12, sp, r0 @ r12 == bottom of caller's frame.
+ ldr lr, [r12, #-4] @ Restore lr.
+ mov sp, r12 @ Remove frame.
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+ blx artEnterInterpreterFromDeoptimize @ Enter interpreter, callee-save ends stack fragment.
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+ bx lr @ Return to caller.
.global art_mul_long
/*
diff --git a/src/oat/runtime/oat_support_entrypoints.h b/src/oat/runtime/oat_support_entrypoints.h
index 284fc0b..285105d 100644
--- a/src/oat/runtime/oat_support_entrypoints.h
+++ b/src/oat/runtime/oat_support_entrypoints.h
@@ -146,8 +146,11 @@
// Change the debugger entry point in the data structure.
void ChangeDebuggerEntryPoint(EntryPoints* points, bool enabled);
-// Is the given return_pc the instrumentation exit return pc?
-bool IsInstrumentationExitPc(uintptr_t pc);
+// The return_pc of instrumentation exit stub.
+uintptr_t GetInstrumentationExitPc();
+
+// Entry point for deoptimization.
+uintptr_t GetDeoptimizationEntryPoint();
// Return address of instrumentation stub.
void* GetInstrumentationEntryPoint();
diff --git a/src/oat/runtime/support_deoptimize.cc b/src/oat/runtime/support_deoptimize.cc
new file mode 100644
index 0000000..13fd3ae
--- /dev/null
+++ b/src/oat/runtime/support_deoptimize.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "callee_save_frame.h"
+#include "interpreter/interpreter.h"
+#include "object.h" // for JValue
+#include "object_utils.h"
+#include "stack.h"
+#include "thread.h"
+#include "verifier/method_verifier.h"
+
+namespace art {
+
+extern "C" uint64_t artDeoptimize(JValue ret_val, Thread* self, AbstractMethod** sp)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ // Return value may hold Object* so avoid suspension.
+ const char* old_cause = self->StartAssertNoThreadSuspension("Deoptimizing stack frame");
+ CHECK(old_cause == NULL);
+ class DeoptimizationVisitor : public StackVisitor {
+ public:
+ DeoptimizationVisitor(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack,
+ Context* context)
+ : StackVisitor(stack, instrumentation_stack, context), shadow_frame_(NULL),
+ runtime_frames_(0) { }
+
+ virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ AbstractMethod* m = GetMethod();
+ if (m->IsRuntimeMethod()) {
+ if (runtime_frames_ == 0) {
+ runtime_frames_++;
+ return true; // Skip the callee save frame.
+ } else {
+ return false; // Caller was an upcall.
+ }
+ }
+ MethodHelper mh(m);
+ const DexFile::CodeItem* code_item = mh.GetCodeItem();
+ CHECK(code_item != NULL);
+ uint16_t num_regs = code_item->registers_size_;
+ shadow_frame_ = ShadowFrame::Create(num_regs, NULL, m, GetDexPc());
+ std::vector<int32_t> kinds =
+ verifier::MethodVerifier::DescribeVRegs(m->GetDexMethodIndex(), &mh.GetDexFile(),
+ mh.GetDexCache(), mh.GetClassLoader(),
+ mh.GetClassDefIndex(), code_item, m,
+ m->GetAccessFlags(), GetDexPc());
+ for(uint16_t reg = 0; reg < num_regs; reg++) {
+ VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
+ switch (kind) {
+ case kUndefined:
+ shadow_frame_->SetVReg(reg, 0xEBADDE09);
+ break;
+ case kConstant:
+ shadow_frame_->SetVReg(reg, kinds.at((reg * 2) + 1));
+ break;
+ default:
+ shadow_frame_->SetVReg(reg, GetVReg(m, reg, kind));
+ break;
+ }
+ }
+ return false; // Stop now we have built the shadow frame.
+ }
+ ShadowFrame* shadow_frame_;
+ uint32_t runtime_frames_;
+ } visitor(self->GetManagedStack(), self->GetInstrumentationStack(), self->GetLongJumpContext());
+ visitor.WalkStack(false);
+ if (visitor.shadow_frame_ != NULL) {
+ self->SetDeoptimizationShadowFrame(visitor.shadow_frame_, ret_val);
+ return (*sp)->GetFrameSizeInBytes();
+ } else {
+ return 0; // Caller was an upcall.
+ }
+}
+
+
+extern "C" JValue artEnterInterpreterFromDeoptimize(Thread* self, AbstractMethod** sp)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ JValue return_value;
+ UniquePtr<ShadowFrame> shadow_frame(self->GetAndClearDeoptimizationShadowFrame(&return_value));
+ self->EndAssertNoThreadSuspension(NULL);
+ return interpreter::EnterInterpreterFromDeoptimize(self, *shadow_frame.get(), return_value);
+}
+
+} // namespace art
diff --git a/src/oat/runtime/support_instrumentation.cc b/src/oat/runtime/support_instrumentation.cc
index 8c5e442..339c11a 100644
--- a/src/oat/runtime/support_instrumentation.cc
+++ b/src/oat/runtime/support_instrumentation.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "base/logging.h"
#include "instrumentation.h"
#include "runtime.h"
#include "thread.h"
@@ -22,26 +23,61 @@
namespace art {
extern "C" const void* artInstrumentationMethodEntryFromCode(AbstractMethod* method, Thread* self,
- uintptr_t lr) {
+ AbstractMethod** sp, uintptr_t lr)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (*sp != NULL) {
+ self->SetTopOfStack(sp, lr);
+ }
+ self->VerifyStack();
Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
- Trace* trace = instrumentation->GetTrace();
- InstrumentationStackFrame instrumentation_frame = InstrumentationStackFrame(method, lr);
+ // +1 as frame id's start at 1, +1 as we haven't yet built this method's frame.
+ const size_t kFrameIdAdjust = 2;
+ size_t frame_id = StackVisitor::ComputeNumFrames(self->GetManagedStack(),
+ self->GetInstrumentationStack()) + kFrameIdAdjust;
+ InstrumentationStackFrame instrumentation_frame(method, lr, frame_id);
self->PushInstrumentationStackFrame(instrumentation_frame);
- trace->LogMethodTraceEvent(self, method, Trace::kMethodTraceEnter);
+ Trace* trace = instrumentation->GetTrace();
+ if (trace != NULL) {
+ trace->LogMethodTraceEvent(self, method, Trace::kMethodTraceEnter);
+ }
return instrumentation->GetSavedCodeFromMap(method);
}
-extern "C" uintptr_t artInstrumentationMethodExitFromCode() {
- Trace* trace = Runtime::Current()->GetInstrumentation()->GetTrace();
- InstrumentationStackFrame instrumentation_frame = Thread::Current()->PopInstrumentationStackFrame();
- AbstractMethod* method = instrumentation_frame.method_;
- uintptr_t lr = instrumentation_frame.return_pc_;
+extern "C" uint64_t artInstrumentationMethodExitFromCode(Thread* self, AbstractMethod** sp)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (*sp != NULL) {
+ self->SetTopOfStack(sp, 0);
+ }
+ self->VerifyStack();
- trace->LogMethodTraceEvent(Thread::Current(), method, Trace::kMethodTraceExit);
-
- return lr;
+ /*
+ // TODO: ComputeNumFrames currently fails here, so it's disabled.
+ // +1 as frame id's start at 1, +1 as we want the called frame not the frame being returned into.
+ const size_t kFrameIdAdjust = 2;
+ size_t frame_id = StackVisitor::ComputeNumFrames(self->GetManagedStack(),
+ self->GetInstrumentationStack()) + kFrameIdAdjust;
+ */
+ InstrumentationStackFrame instrumentation_frame;
+ instrumentation_frame = self->PopInstrumentationStackFrame();
+ /*
+ if (frame_id != instrumentation_frame.frame_id_) {
+ LOG(ERROR) << "Expected frame_id=" << frame_id << " but found " << instrumentation_frame.frame_id_;
+ StackVisitor::DescribeStack(self->GetManagedStack(), self->GetInstrumentationStack());
+ }
+ */
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsMethodTracingActive()) {
+ Trace* trace = runtime->GetInstrumentation()->GetTrace();
+ trace->LogMethodTraceEvent(self, instrumentation_frame.method_, Trace::kMethodTraceExit);
+ }
+ if (self->ReadFlag(kEnterInterpreter)) {
+ return static_cast<uint64_t>(GetDeoptimizationEntryPoint()) |
+ (static_cast<uint64_t>(instrumentation_frame.return_pc_) << 32);
+ } else {
+ return instrumentation_frame.return_pc_;
+ }
}
} // namespace art
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
index 9b32b8b..a3c845e 100644
--- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -233,8 +233,12 @@
UNIMPLEMENTED(FATAL);
}
-bool IsInstrumentationExitPc(uintptr_t) {
- return false;
+uintptr_t GetInstrumentationExitPc() {
+ return 0;
+}
+
+uintptr_t GetDeoptimizationEntryPoint() {
+ return 0;
}
void* GetInstrumentationEntryPoint() {
diff --git a/src/object.cc b/src/object.cc
index 8565c38..c3c4e13 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -591,8 +591,8 @@
return mapping_table[i + 1];
}
}
- LOG(FATAL) << "Failed to find Dex offset for PC offset 0x" << std::hex << sought_offset
- << " in " << PrettyMethod(this);
+ LOG(ERROR) << "Failed to find Dex offset for PC offset " << reinterpret_cast<void*>(sought_offset)
+ << "(PC " << reinterpret_cast<void*>(pc) << ") in " << PrettyMethod(this);
return DexFile::kDexNoIndex;
#else
// Compiler LLVM doesn't use the machine pc, we just use dex pc instead.
diff --git a/src/object.h b/src/object.h
index 0eea8c3..60e45c3 100644
--- a/src/object.h
+++ b/src/object.h
@@ -61,53 +61,7 @@
typedef PrimitiveArray<int32_t> IntArray;
typedef PrimitiveArray<int64_t> LongArray;
typedef PrimitiveArray<int16_t> ShortArray;
-
-union JValue {
- // We default initialize JValue instances to all-zeros.
- JValue() : j(0) {}
-
- int8_t GetB() const { return b; }
- void SetB(int8_t new_b) {
- i = ((static_cast<int32_t>(new_b) << 24) >> 24); // Sign-extend.
- }
-
- uint16_t GetC() const { return c; }
- void SetC(uint16_t new_c) { c = new_c; }
-
- double GetD() const { return d; }
- void SetD(double new_d) { d = new_d; }
-
- float GetF() const { return f; }
- void SetF(float new_f) { f = new_f; }
-
- int32_t GetI() const { return i; }
- void SetI(int32_t new_i) { i = new_i; }
-
- int64_t GetJ() const { return j; }
- void SetJ(int64_t new_j) { j = new_j; }
-
- Object* GetL() const { return l; }
- void SetL(Object* new_l) { l = new_l; }
-
- int16_t GetS() const { return s; }
- void SetS(int16_t new_s) {
- i = ((static_cast<int32_t>(new_s) << 16) >> 16); // Sign-extend.
- }
-
- uint8_t GetZ() const { return z; }
- void SetZ(uint8_t new_z) { z = new_z; }
-
- private:
- uint8_t z;
- int8_t b;
- uint16_t c;
- int16_t s;
- int32_t i;
- int64_t j;
- float f;
- double d;
- Object* l;
-};
+union JValue;
#if defined(ART_USE_LLVM_COMPILER)
namespace compiler_llvm {
diff --git a/src/stack.cc b/src/stack.cc
index ed44df9..e962dec 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -142,10 +142,11 @@
*reinterpret_cast<uintptr_t*>(pc_addr) = new_ret_pc;
}
-size_t StackVisitor::ComputeNumFrames() const {
+size_t StackVisitor::ComputeNumFrames(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instr_stack) {
struct NumFramesVisitor : public StackVisitor {
explicit NumFramesVisitor(const ManagedStack* stack,
- const std::vector<InstrumentationStackFrame>* instrumentation_stack)
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack)
: StackVisitor(stack, instrumentation_stack, NULL), frames(0) {}
virtual bool VisitFrame() {
@@ -155,15 +156,35 @@
size_t frames;
};
-
- NumFramesVisitor visitor(stack_start_, instrumentation_stack_);
+ UNUSED(instr_stack); // We don't use the instrumentation stack as we don't require dex pcs...
+ NumFramesVisitor visitor(stack, NULL);
visitor.WalkStack(true);
return visitor.frames;
}
+void StackVisitor::DescribeStack(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instr_stack) {
+ struct DescribeStackVisitor : public StackVisitor {
+ explicit DescribeStackVisitor(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack)
+ : StackVisitor(stack, instrumentation_stack, NULL) {}
+
+ virtual bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ LOG(INFO) << "Frame Id=" << GetFrameId() << " " << DescribeLocation();
+ return true;
+ }
+ };
+ DescribeStackVisitor visitor(stack, instr_stack);
+ visitor.WalkStack(true);
+}
+
std::string StackVisitor::DescribeLocation() const {
std::string result("Visiting method '");
- result += PrettyMethod(GetMethod());
+ AbstractMethod* m = GetMethod();
+ if (m == NULL) {
+ return "upcall";
+ }
+ result += PrettyMethod(m);
result += StringPrintf("' at dex PC 0x%04zx", GetDexPc());
if (!IsShadowFrame()) {
result += StringPrintf(" (native PC %p)", reinterpret_cast<void*>(GetCurrentQuickFramePc()));
@@ -189,7 +210,7 @@
}
void StackVisitor::WalkStack(bool include_transitions) {
- bool method_tracing_active = Runtime::Current()->IsMethodTracingActive();
+ bool method_tracing_active = instrumentation_stack_ != NULL;
uint32_t instrumentation_stack_depth = 0;
for (const ManagedStack* current_fragment = stack_start_; current_fragment != NULL;
current_fragment = current_fragment->GetLink()) {
@@ -218,7 +239,7 @@
// While profiling, the return pc is restored from the side stack, except when walking
// the stack for an exception where the side stack will be unwound in VisitFrame.
// TODO: stop using include_transitions as a proxy for is this the catch block visitor.
- if (IsInstrumentationExitPc(return_pc) && !include_transitions) {
+ if (GetInstrumentationExitPc() == return_pc && !include_transitions) {
// TODO: unify trace and managed stack.
InstrumentationStackFrame instrumentation_frame = GetInstrumentationStackFrame(instrumentation_stack_depth);
instrumentation_stack_depth++;
diff --git a/src/stack.h b/src/stack.h
index 30de26d..c3b837f 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -331,7 +331,8 @@
class StackVisitor {
protected:
- StackVisitor(const ManagedStack* stack, const std::vector<InstrumentationStackFrame>* instrumentation_stack,
+ StackVisitor(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack,
Context* context)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: stack_start_(stack), instrumentation_stack_(instrumentation_stack), cur_shadow_frame_(NULL),
@@ -388,7 +389,7 @@
size_t GetNumFrames() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (num_frames_ == 0) {
- num_frames_ = ComputeNumFrames();
+ num_frames_ = ComputeNumFrames(stack_start_, instrumentation_stack_);
}
return num_frames_;
}
@@ -492,17 +493,24 @@
std::string DescribeLocation() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static size_t ComputeNumFrames(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instr_stack)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static void DescribeStack(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instr_stack)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
private:
- size_t ComputeNumFrames() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
InstrumentationStackFrame GetInstrumentationStackFrame(uint32_t depth) const {
- return instrumentation_stack_->at(instrumentation_stack_->size() - depth - 1);
+ return instrumentation_stack_->at(depth);
}
void SanityCheckFrame() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const ManagedStack* const stack_start_;
- const std::vector<InstrumentationStackFrame>* const instrumentation_stack_;
+ const std::deque<InstrumentationStackFrame>* const instrumentation_stack_;
ShadowFrame* cur_shadow_frame_;
AbstractMethod** cur_quick_frame_;
uintptr_t cur_quick_frame_pc_;
diff --git a/src/thread.cc b/src/thread.cc
index aa13ad2..484806e 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -93,6 +93,21 @@
#endif
}
+
+void Thread::SetDeoptimizationShadowFrame(ShadowFrame* sf, const JValue& ret_val) {
+ CHECK(sf != NULL);
+ deoptimization_shadow_frame_ = sf;
+ deoptimization_return_value_.SetJ(ret_val.GetJ());
+}
+
+ShadowFrame* Thread::GetAndClearDeoptimizationShadowFrame(JValue* ret_val) {
+ ShadowFrame* sf = deoptimization_shadow_frame_;
+ DCHECK(sf != NULL);
+ deoptimization_shadow_frame_ = NULL;
+ ret_val->SetJ(deoptimization_return_value_.GetJ());
+ return sf;
+}
+
void Thread::InitTid() {
tid_ = ::art::GetTid();
}
@@ -965,7 +980,7 @@
throwing_OutOfMemoryError_(false),
debug_suspend_count_(0),
debug_invoke_req_(new DebugInvokeReq),
- instrumentation_stack_(new std::vector<InstrumentationStackFrame>),
+ instrumentation_stack_(new std::deque<InstrumentationStackFrame>),
name_(new std::string(kThreadNameDuringStartup)),
daemon_(daemon),
pthread_self_(0),
@@ -1240,7 +1255,7 @@
class CountStackDepthVisitor : public StackVisitor {
public:
CountStackDepthVisitor(const ManagedStack* stack,
- const std::vector<InstrumentationStackFrame>* instrumentation_stack)
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: StackVisitor(stack, instrumentation_stack, NULL),
depth_(0), skip_depth_(0), skipping_(true) {}
@@ -1281,7 +1296,7 @@
class BuildInternalStackTraceVisitor : public StackVisitor {
public:
explicit BuildInternalStackTraceVisitor(Thread* self, const ManagedStack* stack,
- const std::vector<InstrumentationStackFrame>* instrumentation_stack,
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack,
int skip_depth)
: StackVisitor(stack, instrumentation_stack, NULL), self_(self),
skip_depth_(skip_depth), count_(0), dex_pc_trace_(NULL), method_trace_(NULL) {}
@@ -1360,8 +1375,8 @@
int32_t skip_depth = count_visitor.GetSkipDepth();
// Build internal stack trace.
- BuildInternalStackTraceVisitor build_trace_visitor(soa.Self(), GetManagedStack(), GetInstrumentationStack(),
- skip_depth);
+ BuildInternalStackTraceVisitor build_trace_visitor(soa.Self(), GetManagedStack(),
+ GetInstrumentationStack(), skip_depth);
if (!build_trace_visitor.Init(depth)) {
return NULL; // Allocation failed.
}
@@ -1703,7 +1718,8 @@
native_method_count_++;
} else {
// Unwind stack when an exception occurs during instrumentation
- if (UNLIKELY(method_tracing_active_ && IsInstrumentationExitPc(GetCurrentQuickFramePc()))) {
+ if (UNLIKELY(method_tracing_active_ &&
+ GetInstrumentationExitPc() == GetCurrentQuickFramePc())) {
uintptr_t pc = InstrumentationMethodUnwindFromCode(Thread::Current());
dex_pc = method->ToDexPc(pc);
} else {
@@ -1802,7 +1818,7 @@
AbstractMethod* Thread::GetCurrentMethod(uint32_t* dex_pc, size_t* frame_id) const {
struct CurrentMethodVisitor : public StackVisitor {
CurrentMethodVisitor(const ManagedStack* stack,
- const std::vector<InstrumentationStackFrame>* instrumentation_stack)
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: StackVisitor(stack, instrumentation_stack, NULL), method_(NULL), dex_pc_(0), frame_id_(0) {}
@@ -1844,7 +1860,8 @@
template <typename RootVisitor>
class ReferenceMapVisitor : public StackVisitor {
public:
- ReferenceMapVisitor(const ManagedStack* stack, const std::vector<InstrumentationStackFrame>* instrumentation_stack,
+ ReferenceMapVisitor(const ManagedStack* stack,
+ const std::deque<InstrumentationStackFrame>* instrumentation_stack,
Context* context, const RootVisitor& visitor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: StackVisitor(stack, instrumentation_stack, context), visitor_(visitor) {}
@@ -2013,8 +2030,8 @@
// Visit roots on this thread's stack
Context* context = GetLongJumpContext();
VerifyCallbackVisitor visitorToCallback(visitor, arg);
- ReferenceMapVisitor<VerifyCallbackVisitor> mapper(GetManagedStack(), GetInstrumentationStack(), context,
- visitorToCallback);
+ ReferenceMapVisitor<VerifyCallbackVisitor> mapper(GetManagedStack(), GetInstrumentationStack(),
+ context, visitorToCallback);
mapper.WalkStack();
ReleaseLongJumpContext(context);
}
diff --git a/src/thread.h b/src/thread.h
index 29ae7c1..e8f69db 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -20,15 +20,16 @@
#include <pthread.h>
#include <bitset>
+#include <deque>
#include <iosfwd>
#include <list>
#include <string>
-#include <vector>
#include "base/macros.h"
#include "closure.h"
#include "globals.h"
#include "instrumentation.h"
+#include "jvalue.h"
#include "oat/runtime/oat_support_entrypoints.h"
#include "locks.h"
#include "offsets.h"
@@ -566,7 +567,11 @@
void SetDebuggerUpdatesEnabled(bool enabled);
- const std::vector<InstrumentationStackFrame>* GetInstrumentationStack() const {
+ void SetDeoptimizationShadowFrame(ShadowFrame* sf, const JValue& ret_val);
+
+ ShadowFrame* GetAndClearDeoptimizationShadowFrame(JValue* ret_val);
+
+ const std::deque<InstrumentationStackFrame>* GetInstrumentationStack() const {
return instrumentation_stack_;
}
@@ -575,12 +580,16 @@
}
void PushInstrumentationStackFrame(const InstrumentationStackFrame& frame) {
+ instrumentation_stack_->push_front(frame);
+ }
+
+ void PushBackInstrumentationStackFrame(const InstrumentationStackFrame& frame) {
instrumentation_stack_->push_back(frame);
}
InstrumentationStackFrame PopInstrumentationStackFrame() {
- InstrumentationStackFrame frame = instrumentation_stack_->back();
- instrumentation_stack_->pop_back();
+ InstrumentationStackFrame frame = instrumentation_stack_->front();
+ instrumentation_stack_->pop_front();
return frame;
}
@@ -767,9 +776,13 @@
// JDWP invoke-during-breakpoint support.
DebugInvokeReq* debug_invoke_req_;
+ // Shadow frame that is used temporarily during the deoptimization of a method.
+ ShadowFrame* deoptimization_shadow_frame_;
+ JValue deoptimization_return_value_;
+
// Additional stack used by method instrumentation to store method and return pc values.
- // Stored as a pointer since std::vector is not PACKED.
- std::vector<InstrumentationStackFrame>* instrumentation_stack_;
+ // Stored as a pointer since std::deque is not PACKED.
+ std::deque<InstrumentationStackFrame>* instrumentation_stack_;
// A cached copy of the java.lang.Thread's name.
std::string* name_;