1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "base/logging.h" 18 #include "base/mutex.h" 19 #include "base/systrace.h" 20 #include "callee_save_frame.h" 21 #include "interpreter/interpreter.h" 22 #include "obj_ptr-inl.h" // TODO: Find the other include that isn't complete, and clean this up. 23 #include "quick_exception_handler.h" 24 #include "runtime.h" 25 #include "thread.h" 26 27 namespace art { 28 29 NO_RETURN static void artDeoptimizeImpl(Thread* self, DeoptimizationKind kind, bool single_frame) 30 REQUIRES_SHARED(Locks::mutator_lock_) { 31 Runtime::Current()->IncrementDeoptimizationCount(kind); 32 if (VLOG_IS_ON(deopt)) { 33 if (single_frame) { 34 // Deopt logging will be in DeoptimizeSingleFrame. It is there to take advantage of the 35 // specialized visitor that will show whether a method is Quick or Shadow. 36 } else { 37 LOG(INFO) << "Deopting:"; 38 self->Dump(LOG_STREAM(INFO)); 39 } 40 } 41 42 self->AssertHasDeoptimizationContext(); 43 QuickExceptionHandler exception_handler(self, true); 44 { 45 ScopedTrace trace(std::string("Deoptimization ") + GetDeoptimizationKindName(kind)); 46 if (single_frame) { 47 exception_handler.DeoptimizeSingleFrame(kind); 48 } else { 49 exception_handler.DeoptimizeStack(); 50 } 51 } 52 uintptr_t return_pc = exception_handler.UpdateInstrumentationStack(); 53 if (exception_handler.IsFullFragmentDone()) { 54 exception_handler.DoLongJump(true); 55 } else { 56 exception_handler.DeoptimizePartialFragmentFixup(return_pc); 57 // We cannot smash the caller-saves, as we need the ArtMethod in a parameter register that would 58 // be caller-saved. This has the downside that we cannot track incorrect register usage down the 59 // line. 60 exception_handler.DoLongJump(false); 61 } 62 } 63 64 extern "C" NO_RETURN void artDeoptimize(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { 65 ScopedQuickEntrypointChecks sqec(self); 66 artDeoptimizeImpl(self, DeoptimizationKind::kFullFrame, false); 67 } 68 69 // This is called directly from compiled code by an HDeoptimize. 70 extern "C" NO_RETURN void artDeoptimizeFromCompiledCode(DeoptimizationKind kind, Thread* self) 71 REQUIRES_SHARED(Locks::mutator_lock_) { 72 ScopedQuickEntrypointChecks sqec(self); 73 // Before deoptimizing to interpreter, we must push the deoptimization context. 74 JValue return_value; 75 return_value.SetJ(0); // we never deoptimize from compiled code with an invoke result. 76 self->PushDeoptimizationContext(return_value, false, /* from_code */ true, self->GetException()); 77 artDeoptimizeImpl(self, kind, true); 78 } 79 80 } // namespace art 81