Home | History | Annotate | Download | only in objects
      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 
     12 bool DebugInfo::IsEmpty() const {
     13   return flags() == kNone && debugger_hints() == 0;
     14 }
     15 
     16 bool DebugInfo::HasBreakInfo() const { return (flags() & kHasBreakInfo) != 0; }
     17 
     18 DebugInfo::ExecutionMode DebugInfo::DebugExecutionMode() const {
     19   return (flags() & kDebugExecutionMode) != 0 ? kSideEffects : kBreakpoints;
     20 }
     21 
     22 void DebugInfo::SetDebugExecutionMode(ExecutionMode value) {
     23   set_flags(value == kSideEffects ? (flags() | kDebugExecutionMode)
     24                                   : (flags() & ~kDebugExecutionMode));
     25 }
     26 
     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 
     43 void DebugInfo::SetBreakAtEntry() {
     44   DCHECK(CanBreakAtEntry());
     45   set_flags(flags() | kBreakAtEntry);
     46 }
     47 
     48 void DebugInfo::ClearBreakAtEntry() {
     49   DCHECK(CanBreakAtEntry());
     50   set_flags(flags() & ~kBreakAtEntry);
     51 }
     52 
     53 bool DebugInfo::BreakAtEntry() const { return (flags() & kBreakAtEntry) != 0; }
     54 
     55 bool DebugInfo::CanBreakAtEntry() const {
     56   return (flags() & kCanBreakAtEntry) != 0;
     57 }
     58 
     59 // Check if there is a break point at this 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.
     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 
     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 
    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.
    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.
    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 
    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 
    190 bool DebugInfo::HasCoverageInfo() const {
    191   return (flags() & kHasCoverageInfo) != 0;
    192 }
    193 
    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 
    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 {
    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.
    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.
    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 
    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.
    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 
    319 int CoverageInfo::SlotCount() const {
    320   DCHECK_EQ(kFirstSlotIndex, length() % kSlotIndexCount);
    321   return (length() - kFirstSlotIndex) / kSlotIndexCount;
    322 }
    323 
    324 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 
    330 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 
    336 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 
    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 
    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 
    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 
    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