debug-objects.cc 14.8 KB
Newer Older
1 2 3 4 5
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#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 13 14

namespace v8 {
namespace internal {

15 16 17
bool DebugInfo::IsEmpty() const {
  return flags() == kNone && debugger_hints() == 0;
}
18 19 20

bool DebugInfo::HasBreakInfo() const { return (flags() & kHasBreakInfo) != 0; }

21 22 23 24 25 26 27
DebugInfo::ExecutionMode DebugInfo::DebugExecutionMode() const {
  return (flags() & kDebugExecutionMode) != 0 ? kSideEffects : kBreakpoints;
}

void DebugInfo::SetDebugExecutionMode(ExecutionMode value) {
  set_flags(value == kSideEffects ? (flags() | kDebugExecutionMode)
                                  : (flags() & ~kDebugExecutionMode));
28 29
}

30 31 32 33 34
void DebugInfo::ClearBreakInfo(Isolate* isolate) {
  if (HasInstrumentedBytecodeArray()) {
    // Reset function's bytecode array field to point to the original bytecode
    // array.
    shared()->SetDebugBytecodeArray(OriginalBytecodeArray());
35 36 37 38 39 40 41 42 43 44 45 46

    // If the function is currently running on the stack, we need to update the
    // bytecode pointers on the stack so they point to the original
    // BytecodeArray before releasing that BytecodeArray from this DebugInfo.
    // Otherwise, it could be flushed and cause problems on resume. See v8:9067.
    {
      RedirectActiveFunctions redirect_visitor(
          shared(), RedirectActiveFunctions::Mode::kUseOriginalBytecode);
      redirect_visitor.VisitThread(isolate, isolate->thread_local_top());
      isolate->thread_manager()->IterateArchivedThreads(&redirect_visitor);
    }

47
    set_original_bytecode_array(ReadOnlyRoots(isolate).undefined_value());
48
    set_debug_bytecode_array(ReadOnlyRoots(isolate).undefined_value());
49
  }
50
  set_break_points(ReadOnlyRoots(isolate).empty_fixed_array());
51

52
  int new_flags = flags();
53
  new_flags &= ~kHasBreakInfo & ~kPreparedForDebugExecution;
54
  new_flags &= ~kBreakAtEntry & ~kCanBreakAtEntry;
55
  new_flags &= ~kDebugExecutionMode;
56 57 58
  set_flags(new_flags);
}

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
void DebugInfo::SetBreakAtEntry() {
  DCHECK(CanBreakAtEntry());
  set_flags(flags() | kBreakAtEntry);
}

void DebugInfo::ClearBreakAtEntry() {
  DCHECK(CanBreakAtEntry());
  set_flags(flags() & ~kBreakAtEntry);
}

bool DebugInfo::BreakAtEntry() const { return (flags() & kBreakAtEntry) != 0; }

bool DebugInfo::CanBreakAtEntry() const {
  return (flags() & kCanBreakAtEntry) != 0;
}

75
// Check if there is a break point at this source position.
76
bool DebugInfo::HasBreakPoint(Isolate* isolate, int source_position) {
77
  DCHECK(HasBreakInfo());
78
  // Get the break point info object for this code offset.
79
  Object break_point_info = GetBreakPointInfo(isolate, source_position);
80 81 82

  // If there is no break point info object or no break points in the break
  // point info object there is no break point at this code offset.
83 84 85
  if (break_point_info->IsUndefined(isolate)) return false;
  return BreakPointInfo::cast(break_point_info)->GetBreakPointCount(isolate) >
         0;
86 87 88
}

// Get the break point info object for this source position.
89
Object DebugInfo::GetBreakPointInfo(Isolate* isolate, int source_position) {
90
  DCHECK(HasBreakInfo());
91 92
  for (int i = 0; i < break_points()->length(); i++) {
    if (!break_points()->get(i)->IsUndefined(isolate)) {
93
      BreakPointInfo break_point_info =
94 95 96
          BreakPointInfo::cast(break_points()->get(i));
      if (break_point_info->source_position() == source_position) {
        return break_point_info;
97 98 99
      }
    }
  }
100
  return ReadOnlyRoots(isolate).undefined_value();
101 102
}

103
bool DebugInfo::ClearBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info,
104
                                Handle<BreakPoint> break_point) {
105
  DCHECK(debug_info->HasBreakInfo());
106 107 108 109
  for (int i = 0; i < debug_info->break_points()->length(); i++) {
    if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
    Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
        BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
110 111
    if (BreakPointInfo::HasBreakPoint(isolate, break_point_info, break_point)) {
      BreakPointInfo::ClearBreakPoint(isolate, break_point_info, break_point);
112 113 114 115 116 117
      return true;
    }
  }
  return false;
}

118 119
void DebugInfo::SetBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info,
                              int source_position,
120
                              Handle<BreakPoint> break_point) {
121
  DCHECK(debug_info->HasBreakInfo());
122
  Handle<Object> break_point_info(
123
      debug_info->GetBreakPointInfo(isolate, source_position), isolate);
124 125
  if (!break_point_info->IsUndefined(isolate)) {
    BreakPointInfo::SetBreakPoint(
126
        isolate, Handle<BreakPointInfo>::cast(break_point_info), break_point);
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    return;
  }

  // Adding a new break point for a code offset which did not have any
  // break points before. Try to find a free slot.
  static const int kNoBreakPointInfo = -1;
  int index = kNoBreakPointInfo;
  for (int i = 0; i < debug_info->break_points()->length(); i++) {
    if (debug_info->break_points()->get(i)->IsUndefined(isolate)) {
      index = i;
      break;
    }
  }
  if (index == kNoBreakPointInfo) {
    // No free slot - extend break point info array.
142 143
    Handle<FixedArray> old_break_points =
        Handle<FixedArray>(debug_info->break_points(), isolate);
144 145 146 147 148 149 150 151 152 153
    Handle<FixedArray> new_break_points = isolate->factory()->NewFixedArray(
        old_break_points->length() +
        DebugInfo::kEstimatedNofBreakPointsInFunction);

    debug_info->set_break_points(*new_break_points);
    for (int i = 0; i < old_break_points->length(); i++) {
      new_break_points->set(i, old_break_points->get(i));
    }
    index = old_break_points->length();
  }
154
  DCHECK_NE(index, kNoBreakPointInfo);
155 156 157 158

  // Allocate new BreakPointInfo object and set the break point.
  Handle<BreakPointInfo> new_break_point_info =
      isolate->factory()->NewBreakPointInfo(source_position);
159
  BreakPointInfo::SetBreakPoint(isolate, new_break_point_info, break_point);
160 161 162 163
  debug_info->break_points()->set(index, *new_break_point_info);
}

