Start adding vm/cc tests for rewind functionality.

These will make it easier to debug rewind on simdbc64.

BUG=
R=rmacnak@google.com

Review-Url: https://codereview.chromium.org/2662333002 .
This commit is contained in:
Todd Turnidge
2017-01-31 12:02:26 -08:00
parent bfdc9139b9
commit bbc2ac93a3
5 changed files with 230 additions and 8 deletions
+4
View File
@@ -299,3 +299,7 @@ dart/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloa
[ $system == linux ] # Tests are currently flaky and are being rewritten.
cc/BasicMallocHookTest: Pass,Fail
cc/FreeUnseenMemoryMallocHookTest: Pass,Fail
[ $arch == simdbc || $arch == simdbc64 ]
cc/Debugger_RewindOneFrame_Unoptimized: Skip # Issue 27878
cc/Debugger_RewindTwoFrames_Unoptimized: Skip # Issue 27878
+1 -1
View File
@@ -1300,7 +1300,7 @@ bool ApiMessageWriter::WriteCObjectInlined(Dart_CObject* object,
break;
}
default:
UNREACHABLE();
FATAL1("Unexpected Dart_CObject_Type %d\n", type);
}
return true;
+204
View File
@@ -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,207 @@ 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] = &param_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] = &param_values;
Dart_CObject param0_name;
param0_name.type = Dart_CObject_kString;
param0_name.value.as_string = const_cast<char*>("isolateId");
param_keys_list[0] = &param0_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] = &param0_value;
Dart_CObject param1_name;
param1_name.type = Dart_CObject_kString;
param1_name.value.as_string = const_cast<char*>("step");
param_keys_list[1] = &param1_name;
Dart_CObject param1_value;
param1_value.type = Dart_CObject_kString;
param1_value.value.as_string = const_cast<char*>("Rewind");
param_values_list[1] = &param1_value;
Dart_CObject param2_name;
param2_name.type = Dart_CObject_kString;
param2_name.value.as_string = const_cast<char*>("frameIndex");
param_keys_list[2] = &param2_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] = &param2_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();
// TODO(turnidge): It is weird that the isolate can get to this
// point in our tests without being marked runnable. Clear this up
// at some point.
I->set_is_runnable(true);
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
+13 -4
View File
@@ -210,10 +210,9 @@ static void Finalizer(void* isolate_callback_data,
void JSONStream::PostReply() {
Dart_Port port = reply_port();
ASSERT(port != ILLEGAL_PORT);
set_reply_port(ILLEGAL_PORT); // Prevent double replies.
ASSERT(seq_ != NULL);
Dart_Port port = reply_port();
set_reply_port(ILLEGAL_PORT); // Prevent double replies.
if (seq_->IsString()) {
const String& str = String::Cast(*seq_);
PrintProperty("id", str.ToCString());
@@ -224,12 +223,22 @@ void JSONStream::PostReply() {
const Double& dbl = Double::Cast(*seq_);
PrintProperty("id", dbl.value());
} else if (seq_->IsNull()) {
if (port == ILLEGAL_PORT) {
// This path is only used in tests.
buffer_.AddChar('}'); // Finish our message.
char* cstr;
intptr_t length;
Steal(&cstr, &length);
OS::PrintErr("-----\nDropping reply:\n%s\n-----\n", cstr);
free(cstr);
}
// JSON-RPC 2.0 says that a request with a null ID shouldn't get a reply.
PostNullReply(port);
return;
}
buffer_.AddChar('}');
ASSERT(port != ILLEGAL_PORT);
buffer_.AddChar('}'); // Finish our message.
char* cstr;
intptr_t length;
Steal(&cstr, &length);
+8 -3
View File
@@ -840,13 +840,18 @@ void Service::InvokeMethod(Isolate* I,
ASSERT(!param_values.IsNull());
ASSERT(param_keys.Length() == param_values.Length());
if (!reply_port.IsSendPort()) {
// We expect a reply port unless there is a null sequence id,
// which indicates that no reply should be sent. We use this in
// tests.
if (!seq.IsNull() && !reply_port.IsSendPort()) {
FATAL("SendPort expected.");
}
JSONStream js;
js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(), seq, method_name,
param_keys, param_values, parameters_are_dart_objects);
Dart_Port reply_port_id =
(reply_port.IsNull() ? ILLEGAL_PORT : SendPort::Cast(reply_port).Id());
js.Setup(zone.GetZone(), reply_port_id, seq, method_name, param_keys,
param_values, parameters_are_dart_objects);
// RPC came in with a custom service id zone.
const char* id_zone_param = js.LookupParam("_idZone");