blob: 5afacb8feb094063f2b75715de096e3fb6f9b3cc [file] [log] [blame]
Sebastien Hertz0462c4c2015-04-01 16:34:17 +02001/*
2 * Copyright (C) 2015 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 "instrumentation.h"
18
19#include "common_runtime_test.h"
20#include "common_throws.h"
21#include "class_linker-inl.h"
22#include "dex_file.h"
23#include "handle_scope-inl.h"
24#include "jvalue.h"
25#include "runtime.h"
26#include "scoped_thread_state_change.h"
27#include "thread_list.h"
28#include "thread-inl.h"
29
30namespace art {
31namespace instrumentation {
32
33class TestInstrumentationListener FINAL : public instrumentation::InstrumentationListener {
34 public:
35 TestInstrumentationListener()
36 : received_method_enter_event(false), received_method_exit_event(false),
37 received_method_unwind_event(false), received_dex_pc_moved_event(false),
38 received_field_read_event(false), received_field_written_event(false),
39 received_exception_caught_event(false), received_backward_branch_event(false) {}
40
41 virtual ~TestInstrumentationListener() {}
42
43 void MethodEntered(Thread* thread ATTRIBUTE_UNUSED,
44 mirror::Object* this_object ATTRIBUTE_UNUSED,
45 mirror::ArtMethod* method ATTRIBUTE_UNUSED,
46 uint32_t dex_pc ATTRIBUTE_UNUSED)
47 OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
48 received_method_enter_event = true;
49 }
50
51 void MethodExited(Thread* thread ATTRIBUTE_UNUSED,
52 mirror::Object* this_object ATTRIBUTE_UNUSED,
53 mirror::ArtMethod* method ATTRIBUTE_UNUSED,
54 uint32_t dex_pc ATTRIBUTE_UNUSED,
55 const JValue& return_value ATTRIBUTE_UNUSED)
56 OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
57 received_method_exit_event = true;
58 }
59
60 void MethodUnwind(Thread* thread ATTRIBUTE_UNUSED,
61 mirror::Object* this_object ATTRIBUTE_UNUSED,
62 mirror::ArtMethod* method ATTRIBUTE_UNUSED,
63 uint32_t dex_pc ATTRIBUTE_UNUSED)
64 OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
65 received_method_unwind_event = true;
66 }
67
68 void DexPcMoved(Thread* thread ATTRIBUTE_UNUSED,
69 mirror::Object* this_object ATTRIBUTE_UNUSED,
70 mirror::ArtMethod* method ATTRIBUTE_UNUSED,
71 uint32_t new_dex_pc ATTRIBUTE_UNUSED)
72 OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
73 received_dex_pc_moved_event = true;
74 }
75
76 void FieldRead(Thread* thread ATTRIBUTE_UNUSED,
77 mirror::Object* this_object ATTRIBUTE_UNUSED,
78 mirror::ArtMethod* method ATTRIBUTE_UNUSED,
79 uint32_t dex_pc ATTRIBUTE_UNUSED,
80 ArtField* field ATTRIBUTE_UNUSED)
81 OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
82 received_field_read_event = true;
83 }
84
85 void FieldWritten(Thread* thread ATTRIBUTE_UNUSED,
86 mirror::Object* this_object ATTRIBUTE_UNUSED,
87 mirror::ArtMethod* method ATTRIBUTE_UNUSED,
88 uint32_t dex_pc ATTRIBUTE_UNUSED,
89 ArtField* field ATTRIBUTE_UNUSED,
90 const JValue& field_value ATTRIBUTE_UNUSED)
91 OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
92 received_field_written_event = true;
93 }
94
95 void ExceptionCaught(Thread* thread ATTRIBUTE_UNUSED,
96 mirror::Throwable* exception_object ATTRIBUTE_UNUSED)
97 OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
98 received_exception_caught_event = true;
99 }
100
101 void BackwardBranch(Thread* thread ATTRIBUTE_UNUSED,
102 mirror::ArtMethod* method ATTRIBUTE_UNUSED,
103 int32_t dex_pc_offset ATTRIBUTE_UNUSED)
104 OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
105 received_backward_branch_event = true;
106 }
107
108 void Reset() {
109 received_method_enter_event = false;
110 received_method_exit_event = false;
111 received_method_unwind_event = false;
112 received_dex_pc_moved_event = false;
113 received_field_read_event = false;
114 received_field_written_event = false;
115 received_exception_caught_event = false;
116 received_backward_branch_event = false;
117 }
118
119 bool received_method_enter_event;
120 bool received_method_exit_event;
121 bool received_method_unwind_event;
122 bool received_dex_pc_moved_event;
123 bool received_field_read_event;
124 bool received_field_written_event;
125 bool received_exception_caught_event;
126 bool received_backward_branch_event;
127
128 private:
129 DISALLOW_COPY_AND_ASSIGN(TestInstrumentationListener);
130};
131
132class InstrumentationTest : public CommonRuntimeTest {
133 public:
134 // Unique keys used to test Instrumentation::ConfigureStubs.
135 static constexpr const char* kClientOneKey = "TestClient1";
136 static constexpr const char* kClientTwoKey = "TestClient2";
137
138 void CheckConfigureStubs(const char* key, Instrumentation::InstrumentationLevel level) {
139 ScopedObjectAccess soa(Thread::Current());
140 instrumentation::Instrumentation* instr = Runtime::Current()->GetInstrumentation();
141 {
142 soa.Self()->TransitionFromRunnableToSuspended(kSuspended);
143 Runtime* runtime = Runtime::Current();
144 runtime->GetThreadList()->SuspendAll("Instrumentation::ConfigureStubs");
145 instr->ConfigureStubs(key, level);
146 runtime->GetThreadList()->ResumeAll();
147 soa.Self()->TransitionFromSuspendedToRunnable();
148 }
149 }
150
151 Instrumentation::InstrumentationLevel GetCurrentInstrumentationLevel() {
152 return Runtime::Current()->GetInstrumentation()->GetCurrentInstrumentationLevel();
153 }
154
155 size_t GetInstrumentationUserCount() {
156 ScopedObjectAccess soa(Thread::Current());
157 return Runtime::Current()->GetInstrumentation()->requested_instrumentation_levels_.size();
158 }
159
160 void TestEvent(uint32_t instrumentation_event) {
161 ScopedObjectAccess soa(Thread::Current());
162 instrumentation::Instrumentation* instr = Runtime::Current()->GetInstrumentation();
163 TestInstrumentationListener listener;
164 {
165 soa.Self()->TransitionFromRunnableToSuspended(kSuspended);
166 Runtime* runtime = Runtime::Current();
167 runtime->GetThreadList()->SuspendAll("Add instrumentation listener");
168 instr->AddListener(&listener, instrumentation_event);
169 runtime->GetThreadList()->ResumeAll();
170 soa.Self()->TransitionFromSuspendedToRunnable();
171 }
172
173 mirror::ArtMethod* const event_method = nullptr;
174 mirror::Object* const event_obj = nullptr;
175 const uint32_t event_dex_pc = 0;
176
177 // Check the listener is registered and is notified of the event.
178 EXPECT_TRUE(HasEventListener(instr, instrumentation_event));
179 EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event));
180 ReportEvent(instr, instrumentation_event, soa.Self(), event_method, event_obj, event_dex_pc);
181 EXPECT_TRUE(DidListenerReceiveEvent(listener, instrumentation_event));
182
183 listener.Reset();
184 {
185 soa.Self()->TransitionFromRunnableToSuspended(kSuspended);
186 Runtime* runtime = Runtime::Current();
187 runtime->GetThreadList()->SuspendAll("Remove instrumentation listener");
188 instr->RemoveListener(&listener, instrumentation_event);
189 runtime->GetThreadList()->ResumeAll();
190 soa.Self()->TransitionFromSuspendedToRunnable();
191 }
192
193 // Check the listener is not registered and is not notified of the event.
194 EXPECT_FALSE(HasEventListener(instr, instrumentation_event));
195 EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event));
196 ReportEvent(instr, instrumentation_event, soa.Self(), event_method, event_obj, event_dex_pc);
197 EXPECT_FALSE(DidListenerReceiveEvent(listener, instrumentation_event));
198 }
199
200 void DeoptimizeMethod(Thread* self, Handle<mirror::ArtMethod> method,
201 bool enable_deoptimization)
202 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
203 Runtime* runtime = Runtime::Current();
204 instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
205 self->TransitionFromRunnableToSuspended(kSuspended);
206 runtime->GetThreadList()->SuspendAll("Single method deoptimization");
207 if (enable_deoptimization) {
208 instrumentation->EnableDeoptimization();
209 }
210 instrumentation->Deoptimize(method.Get());
211 runtime->GetThreadList()->ResumeAll();
212 self->TransitionFromSuspendedToRunnable();
213 }
214
215 void UndeoptimizeMethod(Thread* self, Handle<mirror::ArtMethod> method,
216 const char* key, bool disable_deoptimization)
217 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
218 Runtime* runtime = Runtime::Current();
219 instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
220 self->TransitionFromRunnableToSuspended(kSuspended);
221 runtime->GetThreadList()->SuspendAll("Single method undeoptimization");
222 instrumentation->Undeoptimize(method.Get());
223 if (disable_deoptimization) {
224 instrumentation->DisableDeoptimization(key);
225 }
226 runtime->GetThreadList()->ResumeAll();
227 self->TransitionFromSuspendedToRunnable();
228 }
229
230 void DeoptimizeEverything(Thread* self, const char* key, bool enable_deoptimization)
231 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
232 Runtime* runtime = Runtime::Current();
233 instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
234 self->TransitionFromRunnableToSuspended(kSuspended);
235 runtime->GetThreadList()->SuspendAll("Full deoptimization");
236 if (enable_deoptimization) {
237 instrumentation->EnableDeoptimization();
238 }
239 instrumentation->DeoptimizeEverything(key);
240 runtime->GetThreadList()->ResumeAll();
241 self->TransitionFromSuspendedToRunnable();
242 }
243
244 void UndeoptimizeEverything(Thread* self, const char* key, bool disable_deoptimization)
245 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
246 Runtime* runtime = Runtime::Current();
247 instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
248 self->TransitionFromRunnableToSuspended(kSuspended);
249 runtime->GetThreadList()->SuspendAll("Full undeoptimization");
250 instrumentation->UndeoptimizeEverything(key);
251 if (disable_deoptimization) {
252 instrumentation->DisableDeoptimization(key);
253 }
254 runtime->GetThreadList()->ResumeAll();
255 self->TransitionFromSuspendedToRunnable();
256 }
257
258 void EnableMethodTracing(Thread* self, const char* key, bool needs_interpreter)
259 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
260 Runtime* runtime = Runtime::Current();
261 instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
262 self->TransitionFromRunnableToSuspended(kSuspended);
263 runtime->GetThreadList()->SuspendAll("EnableMethodTracing");
264 instrumentation->EnableMethodTracing(key, needs_interpreter);
265 runtime->GetThreadList()->ResumeAll();
266 self->TransitionFromSuspendedToRunnable();
267 }
268
269 void DisableMethodTracing(Thread* self, const char* key)
270 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
271 Runtime* runtime = Runtime::Current();
272 instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
273 self->TransitionFromRunnableToSuspended(kSuspended);
274 runtime->GetThreadList()->SuspendAll("EnableMethodTracing");
275 instrumentation->DisableMethodTracing(key);
276 runtime->GetThreadList()->ResumeAll();
277 self->TransitionFromSuspendedToRunnable();
278 }
279
280 private:
281 static bool HasEventListener(const instrumentation::Instrumentation* instr, uint32_t event_type)
282 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
283 switch (event_type) {
284 case instrumentation::Instrumentation::kMethodEntered:
285 return instr->HasMethodEntryListeners();
286 case instrumentation::Instrumentation::kMethodExited:
287 return instr->HasMethodExitListeners();
288 case instrumentation::Instrumentation::kMethodUnwind:
289 return instr->HasMethodUnwindListeners();
290 case instrumentation::Instrumentation::kDexPcMoved:
291 return instr->HasDexPcListeners();
292 case instrumentation::Instrumentation::kFieldRead:
293 return instr->HasFieldReadListeners();
294 case instrumentation::Instrumentation::kFieldWritten:
295 return instr->HasFieldWriteListeners();
296 case instrumentation::Instrumentation::kExceptionCaught:
297 return instr->HasExceptionCaughtListeners();
298 case instrumentation::Instrumentation::kBackwardBranch:
299 return instr->HasBackwardBranchListeners();
300 default:
301 LOG(FATAL) << "Unknown instrumentation event " << event_type;
302 UNREACHABLE();
303 }
304 }
305
306 static void ReportEvent(const instrumentation::Instrumentation* instr, uint32_t event_type,
307 Thread* self, mirror::ArtMethod* method, mirror::Object* obj,
308 uint32_t dex_pc)
309 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
310 switch (event_type) {
311 case instrumentation::Instrumentation::kMethodEntered:
312 instr->MethodEnterEvent(self, obj, method, dex_pc);
313 break;
314 case instrumentation::Instrumentation::kMethodExited: {
315 JValue value;
316 instr->MethodExitEvent(self, obj, method, dex_pc, value);
317 break;
318 }
319 case instrumentation::Instrumentation::kMethodUnwind:
320 instr->MethodUnwindEvent(self, obj, method, dex_pc);
321 break;
322 case instrumentation::Instrumentation::kDexPcMoved:
323 instr->DexPcMovedEvent(self, obj, method, dex_pc);
324 break;
325 case instrumentation::Instrumentation::kFieldRead:
326 instr->FieldReadEvent(self, obj, method, dex_pc, nullptr);
327 break;
328 case instrumentation::Instrumentation::kFieldWritten: {
329 JValue value;
330 instr->FieldWriteEvent(self, obj, method, dex_pc, nullptr, value);
331 break;
332 }
333 case instrumentation::Instrumentation::kExceptionCaught: {
334 ThrowArithmeticExceptionDivideByZero();
335 mirror::Throwable* event_exception = self->GetException();
336 instr->ExceptionCaughtEvent(self, event_exception);
337 self->ClearException();
338 break;
339 }
340 case instrumentation::Instrumentation::kBackwardBranch:
341 instr->BackwardBranch(self, method, dex_pc);
342 break;
343 default:
344 LOG(FATAL) << "Unknown instrumentation event " << event_type;
345 UNREACHABLE();
346 }
347 }
348
349 static bool DidListenerReceiveEvent(const TestInstrumentationListener& listener,
350 uint32_t event_type) {
351 switch (event_type) {
352 case instrumentation::Instrumentation::kMethodEntered:
353 return listener.received_method_enter_event;
354 case instrumentation::Instrumentation::kMethodExited:
355 return listener.received_method_exit_event;
356 case instrumentation::Instrumentation::kMethodUnwind:
357 return listener.received_method_unwind_event;
358 case instrumentation::Instrumentation::kDexPcMoved:
359 return listener.received_dex_pc_moved_event;
360 case instrumentation::Instrumentation::kFieldRead:
361 return listener.received_field_read_event;
362 case instrumentation::Instrumentation::kFieldWritten:
363 return listener.received_field_written_event;
364 case instrumentation::Instrumentation::kExceptionCaught:
365 return listener.received_exception_caught_event;
366 case instrumentation::Instrumentation::kBackwardBranch:
367 return listener.received_backward_branch_event;
368 default:
369 LOG(FATAL) << "Unknown instrumentation event " << event_type;
370 UNREACHABLE();
371 }
372 }
373};
374
375TEST_F(InstrumentationTest, NoInstrumentation) {
376 ScopedObjectAccess soa(Thread::Current());
377 instrumentation::Instrumentation* instr = Runtime::Current()->GetInstrumentation();
378 ASSERT_NE(instr, nullptr);
379
380 EXPECT_FALSE(instr->AreExitStubsInstalled());
381 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
382 EXPECT_FALSE(instr->IsActive());
383 EXPECT_FALSE(instr->ShouldNotifyMethodEnterExitEvents());
384
385 // Test interpreter table is the default one.
386 EXPECT_EQ(instrumentation::kMainHandlerTable, instr->GetInterpreterHandlerTable());
387
388 // Check there is no registered listener.
389 EXPECT_FALSE(instr->HasDexPcListeners());
390 EXPECT_FALSE(instr->HasExceptionCaughtListeners());
391 EXPECT_FALSE(instr->HasFieldReadListeners());
392 EXPECT_FALSE(instr->HasFieldWriteListeners());
393 EXPECT_FALSE(instr->HasMethodEntryListeners());
394 EXPECT_FALSE(instr->HasMethodExitListeners());
395 EXPECT_FALSE(instr->IsActive());
396}
397
398// Test instrumentation listeners for each event.
399TEST_F(InstrumentationTest, MethodEntryEvent) {
400 TestEvent(instrumentation::Instrumentation::kMethodEntered);
401}
402
403TEST_F(InstrumentationTest, MethodExitEvent) {
404 TestEvent(instrumentation::Instrumentation::kMethodExited);
405}
406
407TEST_F(InstrumentationTest, MethodUnwindEvent) {
408 TestEvent(instrumentation::Instrumentation::kMethodUnwind);
409}
410
411TEST_F(InstrumentationTest, DexPcMovedEvent) {
412 TestEvent(instrumentation::Instrumentation::kDexPcMoved);
413}
414
415TEST_F(InstrumentationTest, FieldReadEvent) {
416 TestEvent(instrumentation::Instrumentation::kFieldRead);
417}
418
419TEST_F(InstrumentationTest, FieldWriteEvent) {
420 TestEvent(instrumentation::Instrumentation::kFieldWritten);
421}
422
423TEST_F(InstrumentationTest, ExceptionCaughtEvent) {
424 TestEvent(instrumentation::Instrumentation::kExceptionCaught);
425}
426
427TEST_F(InstrumentationTest, BackwardBranchEvent) {
428 TestEvent(instrumentation::Instrumentation::kBackwardBranch);
429}
430
431TEST_F(InstrumentationTest, DeoptimizeDirectMethod) {
432 ScopedObjectAccess soa(Thread::Current());
433 jobject class_loader = LoadDex("Instrumentation");
434 Runtime* const runtime = Runtime::Current();
435 instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
436 ClassLinker* class_linker = runtime->GetClassLinker();
437 StackHandleScope<2> hs(soa.Self());
438 Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
439 mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
440 ASSERT_TRUE(klass != nullptr);
441 Handle<mirror::ArtMethod> method_to_deoptimize(
442 hs.NewHandle(klass->FindDeclaredDirectMethod("instanceMethod", "()V")));
443 ASSERT_TRUE(method_to_deoptimize.Get() != nullptr);
444
445 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
446 EXPECT_FALSE(instr->IsDeoptimized(method_to_deoptimize.Get()));
447
448 DeoptimizeMethod(soa.Self(), method_to_deoptimize, true);
449
450 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
451 EXPECT_TRUE(instr->AreExitStubsInstalled());
452 EXPECT_TRUE(instr->IsDeoptimized(method_to_deoptimize.Get()));
453
454 constexpr const char* instrumentation_key = "DeoptimizeDirectMethod";
455 UndeoptimizeMethod(soa.Self(), method_to_deoptimize, instrumentation_key, true);
456
457 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
458 EXPECT_FALSE(instr->IsDeoptimized(method_to_deoptimize.Get()));
459}
460
461TEST_F(InstrumentationTest, FullDeoptimization) {
462 ScopedObjectAccess soa(Thread::Current());
463 Runtime* const runtime = Runtime::Current();
464 instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
465 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
466
467 constexpr const char* instrumentation_key = "FullDeoptimization";
468 DeoptimizeEverything(soa.Self(), instrumentation_key, true);
469
470 EXPECT_TRUE(instr->AreAllMethodsDeoptimized());
471 EXPECT_TRUE(instr->AreExitStubsInstalled());
472
473 UndeoptimizeEverything(soa.Self(), instrumentation_key, true);
474
475 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
476}
477
478TEST_F(InstrumentationTest, MixedDeoptimization) {
479 ScopedObjectAccess soa(Thread::Current());
480 jobject class_loader = LoadDex("Instrumentation");
481 Runtime* const runtime = Runtime::Current();
482 instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
483 ClassLinker* class_linker = runtime->GetClassLinker();
484 StackHandleScope<2> hs(soa.Self());
485 Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
486 mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
487 ASSERT_TRUE(klass != nullptr);
488 Handle<mirror::ArtMethod> method_to_deoptimize(
489 hs.NewHandle(klass->FindDeclaredDirectMethod("instanceMethod", "()V")));
490 ASSERT_TRUE(method_to_deoptimize.Get() != nullptr);
491
492 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
493 EXPECT_FALSE(instr->IsDeoptimized(method_to_deoptimize.Get()));
494
495 DeoptimizeMethod(soa.Self(), method_to_deoptimize, true);
496 // Deoptimizing a method does not change instrumentation level.
497 EXPECT_EQ(Instrumentation::InstrumentationLevel::kInstrumentNothing,
498 GetCurrentInstrumentationLevel());
499 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
500 EXPECT_TRUE(instr->AreExitStubsInstalled());
501 EXPECT_TRUE(instr->IsDeoptimized(method_to_deoptimize.Get()));
502
503 constexpr const char* instrumentation_key = "MixedDeoptimization";
504 DeoptimizeEverything(soa.Self(), instrumentation_key, false);
505 EXPECT_EQ(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter,
506 GetCurrentInstrumentationLevel());
507 EXPECT_TRUE(instr->AreAllMethodsDeoptimized());
508 EXPECT_TRUE(instr->AreExitStubsInstalled());
509 EXPECT_TRUE(instr->IsDeoptimized(method_to_deoptimize.Get()));
510
511 UndeoptimizeEverything(soa.Self(), instrumentation_key, false);
512 EXPECT_EQ(Instrumentation::InstrumentationLevel::kInstrumentNothing,
513 GetCurrentInstrumentationLevel());
514 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
515 EXPECT_TRUE(instr->AreExitStubsInstalled());
516 EXPECT_TRUE(instr->IsDeoptimized(method_to_deoptimize.Get()));
517
518 UndeoptimizeMethod(soa.Self(), method_to_deoptimize, instrumentation_key, true);
519 EXPECT_EQ(Instrumentation::InstrumentationLevel::kInstrumentNothing,
520 GetCurrentInstrumentationLevel());
521 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
522 EXPECT_FALSE(instr->IsDeoptimized(method_to_deoptimize.Get()));
523}
524
525TEST_F(InstrumentationTest, MethodTracing_Interpreter) {
526 ScopedObjectAccess soa(Thread::Current());
527 Runtime* const runtime = Runtime::Current();
528 instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
529 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
530
531 constexpr const char* instrumentation_key = "MethodTracing";
532 EnableMethodTracing(soa.Self(), instrumentation_key, true);
533 EXPECT_EQ(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter,
534 GetCurrentInstrumentationLevel());
535 EXPECT_TRUE(instr->AreAllMethodsDeoptimized());
536 EXPECT_TRUE(instr->AreExitStubsInstalled());
537
538 DisableMethodTracing(soa.Self(), instrumentation_key);
539 EXPECT_EQ(Instrumentation::InstrumentationLevel::kInstrumentNothing,
540 GetCurrentInstrumentationLevel());
541 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
542}
543
544TEST_F(InstrumentationTest, MethodTracing_InstrumentationEntryExitStubs) {
545 ScopedObjectAccess soa(Thread::Current());
546 Runtime* const runtime = Runtime::Current();
547 instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
548 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
549
550 constexpr const char* instrumentation_key = "MethodTracing";
551 EnableMethodTracing(soa.Self(), instrumentation_key, false);
552 EXPECT_EQ(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
553 GetCurrentInstrumentationLevel());
554 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
555 EXPECT_TRUE(instr->AreExitStubsInstalled());
556
557 DisableMethodTracing(soa.Self(), instrumentation_key);
558 EXPECT_EQ(Instrumentation::InstrumentationLevel::kInstrumentNothing,
559 GetCurrentInstrumentationLevel());
560 EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
561}
562
563// We use a macro to print the line number where the test is failing.
564#define CHECK_INSTRUMENTATION(_level, _user_count) \
565 do { \
566 Instrumentation* const instr = Runtime::Current()->GetInstrumentation(); \
567 bool interpreter = \
568 (_level == Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter); \
569 EXPECT_EQ(_level, GetCurrentInstrumentationLevel()); \
570 EXPECT_EQ(_user_count, GetInstrumentationUserCount()); \
571 if (instr->IsForcedInterpretOnly()) { \
572 EXPECT_TRUE(instr->InterpretOnly()); \
573 } else if (interpreter) { \
574 EXPECT_TRUE(instr->InterpretOnly()); \
575 } else { \
576 EXPECT_FALSE(instr->InterpretOnly()); \
577 } \
578 if (interpreter) { \
579 EXPECT_TRUE(instr->AreAllMethodsDeoptimized()); \
580 } else { \
581 EXPECT_FALSE(instr->AreAllMethodsDeoptimized()); \
582 } \
583 } while (false)
584
585TEST_F(InstrumentationTest, ConfigureStubs_Nothing) {
586 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
587
588 // Check no-op.
589 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
590 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
591}
592
593TEST_F(InstrumentationTest, ConfigureStubs_InstrumentationStubs) {
594 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
595
596 // Check we can switch to instrumentation stubs
597 CheckConfigureStubs(kClientOneKey,
598 Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs);
599 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
600 1U);
601
602 // Check we can disable instrumentation.
603 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
604 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
605}
606
607TEST_F(InstrumentationTest, ConfigureStubs_Interpreter) {
608 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
609
610 // Check we can switch to interpreter
611 CheckConfigureStubs(kClientOneKey,
612 Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter);
613 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 1U);
614
615 // Check we can disable instrumentation.
616 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
617 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
618}
619
620TEST_F(InstrumentationTest, ConfigureStubs_InstrumentationStubsToInterpreter) {
621 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
622
623 // Configure stubs with instrumentation stubs.
624 CheckConfigureStubs(kClientOneKey,
625 Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs);
626 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
627 1U);
628
629 // Configure stubs with interpreter.
630 CheckConfigureStubs(kClientOneKey,
631 Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter);
632 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 1U);
633
634 // Check we can disable instrumentation.
635 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
636 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
637}
638
639TEST_F(InstrumentationTest, ConfigureStubs_InterpreterToInstrumentationStubs) {
640 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
641
642 // Configure stubs with interpreter.
643 CheckConfigureStubs(kClientOneKey,
644 Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter);
645 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 1U);
646
647 // Configure stubs with instrumentation stubs.
648 CheckConfigureStubs(kClientOneKey,
649 Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs);
650 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
651 1U);
652
653 // Check we can disable instrumentation.
654 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
655 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
656}
657
658TEST_F(InstrumentationTest,
659 ConfigureStubs_InstrumentationStubsToInterpreterToInstrumentationStubs) {
660 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
661
662 // Configure stubs with instrumentation stubs.
663 CheckConfigureStubs(kClientOneKey,
664 Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs);
665 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
666 1U);
667
668 // Configure stubs with interpreter.
669 CheckConfigureStubs(kClientOneKey,
670 Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter);
671 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 1U);
672
673 // Configure stubs with instrumentation stubs again.
674 CheckConfigureStubs(kClientOneKey,
675 Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs);
676 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
677 1U);
678
679 // Check we can disable instrumentation.
680 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
681 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
682}
683
684TEST_F(InstrumentationTest, MultiConfigureStubs_Nothing) {
685 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
686
687 // Check kInstrumentNothing with two clients.
688 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
689 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
690
691 CheckConfigureStubs(kClientTwoKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
692 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
693}
694
695TEST_F(InstrumentationTest, MultiConfigureStubs_InstrumentationStubs) {
696 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
697
698 // Configure stubs with instrumentation stubs for 1st client.
699 CheckConfigureStubs(kClientOneKey,
700 Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs);
701 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
702 1U);
703
704 // Configure stubs with instrumentation stubs for 2nd client.
705 CheckConfigureStubs(kClientTwoKey,
706 Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs);
707 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
708 2U);
709
710 // 1st client requests instrumentation deactivation but 2nd client still needs
711 // instrumentation stubs.
712 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
713 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
714 1U);
715
716 // 2nd client requests instrumentation deactivation
717 CheckConfigureStubs(kClientTwoKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
718 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
719}
720
721TEST_F(InstrumentationTest, MultiConfigureStubs_Interpreter) {
722 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
723
724 // Configure stubs with interpreter for 1st client.
725 CheckConfigureStubs(kClientOneKey,
726 Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter);
727 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 1U);
728
729 // Configure stubs with interpreter for 2nd client.
730 CheckConfigureStubs(kClientTwoKey,
731 Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter);
732 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 2U);
733
734 // 1st client requests instrumentation deactivation but 2nd client still needs interpreter.
735 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
736 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 1U);
737
738 // 2nd client requests instrumentation deactivation
739 CheckConfigureStubs(kClientTwoKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
740 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
741}
742
743TEST_F(InstrumentationTest, MultiConfigureStubs_InstrumentationStubsThenInterpreter) {
744 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
745
746 // Configure stubs with instrumentation stubs for 1st client.
747 CheckConfigureStubs(kClientOneKey,
748 Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs);
749 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
750 1U);
751
752 // Configure stubs with interpreter for 2nd client.
753 CheckConfigureStubs(kClientTwoKey,
754 Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter);
755 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 2U);
756
757 // 1st client requests instrumentation deactivation but 2nd client still needs interpreter.
758 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
759 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 1U);
760
761 // 2nd client requests instrumentation deactivation
762 CheckConfigureStubs(kClientTwoKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
763 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
764}
765
766TEST_F(InstrumentationTest, MultiConfigureStubs_InterpreterThenInstrumentationStubs) {
767 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
768
769 // Configure stubs with interpreter for 1st client.
770 CheckConfigureStubs(kClientOneKey,
771 Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter);
772 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 1U);
773
774 // Configure stubs with instrumentation stubs for 2nd client.
775 CheckConfigureStubs(kClientTwoKey,
776 Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs);
777 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter, 2U);
778
779 // 1st client requests instrumentation deactivation but 2nd client still needs
780 // instrumentation stubs.
781 CheckConfigureStubs(kClientOneKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
782 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentWithInstrumentationStubs,
783 1U);
784
785 // 2nd client requests instrumentation deactivation
786 CheckConfigureStubs(kClientTwoKey, Instrumentation::InstrumentationLevel::kInstrumentNothing);
787 CHECK_INSTRUMENTATION(Instrumentation::InstrumentationLevel::kInstrumentNothing, 0U);
788}
789
790} // namespace instrumentation
791} // namespace art