1// Copyright 2014 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 <vector> 6 7#include "src/codegen/compiler.h" 8#include "src/common/globals.h" 9#include "src/debug/debug-coverage.h" 10#include "src/debug/debug-evaluate.h" 11#include "src/debug/debug-frames.h" 12#include "src/debug/debug-scopes.h" 13#include "src/debug/debug.h" 14#include "src/debug/liveedit.h" 15#include "src/deoptimizer/deoptimizer.h" 16#include "src/execution/arguments-inl.h" 17#include "src/execution/frames-inl.h" 18#include "src/execution/isolate-inl.h" 19#include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop. 20#include "src/interpreter/bytecode-array-iterator.h" 21#include "src/interpreter/bytecodes.h" 22#include "src/interpreter/interpreter.h" 23#include "src/logging/counters.h" 24#include "src/objects/debug-objects-inl.h" 25#include "src/objects/heap-object-inl.h" 26#include "src/objects/js-array-buffer-inl.h" 27#include "src/objects/js-collection-inl.h" 28#include "src/objects/js-generator-inl.h" 29#include "src/objects/js-promise-inl.h" 30#include "src/runtime/runtime-utils.h" 31#include "src/runtime/runtime.h" 32#include "src/snapshot/embedded/embedded-data.h" 33#include "src/snapshot/snapshot.h" 34 35#if V8_ENABLE_WEBASSEMBLY 36#include "src/debug/debug-wasm-objects.h" 37#include "src/wasm/wasm-objects-inl.h" 38#endif // V8_ENABLE_WEBASSEMBLY 39 40namespace v8 { 41namespace internal { 42 43RUNTIME_FUNCTION_RETURN_PAIR(Runtime_DebugBreakOnBytecode) { 44 using interpreter::Bytecode; 45 using interpreter::Bytecodes; 46 using interpreter::OperandScale; 47 48 SealHandleScope shs(isolate); 49 DCHECK_EQ(1, args.length()); 50 Handle<Object> value = args.at(0); 51 HandleScope scope(isolate); 52 53 // Return value can be changed by debugger. Last set value will be used as 54 // return value. 55 ReturnValueScope result_scope(isolate->debug()); 56 isolate->debug()->set_return_value(*value); 57 58 // Get the top-most JavaScript frame. 59 JavaScriptFrameIterator it(isolate); 60 if (isolate->debug_execution_mode() == DebugInfo::kBreakpoints) { 61 isolate->debug()->Break(it.frame(), 62 handle(it.frame()->function(), isolate)); 63 } 64 65 // Return the handler from the original bytecode array. 66 DCHECK(it.frame()->is_interpreted()); 67 InterpretedFrame* interpreted_frame = 68 reinterpret_cast<InterpretedFrame*>(it.frame()); 69 70 bool side_effect_check_failed = false; 71 if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) { 72 side_effect_check_failed = 73 !isolate->debug()->PerformSideEffectCheckAtBytecode(interpreted_frame); 74 } 75 76 // Make sure to only access these objects after the side effect check, as the 77 // check can allocate on failure. 78 SharedFunctionInfo shared = interpreted_frame->function().shared(); 79 BytecodeArray bytecode_array = shared.GetBytecodeArray(isolate); 80 int bytecode_offset = interpreted_frame->GetBytecodeOffset(); 81 Bytecode bytecode = Bytecodes::FromByte(bytecode_array.get(bytecode_offset)); 82 83 if (Bytecodes::Returns(bytecode)) { 84 // If we are returning (or suspending), reset the bytecode array on the 85 // interpreted stack frame to the non-debug variant so that the interpreter 86 // entry trampoline sees the return/suspend bytecode rather than the 87 // DebugBreak. 88 interpreted_frame->PatchBytecodeArray(bytecode_array); 89 } 90 91 // We do not have to deal with operand scale here. If the bytecode at the 92 // break is prefixed by operand scaling, we would have patched over the 93 // scaling prefix. We now simply dispatch to the handler for the prefix. 94 // We need to deserialize now to ensure we don't hit the debug break again 95 // after deserializing. 96 OperandScale operand_scale = OperandScale::kSingle; 97 isolate->interpreter()->GetBytecodeHandler(bytecode, operand_scale); 98 99 if (side_effect_check_failed) { 100 return MakePair(ReadOnlyRoots(isolate).exception(), 101 Smi::FromInt(static_cast<uint8_t>(bytecode))); 102 } 103 Object interrupt_object = isolate->stack_guard()->HandleInterrupts(); 104 if (interrupt_object.IsException(isolate)) { 105 return MakePair(interrupt_object, 106 Smi::FromInt(static_cast<uint8_t>(bytecode))); 107 } 108 return MakePair(isolate->debug()->return_value(), 109 Smi::FromInt(static_cast<uint8_t>(bytecode))); 110} 111 112RUNTIME_FUNCTION(Runtime_DebugBreakAtEntry) { 113 HandleScope scope(isolate); 114 DCHECK_EQ(1, args.length()); 115 Handle<JSFunction> function = args.at<JSFunction>(0); 116 USE(function); 117 118 DCHECK(function->shared().HasDebugInfo()); 119 DCHECK(function->shared().GetDebugInfo().BreakAtEntry()); 120 121 // Get the top-most JavaScript frame. This is the debug target function. 122 JavaScriptFrameIterator it(isolate); 123 DCHECK_EQ(*function, it.frame()->function()); 124 // Check whether the next JS frame is closer than the last API entry. 125 // if yes, then the call to the debug target came from JavaScript. Otherwise, 126 // the call to the debug target came from API. Do not break for the latter. 127 it.Advance(); 128 if (!it.done() && 129 it.frame()->fp() < isolate->thread_local_top()->last_api_entry_) { 130 isolate->debug()->Break(it.frame(), function); 131 } 132 133 return ReadOnlyRoots(isolate).undefined_value(); 134} 135 136RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) { 137 SealHandleScope shs(isolate); 138 DCHECK_EQ(0, args.length()); 139 if (isolate->debug()->break_points_active()) { 140 isolate->debug()->HandleDebugBreak( 141 kIgnoreIfTopFrameBlackboxed, 142 v8::debug::BreakReasons({v8::debug::BreakReason::kDebuggerStatement})); 143 } 144 return isolate->stack_guard()->HandleInterrupts(); 145} 146 147RUNTIME_FUNCTION(Runtime_ScheduleBreak) { 148 SealHandleScope shs(isolate); 149 DCHECK_EQ(0, args.length()); 150 isolate->RequestInterrupt( 151 [](v8::Isolate* isolate, void*) { 152 v8::debug::BreakRightNow( 153 isolate, 154 v8::debug::BreakReasons({v8::debug::BreakReason::kScheduled})); 155 }, 156 nullptr); 157 return ReadOnlyRoots(isolate).undefined_value(); 158} 159 160namespace { 161 162template <class IteratorType> 163static Handle<ArrayList> AddIteratorInternalProperties( 164 Isolate* isolate, Handle<ArrayList> result, Handle<IteratorType> iterator) { 165 const char* kind = nullptr; 166 switch (iterator->map().instance_type()) { 167 case JS_MAP_KEY_ITERATOR_TYPE: 168 kind = "keys"; 169 break; 170 case JS_MAP_KEY_VALUE_ITERATOR_TYPE: 171 case JS_SET_KEY_VALUE_ITERATOR_TYPE: 172 kind = "entries"; 173 break; 174 case JS_MAP_VALUE_ITERATOR_TYPE: 175 case JS_SET_VALUE_ITERATOR_TYPE: 176 kind = "values"; 177 break; 178 default: 179 UNREACHABLE(); 180 } 181 182 result = ArrayList::Add( 183 isolate, result, 184 isolate->factory()->NewStringFromAsciiChecked("[[IteratorHasMore]]"), 185 isolate->factory()->ToBoolean(iterator->HasMore())); 186 result = ArrayList::Add( 187 isolate, result, 188 isolate->factory()->NewStringFromAsciiChecked("[[IteratorIndex]]"), 189 handle(iterator->index(), isolate)); 190 result = ArrayList::Add( 191 isolate, result, 192 isolate->factory()->NewStringFromAsciiChecked("[[IteratorKind]]"), 193 isolate->factory()->NewStringFromAsciiChecked(kind)); 194 return result; 195} 196 197} // namespace 198 199MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate, 200 Handle<Object> object) { 201 auto result = ArrayList::New(isolate, 8 * 2); 202 if (object->IsJSObject()) { 203 PrototypeIterator iter(isolate, Handle<JSObject>::cast(object), 204 kStartAtReceiver); 205 if (iter.HasAccess()) { 206 iter.Advance(); 207 Handle<Object> prototype = PrototypeIterator::GetCurrent(iter); 208 if (!prototype->IsNull(isolate)) { 209 result = ArrayList::Add( 210 isolate, result, 211 isolate->factory()->NewStringFromStaticChars("[[Prototype]]"), 212 prototype); 213 } 214 } 215 } 216 if (object->IsJSBoundFunction()) { 217 Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object); 218 219 result = ArrayList::Add( 220 isolate, result, 221 isolate->factory()->NewStringFromAsciiChecked("[[TargetFunction]]"), 222 handle(function->bound_target_function(), isolate)); 223 result = ArrayList::Add( 224 isolate, result, 225 isolate->factory()->NewStringFromAsciiChecked("[[BoundThis]]"), 226 handle(function->bound_this(), isolate)); 227 result = ArrayList::Add( 228 isolate, result, 229 isolate->factory()->NewStringFromAsciiChecked("[[BoundArgs]]"), 230 isolate->factory()->NewJSArrayWithElements( 231 isolate->factory()->CopyFixedArray( 232 handle(function->bound_arguments(), isolate)))); 233 } else if (object->IsJSMapIterator()) { 234 Handle<JSMapIterator> iterator = Handle<JSMapIterator>::cast(object); 235 result = AddIteratorInternalProperties(isolate, result, iterator); 236 } else if (object->IsJSSetIterator()) { 237 Handle<JSSetIterator> iterator = Handle<JSSetIterator>::cast(object); 238 result = AddIteratorInternalProperties(isolate, result, iterator); 239 } else if (object->IsJSGeneratorObject()) { 240 Handle<JSGeneratorObject> generator = 241 Handle<JSGeneratorObject>::cast(object); 242 243 const char* status = "suspended"; 244 if (generator->is_closed()) { 245 status = "closed"; 246 } else if (generator->is_executing()) { 247 status = "running"; 248 } else { 249 DCHECK(generator->is_suspended()); 250 } 251 252 result = ArrayList::Add( 253 isolate, result, 254 isolate->factory()->NewStringFromAsciiChecked("[[GeneratorState]]"), 255 isolate->factory()->NewStringFromAsciiChecked(status)); 256 result = ArrayList::Add( 257 isolate, result, 258 isolate->factory()->NewStringFromAsciiChecked("[[GeneratorFunction]]"), 259 handle(generator->function(), isolate)); 260 result = ArrayList::Add( 261 isolate, result, 262 isolate->factory()->NewStringFromAsciiChecked("[[GeneratorReceiver]]"), 263 handle(generator->receiver(), isolate)); 264 } else if (object->IsJSPromise()) { 265 Handle<JSPromise> promise = Handle<JSPromise>::cast(object); 266 267 result = ArrayList::Add( 268 isolate, result, 269 isolate->factory()->NewStringFromAsciiChecked("[[PromiseState]]"), 270 isolate->factory()->NewStringFromAsciiChecked( 271 JSPromise::Status(promise->status()))); 272 result = ArrayList::Add( 273 isolate, result, 274 isolate->factory()->NewStringFromAsciiChecked("[[PromiseResult]]"), 275 promise->status() == Promise::kPending 276 ? isolate->factory()->undefined_value() 277 : handle(promise->result(), isolate)); 278 } else if (object->IsJSProxy()) { 279 Handle<JSProxy> js_proxy = Handle<JSProxy>::cast(object); 280 281 result = ArrayList::Add( 282 isolate, result, 283 isolate->factory()->NewStringFromAsciiChecked("[[Handler]]"), 284 handle(js_proxy->handler(), isolate)); 285 result = ArrayList::Add( 286 isolate, result, 287 isolate->factory()->NewStringFromAsciiChecked("[[Target]]"), 288 handle(js_proxy->target(), isolate)); 289 result = ArrayList::Add( 290 isolate, result, 291 isolate->factory()->NewStringFromAsciiChecked("[[IsRevoked]]"), 292 isolate->factory()->ToBoolean(js_proxy->IsRevoked())); 293 } else if (object->IsJSPrimitiveWrapper()) { 294 Handle<JSPrimitiveWrapper> js_value = 295 Handle<JSPrimitiveWrapper>::cast(object); 296 297 result = ArrayList::Add( 298 isolate, result, 299 isolate->factory()->NewStringFromAsciiChecked("[[PrimitiveValue]]"), 300 handle(js_value->value(), isolate)); 301 } else if (object->IsJSArrayBuffer()) { 302 Handle<JSArrayBuffer> js_array_buffer = Handle<JSArrayBuffer>::cast(object); 303 if (js_array_buffer->was_detached()) { 304 // Mark a detached JSArrayBuffer and such and don't even try to 305 // create views for it, since the TypedArray constructors will 306 // throw a TypeError when the underlying buffer is detached. 307 result = ArrayList::Add( 308 isolate, result, 309 isolate->factory()->NewStringFromAsciiChecked("[[IsDetached]]"), 310 isolate->factory()->true_value()); 311 } else { 312 const size_t byte_length = js_array_buffer->byte_length(); 313 static const ExternalArrayType kTypes[] = { 314 kExternalInt8Array, 315 kExternalUint8Array, 316 kExternalInt16Array, 317 kExternalInt32Array, 318 }; 319 for (auto type : kTypes) { 320 switch (type) { 321#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ 322 case kExternal##Type##Array: { \ 323 if ((byte_length % sizeof(ctype)) != 0) continue; \ 324 result = ArrayList::Add( \ 325 isolate, result, \ 326 isolate->factory()->NewStringFromStaticChars("[[" #Type "Array]]"), \ 327 isolate->factory()->NewJSTypedArray(kExternal##Type##Array, \ 328 js_array_buffer, 0, \ 329 byte_length / sizeof(ctype))); \ 330 break; \ 331 } 332 TYPED_ARRAYS(TYPED_ARRAY_CASE) 333#undef TYPED_ARRAY_CASE 334 default: 335 UNREACHABLE(); 336 } 337 } 338 result = 339 ArrayList::Add(isolate, result, 340 isolate->factory()->NewStringFromAsciiChecked( 341 "[[ArrayBufferByteLength]]"), 342 isolate->factory()->NewNumberFromSize(byte_length)); 343 344 auto backing_store = js_array_buffer->GetBackingStore(); 345 Handle<Object> array_buffer_data = 346 backing_store 347 ? isolate->factory()->NewNumberFromUint(backing_store->id()) 348 : isolate->factory()->null_value(); 349 result = ArrayList::Add( 350 isolate, result, 351 isolate->factory()->NewStringFromAsciiChecked("[[ArrayBufferData]]"), 352 array_buffer_data); 353 354 Handle<Symbol> memory_symbol = 355 isolate->factory()->array_buffer_wasm_memory_symbol(); 356 Handle<Object> memory_object = 357 JSObject::GetDataProperty(isolate, js_array_buffer, memory_symbol); 358 if (!memory_object->IsUndefined(isolate)) { 359 result = ArrayList::Add(isolate, result, 360 isolate->factory()->NewStringFromAsciiChecked( 361 "[[WebAssemblyMemory]]"), 362 memory_object); 363 } 364 } 365#if V8_ENABLE_WEBASSEMBLY 366 } else if (object->IsWasmInstanceObject()) { 367 result = AddWasmInstanceObjectInternalProperties( 368 isolate, result, Handle<WasmInstanceObject>::cast(object)); 369 } else if (object->IsWasmModuleObject()) { 370 result = AddWasmModuleObjectInternalProperties( 371 isolate, result, Handle<WasmModuleObject>::cast(object)); 372 } else if (object->IsWasmTableObject()) { 373 result = AddWasmTableObjectInternalProperties( 374 isolate, result, Handle<WasmTableObject>::cast(object)); 375#endif // V8_ENABLE_WEBASSEMBLY 376 } 377 return isolate->factory()->NewJSArrayWithElements( 378 ArrayList::Elements(isolate, result), PACKED_ELEMENTS); 379} 380 381RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount) { 382 HandleScope scope(isolate); 383 DCHECK_EQ(1, args.length()); 384 385 if (!args[0].IsJSGeneratorObject()) return Smi::zero(); 386 387 // Check arguments. 388 Handle<JSGeneratorObject> gen = args.at<JSGeneratorObject>(0); 389 390 // Only inspect suspended generator scopes. 391 if (!gen->is_suspended()) { 392 return Smi::zero(); 393 } 394 395 // Count the visible scopes. 396 int n = 0; 397 for (ScopeIterator it(isolate, gen); !it.Done(); it.Next()) { 398 n++; 399 } 400 401 return Smi::FromInt(n); 402} 403 404RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) { 405 HandleScope scope(isolate); 406 DCHECK_EQ(2, args.length()); 407 408 if (!args[0].IsJSGeneratorObject()) { 409 return ReadOnlyRoots(isolate).undefined_value(); 410 } 411 412 // Check arguments. 413 Handle<JSGeneratorObject> gen = args.at<JSGeneratorObject>(0); 414 int index = NumberToInt32(args[1]); 415 416 // Only inspect suspended generator scopes. 417 if (!gen->is_suspended()) { 418 return ReadOnlyRoots(isolate).undefined_value(); 419 } 420 421 // Find the requested scope. 422 int n = 0; 423 ScopeIterator it(isolate, gen); 424 for (; !it.Done() && n < index; it.Next()) { 425 n++; 426 } 427 if (it.Done()) { 428 return ReadOnlyRoots(isolate).undefined_value(); 429 } 430 431 return *it.MaterializeScopeDetails(); 432} 433 434static bool SetScopeVariableValue(ScopeIterator* it, int index, 435 Handle<String> variable_name, 436 Handle<Object> new_value) { 437 for (int n = 0; !it->Done() && n < index; it->Next()) { 438 n++; 439 } 440 if (it->Done()) { 441 return false; 442 } 443 return it->SetVariableValue(variable_name, new_value); 444} 445 446// Change variable value in closure or local scope 447// args[0]: number or JsFunction: break id or function 448// args[1]: number: scope index 449// args[2]: string: variable name 450// args[3]: object: new value 451// 452// Return true if success and false otherwise 453RUNTIME_FUNCTION(Runtime_SetGeneratorScopeVariableValue) { 454 HandleScope scope(isolate); 455 DCHECK_EQ(4, args.length()); 456 Handle<JSGeneratorObject> gen = args.at<JSGeneratorObject>(0); 457 int index = NumberToInt32(args[1]); 458 Handle<String> variable_name = args.at<String>(2); 459 Handle<Object> new_value = args.at(3); 460 ScopeIterator it(isolate, gen); 461 bool res = SetScopeVariableValue(&it, index, variable_name, new_value); 462 return isolate->heap()->ToBoolean(res); 463} 464 465 466RUNTIME_FUNCTION(Runtime_GetBreakLocations) { 467 HandleScope scope(isolate); 468 DCHECK_EQ(1, args.length()); 469 CHECK(isolate->debug()->is_active()); 470 Handle<JSFunction> fun = args.at<JSFunction>(0); 471 472 Handle<SharedFunctionInfo> shared(fun->shared(), isolate); 473 // Find the number of break points 474 Handle<Object> break_locations = 475 Debug::GetSourceBreakLocations(isolate, shared); 476 if (break_locations->IsUndefined(isolate)) { 477 return ReadOnlyRoots(isolate).undefined_value(); 478 } 479 // Return array as JS array 480 return *isolate->factory()->NewJSArrayWithElements( 481 Handle<FixedArray>::cast(break_locations)); 482} 483 484 485// Returns the state of break on exceptions 486// args[0]: boolean indicating uncaught exceptions 487RUNTIME_FUNCTION(Runtime_IsBreakOnException) { 488 HandleScope scope(isolate); 489 DCHECK_EQ(1, args.length()); 490 uint32_t type_arg = NumberToUint32(args[0]); 491 492 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); 493 bool result = isolate->debug()->IsBreakOnException(type); 494 return Smi::FromInt(result); 495} 496 497// Clear all stepping set by PrepareStep. 498RUNTIME_FUNCTION(Runtime_ClearStepping) { 499 HandleScope scope(isolate); 500 DCHECK_EQ(0, args.length()); 501 CHECK(isolate->debug()->is_active()); 502 isolate->debug()->ClearStepping(); 503 return ReadOnlyRoots(isolate).undefined_value(); 504} 505 506RUNTIME_FUNCTION(Runtime_DebugGetLoadedScriptIds) { 507 HandleScope scope(isolate); 508 DCHECK_EQ(0, args.length()); 509 510 Handle<FixedArray> instances; 511 { 512 DebugScope debug_scope(isolate->debug()); 513 // Fill the script objects. 514 instances = isolate->debug()->GetLoadedScripts(); 515 } 516 517 // Convert the script objects to proper JS objects. 518 for (int i = 0; i < instances->length(); i++) { 519 Handle<Script> script(Script::cast(instances->get(i)), isolate); 520 instances->set(i, Smi::FromInt(script->id())); 521 } 522 523 // Return result as a JS array. 524 return *isolate->factory()->NewJSArrayWithElements(instances); 525} 526 527 528RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) { 529 SealHandleScope shs(isolate); 530 DCHECK_EQ(1, args.length()); 531 532 Object f = args[0]; 533 if (f.IsJSFunction()) { 534 return JSFunction::cast(f).shared().inferred_name(); 535 } 536 return ReadOnlyRoots(isolate).empty_string(); 537} 538 539 540// Performs a GC. 541// Presently, it only does a full GC. 542RUNTIME_FUNCTION(Runtime_CollectGarbage) { 543 SealHandleScope shs(isolate); 544 DCHECK_EQ(1, args.length()); 545 isolate->heap()->PreciseCollectAllGarbage(Heap::kNoGCFlags, 546 GarbageCollectionReason::kRuntime); 547 return ReadOnlyRoots(isolate).undefined_value(); 548} 549 550namespace { 551 552int ScriptLinePosition(Handle<Script> script, int line) { 553 if (line < 0) return -1; 554 555#if V8_ENABLE_WEBASSEMBLY 556 if (script->type() == Script::TYPE_WASM) { 557 // Wasm positions are relative to the start of the module. 558 return 0; 559 } 560#endif // V8_ENABLE_WEBASSEMBLY 561 562 Script::InitLineEnds(script->GetIsolate(), script); 563 564 FixedArray line_ends_array = FixedArray::cast(script->line_ends()); 565 const int line_count = line_ends_array.length(); 566 DCHECK_LT(0, line_count); 567 568 if (line == 0) return 0; 569 // If line == line_count, we return the first position beyond the last line. 570 if (line > line_count) return -1; 571 return Smi::ToInt(line_ends_array.get(line - 1)) + 1; 572} 573 574int ScriptLinePositionWithOffset(Handle<Script> script, int line, int offset) { 575 if (line < 0 || offset < 0) return -1; 576 577 if (line == 0 || offset == 0) 578 return ScriptLinePosition(script, line) + offset; 579 580 Script::PositionInfo info; 581 if (!Script::GetPositionInfo(script, offset, &info, Script::NO_OFFSET)) { 582 return -1; 583 } 584 585 const int total_line = info.line + line; 586 return ScriptLinePosition(script, total_line); 587} 588 589Handle<Object> GetJSPositionInfo(Handle<Script> script, int position, 590 Script::OffsetFlag offset_flag, 591 Isolate* isolate) { 592 Script::PositionInfo info; 593 if (!Script::GetPositionInfo(script, position, &info, offset_flag)) { 594 return isolate->factory()->null_value(); 595 } 596 597#if V8_ENABLE_WEBASSEMBLY 598 const bool is_wasm_script = script->type() == Script::TYPE_WASM; 599#else 600 const bool is_wasm_script = false; 601#endif // V8_ENABLE_WEBASSEMBLY 602 Handle<String> sourceText = 603 is_wasm_script ? isolate->factory()->empty_string() 604 : isolate->factory()->NewSubString( 605 handle(String::cast(script->source()), isolate), 606 info.line_start, info.line_end); 607 608 Handle<JSObject> jsinfo = 609 isolate->factory()->NewJSObject(isolate->object_function()); 610 611 JSObject::AddProperty(isolate, jsinfo, isolate->factory()->script_string(), 612 script, NONE); 613 JSObject::AddProperty(isolate, jsinfo, isolate->factory()->position_string(), 614 handle(Smi::FromInt(position), isolate), NONE); 615 JSObject::AddProperty(isolate, jsinfo, isolate->factory()->line_string(), 616 handle(Smi::FromInt(info.line), isolate), NONE); 617 JSObject::AddProperty(isolate, jsinfo, isolate->factory()->column_string(), 618 handle(Smi::FromInt(info.column), isolate), NONE); 619 JSObject::AddProperty(isolate, jsinfo, 620 isolate->factory()->sourceText_string(), sourceText, 621 NONE); 622 623 return jsinfo; 624} 625 626Handle<Object> ScriptLocationFromLine(Isolate* isolate, Handle<Script> script, 627 Handle<Object> opt_line, 628 Handle<Object> opt_column, 629 int32_t offset) { 630 // Line and column are possibly undefined and we need to handle these cases, 631 // additionally subtracting corresponding offsets. 632 633 int32_t line = 0; 634 if (!opt_line->IsNullOrUndefined(isolate)) { 635 CHECK(opt_line->IsNumber()); 636 line = NumberToInt32(*opt_line) - script->line_offset(); 637 } 638 639 int32_t column = 0; 640 if (!opt_column->IsNullOrUndefined(isolate)) { 641 CHECK(opt_column->IsNumber()); 642 column = NumberToInt32(*opt_column); 643 if (line == 0) column -= script->column_offset(); 644 } 645 646 int line_position = ScriptLinePositionWithOffset(script, line, offset); 647 if (line_position < 0 || column < 0) return isolate->factory()->null_value(); 648 649 return GetJSPositionInfo(script, line_position + column, Script::NO_OFFSET, 650 isolate); 651} 652 653// Slow traversal over all scripts on the heap. 654bool GetScriptById(Isolate* isolate, int needle, Handle<Script>* result) { 655 Script::Iterator iterator(isolate); 656 for (Script script = iterator.Next(); !script.is_null(); 657 script = iterator.Next()) { 658 if (script.id() == needle) { 659 *result = handle(script, isolate); 660 return true; 661 } 662 } 663 664 return false; 665} 666 667} // namespace 668 669// TODO(5530): Rename once conflicting function has been deleted. 670RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2) { 671 HandleScope scope(isolate); 672 DCHECK_EQ(4, args.length()); 673 int32_t scriptid = NumberToInt32(args[0]); 674 Handle<Object> opt_line = args.at(1); 675 Handle<Object> opt_column = args.at(2); 676 int32_t offset = NumberToInt32(args[3]); 677 678 Handle<Script> script; 679 CHECK(GetScriptById(isolate, scriptid, &script)); 680 681 return *ScriptLocationFromLine(isolate, script, opt_line, opt_column, offset); 682} 683 684// On function call, depending on circumstances, prepare for stepping in, 685// or perform a side effect check. 686RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall) { 687 HandleScope scope(isolate); 688 DCHECK_EQ(2, args.length()); 689 Handle<JSFunction> fun = args.at<JSFunction>(0); 690 Handle<Object> receiver = args.at(1); 691 if (isolate->debug()->needs_check_on_function_call()) { 692 // Ensure that the callee will perform debug check on function call too. 693 Handle<SharedFunctionInfo> shared(fun->shared(), isolate); 694 isolate->debug()->DeoptimizeFunction(shared); 695 if (isolate->debug()->last_step_action() >= StepInto || 696 isolate->debug()->break_on_next_function_call()) { 697 DCHECK_EQ(isolate->debug_execution_mode(), DebugInfo::kBreakpoints); 698 isolate->debug()->PrepareStepIn(fun); 699 } 700 if (isolate->debug_execution_mode() == DebugInfo::kSideEffects && 701 !isolate->debug()->PerformSideEffectCheck(fun, receiver)) { 702 return ReadOnlyRoots(isolate).exception(); 703 } 704 } 705 return ReadOnlyRoots(isolate).undefined_value(); 706} 707 708// Set one shot breakpoints for the suspended generator object. 709RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator) { 710 HandleScope scope(isolate); 711 DCHECK_EQ(0, args.length()); 712 isolate->debug()->PrepareStepInSuspendedGenerator(); 713 return ReadOnlyRoots(isolate).undefined_value(); 714} 715 716RUNTIME_FUNCTION(Runtime_DebugPushPromise) { 717 DCHECK_EQ(1, args.length()); 718 HandleScope scope(isolate); 719 Handle<JSObject> promise = args.at<JSObject>(0); 720 isolate->PushPromise(promise); 721 return ReadOnlyRoots(isolate).undefined_value(); 722} 723 724 725RUNTIME_FUNCTION(Runtime_DebugPopPromise) { 726 DCHECK_EQ(0, args.length()); 727 SealHandleScope shs(isolate); 728 isolate->PopPromise(); 729 return ReadOnlyRoots(isolate).undefined_value(); 730} 731 732namespace { 733Handle<JSObject> MakeRangeObject(Isolate* isolate, const CoverageBlock& range) { 734 Factory* factory = isolate->factory(); 735 736 Handle<String> start_string = factory->InternalizeUtf8String("start"); 737 Handle<String> end_string = factory->InternalizeUtf8String("end"); 738 Handle<String> count_string = factory->InternalizeUtf8String("count"); 739 740 Handle<JSObject> range_obj = factory->NewJSObjectWithNullProto(); 741 JSObject::AddProperty(isolate, range_obj, start_string, 742 factory->NewNumberFromInt(range.start), NONE); 743 JSObject::AddProperty(isolate, range_obj, end_string, 744 factory->NewNumberFromInt(range.end), NONE); 745 JSObject::AddProperty(isolate, range_obj, count_string, 746 factory->NewNumberFromUint(range.count), NONE); 747 748 return range_obj; 749} 750} // namespace 751 752RUNTIME_FUNCTION(Runtime_DebugCollectCoverage) { 753 HandleScope scope(isolate); 754 DCHECK_EQ(0, args.length()); 755 // Collect coverage data. 756 std::unique_ptr<Coverage> coverage; 757 if (isolate->is_best_effort_code_coverage()) { 758 coverage = Coverage::CollectBestEffort(isolate); 759 } else { 760 coverage = Coverage::CollectPrecise(isolate); 761 } 762 Factory* factory = isolate->factory(); 763 // Turn the returned data structure into JavaScript. 764 // Create an array of scripts. 765 int num_scripts = static_cast<int>(coverage->size()); 766 // Prepare property keys. 767 Handle<FixedArray> scripts_array = factory->NewFixedArray(num_scripts); 768 Handle<String> script_string = factory->script_string(); 769 for (int i = 0; i < num_scripts; i++) { 770 const auto& script_data = coverage->at(i); 771 HandleScope inner_scope(isolate); 772 773 std::vector<CoverageBlock> ranges; 774 int num_functions = static_cast<int>(script_data.functions.size()); 775 for (int j = 0; j < num_functions; j++) { 776 const auto& function_data = script_data.functions[j]; 777 ranges.emplace_back(function_data.start, function_data.end, 778 function_data.count); 779 for (size_t k = 0; k < function_data.blocks.size(); k++) { 780 const auto& block_data = function_data.blocks[k]; 781 ranges.emplace_back(block_data.start, block_data.end, block_data.count); 782 } 783 } 784 785 int num_ranges = static_cast<int>(ranges.size()); 786 Handle<FixedArray> ranges_array = factory->NewFixedArray(num_ranges); 787 for (int j = 0; j < num_ranges; j++) { 788 Handle<JSObject> range_object = MakeRangeObject(isolate, ranges[j]); 789 ranges_array->set(j, *range_object); 790 } 791 792 Handle<JSArray> script_obj = 793 factory->NewJSArrayWithElements(ranges_array, PACKED_ELEMENTS); 794 JSObject::AddProperty(isolate, script_obj, script_string, 795 handle(script_data.script->source(), isolate), NONE); 796 scripts_array->set(i, *script_obj); 797 } 798 return *factory->NewJSArrayWithElements(scripts_array, PACKED_ELEMENTS); 799} 800 801RUNTIME_FUNCTION(Runtime_DebugTogglePreciseCoverage) { 802 SealHandleScope shs(isolate); 803 bool enable = Oddball::cast(args[0]).ToBool(isolate); 804 Coverage::SelectMode(isolate, enable ? debug::CoverageMode::kPreciseCount 805 : debug::CoverageMode::kBestEffort); 806 return ReadOnlyRoots(isolate).undefined_value(); 807} 808 809RUNTIME_FUNCTION(Runtime_DebugToggleBlockCoverage) { 810 SealHandleScope shs(isolate); 811 bool enable = Oddball::cast(args[0]).ToBool(isolate); 812 Coverage::SelectMode(isolate, enable ? debug::CoverageMode::kBlockCount 813 : debug::CoverageMode::kBestEffort); 814 return ReadOnlyRoots(isolate).undefined_value(); 815} 816 817RUNTIME_FUNCTION(Runtime_IncBlockCounter) { 818 UNREACHABLE(); // Never called. See the IncBlockCounter builtin instead. 819} 820 821RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionSuspended) { 822 DCHECK_EQ(5, args.length()); 823 HandleScope scope(isolate); 824 Handle<JSPromise> promise = args.at<JSPromise>(0); 825 Handle<JSPromise> outer_promise = args.at<JSPromise>(1); 826 Handle<JSFunction> reject_handler = args.at<JSFunction>(2); 827 Handle<JSGeneratorObject> generator = args.at<JSGeneratorObject>(3); 828 bool is_predicted_as_caught = Oddball::cast(args[4]).ToBool(isolate); 829 830 // Allocate the throwaway promise and fire the appropriate init 831 // hook for the throwaway promise (passing the {promise} as its 832 // parent). 833 Handle<JSPromise> throwaway = isolate->factory()->NewJSPromiseWithoutHook(); 834 isolate->OnAsyncFunctionSuspended(throwaway, promise); 835 836 // The Promise will be thrown away and not handled, but it 837 // shouldn't trigger unhandled reject events as its work is done 838 throwaway->set_has_handler(true); 839 840 // Enable proper debug support for promises. 841 if (isolate->debug()->is_active()) { 842 Object::SetProperty(isolate, reject_handler, 843 isolate->factory()->promise_forwarding_handler_symbol(), 844 isolate->factory()->true_value(), 845 StoreOrigin::kMaybeKeyed, 846 Just(ShouldThrow::kThrowOnError)) 847 .Check(); 848 promise->set_handled_hint(is_predicted_as_caught); 849 850 // Mark the dependency to {outer_promise} in case the {throwaway} 851 // Promise is found on the Promise stack 852 Object::SetProperty(isolate, throwaway, 853 isolate->factory()->promise_handled_by_symbol(), 854 outer_promise, StoreOrigin::kMaybeKeyed, 855 Just(ShouldThrow::kThrowOnError)) 856 .Check(); 857 858 Object::SetProperty( 859 isolate, promise, isolate->factory()->promise_awaited_by_symbol(), 860 generator, StoreOrigin::kMaybeKeyed, Just(ShouldThrow::kThrowOnError)) 861 .Check(); 862 } 863 864 return *throwaway; 865} 866 867RUNTIME_FUNCTION(Runtime_DebugPromiseThen) { 868 DCHECK_EQ(1, args.length()); 869 HandleScope scope(isolate); 870 Handle<JSReceiver> promise = args.at<JSReceiver>(0); 871 if (promise->IsJSPromise()) { 872 isolate->OnPromiseThen(Handle<JSPromise>::cast(promise)); 873 } 874 return *promise; 875} 876 877RUNTIME_FUNCTION(Runtime_LiveEditPatchScript) { 878 HandleScope scope(isolate); 879 DCHECK_EQ(2, args.length()); 880 Handle<JSFunction> script_function = args.at<JSFunction>(0); 881 Handle<String> new_source = args.at<String>(1); 882 883 Handle<Script> script(Script::cast(script_function->shared().script()), 884 isolate); 885 v8::debug::LiveEditResult result; 886 LiveEdit::PatchScript(isolate, script, new_source, false, &result); 887 switch (result.status) { 888 case v8::debug::LiveEditResult::COMPILE_ERROR: 889 return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( 890 "LiveEdit failed: COMPILE_ERROR")); 891 case v8::debug::LiveEditResult::BLOCKED_BY_RUNNING_GENERATOR: 892 return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( 893 "LiveEdit failed: BLOCKED_BY_RUNNING_GENERATOR")); 894 case v8::debug::LiveEditResult::BLOCKED_BY_ACTIVE_FUNCTION: 895 return isolate->Throw(*isolate->factory()->NewStringFromAsciiChecked( 896 "LiveEdit failed: BLOCKED_BY_ACTIVE_FUNCTION")); 897 case v8::debug::LiveEditResult::OK: 898 return ReadOnlyRoots(isolate).undefined_value(); 899 } 900 return ReadOnlyRoots(isolate).undefined_value(); 901} 902 903RUNTIME_FUNCTION(Runtime_ProfileCreateSnapshotDataBlob) { 904 HandleScope scope(isolate); 905 DCHECK_EQ(0, args.length()); 906 907 // Used only by the test/memory/Memory.json benchmark. This creates a snapshot 908 // blob and outputs various statistics around it. 909 910 DCHECK(FLAG_profile_deserialization && FLAG_serialization_statistics); 911 912 DisableEmbeddedBlobRefcounting(); 913 914 v8::StartupData blob = CreateSnapshotDataBlobInternal( 915 v8::SnapshotCreator::FunctionCodeHandling::kClear, nullptr); 916 delete[] blob.data; 917 918 // Track the embedded blob size as well. 919 { 920 i::EmbeddedData d = i::EmbeddedData::FromBlob(isolate); 921 PrintF("Embedded blob is %d bytes\n", 922 static_cast<int>(d.code_size() + d.data_size())); 923 } 924 925 FreeCurrentEmbeddedBlob(); 926 927 return ReadOnlyRoots(isolate).undefined_value(); 928} 929 930} // namespace internal 931} // namespace v8 932