diff options
| author | 2015-08-25 15:12:33 +0000 | |
|---|---|---|
| committer | 2015-08-26 16:54:32 +0200 | |
| commit | 0747466fca310eedea5fc49e37d54f240a0b3c0f (patch) | |
| tree | 6d27922fa35330dd8d863ea56c82c5f04b711822 /runtime/thread.cc | |
| parent | 9ee5d6cdc14ac94b64ea1961bf221bad48746929 (diff) | |
Revert "Revert "Fix deoptimization with pending exception""
This reverts commit 6e2d5747d00697a25251d25dd33b953e54709507.
Fixes the deoptimization path from compiled code (generated by the
Optimizing compiler) by adding wrapper artDeoptimizeFromCompiledCode.
This wrapper, called through the matching assembler stub
art_quick_deoptimize_from_compiled_code, pushes the deoptimization
context just before deoptimizing the stack.
Bug: 23371176
Bug: 19944235
Change-Id: Ia7082656998aebdd0157438f7e6504c120e10d3e
Diffstat (limited to 'runtime/thread.cc')
| -rw-r--r-- | runtime/thread.cc | 82 |
1 files changed, 54 insertions, 28 deletions
diff --git a/runtime/thread.cc b/runtime/thread.cc index a33e150b93..63534b131b 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -162,27 +162,41 @@ void Thread::ResetQuickAllocEntryPointsForThread() { ResetQuickAllocEntryPoints(&tlsPtr_.quick_entrypoints); } -class DeoptimizationReturnValueRecord { +class DeoptimizationContextRecord { public: - DeoptimizationReturnValueRecord(const JValue& ret_val, - bool is_reference, - DeoptimizationReturnValueRecord* link) - : ret_val_(ret_val), is_reference_(is_reference), link_(link) {} + DeoptimizationContextRecord(const JValue& ret_val, bool is_reference, + mirror::Throwable* pending_exception, + DeoptimizationContextRecord* link) + : ret_val_(ret_val), is_reference_(is_reference), pending_exception_(pending_exception), + link_(link) {} JValue GetReturnValue() const { return ret_val_; } bool IsReference() const { return is_reference_; } - DeoptimizationReturnValueRecord* GetLink() const { return link_; } - mirror::Object** GetGCRoot() { + mirror::Throwable* GetPendingException() const { return pending_exception_; } + DeoptimizationContextRecord* GetLink() const { return link_; } + mirror::Object** GetReturnValueAsGCRoot() { DCHECK(is_reference_); return ret_val_.GetGCRoot(); } + mirror::Object** GetPendingExceptionAsGCRoot() { + return reinterpret_cast<mirror::Object**>(&pending_exception_); + } private: + // The value returned by the method at the top of the stack before deoptimization. JValue ret_val_; + + // Indicates whether the returned value is a reference. If so, the GC will visit it. const bool is_reference_; - DeoptimizationReturnValueRecord* const link_; - DISALLOW_COPY_AND_ASSIGN(DeoptimizationReturnValueRecord); + // The exception that was pending before deoptimization (or null if there was no pending + // exception). + mirror::Throwable* pending_exception_; + + // A link to the previous DeoptimizationContextRecord. + DeoptimizationContextRecord* const link_; + + DISALLOW_COPY_AND_ASSIGN(DeoptimizationContextRecord); }; class StackedShadowFrameRecord { @@ -206,22 +220,28 @@ class StackedShadowFrameRecord { DISALLOW_COPY_AND_ASSIGN(StackedShadowFrameRecord); }; -void Thread::PushAndClearDeoptimizationReturnValue() { - DeoptimizationReturnValueRecord* record = new DeoptimizationReturnValueRecord( - tls64_.deoptimization_return_value, - tls32_.deoptimization_return_value_is_reference, - tlsPtr_.deoptimization_return_value_stack); - tlsPtr_.deoptimization_return_value_stack = record; - ClearDeoptimizationReturnValue(); +void Thread::PushDeoptimizationContext(const JValue& return_value, bool is_reference, + mirror::Throwable* exception) { + DeoptimizationContextRecord* record = new DeoptimizationContextRecord( + return_value, + is_reference, + exception, + tlsPtr_.deoptimization_context_stack); + tlsPtr_.deoptimization_context_stack = record; +} + +void Thread::PopDeoptimizationContext(JValue* result, mirror::Throwable** exception) { + AssertHasDeoptimizationContext(); + DeoptimizationContextRecord* record = tlsPtr_.deoptimization_context_stack; + tlsPtr_.deoptimization_context_stack = record->GetLink(); + result->SetJ(record->GetReturnValue().GetJ()); + *exception = record->GetPendingException(); + delete record; } -JValue Thread::PopDeoptimizationReturnValue() { - DeoptimizationReturnValueRecord* record = tlsPtr_.deoptimization_return_value_stack; - DCHECK(record != nullptr); - tlsPtr_.deoptimization_return_value_stack = record->GetLink(); - JValue ret_val(record->GetReturnValue()); - delete record; - return ret_val; +void Thread::AssertHasDeoptimizationContext() { + CHECK(tlsPtr_.deoptimization_context_stack != nullptr) + << "No deoptimization context for thread " << *this; } void Thread::PushStackedShadowFrame(ShadowFrame* sf, StackedShadowFrameType type) { @@ -1575,6 +1595,9 @@ Thread::~Thread() { CHECK(tlsPtr_.flip_function == nullptr); CHECK_EQ(tls32_.suspended_at_suspend_check, false); + // Make sure we processed all deoptimization requests. + CHECK(tlsPtr_.deoptimization_context_stack == nullptr) << "Missed deoptimization"; + // We may be deleting a still born thread. SetStateUnsafe(kTerminated); @@ -2593,7 +2616,7 @@ void Thread::VisitRoots(RootVisitor* visitor) { visitor->VisitRootIfNonNull(&tlsPtr_.opeer, RootInfo(kRootThreadObject, thread_id)); if (tlsPtr_.exception != nullptr && tlsPtr_.exception != GetDeoptimizationException()) { visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&tlsPtr_.exception), - RootInfo(kRootNativeStack, thread_id)); + RootInfo(kRootNativeStack, thread_id)); } visitor->VisitRootIfNonNull(&tlsPtr_.monitor_enter_object, RootInfo(kRootNativeStack, thread_id)); tlsPtr_.jni_env->locals.VisitRoots(visitor, RootInfo(kRootJNILocal, thread_id)); @@ -2602,6 +2625,7 @@ void Thread::VisitRoots(RootVisitor* visitor) { if (tlsPtr_.debug_invoke_req != nullptr) { tlsPtr_.debug_invoke_req->VisitRoots(visitor, RootInfo(kRootDebugger, thread_id)); } + // Visit roots for deoptimization. if (tlsPtr_.stacked_shadow_frame_record != nullptr) { RootCallbackVisitor visitor_to_callback(visitor, thread_id); ReferenceMapVisitor<RootCallbackVisitor> mapper(this, nullptr, visitor_to_callback); @@ -2615,14 +2639,16 @@ void Thread::VisitRoots(RootVisitor* visitor) { } } } - if (tlsPtr_.deoptimization_return_value_stack != nullptr) { - for (DeoptimizationReturnValueRecord* record = tlsPtr_.deoptimization_return_value_stack; + if (tlsPtr_.deoptimization_context_stack != nullptr) { + for (DeoptimizationContextRecord* record = tlsPtr_.deoptimization_context_stack; record != nullptr; record = record->GetLink()) { if (record->IsReference()) { - visitor->VisitRootIfNonNull(record->GetGCRoot(), - RootInfo(kRootThreadObject, thread_id)); + visitor->VisitRootIfNonNull(record->GetReturnValueAsGCRoot(), + RootInfo(kRootThreadObject, thread_id)); } + visitor->VisitRootIfNonNull(record->GetPendingExceptionAsGCRoot(), + RootInfo(kRootThreadObject, thread_id)); } } for (auto* verifier = tlsPtr_.method_verifier; verifier != nullptr; verifier = verifier->link_) { |