blob: 0a41a2e14147891edeea5c8f7397f4a2995ccc4b [file] [log] [blame]
jeffhaoe343b762011-12-05 16:36:44 -08001// 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
10namespace art {
11
12#if defined(__arm__)
13static 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
40static 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
71static 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
92bool Trace::method_tracing_active_ = false;
93std::map<const Method*, const void*> Trace::saved_code_map_;
94
95void Trace::AddSavedCodeToMap(const Method* method, const void* code) {
96 saved_code_map_.insert(std::make_pair(method, code));
97}
98
99void Trace::RemoveSavedCodeFromMap(const Method* method) {
100 saved_code_map_.erase(method);
101}
102
103const void* Trace::GetSavedCodeFromMap(const Method* method) {
104 return saved_code_map_.find(method)->second;
105}
106
107void 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
113void Trace::ResetSavedCode(Method* method) {
114 CHECK(GetSavedCodeFromMap(method) != NULL);
115 method->SetCode(GetSavedCodeFromMap(method));
116 RemoveSavedCodeFromMap(method);
117}
118
119bool Trace::IsMethodTracingActive() {
120 return method_tracing_active_;
121}
122
123void Trace::SetMethodTracingActive(bool value) {
124 method_tracing_active_ = value;
125}
126
127void 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
140void 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
152void 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
168void 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