// Get the break point objects for a source position.
164 165
Handle<Object> DebugInfo::GetBreakPoints(Isolate* isolate,
                                         int source_position) {
166
  DCHECK(HasBreakInfo());
167
  Object break_point_info = GetBreakPointInfo(isolate, source_position);
168 169 170
  if (break_point_info->IsUndefined(isolate)) {
    return isolate->factory()->undefined_value();
  }
171 172
  return Handle<Object>(BreakPointInfo::cast(break_point_info)->break_points(),
                        isolate);
173 174 175
}

// Get the total number of break points.
176
int DebugInfo::GetBreakPointCount(Isolate* isolate) {
177
  DCHECK(HasBreakInfo());
178 179 180
  int count = 0;
  for (int i = 0; i < break_points()->length(); i++) {
    if (!break_points()->get(i)->IsUndefined(isolate)) {
181
      BreakPointInfo break_point_info =
182
          BreakPointInfo::cast(break_points()->get(i));
183
      count += break_point_info->GetBreakPointCount(isolate);
184 185 186 187 188
    }
  }
  return count;
}

189 190
Handle<Object> DebugInfo::FindBreakPointInfo(Isolate* isolate,
                                             Handle<DebugInfo> debug_info,
191
                                             Handle<BreakPoint> break_point) {
192
  DCHECK(debug_info->HasBreakInfo());
193 194 195 196
  for (int i = 0; i < debug_info->break_points()->length(); i++) {
    if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
      Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
          BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
197 198
      if (BreakPointInfo::HasBreakPoint(isolate, break_point_info,
                                        break_point)) {
199
        return break_point_info;
200 201 202 203 204 205
      }
    }
  }
  return isolate->factory()->undefined_value();
}

