Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: src/debug.cc

Issue 1218493005: Debugger: use debug break slots instead of ICs (except for calls). (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: minor fixes Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698