• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "src/debug/debug-evaluate.h"
7 #include "src/objects/debug-objects-inl.h"
8 
9 namespace v8 {
10 namespace internal {
11 
IsEmpty() const12 bool DebugInfo::IsEmpty() const {
13   return flags() == kNone && debugger_hints() == 0;
14 }
15 
HasBreakInfo() const16 bool DebugInfo::HasBreakInfo() const { return (flags() & kHasBreakInfo) != 0; }
17 
DebugExecutionMode() const18 DebugInfo::ExecutionMode DebugInfo::DebugExecutionMode() const {
19   return (flags() & kDebugExecutionMode) != 0 ? kSideEffects : kBreakpoints;
20 }
21 
SetDebugExecutionMode(ExecutionMode value)22 void DebugInfo::SetDebugExecutionMode(ExecutionMode value) {
23   set_flags(value == kSideEffects ? (flags() | kDebugExecutionMode)
24                                   : (flags() & ~kDebugExecutionMode));
25 }
26 
ClearBreakInfo(Isolate * isolate)27 void DebugInfo::ClearBreakInfo(Isolate* isolate) {
28   if (HasInstrumentedBytecodeArray()) {
29     // Reset function's bytecode array field to point to the original bytecode
30     // array.
31     shared()->SetDebugBytecodeArray(OriginalBytecodeArray());
32     set_original_bytecode_array(ReadOnlyRoots(isolate).undefined_value());
33   }
34   set_break_points(ReadOnlyRoots(isolate).empty_fixed_array());
35 
36   int new_flags = flags();
37   new_flags &= ~kHasBreakInfo & ~kPreparedForDebugExecution;
38   new_flags &= ~kBreakAtEntry & ~kCanBreakAtEntry;
39   new_flags &= ~kDebugExecutionMode;
40   set_flags(new_flags);
41 }
42 
SetBreakAtEntry()43 void DebugInfo::SetBreakAtEntry() {
44   DCHECK(CanBreakAtEntry());
45   set_flags(flags() | kBreakAtEntry);
46 }
47 
ClearBreakAtEntry()48 void DebugInfo::ClearBreakAtEntry() {
49   DCHECK(CanBreakAtEntry());
50   set_flags(flags() & ~kBreakAtEntry);
51 }
52 
BreakAtEntry() const53 bool DebugInfo::BreakAtEntry() const { return (flags() & kBreakAtEntry) != 0; }
54 
CanBreakAtEntry() const55 bool DebugInfo::CanBreakAtEntry() const {
56   return (flags() & kCanBreakAtEntry) != 0;
57 }
58 
59 // Check if there is a break point at this source position.
HasBreakPoint(Isolate * isolate,int source_position)60 bool DebugInfo::HasBreakPoint(Isolate* isolate, int source_position) {
61   DCHECK(HasBreakInfo());
62   // Get the break point info object for this code offset.
63   Object* break_point_info = GetBreakPointInfo(isolate, source_position);
64 
65   // If there is no break point info object or no break points in the break
66   // point info object there is no break point at this code offset.
67   if (break_point_info->IsUndefined(isolate)) return false;
68   return BreakPointInfo::cast(break_point_info)->GetBreakPointCount(isolate) >
69          0;
70 }
71 
72 // Get the break point info object for this source position.
GetBreakPointInfo(Isolate * isolate,int source_position)73 Object* DebugInfo::GetBreakPointInfo(Isolate* isolate, int source_position) {
74   DCHECK(HasBreakInfo());
75   for (int i = 0; i < break_points()->length(); i++) {
76     if (!break_points()->get(i)->IsUndefined(isolate)) {
77       BreakPointInfo* break_point_info =
78           BreakPointInfo::cast(break_points()->get(i));
79       if (break_point_info->source_position() == source_position) {
80         return break_point_info;
81       }
82     }
83   }
84   return ReadOnlyRoots(isolate).undefined_value();
85 }
86 
ClearBreakPoint(Isolate * isolate,Handle<DebugInfo> debug_info,Handle<BreakPoint> break_point)87 bool DebugInfo::ClearBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info,
88                                 Handle<BreakPoint> break_point) {
89   DCHECK(debug_info->HasBreakInfo());
90   for (int i = 0; i < debug_info->break_points()->length(); i++) {
91     if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
92     Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
93         BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
94     if (BreakPointInfo::HasBreakPoint(isolate, break_point_info, break_point)) {
95       BreakPointInfo::ClearBreakPoint(isolate, break_point_info, break_point);
96       return true;
97     }
98   }
99   return false;
100 }
101 
SetBreakPoint(Isolate * isolate,Handle<DebugInfo> debug_info,int source_position,Handle<BreakPoint> break_point)102 void DebugInfo::SetBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info,
103                               int source_position,
104                               Handle<BreakPoint> break_point) {
105   DCHECK(debug_info->HasBreakInfo());
106   Handle<Object> break_point_info(
107       debug_info->GetBreakPointInfo(isolate, source_position), isolate);
108   if (!break_point_info->IsUndefined(isolate)) {
109     BreakPointInfo::SetBreakPoint(
110         isolate, Handle<BreakPointInfo>::cast(break_point_info), break_point);
111     return;
112   }
113 
114   // Adding a new break point for a code offset which did not have any
115   // break points before. Try to find a free slot.
116   static const int kNoBreakPointInfo = -1;
117   int index = kNoBreakPointInfo;
118   for (int i = 0; i < debug_info->break_points()->length(); i++) {
119     if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
120       index = i;
121       break;
122     }
123   }
124   if (index == kNoBreakPointInfo) {
125     // No free slot - extend break point info array.
126     Handle<FixedArray> old_break_points =
127         Handle<FixedArray>(debug_info->break_points(), isolate);
128     Handle<FixedArray> new_break_points = isolate->factory()->NewFixedArray(
129         old_break_points->length() +
130         DebugInfo::kEstimatedNofBreakPointsInFunction);
131 
132     debug_info->set_break_points(*new_break_points);
133     for (int i = 0; i < old_break_points->length(); i++) {
134       new_break_points->set(i, old_break_points->get(i));
135     }
136     index = old_break_points->length();
137   }
138   DCHECK_NE(index, kNoBreakPointInfo);
139 
140   // Allocate new BreakPointInfo object and set the break point.
141   Handle<BreakPointInfo> new_break_point_info =
142       isolate->factory()->NewBreakPointInfo(source_position);
143   BreakPointInfo::SetBreakPoint(isolate, new_break_point_info, break_point);
144   debug_info->break_points()->set(index, *new_break_point_info);
145 }
146 
147 // Get the break point objects for a source position.
GetBreakPoints(Isolate * isolate,int source_position)148 Handle<Object> DebugInfo::GetBreakPoints(Isolate* isolate,
149                                          int source_position) {
150   DCHECK(HasBreakInfo());
151   Object* break_point_info = GetBreakPointInfo(isolate, source_position);
152   if (break_point_info->IsUndefined(isolate)) {
153     return isolate->factory()->undefined_value();
154   }
155   return Handle<Object>(BreakPointInfo::cast(break_point_info)->break_points(),
156                         isolate);
157 }
158 
159 // Get the total number of break points.
GetBreakPointCount(Isolate * isolate)160 int DebugInfo::GetBreakPointCount(Isolate* isolate) {
161   DCHECK(HasBreakInfo());
162   int count = 0;
163   for (int i = 0; i < break_points()->length(); i++) {
164     if (!break_points()->get(i)->IsUndefined(isolate)) {
165       BreakPointInfo* break_point_info =
166           BreakPointInfo::cast(break_points()->get(i));
167       count += break_point_info->GetBreakPointCount(isolate);
168     }
169   }
170   return count;
171 }
172 
FindBreakPointInfo(Isolate * isolate,Handle<DebugInfo> debug_info,Handle<BreakPoint> break_point)173 Handle<Object> DebugInfo::FindBreakPointInfo(Isolate* isolate,
174                                              Handle<DebugInfo> debug_info,
175                                              Handle<BreakPoint> break_point) {
176   DCHECK(debug_info->HasBreakInfo());
177   for (int i = 0; i < debug_info->break_points()->length(); i++) {
178     if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
179       Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
180           BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
181       if (BreakPointInfo::HasBreakPoint(isolate, break_point_info,
182                                         break_point)) {
183         return break_point_info;
184       }
185     }
186   }
187   return isolate->factory()->undefined_value();
188 }
189 
HasCoverageInfo() const190 bool DebugInfo::HasCoverageInfo() const {
191   return (flags() & kHasCoverageInfo) != 0;
192 }
193 
ClearCoverageInfo(Isolate * isolate)194 void DebugInfo::ClearCoverageInfo(Isolate* isolate) {
195   if (HasCoverageInfo()) {
196     set_coverage_info(ReadOnlyRoots(isolate).undefined_value());
197 
198     int new_flags = flags() & ~kHasCoverageInfo;
199     set_flags(new_flags);
200   }
201 }
202 
GetSideEffectState(Isolate * isolate)203 DebugInfo::SideEffectState DebugInfo::GetSideEffectState(Isolate* isolate) {
204   if (side_effect_state() == kNotComputed) {
205     SideEffectState has_no_side_effect =
206         DebugEvaluate::FunctionGetSideEffectState(isolate,
207                                                   handle(shared(), isolate));
208     set_side_effect_state(has_no_side_effect);
209   }
210   return static_cast<SideEffectState>(side_effect_state());
211 }
212 
213 namespace {
IsEqual(BreakPoint * break_point1,BreakPoint * break_point2)214 bool IsEqual(BreakPoint* break_point1, BreakPoint* break_point2) {
215   return break_point1->id() == break_point2->id();
216 }
217 }  // namespace
218 
219 // Remove the specified break point object.
ClearBreakPoint(Isolate * isolate,Handle<BreakPointInfo> break_point_info,Handle<BreakPoint> break_point)220 void BreakPointInfo::ClearBreakPoint(Isolate* isolate,
221                                      Handle<BreakPointInfo> break_point_info,
222                                      Handle<BreakPoint> break_point) {
223   // If there are no break points just ignore.
224   if (break_point_info->break_points()->IsUndefined(isolate)) return;
225   // If there is a single break point clear it if it is the same.
226   if (!break_point_info->break_points()->IsFixedArray()) {
227     if (IsEqual(BreakPoint::cast(break_point_info->break_points()),
228                 *break_point)) {
229       break_point_info->set_break_points(
230           ReadOnlyRoots(isolate).undefined_value());
231     }
232     return;
233   }
234   // If there are multiple break points shrink the array
235   DCHECK(break_point_info->break_points()->IsFixedArray());
236   Handle<FixedArray> old_array = Handle<FixedArray>(
237       FixedArray::cast(break_point_info->break_points()), isolate);
238   Handle<FixedArray> new_array =
239       isolate->factory()->NewFixedArray(old_array->length() - 1);
240   int found_count = 0;
241   for (int i = 0; i < old_array->length(); i++) {
242     if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) {
243       DCHECK_EQ(found_count, 0);
244       found_count++;
245     } else {
246       new_array->set(i - found_count, old_array->get(i));
247     }
248   }
249   // If the break point was found in the list change it.
250   if (found_count > 0) break_point_info->set_break_points(*new_array);
251 }
252 
253 // Add the specified break point object.
SetBreakPoint(Isolate * isolate,Handle<BreakPointInfo> break_point_info,Handle<BreakPoint> break_point)254 void BreakPointInfo::SetBreakPoint(Isolate* isolate,
255                                    Handle<BreakPointInfo> break_point_info,
256                                    Handle<BreakPoint> break_point) {
257   // If there was no break point objects before just set it.
258   if (break_point_info->break_points()->IsUndefined(isolate)) {
259     break_point_info->set_break_points(*break_point);
260     return;
261   }
262   // If the break point object is the same as before just ignore.
263   if (break_point_info->break_points() == *break_point) return;
264   // If there was one break point object before replace with array.
265   if (!break_point_info->break_points()->IsFixedArray()) {
266     Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
267     array->set(0, break_point_info->break_points());
268     array->set(1, *break_point);
269     break_point_info->set_break_points(*array);
270     return;
271   }
272   // If there was more than one break point before extend array.
273   Handle<FixedArray> old_array = Handle<FixedArray>(
274       FixedArray::cast(break_point_info->break_points()), isolate);
275   Handle<FixedArray> new_array =
276       isolate->factory()->NewFixedArray(old_array->length() + 1);
277   for (int i = 0; i < old_array->length(); i++) {
278     // If the break point was there before just ignore.
279     if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) return;
280     new_array->set(i, old_array->get(i));
281   }
282   // Add the new break point.
283   new_array->set(old_array->length(), *break_point);
284   break_point_info->set_break_points(*new_array);
285 }
286 
HasBreakPoint(Isolate * isolate,Handle<BreakPointInfo> break_point_info,Handle<BreakPoint> break_point)287 bool BreakPointInfo::HasBreakPoint(Isolate* isolate,
288                                    Handle<BreakPointInfo> break_point_info,
289                                    Handle<BreakPoint> break_point) {
290   // No break point.
291   if (break_point_info->break_points()->IsUndefined(isolate)) {
292     return false;
293   }
294   // Single break point.
295   if (!break_point_info->break_points()->IsFixedArray()) {
296     return IsEqual(BreakPoint::cast(break_point_info->break_points()),
297                    *break_point);
298   }
299   // Multiple break points.
300   FixedArray* array = FixedArray::cast(break_point_info->break_points());
301   for (int i = 0; i < array->length(); i++) {
302     if (IsEqual(BreakPoint::cast(array->get(i)), *break_point)) {
303       return true;
304     }
305   }
306   return false;
307 }
308 
309 // Get the number of break points.
GetBreakPointCount(Isolate * isolate)310 int BreakPointInfo::GetBreakPointCount(Isolate* isolate) {
311   // No break point.
312   if (break_points()->IsUndefined(isolate)) return 0;
313   // Single break point.
314   if (!break_points()->IsFixedArray()) return 1;
315   // Multiple break points.
316   return FixedArray::cast(break_points())->length();
317 }
318 
SlotCount() const319 int CoverageInfo::SlotCount() const {
320   DCHECK_EQ(kFirstSlotIndex, length() % kSlotIndexCount);
321   return (length() - kFirstSlotIndex) / kSlotIndexCount;
322 }
323 
StartSourcePosition(int slot_index) const324 int CoverageInfo::StartSourcePosition(int slot_index) const {
325   DCHECK_LT(slot_index, SlotCount());
326   const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
327   return Smi::ToInt(get(slot_start + kSlotStartSourcePositionIndex));
328 }
329 
EndSourcePosition(int slot_index) const330 int CoverageInfo::EndSourcePosition(int slot_index) const {
331   DCHECK_LT(slot_index, SlotCount());
332   const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
333   return Smi::ToInt(get(slot_start + kSlotEndSourcePositionIndex));
334 }
335 
BlockCount(int slot_index) const336 int CoverageInfo::BlockCount(int slot_index) const {
337   DCHECK_LT(slot_index, SlotCount());
338   const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
339   return Smi::ToInt(get(slot_start + kSlotBlockCountIndex));
340 }
341 
InitializeSlot(int slot_index,int from_pos,int to_pos)342 void CoverageInfo::InitializeSlot(int slot_index, int from_pos, int to_pos) {
343   DCHECK_LT(slot_index, SlotCount());
344   const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
345   set(slot_start + kSlotStartSourcePositionIndex, Smi::FromInt(from_pos));
346   set(slot_start + kSlotEndSourcePositionIndex, Smi::FromInt(to_pos));
347   set(slot_start + kSlotBlockCountIndex, Smi::kZero);
348 }
349 
IncrementBlockCount(int slot_index)350 void CoverageInfo::IncrementBlockCount(int slot_index) {
351   DCHECK_LT(slot_index, SlotCount());
352   const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
353   const int old_count = BlockCount(slot_index);
354   set(slot_start + kSlotBlockCountIndex, Smi::FromInt(old_count + 1));
355 }
356 
ResetBlockCount(int slot_index)357 void CoverageInfo::ResetBlockCount(int slot_index) {
358   DCHECK_LT(slot_index, SlotCount());
359   const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
360   set(slot_start + kSlotBlockCountIndex, Smi::kZero);
361 }
362 
Print(std::unique_ptr<char[]> function_name)363 void CoverageInfo::Print(std::unique_ptr<char[]> function_name) {
364   DCHECK(FLAG_trace_block_coverage);
365   DisallowHeapAllocation no_gc;
366 
367   StdoutStream os;
368   os << "Coverage info (";
369   if (strlen(function_name.get()) > 0) {
370     os << function_name.get();
371   } else {
372     os << "{anonymous}";
373   }
374   os << "):" << std::endl;
375 
376   for (int i = 0; i < SlotCount(); i++) {
377     os << "{" << StartSourcePosition(i) << "," << EndSourcePosition(i) << "}"
378        << std::endl;
379   }
380 }
381 
382 }  // namespace internal
383 }  // namespace v8
384