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 14namespace v8 { 15namespace internal { 16 17bool DebugInfo::IsEmpty() const { 18 return flags(kRelaxedLoad) == kNone && debugger_hints() == 0; 19} 20 21bool DebugInfo::HasBreakInfo() const { 22 return (flags(kRelaxedLoad) & kHasBreakInfo) != 0; 23} 24 25DebugInfo::ExecutionMode DebugInfo::DebugExecutionMode() const { 26 return (flags(kRelaxedLoad) & kDebugExecutionMode) != 0 ? kSideEffects 27 : kBreakpoints; 28} 29 30void DebugInfo::SetDebugExecutionMode(ExecutionMode value) { 31 set_flags(value == kSideEffects 32 ? (flags(kRelaxedLoad) | kDebugExecutionMode) 33 : (flags(kRelaxedLoad) & ~kDebugExecutionMode), 34 kRelaxedStore); 35} 36 37void 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 61void DebugInfo::SetBreakAtEntry() { 62 DCHECK(CanBreakAtEntry()); 63 set_flags(flags(kRelaxedLoad) | kBreakAtEntry, kRelaxedStore); 64} 65 66void DebugInfo::ClearBreakAtEntry() { 67 DCHECK(CanBreakAtEntry()); 68 set_flags(flags(kRelaxedLoad) & ~kBreakAtEntry, kRelaxedStore); 69} 70 71bool DebugInfo::BreakAtEntry() const { 72 return (flags(kRelaxedLoad) & kBreakAtEntry) != 0; 73} 74 75bool DebugInfo::CanBreakAtEntry() const { 76 return (flags(kRelaxedLoad) & kCanBreakAtEntry) != 0; 77} 78 79// Check if there is a break point at this source position. 80bool 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. 92Object 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 106bool 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 121void 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. 167Handle<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. 179int 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 192Handle<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 209bool DebugInfo::HasCoverageInfo() const { 210 return (flags(kRelaxedLoad) & kHasCoverageInfo) != 0; 211} 212 213void 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 222DebugInfo::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 232namespace { 233bool 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. 239void 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. 273void 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 309bool 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 331MaybeHandle<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. 358int 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 367void 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 374void CoverageInfo::ResetBlockCount(int slot_index) { 375 set_slots_block_count(slot_index, 0); 376} 377 378void 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 400int 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 416void 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 461MaybeHandle<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