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