| 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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 BreakLocatorType type) | 77 BreakLocatorType type) |
| 78 : debug_info_(debug_info), | 78 : debug_info_(debug_info), |
| 79 type_(type), | 79 type_(type), |
| 80 reloc_iterator_(debug_info->code(), | 80 reloc_iterator_(debug_info->code(), |
| 81 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)), | 81 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)), |
| 82 reloc_iterator_original_( | 82 reloc_iterator_original_( |
| 83 debug_info->original_code(), | 83 debug_info->original_code(), |
| 84 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)), | 84 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)), |
| 85 break_index_(-1), | 85 break_index_(-1), |
| 86 position_(1), | 86 position_(1), |
| 87 statement_position_(1), | 87 statement_position_(1) { |
| 88 has_immediate_position_(false) { | |
| 89 Next(); | 88 Next(); |
| 90 } | 89 } |
| 91 | 90 |
| 92 | 91 |
| 93 void BreakLocation::Iterator::Next() { | 92 void BreakLocation::Iterator::Next() { |
| 94 DisallowHeapAllocation no_gc; | 93 DisallowHeapAllocation no_gc; |
| 95 DCHECK(!RinfoDone()); | 94 DCHECK(!RinfoDone()); |
| 96 | 95 |
| 97 // Iterate through reloc info for code and original code stopping at each | 96 // Iterate through reloc info for code and original code stopping at each |
| 98 // breakable code target. | 97 // breakable code target. |
| 99 bool first = break_index_ == -1; | 98 bool first = break_index_ == -1; |
| 100 while (!RinfoDone()) { | 99 while (!RinfoDone()) { |
| 101 if (!first) RinfoNext(); | 100 if (!first) RinfoNext(); |
| 102 first = false; | 101 first = false; |
| 103 if (RinfoDone()) return; | 102 if (RinfoDone()) return; |
| 104 | 103 |
| 105 // Whenever a statement position or (plain) position is passed update the | 104 // Whenever a statement position or (plain) position is passed update the |
| 106 // current value of these. | 105 // current value of these. |
| 107 if (RelocInfo::IsPosition(rmode())) { | 106 if (RelocInfo::IsPosition(rmode())) { |
| 108 if (RelocInfo::IsStatementPosition(rmode())) { | 107 if (RelocInfo::IsStatementPosition(rmode())) { |
| 109 statement_position_ = static_cast<int>( | 108 statement_position_ = static_cast<int>( |
| 110 rinfo()->data() - debug_info_->shared()->start_position()); | 109 rinfo()->data() - debug_info_->shared()->start_position()); |
| 111 } | 110 } |
| 112 // 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 |
| 113 // statement position. | 112 // statement position. |
| 114 position_ = static_cast<int>(rinfo()->data() - | 113 position_ = static_cast<int>(rinfo()->data() - |
| 115 debug_info_->shared()->start_position()); | 114 debug_info_->shared()->start_position()); |
| 116 DCHECK(position_ >= 0); | 115 DCHECK(position_ >= 0); |
| 117 DCHECK(statement_position_ >= 0); | 116 DCHECK(statement_position_ >= 0); |
| 118 has_immediate_position_ = true; | |
| 119 continue; | 117 continue; |
| 120 } | 118 } |
| 121 | 119 |
| 122 // Check for break at return. | 120 // Check for break at return. |
| 123 if (RelocInfo::IsJSReturn(rmode())) { | 121 if (RelocInfo::IsJSReturn(rmode())) { |
| 124 // Set the positions to the end of the function. | 122 // Set the positions to the end of the function. |
| 125 if (debug_info_->shared()->HasSourceCode()) { | 123 if (debug_info_->shared()->HasSourceCode()) { |
| 126 position_ = debug_info_->shared()->end_position() - | 124 position_ = debug_info_->shared()->end_position() - |
| 127 debug_info_->shared()->start_position() - 1; | 125 debug_info_->shared()->start_position() - 1; |
| 128 } else { | 126 } else { |
| 129 position_ = 0; | 127 position_ = 0; |
| 130 } | 128 } |
| 131 statement_position_ = position_; | 129 statement_position_ = position_; |
| 132 break_index_++; | 130 break_index_++; |
| 133 break; | 131 break; |
| 134 } | 132 } |
| 135 | 133 |
| 136 if (RelocInfo::IsCodeTarget(rmode())) { | 134 if (RelocInfo::IsCodeTarget(rmode())) { |
| 137 // Check for breakable code target. Look in the original code as setting | 135 // Check for breakable code target. Look in the original code as setting |
| 138 // break points can cause the code targets in the running (debugged) code | 136 // break points can cause the code targets in the running (debugged) code |
| 139 // to be of a different kind than in the original code. | 137 // to be of a different kind than in the original code. |
| 140 Address target = original_rinfo()->target_address(); | 138 Address target = original_rinfo()->target_address(); |
| 141 Code* code = Code::GetCodeFromTargetAddress(target); | 139 Code* code = Code::GetCodeFromTargetAddress(target); |
| 142 | 140 |
| 143 if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) { | 141 if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) { |
| 144 break_index_++; | 142 break_index_++; |
| 145 break; | 143 break; |
| 146 } | 144 } |
| 147 | 145 |
| 148 // Skip below if we only want locations for calls and returns. | 146 if (code->kind() == Code::STUB && |
| 149 if (type_ == CALLS_AND_RETURNS) continue; | 147 CodeStub::GetMajorKey(code) == CodeStub::CallFunction) { |
| 150 | |
| 151 // Only break at an inline cache if it has an immediate position attached. | |
| 152 if (has_immediate_position_ && | |
| 153 (code->is_inline_cache_stub() && !code->is_binary_op_stub() && | |
| 154 !code->is_compare_ic_stub() && !code->is_to_boolean_ic_stub())) { | |
| 155 break_index_++; | 148 break_index_++; |
| 156 break; | 149 break; |
| 157 } | 150 } |
| 158 if (code->kind() == Code::STUB) { | 151 } |
| 159 if (RelocInfo::IsDebuggerStatement(rmode())) { | 152 |
| 160 break_index_++; | 153 // Skip below if we only want locations for calls and returns. |
| 161 break; | 154 if (type_ == CALLS_AND_RETURNS) continue; |
| 162 } else if (CodeStub::GetMajorKey(code) == CodeStub::CallFunction) { | 155 |
| 163 break_index_++; | 156 if (RelocInfo::IsDebuggerStatement(rmode())) { |
| 164 break; | 157 break_index_++; |
| 165 } | 158 break; |
| 166 } | |
| 167 } | 159 } |
| 168 | 160 |
| 169 if (RelocInfo::IsDebugBreakSlot(rmode()) && type_ != CALLS_AND_RETURNS) { | 161 if (RelocInfo::IsDebugBreakSlot(rmode()) && type_ != CALLS_AND_RETURNS) { |
| 170 // There is always a possible break point at a debug break slot. | 162 // There is always a possible break point at a debug break slot. |
| 171 break_index_++; | 163 break_index_++; |
| 172 break; | 164 break; |
| 173 } | 165 } |
| 174 } | 166 } |
| 175 has_immediate_position_ = false; | |
| 176 } | 167 } |
| 177 | 168 |
| 178 | 169 |
| 179 // Find the break point at the supplied address, or the closest one before | 170 // Find the break point at the supplied address, or the closest one before |
| 180 // the address. | 171 // the address. |
| 181 BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, | 172 BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, |
| 182 BreakLocatorType type, Address pc) { | 173 BreakLocatorType type, Address pc) { |
| 183 Iterator it(debug_info, type); | 174 Iterator it(debug_info, type); |
| 184 it.SkipTo(BreakIndexFromAddress(debug_info, type, pc)); | 175 it.SkipTo(BreakIndexFromAddress(debug_info, type, pc)); |
| 185 return it.GetBreakLocation(); | 176 return it.GetBreakLocation(); |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 } | 369 } |
| 379 | 370 |
| 380 | 371 |
| 381 // Find the builtin to use for invoking the debug break | 372 // Find the builtin to use for invoking the debug break |
| 382 static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) { | 373 static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) { |
| 383 Isolate* isolate = code->GetIsolate(); | 374 Isolate* isolate = code->GetIsolate(); |
| 384 | 375 |
| 385 // Find the builtin debug break function matching the calling convention | 376 // Find the builtin debug break function matching the calling convention |
| 386 // used by the call site. | 377 // used by the call site. |
| 387 if (code->is_inline_cache_stub()) { | 378 if (code->is_inline_cache_stub()) { |
| 388 switch (code->kind()) { | 379 DCHECK(code->kind() == Code::CALL_IC); |
| 389 case Code::CALL_IC: | 380 return isolate->builtins()->CallICStub_DebugBreak(); |
| 390 return isolate->builtins()->CallICStub_DebugBreak(); | |
| 391 | |
| 392 case Code::LOAD_IC: | |
| 393 return isolate->builtins()->LoadIC_DebugBreak(); | |
| 394 | |
| 395 case Code::STORE_IC: | |
| 396 return isolate->builtins()->StoreIC_DebugBreak(); | |
| 397 | |
| 398 case Code::KEYED_LOAD_IC: | |
| 399 return isolate->builtins()->KeyedLoadIC_DebugBreak(); | |
| 400 | |
| 401 case Code::KEYED_STORE_IC: | |
| 402 return isolate->builtins()->KeyedStoreIC_DebugBreak(); | |
| 403 | |
| 404 case Code::COMPARE_NIL_IC: | |
| 405 return isolate->builtins()->CompareNilIC_DebugBreak(); | |
| 406 | |
| 407 default: | |
| 408 UNREACHABLE(); | |
| 409 } | |
| 410 } | 381 } |
| 411 if (RelocInfo::IsConstructCall(mode)) { | 382 if (RelocInfo::IsConstructCall(mode)) { |
| 412 if (code->has_function_cache()) { | 383 if (code->has_function_cache()) { |
| 413 return isolate->builtins()->CallConstructStub_Recording_DebugBreak(); | 384 return isolate->builtins()->CallConstructStub_Recording_DebugBreak(); |
| 414 } else { | 385 } else { |
| 415 return isolate->builtins()->CallConstructStub_DebugBreak(); | 386 return isolate->builtins()->CallConstructStub_DebugBreak(); |
| 416 } | 387 } |
| 417 } | 388 } |
| 418 if (code->kind() == Code::STUB) { | 389 if (code->kind() == Code::STUB) { |
| 419 DCHECK(CodeStub::GetMajorKey(*code) == CodeStub::CallFunction); | 390 DCHECK(CodeStub::GetMajorKey(*code) == CodeStub::CallFunction); |
| (...skipping 833 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1253 // Get the debug info (create it if it does not exist). | 1224 // Get the debug info (create it if it does not exist). |
| 1254 Handle<JSFunction> function(summary.function()); | 1225 Handle<JSFunction> function(summary.function()); |
| 1255 Handle<SharedFunctionInfo> shared(function->shared()); | 1226 Handle<SharedFunctionInfo> shared(function->shared()); |
| 1256 if (!EnsureDebugInfo(shared, function)) { | 1227 if (!EnsureDebugInfo(shared, function)) { |
| 1257 // Return if ensuring debug info failed. | 1228 // Return if ensuring debug info failed. |
| 1258 return; | 1229 return; |
| 1259 } | 1230 } |
| 1260 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 1231 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
| 1261 | 1232 |
| 1262 // Compute whether or not the target is a call target. | 1233 // Compute whether or not the target is a call target. |
| 1263 bool is_load_or_store = false; | |
| 1264 bool is_inline_cache_stub = false; | |
| 1265 bool is_at_restarted_function = false; | 1234 bool is_at_restarted_function = false; |
| 1266 Handle<Code> call_function_stub; | 1235 Handle<Code> call_function_stub; |
| 1267 | 1236 |
| 1268 // PC points to the instruction after the current one, possibly a break | 1237 // PC points to the instruction after the current one, possibly a break |
| 1269 // location as well. So the "- 1" to exclude it from the search. | 1238 // location as well. So the "- 1" to exclude it from the search. |
| 1270 Address call_pc = summary.pc() - 1; | 1239 Address call_pc = summary.pc() - 1; |
| 1271 BreakLocation location = | 1240 BreakLocation location = |
| 1272 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); | 1241 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); |
| 1273 | 1242 |
| 1274 if (thread_local_.restarter_frame_function_pointer_ == NULL) { | 1243 if (thread_local_.restarter_frame_function_pointer_ == NULL) { |
| 1275 if (location.IsCodeTarget()) { | 1244 if (location.IsCodeTarget()) { |
| 1276 Handle<Code> target_code = location.CodeTarget(); | 1245 Handle<Code> target_code = location.CodeTarget(); |
| 1277 is_inline_cache_stub = target_code->is_inline_cache_stub(); | |
| 1278 is_load_or_store = is_inline_cache_stub && !target_code->is_call_stub(); | |
| 1279 | 1246 |
| 1280 // Check if target code is CallFunction stub. | 1247 // Check if target code is CallFunction stub. |
| 1281 Handle<Code> maybe_call_function_stub = target_code; | 1248 Handle<Code> maybe_call_function_stub = target_code; |
| 1282 // If there is a breakpoint at this line look at the original code to | 1249 // If there is a breakpoint at this line look at the original code to |
| 1283 // check if it is a CallFunction stub. | 1250 // check if it is a CallFunction stub. |
| 1284 if (location.IsDebugBreak()) { | 1251 if (location.IsDebugBreak()) { |
| 1285 maybe_call_function_stub = location.OriginalCodeTarget(); | 1252 maybe_call_function_stub = location.OriginalCodeTarget(); |
| 1286 } | 1253 } |
| 1287 if ((maybe_call_function_stub->kind() == Code::STUB && | 1254 if ((maybe_call_function_stub->kind() == Code::STUB && |
| 1288 CodeStub::GetMajorKey(*maybe_call_function_stub) == | 1255 CodeStub::GetMajorKey(*maybe_call_function_stub) == |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1315 } | 1282 } |
| 1316 // Step out: If there is a JavaScript caller frame, we need to | 1283 // Step out: If there is a JavaScript caller frame, we need to |
| 1317 // flood it with breakpoints. | 1284 // flood it with breakpoints. |
| 1318 if (!frames_it.done()) { | 1285 if (!frames_it.done()) { |
| 1319 // Fill the function to return to with one-shot break points. | 1286 // Fill the function to return to with one-shot break points. |
| 1320 JSFunction* function = frames_it.frame()->function(); | 1287 JSFunction* function = frames_it.frame()->function(); |
| 1321 FloodWithOneShot(Handle<JSFunction>(function)); | 1288 FloodWithOneShot(Handle<JSFunction>(function)); |
| 1322 // Set target frame pointer. | 1289 // Set target frame pointer. |
| 1323 ActivateStepOut(frames_it.frame()); | 1290 ActivateStepOut(frames_it.frame()); |
| 1324 } | 1291 } |
| 1325 } else if (!(is_inline_cache_stub || location.IsConstructCall() || | 1292 return; |
| 1326 !call_function_stub.is_null() || is_at_restarted_function) || | 1293 } |
| 1327 step_action == StepNext || step_action == StepMin) { | |
| 1328 // Step next or step min. | |
| 1329 | 1294 |
| 1330 // Fill the current function with one-shot break points. | 1295 if (step_action != StepNext && step_action != StepMin) { |
| 1331 // If we are stepping into another frame, only fill calls and returns. | |
| 1332 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS | |
| 1333 : ALL_BREAK_LOCATIONS); | |
| 1334 | |
| 1335 // Remember source position and frame to handle step next. | |
| 1336 thread_local_.last_statement_position_ = | |
| 1337 debug_info->code()->SourceStatementPosition(summary.pc()); | |
| 1338 thread_local_.last_fp_ = frame->UnpaddedFP(); | |
| 1339 } else { | |
| 1340 // If there's restarter frame on top of the stack, just get the pointer | 1296 // If there's restarter frame on top of the stack, just get the pointer |
| 1341 // to function which is going to be restarted. | 1297 // to function which is going to be restarted. |
| 1342 if (is_at_restarted_function) { | 1298 if (is_at_restarted_function) { |
| 1343 Handle<JSFunction> restarted_function( | 1299 Handle<JSFunction> restarted_function( |
| 1344 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_)); | 1300 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_)); |
| 1345 FloodWithOneShot(restarted_function); | 1301 FloodWithOneShot(restarted_function); |
| 1346 } else if (!call_function_stub.is_null()) { | 1302 } else if (!call_function_stub.is_null()) { |
| 1347 // If it's CallFunction stub ensure target function is compiled and flood | 1303 // If it's CallFunction stub ensure target function is compiled and flood |
| 1348 // it with one shot breakpoints. | 1304 // it with one shot breakpoints. |
| 1349 bool is_call_ic = call_function_stub->kind() == Code::CALL_IC; | 1305 bool is_call_ic = call_function_stub->kind() == Code::CALL_IC; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1390 i -= 1; | 1346 i -= 1; |
| 1391 } | 1347 } |
| 1392 } | 1348 } |
| 1393 | 1349 |
| 1394 if (fun->IsJSFunction()) { | 1350 if (fun->IsJSFunction()) { |
| 1395 Handle<JSFunction> js_function(JSFunction::cast(fun)); | 1351 Handle<JSFunction> js_function(JSFunction::cast(fun)); |
| 1396 FloodWithOneShotGeneric(js_function); | 1352 FloodWithOneShotGeneric(js_function); |
| 1397 } | 1353 } |
| 1398 } | 1354 } |
| 1399 | 1355 |
| 1400 // Fill the current function with one-shot break points even for step in on | |
| 1401 // a call target as the function called might be a native function for | |
| 1402 // which step in will not stop. It also prepares for stepping in | |
| 1403 // getters/setters. | |
| 1404 // If we are stepping into another frame, only fill calls and returns. | |
| 1405 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS | |
| 1406 : ALL_BREAK_LOCATIONS); | |
| 1407 | |
| 1408 if (is_load_or_store) { | |
| 1409 // Remember source position and frame to handle step in getter/setter. If | |
| 1410 // there is a custom getter/setter it will be handled in | |
| 1411 // Object::Get/SetPropertyWithAccessor, otherwise the step action will be | |
| 1412 // propagated on the next Debug::Break. | |
| 1413 thread_local_.last_statement_position_ = | |
| 1414 debug_info->code()->SourceStatementPosition(summary.pc()); | |
| 1415 thread_local_.last_fp_ = frame->UnpaddedFP(); | |
| 1416 } | |
| 1417 | |
| 1418 // Step in or Step in min | |
| 1419 // Step in through construct call requires no changes to the running code. | |
| 1420 // Step in through getters/setters should already be prepared as well | |
| 1421 // because caller of this function (Debug::PrepareStep) is expected to | |
| 1422 // flood the top frame's function with one shot breakpoints. | |
| 1423 // Step in through CallFunction stub should also be prepared by caller of | |
| 1424 // this function (Debug::PrepareStep) which should flood target function | |
| 1425 // with breakpoints. | |
| 1426 DCHECK(location.IsConstructCall() || is_inline_cache_stub || | |
| 1427 !call_function_stub.is_null() || is_at_restarted_function); | |
| 1428 ActivateStepIn(frame); | 1356 ActivateStepIn(frame); |
| 1429 } | 1357 } |
| 1358 |
| 1359 // Fill the current function with one-shot break points even for step in on |
| 1360 // a call target as the function called might be a native function for |
| 1361 // which step in will not stop. It also prepares for stepping in |
| 1362 // getters/setters. |
| 1363 // If we are stepping into another frame, only fill calls and returns. |
| 1364 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS |
| 1365 : ALL_BREAK_LOCATIONS); |
| 1366 |
| 1367 // Remember source position and frame to handle step next. |
| 1368 thread_local_.last_statement_position_ = |
| 1369 debug_info->code()->SourceStatementPosition(summary.pc()); |
| 1370 thread_local_.last_fp_ = frame->UnpaddedFP(); |
| 1430 } | 1371 } |
| 1431 | 1372 |
| 1432 | 1373 |
| 1433 // Check whether the current debug break should be reported to the debugger. It | 1374 // Check whether the current debug break should be reported to the debugger. It |
| 1434 // is used to have step next and step in only report break back to the debugger | 1375 // is used to have step next and step in only report break back to the debugger |
| 1435 // if on a different frame or in a different statement. In some situations | 1376 // if on a different frame or in a different statement. In some situations |
| 1436 // there will be several break points in the same statement when the code is | 1377 // there will be several break points in the same statement when the code is |
| 1437 // flooded with one-shot break points. This function helps to perform several | 1378 // flooded with one-shot break points. This function helps to perform several |
| 1438 // steps before reporting break back to the debugger. | 1379 // steps before reporting break back to the debugger. |
| 1439 bool Debug::StepNextContinue(BreakLocation* break_location, | 1380 bool Debug::StepNextContinue(BreakLocation* break_location, |
| (...skipping 1950 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3390 } | 3331 } |
| 3391 | 3332 |
| 3392 | 3333 |
| 3393 void LockingCommandMessageQueue::Clear() { | 3334 void LockingCommandMessageQueue::Clear() { |
| 3394 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 3335 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 3395 queue_.Clear(); | 3336 queue_.Clear(); |
| 3396 } | 3337 } |
| 3397 | 3338 |
| 3398 } // namespace internal | 3339 } // namespace internal |
| 3399 } // namespace v8 | 3340 } // namespace v8 |
| OLD | NEW |