| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/dart_api_impl.h" | 5 #include "vm/dart_api_impl.h" |
| 6 #include "vm/dart_api_message.h" |
| 6 #include "vm/debugger.h" | 7 #include "vm/debugger.h" |
| 8 #include "vm/message.h" |
| 7 #include "vm/unit_test.h" | 9 #include "vm/unit_test.h" |
| 8 | 10 |
| 9 namespace dart { | 11 namespace dart { |
| 10 | 12 |
| 11 #ifndef PRODUCT | 13 #ifndef PRODUCT |
| 12 | 14 |
| 13 DECLARE_FLAG(bool, remove_script_timestamps_for_test); | 15 DECLARE_FLAG(bool, remove_script_timestamps_for_test); |
| 16 DECLARE_FLAG(bool, trace_rewind); |
| 14 | 17 |
| 15 // Search for the formatted string in buffer. | 18 // Search for the formatted string in buffer. |
| 16 // | 19 // |
| 17 // TODO(turnidge): This function obscures the line number of failing | 20 // TODO(turnidge): This function obscures the line number of failing |
| 18 // EXPECTs. Rework this. | 21 // EXPECTs. Rework this. |
| 19 static void ExpectSubstringF(const char* buff, const char* fmt, ...) { | 22 static void ExpectSubstringF(const char* buff, const char* fmt, ...) { |
| 20 va_list args; | 23 va_list args; |
| 21 va_start(args, fmt); | 24 va_start(args, fmt); |
| 22 intptr_t len = OS::VSNPrint(NULL, 0, fmt, args); | 25 intptr_t len = OS::VSNPrint(NULL, 0, fmt, args); |
| 23 va_end(args); | 26 va_end(args); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 // Set a breakpoint and run. | 137 // Set a breakpoint and run. |
| 135 EXPECT_VALID(Dart_SetBreakpoint(NewString(TestCase::url()), 2)); | 138 EXPECT_VALID(Dart_SetBreakpoint(NewString(TestCase::url()), 2)); |
| 136 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | 139 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); |
| 137 EXPECT_VALID(result); | 140 EXPECT_VALID(result); |
| 138 EXPECT(Dart_IsString(result)); | 141 EXPECT(Dart_IsString(result)); |
| 139 | 142 |
| 140 // We ran the code in InspectPausedEvent. | 143 // We ran the code in InspectPausedEvent. |
| 141 EXPECT(saw_paused_event); | 144 EXPECT(saw_paused_event); |
| 142 } | 145 } |
| 143 | 146 |
| 147 |
| 148 static uint8_t* malloc_allocator(uint8_t* ptr, |
| 149 intptr_t old_size, |
| 150 intptr_t new_size) { |
| 151 void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); |
| 152 return reinterpret_cast<uint8_t*>(new_ptr); |
| 153 } |
| 154 |
| 155 |
| 156 const char* rewind_frame_index = "-1"; |
| 157 |
| 158 |
| 159 // Build and send a fake resume OOB message for testing purposes. |
| 160 void SendResumeMessage(Isolate* isolate) { |
| 161 // Format is: [ oob_type, port, seq, method_name, [keys], [values] ] |
| 162 Dart_CObject msg; |
| 163 Dart_CObject* list_values[6]; |
| 164 msg.type = Dart_CObject_kArray; |
| 165 msg.value.as_array.length = 6; |
| 166 msg.value.as_array.values = list_values; |
| 167 |
| 168 Dart_CObject oob; |
| 169 oob.type = Dart_CObject_kInt32; |
| 170 oob.value.as_int32 = Message::kServiceOOBMsg; |
| 171 list_values[0] = &oob; |
| 172 |
| 173 Dart_CObject reply_port; |
| 174 reply_port.type = Dart_CObject_kNull; |
| 175 list_values[1] = &reply_port; |
| 176 |
| 177 Dart_CObject seq; |
| 178 seq.type = Dart_CObject_kNull; |
| 179 list_values[2] = &seq; |
| 180 |
| 181 Dart_CObject method_name; |
| 182 method_name.type = Dart_CObject_kString; |
| 183 method_name.value.as_string = const_cast<char*>("resume"); |
| 184 list_values[3] = &method_name; |
| 185 |
| 186 const int kParamCount = 3; |
| 187 Dart_CObject param_keys; |
| 188 Dart_CObject* param_keys_list[kParamCount]; |
| 189 param_keys.type = Dart_CObject_kArray; |
| 190 param_keys.value.as_array.values = param_keys_list; |
| 191 param_keys.value.as_array.length = kParamCount; |
| 192 list_values[4] = ¶m_keys; |
| 193 |
| 194 Dart_CObject param_values; |
| 195 Dart_CObject* param_values_list[kParamCount]; |
| 196 param_values.type = Dart_CObject_kArray; |
| 197 param_values.value.as_array.values = param_values_list; |
| 198 param_values.value.as_array.length = kParamCount; |
| 199 list_values[5] = ¶m_values; |
| 200 |
| 201 Dart_CObject param0_name; |
| 202 param0_name.type = Dart_CObject_kString; |
| 203 param0_name.value.as_string = const_cast<char*>("isolateId"); |
| 204 param_keys_list[0] = ¶m0_name; |
| 205 |
| 206 Dart_CObject param0_value; |
| 207 param0_value.type = Dart_CObject_kString; |
| 208 const char* isolate_id = Thread::Current()->zone()->PrintToString( |
| 209 ISOLATE_SERVICE_ID_FORMAT_STRING, |
| 210 static_cast<int64_t>(isolate->main_port())); |
| 211 param0_value.value.as_string = const_cast<char*>(isolate_id); |
| 212 param_values_list[0] = ¶m0_value; |
| 213 |
| 214 Dart_CObject param1_name; |
| 215 param1_name.type = Dart_CObject_kString; |
| 216 param1_name.value.as_string = const_cast<char*>("step"); |
| 217 param_keys_list[1] = ¶m1_name; |
| 218 |
| 219 Dart_CObject param1_value; |
| 220 param1_value.type = Dart_CObject_kString; |
| 221 param1_value.value.as_string = const_cast<char*>("Rewind"); |
| 222 param_values_list[1] = ¶m1_value; |
| 223 |
| 224 Dart_CObject param2_name; |
| 225 param2_name.type = Dart_CObject_kString; |
| 226 param2_name.value.as_string = const_cast<char*>("frameIndex"); |
| 227 param_keys_list[2] = ¶m2_name; |
| 228 |
| 229 Dart_CObject param2_value; |
| 230 param2_value.type = Dart_CObject_kString; |
| 231 param2_value.value.as_string = const_cast<char*>(rewind_frame_index); |
| 232 param_values_list[2] = ¶m2_value; |
| 233 |
| 234 { |
| 235 uint8_t* buffer = NULL; |
| 236 ApiMessageWriter writer(&buffer, &malloc_allocator); |
| 237 bool success = writer.WriteCMessage(&msg); |
| 238 ASSERT(success); |
| 239 |
| 240 // Post the message at the given port. |
| 241 success = PortMap::PostMessage(new Message(isolate->main_port(), buffer, |
| 242 writer.BytesWritten(), |
| 243 Message::kOOBPriority)); |
| 244 ASSERT(success); |
| 245 } |
| 246 } |
| 247 |
| 248 |
| 249 static void RewindOnce(Dart_IsolateId isolate_id, |
| 250 intptr_t bp_id, |
| 251 const Dart_CodeLocation& loc) { |
| 252 bool first_time = !saw_paused_event; |
| 253 saw_paused_event = true; |
| 254 if (first_time) { |
| 255 Thread* T = Thread::Current(); |
| 256 Isolate* I = T->isolate(); |
| 257 // TODO(turnidge): It is weird that the isolate can get to this |
| 258 // point in our tests without being marked runnable. Clear this up |
| 259 // at some point. |
| 260 I->set_is_runnable(true); |
| 261 SendResumeMessage(I); |
| 262 I->PauseEventHandler(); |
| 263 } |
| 264 } |
| 265 |
| 266 |
| 267 TEST_CASE(Debugger_RewindOneFrame_Unoptimized) { |
| 268 SetFlagScope<bool> sfs(&FLAG_trace_rewind, true); |
| 269 saw_paused_event = false; |
| 270 rewind_frame_index = "1"; |
| 271 |
| 272 const char* kScriptChars = |
| 273 "import 'dart:developer';\n" |
| 274 "\n" |
| 275 "var msg = new StringBuffer();\n" |
| 276 "\n" |
| 277 "foo() {\n" |
| 278 " msg.write('enter(foo) ');\n" |
| 279 " debugger();\n" |
| 280 " msg.write('exit(foo) ');\n" |
| 281 "}\n" |
| 282 "\n" |
| 283 "main() {\n" |
| 284 " msg.write('enter(main) ');\n" |
| 285 " foo();\n" |
| 286 " msg.write('exit(main) ');\n" |
| 287 " return msg.toString();\n" |
| 288 "}\n"; |
| 289 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); |
| 290 EXPECT_VALID(lib); |
| 291 |
| 292 Dart_SetPausedEventHandler(RewindOnce); |
| 293 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); |
| 294 const char* result_cstr; |
| 295 EXPECT_VALID(result); |
| 296 EXPECT(Dart_IsString(result)); |
| 297 EXPECT_VALID(Dart_StringToCString(result, &result_cstr)); |
| 298 EXPECT_STREQ("enter(main) enter(foo) enter(foo) exit(foo) exit(main) ", |
| 299 result_cstr); |
| 300 EXPECT(saw_paused_event); |
| 301 } |
| 302 |
| 303 |
| 304 TEST_CASE(Debugger_RewindTwoFrames_Unoptimized) { |
| 305 SetFlagScope<bool> sfs(&FLAG_trace_rewind, true); |
| 306 saw_paused_event = false; |
| 307 rewind_frame_index = "2"; |
| 308 |
| 309 const char* kScriptChars = |
| 310 "import 'dart:developer';\n" |
| 311 "\n" |
| 312 "var msg = new StringBuffer();\n" |
| 313 "\n" |
| 314 "foo() {\n" |
| 315 " msg.write('enter(foo) ');\n" |
| 316 " debugger();\n" |
| 317 " msg.write('exit(foo) ');\n" |
| 318 "}\n" |
| 319 "\n" |
| 320 "bar() {\n" |
| 321 " msg.write('enter(bar) ');\n" |
| 322 " foo();\n" |
| 323 " msg.write('exit(bar) ');\n" |
| 324 "}\n" |
| 325 "\n" |
| 326 "main() {\n" |
| 327 " msg.write('enter(main) ');\n" |
| 328 " bar();\n" |
| 329 " msg.write('exit(main) ');\n" |
| 330 " return msg.toString();\n" |
| 331 "}\n"; |
| 332 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); |
| 333 EXPECT_VALID(lib); |
| 334 |
| 335 Dart_SetPausedEventHandler(RewindOnce); |
| 336 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); |
| 337 const char* result_cstr; |
| 338 EXPECT_VALID(result); |
| 339 EXPECT(Dart_IsString(result)); |
| 340 EXPECT_VALID(Dart_StringToCString(result, &result_cstr)); |
| 341 EXPECT_STREQ( |
| 342 "enter(main) enter(bar) enter(foo) enter(bar) enter(foo) " |
| 343 "exit(foo) exit(bar) exit(main) ", |
| 344 result_cstr); |
| 345 EXPECT(saw_paused_event); |
| 346 } |
| 347 |
| 144 #endif // !PRODUCT | 348 #endif // !PRODUCT |
| 145 | 349 |
| 146 } // namespace dart | 350 } // namespace dart |
| OLD | NEW |