| 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 831 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1251 // Get the debug info (create it if it does not exist). | 1222 // Get the debug info (create it if it does not exist). |
| 1252 Handle<JSFunction> function(summary.function()); | 1223 Handle<JSFunction> function(summary.function()); |
| 1253 Handle<SharedFunctionInfo> shared(function->shared()); | 1224 Handle<SharedFunctionInfo> shared(function->shared()); |
| 1254 if (!EnsureDebugInfo(shared, function)) { | 1225 if (!EnsureDebugInfo(shared, function)) { |
| 1255 // Return if ensuring debug info failed. | 1226 // Return if ensuring debug info failed. |
| 1256 return; | 1227 return; |
| 1257 } | 1228 } |
| 1258 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 1229 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
| 1259 | 1230 |
| 1260 // Compute whether or not the target is a call target. | 1231 // Compute whether or not the target is a call target. |
| 1261 bool is_load_or_store = false; | |
| 1262 bool is_inline_cache_stub = false; | |
| 1263 bool is_at_restarted_function = false; | 1232 bool is_at_restarted_function = false; |
| 1264 Handle<Code> call_function_stub; | 1233 Handle<Code> call_function_stub; |
| 1265 | 1234 |
| 1266 // PC points to the instruction after the current one, possibly a break | 1235 // PC points to the instruction after the current one, possibly a break |
| 1267 // location as well. So the "- 1" to exclude it from the search. | 1236 // location as well. So the "- 1" to exclude it from the search. |
| 1268 Address call_pc = summary.pc() - 1; | 1237 Address call_pc = summary.pc() - 1; |
| 1269 BreakLocation location = | 1238 BreakLocation location = |
| 1270 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); | 1239 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); |
| 1271 | 1240 |
| 1272 if (thread_local_.restarter_frame_function_pointer_ == NULL) { | 1241 if (thread_local_.restarter_frame_function_pointer_ == NULL) { |
| 1273 if (location.IsCodeTarget()) { | 1242 if (location.IsCodeTarget()) { |
| 1274 Handle<Code> target_code = location.CodeTarget(); | 1243 Handle<Code> target_code = location.CodeTarget(); |
| 1275 is_inline_cache_stub = target_code->is_inline_cache_stub(); | |
| 1276 is_load_or_store = is_inline_cache_stub && !target_code->is_call_stub(); | |
| 1277 | 1244 |
| 1278 // Check if target code is CallFunction stub. | 1245 // Check if target code is CallFunction stub. |
| 1279 Handle<Code> maybe_call_function_stub = target_code; | 1246 Handle<Code> maybe_call_function_stub = target_code; |
| 1280 // If there is a breakpoint at this line look at the original code to | 1247 // If there is a breakpoint at this line look at the original code to |
| 1281 // check if it is a CallFunction stub. | 1248 // check if it is a CallFunction stub. |
| 1282 if (location.IsDebugBreak()) { | 1249 if (location.IsDebugBreak()) { |
| 1283 maybe_call_function_stub = location.OriginalCodeTarget(); | 1250 maybe_call_function_stub = location.OriginalCodeTarget(); |
| 1284 } | 1251 } |
| 1285 if ((maybe_call_function_stub->kind() == Code::STUB && | 1252 if ((maybe_call_function_stub->kind() == Code::STUB && |
| 1286 CodeStub::GetMajorKey(*maybe_call_function_stub) == | 1253 CodeStub::GetMajorKey(*maybe_call_function_stub) == |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1313 } | 1280 } |
| 1314 // Step out: If there is a JavaScript caller frame, we need to | 1281 // Step out: If there is a JavaScript caller frame, we need to |
| 1315 // flood it with breakpoints. | 1282 // flood it with breakpoints. |
| 1316 if (!frames_it.done()) { | 1283 if (!frames_it.done()) { |
| 1317 // Fill the function to return to with one-shot break points. | 1284 // Fill the function to return to with one-shot break points. |
| 1318 JSFunction* function = frames_it.frame()->function(); | 1285 JSFunction* function = frames_it.frame()->function(); |
| 1319 FloodWithOneShot(Handle<JSFunction>(function)); | 1286 FloodWithOneShot(Handle<JSFunction>(function)); |
| 1320 // Set target frame pointer. | 1287 // Set target frame pointer. |
| 1321 ActivateStepOut(frames_it.frame()); | 1288 ActivateStepOut(frames_it.frame()); |
| 1322 } | 1289 } |
| 1323 } else if (!(is_inline_cache_stub || location.IsConstructCall() || | 1290 return; |
| 1324 !call_function_stub.is_null() || is_at_restarted_function) || | 1291 } |
| 1325 step_action == StepNext || step_action == StepMin) { | |
| 1326 // Step next or step min. | |
| 1327 | 1292 |
| 1328 // Fill the current function with one-shot break points. | 1293 if (step_action != StepNext && step_action != StepMin) { |
| 1329 // If we are stepping into another frame, only fill calls and returns. | |
| 1330 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS | |
| 1331 : ALL_BREAK_LOCATIONS); | |
| 1332 | |
| 1333 // Remember source position and frame to handle step next. | |
| 1334 thread_local_.last_statement_position_ = | |
| 1335 debug_info->code()->SourceStatementPosition(summary.pc()); | |
| 1336 thread_local_.last_fp_ = frame->UnpaddedFP(); | |
| 1337 } else { | |
| 1338 // If there's restarter frame on top of the stack, just get the pointer | 1294 // If there's restarter frame on top of the stack, just get the pointer |
| 1339 // to function which is going to be restarted. | 1295 // to function which is going to be restarted. |
| 1340 if (is_at_restarted_function) { | 1296 if (is_at_restarted_function) { |
| 1341 Handle<JSFunction> restarted_function( | 1297 Handle<JSFunction> restarted_function( |
| 1342 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_)); | 1298 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_)); |
| 1343 FloodWithOneShot(restarted_function); | 1299 FloodWithOneShot(restarted_function); |
| 1344 } else if (!call_function_stub.is_null()) { | 1300 } else if (!call_function_stub.is_null()) { |
| 1345 // If it's CallFunction stub ensure target function is compiled and flood | 1301 // If it's CallFunction stub ensure target function is compiled and flood |
| 1346 // it with one shot breakpoints. | 1302 // it with one shot breakpoints. |
| 1347 bool is_call_ic = call_function_stub->kind() == Code::CALL_IC; | 1303 bool is_call_ic = call_function_stub->kind() == Code::CALL_IC; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 i -= 1; | 1344 i -= 1; |
| 1389 } | 1345 } |
| 1390 } | 1346 } |
| 1391 | 1347 |
| 1392 if (fun->IsJSFunction()) { | 1348 if (fun->IsJSFunction()) { |
| 1393 Handle<JSFunction> js_function(JSFunction::cast(fun)); | 1349 Handle<JSFunction> js_function(JSFunction::cast(fun)); |
| 1394 FloodWithOneShotGeneric(js_function); | 1350 FloodWithOneShotGeneric(js_function); |
| 1395 } | 1351 } |
| 1396 } | 1352 } |
| 1397 | 1353 |
| 1398 // Fill the current function with one-shot break points even for step in on | |
| 1399 // a call target as the function called might be a native function for | |
| 1400 // which step in will not stop. It also prepares for stepping in | |
| 1401 // getters/setters. | |
| 1402 // If we are stepping into another frame, only fill calls and returns. | |
| 1403 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS | |
| 1404 : ALL_BREAK_LOCATIONS); | |
| 1405 | |
| 1406 if (is_load_or_store) { | |
| 1407 // Remember source position and frame to handle step in getter/setter. If | |
| 1408 // there is a custom getter/setter it will be handled in | |
| 1409 // Object::Get/SetPropertyWithAccessor, otherwise the step action will be | |
| 1410 // propagated on the next Debug::Break. | |
| 1411 thread_local_.last_statement_position_ = | |
| 1412 debug_info->code()->SourceStatementPosition(summary.pc()); | |
| 1413 thread_local_.last_fp_ = frame->UnpaddedFP(); | |
| 1414 } | |
| 1415 | |
| 1416 // Step in or Step in min | |
| 1417 // Step in through construct call requires no changes to the running code. | |
| 1418 // Step in through getters/setters should already be prepared as well | |
| 1419 // because caller of this function (Debug::PrepareStep) is expected to | |
| 1420 // flood the top frame's function with one shot breakpoints. | |
| 1421 // Step in through CallFunction stub should also be prepared by caller of | |
| 1422 // this function (Debug::PrepareStep) which should flood target function | |
| 1423 // with breakpoints. | |
| 1424 DCHECK(location.IsConstructCall() || is_inline_cache_stub || | |
| 1425 !call_function_stub.is_null() || is_at_restarted_function); | |
| 1426 ActivateStepIn(frame); | 1354 ActivateStepIn(frame); |
| 1427 } | 1355 } |
| 1356 |
| 1357 // Fill the current function with one-shot break points even for step in on |
| 1358 // a call target as the function called might be a native function for |
| 1359 // which step in will not stop. It also prepares for stepping in |
| 1360 // getters/setters. |
| 1361 // If we are stepping into another frame, only fill calls and returns. |
| 1362 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS |
| 1363 : ALL_BREAK_LOCATIONS); |
| 1364 |
| 1365 // Remember source position and frame to handle step next. |
| 1366 thread_local_.last_statement_position_ = |
| 1367 debug_info->code()->SourceStatementPosition(summary.pc()); |
| 1368 thread_local_.last_fp_ = frame->UnpaddedFP(); |
| 1428 } | 1369 } |
| 1429 | 1370 |
| 1430 | 1371 |
| 1431 // Check whether the current debug break should be reported to the debugger. It | 1372 // Check whether the current debug break should be reported to the debugger. It |
| 1432 // is used to have step next and step in only report break back to the debugger | 1373 // is used to have step next and step in only report break back to the debugger |
| 1433 // if on a different frame or in a different statement. In some situations | 1374 // if on a different frame or in a different statement. In some situations |
| 1434 // there will be several break points in the same statement when the code is | 1375 // there will be several break points in the same statement when the code is |
| 1435 // flooded with one-shot break points. This function helps to perform several | 1376 // flooded with one-shot break points. This function helps to perform several |
| 1436 // steps before reporting break back to the debugger. | 1377 // steps before reporting break back to the debugger. |
| 1437 bool Debug::StepNextContinue(BreakLocation* break_location, | 1378 bool Debug::StepNextContinue(BreakLocation* break_location, |
| (...skipping 1950 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3388 } | 3329 } |
| 3389 | 3330 |
| 3390 | 3331 |
| 3391 void LockingCommandMessageQueue::Clear() { | 3332 void LockingCommandMessageQueue::Clear() { |
| 3392 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 3333 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 3393 queue_.Clear(); | 3334 queue_.Clear(); |
| 3394 } | 3335 } |
| 3395 | 3336 |
| 3396 } // namespace internal | 3337 } // namespace internal |
| 3397 } // namespace v8 | 3338 } // namespace v8 |
| OLD | NEW |