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