Line data Source code
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/objects/debug-objects-inl.h"
7 :
8 : namespace v8 {
9 : namespace internal {
10 :
11 0 : bool DebugInfo::IsEmpty() const { return flags() == kNone; }
12 :
13 617026 : bool DebugInfo::HasBreakInfo() const { return (flags() & kHasBreakInfo) != 0; }
14 :
15 64481 : bool DebugInfo::IsPreparedForBreakpoints() const {
16 : DCHECK(HasBreakInfo());
17 64481 : return (flags() & kPreparedForBreakpoints) != 0;
18 : }
19 :
20 8341 : bool DebugInfo::ClearBreakInfo() {
21 : Isolate* isolate = GetIsolate();
22 :
23 8341 : set_debug_bytecode_array(isolate->heap()->undefined_value());
24 8341 : set_break_points(isolate->heap()->empty_fixed_array());
25 :
26 8341 : int new_flags = flags() & ~kHasBreakInfo & ~kPreparedForBreakpoints;
27 : set_flags(new_flags);
28 :
29 8341 : return new_flags == kNone;
30 : }
31 :
32 : // Check if there is a break point at this source position.
33 60514 : bool DebugInfo::HasBreakPoint(int source_position) {
34 : DCHECK(HasBreakInfo());
35 : // Get the break point info object for this code offset.
36 60514 : Object* break_point_info = GetBreakPointInfo(source_position);
37 :
38 : // If there is no break point info object or no break points in the break
39 : // point info object there is no break point at this code offset.
40 60514 : if (break_point_info->IsUndefined(GetIsolate())) return false;
41 4152 : return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
42 : }
43 :
44 : // Get the break point info object for this source position.
45 66909 : Object* DebugInfo::GetBreakPointInfo(int source_position) {
46 : DCHECK(HasBreakInfo());
47 : Isolate* isolate = GetIsolate();
48 66909 : if (!break_points()->IsUndefined(isolate)) {
49 537499 : for (int i = 0; i < break_points()->length(); i++) {
50 243662 : if (!break_points()->get(i)->IsUndefined(isolate)) {
51 : BreakPointInfo* break_point_info =
52 : BreakPointInfo::cast(break_points()->get(i));
53 36642 : if (break_point_info->source_position() == source_position) {
54 : return break_point_info;
55 : }
56 : }
57 : }
58 : }
59 58542 : return isolate->heap()->undefined_value();
60 : }
61 :
62 894 : bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
63 : Handle<Object> break_point_object) {
64 : DCHECK(debug_info->HasBreakInfo());
65 : Isolate* isolate = debug_info->GetIsolate();
66 894 : if (debug_info->break_points()->IsUndefined(isolate)) return false;
67 :
68 1112 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
69 1003 : if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
70 : Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
71 : BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
72 1003 : if (BreakPointInfo::HasBreakPointObject(break_point_info,
73 : break_point_object)) {
74 894 : BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object);
75 894 : return true;
76 : }
77 : }
78 : return false;
79 : }
80 :
81 2359 : void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
82 : Handle<Object> break_point_object) {
83 : DCHECK(debug_info->HasBreakInfo());
84 : Isolate* isolate = debug_info->GetIsolate();
85 : Handle<Object> break_point_info(
86 2359 : debug_info->GetBreakPointInfo(source_position), isolate);
87 2359 : if (!break_point_info->IsUndefined(isolate)) {
88 : BreakPointInfo::SetBreakPoint(
89 179 : Handle<BreakPointInfo>::cast(break_point_info), break_point_object);
90 2538 : return;
91 : }
92 :
93 : // Adding a new break point for a code offset which did not have any
94 : // break points before. Try to find a free slot.
95 : static const int kNoBreakPointInfo = -1;
96 : int index = kNoBreakPointInfo;
97 3410 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
98 2780 : if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
99 : index = i;
100 : break;
101 : }
102 : }
103 2180 : if (index == kNoBreakPointInfo) {
104 : // No free slot - extend break point info array.
105 : Handle<FixedArray> old_break_points = Handle<FixedArray>(
106 : FixedArray::cast(debug_info->break_points()), isolate);
107 : Handle<FixedArray> new_break_points = isolate->factory()->NewFixedArray(
108 : old_break_points->length() +
109 15 : DebugInfo::kEstimatedNofBreakPointsInFunction);
110 :
111 15 : debug_info->set_break_points(*new_break_points);
112 150 : for (int i = 0; i < old_break_points->length(); i++) {
113 60 : new_break_points->set(i, old_break_points->get(i));
114 : }
115 : index = old_break_points->length();
116 : }
117 : DCHECK_NE(index, kNoBreakPointInfo);
118 :
119 : // Allocate new BreakPointInfo object and set the break point.
120 : Handle<BreakPointInfo> new_break_point_info =
121 2180 : isolate->factory()->NewBreakPointInfo(source_position);
122 2180 : BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
123 2180 : debug_info->break_points()->set(index, *new_break_point_info);
124 : }
125 :
126 : // Get the break point objects for a source position.
127 4036 : Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) {
128 : DCHECK(HasBreakInfo());
129 4036 : Object* break_point_info = GetBreakPointInfo(source_position);
130 : Isolate* isolate = GetIsolate();
131 4036 : if (break_point_info->IsUndefined(isolate)) {
132 0 : return isolate->factory()->undefined_value();
133 : }
134 : return Handle<Object>(
135 4036 : BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate);
136 : }
137 :
138 : // Get the total number of break points.
139 1326 : int DebugInfo::GetBreakPointCount() {
140 : DCHECK(HasBreakInfo());
141 : Isolate* isolate = GetIsolate();
142 1326 : if (break_points()->IsUndefined(isolate)) return 0;
143 : int count = 0;
144 11934 : for (int i = 0; i < break_points()->length(); i++) {
145 5304 : if (!break_points()->get(i)->IsUndefined(isolate)) {
146 : BreakPointInfo* break_point_info =
147 : BreakPointInfo::cast(break_points()->get(i));
148 1994 : count += break_point_info->GetBreakPointCount();
149 : }
150 : }
151 : return count;
152 : }
153 :
154 1204 : Handle<Object> DebugInfo::FindBreakPointInfo(
155 : Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
156 : DCHECK(debug_info->HasBreakInfo());
157 : Isolate* isolate = debug_info->GetIsolate();
158 1204 : if (!debug_info->break_points()->IsUndefined(isolate)) {
159 3902 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
160 2243 : if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
161 : Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
162 : BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
163 1318 : if (BreakPointInfo::HasBreakPointObject(break_point_info,
164 : break_point_object)) {
165 894 : return break_point_info;
166 : }
167 : }
168 : }
169 : }
170 310 : return isolate->factory()->undefined_value();
171 : }
172 :
173 232585 : bool DebugInfo::HasCoverageInfo() const {
174 233366 : return (flags() & kHasCoverageInfo) != 0;
175 : }
176 :
177 781 : bool DebugInfo::ClearCoverageInfo() {
178 781 : if (HasCoverageInfo()) {
179 : Isolate* isolate = GetIsolate();
180 :
181 781 : set_coverage_info(isolate->heap()->undefined_value());
182 :
183 781 : int new_flags = flags() & ~kHasCoverageInfo;
184 : set_flags(new_flags);
185 : }
186 781 : return flags() == kNone;
187 : }
188 :
189 : namespace {
190 3962 : bool IsEqual(Object* break_point1, Object* break_point2) {
191 : // TODO(kozyatinskiy): remove non-BreakPoint logic once the JS debug API has
192 : // been removed.
193 3962 : if (break_point1->IsBreakPoint() != break_point2->IsBreakPoint())
194 : return false;
195 3962 : if (!break_point1->IsBreakPoint()) return break_point1 == break_point2;
196 : return BreakPoint::cast(break_point1)->id() ==
197 3162 : BreakPoint::cast(break_point2)->id();
198 : }
199 : } // namespace
200 :
201 : // Remove the specified break point object.
202 894 : void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
203 : Handle<Object> break_point_object) {
204 : Isolate* isolate = break_point_info->GetIsolate();
205 : // If there are no break points just ignore.
206 894 : if (break_point_info->break_point_objects()->IsUndefined(isolate)) return;
207 : // If there is a single break point clear it if it is the same.
208 894 : if (!break_point_info->break_point_objects()->IsFixedArray()) {
209 874 : if (IsEqual(break_point_info->break_point_objects(), *break_point_object)) {
210 : break_point_info->set_break_point_objects(
211 1748 : isolate->heap()->undefined_value());
212 : }
213 : return;
214 : }
215 : // If there are multiple break points shrink the array
216 : DCHECK(break_point_info->break_point_objects()->IsFixedArray());
217 : Handle<FixedArray> old_array = Handle<FixedArray>(
218 : FixedArray::cast(break_point_info->break_point_objects()));
219 : Handle<FixedArray> new_array =
220 20 : isolate->factory()->NewFixedArray(old_array->length() - 1);
221 : int found_count = 0;
222 110 : for (int i = 0; i < old_array->length(); i++) {
223 35 : if (IsEqual(old_array->get(i), *break_point_object)) {
224 : DCHECK_EQ(found_count, 0);
225 20 : found_count++;
226 : } else {
227 30 : new_array->set(i - found_count, old_array->get(i));
228 : }
229 : }
230 : // If the break point was found in the list change it.
231 40 : if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
232 : }
233 :
234 : // Add the specified break point object.
235 2453 : void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
236 : Handle<Object> break_point_object) {
237 : Isolate* isolate = break_point_info->GetIsolate();
238 :
239 : // If there was no break point objects before just set it.
240 2453 : if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
241 2274 : break_point_info->set_break_point_objects(*break_point_object);
242 2274 : return;
243 : }
244 : // If the break point object is the same as before just ignore.
245 179 : if (break_point_info->break_point_objects() == *break_point_object) return;
246 : // If there was one break point object before replace with array.
247 179 : if (!break_point_info->break_point_objects()->IsFixedArray()) {
248 49 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
249 49 : array->set(0, break_point_info->break_point_objects());
250 49 : array->set(1, *break_point_object);
251 49 : break_point_info->set_break_point_objects(*array);
252 : return;
253 : }
254 : // If there was more than one break point before extend array.
255 : Handle<FixedArray> old_array = Handle<FixedArray>(
256 : FixedArray::cast(break_point_info->break_point_objects()));
257 : Handle<FixedArray> new_array =
258 130 : isolate->factory()->NewFixedArray(old_array->length() + 1);
259 2230 : for (int i = 0; i < old_array->length(); i++) {
260 : // If the break point was there before just ignore.
261 985 : if (IsEqual(old_array->get(i), *break_point_object)) return;
262 985 : new_array->set(i, old_array->get(i));
263 : }
264 : // Add the new break point.
265 130 : new_array->set(old_array->length(), *break_point_object);
266 130 : break_point_info->set_break_point_objects(*new_array);
267 : }
268 :
269 2321 : bool BreakPointInfo::HasBreakPointObject(
270 : Handle<BreakPointInfo> break_point_info,
271 : Handle<Object> break_point_object) {
272 : // No break point.
273 : Isolate* isolate = break_point_info->GetIsolate();
274 2321 : if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
275 : return false;
276 : }
277 : // Single break point.
278 2058 : if (!break_point_info->break_point_objects()->IsFixedArray()) {
279 : return IsEqual(break_point_info->break_point_objects(),
280 2018 : *break_point_object);
281 : }
282 : // Multiple break points.
283 : FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
284 100 : for (int i = 0; i < array->length(); i++) {
285 50 : if (IsEqual(array->get(i), *break_point_object)) {
286 : return true;
287 : }
288 : }
289 : return false;
290 : }
291 :
292 : // Get the number of break points.
293 66615 : int BreakPointInfo::GetBreakPointCount() {
294 : // No break point.
295 66615 : if (break_point_objects()->IsUndefined(GetIsolate())) return 0;
296 : // Single break point.
297 65243 : if (!break_point_objects()->IsFixedArray()) return 1;
298 : // Multiple break points.
299 591 : return FixedArray::cast(break_point_objects())->length();
300 : }
301 :
302 96236 : int CoverageInfo::SlotCount() const {
303 : DCHECK_EQ(kFirstSlotIndex, length() % kSlotIndexCount);
304 96236 : return (length() - kFirstSlotIndex) / kSlotIndexCount;
305 : }
306 :
307 38308 : int CoverageInfo::StartSourcePosition(int slot_index) const {
308 : DCHECK_LT(slot_index, SlotCount());
309 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
310 38308 : return Smi::ToInt(get(slot_start + kSlotStartSourcePositionIndex));
311 : }
312 :
313 38308 : int CoverageInfo::EndSourcePosition(int slot_index) const {
314 : DCHECK_LT(slot_index, SlotCount());
315 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
316 76616 : return Smi::ToInt(get(slot_start + kSlotEndSourcePositionIndex));
317 : }
318 :
319 262953 : int CoverageInfo::BlockCount(int slot_index) const {
320 : DCHECK_LT(slot_index, SlotCount());
321 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
322 525906 : return Smi::ToInt(get(slot_start + kSlotBlockCountIndex));
323 : }
324 :
325 3169 : void CoverageInfo::InitializeSlot(int slot_index, int from_pos, int to_pos) {
326 : DCHECK_LT(slot_index, SlotCount());
327 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
328 : set(slot_start + kSlotStartSourcePositionIndex, Smi::FromInt(from_pos));
329 : set(slot_start + kSlotEndSourcePositionIndex, Smi::FromInt(to_pos));
330 : set(slot_start + kSlotBlockCountIndex, Smi::kZero);
331 3169 : }
332 :
333 224645 : void CoverageInfo::IncrementBlockCount(int slot_index) {
334 : DCHECK_LT(slot_index, SlotCount());
335 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
336 224645 : const int old_count = BlockCount(slot_index);
337 224645 : set(slot_start + kSlotBlockCountIndex, Smi::FromInt(old_count + 1));
338 224645 : }
339 :
340 38308 : void CoverageInfo::ResetBlockCount(int slot_index) {
341 : DCHECK_LT(slot_index, SlotCount());
342 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
343 : set(slot_start + kSlotBlockCountIndex, Smi::kZero);
344 38308 : }
345 :
346 0 : void CoverageInfo::Print(String* function_name) {
347 : DCHECK(FLAG_trace_block_coverage);
348 : DisallowHeapAllocation no_gc;
349 :
350 0 : OFStream os(stdout);
351 0 : os << "Coverage info (";
352 0 : if (function_name->length() > 0) {
353 0 : auto function_name_cstr = function_name->ToCString();
354 0 : os << function_name_cstr.get();
355 : } else {
356 0 : os << "{anonymous}";
357 : }
358 0 : os << "):" << std::endl;
359 :
360 0 : for (int i = 0; i < SlotCount(); i++) {
361 0 : os << "{" << StartSourcePosition(i) << "," << EndSourcePosition(i) << "}"
362 : << std::endl;
363 0 : }
364 0 : }
365 :
366 : } // namespace internal
367 : } // namespace v8
|