| 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 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 } | 110 } |
| 111 // Always update the position as we don't want that to be before the | 111 // Always update the position as we don't want that to be before the |
| 112 // statement position. | 112 // statement position. |
| 113 position_ = static_cast<int>(rinfo()->data() - | 113 position_ = static_cast<int>(rinfo()->data() - |
| 114 debug_info_->shared()->start_position()); | 114 debug_info_->shared()->start_position()); |
| 115 DCHECK(position_ >= 0); | 115 DCHECK(position_ >= 0); |
| 116 DCHECK(statement_position_ >= 0); | 116 DCHECK(statement_position_ >= 0); |
| 117 continue; | 117 continue; |
| 118 } | 118 } |
| 119 | 119 |
| 120 // Check for break at return. | |
| 121 if (RelocInfo::IsJSReturn(rmode())) { | 120 if (RelocInfo::IsJSReturn(rmode())) { |
| 122 // Set the positions to the end of the function. | 121 // Set the positions to the end of the function. |
| 123 if (debug_info_->shared()->HasSourceCode()) { | 122 if (debug_info_->shared()->HasSourceCode()) { |
| 124 position_ = debug_info_->shared()->end_position() - | 123 position_ = debug_info_->shared()->end_position() - |
| 125 debug_info_->shared()->start_position() - 1; | 124 debug_info_->shared()->start_position() - 1; |
| 126 } else { | 125 } else { |
| 127 position_ = 0; | 126 position_ = 0; |
| 128 } | 127 } |
| 129 statement_position_ = position_; | 128 statement_position_ = position_; |
| 130 break_index_++; | |
| 131 break; | 129 break; |
| 132 } | 130 } |
| 133 | 131 |
| 134 if (RelocInfo::IsCodeTarget(rmode())) { | 132 if (RelocInfo::IsDebugBreakSlot(rmode()) && |
| 135 // Check for breakable code target. Look in the original code as setting | 133 (type_ == ALL_BREAK_LOCATIONS || |
| 136 // break points can cause the code targets in the running (debugged) code | 134 RelocInfo::DebugBreakIsCall(rinfo()->data()))) { |
| 137 // to be of a different kind than in the original code. | |
| 138 Address target = original_rinfo()->target_address(); | |
| 139 Code* code = Code::GetCodeFromTargetAddress(target); | |
| 140 | |
| 141 if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) { | |
| 142 break_index_++; | |
| 143 break; | |
| 144 } | |
| 145 | |
| 146 if (code->kind() == Code::STUB && | |
| 147 CodeStub::GetMajorKey(code) == CodeStub::CallFunction) { | |
| 148 break_index_++; | |
| 149 break; | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 // Skip below if we only want locations for calls and returns. | |
| 154 if (type_ == CALLS_AND_RETURNS) continue; | |
| 155 | |
| 156 if (RelocInfo::IsDebuggerStatement(rmode())) { | |
| 157 break_index_++; | |
| 158 break; | 135 break; |
| 159 } | 136 } |
| 160 | 137 |
| 161 if (RelocInfo::IsDebugBreakSlot(rmode()) && type_ != CALLS_AND_RETURNS) { | 138 if (RelocInfo::IsDebuggerStatement(rmode()) && |
| 162 // There is always a possible break point at a debug break slot. | 139 type_ == ALL_BREAK_LOCATIONS) { |
| 163 break_index_++; | |
| 164 break; | 140 break; |
| 165 } | 141 } |
| 166 } | 142 } |
| 143 break_index_++; |
| 167 } | 144 } |
| 168 | 145 |
| 169 | 146 |
| 170 // Find the break point at the supplied address, or the closest one before | 147 // Find the break point at the supplied address, or the closest one before |
| 171 // the address. | 148 // the address. |
| 172 BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, | 149 BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, |
| 173 BreakLocatorType type, Address pc) { | 150 BreakLocatorType type, Address pc) { |
| 174 Iterator it(debug_info, type); | 151 Iterator it(debug_info, type); |
| 175 it.SkipTo(BreakIndexFromAddress(debug_info, type, pc)); | 152 it.SkipTo(BreakIndexFromAddress(debug_info, type, pc)); |
| 176 return it.GetBreakLocation(); | 153 return it.GetBreakLocation(); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 // function twice might happen when stepping in a function with an exception | 281 // function twice might happen when stepping in a function with an exception |
| 305 // handler as the handler and the function is the same. | 282 // handler as the handler and the function is the same. |
| 306 if (IsDebugBreak()) return; | 283 if (IsDebugBreak()) return; |
| 307 | 284 |
| 308 if (IsExit()) { | 285 if (IsExit()) { |
| 309 // Patch the frame exit code with a break point. | 286 // Patch the frame exit code with a break point. |
| 310 SetDebugBreakAtReturn(); | 287 SetDebugBreakAtReturn(); |
| 311 } else if (IsDebugBreakSlot()) { | 288 } else if (IsDebugBreakSlot()) { |
| 312 // Patch the code in the break slot. | 289 // Patch the code in the break slot. |
| 313 SetDebugBreakAtSlot(); | 290 SetDebugBreakAtSlot(); |
| 314 } else { | |
| 315 // Patch the IC call. | |
| 316 SetDebugBreakAtIC(); | |
| 317 } | 291 } |
| 318 DCHECK(IsDebugBreak()); | 292 DCHECK(IsDebugBreak()); |
| 319 } | 293 } |
| 320 | 294 |
| 321 | 295 |
| 322 void BreakLocation::ClearDebugBreak() { | 296 void BreakLocation::ClearDebugBreak() { |
| 323 // Debugger statement always calls debugger. No need to modify it. | 297 // Debugger statement always calls debugger. No need to modify it. |
| 324 if (IsDebuggerStatement()) return; | 298 if (IsDebuggerStatement()) return; |
| 325 | 299 |
| 326 if (IsExit()) { | 300 if (IsExit()) { |
| 327 // Restore the frame exit code with a break point. | 301 // Restore the frame exit code with a break point. |
| 328 RestoreFromOriginal(Assembler::kJSReturnSequenceLength); | 302 RestoreFromOriginal(Assembler::kJSReturnSequenceLength); |
| 329 } else if (IsDebugBreakSlot()) { | 303 } else if (IsDebugBreakSlot()) { |
| 330 // Restore the code in the break slot. | 304 // Restore the code in the break slot. |
| 331 RestoreFromOriginal(Assembler::kDebugBreakSlotLength); | 305 RestoreFromOriginal(Assembler::kDebugBreakSlotLength); |
| 332 } else { | |
| 333 // Restore the IC call. | |
| 334 rinfo().set_target_address(original_rinfo().target_address()); | |
| 335 // Some ICs store data in the feedback vector. Clear this to ensure we | |
| 336 // won't miss future stepping requirements. | |
| 337 SharedFunctionInfo* shared = debug_info_->shared(); | |
| 338 shared->feedback_vector()->ClearICSlots(shared); | |
| 339 } | 306 } |
| 340 DCHECK(!IsDebugBreak()); | 307 DCHECK(!IsDebugBreak()); |
| 341 } | 308 } |
| 342 | 309 |
| 343 | 310 |
| 344 void BreakLocation::RestoreFromOriginal(int length_in_bytes) { | 311 void BreakLocation::RestoreFromOriginal(int length_in_bytes) { |
| 345 memcpy(pc(), original_pc(), length_in_bytes); | 312 memcpy(pc(), original_pc(), length_in_bytes); |
| 346 CpuFeatures::FlushICache(pc(), length_in_bytes); | 313 CpuFeatures::FlushICache(pc(), length_in_bytes); |
| 347 } | 314 } |
| 348 | 315 |
| 349 | 316 |
| 350 bool BreakLocation::IsStepInLocation() const { | 317 bool BreakLocation::IsStepInLocation() const { |
| 351 if (IsConstructCall()) return true; | 318 return IsConstructCall() || IsCall(); |
| 352 if (RelocInfo::IsCodeTarget(rmode())) { | |
| 353 HandleScope scope(debug_info_->GetIsolate()); | |
| 354 Handle<Code> target_code = CodeTarget(); | |
| 355 return target_code->is_call_stub(); | |
| 356 } | |
| 357 return false; | |
| 358 } | 319 } |
| 359 | 320 |
| 360 | 321 |
| 361 bool BreakLocation::IsDebugBreak() const { | 322 bool BreakLocation::IsDebugBreak() const { |
| 362 if (IsExit()) { | 323 if (IsExit()) { |
| 363 return rinfo().IsPatchedReturnSequence(); | 324 return rinfo().IsPatchedReturnSequence(); |
| 364 } else if (IsDebugBreakSlot()) { | 325 } else if (IsDebugBreakSlot()) { |
| 365 return rinfo().IsPatchedDebugBreakSlotSequence(); | 326 return rinfo().IsPatchedDebugBreakSlotSequence(); |
| 366 } else { | |
| 367 return Debug::IsDebugBreak(rinfo().target_address()); | |
| 368 } | 327 } |
| 328 return false; |
| 369 } | 329 } |
| 370 | 330 |
| 371 | 331 |
| 372 // Find the builtin to use for invoking the debug break | |
| 373 static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) { | |
| 374 Isolate* isolate = code->GetIsolate(); | |
| 375 | |
| 376 // Find the builtin debug break function matching the calling convention | |
| 377 // used by the call site. | |
| 378 if (code->is_inline_cache_stub()) { | |
| 379 DCHECK(code->kind() == Code::CALL_IC); | |
| 380 return isolate->builtins()->CallICStub_DebugBreak(); | |
| 381 } | |
| 382 if (RelocInfo::IsConstructCall(mode)) { | |
| 383 if (code->has_function_cache()) { | |
| 384 return isolate->builtins()->CallConstructStub_Recording_DebugBreak(); | |
| 385 } else { | |
| 386 return isolate->builtins()->CallConstructStub_DebugBreak(); | |
| 387 } | |
| 388 } | |
| 389 if (code->kind() == Code::STUB) { | |
| 390 DCHECK(CodeStub::GetMajorKey(*code) == CodeStub::CallFunction); | |
| 391 return isolate->builtins()->CallFunctionStub_DebugBreak(); | |
| 392 } | |
| 393 | |
| 394 UNREACHABLE(); | |
| 395 return Handle<Code>::null(); | |
| 396 } | |
| 397 | |
| 398 | |
| 399 void BreakLocation::SetDebugBreakAtIC() { | |
| 400 // Patch the original code with the current address as the current address | |
| 401 // might have changed by the inline caching since the code was copied. | |
| 402 original_rinfo().set_target_address(rinfo().target_address()); | |
| 403 | |
| 404 if (RelocInfo::IsCodeTarget(rmode_)) { | |
| 405 Handle<Code> target_code = CodeTarget(); | |
| 406 | |
| 407 // Patch the code to invoke the builtin debug break function matching the | |
| 408 // calling convention used by the call site. | |
| 409 Handle<Code> debug_break_code = DebugBreakForIC(target_code, rmode_); | |
| 410 rinfo().set_target_address(debug_break_code->entry()); | |
| 411 } | |
| 412 } | |
| 413 | |
| 414 | |
| 415 Handle<Object> BreakLocation::BreakPointObjects() const { | 332 Handle<Object> BreakLocation::BreakPointObjects() const { |
| 416 return debug_info_->GetBreakPointObjects(pc_offset_); | 333 return debug_info_->GetBreakPointObjects(pc_offset_); |
| 417 } | 334 } |
| 418 | 335 |
| 419 | 336 |
| 420 Handle<Code> BreakLocation::CodeTarget() const { | |
| 421 DCHECK(IsCodeTarget()); | |
| 422 Address target = rinfo().target_address(); | |
| 423 return Handle<Code>(Code::GetCodeFromTargetAddress(target)); | |
| 424 } | |
| 425 | |
| 426 | |
| 427 Handle<Code> BreakLocation::OriginalCodeTarget() const { | |
| 428 DCHECK(IsCodeTarget()); | |
| 429 Address target = original_rinfo().target_address(); | |
| 430 return Handle<Code>(Code::GetCodeFromTargetAddress(target)); | |
| 431 } | |
| 432 | |
| 433 | |
| 434 bool BreakLocation::Iterator::RinfoDone() const { | 337 bool BreakLocation::Iterator::RinfoDone() const { |
| 435 DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); | 338 DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); |
| 436 return reloc_iterator_.done(); | 339 return reloc_iterator_.done(); |
| 437 } | 340 } |
| 438 | 341 |
| 439 | 342 |
| 440 void BreakLocation::Iterator::RinfoNext() { | 343 void BreakLocation::Iterator::RinfoNext() { |
| 441 reloc_iterator_.next(); | 344 reloc_iterator_.next(); |
| 442 reloc_iterator_original_.next(); | 345 reloc_iterator_original_.next(); |
| 443 #ifdef DEBUG | 346 #ifdef DEBUG |
| 444 DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); | 347 DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); |
| 445 DCHECK(reloc_iterator_.done() || rmode() == original_rmode()); | 348 DCHECK(reloc_iterator_.done() || rmode() == original_rinfo()->rmode()); |
| 446 #endif | 349 #endif |
| 447 } | 350 } |
| 448 | 351 |
| 449 | 352 |
| 450 // Threading support. | 353 // Threading support. |
| 451 void Debug::ThreadInit() { | 354 void Debug::ThreadInit() { |
| 452 thread_local_.break_count_ = 0; | 355 thread_local_.break_count_ = 0; |
| 453 thread_local_.break_id_ = 0; | 356 thread_local_.break_id_ = 0; |
| 454 thread_local_.break_frame_id_ = StackFrame::NO_ID; | 357 thread_local_.break_frame_id_ = StackFrame::NO_ID; |
| 455 thread_local_.last_step_action_ = StepNone; | 358 thread_local_.last_step_action_ = StepNone; |
| (...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 934 // Return if retrieving debug info failed. | 837 // Return if retrieving debug info failed. |
| 935 return true; | 838 return true; |
| 936 } | 839 } |
| 937 | 840 |
| 938 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 841 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
| 939 // Source positions starts with zero. | 842 // Source positions starts with zero. |
| 940 DCHECK(*source_position >= 0); | 843 DCHECK(*source_position >= 0); |
| 941 | 844 |
| 942 // Find the break point and change it. | 845 // Find the break point and change it. |
| 943 BreakLocation location = BreakLocation::FromPosition( | 846 BreakLocation location = BreakLocation::FromPosition( |
| 944 debug_info, SOURCE_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED); | 847 debug_info, ALL_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED); |
| 945 *source_position = location.statement_position(); | 848 *source_position = location.statement_position(); |
| 946 location.SetBreakPoint(break_point_object); | 849 location.SetBreakPoint(break_point_object); |
| 947 | 850 |
| 948 // At least one active break point now. | 851 // At least one active break point now. |
| 949 return debug_info->GetBreakPointCount() > 0; | 852 return debug_info->GetBreakPointCount() > 0; |
| 950 } | 853 } |
| 951 | 854 |
| 952 | 855 |
| 953 bool Debug::SetBreakPointForScript(Handle<Script> script, | 856 bool Debug::SetBreakPointForScript(Handle<Script> script, |
| 954 Handle<Object> break_point_object, | 857 Handle<Object> break_point_object, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 978 } else { | 881 } else { |
| 979 position = *source_position - shared->start_position(); | 882 position = *source_position - shared->start_position(); |
| 980 } | 883 } |
| 981 | 884 |
| 982 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 885 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
| 983 // Source positions starts with zero. | 886 // Source positions starts with zero. |
| 984 DCHECK(position >= 0); | 887 DCHECK(position >= 0); |
| 985 | 888 |
| 986 // Find the break point and change it. | 889 // Find the break point and change it. |
| 987 BreakLocation location = BreakLocation::FromPosition( | 890 BreakLocation location = BreakLocation::FromPosition( |
| 988 debug_info, SOURCE_BREAK_LOCATIONS, position, alignment); | 891 debug_info, ALL_BREAK_LOCATIONS, position, alignment); |
| 989 location.SetBreakPoint(break_point_object); | 892 location.SetBreakPoint(break_point_object); |
| 990 | 893 |
| 991 position = (alignment == STATEMENT_ALIGNED) ? location.statement_position() | 894 position = (alignment == STATEMENT_ALIGNED) ? location.statement_position() |
| 992 : location.position(); | 895 : location.position(); |
| 993 | 896 |
| 994 *source_position = position + shared->start_position(); | 897 *source_position = position + shared->start_position(); |
| 995 | 898 |
| 996 // At least one active break point now. | 899 // At least one active break point now. |
| 997 DCHECK(debug_info->GetBreakPointCount() > 0); | 900 DCHECK(debug_info->GetBreakPointCount() > 0); |
| 998 return true; | 901 return true; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1010 // Get information in the break point. | 913 // Get information in the break point. |
| 1011 Handle<BreakPointInfo> break_point_info = | 914 Handle<BreakPointInfo> break_point_info = |
| 1012 Handle<BreakPointInfo>::cast(result); | 915 Handle<BreakPointInfo>::cast(result); |
| 1013 Handle<DebugInfo> debug_info = node->debug_info(); | 916 Handle<DebugInfo> debug_info = node->debug_info(); |
| 1014 | 917 |
| 1015 // Find the break point and clear it. | 918 // Find the break point and clear it. |
| 1016 Address pc = debug_info->code()->entry() + | 919 Address pc = debug_info->code()->entry() + |
| 1017 break_point_info->code_position()->value(); | 920 break_point_info->code_position()->value(); |
| 1018 | 921 |
| 1019 BreakLocation location = | 922 BreakLocation location = |
| 1020 BreakLocation::FromAddress(debug_info, SOURCE_BREAK_LOCATIONS, pc); | 923 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, pc); |
| 1021 location.ClearBreakPoint(break_point_object); | 924 location.ClearBreakPoint(break_point_object); |
| 1022 | 925 |
| 1023 // If there are no more break points left remove the debug info for this | 926 // If there are no more break points left remove the debug info for this |
| 1024 // function. | 927 // function. |
| 1025 if (debug_info->GetBreakPointCount() == 0) { | 928 if (debug_info->GetBreakPointCount() == 0) { |
| 1026 RemoveDebugInfoAndClearFromShared(debug_info); | 929 RemoveDebugInfoAndClearFromShared(debug_info); |
| 1027 } | 930 } |
| 1028 | 931 |
| 1029 return; | 932 return; |
| 1030 } | 933 } |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1231 // Compute whether or not the target is a call target. | 1134 // Compute whether or not the target is a call target. |
| 1232 bool is_at_restarted_function = false; | 1135 bool is_at_restarted_function = false; |
| 1233 Handle<Code> call_function_stub; | 1136 Handle<Code> call_function_stub; |
| 1234 | 1137 |
| 1235 // PC points to the instruction after the current one, possibly a break | 1138 // PC points to the instruction after the current one, possibly a break |
| 1236 // location as well. So the "- 1" to exclude it from the search. | 1139 // location as well. So the "- 1" to exclude it from the search. |
| 1237 Address call_pc = summary.pc() - 1; | 1140 Address call_pc = summary.pc() - 1; |
| 1238 BreakLocation location = | 1141 BreakLocation location = |
| 1239 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); | 1142 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); |
| 1240 | 1143 |
| 1241 if (thread_local_.restarter_frame_function_pointer_ == NULL) { | 1144 if (thread_local_.restarter_frame_function_pointer_ != NULL) { |
| 1242 if (location.IsCodeTarget()) { | |
| 1243 Handle<Code> target_code = location.CodeTarget(); | |
| 1244 | |
| 1245 // Check if target code is CallFunction stub. | |
| 1246 Handle<Code> maybe_call_function_stub = target_code; | |
| 1247 // If there is a breakpoint at this line look at the original code to | |
| 1248 // check if it is a CallFunction stub. | |
| 1249 if (location.IsDebugBreak()) { | |
| 1250 maybe_call_function_stub = location.OriginalCodeTarget(); | |
| 1251 } | |
| 1252 if ((maybe_call_function_stub->kind() == Code::STUB && | |
| 1253 CodeStub::GetMajorKey(*maybe_call_function_stub) == | |
| 1254 CodeStub::CallFunction) || | |
| 1255 maybe_call_function_stub->is_call_stub()) { | |
| 1256 // Save reference to the code as we may need it to find out arguments | |
| 1257 // count for 'step in' later. | |
| 1258 call_function_stub = maybe_call_function_stub; | |
| 1259 } | |
| 1260 } | |
| 1261 } else { | |
| 1262 is_at_restarted_function = true; | 1145 is_at_restarted_function = true; |
| 1263 } | 1146 } |
| 1264 | 1147 |
| 1265 // If this is the last break code target step out is the only possibility. | 1148 // If this is the last break code target step out is the only possibility. |
| 1266 if (location.IsExit() || step_action == StepOut) { | 1149 if (location.IsExit() || step_action == StepOut) { |
| 1267 if (step_action == StepOut) { | 1150 if (step_action == StepOut) { |
| 1268 // Skip step_count frames starting with the current one. | 1151 // Skip step_count frames starting with the current one. |
| 1269 while (step_count-- > 0 && !frames_it.done()) { | 1152 while (step_count-- > 0 && !frames_it.done()) { |
| 1270 frames_it.Advance(); | 1153 frames_it.Advance(); |
| 1271 } | 1154 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1290 return; | 1173 return; |
| 1291 } | 1174 } |
| 1292 | 1175 |
| 1293 if (step_action != StepNext && step_action != StepMin) { | 1176 if (step_action != StepNext && step_action != StepMin) { |
| 1294 // If there's restarter frame on top of the stack, just get the pointer | 1177 // If there's restarter frame on top of the stack, just get the pointer |
| 1295 // to function which is going to be restarted. | 1178 // to function which is going to be restarted. |
| 1296 if (is_at_restarted_function) { | 1179 if (is_at_restarted_function) { |
| 1297 Handle<JSFunction> restarted_function( | 1180 Handle<JSFunction> restarted_function( |
| 1298 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_)); | 1181 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_)); |
| 1299 FloodWithOneShot(restarted_function); | 1182 FloodWithOneShot(restarted_function); |
| 1300 } else if (!call_function_stub.is_null()) { | 1183 } else if (location.IsCall()) { |
| 1301 // If it's CallFunction stub ensure target function is compiled and flood | |
| 1302 // it with one shot breakpoints. | |
| 1303 bool is_call_ic = call_function_stub->kind() == Code::CALL_IC; | |
| 1304 | |
| 1305 // Find out number of arguments from the stub minor key. | |
| 1306 uint32_t key = call_function_stub->stub_key(); | |
| 1307 // Argc in the stub is the number of arguments passed - not the | |
| 1308 // expected arguments of the called function. | |
| 1309 int call_function_arg_count = is_call_ic | |
| 1310 ? CallICStub::ExtractArgcFromMinorKey(CodeStub::MinorKeyFromKey(key)) | |
| 1311 : CallFunctionStub::ExtractArgcFromMinorKey( | |
| 1312 CodeStub::MinorKeyFromKey(key)); | |
| 1313 | |
| 1314 DCHECK(is_call_ic || | |
| 1315 CodeStub::GetMajorKey(*call_function_stub) == | |
| 1316 CodeStub::MajorKeyFromKey(key)); | |
| 1317 | |
| 1318 // Find target function on the expression stack. | 1184 // Find target function on the expression stack. |
| 1319 // Expression stack looks like this (top to bottom): | 1185 // Expression stack looks like this (top to bottom): |
| 1320 // argN | 1186 // argN |
| 1321 // ... | 1187 // ... |
| 1322 // arg0 | 1188 // arg0 |
| 1323 // Receiver | 1189 // Receiver |
| 1324 // Function to call | 1190 // Function to call |
| 1325 int expressions_count = frame->ComputeExpressionsCount(); | 1191 int num_expressions_without_args = |
| 1326 DCHECK(expressions_count - 2 - call_function_arg_count >= 0); | 1192 frame->ComputeExpressionsCount() - location.CallArgumentsCount(); |
| 1327 Object* fun = frame->GetExpression( | 1193 DCHECK(num_expressions_without_args >= 2); |
| 1328 expressions_count - 2 - call_function_arg_count); | 1194 Object* fun = frame->GetExpression(num_expressions_without_args - 2); |
| 1329 | 1195 |
| 1330 // Flood the actual target of call/apply. | 1196 // Flood the actual target of call/apply. |
| 1331 if (fun->IsJSFunction()) { | 1197 if (fun->IsJSFunction()) { |
| 1332 Isolate* isolate = JSFunction::cast(fun)->GetIsolate(); | 1198 Isolate* isolate = JSFunction::cast(fun)->GetIsolate(); |
| 1333 Code* apply = isolate->builtins()->builtin(Builtins::kFunctionApply); | 1199 Code* apply = isolate->builtins()->builtin(Builtins::kFunctionApply); |
| 1334 Code* call = isolate->builtins()->builtin(Builtins::kFunctionCall); | 1200 Code* call = isolate->builtins()->builtin(Builtins::kFunctionCall); |
| 1335 // Find target function on the expression stack for expression like | 1201 // Find target function on the expression stack for expression like |
| 1336 // Function.call.call...apply(...) | 1202 // Function.call.call...apply(...) |
| 1337 int i = 1; | 1203 int i = 1; |
| 1338 while (fun->IsJSFunction()) { | 1204 while (fun->IsJSFunction()) { |
| 1339 Code* code = JSFunction::cast(fun)->shared()->code(); | 1205 Code* code = JSFunction::cast(fun)->shared()->code(); |
| 1340 if (code != apply && code != call) break; | 1206 if (code != apply && code != call) break; |
| 1341 DCHECK(expressions_count - i - call_function_arg_count >= 0); | 1207 DCHECK(num_expressions_without_args >= i); |
| 1342 fun = frame->GetExpression(expressions_count - i - | 1208 fun = frame->GetExpression(num_expressions_without_args - i); |
| 1343 call_function_arg_count); | 1209 i--; |
| 1344 i -= 1; | |
| 1345 } | 1210 } |
| 1346 } | 1211 } |
| 1347 | 1212 |
| 1348 if (fun->IsJSFunction()) { | 1213 if (fun->IsJSFunction()) { |
| 1349 Handle<JSFunction> js_function(JSFunction::cast(fun)); | 1214 Handle<JSFunction> js_function(JSFunction::cast(fun)); |
| 1350 FloodWithOneShotGeneric(js_function); | 1215 FloodWithOneShotGeneric(js_function); |
| 1351 } | 1216 } |
| 1352 } | 1217 } |
| 1353 | 1218 |
| 1354 ActivateStepIn(frame); | 1219 ActivateStepIn(frame); |
| (...skipping 847 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2202 } | 2067 } |
| 2203 | 2068 |
| 2204 // Move back to where the call instruction sequence started. | 2069 // Move back to where the call instruction sequence started. |
| 2205 after_break_target_ = addr - Assembler::kPatchReturnSequenceAddressOffset; | 2070 after_break_target_ = addr - Assembler::kPatchReturnSequenceAddressOffset; |
| 2206 } else if (at_debug_break_slot) { | 2071 } else if (at_debug_break_slot) { |
| 2207 // Address of where the debug break slot starts. | 2072 // Address of where the debug break slot starts. |
| 2208 addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset; | 2073 addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset; |
| 2209 | 2074 |
| 2210 // Continue just after the slot. | 2075 // Continue just after the slot. |
| 2211 after_break_target_ = addr + Assembler::kDebugBreakSlotLength; | 2076 after_break_target_ = addr + Assembler::kDebugBreakSlotLength; |
| 2212 } else { | |
| 2213 addr = Assembler::target_address_from_return_address(frame->pc()); | |
| 2214 if (IsDebugBreak(Assembler::target_address_at(addr, *code))) { | |
| 2215 // We now know that there is still a debug break call at the target | |
| 2216 // address, so the break point is still there and the original code will | |
| 2217 // hold the address to jump to in order to complete the call which is | |
| 2218 // replaced by a call to DebugBreakXXX. | |
| 2219 | |
| 2220 // Find the corresponding address in the original code. | |
| 2221 addr += original_code->instruction_start() - code->instruction_start(); | |
| 2222 | |
| 2223 // Install jump to the call address in the original code. This will be the | |
| 2224 // call which was overwritten by the call to DebugBreakXXX. | |
| 2225 after_break_target_ = Assembler::target_address_at(addr, *original_code); | |
| 2226 } else { | |
| 2227 // There is no longer a break point present. Don't try to look in the | |
| 2228 // original code as the running code will have the right address. This | |
| 2229 // takes care of the case where the last break point is removed from the | |
| 2230 // function and therefore no "original code" is available. | |
| 2231 after_break_target_ = Assembler::target_address_at(addr, *code); | |
| 2232 } | |
| 2233 } | 2077 } |
| 2234 } | 2078 } |
| 2235 | 2079 |
| 2236 | 2080 |
| 2237 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { | 2081 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { |
| 2238 HandleScope scope(isolate_); | 2082 HandleScope scope(isolate_); |
| 2239 | 2083 |
| 2240 // If there are no break points this cannot be break at return, as | 2084 // If there are no break points this cannot be break at return, as |
| 2241 // the debugger statement and stack guard debug break cannot be at | 2085 // the debugger statement and stack guard debug break cannot be at |
| 2242 // return. | 2086 // return. |
| (...skipping 1084 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3327 } | 3171 } |
| 3328 | 3172 |
| 3329 | 3173 |
| 3330 void LockingCommandMessageQueue::Clear() { | 3174 void LockingCommandMessageQueue::Clear() { |
| 3331 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 3175 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 3332 queue_.Clear(); | 3176 queue_.Clear(); |
| 3333 } | 3177 } |
| 3334 | 3178 |
| 3335 } // namespace internal | 3179 } // namespace internal |
| 3336 } // namespace v8 | 3180 } // namespace v8 |
| OLD | NEW |