Chromium Code Reviews| Index: runtime/vm/debugger_test.cc |
| diff --git a/runtime/vm/debugger_test.cc b/runtime/vm/debugger_test.cc |
| index 6096965985244452b1ae141daa5e00e3a1905068..a783ce69ca48faac23155825628626b9d36a5404 100644 |
| --- a/runtime/vm/debugger_test.cc |
| +++ b/runtime/vm/debugger_test.cc |
| @@ -3,7 +3,9 @@ |
| // BSD-style license that can be found in the LICENSE file. |
| #include "vm/dart_api_impl.h" |
| +#include "vm/dart_api_message.h" |
| #include "vm/debugger.h" |
| +#include "vm/message.h" |
| #include "vm/unit_test.h" |
| namespace dart { |
| @@ -11,6 +13,7 @@ namespace dart { |
| #ifndef PRODUCT |
| DECLARE_FLAG(bool, remove_script_timestamps_for_test); |
| +DECLARE_FLAG(bool, trace_rewind); |
| // Search for the formatted string in buffer. |
| // |
| @@ -141,6 +144,204 @@ TEST_CASE(Debugger_PauseEvent) { |
| EXPECT(saw_paused_event); |
| } |
| + |
| +static uint8_t* malloc_allocator(uint8_t* ptr, |
| + intptr_t old_size, |
| + intptr_t new_size) { |
| + void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); |
| + return reinterpret_cast<uint8_t*>(new_ptr); |
| +} |
| + |
| + |
| +const char* rewind_frame_index = "-1"; |
| + |
| + |
| +// Build and send a fake resume OOB message for testing purposes. |
| +void SendResumeMessage(Isolate* isolate) { |
| + // Format is: [ oob_type, port, seq, method_name, [keys], [values] ] |
| + Dart_CObject msg; |
| + Dart_CObject* list_values[6]; |
| + msg.type = Dart_CObject_kArray; |
| + msg.value.as_array.length = 6; |
| + msg.value.as_array.values = list_values; |
| + |
| + Dart_CObject oob; |
| + oob.type = Dart_CObject_kInt32; |
| + oob.value.as_int32 = Message::kServiceOOBMsg; |
| + list_values[0] = &oob; |
| + |
| + Dart_CObject reply_port; |
| + reply_port.type = Dart_CObject_kNull; |
| + list_values[1] = &reply_port; |
| + |
| + Dart_CObject seq; |
| + seq.type = Dart_CObject_kNull; |
| + list_values[2] = &seq; |
| + |
| + Dart_CObject method_name; |
| + method_name.type = Dart_CObject_kString; |
| + method_name.value.as_string = const_cast<char*>("resume"); |
| + list_values[3] = &method_name; |
| + |
| + const int kParamCount = 3; |
| + Dart_CObject param_keys; |
| + Dart_CObject* param_keys_list[kParamCount]; |
| + param_keys.type = Dart_CObject_kArray; |
| + param_keys.value.as_array.values = param_keys_list; |
| + param_keys.value.as_array.length = kParamCount; |
| + list_values[4] = ¶m_keys; |
| + |
| + Dart_CObject param_values; |
| + Dart_CObject* param_values_list[kParamCount]; |
| + param_values.type = Dart_CObject_kArray; |
| + param_values.value.as_array.values = param_values_list; |
| + param_values.value.as_array.length = kParamCount; |
| + list_values[5] = ¶m_values; |
| + |
| + Dart_CObject param0_name; |
| + param0_name.type = Dart_CObject_kString; |
| + param0_name.value.as_string = const_cast<char*>("isolateId"); |
| + param_keys_list[0] = ¶m0_name; |
| + |
| + Dart_CObject param0_value; |
| + param0_value.type = Dart_CObject_kString; |
| + const char* isolate_id = Thread::Current()->zone()->PrintToString( |
| + ISOLATE_SERVICE_ID_FORMAT_STRING, |
| + static_cast<int64_t>(isolate->main_port())); |
| + param0_value.value.as_string = const_cast<char*>(isolate_id); |
| + param_values_list[0] = ¶m0_value; |
| + |
| + Dart_CObject param1_name; |
| + param1_name.type = Dart_CObject_kString; |
| + param1_name.value.as_string = const_cast<char*>("step"); |
| + param_keys_list[1] = ¶m1_name; |
| + |
| + Dart_CObject param1_value; |
| + param1_value.type = Dart_CObject_kString; |
| + param1_value.value.as_string = const_cast<char*>("Rewind"); |
| + param_values_list[1] = ¶m1_value; |
| + |
| + Dart_CObject param2_name; |
| + param2_name.type = Dart_CObject_kString; |
| + param2_name.value.as_string = const_cast<char*>("frameIndex"); |
| + param_keys_list[2] = ¶m2_name; |
| + |
| + Dart_CObject param2_value; |
| + param2_value.type = Dart_CObject_kString; |
| + param2_value.value.as_string = const_cast<char*>(rewind_frame_index); |
| + param_values_list[2] = ¶m2_value; |
| + |
| + { |
| + uint8_t* buffer = NULL; |
| + ApiMessageWriter writer(&buffer, &malloc_allocator); |
| + bool success = writer.WriteCMessage(&msg); |
| + ASSERT(success); |
| + |
| + // Post the message at the given port. |
| + success = PortMap::PostMessage(new Message(isolate->main_port(), buffer, |
| + writer.BytesWritten(), |
| + Message::kOOBPriority)); |
| + ASSERT(success); |
| + } |
| +} |
| + |
| + |
| +static void RewindOnce(Dart_IsolateId isolate_id, |
| + intptr_t bp_id, |
| + const Dart_CodeLocation& loc) { |
| + bool first_time = !saw_paused_event; |
| + saw_paused_event = true; |
| + if (first_time) { |
| + Thread* T = Thread::Current(); |
| + Isolate* I = T->isolate(); |
| + I->set_is_runnable(true); |
|
rmacnak
2017/01/31 19:21:00
Weird.
turnidge
2017/01/31 19:35:46
Added a TODO
|
| + SendResumeMessage(I); |
| + I->PauseEventHandler(); |
| + } |
| +} |
| + |
| + |
| +TEST_CASE(Debugger_RewindOneFrame_Unoptimized) { |
| + SetFlagScope<bool> sfs(&FLAG_trace_rewind, true); |
| + saw_paused_event = false; |
| + rewind_frame_index = "1"; |
| + |
| + const char* kScriptChars = |
| + "import 'dart:developer';\n" |
| + "\n" |
| + "var msg = new StringBuffer();\n" |
| + "\n" |
| + "foo() {\n" |
| + " msg.write('enter(foo) ');\n" |
| + " debugger();\n" |
| + " msg.write('exit(foo) ');\n" |
| + "}\n" |
| + "\n" |
| + "main() {\n" |
| + " msg.write('enter(main) ');\n" |
| + " foo();\n" |
| + " msg.write('exit(main) ');\n" |
| + " return msg.toString();\n" |
| + "}\n"; |
| + Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); |
| + EXPECT_VALID(lib); |
| + |
| + Dart_SetPausedEventHandler(RewindOnce); |
| + Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); |
| + const char* result_cstr; |
| + EXPECT_VALID(result); |
| + EXPECT(Dart_IsString(result)); |
| + EXPECT_VALID(Dart_StringToCString(result, &result_cstr)); |
| + EXPECT_STREQ("enter(main) enter(foo) enter(foo) exit(foo) exit(main) ", |
| + result_cstr); |
| + EXPECT(saw_paused_event); |
| +} |
| + |
| + |
| +TEST_CASE(Debugger_RewindTwoFrames_Unoptimized) { |
| + SetFlagScope<bool> sfs(&FLAG_trace_rewind, true); |
| + saw_paused_event = false; |
| + rewind_frame_index = "2"; |
| + |
| + const char* kScriptChars = |
| + "import 'dart:developer';\n" |
| + "\n" |
| + "var msg = new StringBuffer();\n" |
| + "\n" |
| + "foo() {\n" |
| + " msg.write('enter(foo) ');\n" |
| + " debugger();\n" |
| + " msg.write('exit(foo) ');\n" |
| + "}\n" |
| + "\n" |
| + "bar() {\n" |
| + " msg.write('enter(bar) ');\n" |
| + " foo();\n" |
| + " msg.write('exit(bar) ');\n" |
| + "}\n" |
| + "\n" |
| + "main() {\n" |
| + " msg.write('enter(main) ');\n" |
| + " bar();\n" |
| + " msg.write('exit(main) ');\n" |
| + " return msg.toString();\n" |
| + "}\n"; |
| + Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); |
| + EXPECT_VALID(lib); |
| + |
| + Dart_SetPausedEventHandler(RewindOnce); |
| + Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); |
| + const char* result_cstr; |
| + EXPECT_VALID(result); |
| + EXPECT(Dart_IsString(result)); |
| + EXPECT_VALID(Dart_StringToCString(result, &result_cstr)); |
| + EXPECT_STREQ( |
| + "enter(main) enter(bar) enter(foo) enter(bar) enter(foo) " |
| + "exit(foo) exit(bar) exit(main) ", |
| + result_cstr); |
| + EXPECT(saw_paused_event); |
| +} |
| + |
| #endif // !PRODUCT |
| } // namespace dart |