Chromium Code Reviews| 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/debug/debug.h" | 5 #include "src/debug/debug.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "src/api.h" | 9 #include "src/api.h" |
| 10 #include "src/arguments.h" | 10 #include "src/arguments.h" |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 #include "src/messages.h" | 26 #include "src/messages.h" |
| 27 #include "src/snapshot/natives.h" | 27 #include "src/snapshot/natives.h" |
| 28 #include "src/wasm/wasm-debug.h" | 28 #include "src/wasm/wasm-debug.h" |
| 29 #include "src/wasm/wasm-module.h" | 29 #include "src/wasm/wasm-module.h" |
| 30 | 30 |
| 31 #include "include/v8-debug.h" | 31 #include "include/v8-debug.h" |
| 32 | 32 |
| 33 namespace v8 { | 33 namespace v8 { |
| 34 namespace internal { | 34 namespace internal { |
| 35 | 35 |
| 36 namespace { | |
| 37 | |
| 38 inline int CallOffsetFromCodeOffset(int code_offset, bool is_interpreted) { | |
| 39 // Code offset points to the instruction after the call. Subtract 1 to | |
| 40 // exclude that instruction from the search. For bytecode, the code offset | |
| 41 // still points to the call. | |
| 42 return is_interpreted ? code_offset : code_offset - 1; | |
| 43 } | |
| 44 | |
| 45 } // namespace | |
| 46 | |
| 47 Debug::Debug(Isolate* isolate) | 36 Debug::Debug(Isolate* isolate) |
| 48 : debug_context_(Handle<Context>()), | 37 : debug_context_(Handle<Context>()), |
| 49 event_listener_(Handle<Object>()), | 38 event_listener_(Handle<Object>()), |
| 50 event_listener_data_(Handle<Object>()), | 39 event_listener_data_(Handle<Object>()), |
| 51 message_handler_(NULL), | 40 message_handler_(NULL), |
| 52 command_received_(0), | 41 command_received_(0), |
| 53 command_queue_(isolate->logger(), kQueueInitialSize), | 42 command_queue_(isolate->logger(), kQueueInitialSize), |
| 54 is_active_(false), | 43 is_active_(false), |
| 55 is_suppressed_(false), | 44 is_suppressed_(false), |
| 56 live_edit_enabled_(true), // TODO(yangguo): set to false by default. | 45 live_edit_enabled_(true), // TODO(yangguo): set to false by default. |
| 57 break_disabled_(false), | 46 break_disabled_(false), |
| 58 break_points_active_(true), | 47 break_points_active_(true), |
| 59 in_debug_event_listener_(false), | 48 in_debug_event_listener_(false), |
| 60 break_on_exception_(false), | 49 break_on_exception_(false), |
| 61 break_on_uncaught_exception_(false), | 50 break_on_uncaught_exception_(false), |
| 62 debug_info_list_(NULL), | 51 debug_info_list_(NULL), |
| 63 feature_tracker_(isolate), | 52 feature_tracker_(isolate), |
| 64 isolate_(isolate) { | 53 isolate_(isolate) { |
| 65 ThreadInit(); | 54 ThreadInit(); |
| 66 } | 55 } |
| 67 | 56 |
| 68 | 57 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, |
| 69 static v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) { | 58 JavaScriptFrame* frame) { |
| 70 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); | 59 FrameSummary summary = FrameSummary::GetFirst(frame); |
| 71 // Isolate::context() may have been NULL when "script collected" event | 60 int offset = summary.code_offset(); |
| 72 // occured. | 61 Handle<AbstractCode> abstract_code = summary.abstract_code(); |
| 73 if (context.is_null()) return v8::Local<v8::Context>(); | 62 if (abstract_code->IsCode()) offset = offset - 1; |
| 74 Handle<Context> native_context(context->native_context()); | 63 auto it = BreakIterator::GetIterator(debug_info, abstract_code); |
| 75 return v8::Utils::ToLocal(native_context); | 64 it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset)); |
| 65 return it->GetBreakLocation(); | |
| 76 } | 66 } |
| 77 | 67 |
| 78 BreakLocation::BreakLocation(Handle<DebugInfo> debug_info, DebugBreakType type, | 68 void BreakLocation::AllAtCurrentStatement(Handle<DebugInfo> debug_info, |
| 79 int code_offset, int position, | 69 JavaScriptFrame* frame, |
| 80 int statement_position) | 70 List<BreakLocation>* result_out) { |
| 81 : debug_info_(debug_info), | 71 FrameSummary summary = FrameSummary::GetFirst(frame); |
| 82 code_offset_(code_offset), | 72 int offset = summary.code_offset(); |
| 83 type_(type), | 73 Handle<AbstractCode> abstract_code = summary.abstract_code(); |
| 84 position_(position), | 74 if (abstract_code->IsCode()) offset = offset - 1; |
| 85 statement_position_(statement_position) {} | 75 int statement_position; |
| 86 | 76 { |
| 87 BreakLocation::Iterator* BreakLocation::GetIterator( | 77 auto it = BreakIterator::GetIterator(debug_info, abstract_code); |
| 88 Handle<DebugInfo> debug_info, BreakLocatorType type) { | 78 it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset)); |
| 89 if (debug_info->abstract_code()->IsBytecodeArray()) { | 79 statement_position = it->statement_position(); |
| 90 return new BytecodeArrayIterator(debug_info, type); | 80 } |
| 91 } else { | 81 for (auto it = BreakIterator::GetIterator(debug_info, abstract_code); |
| 92 return new CodeIterator(debug_info, type); | 82 !it->Done(); it->Next()) { |
| 83 if (it->statement_position() == statement_position) { | |
| 84 result_out->Add(it->GetBreakLocation()); | |
| 85 } | |
| 93 } | 86 } |
| 94 } | 87 } |
| 95 | 88 |
| 96 BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info) | 89 int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info, |
| 97 : debug_info_(debug_info), break_index_(-1) { | 90 Handle<AbstractCode> abstract_code, |
| 91 int offset) { | |
| 92 // Run through all break points to locate the one closest to the address. | |
| 93 int closest_break = 0; | |
| 94 int distance = kMaxInt; | |
| 95 DCHECK(0 <= offset && offset < abstract_code->Size()); | |
| 96 for (auto it = BreakIterator::GetIterator(debug_info, abstract_code); | |
| 97 !it->Done(); it->Next()) { | |
| 98 // Check if this break point is closer that what was previously found. | |
| 99 if (it->code_offset() <= offset && offset - it->code_offset() < distance) { | |
| 100 closest_break = it->break_index(); | |
| 101 distance = offset - it->code_offset(); | |
| 102 // Check whether we can't get any closer. | |
| 103 if (distance == 0) break; | |
| 104 } | |
| 105 } | |
| 106 return closest_break; | |
| 107 } | |
| 108 | |
| 109 bool BreakLocation::HasBreakPoint(Handle<DebugInfo> debug_info) const { | |
| 110 // First check whether there is a break point with the same source position. | |
| 111 if (!debug_info->HasBreakPoint(position_)) return false; | |
| 112 // Then check whether a break point at that source position would have | |
| 113 // the same code offset. Otherwise it's just a break location that we can | |
| 114 // step to, but not actually a location where we can put a break point. | |
| 115 if (abstract_code_->IsCode()) { | |
| 116 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | |
| 117 it.SkipToPosition(position_, BREAK_POSITION_ALIGNED); | |
| 118 return it.code_offset() == code_offset_; | |
| 119 } else { | |
|
jgruber
2016/08/11 14:28:13
Is abstract_code_->IsByteCodeArray() at this point
Yang
2016/08/12 05:33:46
Done. Not sure what kind of DCHECKs you had in min
| |
| 120 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | |
| 121 it.SkipToPosition(position_, BREAK_POSITION_ALIGNED); | |
| 122 return it.code_offset() == code_offset_; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 std::unique_ptr<BreakIterator> BreakIterator::GetIterator( | |
| 127 Handle<DebugInfo> debug_info, Handle<AbstractCode> abstract_code, | |
| 128 BreakLocatorType type) { | |
| 129 if (abstract_code->IsBytecodeArray()) { | |
| 130 DCHECK(debug_info->HasDebugBytecodeArray()); | |
| 131 return std::unique_ptr<BreakIterator>( | |
| 132 new BytecodeArrayBreakIterator(debug_info, type)); | |
| 133 } else { | |
| 134 DCHECK(abstract_code->IsCode()); | |
| 135 DCHECK(debug_info->HasDebugCode()); | |
| 136 return std::unique_ptr<BreakIterator>( | |
| 137 new CodeBreakIterator(debug_info, type)); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 BreakIterator::BreakIterator(Handle<DebugInfo> debug_info, | |
| 142 BreakLocatorType type) | |
| 143 : debug_info_(debug_info), break_index_(-1), break_locator_type_(type) { | |
| 98 position_ = debug_info->shared()->start_position(); | 144 position_ = debug_info->shared()->start_position(); |
| 99 statement_position_ = position_; | 145 statement_position_ = position_; |
| 100 } | 146 } |
| 101 | 147 |
| 102 BreakLocation::CodeIterator::CodeIterator(Handle<DebugInfo> debug_info, | 148 int BreakIterator::BreakIndexFromPosition(int source_position, |
| 103 BreakLocatorType type) | 149 BreakPositionAlignment alignment) { |
| 104 : Iterator(debug_info), | 150 int distance = kMaxInt; |
| 105 reloc_iterator_(debug_info->abstract_code()->GetCode(), | 151 int closest_break = break_index(); |
| 106 GetModeMask(type)), | 152 while (!Done()) { |
| 153 int next_position; | |
| 154 if (alignment == STATEMENT_ALIGNED) { | |
| 155 next_position = statement_position(); | |
| 156 } else { | |
| 157 DCHECK(alignment == BREAK_POSITION_ALIGNED); | |
| 158 next_position = position(); | |
| 159 } | |
| 160 if (source_position <= next_position && | |
| 161 next_position - source_position < distance) { | |
| 162 closest_break = break_index(); | |
| 163 distance = next_position - source_position; | |
| 164 // Check whether we can't get any closer. | |
| 165 if (distance == 0) break; | |
| 166 } | |
| 167 Next(); | |
| 168 } | |
| 169 return closest_break; | |
| 170 } | |
| 171 | |
| 172 CodeBreakIterator::CodeBreakIterator(Handle<DebugInfo> debug_info, | |
| 173 BreakLocatorType type) | |
| 174 : BreakIterator(debug_info, type), | |
| 175 reloc_iterator_(debug_info->DebugCode(), GetModeMask(type)), | |
| 107 source_position_iterator_( | 176 source_position_iterator_( |
| 108 debug_info->abstract_code()->GetCode()->source_position_table()) { | 177 debug_info->DebugCode()->source_position_table()) { |
| 109 // There is at least one break location. | 178 // There is at least one break location. |
| 110 DCHECK(!Done()); | 179 DCHECK(!Done()); |
| 111 Next(); | 180 Next(); |
| 112 } | 181 } |
| 113 | 182 |
| 114 int BreakLocation::CodeIterator::GetModeMask(BreakLocatorType type) { | 183 int CodeBreakIterator::GetModeMask(BreakLocatorType type) { |
| 115 int mask = 0; | 184 int mask = 0; |
| 116 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN); | 185 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN); |
| 117 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL); | 186 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL); |
| 118 if (isolate()->is_tail_call_elimination_enabled()) { | 187 if (isolate()->is_tail_call_elimination_enabled()) { |
| 119 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL); | 188 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL); |
| 120 } | 189 } |
| 121 if (type == ALL_BREAK_LOCATIONS) { | 190 if (type == ALL_BREAK_LOCATIONS) { |
| 122 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION); | 191 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION); |
| 123 mask |= RelocInfo::ModeMask(RelocInfo::DEBUGGER_STATEMENT); | 192 mask |= RelocInfo::ModeMask(RelocInfo::DEBUGGER_STATEMENT); |
| 124 } | 193 } |
| 125 return mask; | 194 return mask; |
| 126 } | 195 } |
| 127 | 196 |
| 128 void BreakLocation::CodeIterator::Next() { | 197 void CodeBreakIterator::Next() { |
| 129 DisallowHeapAllocation no_gc; | 198 DisallowHeapAllocation no_gc; |
| 130 DCHECK(!Done()); | 199 DCHECK(!Done()); |
| 131 | 200 |
| 132 // Iterate through reloc info stopping at each breakable code target. | 201 // Iterate through reloc info stopping at each breakable code target. |
| 133 bool first = break_index_ == -1; | 202 bool first = break_index_ == -1; |
| 134 | 203 |
| 135 if (!first) reloc_iterator_.next(); | 204 if (!first) reloc_iterator_.next(); |
| 136 first = false; | 205 first = false; |
| 137 if (Done()) return; | 206 if (Done()) return; |
| 138 | 207 |
| 139 int offset = code_offset(); | 208 int offset = code_offset(); |
| 140 while (!source_position_iterator_.done() && | 209 while (!source_position_iterator_.done() && |
| 141 source_position_iterator_.code_offset() <= offset) { | 210 source_position_iterator_.code_offset() <= offset) { |
| 142 position_ = source_position_iterator_.source_position(); | 211 position_ = source_position_iterator_.source_position(); |
| 143 if (source_position_iterator_.is_statement()) { | 212 if (source_position_iterator_.is_statement()) { |
| 144 statement_position_ = position_; | 213 statement_position_ = position_; |
| 145 } | 214 } |
| 146 source_position_iterator_.Advance(); | 215 source_position_iterator_.Advance(); |
| 147 } | 216 } |
| 148 | 217 |
| 149 DCHECK(RelocInfo::IsDebugBreakSlot(rmode()) || | 218 DCHECK(RelocInfo::IsDebugBreakSlot(rmode()) || |
| 150 RelocInfo::IsDebuggerStatement(rmode())); | 219 RelocInfo::IsDebuggerStatement(rmode())); |
| 151 break_index_++; | 220 break_index_++; |
| 152 } | 221 } |
| 153 | 222 |
| 154 BreakLocation BreakLocation::CodeIterator::GetBreakLocation() { | 223 DebugBreakType CodeBreakIterator::GetDebugBreakType() { |
| 155 DebugBreakType type; | |
| 156 if (RelocInfo::IsDebugBreakSlotAtReturn(rmode())) { | 224 if (RelocInfo::IsDebugBreakSlotAtReturn(rmode())) { |
| 157 type = DEBUG_BREAK_SLOT_AT_RETURN; | 225 return DEBUG_BREAK_SLOT_AT_RETURN; |
| 158 } else if (RelocInfo::IsDebugBreakSlotAtCall(rmode())) { | 226 } else if (RelocInfo::IsDebugBreakSlotAtCall(rmode())) { |
| 159 type = DEBUG_BREAK_SLOT_AT_CALL; | 227 return DEBUG_BREAK_SLOT_AT_CALL; |
| 160 } else if (RelocInfo::IsDebugBreakSlotAtTailCall(rmode())) { | 228 } else if (RelocInfo::IsDebugBreakSlotAtTailCall(rmode())) { |
| 161 type = isolate()->is_tail_call_elimination_enabled() | 229 return isolate()->is_tail_call_elimination_enabled() |
| 162 ? DEBUG_BREAK_SLOT_AT_TAIL_CALL | 230 ? DEBUG_BREAK_SLOT_AT_TAIL_CALL |
| 163 : DEBUG_BREAK_SLOT_AT_CALL; | 231 : DEBUG_BREAK_SLOT_AT_CALL; |
| 164 } else if (RelocInfo::IsDebuggerStatement(rmode())) { | 232 } else if (RelocInfo::IsDebuggerStatement(rmode())) { |
| 165 type = DEBUGGER_STATEMENT; | 233 return DEBUGGER_STATEMENT; |
| 166 } else if (RelocInfo::IsDebugBreakSlot(rmode())) { | 234 } else if (RelocInfo::IsDebugBreakSlot(rmode())) { |
| 167 type = DEBUG_BREAK_SLOT; | 235 return DEBUG_BREAK_SLOT; |
| 168 } else { | 236 } else { |
| 169 type = NOT_DEBUG_BREAK; | 237 return NOT_DEBUG_BREAK; |
| 170 } | 238 } |
| 171 return BreakLocation(debug_info_, type, code_offset(), position(), | |
| 172 statement_position()); | |
| 173 } | 239 } |
| 174 | 240 |
| 175 BreakLocation::BytecodeArrayIterator::BytecodeArrayIterator( | 241 void CodeBreakIterator::SkipToPosition(int position, |
| 242 BreakPositionAlignment alignment) { | |
| 243 CodeBreakIterator it(debug_info_, break_locator_type_); | |
| 244 SkipTo(it.BreakIndexFromPosition(position, alignment)); | |
| 245 } | |
| 246 | |
| 247 void CodeBreakIterator::SetDebugBreak() { | |
| 248 DebugBreakType debug_break_type = GetDebugBreakType(); | |
| 249 if (debug_break_type == DEBUGGER_STATEMENT) return; | |
| 250 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); | |
| 251 Builtins* builtins = isolate()->builtins(); | |
| 252 Handle<Code> target = debug_break_type == DEBUG_BREAK_SLOT_AT_RETURN | |
| 253 ? builtins->Return_DebugBreak() | |
| 254 : builtins->Slot_DebugBreak(); | |
| 255 DebugCodegen::PatchDebugBreakSlot(isolate(), rinfo()->pc(), target); | |
| 256 } | |
| 257 | |
| 258 void CodeBreakIterator::ClearDebugBreak() { | |
| 259 DebugBreakType debug_break_type = GetDebugBreakType(); | |
| 260 if (debug_break_type == DEBUGGER_STATEMENT) return; | |
| 261 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); | |
| 262 DebugCodegen::ClearDebugBreakSlot(isolate(), rinfo()->pc()); | |
| 263 } | |
| 264 | |
| 265 bool CodeBreakIterator::IsDebugBreak() { | |
| 266 DebugBreakType debug_break_type = GetDebugBreakType(); | |
| 267 if (debug_break_type == DEBUGGER_STATEMENT) return false; | |
| 268 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); | |
| 269 return DebugCodegen::DebugBreakSlotIsPatched(rinfo()->pc()); | |
| 270 } | |
| 271 | |
| 272 BreakLocation CodeBreakIterator::GetBreakLocation() { | |
| 273 Handle<AbstractCode> code(AbstractCode::cast(debug_info_->DebugCode())); | |
| 274 return BreakLocation(code, GetDebugBreakType(), code_offset(), position_); | |
| 275 } | |
| 276 | |
| 277 BytecodeArrayBreakIterator::BytecodeArrayBreakIterator( | |
| 176 Handle<DebugInfo> debug_info, BreakLocatorType type) | 278 Handle<DebugInfo> debug_info, BreakLocatorType type) |
| 177 : Iterator(debug_info), | 279 : BreakIterator(debug_info, type), |
| 178 source_position_iterator_(debug_info->abstract_code() | 280 source_position_iterator_( |
| 179 ->GetBytecodeArray() | 281 debug_info->DebugBytecodeArray()->source_position_table()) { |
| 180 ->source_position_table()), | |
| 181 break_locator_type_(type) { | |
| 182 // There is at least one break location. | 282 // There is at least one break location. |
| 183 DCHECK(!Done()); | 283 DCHECK(!Done()); |
| 184 Next(); | 284 Next(); |
| 185 } | 285 } |
| 186 | 286 |
| 187 void BreakLocation::BytecodeArrayIterator::Next() { | 287 void BytecodeArrayBreakIterator::Next() { |
| 188 DisallowHeapAllocation no_gc; | 288 DisallowHeapAllocation no_gc; |
| 189 DCHECK(!Done()); | 289 DCHECK(!Done()); |
| 190 bool first = break_index_ == -1; | 290 bool first = break_index_ == -1; |
| 191 while (!Done()) { | 291 while (!Done()) { |
| 192 if (!first) source_position_iterator_.Advance(); | 292 if (!first) source_position_iterator_.Advance(); |
| 193 first = false; | 293 first = false; |
| 194 if (Done()) return; | 294 if (Done()) return; |
| 195 position_ = source_position_iterator_.source_position(); | 295 position_ = source_position_iterator_.source_position(); |
| 196 if (source_position_iterator_.is_statement()) { | 296 if (source_position_iterator_.is_statement()) { |
| 197 statement_position_ = position_; | 297 statement_position_ = position_; |
| 198 } | 298 } |
| 199 DCHECK(position_ >= 0); | 299 DCHECK(position_ >= 0); |
| 200 DCHECK(statement_position_ >= 0); | 300 DCHECK(statement_position_ >= 0); |
| 201 | 301 |
| 202 enum DebugBreakType type = GetDebugBreakType(); | 302 DebugBreakType type = GetDebugBreakType(); |
| 203 if (type == NOT_DEBUG_BREAK) continue; | 303 if (type == NOT_DEBUG_BREAK) continue; |
| 204 | 304 |
| 205 if (break_locator_type_ == ALL_BREAK_LOCATIONS) break; | 305 if (break_locator_type_ == ALL_BREAK_LOCATIONS) break; |
| 206 | 306 |
| 207 DCHECK_EQ(CALLS_AND_RETURNS, break_locator_type_); | 307 DCHECK_EQ(CALLS_AND_RETURNS, break_locator_type_); |
| 208 if (type == DEBUG_BREAK_SLOT_AT_CALL) break; | 308 if (type == DEBUG_BREAK_SLOT_AT_CALL) break; |
| 209 if (type == DEBUG_BREAK_SLOT_AT_RETURN) break; | 309 if (type == DEBUG_BREAK_SLOT_AT_RETURN) break; |
| 210 } | 310 } |
| 211 break_index_++; | 311 break_index_++; |
| 212 } | 312 } |
| 213 | 313 |
| 214 BreakLocation::DebugBreakType | 314 DebugBreakType BytecodeArrayBreakIterator::GetDebugBreakType() { |
| 215 BreakLocation::BytecodeArrayIterator::GetDebugBreakType() { | 315 BytecodeArray* bytecode_array = debug_info_->OriginalBytecodeArray(); |
| 216 BytecodeArray* bytecode_array = debug_info_->original_bytecode_array(); | |
| 217 interpreter::Bytecode bytecode = | 316 interpreter::Bytecode bytecode = |
| 218 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); | 317 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); |
| 219 | 318 |
| 220 if (bytecode == interpreter::Bytecode::kDebugger) { | 319 if (bytecode == interpreter::Bytecode::kDebugger) { |
| 221 return DEBUGGER_STATEMENT; | 320 return DEBUGGER_STATEMENT; |
| 222 } else if (bytecode == interpreter::Bytecode::kReturn) { | 321 } else if (bytecode == interpreter::Bytecode::kReturn) { |
| 223 return DEBUG_BREAK_SLOT_AT_RETURN; | 322 return DEBUG_BREAK_SLOT_AT_RETURN; |
| 224 } else if (bytecode == interpreter::Bytecode::kTailCall) { | 323 } else if (bytecode == interpreter::Bytecode::kTailCall) { |
| 225 return isolate()->is_tail_call_elimination_enabled() | 324 return isolate()->is_tail_call_elimination_enabled() |
| 226 ? DEBUG_BREAK_SLOT_AT_TAIL_CALL | 325 ? DEBUG_BREAK_SLOT_AT_TAIL_CALL |
| 227 : DEBUG_BREAK_SLOT_AT_CALL; | 326 : DEBUG_BREAK_SLOT_AT_CALL; |
| 228 } else if (interpreter::Bytecodes::IsCallOrNew(bytecode)) { | 327 } else if (interpreter::Bytecodes::IsCallOrNew(bytecode)) { |
| 229 return DEBUG_BREAK_SLOT_AT_CALL; | 328 return DEBUG_BREAK_SLOT_AT_CALL; |
| 230 } else if (source_position_iterator_.is_statement()) { | 329 } else if (source_position_iterator_.is_statement()) { |
| 231 return DEBUG_BREAK_SLOT; | 330 return DEBUG_BREAK_SLOT; |
| 232 } else { | 331 } else { |
| 233 return NOT_DEBUG_BREAK; | 332 return NOT_DEBUG_BREAK; |
| 234 } | 333 } |
| 235 } | 334 } |
| 236 | 335 |
| 237 BreakLocation BreakLocation::BytecodeArrayIterator::GetBreakLocation() { | 336 void BytecodeArrayBreakIterator::SkipToPosition( |
| 238 return BreakLocation(debug_info_, GetDebugBreakType(), code_offset(), | 337 int position, BreakPositionAlignment alignment) { |
| 239 position(), statement_position()); | 338 BytecodeArrayBreakIterator it(debug_info_, break_locator_type_); |
| 339 SkipTo(it.BreakIndexFromPosition(position, alignment)); | |
| 240 } | 340 } |
| 241 | 341 |
| 242 // Find the break point at the supplied address, or the closest one before | 342 void BytecodeArrayBreakIterator::SetDebugBreak() { |
| 243 // the address. | 343 DebugBreakType debug_break_type = GetDebugBreakType(); |
| 244 BreakLocation BreakLocation::FromCodeOffset(Handle<DebugInfo> debug_info, | 344 if (debug_break_type == DEBUGGER_STATEMENT) return; |
| 245 int offset) { | 345 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); |
| 246 std::unique_ptr<Iterator> it(GetIterator(debug_info)); | 346 BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); |
| 247 it->SkipTo(BreakIndexFromCodeOffset(debug_info, offset)); | 347 interpreter::Bytecode bytecode = |
| 248 return it->GetBreakLocation(); | 348 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); |
| 349 if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return; | |
| 350 interpreter::Bytecode debugbreak = | |
| 351 interpreter::Bytecodes::GetDebugBreak(bytecode); | |
| 352 bytecode_array->set(code_offset(), | |
| 353 interpreter::Bytecodes::ToByte(debugbreak)); | |
| 249 } | 354 } |
| 250 | 355 |
| 251 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, | 356 void BytecodeArrayBreakIterator::ClearDebugBreak() { |
| 252 JavaScriptFrame* frame) { | 357 DebugBreakType debug_break_type = GetDebugBreakType(); |
| 253 int code_offset = FrameSummary::GetFirst(frame).code_offset(); | 358 if (debug_break_type == DEBUGGER_STATEMENT) return; |
| 254 int call_offset = | 359 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); |
| 255 CallOffsetFromCodeOffset(code_offset, frame->is_interpreted()); | 360 BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); |
| 256 return FromCodeOffset(debug_info, call_offset); | 361 BytecodeArray* original = debug_info_->OriginalBytecodeArray(); |
| 362 bytecode_array->set(code_offset(), original->get(code_offset())); | |
| 257 } | 363 } |
| 258 | 364 |
| 259 void BreakLocation::AllForStatementPosition(Handle<DebugInfo> debug_info, | 365 bool BytecodeArrayBreakIterator::IsDebugBreak() { |
| 260 int statement_position, | 366 DebugBreakType debug_break_type = GetDebugBreakType(); |
| 261 List<BreakLocation>* result_out) { | 367 if (debug_break_type == DEBUGGER_STATEMENT) return false; |
| 262 for (std::unique_ptr<Iterator> it(GetIterator(debug_info)); !it->Done(); | 368 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); |
| 263 it->Next()) { | 369 BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); |
| 264 if (it->statement_position() == statement_position) { | 370 interpreter::Bytecode bytecode = |
| 265 result_out->Add(it->GetBreakLocation()); | 371 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); |
| 266 } | 372 return interpreter::Bytecodes::IsDebugBreak(bytecode); |
| 267 } | |
| 268 } | 373 } |
| 269 | 374 |
| 270 int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info, | 375 BreakLocation BytecodeArrayBreakIterator::GetBreakLocation() { |
| 271 int offset) { | 376 Handle<AbstractCode> code( |
| 272 // Run through all break points to locate the one closest to the address. | 377 AbstractCode::cast(debug_info_->DebugBytecodeArray())); |
| 273 int closest_break = 0; | 378 return BreakLocation(code, GetDebugBreakType(), code_offset(), position_); |
| 274 int distance = kMaxInt; | |
| 275 DCHECK(0 <= offset && offset < debug_info->abstract_code()->Size()); | |
| 276 for (std::unique_ptr<Iterator> it(GetIterator(debug_info)); !it->Done(); | |
| 277 it->Next()) { | |
| 278 // Check if this break point is closer that what was previously found. | |
| 279 if (it->code_offset() <= offset && offset - it->code_offset() < distance) { | |
| 280 closest_break = it->break_index(); | |
| 281 distance = offset - it->code_offset(); | |
| 282 // Check whether we can't get any closer. | |
| 283 if (distance == 0) break; | |
| 284 } | |
| 285 } | |
| 286 return closest_break; | |
| 287 } | 379 } |
| 288 | 380 |
| 289 | 381 |
| 290 BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info, | |
| 291 int position, | |
| 292 BreakPositionAlignment alignment) { | |
| 293 // Run through all break points to locate the one closest to the source | |
| 294 // position. | |
| 295 int distance = kMaxInt; | |
| 296 std::unique_ptr<Iterator> it(GetIterator(debug_info)); | |
| 297 BreakLocation closest_break = it->GetBreakLocation(); | |
| 298 while (!it->Done()) { | |
| 299 int next_position; | |
| 300 if (alignment == STATEMENT_ALIGNED) { | |
| 301 next_position = it->statement_position(); | |
| 302 } else { | |
| 303 DCHECK(alignment == BREAK_POSITION_ALIGNED); | |
| 304 next_position = it->position(); | |
| 305 } | |
| 306 if (position <= next_position && next_position - position < distance) { | |
| 307 closest_break = it->GetBreakLocation(); | |
| 308 distance = next_position - position; | |
| 309 // Check whether we can't get any closer. | |
| 310 if (distance == 0) break; | |
| 311 } | |
| 312 it->Next(); | |
| 313 } | |
| 314 return closest_break; | |
| 315 } | |
| 316 | |
| 317 | |
| 318 void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) { | |
| 319 // If there is not already a real break point here patch code with debug | |
| 320 // break. | |
| 321 if (!HasBreakPoint()) SetDebugBreak(); | |
| 322 DCHECK(IsDebugBreak() || IsDebuggerStatement()); | |
| 323 // Set the break point information. | |
| 324 DebugInfo::SetBreakPoint(debug_info_, position_, statement_position_, | |
| 325 break_point_object); | |
| 326 } | |
| 327 | |
| 328 | |
| 329 void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) { | |
| 330 // Clear the break point information. | |
| 331 DebugInfo::ClearBreakPoint(debug_info_, position_, break_point_object); | |
| 332 // If there are no more break points here remove the debug break. | |
| 333 if (!HasBreakPoint()) { | |
| 334 ClearDebugBreak(); | |
| 335 DCHECK(!IsDebugBreak()); | |
| 336 } | |
| 337 } | |
| 338 | |
| 339 | |
| 340 void BreakLocation::SetOneShot() { | |
| 341 // Debugger statement always calls debugger. No need to modify it. | |
| 342 if (IsDebuggerStatement()) return; | |
| 343 | |
| 344 // Patch code with debug break. | |
| 345 SetDebugBreak(); | |
| 346 } | |
| 347 | |
| 348 | |
| 349 void BreakLocation::ClearOneShot() { | |
| 350 // Debugger statement always calls debugger. No need to modify it. | |
| 351 if (IsDebuggerStatement()) return; | |
| 352 | |
| 353 // If there is a real break point here no more to do. | |
| 354 if (HasBreakPoint()) { | |
| 355 DCHECK(IsDebugBreak()); | |
| 356 return; | |
| 357 } | |
| 358 | |
| 359 // Patch code removing debug break. | |
| 360 ClearDebugBreak(); | |
| 361 DCHECK(!IsDebugBreak()); | |
| 362 } | |
| 363 | |
| 364 | |
| 365 void BreakLocation::SetDebugBreak() { | |
| 366 // Debugger statement always calls debugger. No need to modify it. | |
| 367 if (IsDebuggerStatement()) return; | |
| 368 | |
| 369 // If there is already a break point here just return. This might happen if | |
| 370 // the same code is flooded with break points twice. Flooding the same | |
| 371 // function twice might happen when stepping in a function with an exception | |
| 372 // handler as the handler and the function is the same. | |
| 373 if (IsDebugBreak()) return; | |
| 374 | |
| 375 DCHECK(IsDebugBreakSlot()); | |
| 376 if (abstract_code()->IsCode()) { | |
| 377 Code* code = abstract_code()->GetCode(); | |
| 378 DCHECK(code->kind() == Code::FUNCTION); | |
| 379 Builtins* builtins = isolate()->builtins(); | |
| 380 Handle<Code> target = IsReturn() ? builtins->Return_DebugBreak() | |
| 381 : builtins->Slot_DebugBreak(); | |
| 382 Address pc = code->instruction_start() + code_offset(); | |
| 383 DebugCodegen::PatchDebugBreakSlot(isolate(), pc, target); | |
| 384 } else { | |
| 385 BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray(); | |
| 386 interpreter::Bytecode bytecode = | |
| 387 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); | |
| 388 interpreter::Bytecode debugbreak = | |
| 389 interpreter::Bytecodes::GetDebugBreak(bytecode); | |
| 390 bytecode_array->set(code_offset(), | |
| 391 interpreter::Bytecodes::ToByte(debugbreak)); | |
| 392 } | |
| 393 DCHECK(IsDebugBreak()); | |
| 394 } | |
| 395 | |
| 396 | |
| 397 void BreakLocation::ClearDebugBreak() { | |
| 398 // Debugger statement always calls debugger. No need to modify it. | |
| 399 if (IsDebuggerStatement()) return; | |
| 400 | |
| 401 DCHECK(IsDebugBreakSlot()); | |
| 402 if (abstract_code()->IsCode()) { | |
| 403 Code* code = abstract_code()->GetCode(); | |
| 404 DCHECK(code->kind() == Code::FUNCTION); | |
| 405 Address pc = code->instruction_start() + code_offset(); | |
| 406 DebugCodegen::ClearDebugBreakSlot(isolate(), pc); | |
| 407 } else { | |
| 408 BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray(); | |
| 409 BytecodeArray* original = debug_info_->original_bytecode_array(); | |
| 410 bytecode_array->set(code_offset(), original->get(code_offset())); | |
| 411 } | |
| 412 DCHECK(!IsDebugBreak()); | |
| 413 } | |
| 414 | |
| 415 | |
| 416 bool BreakLocation::IsDebugBreak() const { | |
| 417 if (IsDebuggerStatement()) return false; | |
| 418 DCHECK(IsDebugBreakSlot()); | |
| 419 if (abstract_code()->IsCode()) { | |
| 420 Code* code = abstract_code()->GetCode(); | |
| 421 DCHECK(code->kind() == Code::FUNCTION); | |
| 422 Address pc = code->instruction_start() + code_offset(); | |
| 423 return DebugCodegen::DebugBreakSlotIsPatched(pc); | |
| 424 } else { | |
| 425 BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray(); | |
| 426 interpreter::Bytecode bytecode = | |
| 427 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); | |
| 428 return interpreter::Bytecodes::IsDebugBreak(bytecode); | |
| 429 } | |
| 430 } | |
| 431 | |
| 432 Handle<Object> BreakLocation::BreakPointObjects() const { | |
| 433 return debug_info_->GetBreakPointObjects(position_); | |
| 434 } | |
| 435 | |
| 436 bool BreakLocation::HasBreakPoint() const { | |
| 437 // First check whether there is a break point with the same source position. | |
| 438 if (!debug_info_->HasBreakPoint(position_)) return false; | |
| 439 // Then check whether a break point at that source position would have | |
| 440 // the same code offset. Otherwise it's just a break location that we can | |
| 441 // step to, but not actually a location where we can put a break point. | |
| 442 BreakLocation break_point_location = BreakLocation::FromPosition( | |
| 443 debug_info_, position_, BREAK_POSITION_ALIGNED); | |
| 444 return break_point_location.code_offset() == code_offset_; | |
| 445 } | |
| 446 | |
| 447 void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) { | 382 void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) { |
| 448 uint32_t mask = 1 << feature; | 383 uint32_t mask = 1 << feature; |
| 449 // Only count one sample per feature and isolate. | 384 // Only count one sample per feature and isolate. |
| 450 if (bitfield_ & mask) return; | 385 if (bitfield_ & mask) return; |
| 451 isolate_->counters()->debug_feature_usage()->AddSample(feature); | 386 isolate_->counters()->debug_feature_usage()->AddSample(feature); |
| 452 bitfield_ |= mask; | 387 bitfield_ |= mask; |
| 453 } | 388 } |
| 454 | 389 |
| 455 | 390 |
| 456 // Threading support. | 391 // Threading support. |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 575 if (!EnsureDebugInfo(shared, function)) { | 510 if (!EnsureDebugInfo(shared, function)) { |
| 576 // Return if we failed to retrieve the debug info. | 511 // Return if we failed to retrieve the debug info. |
| 577 return; | 512 return; |
| 578 } | 513 } |
| 579 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); | 514 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); |
| 580 | 515 |
| 581 // Find the break location where execution has stopped. | 516 // Find the break location where execution has stopped. |
| 582 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); | 517 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); |
| 583 | 518 |
| 584 // Find actual break points, if any, and trigger debug break event. | 519 // Find actual break points, if any, and trigger debug break event. |
| 585 Handle<Object> break_points_hit = CheckBreakPoints(&location); | 520 Handle<Object> break_points_hit = CheckBreakPoints(debug_info, &location); |
| 586 if (!break_points_hit->IsUndefined(isolate_)) { | 521 if (!break_points_hit->IsUndefined(isolate_)) { |
| 587 // Clear all current stepping setup. | 522 // Clear all current stepping setup. |
| 588 ClearStepping(); | 523 ClearStepping(); |
| 589 // Notify the debug event listeners. | 524 // Notify the debug event listeners. |
| 590 OnDebugBreak(break_points_hit, false); | 525 OnDebugBreak(break_points_hit, false); |
| 591 return; | 526 return; |
| 592 } | 527 } |
| 593 | 528 |
| 594 // No break point. Check for stepping. | 529 // No break point. Check for stepping. |
| 595 StepAction step_action = last_step_action(); | 530 StepAction step_action = last_step_action(); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 611 if (current_fp < target_fp) return; | 546 if (current_fp < target_fp) return; |
| 612 // For step-next, a tail call is like a return and should break. | 547 // For step-next, a tail call is like a return and should break. |
| 613 step_break = location.IsTailCall(); | 548 step_break = location.IsTailCall(); |
| 614 // Fall through. | 549 // Fall through. |
| 615 case StepIn: { | 550 case StepIn: { |
| 616 FrameSummary summary = FrameSummary::GetFirst(frame); | 551 FrameSummary summary = FrameSummary::GetFirst(frame); |
| 617 int offset = summary.code_offset(); | 552 int offset = summary.code_offset(); |
| 618 step_break = step_break || location.IsReturn() || | 553 step_break = step_break || location.IsReturn() || |
| 619 (current_fp != last_fp) || | 554 (current_fp != last_fp) || |
| 620 (thread_local_.last_statement_position_ != | 555 (thread_local_.last_statement_position_ != |
| 621 location.abstract_code()->SourceStatementPosition(offset)); | 556 summary.abstract_code()->SourceStatementPosition(offset)); |
| 622 break; | 557 break; |
| 623 } | 558 } |
| 624 case StepFrame: | 559 case StepFrame: |
| 625 step_break = current_fp != last_fp; | 560 step_break = current_fp != last_fp; |
| 626 break; | 561 break; |
| 627 } | 562 } |
| 628 | 563 |
| 629 // Clear all current stepping setup. | 564 // Clear all current stepping setup. |
| 630 ClearStepping(); | 565 ClearStepping(); |
| 631 | 566 |
| 632 if (step_break) { | 567 if (step_break) { |
| 633 // Notify the debug event listeners. | 568 // Notify the debug event listeners. |
| 634 OnDebugBreak(isolate_->factory()->undefined_value(), false); | 569 OnDebugBreak(isolate_->factory()->undefined_value(), false); |
| 635 } else { | 570 } else { |
| 636 // Re-prepare to continue. | 571 // Re-prepare to continue. |
| 637 PrepareStep(step_action); | 572 PrepareStep(step_action); |
| 638 } | 573 } |
| 639 } | 574 } |
| 640 | 575 |
| 641 | 576 |
| 642 // Find break point objects for this location, if any, and evaluate them. | 577 // Find break point objects for this location, if any, and evaluate them. |
| 643 // Return an array of break point objects that evaluated true. | 578 // Return an array of break point objects that evaluated true. |
| 644 Handle<Object> Debug::CheckBreakPoints(BreakLocation* location, | 579 Handle<Object> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info, |
| 580 BreakLocation* location, | |
| 645 bool* has_break_points) { | 581 bool* has_break_points) { |
| 646 Factory* factory = isolate_->factory(); | 582 Factory* factory = isolate_->factory(); |
| 647 bool has_break_points_to_check = | 583 bool has_break_points_to_check = |
| 648 break_points_active_ && location->HasBreakPoint(); | 584 break_points_active_ && location->HasBreakPoint(debug_info); |
| 649 if (has_break_points) *has_break_points = has_break_points_to_check; | 585 if (has_break_points) *has_break_points = has_break_points_to_check; |
| 650 if (!has_break_points_to_check) return factory->undefined_value(); | 586 if (!has_break_points_to_check) return factory->undefined_value(); |
| 651 | 587 |
| 652 Handle<Object> break_point_objects = location->BreakPointObjects(); | 588 Handle<Object> break_point_objects = |
| 589 debug_info->GetBreakPointObjects(location->position()); | |
| 653 // Count the number of break points hit. If there are multiple break points | 590 // Count the number of break points hit. If there are multiple break points |
| 654 // they are in a FixedArray. | 591 // they are in a FixedArray. |
| 655 Handle<FixedArray> break_points_hit; | 592 Handle<FixedArray> break_points_hit; |
| 656 int break_points_hit_count = 0; | 593 int break_points_hit_count = 0; |
| 657 DCHECK(!break_point_objects->IsUndefined(isolate_)); | 594 DCHECK(!break_point_objects->IsUndefined(isolate_)); |
| 658 if (break_point_objects->IsFixedArray()) { | 595 if (break_point_objects->IsFixedArray()) { |
| 659 Handle<FixedArray> array(FixedArray::cast(*break_point_objects)); | 596 Handle<FixedArray> array(FixedArray::cast(*break_point_objects)); |
| 660 break_points_hit = factory->NewFixedArray(array->length()); | 597 break_points_hit = factory->NewFixedArray(array->length()); |
| 661 for (int i = 0; i < array->length(); i++) { | 598 for (int i = 0; i < array->length(); i++) { |
| 662 Handle<Object> break_point_object(array->get(i), isolate_); | 599 Handle<Object> break_point_object(array->get(i), isolate_); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 685 // an exception event on exception at this location. | 622 // an exception event on exception at this location. |
| 686 Object* fun = frame->function(); | 623 Object* fun = frame->function(); |
| 687 if (!fun->IsJSFunction()) return false; | 624 if (!fun->IsJSFunction()) return false; |
| 688 JSFunction* function = JSFunction::cast(fun); | 625 JSFunction* function = JSFunction::cast(fun); |
| 689 if (!function->shared()->HasDebugInfo()) return false; | 626 if (!function->shared()->HasDebugInfo()) return false; |
| 690 HandleScope scope(isolate_); | 627 HandleScope scope(isolate_); |
| 691 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); | 628 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); |
| 692 // Enter the debugger. | 629 // Enter the debugger. |
| 693 DebugScope debug_scope(this); | 630 DebugScope debug_scope(this); |
| 694 if (debug_scope.failed()) return false; | 631 if (debug_scope.failed()) return false; |
| 695 BreakLocation current_position = BreakLocation::FromFrame(debug_info, frame); | |
| 696 List<BreakLocation> break_locations; | 632 List<BreakLocation> break_locations; |
| 697 BreakLocation::AllForStatementPosition( | 633 BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations); |
| 698 debug_info, current_position.statement_position(), &break_locations); | |
| 699 bool has_break_points_at_all = false; | 634 bool has_break_points_at_all = false; |
| 700 for (int i = 0; i < break_locations.length(); i++) { | 635 for (int i = 0; i < break_locations.length(); i++) { |
| 701 bool has_break_points; | 636 bool has_break_points; |
| 702 Handle<Object> check_result = | 637 Handle<Object> check_result = |
| 703 CheckBreakPoints(&break_locations[i], &has_break_points); | 638 CheckBreakPoints(debug_info, &break_locations[i], &has_break_points); |
| 704 has_break_points_at_all |= has_break_points; | 639 has_break_points_at_all |= has_break_points; |
| 705 if (has_break_points && !check_result->IsUndefined(isolate_)) return false; | 640 if (has_break_points && !check_result->IsUndefined(isolate_)) return false; |
| 706 } | 641 } |
| 707 return has_break_points_at_all; | 642 return has_break_points_at_all; |
| 708 } | 643 } |
| 709 | 644 |
| 710 | 645 |
| 711 MaybeHandle<Object> Debug::CallFunction(const char* name, int argc, | 646 MaybeHandle<Object> Debug::CallFunction(const char* name, int argc, |
| 712 Handle<Object> args[]) { | 647 Handle<Object> args[]) { |
| 713 PostponeInterruptsScope no_interrupts(isolate_); | 648 PostponeInterruptsScope no_interrupts(isolate_); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 755 if (!EnsureDebugInfo(shared, function)) { | 690 if (!EnsureDebugInfo(shared, function)) { |
| 756 // Return if retrieving debug info failed. | 691 // Return if retrieving debug info failed. |
| 757 return true; | 692 return true; |
| 758 } | 693 } |
| 759 | 694 |
| 760 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 695 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 761 // Source positions starts with zero. | 696 // Source positions starts with zero. |
| 762 DCHECK(*source_position >= 0); | 697 DCHECK(*source_position >= 0); |
| 763 | 698 |
| 764 // Find the break point and change it. | 699 // Find the break point and change it. |
| 765 BreakLocation location = BreakLocation::FromPosition( | 700 *source_position = |
| 766 debug_info, *source_position, STATEMENT_ALIGNED); | 701 FindBreakablePosition(debug_info, *source_position, STATEMENT_ALIGNED); |
| 767 *source_position = location.statement_position(); | 702 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); |
| 768 location.SetBreakPoint(break_point_object); | 703 // At least one active break point now. |
| 704 DCHECK(debug_info->GetBreakPointCount() > 0); | |
| 705 | |
| 706 ClearBreakPoints(debug_info); | |
| 707 ApplyBreakPoints(debug_info); | |
| 769 | 708 |
| 770 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); | 709 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); |
| 771 | 710 return true; |
| 772 // At least one active break point now. | |
| 773 return debug_info->GetBreakPointCount() > 0; | |
| 774 } | 711 } |
| 775 | 712 |
| 776 | 713 |
| 777 bool Debug::SetBreakPointForScript(Handle<Script> script, | 714 bool Debug::SetBreakPointForScript(Handle<Script> script, |
| 778 Handle<Object> break_point_object, | 715 Handle<Object> break_point_object, |
| 779 int* source_position, | 716 int* source_position, |
| 780 BreakPositionAlignment alignment) { | 717 BreakPositionAlignment alignment) { |
| 781 if (script->type() == Script::TYPE_WASM) { | 718 if (script->type() == Script::TYPE_WASM) { |
| 782 // TODO(clemensh): set breakpoint for wasm. | 719 // TODO(clemensh): set breakpoint for wasm. |
| 783 return false; | 720 return false; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 798 | 735 |
| 799 // Find position within function. The script position might be before the | 736 // Find position within function. The script position might be before the |
| 800 // source position of the first function. | 737 // source position of the first function. |
| 801 if (shared->start_position() > *source_position) { | 738 if (shared->start_position() > *source_position) { |
| 802 *source_position = shared->start_position(); | 739 *source_position = shared->start_position(); |
| 803 } | 740 } |
| 804 | 741 |
| 805 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 742 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 806 | 743 |
| 807 // Find the break point and change it. | 744 // Find the break point and change it. |
| 808 BreakLocation location = | 745 *source_position = |
| 809 BreakLocation::FromPosition(debug_info, *source_position, alignment); | 746 FindBreakablePosition(debug_info, *source_position, alignment); |
| 810 location.SetBreakPoint(break_point_object); | 747 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); |
| 748 // At least one active break point now. | |
| 749 DCHECK(debug_info->GetBreakPointCount() > 0); | |
| 750 | |
| 751 ClearBreakPoints(debug_info); | |
| 752 ApplyBreakPoints(debug_info); | |
| 811 | 753 |
| 812 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); | 754 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); |
| 813 | |
| 814 *source_position = (alignment == STATEMENT_ALIGNED) | |
| 815 ? location.statement_position() | |
| 816 : location.position(); | |
| 817 | |
| 818 // At least one active break point now. | |
| 819 DCHECK(debug_info->GetBreakPointCount() > 0); | |
| 820 return true; | 755 return true; |
| 821 } | 756 } |
| 822 | 757 |
| 758 int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info, | |
| 759 int source_position, | |
| 760 BreakPositionAlignment alignment) { | |
| 761 int statement_position; | |
| 762 int position; | |
| 763 if (debug_info->HasDebugCode()) { | |
| 764 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | |
| 765 it.SkipToPosition(source_position, alignment); | |
| 766 statement_position = it.statement_position(); | |
| 767 position = it.position(); | |
| 768 } else { | |
| 769 DCHECK(debug_info->HasDebugBytecodeArray()); | |
| 770 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | |
| 771 it.SkipToPosition(source_position, alignment); | |
| 772 statement_position = it.statement_position(); | |
| 773 position = it.position(); | |
| 774 } | |
| 775 return alignment == STATEMENT_ALIGNED ? statement_position : position; | |
| 776 } | |
| 777 | |
| 778 void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) { | |
| 779 DisallowHeapAllocation no_gc; | |
| 780 if (debug_info->break_points()->IsUndefined(isolate_)) return; | |
| 781 FixedArray* break_points = debug_info->break_points(); | |
| 782 for (int i = 0; i < break_points->length(); i++) { | |
| 783 if (break_points->get(i)->IsUndefined(isolate_)) continue; | |
| 784 BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i)); | |
| 785 if (info->GetBreakPointCount() == 0) continue; | |
| 786 if (debug_info->HasDebugCode()) { | |
| 787 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | |
| 788 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); | |
| 789 it.SetDebugBreak(); | |
| 790 } | |
| 791 if (debug_info->HasDebugBytecodeArray()) { | |
| 792 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | |
| 793 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); | |
| 794 it.SetDebugBreak(); | |
| 795 } | |
| 796 } | |
| 797 } | |
| 798 | |
| 799 void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) { | |
| 800 DisallowHeapAllocation no_gc; | |
| 801 if (debug_info->HasDebugCode()) { | |
| 802 for (CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); | |
| 803 it.Next()) { | |
| 804 it.ClearDebugBreak(); | |
| 805 } | |
| 806 } | |
| 807 if (debug_info->HasDebugBytecodeArray()) { | |
| 808 for (BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | |
| 809 !it.Done(); it.Next()) { | |
| 810 it.ClearDebugBreak(); | |
| 811 } | |
| 812 } | |
| 813 } | |
| 823 | 814 |
| 824 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { | 815 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { |
| 825 HandleScope scope(isolate_); | 816 HandleScope scope(isolate_); |
| 826 | 817 |
| 827 DebugInfoListNode* node = debug_info_list_; | 818 for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
| 828 while (node != NULL) { | 819 node = node->next()) { |
| 829 Handle<Object> result = | 820 Handle<Object> result = |
| 830 DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object); | 821 DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object); |
| 831 if (!result->IsUndefined(isolate_)) { | 822 if (result->IsUndefined(isolate_)) continue; |
| 832 // Get information in the break point. | 823 Handle<DebugInfo> debug_info = node->debug_info(); |
| 833 Handle<BreakPointInfo> break_point_info = | 824 if (DebugInfo::ClearBreakPoint(debug_info, break_point_object)) { |
| 834 Handle<BreakPointInfo>::cast(result); | 825 ClearBreakPoints(debug_info); |
| 835 Handle<DebugInfo> debug_info = node->debug_info(); | |
| 836 | |
| 837 BreakLocation location = BreakLocation::FromPosition( | |
| 838 debug_info, break_point_info->source_position(), | |
| 839 BREAK_POSITION_ALIGNED); | |
| 840 location.ClearBreakPoint(break_point_object); | |
| 841 | |
| 842 // If there are no more break points left remove the debug info for this | |
| 843 // function. | |
| 844 if (debug_info->GetBreakPointCount() == 0) { | 826 if (debug_info->GetBreakPointCount() == 0) { |
| 845 RemoveDebugInfoAndClearFromShared(debug_info); | 827 RemoveDebugInfoAndClearFromShared(debug_info); |
| 828 } else { | |
| 829 ApplyBreakPoints(debug_info); | |
| 846 } | 830 } |
| 847 | |
| 848 return; | 831 return; |
| 849 } | 832 } |
| 850 node = node->next(); | |
| 851 } | 833 } |
| 852 } | 834 } |
| 853 | 835 |
| 854 | |
| 855 // Clear out all the debug break code. This is ONLY supposed to be used when | 836 // Clear out all the debug break code. This is ONLY supposed to be used when |
| 856 // shutting down the debugger as it will leave the break point information in | 837 // shutting down the debugger as it will leave the break point information in |
| 857 // DebugInfo even though the code is patched back to the non break point state. | 838 // DebugInfo even though the code is patched back to the non break point state. |
| 858 void Debug::ClearAllBreakPoints() { | 839 void Debug::ClearAllBreakPoints() { |
| 859 for (DebugInfoListNode* node = debug_info_list_; node != NULL; | 840 for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
| 860 node = node->next()) { | 841 node = node->next()) { |
| 861 for (std::unique_ptr<BreakLocation::Iterator> it( | 842 ClearBreakPoints(node->debug_info()); |
| 862 BreakLocation::GetIterator(node->debug_info())); | |
| 863 !it->Done(); it->Next()) { | |
| 864 it->GetBreakLocation().ClearDebugBreak(); | |
| 865 } | |
| 866 } | 843 } |
| 867 // Remove all debug info. | 844 // Remove all debug info. |
| 868 while (debug_info_list_ != NULL) { | 845 while (debug_info_list_ != NULL) { |
| 869 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); | 846 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); |
| 870 } | 847 } |
| 871 } | 848 } |
| 872 | 849 |
| 873 | |
| 874 void Debug::FloodWithOneShot(Handle<JSFunction> function, | 850 void Debug::FloodWithOneShot(Handle<JSFunction> function, |
| 875 BreakLocatorType type) { | 851 BreakLocatorType type) { |
| 876 // Debug utility functions are not subject to debugging. | 852 // Debug utility functions are not subject to debugging. |
| 877 if (function->native_context() == *debug_context()) return; | 853 if (function->native_context() == *debug_context()) return; |
| 878 | 854 |
| 879 if (!function->shared()->IsSubjectToDebugging()) { | 855 if (!function->shared()->IsSubjectToDebugging()) { |
| 880 // Builtin functions are not subject to stepping, but need to be | 856 // Builtin functions are not subject to stepping, but need to be |
| 881 // deoptimized, because optimized code does not check for debug | 857 // deoptimized, because optimized code does not check for debug |
| 882 // step in at call sites. | 858 // step in at call sites. |
| 883 Deoptimizer::DeoptimizeFunction(*function); | 859 Deoptimizer::DeoptimizeFunction(*function); |
| 884 return; | 860 return; |
| 885 } | 861 } |
| 886 // Make sure the function is compiled and has set up the debug info. | 862 // Make sure the function is compiled and has set up the debug info. |
| 887 Handle<SharedFunctionInfo> shared(function->shared()); | 863 Handle<SharedFunctionInfo> shared(function->shared()); |
| 888 if (!EnsureDebugInfo(shared, function)) { | 864 if (!EnsureDebugInfo(shared, function)) { |
| 889 // Return if we failed to retrieve the debug info. | 865 // Return if we failed to retrieve the debug info. |
| 890 return; | 866 return; |
| 891 } | 867 } |
| 892 | 868 |
| 893 // Flood the function with break points. | 869 // Flood the function with break points. |
| 894 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 870 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 895 for (std::unique_ptr<BreakLocation::Iterator> it( | 871 if (debug_info->HasDebugCode()) { |
| 896 BreakLocation::GetIterator(debug_info, type)); | 872 for (CodeBreakIterator it(debug_info, type); !it.Done(); it.Next()) { |
| 897 !it->Done(); it->Next()) { | 873 it.SetDebugBreak(); |
| 898 it->GetBreakLocation().SetOneShot(); | 874 } |
| 875 } | |
| 876 if (debug_info->HasDebugBytecodeArray()) { | |
| 877 for (BytecodeArrayBreakIterator it(debug_info, type); !it.Done(); | |
| 878 it.Next()) { | |
| 879 it.SetDebugBreak(); | |
| 880 } | |
| 899 } | 881 } |
| 900 } | 882 } |
| 901 | 883 |
| 902 | |
| 903 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { | 884 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { |
| 904 if (type == BreakUncaughtException) { | 885 if (type == BreakUncaughtException) { |
| 905 break_on_uncaught_exception_ = enable; | 886 break_on_uncaught_exception_ = enable; |
| 906 } else { | 887 } else { |
| 907 break_on_exception_ = enable; | 888 break_on_exception_ = enable; |
| 908 } | 889 } |
| 909 } | 890 } |
| 910 | 891 |
| 911 | 892 |
| 912 bool Debug::IsBreakOnException(ExceptionBreakType type) { | 893 bool Debug::IsBreakOnException(ExceptionBreakType type) { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1007 // Get the debug info (create it if it does not exist). | 988 // Get the debug info (create it if it does not exist). |
| 1008 FrameSummary summary = FrameSummary::GetFirst(frame); | 989 FrameSummary summary = FrameSummary::GetFirst(frame); |
| 1009 Handle<JSFunction> function(summary.function()); | 990 Handle<JSFunction> function(summary.function()); |
| 1010 Handle<SharedFunctionInfo> shared(function->shared()); | 991 Handle<SharedFunctionInfo> shared(function->shared()); |
| 1011 if (!EnsureDebugInfo(shared, function)) { | 992 if (!EnsureDebugInfo(shared, function)) { |
| 1012 // Return if ensuring debug info failed. | 993 // Return if ensuring debug info failed. |
| 1013 return; | 994 return; |
| 1014 } | 995 } |
| 1015 | 996 |
| 1016 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 997 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 1017 // Refresh frame summary if the code has been recompiled for debugging. | 998 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); |
| 1018 if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) { | |
| 1019 summary = FrameSummary::GetFirst(frame); | |
| 1020 } | |
| 1021 | |
| 1022 int call_offset = | |
| 1023 CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted()); | |
| 1024 BreakLocation location = | |
| 1025 BreakLocation::FromCodeOffset(debug_info, call_offset); | |
| 1026 | 999 |
| 1027 // Any step at a return is a step-out. | 1000 // Any step at a return is a step-out. |
| 1028 if (location.IsReturn()) step_action = StepOut; | 1001 if (location.IsReturn()) step_action = StepOut; |
| 1029 // A step-next at a tail call is a step-out. | 1002 // A step-next at a tail call is a step-out. |
| 1030 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; | 1003 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; |
| 1031 | 1004 |
| 1032 thread_local_.last_statement_position_ = | 1005 thread_local_.last_statement_position_ = |
| 1033 debug_info->abstract_code()->SourceStatementPosition( | 1006 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); |
| 1034 summary.code_offset()); | |
| 1035 thread_local_.last_fp_ = frame->UnpaddedFP(); | 1007 thread_local_.last_fp_ = frame->UnpaddedFP(); |
| 1036 // No longer perform the current async step. | 1008 // No longer perform the current async step. |
| 1037 clear_suspended_generator(); | 1009 clear_suspended_generator(); |
| 1038 | 1010 |
| 1039 switch (step_action) { | 1011 switch (step_action) { |
| 1040 case StepNone: | 1012 case StepNone: |
| 1041 UNREACHABLE(); | 1013 UNREACHABLE(); |
| 1042 break; | 1014 break; |
| 1043 case StepOut: | 1015 case StepOut: |
| 1044 // Advance to caller frame. | 1016 // Advance to caller frame. |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1069 FloodWithOneShot(function); | 1041 FloodWithOneShot(function); |
| 1070 break; | 1042 break; |
| 1071 case StepFrame: | 1043 case StepFrame: |
| 1072 // No point in setting one-shot breaks at places where we are not about | 1044 // No point in setting one-shot breaks at places where we are not about |
| 1073 // to leave the current frame. | 1045 // to leave the current frame. |
| 1074 FloodWithOneShot(function, CALLS_AND_RETURNS); | 1046 FloodWithOneShot(function, CALLS_AND_RETURNS); |
| 1075 break; | 1047 break; |
| 1076 } | 1048 } |
| 1077 } | 1049 } |
| 1078 | 1050 |
| 1079 | |
| 1080 // Simple function for returning the source positions for active break points. | 1051 // Simple function for returning the source positions for active break points. |
| 1081 Handle<Object> Debug::GetSourceBreakLocations( | 1052 Handle<Object> Debug::GetSourceBreakLocations( |
| 1082 Handle<SharedFunctionInfo> shared, | 1053 Handle<SharedFunctionInfo> shared, |
| 1083 BreakPositionAlignment position_alignment) { | 1054 BreakPositionAlignment position_alignment) { |
| 1084 Isolate* isolate = shared->GetIsolate(); | 1055 Isolate* isolate = shared->GetIsolate(); |
| 1085 if (!shared->HasDebugInfo()) { | 1056 if (!shared->HasDebugInfo()) { |
| 1086 return isolate->factory()->undefined_value(); | 1057 return isolate->factory()->undefined_value(); |
| 1087 } | 1058 } |
| 1088 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 1059 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 1089 if (debug_info->GetBreakPointCount() == 0) { | 1060 if (debug_info->GetBreakPointCount() == 0) { |
| 1090 return isolate->factory()->undefined_value(); | 1061 return isolate->factory()->undefined_value(); |
| 1091 } | 1062 } |
| 1092 Handle<FixedArray> locations = | 1063 Handle<FixedArray> locations = |
| 1093 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount()); | 1064 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount()); |
| 1094 int count = 0; | 1065 int count = 0; |
| 1095 for (int i = 0; i < debug_info->break_points()->length(); ++i) { | 1066 for (int i = 0; i < debug_info->break_points()->length(); ++i) { |
| 1096 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { | 1067 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { |
| 1097 BreakPointInfo* break_point_info = | 1068 BreakPointInfo* break_point_info = |
| 1098 BreakPointInfo::cast(debug_info->break_points()->get(i)); | 1069 BreakPointInfo::cast(debug_info->break_points()->get(i)); |
| 1099 int break_points = break_point_info->GetBreakPointCount(); | 1070 int break_points = break_point_info->GetBreakPointCount(); |
| 1100 if (break_points == 0) continue; | 1071 if (break_points == 0) continue; |
| 1101 Smi* position = NULL; | 1072 Smi* position = NULL; |
| 1102 if (position_alignment == STATEMENT_ALIGNED) { | 1073 if (position_alignment == STATEMENT_ALIGNED) { |
| 1103 BreakLocation break_point_location = BreakLocation::FromPosition( | 1074 if (debug_info->HasDebugCode()) { |
| 1104 debug_info, break_point_info->source_position(), | 1075 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); |
| 1105 BREAK_POSITION_ALIGNED); | 1076 it.SkipToPosition(break_point_info->source_position(), |
| 1106 position = Smi::FromInt(break_point_location.statement_position()); | 1077 BREAK_POSITION_ALIGNED); |
| 1078 position = Smi::FromInt(it.statement_position()); | |
| 1079 } else { | |
|
jgruber
2016/08/11 14:28:13
Same here.
Yang
2016/08/12 05:33:46
Done.
| |
| 1080 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | |
| 1081 it.SkipToPosition(break_point_info->source_position(), | |
| 1082 BREAK_POSITION_ALIGNED); | |
| 1083 position = Smi::FromInt(it.statement_position()); | |
| 1084 } | |
| 1107 } else { | 1085 } else { |
| 1108 DCHECK_EQ(BREAK_POSITION_ALIGNED, position_alignment); | 1086 DCHECK_EQ(BREAK_POSITION_ALIGNED, position_alignment); |
| 1109 position = Smi::FromInt(break_point_info->source_position()); | 1087 position = Smi::FromInt(break_point_info->source_position()); |
| 1110 } | 1088 } |
| 1111 for (int j = 0; j < break_points; ++j) locations->set(count++, position); | 1089 for (int j = 0; j < break_points; ++j) locations->set(count++, position); |
| 1112 } | 1090 } |
| 1113 } | 1091 } |
| 1114 return locations; | 1092 return locations; |
| 1115 } | 1093 } |
| 1116 | 1094 |
| 1117 | |
| 1118 void Debug::ClearStepping() { | 1095 void Debug::ClearStepping() { |
| 1119 // Clear the various stepping setup. | 1096 // Clear the various stepping setup. |
| 1120 ClearOneShot(); | 1097 ClearOneShot(); |
| 1121 | 1098 |
| 1122 thread_local_.last_step_action_ = StepNone; | 1099 thread_local_.last_step_action_ = StepNone; |
| 1123 thread_local_.last_statement_position_ = kNoSourcePosition; | 1100 thread_local_.last_statement_position_ = kNoSourcePosition; |
| 1124 thread_local_.last_fp_ = 0; | 1101 thread_local_.last_fp_ = 0; |
| 1125 thread_local_.target_fp_ = 0; | 1102 thread_local_.target_fp_ = 0; |
| 1126 } | 1103 } |
| 1127 | 1104 |
| 1128 | 1105 |
| 1129 // Clears all the one-shot break points that are currently set. Normally this | 1106 // Clears all the one-shot break points that are currently set. Normally this |
| 1130 // function is called each time a break point is hit as one shot break points | 1107 // function is called each time a break point is hit as one shot break points |
| 1131 // are used to support stepping. | 1108 // are used to support stepping. |
| 1132 void Debug::ClearOneShot() { | 1109 void Debug::ClearOneShot() { |
| 1133 // The current implementation just runs through all the breakpoints. When the | 1110 // The current implementation just runs through all the breakpoints. When the |
| 1134 // last break point for a function is removed that function is automatically | 1111 // last break point for a function is removed that function is automatically |
| 1135 // removed from the list. | 1112 // removed from the list. |
| 1136 for (DebugInfoListNode* node = debug_info_list_; node != NULL; | 1113 for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
| 1137 node = node->next()) { | 1114 node = node->next()) { |
| 1138 for (std::unique_ptr<BreakLocation::Iterator> it( | 1115 Handle<DebugInfo> debug_info = node->debug_info(); |
| 1139 BreakLocation::GetIterator(node->debug_info())); | 1116 ClearBreakPoints(debug_info); |
| 1140 !it->Done(); it->Next()) { | 1117 ApplyBreakPoints(debug_info); |
|
jgruber
2016/08/11 14:28:13
Why are breakpoints reapplied here?
Yang
2016/08/12 05:33:46
Because having a function flooded with one-shots m
| |
| 1141 it->GetBreakLocation().ClearOneShot(); | |
| 1142 } | |
| 1143 } | 1118 } |
| 1144 } | 1119 } |
| 1145 | 1120 |
| 1146 | 1121 |
| 1147 bool MatchingCodeTargets(Code* target1, Code* target2) { | 1122 bool MatchingCodeTargets(Code* target1, Code* target2) { |
| 1148 if (target1 == target2) return true; | 1123 if (target1 == target2) return true; |
| 1149 if (target1->kind() != target2->kind()) return false; | 1124 if (target1->kind() != target2->kind()) return false; |
| 1150 return target1->is_handler() || target1->is_inline_cache_stub(); | 1125 return target1->is_handler() || target1->is_inline_cache_stub(); |
| 1151 } | 1126 } |
| 1152 | 1127 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1236 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) { | 1211 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) { |
| 1237 JavaScriptFrame* frame = it.frame(); | 1212 JavaScriptFrame* frame = it.frame(); |
| 1238 JSFunction* function = frame->function(); | 1213 JSFunction* function = frame->function(); |
| 1239 if (frame->is_optimized()) continue; | 1214 if (frame->is_optimized()) continue; |
| 1240 if (!function->Inlines(shared_)) continue; | 1215 if (!function->Inlines(shared_)) continue; |
| 1241 | 1216 |
| 1242 if (frame->is_interpreted()) { | 1217 if (frame->is_interpreted()) { |
| 1243 InterpretedFrame* interpreted_frame = | 1218 InterpretedFrame* interpreted_frame = |
| 1244 reinterpret_cast<InterpretedFrame*>(frame); | 1219 reinterpret_cast<InterpretedFrame*>(frame); |
| 1245 BytecodeArray* debug_copy = | 1220 BytecodeArray* debug_copy = |
| 1246 shared_->GetDebugInfo()->abstract_code()->GetBytecodeArray(); | 1221 shared_->GetDebugInfo()->DebugBytecodeArray(); |
| 1247 interpreted_frame->PatchBytecodeArray(debug_copy); | 1222 interpreted_frame->PatchBytecodeArray(debug_copy); |
| 1248 continue; | 1223 continue; |
| 1249 } | 1224 } |
| 1250 | 1225 |
| 1251 Code* frame_code = frame->LookupCode(); | 1226 Code* frame_code = frame->LookupCode(); |
| 1252 DCHECK(frame_code->kind() == Code::FUNCTION); | 1227 DCHECK(frame_code->kind() == Code::FUNCTION); |
| 1253 if (frame_code->has_debug_break_slots()) continue; | 1228 if (frame_code->has_debug_break_slots()) continue; |
| 1254 | 1229 |
| 1255 Code* new_code = function->shared()->code(); | 1230 Code* new_code = function->shared()->code(); |
| 1256 Address old_pc = frame->pc(); | 1231 Address old_pc = frame->pc(); |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1589 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { | 1564 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { |
| 1590 HandleScope scope(isolate_); | 1565 HandleScope scope(isolate_); |
| 1591 | 1566 |
| 1592 // Get the executing function in which the debug break occurred. | 1567 // Get the executing function in which the debug break occurred. |
| 1593 Handle<SharedFunctionInfo> shared(frame->function()->shared()); | 1568 Handle<SharedFunctionInfo> shared(frame->function()->shared()); |
| 1594 | 1569 |
| 1595 // With no debug info there are no break points, so we can't be at a return. | 1570 // With no debug info there are no break points, so we can't be at a return. |
| 1596 if (!shared->HasDebugInfo()) return false; | 1571 if (!shared->HasDebugInfo()) return false; |
| 1597 | 1572 |
| 1598 DCHECK(!frame->is_optimized()); | 1573 DCHECK(!frame->is_optimized()); |
| 1599 int code_offset = FrameSummary::GetFirst(frame).code_offset(); | |
| 1600 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 1574 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 1601 BreakLocation location = | 1575 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); |
| 1602 BreakLocation::FromCodeOffset(debug_info, code_offset); | |
| 1603 return location.IsReturn() || location.IsTailCall(); | 1576 return location.IsReturn() || location.IsTailCall(); |
| 1604 } | 1577 } |
| 1605 | 1578 |
| 1606 | 1579 |
| 1607 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, | 1580 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, |
| 1608 LiveEdit::FrameDropMode mode) { | 1581 LiveEdit::FrameDropMode mode) { |
| 1609 if (mode != LiveEdit::CURRENTLY_SET_MODE) { | 1582 if (mode != LiveEdit::CURRENTLY_SET_MODE) { |
| 1610 thread_local_.frame_drop_mode_ = mode; | 1583 thread_local_.frame_drop_mode_ = mode; |
| 1611 } | 1584 } |
| 1612 thread_local_.break_frame_id_ = new_break_frame_id; | 1585 thread_local_.break_frame_id_ = new_break_frame_id; |
| (...skipping 810 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2423 Handle<Object> json; | 2396 Handle<Object> json; |
| 2424 if (!maybe_json.ToHandle(&json) || !json->IsString()) { | 2397 if (!maybe_json.ToHandle(&json) || !json->IsString()) { |
| 2425 return v8::Local<v8::String>(); | 2398 return v8::Local<v8::String>(); |
| 2426 } | 2399 } |
| 2427 return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json))); | 2400 return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json))); |
| 2428 } else { | 2401 } else { |
| 2429 return v8::Utils::ToLocal(response_json_); | 2402 return v8::Utils::ToLocal(response_json_); |
| 2430 } | 2403 } |
| 2431 } | 2404 } |
| 2432 | 2405 |
| 2406 namespace { | |
| 2407 v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) { | |
| 2408 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); | |
| 2409 // Isolate::context() may have been NULL when "script collected" event | |
| 2410 // occured. | |
| 2411 if (context.is_null()) return v8::Local<v8::Context>(); | |
| 2412 Handle<Context> native_context(context->native_context()); | |
| 2413 return v8::Utils::ToLocal(native_context); | |
| 2414 } | |
| 2415 } // anonymous namespace | |
| 2433 | 2416 |
| 2434 v8::Local<v8::Context> MessageImpl::GetEventContext() const { | 2417 v8::Local<v8::Context> MessageImpl::GetEventContext() const { |
| 2435 Isolate* isolate = event_data_->GetIsolate(); | 2418 Isolate* isolate = event_data_->GetIsolate(); |
| 2436 v8::Local<v8::Context> context = GetDebugEventContext(isolate); | 2419 v8::Local<v8::Context> context = GetDebugEventContext(isolate); |
| 2437 // Isolate::context() may be NULL when "script collected" event occurs. | 2420 // Isolate::context() may be NULL when "script collected" event occurs. |
| 2438 DCHECK(!context.IsEmpty()); | 2421 DCHECK(!context.IsEmpty()); |
| 2439 return context; | 2422 return context; |
| 2440 } | 2423 } |
| 2441 | 2424 |
| 2442 | 2425 |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2583 } | 2566 } |
| 2584 | 2567 |
| 2585 | 2568 |
| 2586 void LockingCommandMessageQueue::Clear() { | 2569 void LockingCommandMessageQueue::Clear() { |
| 2587 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 2570 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 2588 queue_.Clear(); | 2571 queue_.Clear(); |
| 2589 } | 2572 } |
| 2590 | 2573 |
| 2591 } // namespace internal | 2574 } // namespace internal |
| 2592 } // namespace v8 | 2575 } // namespace v8 |
| OLD | NEW |