/* * Copyright (C) 2018 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 "gc/scoped_gc_critical_section.h" #include "instrumentation.h" #include "runtime.h" #include "runtime_callbacks.h" #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" #include "thread_list.h" namespace tracefast { #if ((!defined(TRACEFAST_INTERPRETER) && !defined(TRACEFAST_TRAMPOLINE)) || \ (defined(TRACEFAST_INTERPRETER) && defined(TRACEFAST_TRAMPOLINE))) #error Must set one of TRACEFAST_TRAMPOLINE or TRACEFAST_INTERPRETER during build #endif #ifdef TRACEFAST_INTERPRETER static constexpr const char* kTracerInstrumentationKey = "tracefast_INTERPRETER"; static constexpr bool kNeedsInterpreter = true; #else // defined(TRACEFAST_TRAMPOLINE) static constexpr const char* kTracerInstrumentationKey = "tracefast_TRAMPOLINE"; static constexpr bool kNeedsInterpreter = false; #endif // TRACEFAST_INITERPRETER class Tracer final : public art::instrumentation::InstrumentationListener { public: Tracer() {} void MethodEntered(art::Thread* thread ATTRIBUTE_UNUSED, art::Handle this_object ATTRIBUTE_UNUSED, art::ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void MethodExited(art::Thread* thread ATTRIBUTE_UNUSED, art::Handle this_object ATTRIBUTE_UNUSED, art::ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, art::Handle return_value ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void MethodExited(art::Thread* thread ATTRIBUTE_UNUSED, art::Handle this_object ATTRIBUTE_UNUSED, art::ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, const art::JValue& return_value ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void MethodUnwind(art::Thread* thread ATTRIBUTE_UNUSED, art::Handle this_object ATTRIBUTE_UNUSED, art::ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void DexPcMoved(art::Thread* thread ATTRIBUTE_UNUSED, art::Handle this_object ATTRIBUTE_UNUSED, art::ArtMethod* method ATTRIBUTE_UNUSED, uint32_t new_dex_pc ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void FieldRead(art::Thread* thread ATTRIBUTE_UNUSED, art::Handle this_object ATTRIBUTE_UNUSED, art::ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, art::ArtField* field ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void FieldWritten(art::Thread* thread ATTRIBUTE_UNUSED, art::Handle this_object ATTRIBUTE_UNUSED, art::ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, art::ArtField* field ATTRIBUTE_UNUSED, art::Handle field_value ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void FieldWritten(art::Thread* thread ATTRIBUTE_UNUSED, art::Handle this_object ATTRIBUTE_UNUSED, art::ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, art::ArtField* field ATTRIBUTE_UNUSED, const art::JValue& field_value ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void ExceptionThrown(art::Thread* thread ATTRIBUTE_UNUSED, art::Handle exception_object ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void ExceptionHandled(art::Thread* self ATTRIBUTE_UNUSED, art::Handle throwable ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void Branch(art::Thread* thread ATTRIBUTE_UNUSED, art::ArtMethod* method ATTRIBUTE_UNUSED, uint32_t dex_pc ATTRIBUTE_UNUSED, int32_t dex_pc_offset ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } void WatchedFramePop(art::Thread* thread ATTRIBUTE_UNUSED, const art::ShadowFrame& frame ATTRIBUTE_UNUSED) override REQUIRES_SHARED(art::Locks::mutator_lock_) { } private: DISALLOW_COPY_AND_ASSIGN(Tracer); }; Tracer gEmptyTracer; static void StartTracing() REQUIRES(!art::Locks::mutator_lock_, !art::Locks::thread_list_lock_, !art::Locks::thread_suspend_count_lock_) { art::Thread* self = art::Thread::Current(); art::Runtime* runtime = art::Runtime::Current(); art::gc::ScopedGCCriticalSection gcs(self, art::gc::kGcCauseInstrumentation, art::gc::kCollectorTypeInstrumentation); art::ScopedSuspendAll ssa("starting fast tracing"); runtime->GetInstrumentation()->AddListener(&gEmptyTracer, art::instrumentation::Instrumentation::kMethodEntered | art::instrumentation::Instrumentation::kMethodExited | art::instrumentation::Instrumentation::kMethodUnwind); runtime->GetInstrumentation()->EnableMethodTracing(kTracerInstrumentationKey, kNeedsInterpreter); } class TraceFastPhaseCB : public art::RuntimePhaseCallback { public: TraceFastPhaseCB() {} void NextRuntimePhase(art::RuntimePhaseCallback::RuntimePhase phase) override REQUIRES_SHARED(art::Locks::mutator_lock_) { if (phase == art::RuntimePhaseCallback::RuntimePhase::kInit) { art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kWaitingForMethodTracingStart); StartTracing(); } } }; TraceFastPhaseCB gPhaseCallback; // The plugin initialization function. extern "C" bool ArtPlugin_Initialize() REQUIRES_SHARED(art::Locks::mutator_lock_) { art::Runtime* runtime = art::Runtime::Current(); art::ScopedThreadSuspension stsc(art::Thread::Current(), art::ThreadState::kWaitingForMethodTracingStart); art::ScopedSuspendAll ssa("Add phase callback"); runtime->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gPhaseCallback); return true; } extern "C" bool ArtPlugin_Deinitialize() { // Don't need to bother doing anything. return true; } } // namespace tracefast