1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/objects/debug-objects.h"
6
7 #include "src/debug/debug-evaluate.h"
8 #include "src/handles/handles-inl.h"
9 #include "src/objects/debug-objects-inl.h"
10 #include "src/utils/ostreams.h"
11
12 namespace v8 {
13 namespace internal {
14
IsEmpty() const15 bool DebugInfo::IsEmpty() const {
16 return flags() == kNone && debugger_hints() == 0;
17 }
18
HasBreakInfo() const19 bool DebugInfo::HasBreakInfo() const { return (flags() & kHasBreakInfo) != 0; }
20
DebugExecutionMode() const21 DebugInfo::ExecutionMode DebugInfo::DebugExecutionMode() const {
22 return (flags() & kDebugExecutionMode) != 0 ? kSideEffects : kBreakpoints;
23 }
24
SetDebugExecutionMode(ExecutionMode value)25 void DebugInfo::SetDebugExecutionMode(ExecutionMode value) {
26 set_flags(value == kSideEffects ? (flags() | kDebugExecutionMode)
27 : (flags() & ~kDebugExecutionMode));
28 }
29
ClearBreakInfo(Isolate * isolate)30 void DebugInfo::ClearBreakInfo(Isolate* isolate) {
31 if (HasInstrumentedBytecodeArray()) {
32 // Reset function's bytecode array field to point to the original bytecode
33 // array.
34 shared().SetDebugBytecodeArray(OriginalBytecodeArray());
35
36 // If the function is currently running on the stack, we need to update the
37 // bytecode pointers on the stack so they point to the original
38 // BytecodeArray before releasing that BytecodeArray from this DebugInfo.
39 // Otherwise, it could be flushed and cause problems on resume. See v8:9067.
40 {
41 RedirectActiveFunctions redirect_visitor(
42 shared(), RedirectActiveFunctions::Mode::kUseOriginalBytecode);
43 redirect_visitor.VisitThread(isolate, isolate->thread_local_top());
44 isolate->thread_manager()->IterateArchivedThreads(&redirect_visitor);
45 }
46
47 set_original_bytecode_array(ReadOnlyRoots(isolate).undefined_value());
48 set_debug_bytecode_array(ReadOnlyRoots(isolate).undefined_value());
49 }
50 set_break_points(ReadOnlyRoots(isolate).empty_fixed_array());
51
52 int new_flags = flags();
53 new_flags &= ~kHasBreakInfo & ~kPreparedForDebugExecution;
54 new_flags &= ~kBreakAtEntry & ~kCanBreakAtEntry;
55 new_flags &= ~kDebugExecutionMode;
56 set_flags(new_flags);
57 }
58
SetBreakAtEntry()59 void DebugInfo::SetBreakAtEntry() {
60 DCHECK(CanBreakAtEntry());
61 set_flags(flags() | kBreakAtEntry);
62 }
63
ClearBreakAtEntry()64 void DebugInfo::ClearBreakAtEntry() {
65 DCHECK(CanBreakAtEntry());
66 set_flags(flags() & ~kBreakAtEntry);
67 }
68
BreakAtEntry() const69 bool DebugInfo::BreakAtEntry() const { return (flags() & kBreakAtEntry) != 0; }
70
CanBreakAtEntry() const71 bool DebugInfo::CanBreakAtEntry() const {
72 return (flags() & kCanBreakAtEntry) != 0;
73 }
74
75 // Check if there is a break point at this source position.
HasBreakPoint(Isolate * isolate,int source_position)76 bool DebugInfo::HasBreakPoint(Isolate* isolate, int source_position) {
77 DCHECK(HasBreakInfo());
78 // Get the break point info object for this code offset.
79 Object break_point_info = GetBreakPointInfo(isolate, source_position);
80
81 // If there is no break point info object or no break points in the break
82 // point info object there is no break point at this code offset.
83 if (break_point_info.IsUndefined(isolate)) return false;
84 return BreakPointInfo::cast(break_point_info).GetBreakPointCount(isolate) > 0;
85 }
86
87 // Get the break point info object for this source position.
GetBreakPointInfo(Isolate * isolate,int source_position)88 Object DebugInfo::GetBreakPointInfo(Isolate* isolate, int source_position) {
89 DCHECK(HasBreakInfo());
90 for (int i = 0; i < break_points().length(); i++) {
91 if (!break_points().get(i).IsUndefined(isolate)) {
92 BreakPointInfo break_point_info =
93 BreakPointInfo::cast(break_points().get(i));
94 if (break_point_info.source_position() == source_position) {
95 return break_point_info;
96 }
97 }
98 }
99 return ReadOnlyRoots(isolate).undefined_value();
100 }
101
ClearBreakPoint(Isolate * isolate,Handle<DebugInfo> debug_info,Handle<BreakPoint> break_point)102 bool DebugInfo::ClearBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info,
103 Handle<BreakPoint> break_point) {
104 DCHECK(debug_info->HasBreakInfo());
105 for (int i = 0; i < debug_info->break_points().length(); i++) {
106 if (debug_info->break_points().get(i).IsUndefined(isolate)) continue;
107 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
108 BreakPointInfo::cast(debug_info->break_points().get(i)), isolate);
109 if (BreakPointInfo::HasBreakPoint(isolate, break_point_info, break_point)) {
110 BreakPointInfo::ClearBreakPoint(isolate, break_point_info, break_point);
111 return true;
112 }
113 }
114 return false;
115 }
116
SetBreakPoint(Isolate * isolate,Handle<DebugInfo> debug_info,int source_position,Handle<BreakPoint> break_point)117 void DebugInfo::SetBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info,
118 int source_position,
119 Handle<BreakPoint> break_point) {
120 DCHECK(debug_info->HasBreakInfo());
121 Handle<Object> break_point_info(
122 debug_info->GetBreakPointInfo(isolate, source_position), isolate);
123 if (!break_point_info->IsUndefined(isolate)) {
124 BreakPointInfo::SetBreakPoint(
125 isolate, Handle<BreakPointInfo>::cast(break_point_info), break_point);
126 return;
127 }
128
129 // Adding a new break point for a code offset which did not have any
130 // break points before. Try to find a free slot.
131 static const int kNoBreakPointInfo = -1;
132 int index = kNoBreakPointInfo;
133 for (int i = 0; i < debug_info->break_points().length(); i++) {
134 if (debug_info->break_points().get(i).IsUndefined(isolate)) {
135 index = i;
136 break;
137 }
138 }
139 if (index == kNoBreakPointInfo) {
140 // No free slot - extend break point info array.
141 Handle<FixedArray> old_break_points =
142 Handle<FixedArray>(debug_info->break_points(), isolate);
143 Handle<FixedArray> new_break_points = isolate->factory()->NewFixedArray(
144 old_break_points->length() +
145 DebugInfo::kEstimatedNofBreakPointsInFunction);
146
147 debug_info->set_break_points(*new_break_points);
148 for (int i = 0; i < old_break_points->length(); i++) {
149 new_break_points->set(i, old_break_points->get(i));
150 }
151 index = old_break_points->length();
152 }
153 DCHECK_NE(index, kNoBreakPointInfo);
154
155 // Allocate new BreakPointInfo object and set the break point.
156 Handle<BreakPointInfo> new_break_point_info =
157 isolate->factory()->NewBreakPointInfo(source_position);
158 BreakPointInfo::SetBreakPoint(isolate, new_break_point_info, break_point);
159 debug_info->break_points().set(index, *new_break_point_info);
160 }
161
162 // Get the break point objects for a source position.
GetBreakPoints(Isolate * isolate,int source_position)163 Handle<Object> DebugInfo::GetBreakPoints(Isolate* isolate,
164 int source_position) {
165 DCHECK(HasBreakInfo());
166 Object break_point_info = GetBreakPointInfo(isolate, source_position);
167 if (break_point_info.IsUndefined(isolate)) {
168 return isolate->factory()->undefined_value();
169 }
170 return Handle<Object>(BreakPointInfo::cast(break_point_info).break_points(),
171 isolate);
172 }
173
174 // Get the total number of break points.
GetBreakPointCount(Isolate * isolate)175 int DebugInfo::GetBreakPointCount(Isolate* isolate) {
176 DCHECK(HasBreakInfo());
177 int count = 0;
178 for (int i = 0; i < break_points().length(); i++) {
179 if (!break_points().get(i).IsUndefined(isolate)) {
180 BreakPointInfo break_point_info =
181 BreakPointInfo::cast(break_points().get(i));
182 count += break_point_info.GetBreakPointCount(isolate);
183 }
184 }
185 return count;
186 }
187
FindBreakPointInfo(Isolate * isolate,Handle<DebugInfo> debug_info,Handle<BreakPoint> break_point)188 Handle<Object> DebugInfo::FindBreakPointInfo(Isolate* isolate,
189 Handle<DebugInfo> debug_info,
190 Handle<BreakPoint> break_point) {
191 DCHECK(debug_info->HasBreakInfo());
192 for (int i = 0; i < debug_info->break_points().length(); i++) {
193 if (!debug_info->break_points().get(i).IsUndefined(isolate)) {
194 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
195 BreakPointInfo::cast(debug_info->break_points().get(i)), isolate);
196 if (BreakPointInfo::HasBreakPoint(isolate, break_point_info,
197 break_point)) {
198 return break_point_info;
199 }
200 }
201 }
202 return isolate->factory()->undefined_value();
203 }
204
HasCoverageInfo() const205 bool DebugInfo::HasCoverageInfo() const {
206 return (flags() & kHasCoverageInfo) != 0;
207 }
208
ClearCoverageInfo(Isolate * isolate)209 void DebugInfo::ClearCoverageInfo(Isolate* isolate) {
210 if (HasCoverageInfo()) {
211 set_coverage_info(ReadOnlyRoots(isolate).undefined_value());
212
213 int new_flags = flags() & ~kHasCoverageInfo;
214 set_flags(new_flags);
215 }
216 }
217
GetSideEffectState(Isolate * isolate)218 DebugInfo::SideEffectState DebugInfo::GetSideEffectState(Isolate* isolate) {
219 if (side_effect_state() == kNotComputed) {
220 SideEffectState has_no_side_effect =
221 DebugEvaluate::FunctionGetSideEffectState(isolate,
222 handle(shared(), isolate));
223 set_side_effect_state(has_no_side_effect);
224 }
225 return static_cast<SideEffectState>(side_effect_state());
226 }
227
228 namespace {
IsEqual(BreakPoint break_point1,BreakPoint break_point2)229 bool IsEqual(BreakPoint break_point1, BreakPoint break_point2) {
230 return break_point1.id() == break_point2.id();
231 }
232 } // namespace
233
234 // Remove the specified break point object.
ClearBreakPoint(Isolate * isolate,Handle<BreakPointInfo> break_point_info,Handle<BreakPoint> break_point)235 void BreakPointInfo::ClearBreakPoint(Isolate* isolate,
236 Handle<BreakPointInfo> break_point_info,
237 Handle<BreakPoint> break_point) {
238 // If there are no break points just ignore.
239 if (break_point_info->break_points().IsUndefined(isolate)) return;
240 // If there is a single break point clear it if it is the same.
241 if (!break_point_info->break_points().IsFixedArray()) {
242 if (IsEqual(BreakPoint::cast(break_point_info->break_points()),
243 *break_point)) {
244 break_point_info->set_break_points(
245 ReadOnlyRoots(isolate).undefined_value());
246 }
247 return;
248 }
249 // If there are multiple break points shrink the array
250 DCHECK(break_point_info->break_points().IsFixedArray());
251 Handle<FixedArray> old_array = Handle<FixedArray>(
252 FixedArray::cast(break_point_info->break_points()), isolate);
253 Handle<FixedArray> new_array =
254 isolate->factory()->NewFixedArray(old_array->length() - 1);
255 int found_count = 0;
256 for (int i = 0; i < old_array->length(); i++) {
257 if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) {
258 DCHECK_EQ(found_count, 0);
259 found_count++;
260 } else {
261 new_array->set(i - found_count, old_array->get(i));
262 }
263 }
264 // If the break point was found in the list change it.
265 if (found_count > 0) break_point_info->set_break_points(*new_array);
266 }
267
268 // Add the specified break point object.
SetBreakPoint(Isolate * isolate,Handle<BreakPointInfo> break_point_info,Handle<BreakPoint> break_point)269 void BreakPointInfo::SetBreakPoint(Isolate* isolate,
270 Handle<BreakPointInfo> break_point_info,
271 Handle<BreakPoint> break_point) {
272 // If there was no break point objects before just set it.
273 if (break_point_info->break_points().IsUndefined(isolate)) {
274 break_point_info->set_break_points(*break_point);
275 return;
276 }
277 // If there was one break point object before replace with array.
278 if (!break_point_info->break_points().IsFixedArray()) {
279 if (IsEqual(BreakPoint::cast(break_point_info->break_points()),
280 *break_point)) {
281 return;
282 }
283
284 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
285 array->set(0, break_point_info->break_points());
286 array->set(1, *break_point);
287 break_point_info->set_break_points(*array);
288 return;
289 }
290 // If there was more than one break point before extend array.
291 Handle<FixedArray> old_array = Handle<FixedArray>(
292 FixedArray::cast(break_point_info->break_points()), isolate);
293 Handle<FixedArray> new_array =
294 isolate->factory()->NewFixedArray(old_array->length() + 1);
295 for (int i = 0; i < old_array->length(); i++) {
296 // If the break point was there before just ignore.
297 if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) return;
298 new_array->set(i, old_array->get(i));
299 }
300 // Add the new break point.
301 new_array->set(old_array->length(), *break_point);
302 break_point_info->set_break_points(*new_array);
303 }
304
HasBreakPoint(Isolate * isolate,Handle<BreakPointInfo> break_point_info,Handle<BreakPoint> break_point)305 bool BreakPointInfo::HasBreakPoint(Isolate* isolate,
306 Handle<BreakPointInfo> break_point_info,
307 Handle<BreakPoint> break_point) {
308 // No break point.
309 if (break_point_info->break_points().IsUndefined(isolate)) {
310 return false;
311 }
312 // Single break point.
313 if (!break_point_info->break_points().IsFixedArray()) {
314 return IsEqual(BreakPoint::cast(break_point_info->break_points()),
315 *break_point);
316 }
317 // Multiple break points.
318 FixedArray array = FixedArray::cast(break_point_info->break_points());
319 for (int i = 0; i < array.length(); i++) {
320 if (IsEqual(BreakPoint::cast(array.get(i)), *break_point)) {
321 return true;
322 }
323 }
324 return false;
325 }
326
GetBreakPointById(Isolate * isolate,Handle<BreakPointInfo> break_point_info,int breakpoint_id)327 MaybeHandle<BreakPoint> BreakPointInfo::GetBreakPointById(
328 Isolate* isolate, Handle<BreakPointInfo> break_point_info,
329 int breakpoint_id) {
330 // No break point.
331 if (break_point_info->break_points().IsUndefined(isolate)) {
332 return MaybeHandle<BreakPoint>();
333 }
334 // Single break point.
335 if (!break_point_info->break_points().IsFixedArray()) {
336 BreakPoint breakpoint = BreakPoint::cast(break_point_info->break_points());
337 if (breakpoint.id() == breakpoint_id) {
338 return handle(breakpoint, isolate);
339 }
340 } else {
341 // Multiple break points.
342 FixedArray array = FixedArray::cast(break_point_info->break_points());
343 for (int i = 0; i < array.length(); i++) {
344 BreakPoint breakpoint = BreakPoint::cast(array.get(i));
345 if (breakpoint.id() == breakpoint_id) {
346 return handle(breakpoint, isolate);
347 }
348 }
349 }
350 return MaybeHandle<BreakPoint>();
351 }
352
353 // Get the number of break points.
GetBreakPointCount(Isolate * isolate)354 int BreakPointInfo::GetBreakPointCount(Isolate* isolate) {
355 // No break point.
356 if (break_points().IsUndefined(isolate)) return 0;
357 // Single break point.
358 if (!break_points().IsFixedArray()) return 1;
359 // Multiple break points.
360 return FixedArray::cast(break_points()).length();
361 }
362
SlotFieldOffset(int slot_index,int field_offset) const363 int CoverageInfo::SlotFieldOffset(int slot_index, int field_offset) const {
364 DCHECK_LT(field_offset, Slot::kSize);
365 DCHECK_LT(slot_index, slot_count());
366 return kSlotsOffset + slot_index * Slot::kSize + field_offset;
367 }
368
StartSourcePosition(int slot_index) const369 int CoverageInfo::StartSourcePosition(int slot_index) const {
370 return ReadField<int32_t>(
371 SlotFieldOffset(slot_index, Slot::kStartSourcePositionOffset));
372 }
373
EndSourcePosition(int slot_index) const374 int CoverageInfo::EndSourcePosition(int slot_index) const {
375 return ReadField<int32_t>(
376 SlotFieldOffset(slot_index, Slot::kEndSourcePositionOffset));
377 }
378
BlockCount(int slot_index) const379 int CoverageInfo::BlockCount(int slot_index) const {
380 return ReadField<int32_t>(
381 SlotFieldOffset(slot_index, Slot::kBlockCountOffset));
382 }
383
InitializeSlot(int slot_index,int from_pos,int to_pos)384 void CoverageInfo::InitializeSlot(int slot_index, int from_pos, int to_pos) {
385 WriteField<int32_t>(
386 SlotFieldOffset(slot_index, Slot::kStartSourcePositionOffset), from_pos);
387 WriteField<int32_t>(
388 SlotFieldOffset(slot_index, Slot::kEndSourcePositionOffset), to_pos);
389 ResetBlockCount(slot_index);
390 WriteField<int32_t>(SlotFieldOffset(slot_index, Slot::kPaddingOffset), 0);
391 }
392
ResetBlockCount(int slot_index)393 void CoverageInfo::ResetBlockCount(int slot_index) {
394 WriteField<int32_t>(SlotFieldOffset(slot_index, Slot::kBlockCountOffset), 0);
395 }
396
CoverageInfoPrint(std::ostream & os,std::unique_ptr<char[]> function_name)397 void CoverageInfo::CoverageInfoPrint(std::ostream& os,
398 std::unique_ptr<char[]> function_name) {
399 DCHECK(FLAG_trace_block_coverage);
400 DisallowHeapAllocation no_gc;
401
402 os << "Coverage info (";
403 if (function_name == nullptr) {
404 os << "{unknown}";
405 } else if (strlen(function_name.get()) > 0) {
406 os << function_name.get();
407 } else {
408 os << "{anonymous}";
409 }
410 os << "):" << std::endl;
411
412 for (int i = 0; i < slot_count(); i++) {
413 os << "{" << StartSourcePosition(i) << "," << EndSourcePosition(i) << "}"
414 << std::endl;
415 }
416 }
417
418 } // namespace internal
419 } // namespace v8
420