• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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