OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/arguments.h" | 8 #include "src/arguments.h" |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); | 380 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); |
381 if (target_code->kind() == Code::STUB) { | 381 if (target_code->kind() == Code::STUB) { |
382 return CodeStub::GetMajorKey(*target_code) == CodeStub::CallFunction; | 382 return CodeStub::GetMajorKey(*target_code) == CodeStub::CallFunction; |
383 } | 383 } |
384 return target_code->is_call_stub(); | 384 return target_code->is_call_stub(); |
385 } | 385 } |
386 return false; | 386 return false; |
387 } | 387 } |
388 | 388 |
389 | 389 |
390 void BreakLocationIterator::PrepareStepIn(Isolate* isolate) { | |
391 #ifdef DEBUG | |
392 HandleScope scope(isolate); | |
393 // Step in can only be prepared if currently positioned on an IC call, | |
394 // construct call or CallFunction stub call. | |
395 Address target = rinfo()->target_address(); | |
396 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); | |
397 // All the following stuff is needed only for assertion checks so the code | |
398 // is wrapped in ifdef. | |
399 Handle<Code> maybe_call_function_stub = target_code; | |
400 if (IsDebugBreak()) { | |
401 Address original_target = original_rinfo()->target_address(); | |
402 maybe_call_function_stub = | |
403 Handle<Code>(Code::GetCodeFromTargetAddress(original_target)); | |
404 } | |
405 bool is_call_function_stub = | |
406 (maybe_call_function_stub->kind() == Code::STUB && | |
407 CodeStub::GetMajorKey(*maybe_call_function_stub) == | |
408 CodeStub::CallFunction); | |
409 | |
410 // Step in through construct call requires no changes to the running code. | |
411 // Step in through getters/setters should already be prepared as well | |
412 // because caller of this function (Debug::PrepareStep) is expected to | |
413 // flood the top frame's function with one shot breakpoints. | |
414 // Step in through CallFunction stub should also be prepared by caller of | |
415 // this function (Debug::PrepareStep) which should flood target function | |
416 // with breakpoints. | |
417 DCHECK(RelocInfo::IsConstructCall(rmode()) || | |
418 target_code->is_inline_cache_stub() || | |
419 is_call_function_stub); | |
420 #endif | |
421 } | |
422 | |
423 | |
424 // Check whether the break point is at a position which will exit the function. | 390 // Check whether the break point is at a position which will exit the function. |
425 bool BreakLocationIterator::IsExit() const { | 391 bool BreakLocationIterator::IsExit() const { |
426 return (RelocInfo::IsJSReturn(rmode())); | 392 return (RelocInfo::IsJSReturn(rmode())); |
427 } | 393 } |
428 | 394 |
429 | 395 |
430 bool BreakLocationIterator::HasBreakPoint() { | 396 bool BreakLocationIterator::HasBreakPoint() { |
431 return debug_info_->HasBreakPoint(code_position()); | 397 return debug_info_->HasBreakPoint(code_position()); |
432 } | 398 } |
433 | 399 |
(...skipping 930 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1364 | 1330 |
1365 // Get the debug info (create it if it does not exist). | 1331 // Get the debug info (create it if it does not exist). |
1366 Handle<JSFunction> function(frame->function()); | 1332 Handle<JSFunction> function(frame->function()); |
1367 Handle<SharedFunctionInfo> shared(function->shared()); | 1333 Handle<SharedFunctionInfo> shared(function->shared()); |
1368 if (!EnsureDebugInfo(shared, function)) { | 1334 if (!EnsureDebugInfo(shared, function)) { |
1369 // Return if ensuring debug info failed. | 1335 // Return if ensuring debug info failed. |
1370 return; | 1336 return; |
1371 } | 1337 } |
1372 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 1338 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
1373 | 1339 |
1374 // Find the break location where execution has stopped. | |
1375 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS); | |
1376 // pc points to the instruction after the current one, possibly a break | |
1377 // location as well. So the "- 1" to exclude it from the search. | |
1378 it.FindBreakLocationFromAddress(frame->pc() - 1); | |
1379 | |
1380 // Compute whether or not the target is a call target. | 1340 // Compute whether or not the target is a call target. |
1381 bool is_load_or_store = false; | 1341 bool is_load_or_store = false; |
1382 bool is_inline_cache_stub = false; | 1342 bool is_inline_cache_stub = false; |
1383 bool is_at_restarted_function = false; | 1343 bool is_at_restarted_function = false; |
| 1344 bool is_exit = false; |
| 1345 bool is_construct_call = false; |
1384 Handle<Code> call_function_stub; | 1346 Handle<Code> call_function_stub; |
1385 | 1347 |
1386 if (thread_local_.restarter_frame_function_pointer_ == NULL) { | 1348 { |
1387 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) { | 1349 // Find the break location where execution has stopped. |
1388 bool is_call_target = false; | 1350 DisallowHeapAllocation no_gc; |
1389 Address target = it.rinfo()->target_address(); | 1351 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS); |
1390 Code* code = Code::GetCodeFromTargetAddress(target); | 1352 |
1391 if (code->is_call_stub()) { | 1353 // pc points to the instruction after the current one, possibly a break |
1392 is_call_target = true; | 1354 // location as well. So the "- 1" to exclude it from the search. |
| 1355 it.FindBreakLocationFromAddress(frame->pc() - 1); |
| 1356 |
| 1357 is_exit = it.IsExit(); |
| 1358 |
| 1359 if (thread_local_.restarter_frame_function_pointer_ == NULL) { |
| 1360 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) { |
| 1361 bool is_call_target = false; |
| 1362 Address target = it.rinfo()->target_address(); |
| 1363 Code* code = Code::GetCodeFromTargetAddress(target); |
| 1364 |
| 1365 is_call_target = code->is_call_stub(); |
| 1366 is_construct_call = RelocInfo::IsConstructCall(it.rmode()); |
| 1367 is_inline_cache_stub = code->is_inline_cache_stub(); |
| 1368 is_load_or_store = is_inline_cache_stub && !is_call_target; |
| 1369 |
| 1370 // Check if target code is CallFunction stub. |
| 1371 Code* maybe_call_function_stub = code; |
| 1372 // If there is a breakpoint at this line look at the original code to |
| 1373 // check if it is a CallFunction stub. |
| 1374 if (it.IsDebugBreak()) { |
| 1375 Address original_target = it.original_rinfo()->target_address(); |
| 1376 maybe_call_function_stub = |
| 1377 Code::GetCodeFromTargetAddress(original_target); |
| 1378 } |
| 1379 if ((maybe_call_function_stub->kind() == Code::STUB && |
| 1380 CodeStub::GetMajorKey(maybe_call_function_stub) == |
| 1381 CodeStub::CallFunction) || |
| 1382 maybe_call_function_stub->is_call_stub()) { |
| 1383 // Save reference to the code as we may need it to find out arguments |
| 1384 // count for 'step in' later. |
| 1385 call_function_stub = Handle<Code>(maybe_call_function_stub); |
| 1386 } |
1393 } | 1387 } |
1394 if (code->is_inline_cache_stub()) { | 1388 } else { |
1395 is_inline_cache_stub = true; | 1389 is_at_restarted_function = true; |
1396 is_load_or_store = !is_call_target; | |
1397 } | |
1398 | |
1399 // Check if target code is CallFunction stub. | |
1400 Code* maybe_call_function_stub = code; | |
1401 // If there is a breakpoint at this line look at the original code to | |
1402 // check if it is a CallFunction stub. | |
1403 if (it.IsDebugBreak()) { | |
1404 Address original_target = it.original_rinfo()->target_address(); | |
1405 maybe_call_function_stub = | |
1406 Code::GetCodeFromTargetAddress(original_target); | |
1407 } | |
1408 if ((maybe_call_function_stub->kind() == Code::STUB && | |
1409 CodeStub::GetMajorKey(maybe_call_function_stub) == | |
1410 CodeStub::CallFunction) || | |
1411 maybe_call_function_stub->is_call_stub()) { | |
1412 // Save reference to the code as we may need it to find out arguments | |
1413 // count for 'step in' later. | |
1414 call_function_stub = Handle<Code>(maybe_call_function_stub); | |
1415 } | |
1416 } | 1390 } |
1417 } else { | |
1418 is_at_restarted_function = true; | |
1419 } | 1391 } |
1420 | 1392 |
1421 // If this is the last break code target step out is the only possibility. | 1393 // If this is the last break code target step out is the only possibility. |
1422 if (it.IsExit() || step_action == StepOut) { | 1394 if (is_exit || step_action == StepOut) { |
1423 if (step_action == StepOut) { | 1395 if (step_action == StepOut) { |
1424 // Skip step_count frames starting with the current one. | 1396 // Skip step_count frames starting with the current one. |
1425 while (step_count-- > 0 && !frames_it.done()) { | 1397 while (step_count-- > 0 && !frames_it.done()) { |
1426 frames_it.Advance(); | 1398 frames_it.Advance(); |
1427 } | 1399 } |
1428 } else { | 1400 } else { |
1429 DCHECK(it.IsExit()); | 1401 DCHECK(is_exit); |
1430 frames_it.Advance(); | 1402 frames_it.Advance(); |
1431 } | 1403 } |
1432 // Skip builtin functions on the stack. | 1404 // Skip builtin functions on the stack. |
1433 while (!frames_it.done() && | 1405 while (!frames_it.done() && |
1434 frames_it.frame()->function()->IsFromNativeScript()) { | 1406 frames_it.frame()->function()->IsFromNativeScript()) { |
1435 frames_it.Advance(); | 1407 frames_it.Advance(); |
1436 } | 1408 } |
1437 // Step out: If there is a JavaScript caller frame, we need to | 1409 // Step out: If there is a JavaScript caller frame, we need to |
1438 // flood it with breakpoints. | 1410 // flood it with breakpoints. |
1439 if (!frames_it.done()) { | 1411 if (!frames_it.done()) { |
1440 // Fill the function to return to with one-shot break points. | 1412 // Fill the function to return to with one-shot break points. |
1441 JSFunction* function = frames_it.frame()->function(); | 1413 JSFunction* function = frames_it.frame()->function(); |
1442 FloodWithOneShot(Handle<JSFunction>(function)); | 1414 FloodWithOneShot(Handle<JSFunction>(function)); |
1443 // Set target frame pointer. | 1415 // Set target frame pointer. |
1444 ActivateStepOut(frames_it.frame()); | 1416 ActivateStepOut(frames_it.frame()); |
1445 } | 1417 } |
1446 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) || | 1418 } else if (!(is_inline_cache_stub || is_construct_call || |
1447 !call_function_stub.is_null() || is_at_restarted_function) | 1419 !call_function_stub.is_null() || is_at_restarted_function) || |
1448 || step_action == StepNext || step_action == StepMin) { | 1420 step_action == StepNext || step_action == StepMin) { |
1449 // Step next or step min. | 1421 // Step next or step min. |
1450 | 1422 |
1451 // Fill the current function with one-shot break points. | 1423 // Fill the current function with one-shot break points. |
1452 // If we are stepping into another frame, only fill calls and returns. | 1424 // If we are stepping into another frame, only fill calls and returns. |
1453 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS | 1425 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS |
1454 : ALL_BREAK_LOCATIONS); | 1426 : ALL_BREAK_LOCATIONS); |
1455 | 1427 |
1456 // Remember source position and frame to handle step next. | 1428 // Remember source position and frame to handle step next. |
1457 thread_local_.last_statement_position_ = | 1429 thread_local_.last_statement_position_ = |
1458 debug_info->code()->SourceStatementPosition(frame->pc()); | 1430 debug_info->code()->SourceStatementPosition(frame->pc()); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1525 // Remember source position and frame to handle step in getter/setter. If | 1497 // Remember source position and frame to handle step in getter/setter. If |
1526 // there is a custom getter/setter it will be handled in | 1498 // there is a custom getter/setter it will be handled in |
1527 // Object::Get/SetPropertyWithAccessor, otherwise the step action will be | 1499 // Object::Get/SetPropertyWithAccessor, otherwise the step action will be |
1528 // propagated on the next Debug::Break. | 1500 // propagated on the next Debug::Break. |
1529 thread_local_.last_statement_position_ = | 1501 thread_local_.last_statement_position_ = |
1530 debug_info->code()->SourceStatementPosition(frame->pc()); | 1502 debug_info->code()->SourceStatementPosition(frame->pc()); |
1531 thread_local_.last_fp_ = frame->UnpaddedFP(); | 1503 thread_local_.last_fp_ = frame->UnpaddedFP(); |
1532 } | 1504 } |
1533 | 1505 |
1534 // Step in or Step in min | 1506 // Step in or Step in min |
1535 it.PrepareStepIn(isolate_); | 1507 // Step in through construct call requires no changes to the running code. |
| 1508 // Step in through getters/setters should already be prepared as well |
| 1509 // because caller of this function (Debug::PrepareStep) is expected to |
| 1510 // flood the top frame's function with one shot breakpoints. |
| 1511 // Step in through CallFunction stub should also be prepared by caller of |
| 1512 // this function (Debug::PrepareStep) which should flood target function |
| 1513 // with breakpoints. |
| 1514 DCHECK(is_construct_call || is_inline_cache_stub || |
| 1515 !call_function_stub.is_null()); |
1536 ActivateStepIn(frame); | 1516 ActivateStepIn(frame); |
1537 } | 1517 } |
1538 } | 1518 } |
1539 | 1519 |
1540 | 1520 |
1541 // Check whether the current debug break should be reported to the debugger. It | 1521 // Check whether the current debug break should be reported to the debugger. It |
1542 // is used to have step next and step in only report break back to the debugger | 1522 // is used to have step next and step in only report break back to the debugger |
1543 // if on a different frame or in a different statement. In some situations | 1523 // if on a different frame or in a different statement. In some situations |
1544 // there will be several break points in the same statement when the code is | 1524 // there will be several break points in the same statement when the code is |
1545 // flooded with one-shot break points. This function helps to perform several | 1525 // flooded with one-shot break points. This function helps to perform several |
(...skipping 1946 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3492 logger_->DebugEvent("Put", message.text()); | 3472 logger_->DebugEvent("Put", message.text()); |
3493 } | 3473 } |
3494 | 3474 |
3495 | 3475 |
3496 void LockingCommandMessageQueue::Clear() { | 3476 void LockingCommandMessageQueue::Clear() { |
3497 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 3477 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
3498 queue_.Clear(); | 3478 queue_.Clear(); |
3499 } | 3479 } |
3500 | 3480 |
3501 } } // namespace v8::internal | 3481 } } // namespace v8::internal |
OLD | NEW |