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 :
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 58617 : bool DebugInfo::IsEmpty() const {
16 117046 : return flags() == kNone && debugger_hints() == 0;
17 : }
18 :
19 3251814 : bool DebugInfo::HasBreakInfo() const { return (flags() & kHasBreakInfo) != 0; }
20 :
21 12975 : DebugInfo::ExecutionMode DebugInfo::DebugExecutionMode() const {
22 12975 : return (flags() & kDebugExecutionMode) != 0 ? kSideEffects : kBreakpoints;
23 : }
24 :
25 1138056 : void DebugInfo::SetDebugExecutionMode(ExecutionMode value) {
26 : set_flags(value == kSideEffects ? (flags() | kDebugExecutionMode)
27 2276112 : : (flags() & ~kDebugExecutionMode));
28 1138056 : }
29 :
30 28349 : void DebugInfo::ClearBreakInfo(Isolate* isolate) {
31 28349 : if (HasInstrumentedBytecodeArray()) {
32 : // Reset function's bytecode array field to point to the original bytecode
33 : // array.
34 10577 : shared()->SetDebugBytecodeArray(OriginalBytecodeArray());
35 10577 : set_original_bytecode_array(ReadOnlyRoots(isolate).undefined_value());
36 10577 : set_debug_bytecode_array(ReadOnlyRoots(isolate).undefined_value());
37 : }
38 28349 : 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 28349 : new_flags &= ~kDebugExecutionMode;
44 : set_flags(new_flags);
45 28349 : }
46 :
47 585 : void DebugInfo::SetBreakAtEntry() {
48 : DCHECK(CanBreakAtEntry());
49 585 : set_flags(flags() | kBreakAtEntry);
50 585 : }
51 :
52 735 : void DebugInfo::ClearBreakAtEntry() {
53 : DCHECK(CanBreakAtEntry());
54 735 : set_flags(flags() & ~kBreakAtEntry);
55 735 : }
56 :
57 10208 : bool DebugInfo::BreakAtEntry() const { return (flags() & kBreakAtEntry) != 0; }
58 :
59 2987554 : bool DebugInfo::CanBreakAtEntry() const {
60 2987554 : return (flags() & kCanBreakAtEntry) != 0;
61 : }
62 :
63 : // Check if there is a break point at this source position.
64 186838 : bool DebugInfo::HasBreakPoint(Isolate* isolate, int source_position) {
65 : DCHECK(HasBreakInfo());
66 : // Get the break point info object for this code offset.
67 186838 : 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 186838 : if (break_point_info->IsUndefined(isolate)) return false;
72 8500 : return BreakPointInfo::cast(break_point_info)->GetBreakPointCount(isolate) >
73 4250 : 0;
74 : }
75 :
76 : // Get the break point info object for this source position.
77 193470 : Object DebugInfo::GetBreakPointInfo(Isolate* isolate, int source_position) {
78 : DCHECK(HasBreakInfo());
79 1868352 : for (int i = 0; i < break_points()->length(); i++) {
80 2247756 : if (!break_points()->get(i)->IsUndefined(isolate)) {
81 : BreakPointInfo break_point_info =
82 80956 : BreakPointInfo::cast(break_points()->get(i));
83 40478 : if (break_point_info->source_position() == source_position) {
84 8546 : return break_point_info;
85 : }
86 : }
87 : }
88 184924 : return ReadOnlyRoots(isolate).undefined_value();
89 : }
90 :
91 2278 : bool DebugInfo::ClearBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info,
92 : Handle<BreakPoint> break_point) {
93 : DCHECK(debug_info->HasBreakInfo());
94 8637 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
95 8637 : if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
96 : Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
97 5758 : BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
98 2879 : if (BreakPointInfo::HasBreakPoint(isolate, break_point_info, break_point)) {
99 2278 : BreakPointInfo::ClearBreakPoint(isolate, break_point_info, break_point);
100 2278 : return true;
101 : }
102 : }
103 : return false;
104 : }
105 :
106 2468 : 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 4936 : debug_info->GetBreakPointInfo(isolate, source_position), isolate);
112 4936 : if (!break_point_info->IsUndefined(isolate)) {
113 : BreakPointInfo::SetBreakPoint(
114 132 : isolate, Handle<BreakPointInfo>::cast(break_point_info), break_point);
115 2600 : 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 6469 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
123 8763 : if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
124 : index = i;
125 : break;
126 : }
127 : }
128 2336 : if (index == kNoBreakPointInfo) {
129 : // No free slot - extend break point info array.
130 : Handle<FixedArray> old_break_points =
131 28 : Handle<FixedArray>(debug_info->break_points(), isolate);
132 : Handle<FixedArray> new_break_points = isolate->factory()->NewFixedArray(
133 : old_break_points->length() +
134 14 : DebugInfo::kEstimatedNofBreakPointsInFunction);
135 :
136 14 : debug_info->set_break_points(*new_break_points);
137 140 : for (int i = 0; i < old_break_points->length(); i++) {
138 56 : 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 2336 : isolate->factory()->NewBreakPointInfo(source_position);
147 2336 : BreakPointInfo::SetBreakPoint(isolate, new_break_point_info, break_point);
148 4672 : debug_info->break_points()->set(index, *new_break_point_info);
149 : }
150 :
151 : // Get the break point objects for a source position.
152 4164 : Handle<Object> DebugInfo::GetBreakPoints(Isolate* isolate,
153 : int source_position) {
154 : DCHECK(HasBreakInfo());
155 4164 : Object break_point_info = GetBreakPointInfo(isolate, source_position);
156 4164 : if (break_point_info->IsUndefined(isolate)) {
157 0 : return isolate->factory()->undefined_value();
158 : }
159 : return Handle<Object>(BreakPointInfo::cast(break_point_info)->break_points(),
160 4164 : isolate);
161 : }
162 :
163 : // Get the total number of break points.
164 3106 : int DebugInfo::GetBreakPointCount(Isolate* isolate) {
165 : DCHECK(HasBreakInfo());
166 : int count = 0;
167 32132 : for (int i = 0; i < break_points()->length(); i++) {
168 38880 : if (!break_points()->get(i)->IsUndefined(isolate)) {
169 : BreakPointInfo break_point_info =
170 10820 : BreakPointInfo::cast(break_points()->get(i));
171 5410 : count += break_point_info->GetBreakPointCount(isolate);
172 : }
173 : }
174 3106 : return count;
175 : }
176 :
177 8010 : Handle<Object> DebugInfo::FindBreakPointInfo(Isolate* isolate,
178 : Handle<DebugInfo> debug_info,
179 : Handle<BreakPoint> break_point) {
180 : DCHECK(debug_info->HasBreakInfo());
181 95493 : for (int i = 0; i < debug_info->break_points()->length(); i++) {
182 78297 : if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
183 : Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
184 9552 : BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
185 4776 : if (BreakPointInfo::HasBreakPoint(isolate, break_point_info,
186 : break_point)) {
187 2278 : return break_point_info;
188 : }
189 : }
190 : }
191 5732 : return isolate->factory()->undefined_value();
192 : }
193 :
194 207498 : bool DebugInfo::HasCoverageInfo() const {
195 207498 : return (flags() & kHasCoverageInfo) != 0;
196 : }
197 :
198 15578 : void DebugInfo::ClearCoverageInfo(Isolate* isolate) {
199 15578 : if (HasCoverageInfo()) {
200 872 : set_coverage_info(ReadOnlyRoots(isolate).undefined_value());
201 :
202 872 : int new_flags = flags() & ~kHasCoverageInfo;
203 : set_flags(new_flags);
204 : }
205 15578 : }
206 :
207 13700 : DebugInfo::SideEffectState DebugInfo::GetSideEffectState(Isolate* isolate) {
208 13700 : if (side_effect_state() == kNotComputed) {
209 : SideEffectState has_no_side_effect =
210 : DebugEvaluate::FunctionGetSideEffectState(isolate,
211 24316 : handle(shared(), isolate));
212 12158 : set_side_effect_state(has_no_side_effect);
213 : }
214 13700 : return static_cast<SideEffectState>(side_effect_state());
215 : }
216 :
217 : namespace {
218 11689 : bool IsEqual(BreakPoint break_point1, BreakPoint break_point2) {
219 11689 : return break_point1->id() == break_point2->id();
220 : }
221 : } // namespace
222 :
223 : // Remove the specified break point object.
224 2278 : 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 4556 : 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 4556 : if (!break_point_info->break_points()->IsFixedArray()) {
231 2119 : if (IsEqual(BreakPoint::cast(break_point_info->break_points()),
232 : *break_point)) {
233 : break_point_info->set_break_points(
234 4238 : 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 159 : isolate->factory()->NewFixedArray(old_array->length() - 1);
244 : int found_count = 0;
245 2268 : for (int i = 0; i < old_array->length(); i++) {
246 975 : if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) {
247 : DCHECK_EQ(found_count, 0);
248 159 : found_count++;
249 : } else {
250 1632 : 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 477 : if (found_count > 0) break_point_info->set_break_points(*new_array);
255 : }
256 :
257 : // Add the specified break point object.
258 2580 : 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 5160 : if (break_point_info->break_points()->IsUndefined(isolate)) {
263 4896 : break_point_info->set_break_points(*break_point);
264 2448 : return;
265 : }
266 : // If the break point object is the same as before just ignore.
267 132 : if (break_point_info->break_points() == *break_point) return;
268 : // If there was one break point object before replace with array.
269 264 : if (!break_point_info->break_points()->IsFixedArray()) {
270 27 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
271 27 : array->set(0, break_point_info->break_points());
272 54 : array->set(1, *break_point);
273 54 : 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 105 : isolate->factory()->NewFixedArray(old_array->length() + 1);
281 1788 : for (int i = 0; i < old_array->length(); i++) {
282 : // If the break point was there before just ignore.
283 789 : if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) return;
284 789 : new_array->set(i, old_array->get(i));
285 : }
286 : // Add the new break point.
287 210 : new_array->set(old_array->length(), *break_point);
288 210 : break_point_info->set_break_points(*new_array);
289 : }
290 :
291 7655 : bool BreakPointInfo::HasBreakPoint(Isolate* isolate,
292 : Handle<BreakPointInfo> break_point_info,
293 : Handle<BreakPoint> break_point) {
294 : // No break point.
295 15310 : if (break_point_info->break_points()->IsUndefined(isolate)) {
296 : return false;
297 : }
298 : // Single break point.
299 13716 : if (!break_point_info->break_points()->IsFixedArray()) {
300 : return IsEqual(BreakPoint::cast(break_point_info->break_points()),
301 6460 : *break_point);
302 : }
303 : // Multiple break points.
304 : FixedArray array = FixedArray::cast(break_point_info->break_points());
305 2852 : for (int i = 0; i < array->length(); i++) {
306 1346 : 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 78451 : int BreakPointInfo::GetBreakPointCount(Isolate* isolate) {
315 : // No break point.
316 156902 : if (break_points()->IsUndefined(isolate)) return 0;
317 : // Single break point.
318 148820 : if (!break_points()->IsFixedArray()) return 1;
319 : // Multiple break points.
320 : return FixedArray::cast(break_points())->length();
321 : }
322 :
323 121912 : int CoverageInfo::SlotCount() const {
324 : DCHECK_EQ(kFirstSlotIndex, length() % kSlotIndexCount);
325 121912 : return (length() - kFirstSlotIndex) / kSlotIndexCount;
326 : }
327 :
328 45380 : int CoverageInfo::StartSourcePosition(int slot_index) const {
329 : DCHECK_LT(slot_index, SlotCount());
330 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
331 45380 : return Smi::ToInt(get(slot_start + kSlotStartSourcePositionIndex));
332 : }
333 :
334 45380 : int CoverageInfo::EndSourcePosition(int slot_index) const {
335 : DCHECK_LT(slot_index, SlotCount());
336 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
337 90760 : return Smi::ToInt(get(slot_start + kSlotEndSourcePositionIndex));
338 : }
339 :
340 224828 : int CoverageInfo::BlockCount(int slot_index) const {
341 : DCHECK_LT(slot_index, SlotCount());
342 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
343 449656 : return Smi::ToInt(get(slot_start + kSlotBlockCountIndex));
344 : }
345 :
346 2272 : 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 2272 : set(slot_start + kSlotBlockCountIndex, Smi::kZero);
352 2272 : }
353 :
354 179448 : void CoverageInfo::IncrementBlockCount(int slot_index) {
355 : DCHECK_LT(slot_index, SlotCount());
356 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
357 179448 : const int old_count = BlockCount(slot_index);
358 179448 : set(slot_start + kSlotBlockCountIndex, Smi::FromInt(old_count + 1));
359 179448 : }
360 :
361 45380 : void CoverageInfo::ResetBlockCount(int slot_index) {
362 : DCHECK_LT(slot_index, SlotCount());
363 : const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
364 45380 : set(slot_start + kSlotBlockCountIndex, Smi::kZero);
365 45380 : }
366 :
367 0 : void CoverageInfo::Print(std::unique_ptr<char[]> function_name) {
368 : DCHECK(FLAG_trace_block_coverage);
369 : DisallowHeapAllocation no_gc;
370 :
371 0 : StdoutStream os;
372 0 : os << "Coverage info (";
373 0 : if (strlen(function_name.get()) > 0) {
374 0 : os << function_name.get();
375 : } else {
376 0 : os << "{anonymous}";
377 : }
378 0 : os << "):" << std::endl;
379 :
380 0 : for (int i = 0; i < SlotCount(); i++) {
381 0 : os << "{" << StartSourcePosition(i) << "," << EndSourcePosition(i) << "}"
382 : << std::endl;
383 0 : }
384 0 : }
385 :
386 : } // namespace internal
387 178779 : } // namespace v8
|