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