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 "src/runtime/runtime-utils.h" 6 7 #include "src/arguments.h" 8 #include "src/compiler.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/frames-inl.h" 16 #include "src/globals.h" 17 #include "src/interpreter/bytecodes.h" 18 #include "src/interpreter/interpreter.h" 19 #include "src/isolate-inl.h" 20 #include "src/runtime/runtime.h" 21 #include "src/wasm/wasm-module.h" 22 #include "src/wasm/wasm-objects.h" 23 24 namespace v8 { 25 namespace internal { 26 RUNTIME_FUNCTION(Runtime_DebugBreak)27 RUNTIME_FUNCTION(Runtime_DebugBreak) { 28 SealHandleScope shs(isolate); 29 DCHECK_EQ(1, args.length()); 30 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); 31 HandleScope scope(isolate); 32 ReturnValueScope result_scope(isolate->debug()); 33 isolate->debug()->set_return_value(*value); 34 35 // Get the top-most JavaScript frame. 36 JavaScriptFrameIterator it(isolate); 37 isolate->debug()->Break(it.frame()); 38 return isolate->debug()->return_value(); 39 } 40 RUNTIME_FUNCTION(Runtime_DebugBreakOnBytecode)41 RUNTIME_FUNCTION(Runtime_DebugBreakOnBytecode) { 42 SealHandleScope shs(isolate); 43 DCHECK_EQ(1, args.length()); 44 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); 45 HandleScope scope(isolate); 46 ReturnValueScope result_scope(isolate->debug()); 47 isolate->debug()->set_return_value(*value); 48 49 // Get the top-most JavaScript frame. 50 JavaScriptFrameIterator it(isolate); 51 isolate->debug()->Break(it.frame()); 52 53 // Return the handler from the original bytecode array. 54 DCHECK(it.frame()->is_interpreted()); 55 InterpretedFrame* interpreted_frame = 56 reinterpret_cast<InterpretedFrame*>(it.frame()); 57 SharedFunctionInfo* shared = interpreted_frame->function()->shared(); 58 BytecodeArray* bytecode_array = shared->bytecode_array(); 59 int bytecode_offset = interpreted_frame->GetBytecodeOffset(); 60 interpreter::Bytecode bytecode = 61 interpreter::Bytecodes::FromByte(bytecode_array->get(bytecode_offset)); 62 return isolate->interpreter()->GetBytecodeHandler( 63 bytecode, interpreter::OperandScale::kSingle); 64 } 65 66 RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement)67 RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) { 68 SealHandleScope shs(isolate); 69 DCHECK_EQ(0, args.length()); 70 if (isolate->debug()->break_points_active()) { 71 isolate->debug()->HandleDebugBreak(); 72 } 73 return isolate->heap()->undefined_value(); 74 } 75 76 77 // Adds a JavaScript function as a debug event listener. 78 // args[0]: debug event listener function to set or null or undefined for 79 // clearing the event listener function 80 // args[1]: object supplied during callback RUNTIME_FUNCTION(Runtime_SetDebugEventListener)81 RUNTIME_FUNCTION(Runtime_SetDebugEventListener) { 82 SealHandleScope shs(isolate); 83 DCHECK_EQ(2, args.length()); 84 CHECK(args[0]->IsJSFunction() || args[0]->IsNullOrUndefined(isolate)); 85 CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0); 86 CONVERT_ARG_HANDLE_CHECKED(Object, data, 1); 87 if (callback->IsJSFunction()) { 88 JavaScriptDebugDelegate* delegate = new JavaScriptDebugDelegate( 89 isolate, Handle<JSFunction>::cast(callback), data); 90 isolate->debug()->SetDebugDelegate(delegate, true); 91 } else { 92 isolate->debug()->SetDebugDelegate(nullptr, false); 93 } 94 return isolate->heap()->undefined_value(); 95 } 96 97 RUNTIME_FUNCTION(Runtime_ScheduleBreak)98 RUNTIME_FUNCTION(Runtime_ScheduleBreak) { 99 SealHandleScope shs(isolate); 100 DCHECK_EQ(0, args.length()); 101 isolate->stack_guard()->RequestDebugBreak(); 102 return isolate->heap()->undefined_value(); 103 } 104 105 DebugGetProperty(LookupIterator * it,bool * has_caught=NULL)106 static Handle<Object> DebugGetProperty(LookupIterator* it, 107 bool* has_caught = NULL) { 108 for (; it->IsFound(); it->Next()) { 109 switch (it->state()) { 110 case LookupIterator::NOT_FOUND: 111 case LookupIterator::TRANSITION: 112 UNREACHABLE(); 113 case LookupIterator::ACCESS_CHECK: 114 // Ignore access checks. 115 break; 116 case LookupIterator::INTEGER_INDEXED_EXOTIC: 117 case LookupIterator::INTERCEPTOR: 118 case LookupIterator::JSPROXY: 119 return it->isolate()->factory()->undefined_value(); 120 case LookupIterator::ACCESSOR: { 121 Handle<Object> accessors = it->GetAccessors(); 122 if (!accessors->IsAccessorInfo()) { 123 return it->isolate()->factory()->undefined_value(); 124 } 125 MaybeHandle<Object> maybe_result = 126 JSObject::GetPropertyWithAccessor(it); 127 Handle<Object> result; 128 if (!maybe_result.ToHandle(&result)) { 129 result = handle(it->isolate()->pending_exception(), it->isolate()); 130 it->isolate()->clear_pending_exception(); 131 if (has_caught != NULL) *has_caught = true; 132 } 133 return result; 134 } 135 136 case LookupIterator::DATA: 137 return it->GetDataValue(); 138 } 139 } 140 141 return it->isolate()->factory()->undefined_value(); 142 } 143 144 template <class IteratorType> GetIteratorInternalProperties(Isolate * isolate,Handle<IteratorType> object)145 static MaybeHandle<JSArray> GetIteratorInternalProperties( 146 Isolate* isolate, Handle<IteratorType> object) { 147 Factory* factory = isolate->factory(); 148 Handle<IteratorType> iterator = Handle<IteratorType>::cast(object); 149 CHECK(iterator->kind()->IsSmi()); 150 const char* kind = NULL; 151 switch (Smi::cast(iterator->kind())->value()) { 152 case IteratorType::kKindKeys: 153 kind = "keys"; 154 break; 155 case IteratorType::kKindValues: 156 kind = "values"; 157 break; 158 case IteratorType::kKindEntries: 159 kind = "entries"; 160 break; 161 default: 162 UNREACHABLE(); 163 } 164 165 Handle<FixedArray> result = factory->NewFixedArray(2 * 3); 166 Handle<String> has_more = 167 factory->NewStringFromAsciiChecked("[[IteratorHasMore]]"); 168 result->set(0, *has_more); 169 result->set(1, isolate->heap()->ToBoolean(iterator->HasMore())); 170 171 Handle<String> index = 172 factory->NewStringFromAsciiChecked("[[IteratorIndex]]"); 173 result->set(2, *index); 174 result->set(3, iterator->index()); 175 176 Handle<String> iterator_kind = 177 factory->NewStringFromAsciiChecked("[[IteratorKind]]"); 178 result->set(4, *iterator_kind); 179 Handle<String> kind_str = factory->NewStringFromAsciiChecked(kind); 180 result->set(5, *kind_str); 181 return factory->NewJSArrayWithElements(result); 182 } 183 184 GetInternalProperties(Isolate * isolate,Handle<Object> object)185 MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate, 186 Handle<Object> object) { 187 Factory* factory = isolate->factory(); 188 if (object->IsJSBoundFunction()) { 189 Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object); 190 191 Handle<FixedArray> result = factory->NewFixedArray(2 * 3); 192 Handle<String> target = 193 factory->NewStringFromAsciiChecked("[[TargetFunction]]"); 194 result->set(0, *target); 195 result->set(1, function->bound_target_function()); 196 197 Handle<String> bound_this = 198 factory->NewStringFromAsciiChecked("[[BoundThis]]"); 199 result->set(2, *bound_this); 200 result->set(3, function->bound_this()); 201 202 Handle<String> bound_args = 203 factory->NewStringFromAsciiChecked("[[BoundArgs]]"); 204 result->set(4, *bound_args); 205 Handle<FixedArray> bound_arguments = 206 factory->CopyFixedArray(handle(function->bound_arguments(), isolate)); 207 Handle<JSArray> arguments_array = 208 factory->NewJSArrayWithElements(bound_arguments); 209 result->set(5, *arguments_array); 210 return factory->NewJSArrayWithElements(result); 211 } else if (object->IsJSMapIterator()) { 212 Handle<JSMapIterator> iterator = Handle<JSMapIterator>::cast(object); 213 return GetIteratorInternalProperties(isolate, iterator); 214 } else if (object->IsJSSetIterator()) { 215 Handle<JSSetIterator> iterator = Handle<JSSetIterator>::cast(object); 216 return GetIteratorInternalProperties(isolate, iterator); 217 } else if (object->IsJSGeneratorObject()) { 218 Handle<JSGeneratorObject> generator = 219 Handle<JSGeneratorObject>::cast(object); 220 221 const char* status = "suspended"; 222 if (generator->is_closed()) { 223 status = "closed"; 224 } else if (generator->is_executing()) { 225 status = "running"; 226 } else { 227 DCHECK(generator->is_suspended()); 228 } 229 230 Handle<FixedArray> result = factory->NewFixedArray(2 * 3); 231 Handle<String> generator_status = 232 factory->NewStringFromAsciiChecked("[[GeneratorStatus]]"); 233 result->set(0, *generator_status); 234 Handle<String> status_str = factory->NewStringFromAsciiChecked(status); 235 result->set(1, *status_str); 236 237 Handle<String> function = 238 factory->NewStringFromAsciiChecked("[[GeneratorFunction]]"); 239 result->set(2, *function); 240 result->set(3, generator->function()); 241 242 Handle<String> receiver = 243 factory->NewStringFromAsciiChecked("[[GeneratorReceiver]]"); 244 result->set(4, *receiver); 245 result->set(5, generator->receiver()); 246 return factory->NewJSArrayWithElements(result); 247 } else if (object->IsJSPromise()) { 248 Handle<JSPromise> promise = Handle<JSPromise>::cast(object); 249 const char* status = JSPromise::Status(promise->status()); 250 Handle<FixedArray> result = factory->NewFixedArray(2 * 2); 251 Handle<String> promise_status = 252 factory->NewStringFromAsciiChecked("[[PromiseStatus]]"); 253 result->set(0, *promise_status); 254 Handle<String> status_str = factory->NewStringFromAsciiChecked(status); 255 result->set(1, *status_str); 256 257 Handle<Object> value_obj(promise->result(), isolate); 258 Handle<String> promise_value = 259 factory->NewStringFromAsciiChecked("[[PromiseValue]]"); 260 result->set(2, *promise_value); 261 result->set(3, *value_obj); 262 return factory->NewJSArrayWithElements(result); 263 } else if (object->IsJSProxy()) { 264 Handle<JSProxy> js_proxy = Handle<JSProxy>::cast(object); 265 Handle<FixedArray> result = factory->NewFixedArray(3 * 2); 266 267 Handle<String> handler_str = 268 factory->NewStringFromAsciiChecked("[[Handler]]"); 269 result->set(0, *handler_str); 270 result->set(1, js_proxy->handler()); 271 272 Handle<String> target_str = 273 factory->NewStringFromAsciiChecked("[[Target]]"); 274 result->set(2, *target_str); 275 result->set(3, js_proxy->target()); 276 277 Handle<String> is_revoked_str = 278 factory->NewStringFromAsciiChecked("[[IsRevoked]]"); 279 result->set(4, *is_revoked_str); 280 result->set(5, isolate->heap()->ToBoolean(js_proxy->IsRevoked())); 281 return factory->NewJSArrayWithElements(result); 282 } else if (object->IsJSValue()) { 283 Handle<JSValue> js_value = Handle<JSValue>::cast(object); 284 285 Handle<FixedArray> result = factory->NewFixedArray(2); 286 Handle<String> primitive_value = 287 factory->NewStringFromAsciiChecked("[[PrimitiveValue]]"); 288 result->set(0, *primitive_value); 289 result->set(1, js_value->value()); 290 return factory->NewJSArrayWithElements(result); 291 } 292 return factory->NewJSArray(0); 293 } 294 295 RUNTIME_FUNCTION(Runtime_DebugGetInternalProperties)296 RUNTIME_FUNCTION(Runtime_DebugGetInternalProperties) { 297 HandleScope scope(isolate); 298 DCHECK_EQ(1, args.length()); 299 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); 300 RETURN_RESULT_OR_FAILURE(isolate, 301 Runtime::GetInternalProperties(isolate, obj)); 302 } 303 304 305 // Get debugger related details for an object property, in the following format: 306 // 0: Property value 307 // 1: Property details 308 // 2: Property value is exception 309 // 3: Getter function if defined 310 // 4: Setter function if defined 311 // Items 2-4 are only filled if the property has either a getter or a setter. RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails)312 RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) { 313 HandleScope scope(isolate); 314 DCHECK_EQ(2, args.length()); 315 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 316 CONVERT_ARG_HANDLE_CHECKED(Object, name_obj, 1); 317 318 // Convert the {name_obj} to a Name. 319 Handle<Name> name; 320 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, 321 Object::ToName(isolate, name_obj)); 322 323 // Make sure to set the current context to the context before the debugger was 324 // entered (if the debugger is entered). The reason for switching context here 325 // is that for some property lookups (accessors and interceptors) callbacks 326 // into the embedding application can occour, and the embedding application 327 // could have the assumption that its own native context is the current 328 // context and not some internal debugger context. 329 SaveContext save(isolate); 330 if (isolate->debug()->in_debug_scope()) { 331 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); 332 } 333 334 // Check if the name is trivially convertible to an index and get the element 335 // if so. 336 uint32_t index; 337 // TODO(verwaest): Make sure DebugGetProperty can handle arrays, and remove 338 // this special case. 339 if (name->AsArrayIndex(&index)) { 340 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); 341 Handle<Object> element_or_char; 342 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 343 isolate, element_or_char, JSReceiver::GetElement(isolate, obj, index)); 344 details->set(0, *element_or_char); 345 details->set(1, PropertyDetails::Empty().AsSmi()); 346 return *isolate->factory()->NewJSArrayWithElements(details); 347 } 348 349 LookupIterator it(obj, name, LookupIterator::OWN); 350 bool has_caught = false; 351 Handle<Object> value = DebugGetProperty(&it, &has_caught); 352 if (!it.IsFound()) return isolate->heap()->undefined_value(); 353 354 Handle<Object> maybe_pair; 355 if (it.state() == LookupIterator::ACCESSOR) { 356 maybe_pair = it.GetAccessors(); 357 } 358 359 // If the callback object is a fixed array then it contains JavaScript 360 // getter and/or setter. 361 bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair(); 362 Handle<FixedArray> details = 363 isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3); 364 details->set(0, *value); 365 // TODO(verwaest): Get rid of this random way of handling interceptors. 366 PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR 367 ? PropertyDetails::Empty() 368 : it.property_details(); 369 details->set(1, d.AsSmi()); 370 details->set( 371 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR)); 372 if (has_js_accessors) { 373 Handle<AccessorPair> accessors = Handle<AccessorPair>::cast(maybe_pair); 374 details->set(3, isolate->heap()->ToBoolean(has_caught)); 375 Handle<Object> getter = 376 AccessorPair::GetComponent(accessors, ACCESSOR_GETTER); 377 Handle<Object> setter = 378 AccessorPair::GetComponent(accessors, ACCESSOR_SETTER); 379 details->set(4, *getter); 380 details->set(5, *setter); 381 } 382 383 return *isolate->factory()->NewJSArrayWithElements(details); 384 } 385 386 RUNTIME_FUNCTION(Runtime_DebugGetProperty)387 RUNTIME_FUNCTION(Runtime_DebugGetProperty) { 388 HandleScope scope(isolate); 389 390 DCHECK_EQ(2, args.length()); 391 392 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); 393 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 394 395 LookupIterator it(obj, name); 396 return *DebugGetProperty(&it); 397 } 398 399 // Return the property kind calculated from the property details. 400 // args[0]: smi with property details. RUNTIME_FUNCTION(Runtime_DebugPropertyKindFromDetails)401 RUNTIME_FUNCTION(Runtime_DebugPropertyKindFromDetails) { 402 SealHandleScope shs(isolate); 403 DCHECK_EQ(1, args.length()); 404 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 405 return Smi::FromInt(static_cast<int>(details.kind())); 406 } 407 408 409 // Return the property attribute calculated from the property details. 410 // args[0]: smi with property details. RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails)411 RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) { 412 SealHandleScope shs(isolate); 413 DCHECK_EQ(1, args.length()); 414 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 415 return Smi::FromInt(static_cast<int>(details.attributes())); 416 } 417 418 RUNTIME_FUNCTION(Runtime_CheckExecutionState)419 RUNTIME_FUNCTION(Runtime_CheckExecutionState) { 420 SealHandleScope shs(isolate); 421 DCHECK_EQ(1, args.length()); 422 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 423 CHECK(isolate->debug()->CheckExecutionState(break_id)); 424 return isolate->heap()->true_value(); 425 } 426 427 RUNTIME_FUNCTION(Runtime_GetFrameCount)428 RUNTIME_FUNCTION(Runtime_GetFrameCount) { 429 HandleScope scope(isolate); 430 DCHECK_EQ(1, args.length()); 431 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 432 CHECK(isolate->debug()->CheckExecutionState(break_id)); 433 434 // Count all frames which are relevant to debugging stack trace. 435 int n = 0; 436 StackFrame::Id id = isolate->debug()->break_frame_id(); 437 if (id == StackFrame::NO_ID) { 438 // If there is no JavaScript stack frame count is 0. 439 return Smi::kZero; 440 } 441 442 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); 443 for (StackTraceFrameIterator it(isolate, id); !it.done(); it.Advance()) { 444 frames.Clear(); 445 it.frame()->Summarize(&frames); 446 for (int i = frames.length() - 1; i >= 0; i--) { 447 // Omit functions from native and extension scripts. 448 if (frames[i].is_subject_to_debugging()) n++; 449 } 450 } 451 return Smi::FromInt(n); 452 } 453 454 static const int kFrameDetailsFrameIdIndex = 0; 455 static const int kFrameDetailsReceiverIndex = 1; 456 static const int kFrameDetailsFunctionIndex = 2; 457 static const int kFrameDetailsScriptIndex = 3; 458 static const int kFrameDetailsArgumentCountIndex = 4; 459 static const int kFrameDetailsLocalCountIndex = 5; 460 static const int kFrameDetailsSourcePositionIndex = 6; 461 static const int kFrameDetailsConstructCallIndex = 7; 462 static const int kFrameDetailsAtReturnIndex = 8; 463 static const int kFrameDetailsFlagsIndex = 9; 464 static const int kFrameDetailsFirstDynamicIndex = 10; 465 466 // Return an array with frame details 467 // args[0]: number: break id 468 // args[1]: number: frame index 469 // 470 // The array returned contains the following information: 471 // 0: Frame id 472 // 1: Receiver 473 // 2: Function 474 // 3: Script 475 // 4: Argument count 476 // 5: Local count 477 // 6: Source position 478 // 7: Constructor call 479 // 8: Is at return 480 // 9: Flags 481 // Arguments name, value 482 // Locals name, value 483 // Return value if any RUNTIME_FUNCTION(Runtime_GetFrameDetails)484 RUNTIME_FUNCTION(Runtime_GetFrameDetails) { 485 HandleScope scope(isolate); 486 DCHECK_EQ(2, args.length()); 487 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 488 CHECK(isolate->debug()->CheckExecutionState(break_id)); 489 490 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 491 Heap* heap = isolate->heap(); 492 493 // Find the relevant frame with the requested index. 494 StackFrame::Id id = isolate->debug()->break_frame_id(); 495 if (id == StackFrame::NO_ID) { 496 // If there are no JavaScript stack frames return undefined. 497 return heap->undefined_value(); 498 } 499 500 StackTraceFrameIterator it(isolate, id); 501 // Inlined frame index in optimized frame, starting from outer function. 502 int inlined_frame_index = 503 DebugFrameHelper::FindIndexedNonNativeFrame(&it, index); 504 if (inlined_frame_index == -1) return heap->undefined_value(); 505 506 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate); 507 508 // Traverse the saved contexts chain to find the active context for the 509 // selected frame. 510 SaveContext* save = 511 DebugFrameHelper::FindSavedContextForFrame(isolate, it.frame()); 512 513 // Get the frame id. 514 Handle<Object> frame_id(DebugFrameHelper::WrapFrameId(it.frame()->id()), 515 isolate); 516 517 if (frame_inspector.summary().IsWasm()) { 518 // Create the details array (no dynamic information for wasm). 519 Handle<FixedArray> details = 520 isolate->factory()->NewFixedArray(kFrameDetailsFirstDynamicIndex); 521 522 // Add the frame id. 523 details->set(kFrameDetailsFrameIdIndex, *frame_id); 524 525 // Add the function name. 526 Handle<String> func_name = frame_inspector.summary().FunctionName(); 527 details->set(kFrameDetailsFunctionIndex, *func_name); 528 529 // Add the script wrapper 530 Handle<Object> script_wrapper = 531 Script::GetWrapper(frame_inspector.GetScript()); 532 details->set(kFrameDetailsScriptIndex, *script_wrapper); 533 534 // Add the arguments count. 535 details->set(kFrameDetailsArgumentCountIndex, Smi::kZero); 536 537 // Add the locals count 538 details->set(kFrameDetailsLocalCountIndex, Smi::kZero); 539 540 // Add the source position. 541 int position = frame_inspector.summary().SourcePosition(); 542 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); 543 544 // Add the constructor information. 545 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(false)); 546 547 // Add the at return information. 548 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(false)); 549 550 // Add flags to indicate information on whether this frame is 551 // bit 0: invoked in the debugger context. 552 // bit 1: optimized frame. 553 // bit 2: inlined in optimized frame 554 int flags = 0; 555 if (*save->context() == *isolate->debug()->debug_context()) { 556 flags |= 1 << 0; 557 } 558 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); 559 560 return *isolate->factory()->NewJSArrayWithElements(details); 561 } 562 563 // Find source position in unoptimized code. 564 int position = frame_inspector.GetSourcePosition(); 565 566 // Handle JavaScript frames. 567 bool is_optimized = it.frame()->is_optimized(); 568 569 // Check for constructor frame. 570 bool constructor = frame_inspector.IsConstructor(); 571 572 // Get scope info and read from it for local variable information. 573 Handle<JSFunction> function = 574 Handle<JSFunction>::cast(frame_inspector.GetFunction()); 575 CHECK(function->shared()->IsSubjectToDebugging()); 576 Handle<SharedFunctionInfo> shared(function->shared()); 577 Handle<ScopeInfo> scope_info(shared->scope_info()); 578 DCHECK(*scope_info != ScopeInfo::Empty(isolate)); 579 580 // Get the locals names and values into a temporary array. 581 Handle<Object> maybe_context = frame_inspector.GetContext(); 582 const int local_count_with_synthetic = maybe_context->IsContext() 583 ? scope_info->LocalCount() 584 : scope_info->StackLocalCount(); 585 int local_count = local_count_with_synthetic; 586 for (int slot = 0; slot < local_count_with_synthetic; ++slot) { 587 // Hide compiler-introduced temporary variables, whether on the stack or on 588 // the context. 589 if (ScopeInfo::VariableIsSynthetic(scope_info->LocalName(slot))) { 590 local_count--; 591 } 592 } 593 594 List<Handle<Object>> locals; 595 // Fill in the values of the locals. 596 int i = 0; 597 for (; i < scope_info->StackLocalCount(); ++i) { 598 // Use the value from the stack. 599 if (ScopeInfo::VariableIsSynthetic(scope_info->LocalName(i))) continue; 600 locals.Add(Handle<String>(scope_info->LocalName(i), isolate)); 601 Handle<Object> value = 602 frame_inspector.GetExpression(scope_info->StackLocalIndex(i)); 603 // TODO(yangguo): We convert optimized out values to {undefined} when they 604 // are passed to the debugger. Eventually we should handle them somehow. 605 if (value->IsOptimizedOut(isolate)) { 606 value = isolate->factory()->undefined_value(); 607 } 608 locals.Add(value); 609 } 610 if (locals.length() < local_count * 2) { 611 // Get the context containing declarations. 612 DCHECK(maybe_context->IsContext()); 613 Handle<Context> context(Context::cast(*maybe_context)->closure_context()); 614 615 for (; i < scope_info->LocalCount(); ++i) { 616 Handle<String> name(scope_info->LocalName(i)); 617 if (ScopeInfo::VariableIsSynthetic(*name)) continue; 618 VariableMode mode; 619 InitializationFlag init_flag; 620 MaybeAssignedFlag maybe_assigned_flag; 621 locals.Add(name); 622 int context_slot_index = ScopeInfo::ContextSlotIndex( 623 scope_info, name, &mode, &init_flag, &maybe_assigned_flag); 624 Object* value = context->get(context_slot_index); 625 locals.Add(Handle<Object>(value, isolate)); 626 } 627 } 628 629 // Check whether this frame is positioned at return. If not top 630 // frame or if the frame is optimized it cannot be at a return. 631 bool at_return = false; 632 if (!is_optimized && index == 0) { 633 at_return = isolate->debug()->IsBreakAtReturn(it.javascript_frame()); 634 } 635 636 // If positioned just before return find the value to be returned and add it 637 // to the frame information. 638 Handle<Object> return_value = isolate->factory()->undefined_value(); 639 if (at_return) { 640 return_value = handle(isolate->debug()->return_value(), isolate); 641 } 642 643 // Now advance to the arguments adapter frame (if any). It contains all 644 // the provided parameters whereas the function frame always have the number 645 // of arguments matching the functions parameters. The rest of the 646 // information (except for what is collected above) is the same. 647 if ((inlined_frame_index == 0) && 648 it.javascript_frame()->has_adapted_arguments()) { 649 it.AdvanceToArgumentsFrame(); 650 frame_inspector.SetArgumentsFrame(it.frame()); 651 } 652 653 // Find the number of arguments to fill. At least fill the number of 654 // parameters for the function and fill more if more parameters are provided. 655 int argument_count = scope_info->ParameterCount(); 656 if (argument_count < frame_inspector.GetParametersCount()) { 657 argument_count = frame_inspector.GetParametersCount(); 658 } 659 660 // Calculate the size of the result. 661 int details_size = kFrameDetailsFirstDynamicIndex + 662 2 * (argument_count + local_count) + (at_return ? 1 : 0); 663 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); 664 665 // Add the frame id. 666 details->set(kFrameDetailsFrameIdIndex, *frame_id); 667 668 // Add the function (same as in function frame). 669 details->set(kFrameDetailsFunctionIndex, *(frame_inspector.GetFunction())); 670 671 // Add the script wrapper 672 Handle<Object> script_wrapper = 673 Script::GetWrapper(frame_inspector.GetScript()); 674 details->set(kFrameDetailsScriptIndex, *script_wrapper); 675 676 // Add the arguments count. 677 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); 678 679 // Add the locals count 680 details->set(kFrameDetailsLocalCountIndex, Smi::FromInt(local_count)); 681 682 // Add the source position. 683 if (position != kNoSourcePosition) { 684 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); 685 } else { 686 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value()); 687 } 688 689 // Add the constructor information. 690 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor)); 691 692 // Add the at return information. 693 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); 694 695 // Add flags to indicate information on whether this frame is 696 // bit 0: invoked in the debugger context. 697 // bit 1: optimized frame. 698 // bit 2: inlined in optimized frame 699 int flags = 0; 700 if (*save->context() == *isolate->debug()->debug_context()) { 701 flags |= 1 << 0; 702 } 703 if (is_optimized) { 704 flags |= 1 << 1; 705 flags |= inlined_frame_index << 2; 706 } 707 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); 708 709 // Fill the dynamic part. 710 int details_index = kFrameDetailsFirstDynamicIndex; 711 712 // Add arguments name and value. 713 for (int i = 0; i < argument_count; i++) { 714 // Name of the argument. 715 if (i < scope_info->ParameterCount()) { 716 details->set(details_index++, scope_info->ParameterName(i)); 717 } else { 718 details->set(details_index++, heap->undefined_value()); 719 } 720 721 // Parameter value. 722 if (i < frame_inspector.GetParametersCount()) { 723 // Get the value from the stack. 724 details->set(details_index++, *(frame_inspector.GetParameter(i))); 725 } else { 726 details->set(details_index++, heap->undefined_value()); 727 } 728 } 729 730 // Add locals name and value from the temporary copy from the function frame. 731 for (const auto& local : locals) details->set(details_index++, *local); 732 733 // Add the value being returned. 734 if (at_return) { 735 details->set(details_index++, *return_value); 736 } 737 738 // Add the receiver (same as in function frame). 739 Handle<Object> receiver = frame_inspector.summary().receiver(); 740 DCHECK(function->shared()->IsUserJavaScript()); 741 // Optimized frames only restore the receiver as best-effort (see 742 // OptimizedFrame::Summarize). 743 DCHECK_IMPLIES(!is_optimized && is_sloppy(shared->language_mode()), 744 receiver->IsJSReceiver()); 745 details->set(kFrameDetailsReceiverIndex, *receiver); 746 747 DCHECK_EQ(details_size, details_index); 748 return *isolate->factory()->NewJSArrayWithElements(details); 749 } 750 751 RUNTIME_FUNCTION(Runtime_GetScopeCount)752 RUNTIME_FUNCTION(Runtime_GetScopeCount) { 753 HandleScope scope(isolate); 754 DCHECK_EQ(2, args.length()); 755 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 756 CHECK(isolate->debug()->CheckExecutionState(break_id)); 757 758 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 759 760 // Get the frame where the debugging is performed. 761 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 762 StackTraceFrameIterator it(isolate, id); 763 StandardFrame* frame = it.frame(); 764 if (it.frame()->is_wasm()) return 0; 765 766 FrameInspector frame_inspector(frame, 0, isolate); 767 768 // Count the visible scopes. 769 int n = 0; 770 for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) { 771 n++; 772 } 773 774 return Smi::FromInt(n); 775 } 776 777 778 // Return an array with scope details 779 // args[0]: number: break id 780 // args[1]: number: frame index 781 // args[2]: number: inlined frame index 782 // args[3]: number: scope index 783 // 784 // The array returned contains the following information: 785 // 0: Scope type 786 // 1: Scope object RUNTIME_FUNCTION(Runtime_GetScopeDetails)787 RUNTIME_FUNCTION(Runtime_GetScopeDetails) { 788 HandleScope scope(isolate); 789 DCHECK_EQ(4, args.length()); 790 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 791 CHECK(isolate->debug()->CheckExecutionState(break_id)); 792 793 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 794 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 795 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 796 797 // Get the frame where the debugging is performed. 798 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 799 StackTraceFrameIterator frame_it(isolate, id); 800 // Wasm has no scopes, this must be javascript. 801 JavaScriptFrame* frame = JavaScriptFrame::cast(frame_it.frame()); 802 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 803 804 // Find the requested scope. 805 int n = 0; 806 ScopeIterator it(isolate, &frame_inspector); 807 for (; !it.Done() && n < index; it.Next()) { 808 n++; 809 } 810 if (it.Done()) { 811 return isolate->heap()->undefined_value(); 812 } 813 RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails()); 814 } 815 816 817 // Return an array of scope details 818 // args[0]: number: break id 819 // args[1]: number: frame index 820 // args[2]: number: inlined frame index 821 // args[3]: boolean: ignore nested scopes 822 // 823 // The array returned contains arrays with the following information: 824 // 0: Scope type 825 // 1: Scope object RUNTIME_FUNCTION(Runtime_GetAllScopesDetails)826 RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) { 827 HandleScope scope(isolate); 828 DCHECK(args.length() == 3 || args.length() == 4); 829 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 830 CHECK(isolate->debug()->CheckExecutionState(break_id)); 831 832 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 833 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 834 835 ScopeIterator::Option option = ScopeIterator::DEFAULT; 836 if (args.length() == 4) { 837 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3); 838 if (flag) option = ScopeIterator::IGNORE_NESTED_SCOPES; 839 } 840 841 // Get the frame where the debugging is performed. 842 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 843 StackTraceFrameIterator frame_it(isolate, id); 844 StandardFrame* frame = frame_it.frame(); 845 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 846 847 List<Handle<JSObject> > result(4); 848 ScopeIterator it(isolate, &frame_inspector, option); 849 for (; !it.Done(); it.Next()) { 850 Handle<JSObject> details; 851 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, 852 it.MaterializeScopeDetails()); 853 result.Add(details); 854 } 855 856 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length()); 857 for (int i = 0; i < result.length(); ++i) { 858 array->set(i, *result[i]); 859 } 860 return *isolate->factory()->NewJSArrayWithElements(array); 861 } 862 863 RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount)864 RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) { 865 HandleScope scope(isolate); 866 DCHECK_EQ(1, args.length()); 867 868 // Check arguments. 869 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0); 870 871 // Count the visible scopes. 872 int n = 0; 873 if (function->IsJSFunction()) { 874 for (ScopeIterator it(isolate, Handle<JSFunction>::cast(function)); 875 !it.Done(); it.Next()) { 876 n++; 877 } 878 } 879 880 return Smi::FromInt(n); 881 } 882 883 RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails)884 RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) { 885 HandleScope scope(isolate); 886 DCHECK_EQ(2, args.length()); 887 888 // Check arguments. 889 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 890 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 891 892 // Find the requested scope. 893 int n = 0; 894 ScopeIterator it(isolate, fun); 895 for (; !it.Done() && n < index; it.Next()) { 896 n++; 897 } 898 if (it.Done()) { 899 return isolate->heap()->undefined_value(); 900 } 901 902 RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails()); 903 } 904 RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount)905 RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount) { 906 HandleScope scope(isolate); 907 DCHECK_EQ(1, args.length()); 908 909 if (!args[0]->IsJSGeneratorObject()) return Smi::kZero; 910 911 // Check arguments. 912 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0); 913 914 // Count the visible scopes. 915 int n = 0; 916 for (ScopeIterator it(isolate, gen); !it.Done(); it.Next()) { 917 n++; 918 } 919 920 return Smi::FromInt(n); 921 } 922 RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails)923 RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) { 924 HandleScope scope(isolate); 925 DCHECK_EQ(2, args.length()); 926 927 if (!args[0]->IsJSGeneratorObject()) { 928 return isolate->heap()->undefined_value(); 929 } 930 931 // Check arguments. 932 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0); 933 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 934 935 // Find the requested scope. 936 int n = 0; 937 ScopeIterator it(isolate, gen); 938 for (; !it.Done() && n < index; it.Next()) { 939 n++; 940 } 941 if (it.Done()) { 942 return isolate->heap()->undefined_value(); 943 } 944 945 RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails()); 946 } 947 SetScopeVariableValue(ScopeIterator * it,int index,Handle<String> variable_name,Handle<Object> new_value)948 static bool SetScopeVariableValue(ScopeIterator* it, int index, 949 Handle<String> variable_name, 950 Handle<Object> new_value) { 951 for (int n = 0; !it->Done() && n < index; it->Next()) { 952 n++; 953 } 954 if (it->Done()) { 955 return false; 956 } 957 return it->SetVariableValue(variable_name, new_value); 958 } 959 960 961 // Change variable value in closure or local scope 962 // args[0]: number or JsFunction: break id or function 963 // args[1]: number: frame index (when arg[0] is break id) 964 // args[2]: number: inlined frame index (when arg[0] is break id) 965 // args[3]: number: scope index 966 // args[4]: string: variable name 967 // args[5]: object: new value 968 // 969 // Return true if success and false otherwise RUNTIME_FUNCTION(Runtime_SetScopeVariableValue)970 RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) { 971 HandleScope scope(isolate); 972 DCHECK_EQ(6, args.length()); 973 974 // Check arguments. 975 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 976 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4); 977 CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5); 978 979 bool res; 980 if (args[0]->IsNumber()) { 981 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 982 CHECK(isolate->debug()->CheckExecutionState(break_id)); 983 984 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 985 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 986 987 // Get the frame where the debugging is performed. 988 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 989 StackTraceFrameIterator frame_it(isolate, id); 990 // Wasm has no scopes, this must be javascript. 991 JavaScriptFrame* frame = JavaScriptFrame::cast(frame_it.frame()); 992 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 993 994 ScopeIterator it(isolate, &frame_inspector); 995 res = SetScopeVariableValue(&it, index, variable_name, new_value); 996 } else if (args[0]->IsJSFunction()) { 997 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 998 ScopeIterator it(isolate, fun); 999 res = SetScopeVariableValue(&it, index, variable_name, new_value); 1000 } else { 1001 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0); 1002 ScopeIterator it(isolate, gen); 1003 res = SetScopeVariableValue(&it, index, variable_name, new_value); 1004 } 1005 1006 return isolate->heap()->ToBoolean(res); 1007 } 1008 1009 RUNTIME_FUNCTION(Runtime_DebugPrintScopes)1010 RUNTIME_FUNCTION(Runtime_DebugPrintScopes) { 1011 HandleScope scope(isolate); 1012 DCHECK_EQ(0, args.length()); 1013 1014 #ifdef DEBUG 1015 // Print the scopes for the top frame. 1016 StackFrameLocator locator(isolate); 1017 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 1018 FrameInspector frame_inspector(frame, 0, isolate); 1019 1020 for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) { 1021 it.DebugPrint(); 1022 } 1023 #endif 1024 return isolate->heap()->undefined_value(); 1025 } 1026 1027 1028 // Sets the disable break state 1029 // args[0]: disable break state RUNTIME_FUNCTION(Runtime_SetBreakPointsActive)1030 RUNTIME_FUNCTION(Runtime_SetBreakPointsActive) { 1031 HandleScope scope(isolate); 1032 DCHECK_EQ(1, args.length()); 1033 CONVERT_BOOLEAN_ARG_CHECKED(active, 0); 1034 isolate->debug()->set_break_points_active(active); 1035 return isolate->heap()->undefined_value(); 1036 } 1037 1038 IsPositionAlignmentCodeCorrect(int alignment)1039 static bool IsPositionAlignmentCodeCorrect(int alignment) { 1040 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED; 1041 } 1042 1043 RUNTIME_FUNCTION(Runtime_GetBreakLocations)1044 RUNTIME_FUNCTION(Runtime_GetBreakLocations) { 1045 HandleScope scope(isolate); 1046 DCHECK_EQ(2, args.length()); 1047 CHECK(isolate->debug()->is_active()); 1048 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 1049 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]); 1050 1051 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { 1052 return isolate->ThrowIllegalOperation(); 1053 } 1054 BreakPositionAlignment alignment = 1055 static_cast<BreakPositionAlignment>(statement_aligned_code); 1056 1057 Handle<SharedFunctionInfo> shared(fun->shared()); 1058 // Find the number of break points 1059 Handle<Object> break_locations = 1060 Debug::GetSourceBreakLocations(shared, alignment); 1061 if (break_locations->IsUndefined(isolate)) { 1062 return isolate->heap()->undefined_value(); 1063 } 1064 // Return array as JS array 1065 return *isolate->factory()->NewJSArrayWithElements( 1066 Handle<FixedArray>::cast(break_locations)); 1067 } 1068 1069 1070 // Set a break point in a function. 1071 // args[0]: function 1072 // args[1]: number: break source position (within the function source) 1073 // args[2]: number: break point object RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint)1074 RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) { 1075 HandleScope scope(isolate); 1076 DCHECK_EQ(3, args.length()); 1077 CHECK(isolate->debug()->is_active()); 1078 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 1079 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 1080 CHECK(source_position >= function->shared()->start_position() && 1081 source_position <= function->shared()->end_position()); 1082 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2); 1083 1084 // Set break point. 1085 CHECK(isolate->debug()->SetBreakPoint(function, break_point_object_arg, 1086 &source_position)); 1087 1088 return Smi::FromInt(source_position); 1089 } 1090 1091 1092 // Changes the state of a break point in a script and returns source position 1093 // where break point was set. NOTE: Regarding performance see the NOTE for 1094 // GetScriptFromScriptData. 1095 // args[0]: script to set break point in 1096 // args[1]: number: break source position (within the script source) 1097 // args[2]: number, breakpoint position alignment 1098 // args[3]: number: break point object RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint)1099 RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) { 1100 HandleScope scope(isolate); 1101 DCHECK_EQ(4, args.length()); 1102 CHECK(isolate->debug()->is_active()); 1103 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0); 1104 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 1105 CHECK(source_position >= 0); 1106 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]); 1107 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3); 1108 1109 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { 1110 return isolate->ThrowIllegalOperation(); 1111 } 1112 BreakPositionAlignment alignment = 1113 static_cast<BreakPositionAlignment>(statement_aligned_code); 1114 1115 // Get the script from the script wrapper. 1116 CHECK(wrapper->value()->IsScript()); 1117 Handle<Script> script(Script::cast(wrapper->value())); 1118 1119 // Set break point. 1120 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg, 1121 &source_position, alignment)) { 1122 return isolate->heap()->undefined_value(); 1123 } 1124 1125 return Smi::FromInt(source_position); 1126 } 1127 1128 1129 // Clear a break point 1130 // args[0]: number: break point object RUNTIME_FUNCTION(Runtime_ClearBreakPoint)1131 RUNTIME_FUNCTION(Runtime_ClearBreakPoint) { 1132 HandleScope scope(isolate); 1133 DCHECK_EQ(1, args.length()); 1134 CHECK(isolate->debug()->is_active()); 1135 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0); 1136 1137 // Clear break point. 1138 isolate->debug()->ClearBreakPoint(break_point_object_arg); 1139 1140 return isolate->heap()->undefined_value(); 1141 } 1142 1143 1144 // Change the state of break on exceptions. 1145 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions. 1146 // args[1]: Boolean indicating on/off. RUNTIME_FUNCTION(Runtime_ChangeBreakOnException)1147 RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) { 1148 HandleScope scope(isolate); 1149 DCHECK_EQ(2, args.length()); 1150 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); 1151 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1); 1152 1153 // If the number doesn't match an enum value, the ChangeBreakOnException 1154 // function will default to affecting caught exceptions. 1155 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); 1156 // Update break point state. 1157 isolate->debug()->ChangeBreakOnException(type, enable); 1158 return isolate->heap()->undefined_value(); 1159 } 1160 1161 1162 // Returns the state of break on exceptions 1163 // args[0]: boolean indicating uncaught exceptions RUNTIME_FUNCTION(Runtime_IsBreakOnException)1164 RUNTIME_FUNCTION(Runtime_IsBreakOnException) { 1165 HandleScope scope(isolate); 1166 DCHECK_EQ(1, args.length()); 1167 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); 1168 1169 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); 1170 bool result = isolate->debug()->IsBreakOnException(type); 1171 return Smi::FromInt(result); 1172 } 1173 1174 1175 // Prepare for stepping 1176 // args[0]: break id for checking execution state 1177 // args[1]: step action from the enumeration StepAction 1178 // args[2]: number of times to perform the step, for step out it is the number 1179 // of frames to step down. RUNTIME_FUNCTION(Runtime_PrepareStep)1180 RUNTIME_FUNCTION(Runtime_PrepareStep) { 1181 HandleScope scope(isolate); 1182 DCHECK_EQ(2, args.length()); 1183 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 1184 CHECK(isolate->debug()->CheckExecutionState(break_id)); 1185 1186 if (!args[1]->IsNumber()) { 1187 return isolate->Throw(isolate->heap()->illegal_argument_string()); 1188 } 1189 1190 // Get the step action and check validity. 1191 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); 1192 if (step_action != StepIn && step_action != StepNext && 1193 step_action != StepOut) { 1194 return isolate->Throw(isolate->heap()->illegal_argument_string()); 1195 } 1196 1197 // Clear all current stepping setup. 1198 isolate->debug()->ClearStepping(); 1199 1200 // Prepare step. 1201 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action)); 1202 return isolate->heap()->undefined_value(); 1203 } 1204 1205 // Clear all stepping set by PrepareStep. RUNTIME_FUNCTION(Runtime_ClearStepping)1206 RUNTIME_FUNCTION(Runtime_ClearStepping) { 1207 HandleScope scope(isolate); 1208 DCHECK_EQ(0, args.length()); 1209 CHECK(isolate->debug()->is_active()); 1210 isolate->debug()->ClearStepping(); 1211 return isolate->heap()->undefined_value(); 1212 } 1213 1214 RUNTIME_FUNCTION(Runtime_DebugEvaluate)1215 RUNTIME_FUNCTION(Runtime_DebugEvaluate) { 1216 HandleScope scope(isolate); 1217 1218 // Check the execution state and decode arguments frame and source to be 1219 // evaluated. 1220 DCHECK_EQ(5, args.length()); 1221 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 1222 CHECK(isolate->debug()->CheckExecutionState(break_id)); 1223 1224 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 1225 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 1226 CONVERT_ARG_HANDLE_CHECKED(String, source, 3); 1227 CONVERT_BOOLEAN_ARG_CHECKED(throw_on_side_effect, 4); 1228 1229 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 1230 1231 RETURN_RESULT_OR_FAILURE( 1232 isolate, DebugEvaluate::Local(isolate, id, inlined_jsframe_index, source, 1233 throw_on_side_effect)); 1234 } 1235 1236 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal)1237 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { 1238 HandleScope scope(isolate); 1239 1240 // Check the execution state and decode arguments frame and source to be 1241 // evaluated. 1242 DCHECK_EQ(2, args.length()); 1243 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 1244 CHECK(isolate->debug()->CheckExecutionState(break_id)); 1245 1246 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 1247 1248 RETURN_RESULT_OR_FAILURE(isolate, DebugEvaluate::Global(isolate, source)); 1249 } 1250 1251 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts)1252 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) { 1253 HandleScope scope(isolate); 1254 DCHECK_EQ(0, args.length()); 1255 1256 Handle<FixedArray> instances; 1257 { 1258 DebugScope debug_scope(isolate->debug()); 1259 if (debug_scope.failed()) { 1260 DCHECK(isolate->has_pending_exception()); 1261 return isolate->heap()->exception(); 1262 } 1263 // Fill the script objects. 1264 instances = isolate->debug()->GetLoadedScripts(); 1265 } 1266 1267 // Convert the script objects to proper JS objects. 1268 for (int i = 0; i < instances->length(); i++) { 1269 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); 1270 // Get the script wrapper in a local handle before calling GetScriptWrapper, 1271 // because using 1272 // instances->set(i, *GetScriptWrapper(script)) 1273 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might 1274 // already have dereferenced the instances handle. 1275 Handle<JSObject> wrapper = Script::GetWrapper(script); 1276 instances->set(i, *wrapper); 1277 } 1278 1279 // Return result as a JS array. 1280 return *isolate->factory()->NewJSArrayWithElements(instances); 1281 } 1282 HasInPrototypeChainIgnoringProxies(Isolate * isolate,JSObject * object,Object * proto)1283 static bool HasInPrototypeChainIgnoringProxies(Isolate* isolate, 1284 JSObject* object, 1285 Object* proto) { 1286 PrototypeIterator iter(isolate, object, kStartAtReceiver); 1287 while (true) { 1288 iter.AdvanceIgnoringProxies(); 1289 if (iter.IsAtEnd()) return false; 1290 if (iter.GetCurrent() == proto) return true; 1291 } 1292 } 1293 1294 1295 // Scan the heap for objects with direct references to an object 1296 // args[0]: the object to find references to 1297 // args[1]: constructor function for instances to exclude (Mirror) 1298 // args[2]: the the maximum number of objects to return RUNTIME_FUNCTION(Runtime_DebugReferencedBy)1299 RUNTIME_FUNCTION(Runtime_DebugReferencedBy) { 1300 HandleScope scope(isolate); 1301 DCHECK_EQ(3, args.length()); 1302 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0); 1303 CONVERT_ARG_HANDLE_CHECKED(Object, filter, 1); 1304 CHECK(filter->IsUndefined(isolate) || filter->IsJSObject()); 1305 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); 1306 CHECK(max_references >= 0); 1307 1308 List<Handle<JSObject> > instances; 1309 Heap* heap = isolate->heap(); 1310 { 1311 HeapIterator iterator(heap, HeapIterator::kFilterUnreachable); 1312 // Get the constructor function for context extension and arguments array. 1313 Object* arguments_fun = isolate->sloppy_arguments_map()->GetConstructor(); 1314 HeapObject* heap_obj; 1315 while ((heap_obj = iterator.next())) { 1316 if (!heap_obj->IsJSObject()) continue; 1317 JSObject* obj = JSObject::cast(heap_obj); 1318 if (obj->IsJSContextExtensionObject()) continue; 1319 if (obj->map()->GetConstructor() == arguments_fun) continue; 1320 if (!obj->ReferencesObject(*target)) continue; 1321 // Check filter if supplied. This is normally used to avoid 1322 // references from mirror objects. 1323 if (!filter->IsUndefined(isolate) && 1324 HasInPrototypeChainIgnoringProxies(isolate, obj, *filter)) { 1325 continue; 1326 } 1327 if (obj->IsJSGlobalObject()) { 1328 obj = JSGlobalObject::cast(obj)->global_proxy(); 1329 } 1330 instances.Add(Handle<JSObject>(obj)); 1331 if (instances.length() == max_references) break; 1332 } 1333 // Iterate the rest of the heap to satisfy HeapIterator constraints. 1334 while (iterator.next()) { 1335 } 1336 } 1337 1338 Handle<FixedArray> result; 1339 if (instances.length() == 1 && instances.last().is_identical_to(target)) { 1340 // Check for circular reference only. This can happen when the object is 1341 // only referenced from mirrors and has a circular reference in which case 1342 // the object is not really alive and would have been garbage collected if 1343 // not referenced from the mirror. 1344 result = isolate->factory()->empty_fixed_array(); 1345 } else { 1346 result = isolate->factory()->NewFixedArray(instances.length()); 1347 for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]); 1348 } 1349 return *isolate->factory()->NewJSArrayWithElements(result); 1350 } 1351 1352 1353 // Scan the heap for objects constructed by a specific function. 1354 // args[0]: the constructor to find instances of 1355 // args[1]: the the maximum number of objects to return RUNTIME_FUNCTION(Runtime_DebugConstructedBy)1356 RUNTIME_FUNCTION(Runtime_DebugConstructedBy) { 1357 HandleScope scope(isolate); 1358 DCHECK_EQ(2, args.length()); 1359 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0); 1360 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); 1361 CHECK(max_references >= 0); 1362 1363 List<Handle<JSObject> > instances; 1364 Heap* heap = isolate->heap(); 1365 { 1366 HeapIterator iterator(heap, HeapIterator::kFilterUnreachable); 1367 HeapObject* heap_obj; 1368 while ((heap_obj = iterator.next())) { 1369 if (!heap_obj->IsJSObject()) continue; 1370 JSObject* obj = JSObject::cast(heap_obj); 1371 if (obj->map()->GetConstructor() != *constructor) continue; 1372 instances.Add(Handle<JSObject>(obj)); 1373 if (instances.length() == max_references) break; 1374 } 1375 // Iterate the rest of the heap to satisfy HeapIterator constraints. 1376 while (iterator.next()) { 1377 } 1378 } 1379 1380 Handle<FixedArray> result = 1381 isolate->factory()->NewFixedArray(instances.length()); 1382 for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]); 1383 return *isolate->factory()->NewJSArrayWithElements(result); 1384 } 1385 1386 1387 // Find the effective prototype object as returned by __proto__. 1388 // args[0]: the object to find the prototype for. RUNTIME_FUNCTION(Runtime_DebugGetPrototype)1389 RUNTIME_FUNCTION(Runtime_DebugGetPrototype) { 1390 HandleScope shs(isolate); 1391 DCHECK_EQ(1, args.length()); 1392 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 1393 // TODO(1543): Come up with a solution for clients to handle potential errors 1394 // thrown by an intermediate proxy. 1395 RETURN_RESULT_OR_FAILURE(isolate, JSReceiver::GetPrototype(isolate, obj)); 1396 } 1397 1398 1399 // Patches script source (should be called upon BeforeCompile event). 1400 // TODO(5530): Remove once uses in debug.js are gone. RUNTIME_FUNCTION(Runtime_DebugSetScriptSource)1401 RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) { 1402 HandleScope scope(isolate); 1403 DCHECK_EQ(2, args.length()); 1404 1405 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0); 1406 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 1407 1408 CHECK(script_wrapper->value()->IsScript()); 1409 Handle<Script> script(Script::cast(script_wrapper->value())); 1410 1411 // The following condition is not guaranteed to hold and a failure is also 1412 // propagated to callers. Hence we fail gracefully here and don't crash. 1413 if (script->compilation_state() != Script::COMPILATION_STATE_INITIAL) { 1414 return isolate->ThrowIllegalOperation(); 1415 } 1416 1417 script->set_source(*source); 1418 1419 return isolate->heap()->undefined_value(); 1420 } 1421 1422 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName)1423 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) { 1424 SealHandleScope shs(isolate); 1425 DCHECK_EQ(1, args.length()); 1426 1427 CONVERT_ARG_CHECKED(Object, f, 0); 1428 if (f->IsJSFunction()) { 1429 return JSFunction::cast(f)->shared()->inferred_name(); 1430 } 1431 return isolate->heap()->empty_string(); 1432 } 1433 1434 RUNTIME_FUNCTION(Runtime_FunctionGetDebugName)1435 RUNTIME_FUNCTION(Runtime_FunctionGetDebugName) { 1436 HandleScope scope(isolate); 1437 DCHECK_EQ(1, args.length()); 1438 1439 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0); 1440 1441 if (function->IsJSBoundFunction()) { 1442 RETURN_RESULT_OR_FAILURE( 1443 isolate, JSBoundFunction::GetName( 1444 isolate, Handle<JSBoundFunction>::cast(function))); 1445 } else { 1446 return *JSFunction::GetDebugName(Handle<JSFunction>::cast(function)); 1447 } 1448 } 1449 1450 RUNTIME_FUNCTION(Runtime_GetDebugContext)1451 RUNTIME_FUNCTION(Runtime_GetDebugContext) { 1452 HandleScope scope(isolate); 1453 DCHECK_EQ(0, args.length()); 1454 Handle<Context> context; 1455 { 1456 DebugScope debug_scope(isolate->debug()); 1457 if (debug_scope.failed()) { 1458 DCHECK(isolate->has_pending_exception()); 1459 return isolate->heap()->exception(); 1460 } 1461 context = isolate->debug()->GetDebugContext(); 1462 } 1463 if (context.is_null()) return isolate->heap()->undefined_value(); 1464 context->set_security_token(isolate->native_context()->security_token()); 1465 return context->global_proxy(); 1466 } 1467 1468 1469 // Performs a GC. 1470 // Presently, it only does a full GC. RUNTIME_FUNCTION(Runtime_CollectGarbage)1471 RUNTIME_FUNCTION(Runtime_CollectGarbage) { 1472 SealHandleScope shs(isolate); 1473 DCHECK_EQ(1, args.length()); 1474 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 1475 GarbageCollectionReason::kRuntime); 1476 return isolate->heap()->undefined_value(); 1477 } 1478 1479 1480 // Gets the current heap usage. RUNTIME_FUNCTION(Runtime_GetHeapUsage)1481 RUNTIME_FUNCTION(Runtime_GetHeapUsage) { 1482 SealHandleScope shs(isolate); 1483 DCHECK_EQ(0, args.length()); 1484 int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); 1485 if (!Smi::IsValid(usage)) { 1486 return *isolate->factory()->NewNumberFromInt(usage); 1487 } 1488 return Smi::FromInt(usage); 1489 } 1490 1491 1492 // Finds the script object from the script data. NOTE: This operation uses 1493 // heap traversal to find the function generated for the source position 1494 // for the requested break point. For lazily compiled functions several heap 1495 // traversals might be required rendering this operation as a rather slow 1496 // operation. However for setting break points which is normally done through 1497 // some kind of user interaction the performance is not crucial. RUNTIME_FUNCTION(Runtime_GetScript)1498 RUNTIME_FUNCTION(Runtime_GetScript) { 1499 HandleScope scope(isolate); 1500 DCHECK_EQ(1, args.length()); 1501 CONVERT_ARG_HANDLE_CHECKED(String, script_name, 0); 1502 1503 Handle<Script> found; 1504 { 1505 Script::Iterator iterator(isolate); 1506 Script* script = NULL; 1507 while ((script = iterator.Next()) != NULL) { 1508 if (!script->name()->IsString()) continue; 1509 String* name = String::cast(script->name()); 1510 if (name->Equals(*script_name)) { 1511 found = Handle<Script>(script, isolate); 1512 break; 1513 } 1514 } 1515 } 1516 1517 if (found.is_null()) return isolate->heap()->undefined_value(); 1518 return *Script::GetWrapper(found); 1519 } 1520 1521 // TODO(5530): Remove once uses in debug.js are gone. RUNTIME_FUNCTION(Runtime_ScriptLineCount)1522 RUNTIME_FUNCTION(Runtime_ScriptLineCount) { 1523 HandleScope scope(isolate); 1524 DCHECK_EQ(1, args.length()); 1525 CONVERT_ARG_CHECKED(JSValue, script, 0); 1526 1527 CHECK(script->value()->IsScript()); 1528 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 1529 1530 if (script_handle->type() == Script::TYPE_WASM) { 1531 // Return 0 for now; this function will disappear soon anyway. 1532 return Smi::FromInt(0); 1533 } 1534 1535 Script::InitLineEnds(script_handle); 1536 1537 FixedArray* line_ends_array = FixedArray::cast(script_handle->line_ends()); 1538 return Smi::FromInt(line_ends_array->length()); 1539 } 1540 1541 namespace { 1542 ScriptLinePosition(Handle<Script> script,int line)1543 int ScriptLinePosition(Handle<Script> script, int line) { 1544 if (line < 0) return -1; 1545 1546 if (script->type() == Script::TYPE_WASM) { 1547 return WasmCompiledModule::cast(script->wasm_compiled_module()) 1548 ->GetFunctionOffset(line); 1549 } 1550 1551 Script::InitLineEnds(script); 1552 1553 FixedArray* line_ends_array = FixedArray::cast(script->line_ends()); 1554 const int line_count = line_ends_array->length(); 1555 DCHECK_LT(0, line_count); 1556 1557 if (line == 0) return 0; 1558 // If line == line_count, we return the first position beyond the last line. 1559 if (line > line_count) return -1; 1560 return Smi::cast(line_ends_array->get(line - 1))->value() + 1; 1561 } 1562 1563 } // namespace 1564 1565 // TODO(5530): Remove once uses in debug.js are gone. RUNTIME_FUNCTION(Runtime_ScriptLineStartPosition)1566 RUNTIME_FUNCTION(Runtime_ScriptLineStartPosition) { 1567 HandleScope scope(isolate); 1568 DCHECK_EQ(2, args.length()); 1569 CONVERT_ARG_CHECKED(JSValue, script, 0); 1570 CONVERT_NUMBER_CHECKED(int32_t, line, Int32, args[1]); 1571 1572 CHECK(script->value()->IsScript()); 1573 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 1574 1575 return Smi::FromInt(ScriptLinePosition(script_handle, line)); 1576 } 1577 1578 // TODO(5530): Remove once uses in debug.js are gone. RUNTIME_FUNCTION(Runtime_ScriptLineEndPosition)1579 RUNTIME_FUNCTION(Runtime_ScriptLineEndPosition) { 1580 HandleScope scope(isolate); 1581 DCHECK_EQ(2, args.length()); 1582 CONVERT_ARG_CHECKED(JSValue, script, 0); 1583 CONVERT_NUMBER_CHECKED(int32_t, line, Int32, args[1]); 1584 1585 CHECK(script->value()->IsScript()); 1586 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 1587 1588 if (script_handle->type() == Script::TYPE_WASM) { 1589 // Return zero for now; this function will disappear soon anyway. 1590 return Smi::FromInt(0); 1591 } 1592 1593 Script::InitLineEnds(script_handle); 1594 1595 FixedArray* line_ends_array = FixedArray::cast(script_handle->line_ends()); 1596 const int line_count = line_ends_array->length(); 1597 1598 if (line < 0 || line >= line_count) { 1599 return Smi::FromInt(-1); 1600 } else { 1601 return Smi::cast(line_ends_array->get(line)); 1602 } 1603 } 1604 GetJSPositionInfo(Handle<Script> script,int position,Script::OffsetFlag offset_flag,Isolate * isolate)1605 static Handle<Object> GetJSPositionInfo(Handle<Script> script, int position, 1606 Script::OffsetFlag offset_flag, 1607 Isolate* isolate) { 1608 Script::PositionInfo info; 1609 if (!Script::GetPositionInfo(script, position, &info, offset_flag)) { 1610 return isolate->factory()->null_value(); 1611 } 1612 1613 Handle<String> source = handle(String::cast(script->source()), isolate); 1614 Handle<String> sourceText = script->type() == Script::TYPE_WASM 1615 ? isolate->factory()->empty_string() 1616 : isolate->factory()->NewSubString( 1617 source, info.line_start, info.line_end); 1618 1619 Handle<JSObject> jsinfo = 1620 isolate->factory()->NewJSObject(isolate->object_function()); 1621 1622 JSObject::AddProperty(jsinfo, isolate->factory()->script_string(), script, 1623 NONE); 1624 JSObject::AddProperty(jsinfo, isolate->factory()->position_string(), 1625 handle(Smi::FromInt(position), isolate), NONE); 1626 JSObject::AddProperty(jsinfo, isolate->factory()->line_string(), 1627 handle(Smi::FromInt(info.line), isolate), NONE); 1628 JSObject::AddProperty(jsinfo, isolate->factory()->column_string(), 1629 handle(Smi::FromInt(info.column), isolate), NONE); 1630 JSObject::AddProperty(jsinfo, isolate->factory()->sourceText_string(), 1631 sourceText, NONE); 1632 1633 return jsinfo; 1634 } 1635 1636 namespace { 1637 ScriptLinePositionWithOffset(Handle<Script> script,int line,int offset)1638 int ScriptLinePositionWithOffset(Handle<Script> script, int line, int offset) { 1639 if (line < 0 || offset < 0) return -1; 1640 1641 if (line == 0 || offset == 0) 1642 return ScriptLinePosition(script, line) + offset; 1643 1644 Script::PositionInfo info; 1645 if (!Script::GetPositionInfo(script, offset, &info, Script::NO_OFFSET)) { 1646 return -1; 1647 } 1648 1649 const int total_line = info.line + line; 1650 return ScriptLinePosition(script, total_line); 1651 } 1652 ScriptLocationFromLine(Isolate * isolate,Handle<Script> script,Handle<Object> opt_line,Handle<Object> opt_column,int32_t offset)1653 Handle<Object> ScriptLocationFromLine(Isolate* isolate, Handle<Script> script, 1654 Handle<Object> opt_line, 1655 Handle<Object> opt_column, 1656 int32_t offset) { 1657 // Line and column are possibly undefined and we need to handle these cases, 1658 // additionally subtracting corresponding offsets. 1659 1660 int32_t line = 0; 1661 if (!opt_line->IsNullOrUndefined(isolate)) { 1662 CHECK(opt_line->IsNumber()); 1663 line = NumberToInt32(*opt_line) - script->line_offset(); 1664 } 1665 1666 int32_t column = 0; 1667 if (!opt_column->IsNullOrUndefined(isolate)) { 1668 CHECK(opt_column->IsNumber()); 1669 column = NumberToInt32(*opt_column); 1670 if (line == 0) column -= script->column_offset(); 1671 } 1672 1673 int line_position = ScriptLinePositionWithOffset(script, line, offset); 1674 if (line_position < 0 || column < 0) return isolate->factory()->null_value(); 1675 1676 return GetJSPositionInfo(script, line_position + column, Script::NO_OFFSET, 1677 isolate); 1678 } 1679 1680 // Slow traversal over all scripts on the heap. GetScriptById(Isolate * isolate,int needle,Handle<Script> * result)1681 bool GetScriptById(Isolate* isolate, int needle, Handle<Script>* result) { 1682 Script::Iterator iterator(isolate); 1683 Script* script = NULL; 1684 while ((script = iterator.Next()) != NULL) { 1685 if (script->id() == needle) { 1686 *result = handle(script); 1687 return true; 1688 } 1689 } 1690 1691 return false; 1692 } 1693 1694 } // namespace 1695 1696 // Get information on a specific source line and column possibly offset by a 1697 // fixed source position. This function is used to find a source position from 1698 // a line and column position. The fixed source position offset is typically 1699 // used to find a source position in a function based on a line and column in 1700 // the source for the function alone. The offset passed will then be the 1701 // start position of the source for the function within the full script source. 1702 // Note that incoming line and column parameters may be undefined, and are 1703 // assumed to be passed *with* offsets. 1704 // TODO(5530): Remove once uses in debug.js are gone. RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine)1705 RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine) { 1706 HandleScope scope(isolate); 1707 DCHECK_EQ(4, args.length()); 1708 CONVERT_ARG_HANDLE_CHECKED(JSValue, script, 0); 1709 CONVERT_ARG_HANDLE_CHECKED(Object, opt_line, 1); 1710 CONVERT_ARG_HANDLE_CHECKED(Object, opt_column, 2); 1711 CONVERT_NUMBER_CHECKED(int32_t, offset, Int32, args[3]); 1712 1713 CHECK(script->value()->IsScript()); 1714 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 1715 1716 return *ScriptLocationFromLine(isolate, script_handle, opt_line, opt_column, 1717 offset); 1718 } 1719 1720 // TODO(5530): Rename once conflicting function has been deleted. RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2)1721 RUNTIME_FUNCTION(Runtime_ScriptLocationFromLine2) { 1722 HandleScope scope(isolate); 1723 DCHECK_EQ(4, args.length()); 1724 CONVERT_NUMBER_CHECKED(int32_t, scriptid, Int32, args[0]); 1725 CONVERT_ARG_HANDLE_CHECKED(Object, opt_line, 1); 1726 CONVERT_ARG_HANDLE_CHECKED(Object, opt_column, 2); 1727 CONVERT_NUMBER_CHECKED(int32_t, offset, Int32, args[3]); 1728 1729 Handle<Script> script; 1730 CHECK(GetScriptById(isolate, scriptid, &script)); 1731 1732 return *ScriptLocationFromLine(isolate, script, opt_line, opt_column, offset); 1733 } 1734 1735 // TODO(5530): Remove once uses in debug.js are gone. RUNTIME_FUNCTION(Runtime_ScriptPositionInfo)1736 RUNTIME_FUNCTION(Runtime_ScriptPositionInfo) { 1737 HandleScope scope(isolate); 1738 DCHECK_EQ(3, args.length()); 1739 CONVERT_ARG_CHECKED(JSValue, script, 0); 1740 CONVERT_NUMBER_CHECKED(int32_t, position, Int32, args[1]); 1741 CONVERT_BOOLEAN_ARG_CHECKED(with_offset, 2); 1742 1743 CHECK(script->value()->IsScript()); 1744 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 1745 1746 const Script::OffsetFlag offset_flag = 1747 with_offset ? Script::WITH_OFFSET : Script::NO_OFFSET; 1748 return *GetJSPositionInfo(script_handle, position, offset_flag, isolate); 1749 } 1750 1751 // TODO(5530): Rename once conflicting function has been deleted. RUNTIME_FUNCTION(Runtime_ScriptPositionInfo2)1752 RUNTIME_FUNCTION(Runtime_ScriptPositionInfo2) { 1753 HandleScope scope(isolate); 1754 DCHECK_EQ(3, args.length()); 1755 CONVERT_NUMBER_CHECKED(int32_t, scriptid, Int32, args[0]); 1756 CONVERT_NUMBER_CHECKED(int32_t, position, Int32, args[1]); 1757 CONVERT_BOOLEAN_ARG_CHECKED(with_offset, 2); 1758 1759 Handle<Script> script; 1760 CHECK(GetScriptById(isolate, scriptid, &script)); 1761 1762 const Script::OffsetFlag offset_flag = 1763 with_offset ? Script::WITH_OFFSET : Script::NO_OFFSET; 1764 return *GetJSPositionInfo(script, position, offset_flag, isolate); 1765 } 1766 1767 // Returns the given line as a string, or null if line is out of bounds. 1768 // The parameter line is expected to include the script's line offset. 1769 // TODO(5530): Remove once uses in debug.js are gone. RUNTIME_FUNCTION(Runtime_ScriptSourceLine)1770 RUNTIME_FUNCTION(Runtime_ScriptSourceLine) { 1771 HandleScope scope(isolate); 1772 DCHECK_EQ(2, args.length()); 1773 CONVERT_ARG_CHECKED(JSValue, script, 0); 1774 CONVERT_NUMBER_CHECKED(int32_t, line, Int32, args[1]); 1775 1776 CHECK(script->value()->IsScript()); 1777 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 1778 1779 if (script_handle->type() == Script::TYPE_WASM) { 1780 // Return null for now; this function will disappear soon anyway. 1781 return isolate->heap()->null_value(); 1782 } 1783 1784 Script::InitLineEnds(script_handle); 1785 1786 FixedArray* line_ends_array = FixedArray::cast(script_handle->line_ends()); 1787 const int line_count = line_ends_array->length(); 1788 1789 line -= script_handle->line_offset(); 1790 if (line < 0 || line_count <= line) { 1791 return isolate->heap()->null_value(); 1792 } 1793 1794 const int start = 1795 (line == 0) ? 0 : Smi::cast(line_ends_array->get(line - 1))->value() + 1; 1796 const int end = Smi::cast(line_ends_array->get(line))->value(); 1797 1798 Handle<String> source = 1799 handle(String::cast(script_handle->source()), isolate); 1800 Handle<String> str = isolate->factory()->NewSubString(source, start, end); 1801 1802 return *str; 1803 } 1804 1805 // On function call, depending on circumstances, prepare for stepping in, 1806 // or perform a side effect check. RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall)1807 RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall) { 1808 HandleScope scope(isolate); 1809 DCHECK_EQ(1, args.length()); 1810 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 1811 if (isolate->debug()->last_step_action() >= StepIn) { 1812 isolate->debug()->PrepareStepIn(fun); 1813 } 1814 if (isolate->needs_side_effect_check() && 1815 !isolate->debug()->PerformSideEffectCheck(fun)) { 1816 return isolate->heap()->exception(); 1817 } 1818 return isolate->heap()->undefined_value(); 1819 } 1820 1821 // Set one shot breakpoints for the suspended generator object. RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator)1822 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInSuspendedGenerator) { 1823 HandleScope scope(isolate); 1824 DCHECK_EQ(0, args.length()); 1825 isolate->debug()->PrepareStepInSuspendedGenerator(); 1826 return isolate->heap()->undefined_value(); 1827 } 1828 RUNTIME_FUNCTION(Runtime_DebugRecordGenerator)1829 RUNTIME_FUNCTION(Runtime_DebugRecordGenerator) { 1830 HandleScope scope(isolate); 1831 DCHECK_EQ(1, args.length()); 1832 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); 1833 CHECK(isolate->debug()->last_step_action() >= StepNext); 1834 isolate->debug()->RecordGenerator(generator); 1835 return isolate->heap()->undefined_value(); 1836 } 1837 RUNTIME_FUNCTION(Runtime_DebugPushPromise)1838 RUNTIME_FUNCTION(Runtime_DebugPushPromise) { 1839 DCHECK_EQ(1, args.length()); 1840 HandleScope scope(isolate); 1841 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); 1842 isolate->PushPromise(promise); 1843 return isolate->heap()->undefined_value(); 1844 } 1845 1846 RUNTIME_FUNCTION(Runtime_DebugPopPromise)1847 RUNTIME_FUNCTION(Runtime_DebugPopPromise) { 1848 DCHECK_EQ(0, args.length()); 1849 SealHandleScope shs(isolate); 1850 isolate->PopPromise(); 1851 return isolate->heap()->undefined_value(); 1852 } 1853 RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionPromiseCreated)1854 RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionPromiseCreated) { 1855 DCHECK_EQ(1, args.length()); 1856 HandleScope scope(isolate); 1857 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); 1858 isolate->PushPromise(promise); 1859 int id = isolate->debug()->NextAsyncTaskId(promise); 1860 Handle<Symbol> async_stack_id_symbol = 1861 isolate->factory()->promise_async_stack_id_symbol(); 1862 JSObject::SetProperty(promise, async_stack_id_symbol, 1863 handle(Smi::FromInt(id), isolate), STRICT) 1864 .Assert(); 1865 isolate->debug()->OnAsyncTaskEvent(debug::kDebugEnqueueAsyncFunction, id, 0); 1866 return isolate->heap()->undefined_value(); 1867 } 1868 RUNTIME_FUNCTION(Runtime_DebugPromiseReject)1869 RUNTIME_FUNCTION(Runtime_DebugPromiseReject) { 1870 HandleScope scope(isolate); 1871 DCHECK_EQ(2, args.length()); 1872 CONVERT_ARG_HANDLE_CHECKED(JSPromise, rejected_promise, 0); 1873 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); 1874 1875 isolate->debug()->OnPromiseReject(rejected_promise, value); 1876 return isolate->heap()->undefined_value(); 1877 } 1878 RUNTIME_FUNCTION(Runtime_DebugAsyncEventEnqueueRecurring)1879 RUNTIME_FUNCTION(Runtime_DebugAsyncEventEnqueueRecurring) { 1880 HandleScope scope(isolate); 1881 DCHECK_EQ(2, args.length()); 1882 CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0); 1883 CONVERT_SMI_ARG_CHECKED(status, 1); 1884 if (isolate->debug()->is_active()) { 1885 isolate->debug()->OnAsyncTaskEvent( 1886 status == v8::Promise::kFulfilled ? debug::kDebugEnqueuePromiseResolve 1887 : debug::kDebugEnqueuePromiseReject, 1888 isolate->debug()->NextAsyncTaskId(promise), 0); 1889 } 1890 return isolate->heap()->undefined_value(); 1891 } 1892 RUNTIME_FUNCTION(Runtime_DebugIsActive)1893 RUNTIME_FUNCTION(Runtime_DebugIsActive) { 1894 SealHandleScope shs(isolate); 1895 return Smi::FromInt(isolate->debug()->is_active()); 1896 } 1897 RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode)1898 RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode) { 1899 UNIMPLEMENTED(); 1900 return NULL; 1901 } 1902 RUNTIME_FUNCTION(Runtime_DebugCollectCoverage)1903 RUNTIME_FUNCTION(Runtime_DebugCollectCoverage) { 1904 HandleScope scope(isolate); 1905 DCHECK_EQ(0, args.length()); 1906 // Collect coverage data. 1907 std::unique_ptr<Coverage> coverage(Coverage::Collect(isolate, false)); 1908 Factory* factory = isolate->factory(); 1909 // Turn the returned data structure into JavaScript. 1910 // Create an array of scripts. 1911 int num_scripts = static_cast<int>(coverage->size()); 1912 // Prepare property keys. 1913 Handle<FixedArray> scripts_array = factory->NewFixedArray(num_scripts); 1914 Handle<String> script_string = factory->NewStringFromStaticChars("script"); 1915 Handle<String> start_string = factory->NewStringFromStaticChars("start"); 1916 Handle<String> end_string = factory->NewStringFromStaticChars("end"); 1917 Handle<String> count_string = factory->NewStringFromStaticChars("count"); 1918 for (int i = 0; i < num_scripts; i++) { 1919 const auto& script_data = coverage->at(i); 1920 HandleScope inner_scope(isolate); 1921 int num_functions = static_cast<int>(script_data.functions.size()); 1922 Handle<FixedArray> functions_array = factory->NewFixedArray(num_functions); 1923 for (int j = 0; j < num_functions; j++) { 1924 const auto& function_data = script_data.functions[j]; 1925 Handle<JSObject> range_obj = factory->NewJSObjectWithNullProto(); 1926 JSObject::AddProperty(range_obj, start_string, 1927 factory->NewNumberFromInt(function_data.start), 1928 NONE); 1929 JSObject::AddProperty(range_obj, end_string, 1930 factory->NewNumberFromInt(function_data.end), NONE); 1931 JSObject::AddProperty(range_obj, count_string, 1932 factory->NewNumberFromUint(function_data.count), 1933 NONE); 1934 functions_array->set(j, *range_obj); 1935 } 1936 Handle<JSArray> script_obj = 1937 factory->NewJSArrayWithElements(functions_array, FAST_ELEMENTS); 1938 Handle<JSObject> wrapper = Script::GetWrapper(script_data.script); 1939 JSObject::AddProperty(script_obj, script_string, wrapper, NONE); 1940 scripts_array->set(i, *script_obj); 1941 } 1942 return *factory->NewJSArrayWithElements(scripts_array, FAST_ELEMENTS); 1943 } 1944 RUNTIME_FUNCTION(Runtime_DebugTogglePreciseCoverage)1945 RUNTIME_FUNCTION(Runtime_DebugTogglePreciseCoverage) { 1946 SealHandleScope shs(isolate); 1947 CONVERT_BOOLEAN_ARG_CHECKED(enable, 0); 1948 Coverage::TogglePrecise(isolate, enable); 1949 return isolate->heap()->undefined_value(); 1950 } 1951 1952 } // namespace internal 1953 } // namespace v8 1954