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

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: addressed comments 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
« no previous file with comments | « src/debug.h ('k') | src/full-codegen.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 831 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
OLDNEW
« no previous file with comments | « src/debug.h ('k') | src/full-codegen.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698