206 207 208 209
bool DebugInfo::HasCoverageInfo() const {
  return (flags() & kHasCoverageInfo) != 0;
}

210
void DebugInfo::ClearCoverageInfo(Isolate* isolate) {
211
  if (HasCoverageInfo()) {
212
    set_coverage_info(ReadOnlyRoots(isolate).undefined_value());
213

214 215 216
    int new_flags = flags() & ~kHasCoverageInfo;
    set_flags(new_flags);
  }
217 218 219 220 221 222 223 224 225 226
}

DebugInfo::SideEffectState DebugInfo::GetSideEffectState(Isolate* isolate) {
  if (side_effect_state() == kNotComputed) {
    SideEffectState has_no_side_effect =
        DebugEvaluate::FunctionGetSideEffectState(isolate,
                                                  handle(shared(), isolate));
    set_side_effect_state(has_no_side_effect);
  }
  return static_cast<SideEffectState>(side_effect_state());
227 228
}

229
namespace {
230
bool IsEqual(BreakPoint break_point1, BreakPoint break_point2) {
231
  return break_point1->id() == break_point2->id();
232 233 234
}
}  // namespace

235
// Remove the specified break point object.
236 237
void BreakPointInfo::ClearBreakPoint(Isolate* isolate,
                                     Handle<BreakPointInfo> break_point_info,
238
                                     Handle<BreakPoint> break_point) {
239
  // If there are no break points just ignore.
240
  if (break_point_info->break_points()->IsUndefined(isolate)) return;
241
  // If there is a single break point clear it if it is the same.
242 243 244
  if (!break_point_info->break_points()->IsFixedArray()) {
    if (IsEqual(BreakPoint::cast(break_point_info->break_points()),
                *break_point)) {
245 246
      break_point_info->set_break_points(
          ReadOnlyRoots(isolate).undefined_value());
247 248 249 250
    }
    return;
  }
  // If there are multiple break points shrink the array
251
  DCHECK(break_point_info->break_points()->IsFixedArray());
252 253
  Handle<FixedArray> old_array = Handle<FixedArray>(
      FixedArray::cast(break_point_info->break_points()), isolate);
254 255 256 257
  Handle<FixedArray> new_array =
      isolate->factory()->NewFixedArray(old_array->length() - 1);
  int found_count = 0;
  for (int i = 0; i < old_array->length(); i++) {
258
    if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) {
259
      DCHECK_EQ(found_count, 0);
260 261 262 263 264 265
      found_count++;
    } else {
      new_array->set(i - found_count, old_array->get(i));
    }
  }
  // If the break point was found in the list change it.
266
  if (found_count > 0) break_point_info->set_break_points(*new_array);
267 268 269
}

// Add the specified break point object.
270 271
void BreakPointInfo::SetBreakPoint(Isolate* isolate,
                                   Handle<BreakPointInfo> break_point_info,
272
                                   Handle<BreakPoint> break_point) {
273
  // If there was no break point objects before just set it.
274 275
  if (break_point_info->break_points()->IsUndefined(isolate)) {
    break_point_info->set_break_points(*break_point);
276 277 278
    return;
  }
  // If the break point object is the same as before just ignore.
279
  if (break_point_info->break_points() == *break_point) return;
280
  // If there was one break point object before replace with array.
281
  if (!break_point_info->break_points()->IsFixedArray()) {
282
    Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
283 284 285
    array->set(0, break_point_info->break_points());
    array->set(1, *break_point);
    break_point_info->set_break_points(*array);
286 287 288
    return;
  }
  // If there was more than one break point before extend array.
289 290
  Handle<FixedArray> old_array = Handle<FixedArray>(
      FixedArray::cast(break_point_info->break_points()), isolate);
291 292 293 294
  Handle<FixedArray> new_array =
      isolate->factory()->NewFixedArray(old_array->length() + 1);
  for (int i = 0; i < old_array->length(); i++) {
    // If the break point was there before just ignore.
295
    if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) return;
296 297 298
    new_array->set(i, old_array->get(i));
  }
  // Add the new break point.
299 300
  new_array->set(old_array->length(), *break_point);
  break_point_info->set_break_points(*new_array);
