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:
@@ -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
|
||||
|
||||
@@ -1300,7 +1300,7 @@ bool ApiMessageWriter::WriteCObjectInlined(Dart_CObject* object,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
FATAL1("Unexpected Dart_CObject_Type %d\n", type);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -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] = ¶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();
|
||||
// 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user