| Index: runtime/vm/debugger_api_impl_test.cc
|
| ===================================================================
|
| --- runtime/vm/debugger_api_impl_test.cc (revision 28466)
|
| +++ runtime/vm/debugger_api_impl_test.cc (working copy)
|
| @@ -11,6 +11,9 @@
|
|
|
| namespace dart {
|
|
|
| +DECLARE_FLAG(int, optimization_counter_threshold);
|
| +DECLARE_FLAG(bool, use_osr);
|
| +
|
| static bool breakpoint_hit = false;
|
| static int breakpoint_hit_counter = 0;
|
| static Dart_Handle script_lib = NULL;
|
| @@ -332,7 +335,160 @@
|
| EXPECT(breakpoint_hit == true);
|
| }
|
|
|
| +static const int stack_buffer_size = 1024;
|
| +static char stack_buffer[stack_buffer_size];
|
|
|
| +static void SaveStackTrace(Dart_StackTrace trace) {
|
| + Dart_ActivationFrame frame;
|
| + Dart_Handle func_name;
|
| +
|
| + char* buffer = stack_buffer;
|
| + int buffer_size = stack_buffer_size;
|
| +
|
| + intptr_t trace_len;
|
| + EXPECT_VALID(Dart_StackTraceLength(trace, &trace_len));
|
| +
|
| + for (intptr_t frame_index = 0; frame_index < trace_len; frame_index++) {
|
| + EXPECT_VALID(Dart_GetActivationFrame(trace, frame_index, &frame));
|
| + EXPECT_VALID(Dart_ActivationFrameInfo(frame, &func_name,
|
| + NULL, NULL, NULL));
|
| + int pos = OS::SNPrint(buffer, buffer_size, "[%" Pd "] %s { ",
|
| + frame_index, ToCString(func_name));
|
| + buffer += pos;
|
| + buffer_size -= pos;
|
| +
|
| + Dart_Handle locals = Dart_GetLocalVariables(frame);
|
| + EXPECT_VALID(locals);
|
| + intptr_t list_length = 0;
|
| + EXPECT_VALID(Dart_ListLength(locals, &list_length));
|
| +
|
| + for (intptr_t i = 0; i + 1 < list_length; i += 2) {
|
| + Dart_Handle name = Dart_ListGetAt(locals, i);
|
| + EXPECT_VALID(name);
|
| + EXPECT(Dart_IsString(name));
|
| +
|
| + Dart_Handle value = Dart_ListGetAt(locals, i + 1);
|
| + EXPECT_VALID(value);
|
| + Dart_Handle value_str = Dart_ToString(value);
|
| + EXPECT_VALID(value_str);
|
| +
|
| + const char* name_cstr = NULL;
|
| + const char* value_cstr = NULL;
|
| + EXPECT_VALID(Dart_StringToCString(name, &name_cstr));
|
| + EXPECT_VALID(Dart_StringToCString(value_str, &value_cstr));
|
| + pos = OS::SNPrint(buffer, buffer_size, "%s = %s ",
|
| + name_cstr, value_cstr);
|
| + buffer += pos;
|
| + buffer_size -= pos;
|
| + }
|
| + pos = OS::SNPrint(buffer, buffer_size, "}\n");
|
| + buffer += pos;
|
| + buffer_size -= pos;
|
| + }
|
| +}
|
| +
|
| +
|
| +static void InspectOptimizedStack_Breakpoint(Dart_IsolateId isolate_id,
|
| + const Dart_CodeLocation& loc) {
|
| + Dart_StackTrace trace;
|
| + Dart_GetStackTrace(&trace);
|
| + SaveStackTrace(trace);
|
| +}
|
| +
|
| +
|
| +static void InspectStackTest(bool optimize) {
|
| + const char* kScriptChars =
|
| + "void breakpointNow() {\n"
|
| + "}\n"
|
| + "void helper(int a, int b, bool stop) {\n"
|
| + " if (b == 99 && stop) {\n"
|
| + " breakpointNow();\n"
|
| + " }\n"
|
| + " int c = a*b;\n"
|
| + " return c;\n"
|
| + "}\n"
|
| + "int anotherMiddleMan(int one, int two, bool stop) {\n"
|
| + " return helper(one, two, stop);\n"
|
| + "}\n"
|
| + "int middleMan(int x, int limit, bool stop) {\n"
|
| + " int value = 0;\n"
|
| + " for (int i = 0; i < limit; i++) {\n"
|
| + " value += anotherMiddleMan(x, i, stop);\n"
|
| + " }\n"
|
| + " return value;\n"
|
| + "}\n"
|
| + "int test(bool stop, int limit) {\n"
|
| + " return middleMan(5, limit, stop);\n"
|
| + "}\n";
|
| +
|
| + LoadScript(kScriptChars);
|
| +
|
| + // Save/restore some compiler flags.
|
| + Dart_Handle dart_args[2];
|
| + int saved_threshold = FLAG_optimization_counter_threshold;
|
| + const int kLowThreshold = 100;
|
| + const int kHighThreshold = 10000;
|
| + bool saved_osr = FLAG_use_osr;
|
| + FLAG_use_osr = false;
|
| +
|
| + // Set up the breakpoint.
|
| + Dart_SetPausedEventHandler(InspectOptimizedStack_Breakpoint);
|
| + SetBreakpointAtEntry("", "breakpointNow");
|
| +
|
| + if (optimize) {
|
| + // Warm up the code to make sure it gets optimized. We ignore any
|
| + // breakpoints that get hit during warm-up.
|
| + FLAG_optimization_counter_threshold = kLowThreshold;
|
| + dart_args[0] = Dart_False();
|
| + dart_args[1] = Dart_NewInteger(kLowThreshold);
|
| + EXPECT_VALID(Dart_Invoke(script_lib, NewString("test"), 2, dart_args));
|
| + } else {
|
| + // Try to ensure that none of the test code gets optimized.
|
| + FLAG_optimization_counter_threshold = kHighThreshold;
|
| + }
|
| +
|
| + // Run the code and inspect the stack.
|
| + stack_buffer[0] = '\0';
|
| + dart_args[0] = Dart_True();
|
| + dart_args[1] = Dart_NewInteger(kLowThreshold);
|
| + EXPECT_VALID(Dart_Invoke(script_lib, NewString("test"), 2, dart_args));
|
| + if (optimize) {
|
| + // Note that several variables have the value 'null' in the
|
| + // optimized case. This is because these values were determined
|
| + // to be dead by the optimizing compiler and their values were not
|
| + // preserved by the deopt information.
|
| + EXPECT_STREQ("[0] breakpointNow { }\n"
|
| + "[1] helper { a = 5 b = 99 stop = null }\n"
|
| + "[2] anotherMiddleMan { one = null two = null stop = null }\n"
|
| + "[3] middleMan { x = 5 limit = 100 stop = true value = 24255"
|
| + " i = 99 }\n"
|
| + "[4] test { stop = true limit = 100 }\n",
|
| + stack_buffer);
|
| + } else {
|
| + EXPECT_STREQ("[0] breakpointNow { }\n"
|
| + "[1] helper { a = 5 b = 99 stop = true }\n"
|
| + "[2] anotherMiddleMan { one = 5 two = 99 stop = true }\n"
|
| + "[3] middleMan { x = 5 limit = 100 stop = true value = 24255"
|
| + " i = 99 }\n"
|
| + "[4] test { stop = true limit = 100 }\n",
|
| + stack_buffer);
|
| + }
|
| +
|
| + FLAG_optimization_counter_threshold = saved_threshold;
|
| + FLAG_use_osr = saved_osr;
|
| +}
|
| +
|
| +
|
| +TEST_CASE(Debug_InspectStack_NotOptimized) {
|
| + InspectStackTest(false);
|
| +}
|
| +
|
| +
|
| +TEST_CASE(Debug_InspectStack_Optimized) {
|
| + InspectStackTest(true);
|
| +}
|
| +
|
| +
|
| void TestStepOutHandler(Dart_IsolateId isolate_id,
|
| const Dart_CodeLocation& location) {
|
| Dart_StackTrace trace;
|
|
|