301 302
}

303 304
bool BreakPointInfo::HasBreakPoint(Isolate* isolate,
                                   Handle<BreakPointInfo> break_point_info,
305
                                   Handle<BreakPoint> break_point) {
306
  // No break point.
307
  if (break_point_info->break_points()->IsUndefined(isolate)) {
308 309 310
    return false;
  }
  // Single break point.
311 312 313
  if (!break_point_info->break_points()->IsFixedArray()) {
    return IsEqual(BreakPoint::cast(break_point_info->break_points()),
                   *break_point);
314 315
  }
  // Multiple break points.
316
  FixedArray array = FixedArray::cast(break_point_info->break_points());
317
  for (int i = 0; i < array->length(); i++) {
318
    if (IsEqual(BreakPoint::cast(array->get(i)), *break_point)) {
319 320 321 322 323 324 325
      return true;
    }
  }
  return false;
}

// Get the number of break points.
326
int BreakPointInfo::GetBreakPointCount(Isolate* isolate) {
327
  // No break point.
328
  if (break_points()->IsUndefined(isolate)) return 0;
329
  // Single break point.
330
  if (!break_points()->IsFixedArray()) return 1;
331
  // Multiple break points.
332
  return FixedArray::cast(break_points())->length();
333 334
}

335 336 337 338 339 340 341 342
int CoverageInfo::SlotCount() const {
  DCHECK_EQ(kFirstSlotIndex, length() % kSlotIndexCount);
  return (length() - kFirstSlotIndex) / kSlotIndexCount;
}

int CoverageInfo::StartSourcePosition(int slot_index) const {
  DCHECK_LT(slot_index, SlotCount());
  const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
jgruber's avatar
jgruber committed
343
  return Smi::ToInt(get(slot_start + kSlotStartSourcePositionIndex));
344 345 346 347 348
}

int CoverageInfo::EndSourcePosition(int slot_index) const {
  DCHECK_LT(slot_index, SlotCount());
  const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
jgruber's avatar
jgruber committed
349
  return Smi::ToInt(get(slot_start + kSlotEndSourcePositionIndex));
350 351 352 353 354
}

int CoverageInfo::BlockCount(int slot_index) const {
  DCHECK_LT(slot_index, SlotCount());
  const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
jgruber's avatar
jgruber committed
355
  return Smi::ToInt(get(slot_start + kSlotBlockCountIndex));
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
}

void CoverageInfo::InitializeSlot(int slot_index, int from_pos, int to_pos) {
  DCHECK_LT(slot_index, SlotCount());
  const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
  set(slot_start + kSlotStartSourcePositionIndex, Smi::FromInt(from_pos));
  set(slot_start + kSlotEndSourcePositionIndex, Smi::FromInt(to_pos));
  set(slot_start + kSlotBlockCountIndex, Smi::kZero);
}

void CoverageInfo::IncrementBlockCount(int slot_index) {
  DCHECK_LT(slot_index, SlotCount());
  const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
  const int old_count = BlockCount(slot_index);
  set(slot_start + kSlotBlockCountIndex, Smi::FromInt(old_count + 1));
}

373 374 375 376 377 378
void CoverageInfo::ResetBlockCount(int slot_index) {
  DCHECK_LT(slot_index, SlotCount());
  const int slot_start = CoverageInfo::FirstIndexForSlot(slot_index);
  set(slot_start + kSlotBlockCountIndex, Smi::kZero);
}

379
void CoverageInfo::Print(std::unique_ptr<char[]> function_name) {
380 381 382
  DCHECK(FLAG_trace_block_coverage);
  DisallowHeapAllocation no_gc;

383
  StdoutStream os;
384
  os << "Coverage info (";
385 386
  if (strlen(function_name.get()) > 0) {
    os << function_name.get();
387 388 389 390 391 392 393
  } else {
    os << "{anonymous}";
  }
  os << "):" << std::endl;

  for (int i = 0; i < SlotCount(); i++) {
    os << "{" << StartSourcePosition(i) << "," << EndSourcePosition(i) << "}"
394
       << std::endl;
395 396 397
  }
}

398 399
}  // namespace internal
}  // namespace v8