jeffhao | e343b76 | 2011-12-05 16:36:44 -0800 | [diff] [blame^] | 1 | // Copyright 2011 Google Inc. All Rights Reserved. |
| 2 | |
| 3 | #include "trace.h" |
| 4 | |
| 5 | #include "class_linker.h" |
| 6 | #include "dex_cache.h" |
| 7 | #include "runtime_support.h" |
| 8 | #include "thread.h" |
| 9 | |
| 10 | namespace art { |
| 11 | |
| 12 | #if defined(__arm__) |
| 13 | static bool InstallStubsClassVisitor(Class* klass, void* trace_stub) { |
| 14 | for (size_t i = 0; i < klass->NumDirectMethods(); i++) { |
| 15 | Method* method = klass->GetDirectMethod(i); |
| 16 | if (method->GetCode() != trace_stub) { |
| 17 | Trace::SaveAndUpdateCode(method, trace_stub); |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | for (size_t i = 0; i < klass->NumVirtualMethods(); i++) { |
| 22 | Method* method = klass->GetVirtualMethod(i); |
| 23 | if (method->GetCode() != trace_stub) { |
| 24 | Trace::SaveAndUpdateCode(method, trace_stub); |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | if (!klass->IsArrayClass() && !klass->IsPrimitive()) { |
| 29 | CodeAndDirectMethods* c_and_dm = klass->GetDexCache()->GetCodeAndDirectMethods(); |
| 30 | for (size_t i = 0; i < c_and_dm->NumCodeAndDirectMethods(); i++) { |
| 31 | Method* method = c_and_dm->GetResolvedMethod(i); |
| 32 | if (method != NULL && (size_t) method != i) { |
| 33 | c_and_dm->SetResolvedDirectMethodTraceEntry(i, trace_stub); |
| 34 | } |
| 35 | } |
| 36 | } |
| 37 | return true; |
| 38 | } |
| 39 | |
| 40 | static bool UninstallStubsClassVisitor(Class* klass, void* trace_stub) { |
| 41 | for (size_t i = 0; i < klass->NumDirectMethods(); i++) { |
| 42 | Method* method = klass->GetDirectMethod(i); |
| 43 | if (Trace::GetSavedCodeFromMap(method) != NULL) { |
| 44 | Trace::ResetSavedCode(method); |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | for (size_t i = 0; i < klass->NumVirtualMethods(); i++) { |
| 49 | Method* method = klass->GetVirtualMethod(i); |
| 50 | if (Trace::GetSavedCodeFromMap(method) != NULL) { |
| 51 | Trace::ResetSavedCode(method); |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | if (!klass->IsArrayClass() && !klass->IsPrimitive()) { |
| 56 | CodeAndDirectMethods* c_and_dm = klass->GetDexCache()->GetCodeAndDirectMethods(); |
| 57 | for (size_t i = 0; i < c_and_dm->NumCodeAndDirectMethods(); i++) { |
| 58 | const void* code = c_and_dm->GetResolvedCode(i); |
| 59 | if (code == trace_stub) { |
| 60 | Method* method = klass->GetDexCache()->GetResolvedMethod(i); |
| 61 | if (Trace::GetSavedCodeFromMap(method) != NULL) { |
| 62 | Trace::ResetSavedCode(method); |
| 63 | } |
| 64 | c_and_dm->SetResolvedDirectMethod(i, method); |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | return true; |
| 69 | } |
| 70 | |
| 71 | static void TraceRestoreStack(Thread* t, void*) { |
| 72 | uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code); |
| 73 | |
| 74 | Frame frame = t->GetTopOfStack(); |
| 75 | if (frame.GetSP() != 0) { |
| 76 | for ( ; frame.GetMethod() != 0; frame.Next()) { |
| 77 | if (t->IsTraceStackEmpty()) { |
| 78 | break; |
| 79 | } |
| 80 | uintptr_t pc = frame.GetReturnPC(); |
| 81 | Method* method = frame.GetMethod(); |
| 82 | if (trace_exit == pc) { |
| 83 | TraceStackFrame trace_frame = t->PopTraceStackFrame(); |
| 84 | frame.SetReturnPC(trace_frame.return_pc_); |
| 85 | CHECK(method == trace_frame.method_); |
| 86 | } |
| 87 | } |
| 88 | } |
| 89 | } |
| 90 | #endif |
| 91 | |
| 92 | bool Trace::method_tracing_active_ = false; |
| 93 | std::map<const Method*, const void*> Trace::saved_code_map_; |
| 94 | |
| 95 | void Trace::AddSavedCodeToMap(const Method* method, const void* code) { |
| 96 | saved_code_map_.insert(std::make_pair(method, code)); |
| 97 | } |
| 98 | |
| 99 | void Trace::RemoveSavedCodeFromMap(const Method* method) { |
| 100 | saved_code_map_.erase(method); |
| 101 | } |
| 102 | |
| 103 | const void* Trace::GetSavedCodeFromMap(const Method* method) { |
| 104 | return saved_code_map_.find(method)->second; |
| 105 | } |
| 106 | |
| 107 | void Trace::SaveAndUpdateCode(Method* method, const void* new_code) { |
| 108 | CHECK(GetSavedCodeFromMap(method) == NULL); |
| 109 | AddSavedCodeToMap(method, method->GetCode()); |
| 110 | method->SetCode(new_code); |
| 111 | } |
| 112 | |
| 113 | void Trace::ResetSavedCode(Method* method) { |
| 114 | CHECK(GetSavedCodeFromMap(method) != NULL); |
| 115 | method->SetCode(GetSavedCodeFromMap(method)); |
| 116 | RemoveSavedCodeFromMap(method); |
| 117 | } |
| 118 | |
| 119 | bool Trace::IsMethodTracingActive() { |
| 120 | return method_tracing_active_; |
| 121 | } |
| 122 | |
| 123 | void Trace::SetMethodTracingActive(bool value) { |
| 124 | method_tracing_active_ = value; |
| 125 | } |
| 126 | |
| 127 | void Trace::Start(const char* trace_filename, int trace_fd, int buffer_size, int flags, bool direct_to_ddms) { |
| 128 | LOG(INFO) << "Starting method tracing..."; |
| 129 | if (IsMethodTracingActive()) { |
| 130 | // TODO: Stop the trace, then start it up again instead of returning |
| 131 | LOG(INFO) << "Trace already in progress, stopping"; |
| 132 | return; |
| 133 | } |
| 134 | |
| 135 | SetMethodTracingActive(true); |
| 136 | InstallStubs(); |
| 137 | LOG(INFO) << "Method tracing started"; |
| 138 | } |
| 139 | |
| 140 | void Trace::Stop() { |
| 141 | LOG(INFO) << "Stopping method tracing..."; |
| 142 | if (!IsMethodTracingActive()) { |
| 143 | LOG(INFO) << "Trace stop requested, but not running"; |
| 144 | return; |
| 145 | } |
| 146 | |
| 147 | UninstallStubs(); |
| 148 | SetMethodTracingActive(false); |
| 149 | LOG(INFO) << "Method tracing stopped"; |
| 150 | } |
| 151 | |
| 152 | void Trace::InstallStubs() { |
| 153 | #if defined(__arm__) |
| 154 | { |
| 155 | ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable); |
| 156 | Runtime::Current()->GetThreadList()->SuspendAll(false); |
| 157 | } |
| 158 | |
| 159 | void* trace_stub = reinterpret_cast<void*>(art_trace_entry_from_code); |
| 160 | Runtime::Current()->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, trace_stub); |
| 161 | |
| 162 | Runtime::Current()->GetThreadList()->ResumeAll(false); |
| 163 | #else |
| 164 | UNIMPLEMENTED(WARNING); |
| 165 | #endif |
| 166 | } |
| 167 | |
| 168 | void Trace::UninstallStubs() { |
| 169 | #if defined(__arm__) |
| 170 | { |
| 171 | ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable); |
| 172 | Runtime::Current()->GetThreadList()->SuspendAll(false); |
| 173 | } |
| 174 | |
| 175 | void* trace_stub = reinterpret_cast<void*>(art_trace_entry_from_code); |
| 176 | Runtime::Current()->GetClassLinker()->VisitClasses(UninstallStubsClassVisitor, trace_stub); |
| 177 | |
| 178 | // Restore stacks of all threads |
| 179 | { |
| 180 | ScopedThreadListLock thread_list_lock; |
| 181 | Runtime::Current()->GetThreadList()->ForEach(TraceRestoreStack, NULL); |
| 182 | } |
| 183 | |
| 184 | Runtime::Current()->GetThreadList()->ResumeAll(false); |
| 185 | #else |
| 186 | UNIMPLEMENTED(WARNING); |
| 187 | #endif |
| 188 | } |
| 189 | |
| 190 | } // namespace art |