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 |