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/base/platform/mutex.h"
8 #include "src/debug/debug-evaluate.h"
9 #include "src/handles/handles-inl.h"
10 #include "src/objects/call-site-info-inl.h"
11 #include "src/objects/debug-objects-inl.h"
12 #include "src/utils/ostreams.h"
13
14 namespace v8 {
15 namespace internal {
16
IsEmpty() const17 bool DebugInfo::IsEmpty() const {
18 return flags(kRelaxedLoad) == kNone && debugger_hints() == 0;
19 }
20
HasBreakInfo() const21 bool DebugInfo::HasBreakInfo() const {
22 return (flags(kRelaxedLoad) & kHasBreakInfo) != 0;
23 }
24
DebugExecutionMode() const25 DebugInfo::ExecutionMode DebugInfo::DebugExecutionMode() const {
26 return (flags(kRelaxedLoad) & kDebugExecutionMode) != 0 ? kSideEffects
27 : kBreakpoints;
28 }
29
SetDebugExecutionMode(ExecutionMode value)30 void DebugInfo::SetDebugExecutionMode(ExecutionMode value) {
31 set_flags(value == kSideEffects
32 ? (flags(kRelaxedLoad) | kDebugExecutionMode)
33 : (flags(kRelaxedLoad) & ~kDebugExecutionMode),
34 kRelaxedStore);
35 }
36
ClearBreakInfo(Isolate * isolate)37 void DebugInfo::ClearBreakInfo(Isolate* isolate) {
38 if (HasInstrumentedBytecodeArray()) {
39 // If the function is currently running on the stack, we need to update the
40 // bytecode pointers on the stack so they point to the original
41 // BytecodeArray before releasing that BytecodeArray from this DebugInfo.
42 // Otherwise, it could be flushed and cause problems on resume. See v8:9067.
43 {
44 RedirectActiveFunctions redirect_visitor(
45 shared(), RedirectActiveFunctions::Mode::kUseOriginalBytecode);
46 redirect_visitor.VisitThread(isolate, isolate->thread_local_top());
47 isolate->thread_manager()->IterateArchivedThreads(&redirect_visitor);
48 }
49
50 SharedFunctionInfo::UninstallDebugBytecode(shared(), isolate);
51 }
52 set_break_points(ReadOnlyRoots(isolate).empty_fixed_array());
53
54 int new_flags = flags(kRelaxedLoad);
55 new_flags &= ~kHasBreakInfo & ~kPreparedForDebugExecution;
56 new_flags &= ~kBreakAtEntry & ~kCanBreakAtEntry;
57 new_flags &= ~kDebugExecutionMode;
58 set_flags(new_flags, kRelaxedStore);
59 }
60
SetBreakAtEntry()61 void DebugInfo::SetBreakAtEntry() {
62 DCHECK(CanBreakAtEntry());
63 set_flags(flags(kRelaxedLoad) | kBreakAtEntry, kRelaxedStore);
64 }
65
ClearBreakAtEntry()66 void DebugInfo::ClearBreakAtEntry() {
67 DCHECK(CanBreakAtEntry());
68 set_flags(flags(kRelaxedLoad) & ~kBreakAtEntry, kRelaxedStore);
69 }
70
BreakAtEntry() const71 bool DebugInfo::BreakAtEntry() const {
72 return (flags(kRelaxedLoad) & kBreakAtEntry) != 0;
73 }
74
CanBreakAtEntry() const75 bool DebugInfo::CanBreakAtEntry() const {
76 return (flags(kRelaxedLoad) & kCanBreakAtEntry) != 0;
77 }
78
79 // Check if there is a break point at this source position.
HasBreakPoint(Isolate * isolate,int source_position)80 bool DebugInfo::HasBreakPoint(Isolate* isolate, int source_position) {
81 DCHECK(HasBreakInfo());
82 // Get the break point info object for this code offset.
83 Object break_point_info = GetBreakPointInfo(isolate, source_position);
84
85 // If there is no break point info object or no break points in the break
86 // point info object there is no break point at this code offset.
87 if (break_point_info.IsUndefined(isolate)) return false;
88 return BreakPointInfo::cast(break_point_info).GetBreakPointCount(isolate) > 0;
89 }
90
91 // Get the break point info object for this source position.
GetBreakPointInfo(Isolate * isolate,int source_position)92 Object DebugInfo::GetBreakPointInfo(Isolate* isolate, int source_position) {
93 DCHECK(HasBreakInfo());
94 for (int i = 0; i < break_points().length(); i++) {
95 if (!break_points().get(i).IsUndefined(isolate)) {
96 BreakPointInfo break_point_info =
97 BreakPointInfo::cast(break_points().get(i));
98 if (break_point_info.source_position() == source_position) {
99 return break_point_info;
100 }
101 }
102 }
103 return ReadOnlyRoots(isolate).undefined_value();
104 }
105
ClearBreakPoint(Isolate * isolate,Handle<DebugInfo> debug_info,Handle<BreakPoint> break_point)106 bool DebugInfo::ClearBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info,
107 Handle<BreakPoint> break_point) {
108 DCHECK(debug_info->HasBreakInfo());
109 for (int i = 0; i < debug_info->break_points().length(); i++) {
110 if (debug_info->break_points().get(i).IsUndefined(isolate)) continue;
111 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
112 BreakPointInfo::cast(debug_info->break_points().get(i)), isolate);
113 if (BreakPointInfo::HasBreakPoint(isolate, break_point_info, break_point)) {
114 BreakPointInfo::ClearBreakPoint(isolate, break_point_info, break_point);
115 return true;
116 }
117 }
118 return false;
119 }
120
SetBreakPoint(Isolate * isolate,Handle<DebugInfo> debug_info,int source_position,Handle<BreakPoint> break_point)121 void DebugInfo::SetBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info,
122 int source_position,
123 Handle<BreakPoint> break_point) {
124 DCHECK(debug_info->HasBreakInfo());
125 Handle<Object> break_point_info(
126 debug_info->GetBreakPointInfo(isolate, source_position), isolate);
127 if (!break_point_info->IsUndefined(isolate)) {
128 BreakPointInfo::SetBreakPoint(
129 isolate, Handle<BreakPointInfo>::cast(break_point_info), break_point);
130 return;
131 }
132
133 // Adding a new break point for a code offset which did not have any
134 // break points before. Try to find a free slot.
135 static const int kNoBreakPointInfo = -1;
136 int index = kNoBreakPointInfo;
137 for (int i = 0; i < debug_info->break_points().length(); i++) {
138 if (debug_info->break_points().get(i).IsUndefined(isolate)) {
139 index = i;
140 break;
141 }
142 }
143 if (index == kNoBreakPointInfo) {
144 // No free slot - extend break point info array.
145 Handle<FixedArray> old_break_points =
146 Handle<FixedArray>(debug_info->break_points(), isolate);
147 Handle<FixedArray> new_break_points = isolate->factory()->NewFixedArray(
148 old_break_points->length() +
149 DebugInfo::kEstimatedNofBreakPointsInFunction);
150
151 debug_info->set_break_points(*new_break_points);
152 for (int i = 0; i < old_break_points->length(); i++) {
153 new_break_points->set(i, old_break_points->get(i));
154 }
155 index = old_break_points->length();
156 }
157 DCHECK_NE(index, kNoBreakPointInfo);
158
159 // Allocate new BreakPointInfo object and set the break point.
160 Handle<BreakPointInfo> new_break_point_info =
161 isolate->factory()->NewBreakPointInfo(source_position);
162 BreakPointInfo::SetBreakPoint(isolate, new_break_point_info, break_point);
163 debug_info->break_points().set(index, *new_break_point_info);
164 }
165
166 // Get the break point objects for a source position.
GetBreakPoints(Isolate * isolate,int source_position)167 Handle<Object> DebugInfo::GetBreakPoints(Isolate* isolate,
168 int source_position) {
169 DCHECK(HasBreakInfo());
170 Object break_point_info = GetBreakPointInfo(isolate, source_position);
171 if (break_point_info.IsUndefined(isolate)) {
172 return isolate->factory()->undefined_value();
173 }
174 return Handle<Object>(BreakPointInfo::cast(break_point_info).break_points(),
175 isolate);
176 }
177
178 // Get the total number of break points.
GetBreakPointCount(Isolate * isolate)179 int DebugInfo::GetBreakPointCount(Isolate* isolate) {
180 DCHECK(HasBreakInfo());
181 int count = 0;
182 for (int i = 0; i < break_points().length(); i++) {
183 if (!break_points().get(i).IsUndefined(isolate)) {
184 BreakPointInfo break_point_info =
185 BreakPointInfo::cast(break_points().get(i));
186 count += break_point_info.GetBreakPointCount(isolate);
187 }
188 }
189 return count;
190 }
191
FindBreakPointInfo(Isolate * isolate,Handle<DebugInfo> debug_info,Handle<BreakPoint> break_point)192 Handle<Object> DebugInfo::FindBreakPointInfo(Isolate* isolate,
193 Handle<DebugInfo> debug_info,
194 Handle<BreakPoint> break_point) {
195 DCHECK(debug_info->HasBreakInfo());
196 for (int i = 0; i < debug_info->break_points().length(); i++) {
197 if (!debug_info->break_points().get(i).IsUndefined(isolate)) {
198 Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
199 BreakPointInfo::cast(debug_info->break_points().get(i)), isolate);
200 if (BreakPointInfo::HasBreakPoint(isolate, break_point_info,
201 break_point)) {
202 return break_point_info;
203 }
204 }
205 }
206 return isolate->factory()->undefined_value();
207 }
208
HasCoverageInfo() const209 bool DebugInfo::HasCoverageInfo() const {
210 return (flags(kRelaxedLoad) & kHasCoverageInfo) != 0;
211 }
212
ClearCoverageInfo(Isolate * isolate)213 void DebugInfo::ClearCoverageInfo(Isolate* isolate) {
214 if (HasCoverageInfo()) {
215 set_coverage_info(ReadOnlyRoots(isolate).undefined_value());
216
217 int new_flags = flags(kRelaxedLoad) & ~kHasCoverageInfo;
218 set_flags(new_flags, kRelaxedStore);
219 }
220 }
221
GetSideEffectState(Isolate * isolate)222 DebugInfo::SideEffectState DebugInfo::GetSideEffectState(Isolate* isolate) {
223 if (side_effect_state() == kNotComputed) {
224 SideEffectState has_no_side_effect =
225 DebugEvaluate::FunctionGetSideEffectState(isolate,
226 handle(shared(), isolate));
227 set_side_effect_state(has_no_side_effect);
228 }
229 return static_cast<SideEffectState>(side_effect_state());
230 }
231
232 namespace {
IsEqual(BreakPoint break_point1,BreakPoint break_point2)233 bool IsEqual(BreakPoint break_point1, BreakPoint break_point2) {
234 return break_point1.id() == break_point2.id();
235 }
236 } // namespace
237
238 // Remove the specified break point object.
ClearBreakPoint(Isolate * isolate,Handle<BreakPointInfo> break_point_info,Handle<BreakPoint> break_point)239 void BreakPointInfo::ClearBreakPoint(Isolate* isolate,
240 Handle<BreakPointInfo> break_point_info,
241 Handle<BreakPoint> break_point) {
242 // If there are no break points just ignore.
243 if (break_point_info->break_points().IsUndefined(isolate)) return;
244 // If there is a single break point clear it if it is the same.
245 if (!break_point_info->break_points().IsFixedArray()) {
246 if (IsEqual(BreakPoint::cast(break_point_info->break_points()),
247 *break_point)) {
248 break_point_info->set_break_points(
249 ReadOnlyRoots(isolate).undefined_value());
250 }
251 return;
252 }
253 // If there are multiple break points shrink the array
254 DCHECK(break_point_info->break_points().IsFixedArray());
255 Handle<FixedArray> old_array = Handle<FixedArray>(
256 FixedArray::cast(break_point_info->break_points()), isolate);
257 Handle<FixedArray> new_array =
258 isolate->factory()->NewFixedArray(old_array->length() - 1);
259 int found_count = 0;
260 for (int i = 0; i < old_array->length(); i++) {
261 if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) {
262 DCHECK_EQ(found_count, 0);
263 found_count++;
264 } else {
265 new_array->set(i - found_count, old_array->get(i));
266 }
267 }
268 // If the break point was found in the list change it.
269 if (found_count > 0) break_point_info->set_break_points(*new_array);
270 }
271
272 // Add the specified break point object.
SetBreakPoint(Isolate * isolate,Handle<BreakPointInfo> break_point_info,Handle<BreakPoint> break_point)273 void BreakPointInfo::SetBreakPoint(Isolate* isolate,
274 Handle<BreakPointInfo> break_point_info,
275 Handle<BreakPoint> break_point) {
276 // If there was no break point objects before just set it.
277 if (break_point_info->break_points().IsUndefined(isolate)) {
278 break_point_info->set_break_points(*break_point);
279 return;
280 }
281 // If there was one break point object before replace with array.
282 if (!break_point_info->break_points().IsFixedArray()) {
283 if (IsEqual(BreakPoint::cast(break_point_info->break_points()),
284 *break_point)) {
285 return;
286 }
287
288 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
289 array->set(0, break_point_info->break_points());
290 array->set(1, *break_point);
291 break_point_info->set_break_points(*array);
292 return;
293 }
294 // If there was more than one break point before extend array.
295 Handle<FixedArray> old_array = Handle<FixedArray>(
296 FixedArray::cast(break_point_info->break_points()), isolate);
297 Handle<FixedArray> new_array =
298 isolate->factory()->NewFixedArray(old_array->length() + 1);
299 for (int i = 0; i < old_array->length(); i++) {
300 // If the break point was there before just ignore.
301 if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) return;
302 new_array->set(i, old_array->get(i));
303 }
304 // Add the new break point.
305 new_array->set(old_array->length(), *break_point);
306 break_point_info->set_break_points(*new_array);
307 }
308
HasBreakPoint(Isolate * isolate,Handle<BreakPointInfo> break_point_info,Handle<BreakPoint> break_point)309 bool BreakPointInfo::HasBreakPoint(Isolate* isolate,
310 Handle<BreakPointInfo> break_point_info,
311 Handle<BreakPoint> break_point) {
312 // No break point.
313 if (break_point_info->break_points().IsUndefined(isolate)) {
314 return false;
315 }
316 // Single break point.
317 if (!break_point_info->break_points().IsFixedArray()) {
318 return IsEqual(BreakPoint::cast(break_point_info->break_points()),
319 *break_point);
320 }
321 // Multiple break points.
322 FixedArray array = FixedArray::cast(break_point_info->break_points());
323 for (int i = 0; i < array.length(); i++) {
324 if (IsEqual(BreakPoint::cast(array.get(i)), *break_point)) {
325 return true;
326 }
327 }
328 return false;
329 }
330
GetBreakPointById(Isolate * isolate,Handle<BreakPointInfo> break_point_info,int breakpoint_id)331 MaybeHandle<BreakPoint> BreakPointInfo::GetBreakPointById(
332 Isolate* isolate, Handle<BreakPointInfo> break_point_info,
333 int breakpoint_id) {
334 // No break point.
335 if (break_point_info->break_points().IsUndefined(isolate)) {
336 return MaybeHandle<BreakPoint>();
337 }
338 // Single break point.
339 if (!break_point_info->break_points().IsFixedArray()) {
340 BreakPoint breakpoint = BreakPoint::cast(break_point_info->break_points());
341 if (breakpoint.id() == breakpoint_id) {
342 return handle(breakpoint, isolate);
343 }
344 } else {
345 // Multiple break points.
346 FixedArray array = FixedArray::cast(break_point_info->break_points());
347 for (int i = 0; i < array.length(); i++) {
348 BreakPoint breakpoint = BreakPoint::cast(array.get(i));
349 if (breakpoint.id() == breakpoint_id) {
350 return handle(breakpoint, isolate);
351 }
352 }
353 }
354 return MaybeHandle<BreakPoint>();
355 }
356
357 // Get the number of break points.
GetBreakPointCount(Isolate * isolate)358 int BreakPointInfo::GetBreakPointCount(Isolate* isolate) {
359 // No break point.
360 if (break_points().IsUndefined(isolate)) return 0;
361 // Single break point.
362 if (!break_points().IsFixedArray()) return 1;
363 // Multiple break points.
364 return FixedArray::cast(break_points()).length();
365 }
366
InitializeSlot(int slot_index,int from_pos,int to_pos)367 void CoverageInfo::InitializeSlot(int slot_index, int from_pos, int to_pos) {
368 set_slots_start_source_position(slot_index, from_pos);
369 set_slots_end_source_position(slot_index, to_pos);
370 ResetBlockCount(slot_index);
371 set_slots_padding(slot_index, 0);
372 }
373
ResetBlockCount(int slot_index)374 void CoverageInfo::ResetBlockCount(int slot_index) {
375 set_slots_block_count(slot_index, 0);
376 }
377
CoverageInfoPrint(std::ostream & os,std::unique_ptr<char[]> function_name)378 void CoverageInfo::CoverageInfoPrint(std::ostream& os,
379 std::unique_ptr<char[]> function_name) {
380 DCHECK(FLAG_trace_block_coverage);
381 DisallowGarbageCollection no_gc;
382
383 os << "Coverage info (";
384 if (function_name == nullptr) {
385 os << "{unknown}";
386 } else if (strlen(function_name.get()) > 0) {
387 os << function_name.get();
388 } else {
389 os << "{anonymous}";
390 }
391 os << "):" << std::endl;
392
393 for (int i = 0; i < slot_count(); i++) {
394 os << "{" << slots_start_source_position(i) << ","
395 << slots_end_source_position(i) << "}" << std::endl;
396 }
397 }
398
399 // static
GetSourcePosition(Handle<StackFrameInfo> info)400 int StackFrameInfo::GetSourcePosition(Handle<StackFrameInfo> info) {
401 if (info->shared_or_script().IsScript()) {
402 return info->bytecode_offset_or_source_position();
403 }
404 Isolate* isolate = info->GetIsolate();
405 Handle<SharedFunctionInfo> shared(
406 SharedFunctionInfo::cast(info->shared_or_script()), isolate);
407 SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared);
408 int source_position = shared->abstract_code(isolate).SourcePosition(
409 info->bytecode_offset_or_source_position());
410 info->set_shared_or_script(shared->script());
411 info->set_bytecode_offset_or_source_position(source_position);
412 return source_position;
413 }
414
415 // static
EnsureStackFrameInfos(Isolate * isolate,Handle<ErrorStackData> error_stack)416 void ErrorStackData::EnsureStackFrameInfos(Isolate* isolate,
417 Handle<ErrorStackData> error_stack) {
418 if (!error_stack->limit_or_stack_frame_infos().IsSmi()) {
419 return;
420 }
421 int limit = Smi::cast(error_stack->limit_or_stack_frame_infos()).value();
422 Handle<FixedArray> call_site_infos(error_stack->call_site_infos(), isolate);
423 Handle<FixedArray> stack_frame_infos =
424 isolate->factory()->NewFixedArray(call_site_infos->length());
425 int index = 0;
426 for (int i = 0; i < call_site_infos->length(); ++i) {
427 Handle<CallSiteInfo> call_site_info(
428 CallSiteInfo::cast(call_site_infos->get(i)), isolate);
429 if (call_site_info->IsAsync()) {
430 break;
431 }
432 Handle<Script> script;
433 if (!CallSiteInfo::GetScript(isolate, call_site_info).ToHandle(&script) ||
434 !script->IsSubjectToDebugging()) {
435 continue;
436 }
437 Handle<StackFrameInfo> stack_frame_info =
438 isolate->factory()->NewStackFrameInfo(
439 script, CallSiteInfo::GetSourcePosition(call_site_info),
440 CallSiteInfo::GetFunctionDebugName(call_site_info),
441 call_site_info->IsConstructor());
442 stack_frame_infos->set(index++, *stack_frame_info);
443 }
444 stack_frame_infos =
445 FixedArray::ShrinkOrEmpty(isolate, stack_frame_infos, index);
446 if (limit < 0 && -limit < index) {
447 // Negative limit encodes cap to be applied to |stack_frame_infos|.
448 stack_frame_infos =
449 FixedArray::ShrinkOrEmpty(isolate, stack_frame_infos, -limit);
450 } else if (limit >= 0 && limit < call_site_infos->length()) {
451 // Positive limit means we need to cap the |call_site_infos|
452 // to that number before exposing them to the world.
453 call_site_infos =
454 FixedArray::ShrinkOrEmpty(isolate, call_site_infos, limit);
455 error_stack->set_call_site_infos(*call_site_infos);
456 }
457 error_stack->set_limit_or_stack_frame_infos(*stack_frame_infos);
458 }
459
460 // static
GetPromise(Handle<PromiseOnStack> promise_on_stack)461 MaybeHandle<JSObject> PromiseOnStack::GetPromise(
462 Handle<PromiseOnStack> promise_on_stack) {
463 HeapObject promise;
464 Isolate* isolate = promise_on_stack->GetIsolate();
465 if (promise_on_stack->promise()->GetHeapObjectIfWeak(isolate, &promise)) {
466 return handle(JSObject::cast(promise), isolate);
467 }
468 return {};
469 }
470
471 } // namespace internal
472 } // namespace v8
473