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