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