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/debug/debug.h" 9 #include "src/debug/debug-evaluate.h" 10 #include "src/debug/debug-frames.h" 11 #include "src/debug/debug-scopes.h" 12 #include "src/frames-inl.h" 13 #include "src/isolate-inl.h" 14 #include "src/runtime/runtime.h" 15 16 namespace v8 { 17 namespace internal { 18 19 RUNTIME_FUNCTION(Runtime_DebugBreak) { 20 SealHandleScope shs(isolate); 21 DCHECK(args.length() == 0); 22 // Get the top-most JavaScript frame. 23 JavaScriptFrameIterator it(isolate); 24 isolate->debug()->Break(args, it.frame()); 25 isolate->debug()->SetAfterBreakTarget(it.frame()); 26 return isolate->heap()->undefined_value(); 27 } 28 29 30 RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) { 31 SealHandleScope shs(isolate); 32 DCHECK(args.length() == 0); 33 if (isolate->debug()->break_points_active()) { 34 isolate->debug()->HandleDebugBreak(); 35 } 36 return isolate->heap()->undefined_value(); 37 } 38 39 40 // Adds a JavaScript function as a debug event listener. 41 // args[0]: debug event listener function to set or null or undefined for 42 // clearing the event listener function 43 // args[1]: object supplied during callback 44 RUNTIME_FUNCTION(Runtime_SetDebugEventListener) { 45 SealHandleScope shs(isolate); 46 DCHECK(args.length() == 2); 47 RUNTIME_ASSERT(args[0]->IsJSFunction() || args[0]->IsUndefined() || 48 args[0]->IsNull()); 49 CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0); 50 CONVERT_ARG_HANDLE_CHECKED(Object, data, 1); 51 isolate->debug()->SetEventListener(callback, data); 52 53 return isolate->heap()->undefined_value(); 54 } 55 56 57 RUNTIME_FUNCTION(Runtime_ScheduleBreak) { 58 SealHandleScope shs(isolate); 59 DCHECK(args.length() == 0); 60 isolate->stack_guard()->RequestDebugBreak(); 61 return isolate->heap()->undefined_value(); 62 } 63 64 65 static Handle<Object> DebugGetProperty(LookupIterator* it, 66 bool* has_caught = NULL) { 67 for (; it->IsFound(); it->Next()) { 68 switch (it->state()) { 69 case LookupIterator::NOT_FOUND: 70 case LookupIterator::TRANSITION: 71 UNREACHABLE(); 72 case LookupIterator::ACCESS_CHECK: 73 // Ignore access checks. 74 break; 75 case LookupIterator::INTEGER_INDEXED_EXOTIC: 76 case LookupIterator::INTERCEPTOR: 77 case LookupIterator::JSPROXY: 78 return it->isolate()->factory()->undefined_value(); 79 case LookupIterator::ACCESSOR: { 80 Handle<Object> accessors = it->GetAccessors(); 81 if (!accessors->IsAccessorInfo()) { 82 return it->isolate()->factory()->undefined_value(); 83 } 84 MaybeHandle<Object> maybe_result = 85 JSObject::GetPropertyWithAccessor(it, SLOPPY); 86 Handle<Object> result; 87 if (!maybe_result.ToHandle(&result)) { 88 result = handle(it->isolate()->pending_exception(), it->isolate()); 89 it->isolate()->clear_pending_exception(); 90 if (has_caught != NULL) *has_caught = true; 91 } 92 return result; 93 } 94 95 case LookupIterator::DATA: 96 return it->GetDataValue(); 97 } 98 } 99 100 return it->isolate()->factory()->undefined_value(); 101 } 102 103 104 static Handle<Object> DebugGetProperty(Handle<Object> object, 105 Handle<Name> name) { 106 LookupIterator it(object, name); 107 return DebugGetProperty(&it); 108 } 109 110 111 template <class IteratorType> 112 static MaybeHandle<JSArray> GetIteratorInternalProperties( 113 Isolate* isolate, Handle<IteratorType> object) { 114 Factory* factory = isolate->factory(); 115 Handle<IteratorType> iterator = Handle<IteratorType>::cast(object); 116 RUNTIME_ASSERT_HANDLIFIED(iterator->kind()->IsSmi(), JSArray); 117 const char* kind = NULL; 118 switch (Smi::cast(iterator->kind())->value()) { 119 case IteratorType::kKindKeys: 120 kind = "keys"; 121 break; 122 case IteratorType::kKindValues: 123 kind = "values"; 124 break; 125 case IteratorType::kKindEntries: 126 kind = "entries"; 127 break; 128 default: 129 RUNTIME_ASSERT_HANDLIFIED(false, JSArray); 130 } 131 132 Handle<FixedArray> result = factory->NewFixedArray(2 * 3); 133 Handle<String> has_more = 134 factory->NewStringFromAsciiChecked("[[IteratorHasMore]]"); 135 result->set(0, *has_more); 136 result->set(1, isolate->heap()->ToBoolean(iterator->HasMore())); 137 138 Handle<String> index = 139 factory->NewStringFromAsciiChecked("[[IteratorIndex]]"); 140 result->set(2, *index); 141 result->set(3, iterator->index()); 142 143 Handle<String> iterator_kind = 144 factory->NewStringFromAsciiChecked("[[IteratorKind]]"); 145 result->set(4, *iterator_kind); 146 Handle<String> kind_str = factory->NewStringFromAsciiChecked(kind); 147 result->set(5, *kind_str); 148 return factory->NewJSArrayWithElements(result); 149 } 150 151 152 MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate, 153 Handle<Object> object) { 154 Factory* factory = isolate->factory(); 155 if (object->IsJSBoundFunction()) { 156 Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(object); 157 158 Handle<FixedArray> result = factory->NewFixedArray(2 * 3); 159 Handle<String> target = 160 factory->NewStringFromAsciiChecked("[[TargetFunction]]"); 161 result->set(0, *target); 162 result->set(1, function->bound_target_function()); 163 164 Handle<String> bound_this = 165 factory->NewStringFromAsciiChecked("[[BoundThis]]"); 166 result->set(2, *bound_this); 167 result->set(3, function->bound_this()); 168 169 Handle<String> bound_args = 170 factory->NewStringFromAsciiChecked("[[BoundArgs]]"); 171 result->set(4, *bound_args); 172 Handle<FixedArray> bound_arguments = 173 factory->CopyFixedArray(handle(function->bound_arguments(), isolate)); 174 Handle<JSArray> arguments_array = 175 factory->NewJSArrayWithElements(bound_arguments); 176 result->set(5, *arguments_array); 177 return factory->NewJSArrayWithElements(result); 178 } else if (object->IsJSMapIterator()) { 179 Handle<JSMapIterator> iterator = Handle<JSMapIterator>::cast(object); 180 return GetIteratorInternalProperties(isolate, iterator); 181 } else if (object->IsJSSetIterator()) { 182 Handle<JSSetIterator> iterator = Handle<JSSetIterator>::cast(object); 183 return GetIteratorInternalProperties(isolate, iterator); 184 } else if (object->IsJSGeneratorObject()) { 185 Handle<JSGeneratorObject> generator = 186 Handle<JSGeneratorObject>::cast(object); 187 188 const char* status = "suspended"; 189 if (generator->is_closed()) { 190 status = "closed"; 191 } else if (generator->is_executing()) { 192 status = "running"; 193 } else { 194 DCHECK(generator->is_suspended()); 195 } 196 197 Handle<FixedArray> result = factory->NewFixedArray(2 * 3); 198 Handle<String> generator_status = 199 factory->NewStringFromAsciiChecked("[[GeneratorStatus]]"); 200 result->set(0, *generator_status); 201 Handle<String> status_str = factory->NewStringFromAsciiChecked(status); 202 result->set(1, *status_str); 203 204 Handle<String> function = 205 factory->NewStringFromAsciiChecked("[[GeneratorFunction]]"); 206 result->set(2, *function); 207 result->set(3, generator->function()); 208 209 Handle<String> receiver = 210 factory->NewStringFromAsciiChecked("[[GeneratorReceiver]]"); 211 result->set(4, *receiver); 212 result->set(5, generator->receiver()); 213 return factory->NewJSArrayWithElements(result); 214 } else if (Object::IsPromise(object)) { 215 Handle<JSObject> promise = Handle<JSObject>::cast(object); 216 217 Handle<Object> status_obj = 218 DebugGetProperty(promise, isolate->factory()->promise_status_symbol()); 219 RUNTIME_ASSERT_HANDLIFIED(status_obj->IsSmi(), JSArray); 220 const char* status = "rejected"; 221 int status_val = Handle<Smi>::cast(status_obj)->value(); 222 switch (status_val) { 223 case +1: 224 status = "resolved"; 225 break; 226 case 0: 227 status = "pending"; 228 break; 229 default: 230 DCHECK_EQ(-1, status_val); 231 } 232 233 Handle<FixedArray> result = factory->NewFixedArray(2 * 2); 234 Handle<String> promise_status = 235 factory->NewStringFromAsciiChecked("[[PromiseStatus]]"); 236 result->set(0, *promise_status); 237 Handle<String> status_str = factory->NewStringFromAsciiChecked(status); 238 result->set(1, *status_str); 239 240 Handle<Object> value_obj = 241 DebugGetProperty(promise, isolate->factory()->promise_value_symbol()); 242 Handle<String> promise_value = 243 factory->NewStringFromAsciiChecked("[[PromiseValue]]"); 244 result->set(2, *promise_value); 245 result->set(3, *value_obj); 246 return factory->NewJSArrayWithElements(result); 247 } else if (object->IsJSValue()) { 248 Handle<JSValue> js_value = Handle<JSValue>::cast(object); 249 250 Handle<FixedArray> result = factory->NewFixedArray(2); 251 Handle<String> primitive_value = 252 factory->NewStringFromAsciiChecked("[[PrimitiveValue]]"); 253 result->set(0, *primitive_value); 254 result->set(1, js_value->value()); 255 return factory->NewJSArrayWithElements(result); 256 } 257 return factory->NewJSArray(0); 258 } 259 260 261 RUNTIME_FUNCTION(Runtime_DebugGetInternalProperties) { 262 HandleScope scope(isolate); 263 DCHECK(args.length() == 1); 264 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); 265 Handle<JSArray> result; 266 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 267 isolate, result, Runtime::GetInternalProperties(isolate, obj)); 268 return *result; 269 } 270 271 272 // Get debugger related details for an object property, in the following format: 273 // 0: Property value 274 // 1: Property details 275 // 2: Property value is exception 276 // 3: Getter function if defined 277 // 4: Setter function if defined 278 // Items 2-4 are only filled if the property has either a getter or a setter. 279 RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) { 280 HandleScope scope(isolate); 281 282 DCHECK(args.length() == 2); 283 284 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 285 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 286 287 // Make sure to set the current context to the context before the debugger was 288 // entered (if the debugger is entered). The reason for switching context here 289 // is that for some property lookups (accessors and interceptors) callbacks 290 // into the embedding application can occour, and the embedding application 291 // could have the assumption that its own native context is the current 292 // context and not some internal debugger context. 293 SaveContext save(isolate); 294 if (isolate->debug()->in_debug_scope()) { 295 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); 296 } 297 298 // Check if the name is trivially convertible to an index and get the element 299 // if so. 300 uint32_t index; 301 // TODO(verwaest): Make sure DebugGetProperty can handle arrays, and remove 302 // this special case. 303 if (name->AsArrayIndex(&index)) { 304 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); 305 Handle<Object> element_or_char; 306 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_or_char, 307 Object::GetElement(isolate, obj, index)); 308 details->set(0, *element_or_char); 309 details->set(1, PropertyDetails::Empty().AsSmi()); 310 return *isolate->factory()->NewJSArrayWithElements(details); 311 } 312 313 LookupIterator it(obj, name, LookupIterator::HIDDEN); 314 bool has_caught = false; 315 Handle<Object> value = DebugGetProperty(&it, &has_caught); 316 if (!it.IsFound()) return isolate->heap()->undefined_value(); 317 318 Handle<Object> maybe_pair; 319 if (it.state() == LookupIterator::ACCESSOR) { 320 maybe_pair = it.GetAccessors(); 321 } 322 323 // If the callback object is a fixed array then it contains JavaScript 324 // getter and/or setter. 325 bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair(); 326 Handle<FixedArray> details = 327 isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3); 328 details->set(0, *value); 329 // TODO(verwaest): Get rid of this random way of handling interceptors. 330 PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR 331 ? PropertyDetails::Empty() 332 : it.property_details(); 333 details->set(1, d.AsSmi()); 334 details->set( 335 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR)); 336 if (has_js_accessors) { 337 AccessorPair* accessors = AccessorPair::cast(*maybe_pair); 338 details->set(3, isolate->heap()->ToBoolean(has_caught)); 339 details->set(4, accessors->GetComponent(ACCESSOR_GETTER)); 340 details->set(5, accessors->GetComponent(ACCESSOR_SETTER)); 341 } 342 343 return *isolate->factory()->NewJSArrayWithElements(details); 344 } 345 346 347 RUNTIME_FUNCTION(Runtime_DebugGetProperty) { 348 HandleScope scope(isolate); 349 350 DCHECK(args.length() == 2); 351 352 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 353 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 354 355 LookupIterator it(obj, name); 356 return *DebugGetProperty(&it); 357 } 358 359 360 // Return the property type calculated from the property details. 361 // args[0]: smi with property details. 362 RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) { 363 SealHandleScope shs(isolate); 364 DCHECK(args.length() == 1); 365 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 366 return Smi::FromInt(static_cast<int>(details.type())); 367 } 368 369 370 // Return the property attribute calculated from the property details. 371 // args[0]: smi with property details. 372 RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) { 373 SealHandleScope shs(isolate); 374 DCHECK(args.length() == 1); 375 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 376 return Smi::FromInt(static_cast<int>(details.attributes())); 377 } 378 379 380 // Return the property insertion index calculated from the property details. 381 // args[0]: smi with property details. 382 RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) { 383 SealHandleScope shs(isolate); 384 DCHECK(args.length() == 1); 385 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 386 // TODO(verwaest): Works only for dictionary mode holders. 387 return Smi::FromInt(details.dictionary_index()); 388 } 389 390 391 // Return property value from named interceptor. 392 // args[0]: object 393 // args[1]: property name 394 RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) { 395 HandleScope scope(isolate); 396 DCHECK(args.length() == 2); 397 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 398 RUNTIME_ASSERT(obj->HasNamedInterceptor()); 399 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 400 401 Handle<Object> result; 402 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 403 JSObject::GetProperty(obj, name)); 404 return *result; 405 } 406 407 408 // Return element value from indexed interceptor. 409 // args[0]: object 410 // args[1]: index 411 RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) { 412 HandleScope scope(isolate); 413 DCHECK(args.length() == 2); 414 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 415 RUNTIME_ASSERT(obj->HasIndexedInterceptor()); 416 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); 417 Handle<Object> result; 418 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 419 Object::GetElement(isolate, obj, index)); 420 return *result; 421 } 422 423 424 RUNTIME_FUNCTION(Runtime_CheckExecutionState) { 425 SealHandleScope shs(isolate); 426 DCHECK(args.length() == 1); 427 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 428 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 429 return isolate->heap()->true_value(); 430 } 431 432 433 RUNTIME_FUNCTION(Runtime_GetFrameCount) { 434 HandleScope scope(isolate); 435 DCHECK(args.length() == 1); 436 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 437 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 438 439 // Count all frames which are relevant to debugging stack trace. 440 int n = 0; 441 StackFrame::Id id = isolate->debug()->break_frame_id(); 442 if (id == StackFrame::NO_ID) { 443 // If there is no JavaScript stack frame count is 0. 444 return Smi::FromInt(0); 445 } 446 447 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) { 448 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); 449 it.frame()->Summarize(&frames); 450 for (int i = frames.length() - 1; i >= 0; i--) { 451 // Omit functions from native and extension scripts. 452 if (frames[i].function()->shared()->IsSubjectToDebugging()) n++; 453 } 454 } 455 return Smi::FromInt(n); 456 } 457 458 459 static const int kFrameDetailsFrameIdIndex = 0; 460 static const int kFrameDetailsReceiverIndex = 1; 461 static const int kFrameDetailsFunctionIndex = 2; 462 static const int kFrameDetailsArgumentCountIndex = 3; 463 static const int kFrameDetailsLocalCountIndex = 4; 464 static const int kFrameDetailsSourcePositionIndex = 5; 465 static const int kFrameDetailsConstructCallIndex = 6; 466 static const int kFrameDetailsAtReturnIndex = 7; 467 static const int kFrameDetailsFlagsIndex = 8; 468 static const int kFrameDetailsFirstDynamicIndex = 9; 469 470 471 // Return an array with frame details 472 // args[0]: number: break id 473 // args[1]: number: frame index 474 // 475 // The array returned contains the following information: 476 // 0: Frame id 477 // 1: Receiver 478 // 2: Function 479 // 3: Argument count 480 // 4: Local count 481 // 5: Source position 482 // 6: Constructor call 483 // 7: Is at return 484 // 8: Flags 485 // Arguments name, value 486 // Locals name, value 487 // Return value if any 488 RUNTIME_FUNCTION(Runtime_GetFrameDetails) { 489 HandleScope scope(isolate); 490 DCHECK(args.length() == 2); 491 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 492 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 493 494 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 495 Heap* heap = isolate->heap(); 496 497 // Find the relevant frame with the requested index. 498 StackFrame::Id id = isolate->debug()->break_frame_id(); 499 if (id == StackFrame::NO_ID) { 500 // If there are no JavaScript stack frames return undefined. 501 return heap->undefined_value(); 502 } 503 504 JavaScriptFrameIterator it(isolate, id); 505 // Inlined frame index in optimized frame, starting from outer function. 506 int inlined_jsframe_index = 507 DebugFrameHelper::FindIndexedNonNativeFrame(&it, index); 508 if (inlined_jsframe_index == -1) return heap->undefined_value(); 509 510 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate); 511 bool is_optimized = it.frame()->is_optimized(); 512 513 // Traverse the saved contexts chain to find the active context for the 514 // selected frame. 515 SaveContext* save = 516 DebugFrameHelper::FindSavedContextForFrame(isolate, it.frame()); 517 518 // Get the frame id. 519 Handle<Object> frame_id(DebugFrameHelper::WrapFrameId(it.frame()->id()), 520 isolate); 521 522 // Find source position in unoptimized code. 523 int position = frame_inspector.GetSourcePosition(); 524 525 // Check for constructor frame. 526 bool constructor = frame_inspector.IsConstructor(); 527 528 // Get scope info and read from it for local variable information. 529 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 530 RUNTIME_ASSERT(function->shared()->IsSubjectToDebugging()); 531 Handle<SharedFunctionInfo> shared(function->shared()); 532 Handle<ScopeInfo> scope_info(shared->scope_info()); 533 DCHECK(*scope_info != ScopeInfo::Empty(isolate)); 534 535 // Get the locals names and values into a temporary array. 536 int local_count = scope_info->LocalCount(); 537 for (int slot = 0; slot < scope_info->LocalCount(); ++slot) { 538 // Hide compiler-introduced temporary variables, whether on the stack or on 539 // the context. 540 if (scope_info->LocalIsSynthetic(slot)) local_count--; 541 } 542 543 Handle<FixedArray> locals = 544 isolate->factory()->NewFixedArray(local_count * 2); 545 546 // Fill in the values of the locals. 547 int local = 0; 548 int i = 0; 549 for (; i < scope_info->StackLocalCount(); ++i) { 550 // Use the value from the stack. 551 if (scope_info->LocalIsSynthetic(i)) continue; 552 locals->set(local * 2, scope_info->LocalName(i)); 553 locals->set(local * 2 + 1, frame_inspector.GetExpression(i)); 554 local++; 555 } 556 if (local < local_count) { 557 // Get the context containing declarations. 558 Handle<Context> context( 559 Context::cast(frame_inspector.GetContext())->declaration_context()); 560 for (; i < scope_info->LocalCount(); ++i) { 561 if (scope_info->LocalIsSynthetic(i)) continue; 562 Handle<String> name(scope_info->LocalName(i)); 563 VariableMode mode; 564 InitializationFlag init_flag; 565 MaybeAssignedFlag maybe_assigned_flag; 566 locals->set(local * 2, *name); 567 int context_slot_index = ScopeInfo::ContextSlotIndex( 568 scope_info, name, &mode, &init_flag, &maybe_assigned_flag); 569 Object* value = context->get(context_slot_index); 570 locals->set(local * 2 + 1, value); 571 local++; 572 } 573 } 574 575 // Check whether this frame is positioned at return. If not top 576 // frame or if the frame is optimized it cannot be at a return. 577 bool at_return = false; 578 if (!is_optimized && index == 0) { 579 at_return = isolate->debug()->IsBreakAtReturn(it.frame()); 580 } 581 582 // If positioned just before return find the value to be returned and add it 583 // to the frame information. 584 Handle<Object> return_value = isolate->factory()->undefined_value(); 585 if (at_return) { 586 StackFrameIterator it2(isolate); 587 Address internal_frame_sp = NULL; 588 while (!it2.done()) { 589 if (it2.frame()->is_internal()) { 590 internal_frame_sp = it2.frame()->sp(); 591 } else { 592 if (it2.frame()->is_java_script()) { 593 if (it2.frame()->id() == it.frame()->id()) { 594 // The internal frame just before the JavaScript frame contains the 595 // value to return on top. A debug break at return will create an 596 // internal frame to store the return value (eax/rax/r0) before 597 // entering the debug break exit frame. 598 if (internal_frame_sp != NULL) { 599 return_value = 600 Handle<Object>(Memory::Object_at(internal_frame_sp), isolate); 601 break; 602 } 603 } 604 } 605 606 // Indicate that the previous frame was not an internal frame. 607 internal_frame_sp = NULL; 608 } 609 it2.Advance(); 610 } 611 } 612 613 // Now advance to the arguments adapter frame (if any). It contains all 614 // the provided parameters whereas the function frame always have the number 615 // of arguments matching the functions parameters. The rest of the 616 // information (except for what is collected above) is the same. 617 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) { 618 it.AdvanceToArgumentsFrame(); 619 frame_inspector.SetArgumentsFrame(it.frame()); 620 } 621 622 // Find the number of arguments to fill. At least fill the number of 623 // parameters for the function and fill more if more parameters are provided. 624 int argument_count = scope_info->ParameterCount(); 625 if (argument_count < frame_inspector.GetParametersCount()) { 626 argument_count = frame_inspector.GetParametersCount(); 627 } 628 629 // Calculate the size of the result. 630 int details_size = kFrameDetailsFirstDynamicIndex + 631 2 * (argument_count + local_count) + (at_return ? 1 : 0); 632 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); 633 634 // Add the frame id. 635 details->set(kFrameDetailsFrameIdIndex, *frame_id); 636 637 // Add the function (same as in function frame). 638 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction()); 639 640 // Add the arguments count. 641 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); 642 643 // Add the locals count 644 details->set(kFrameDetailsLocalCountIndex, Smi::FromInt(local_count)); 645 646 // Add the source position. 647 if (position != RelocInfo::kNoPosition) { 648 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); 649 } else { 650 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value()); 651 } 652 653 // Add the constructor information. 654 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor)); 655 656 // Add the at return information. 657 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); 658 659 // Add flags to indicate information on whether this frame is 660 // bit 0: invoked in the debugger context. 661 // bit 1: optimized frame. 662 // bit 2: inlined in optimized frame 663 int flags = 0; 664 if (*save->context() == *isolate->debug()->debug_context()) { 665 flags |= 1 << 0; 666 } 667 if (is_optimized) { 668 flags |= 1 << 1; 669 flags |= inlined_jsframe_index << 2; 670 } 671 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); 672 673 // Fill the dynamic part. 674 int details_index = kFrameDetailsFirstDynamicIndex; 675 676 // Add arguments name and value. 677 for (int i = 0; i < argument_count; i++) { 678 // Name of the argument. 679 if (i < scope_info->ParameterCount()) { 680 details->set(details_index++, scope_info->ParameterName(i)); 681 } else { 682 details->set(details_index++, heap->undefined_value()); 683 } 684 685 // Parameter value. 686 if (i < frame_inspector.GetParametersCount()) { 687 // Get the value from the stack. 688 details->set(details_index++, frame_inspector.GetParameter(i)); 689 } else { 690 details->set(details_index++, heap->undefined_value()); 691 } 692 } 693 694 // Add locals name and value from the temporary copy from the function frame. 695 for (int i = 0; i < local_count * 2; i++) { 696 details->set(details_index++, locals->get(i)); 697 } 698 699 // Add the value being returned. 700 if (at_return) { 701 details->set(details_index++, *return_value); 702 } 703 704 // Add the receiver (same as in function frame). 705 Handle<Object> receiver(it.frame()->receiver(), isolate); 706 DCHECK(!function->shared()->IsBuiltin()); 707 if (!receiver->IsJSObject() && is_sloppy(shared->language_mode())) { 708 // If the receiver is not a JSObject and the function is not a builtin or 709 // strict-mode we have hit an optimization where a value object is not 710 // converted into a wrapped JS objects. To hide this optimization from the 711 // debugger, we wrap the receiver by creating correct wrapper object based 712 // on the function's native context. 713 // See ECMA-262 6.0, 9.2.1.2, 6 b iii. 714 if (receiver->IsUndefined()) { 715 receiver = handle(function->global_proxy()); 716 } else { 717 Context* context = function->context(); 718 Handle<Context> native_context(Context::cast(context->native_context())); 719 if (!Object::ToObject(isolate, receiver, native_context) 720 .ToHandle(&receiver)) { 721 // This only happens if the receiver is forcibly set in %_CallFunction. 722 return heap->undefined_value(); 723 } 724 } 725 } 726 details->set(kFrameDetailsReceiverIndex, *receiver); 727 728 DCHECK_EQ(details_size, details_index); 729 return *isolate->factory()->NewJSArrayWithElements(details); 730 } 731 732 733 RUNTIME_FUNCTION(Runtime_GetScopeCount) { 734 HandleScope scope(isolate); 735 DCHECK(args.length() == 2); 736 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 737 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 738 739 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 740 741 // Get the frame where the debugging is performed. 742 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 743 JavaScriptFrameIterator it(isolate, id); 744 JavaScriptFrame* frame = it.frame(); 745 FrameInspector frame_inspector(frame, 0, isolate); 746 747 // Count the visible scopes. 748 int n = 0; 749 for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) { 750 n++; 751 } 752 753 return Smi::FromInt(n); 754 } 755 756 757 // Returns the list of step-in positions (text offset) in a function of the 758 // stack frame in a range from the current debug break position to the end 759 // of the corresponding statement. 760 RUNTIME_FUNCTION(Runtime_GetStepInPositions) { 761 HandleScope scope(isolate); 762 DCHECK(args.length() == 2); 763 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 764 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 765 766 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 767 768 // Get the frame where the debugging is performed. 769 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 770 JavaScriptFrameIterator frame_it(isolate, id); 771 RUNTIME_ASSERT(!frame_it.done()); 772 773 List<int> positions; 774 isolate->debug()->GetStepinPositions(frame_it.frame(), id, &positions); 775 Factory* factory = isolate->factory(); 776 Handle<FixedArray> array = factory->NewFixedArray(positions.length()); 777 for (int i = 0; i < positions.length(); ++i) { 778 array->set(i, Smi::FromInt(positions[i])); 779 } 780 return *factory->NewJSArrayWithElements(array, FAST_SMI_ELEMENTS); 781 } 782 783 784 // Return an array with scope details 785 // args[0]: number: break id 786 // args[1]: number: frame index 787 // args[2]: number: inlined frame index 788 // args[3]: number: scope index 789 // 790 // The array returned contains the following information: 791 // 0: Scope type 792 // 1: Scope object 793 RUNTIME_FUNCTION(Runtime_GetScopeDetails) { 794 HandleScope scope(isolate); 795 DCHECK(args.length() == 4); 796 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 797 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 798 799 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 800 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 801 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 802 803 // Get the frame where the debugging is performed. 804 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 805 JavaScriptFrameIterator frame_it(isolate, id); 806 JavaScriptFrame* frame = frame_it.frame(); 807 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 808 809 // Find the requested scope. 810 int n = 0; 811 ScopeIterator it(isolate, &frame_inspector); 812 for (; !it.Done() && n < index; it.Next()) { 813 n++; 814 } 815 if (it.Done()) { 816 return isolate->heap()->undefined_value(); 817 } 818 Handle<JSObject> details; 819 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, 820 it.MaterializeScopeDetails()); 821 return *details; 822 } 823 824 825 // Return an array of scope details 826 // args[0]: number: break id 827 // args[1]: number: frame index 828 // args[2]: number: inlined frame index 829 // args[3]: boolean: ignore nested scopes 830 // 831 // The array returned contains arrays with the following information: 832 // 0: Scope type 833 // 1: Scope object 834 RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) { 835 HandleScope scope(isolate); 836 DCHECK(args.length() == 3 || args.length() == 4); 837 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 838 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 839 840 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 841 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 842 843 ScopeIterator::Option option = ScopeIterator::DEFAULT; 844 if (args.length() == 4) { 845 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3); 846 if (flag) option = ScopeIterator::IGNORE_NESTED_SCOPES; 847 } 848 849 // Get the frame where the debugging is performed. 850 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 851 JavaScriptFrameIterator frame_it(isolate, id); 852 JavaScriptFrame* frame = frame_it.frame(); 853 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 854 855 List<Handle<JSObject> > result(4); 856 ScopeIterator it(isolate, &frame_inspector, option); 857 for (; !it.Done(); it.Next()) { 858 Handle<JSObject> details; 859 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, 860 it.MaterializeScopeDetails()); 861 result.Add(details); 862 } 863 864 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length()); 865 for (int i = 0; i < result.length(); ++i) { 866 array->set(i, *result[i]); 867 } 868 return *isolate->factory()->NewJSArrayWithElements(array); 869 } 870 871 872 RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) { 873 HandleScope scope(isolate); 874 DCHECK_EQ(1, args.length()); 875 876 // Check arguments. 877 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0); 878 879 // Count the visible scopes. 880 int n = 0; 881 if (function->IsJSFunction()) { 882 for (ScopeIterator it(isolate, Handle<JSFunction>::cast(function)); 883 !it.Done(); it.Next()) { 884 n++; 885 } 886 } 887 888 return Smi::FromInt(n); 889 } 890 891 892 RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) { 893 HandleScope scope(isolate); 894 DCHECK(args.length() == 2); 895 896 // Check arguments. 897 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 898 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 899 900 // Find the requested scope. 901 int n = 0; 902 ScopeIterator it(isolate, fun); 903 for (; !it.Done() && n < index; it.Next()) { 904 n++; 905 } 906 if (it.Done()) { 907 return isolate->heap()->undefined_value(); 908 } 909 910 Handle<JSObject> details; 911 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, 912 it.MaterializeScopeDetails()); 913 return *details; 914 } 915 916 917 static bool SetScopeVariableValue(ScopeIterator* it, int index, 918 Handle<String> variable_name, 919 Handle<Object> new_value) { 920 for (int n = 0; !it->Done() && n < index; it->Next()) { 921 n++; 922 } 923 if (it->Done()) { 924 return false; 925 } 926 return it->SetVariableValue(variable_name, new_value); 927 } 928 929 930 // Change variable value in closure or local scope 931 // args[0]: number or JsFunction: break id or function 932 // args[1]: number: frame index (when arg[0] is break id) 933 // args[2]: number: inlined frame index (when arg[0] is break id) 934 // args[3]: number: scope index 935 // args[4]: string: variable name 936 // args[5]: object: new value 937 // 938 // Return true if success and false otherwise 939 RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) { 940 HandleScope scope(isolate); 941 DCHECK(args.length() == 6); 942 943 // Check arguments. 944 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 945 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4); 946 CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5); 947 948 bool res; 949 if (args[0]->IsNumber()) { 950 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 951 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 952 953 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 954 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 955 956 // Get the frame where the debugging is performed. 957 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 958 JavaScriptFrameIterator frame_it(isolate, id); 959 JavaScriptFrame* frame = frame_it.frame(); 960 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 961 962 ScopeIterator it(isolate, &frame_inspector); 963 res = SetScopeVariableValue(&it, index, variable_name, new_value); 964 } else { 965 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 966 ScopeIterator it(isolate, fun); 967 res = SetScopeVariableValue(&it, index, variable_name, new_value); 968 } 969 970 return isolate->heap()->ToBoolean(res); 971 } 972 973 974 RUNTIME_FUNCTION(Runtime_DebugPrintScopes) { 975 HandleScope scope(isolate); 976 DCHECK(args.length() == 0); 977 978 #ifdef DEBUG 979 // Print the scopes for the top frame. 980 StackFrameLocator locator(isolate); 981 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 982 FrameInspector frame_inspector(frame, 0, isolate); 983 984 for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) { 985 it.DebugPrint(); 986 } 987 #endif 988 return isolate->heap()->undefined_value(); 989 } 990 991 992 RUNTIME_FUNCTION(Runtime_GetThreadCount) { 993 HandleScope scope(isolate); 994 DCHECK(args.length() == 1); 995 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 996 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 997 998 // Count all archived V8 threads. 999 int n = 0; 1000 for (ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse(); 1001 thread != NULL; thread = thread->Next()) { 1002 n++; 1003 } 1004 1005 // Total number of threads is current thread and archived threads. 1006 return Smi::FromInt(n + 1); 1007 } 1008 1009 1010 static const int kThreadDetailsCurrentThreadIndex = 0; 1011 static const int kThreadDetailsThreadIdIndex = 1; 1012 static const int kThreadDetailsSize = 2; 1013 1014 // Return an array with thread details 1015 // args[0]: number: break id 1016 // args[1]: number: thread index 1017 // 1018 // The array returned contains the following information: 1019 // 0: Is current thread? 1020 // 1: Thread id 1021 RUNTIME_FUNCTION(Runtime_GetThreadDetails) { 1022 HandleScope scope(isolate); 1023 DCHECK(args.length() == 2); 1024 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 1025 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 1026 1027 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 1028 1029 // Allocate array for result. 1030 Handle<FixedArray> details = 1031 isolate->factory()->NewFixedArray(kThreadDetailsSize); 1032 1033 // Thread index 0 is current thread. 1034 if (index == 0) { 1035 // Fill the details. 1036 details->set(kThreadDetailsCurrentThreadIndex, 1037 isolate->heap()->true_value()); 1038 details->set(kThreadDetailsThreadIdIndex, 1039 Smi::FromInt(ThreadId::Current().ToInteger())); 1040 } else { 1041 // Find the thread with the requested index. 1042 int n = 1; 1043 ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse(); 1044 while (index != n && thread != NULL) { 1045 thread = thread->Next(); 1046 n++; 1047 } 1048 if (thread == NULL) { 1049 return isolate->heap()->undefined_value(); 1050 } 1051 1052 // Fill the details. 1053 details->set(kThreadDetailsCurrentThreadIndex, 1054 isolate->heap()->false_value()); 1055 details->set(kThreadDetailsThreadIdIndex, 1056 Smi::FromInt(thread->id().ToInteger())); 1057 } 1058 1059 // Convert to JS array and return. 1060 return *isolate->factory()->NewJSArrayWithElements(details); 1061 } 1062 1063 1064 // Sets the disable break state 1065 // args[0]: disable break state 1066 RUNTIME_FUNCTION(Runtime_SetBreakPointsActive) { 1067 HandleScope scope(isolate); 1068 DCHECK(args.length() == 1); 1069 CONVERT_BOOLEAN_ARG_CHECKED(active, 0); 1070 isolate->debug()->set_break_points_active(active); 1071 return isolate->heap()->undefined_value(); 1072 } 1073 1074 1075 static bool IsPositionAlignmentCodeCorrect(int alignment) { 1076 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED; 1077 } 1078 1079 1080 RUNTIME_FUNCTION(Runtime_GetBreakLocations) { 1081 HandleScope scope(isolate); 1082 DCHECK(args.length() == 2); 1083 RUNTIME_ASSERT(isolate->debug()->is_active()); 1084 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 1085 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]); 1086 1087 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { 1088 return isolate->ThrowIllegalOperation(); 1089 } 1090 BreakPositionAlignment alignment = 1091 static_cast<BreakPositionAlignment>(statement_aligned_code); 1092 1093 Handle<SharedFunctionInfo> shared(fun->shared()); 1094 // Find the number of break points 1095 Handle<Object> break_locations = 1096 Debug::GetSourceBreakLocations(shared, alignment); 1097 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value(); 1098 // Return array as JS array 1099 return *isolate->factory()->NewJSArrayWithElements( 1100 Handle<FixedArray>::cast(break_locations)); 1101 } 1102 1103 1104 // Set a break point in a function. 1105 // args[0]: function 1106 // args[1]: number: break source position (within the function source) 1107 // args[2]: number: break point object 1108 RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) { 1109 HandleScope scope(isolate); 1110 DCHECK(args.length() == 3); 1111 RUNTIME_ASSERT(isolate->debug()->is_active()); 1112 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 1113 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 1114 RUNTIME_ASSERT(source_position >= function->shared()->start_position() && 1115 source_position <= function->shared()->end_position()); 1116 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2); 1117 1118 // Set break point. 1119 RUNTIME_ASSERT(isolate->debug()->SetBreakPoint( 1120 function, break_point_object_arg, &source_position)); 1121 1122 return Smi::FromInt(source_position); 1123 } 1124 1125 1126 // Changes the state of a break point in a script and returns source position 1127 // where break point was set. NOTE: Regarding performance see the NOTE for 1128 // GetScriptFromScriptData. 1129 // args[0]: script to set break point in 1130 // args[1]: number: break source position (within the script source) 1131 // args[2]: number, breakpoint position alignment 1132 // args[3]: number: break point object 1133 RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) { 1134 HandleScope scope(isolate); 1135 DCHECK(args.length() == 4); 1136 RUNTIME_ASSERT(isolate->debug()->is_active()); 1137 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0); 1138 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 1139 RUNTIME_ASSERT(source_position >= 0); 1140 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]); 1141 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3); 1142 1143 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { 1144 return isolate->ThrowIllegalOperation(); 1145 } 1146 BreakPositionAlignment alignment = 1147 static_cast<BreakPositionAlignment>(statement_aligned_code); 1148 1149 // Get the script from the script wrapper. 1150 RUNTIME_ASSERT(wrapper->value()->IsScript()); 1151 Handle<Script> script(Script::cast(wrapper->value())); 1152 1153 // Set break point. 1154 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg, 1155 &source_position, alignment)) { 1156 return isolate->heap()->undefined_value(); 1157 } 1158 1159 return Smi::FromInt(source_position); 1160 } 1161 1162 1163 // Clear a break point 1164 // args[0]: number: break point object 1165 RUNTIME_FUNCTION(Runtime_ClearBreakPoint) { 1166 HandleScope scope(isolate); 1167 DCHECK(args.length() == 1); 1168 RUNTIME_ASSERT(isolate->debug()->is_active()); 1169 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0); 1170 1171 // Clear break point. 1172 isolate->debug()->ClearBreakPoint(break_point_object_arg); 1173 1174 return isolate->heap()->undefined_value(); 1175 } 1176 1177 1178 // Change the state of break on exceptions. 1179 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions. 1180 // args[1]: Boolean indicating on/off. 1181 RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) { 1182 HandleScope scope(isolate); 1183 DCHECK(args.length() == 2); 1184 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); 1185 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1); 1186 1187 // If the number doesn't match an enum value, the ChangeBreakOnException 1188 // function will default to affecting caught exceptions. 1189 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); 1190 // Update break point state. 1191 isolate->debug()->ChangeBreakOnException(type, enable); 1192 return isolate->heap()->undefined_value(); 1193 } 1194 1195 1196 // Returns the state of break on exceptions 1197 // args[0]: boolean indicating uncaught exceptions 1198 RUNTIME_FUNCTION(Runtime_IsBreakOnException) { 1199 HandleScope scope(isolate); 1200 DCHECK(args.length() == 1); 1201 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); 1202 1203 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); 1204 bool result = isolate->debug()->IsBreakOnException(type); 1205 return Smi::FromInt(result); 1206 } 1207 1208 1209 // Prepare for stepping 1210 // args[0]: break id for checking execution state 1211 // args[1]: step action from the enumeration StepAction 1212 // args[2]: number of times to perform the step, for step out it is the number 1213 // of frames to step down. 1214 RUNTIME_FUNCTION(Runtime_PrepareStep) { 1215 HandleScope scope(isolate); 1216 DCHECK(args.length() == 2); 1217 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 1218 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 1219 1220 if (!args[1]->IsNumber()) { 1221 return isolate->Throw(isolate->heap()->illegal_argument_string()); 1222 } 1223 1224 // Get the step action and check validity. 1225 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); 1226 if (step_action != StepIn && step_action != StepNext && 1227 step_action != StepOut && step_action != StepFrame) { 1228 return isolate->Throw(isolate->heap()->illegal_argument_string()); 1229 } 1230 1231 // Clear all current stepping setup. 1232 isolate->debug()->ClearStepping(); 1233 1234 // Prepare step. 1235 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action)); 1236 return isolate->heap()->undefined_value(); 1237 } 1238 1239 1240 // Clear all stepping set by PrepareStep. 1241 RUNTIME_FUNCTION(Runtime_ClearStepping) { 1242 HandleScope scope(isolate); 1243 DCHECK(args.length() == 0); 1244 RUNTIME_ASSERT(isolate->debug()->is_active()); 1245 isolate->debug()->ClearStepping(); 1246 return isolate->heap()->undefined_value(); 1247 } 1248 1249 1250 RUNTIME_FUNCTION(Runtime_DebugEvaluate) { 1251 HandleScope scope(isolate); 1252 1253 // Check the execution state and decode arguments frame and source to be 1254 // evaluated. 1255 DCHECK(args.length() == 6); 1256 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 1257 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 1258 1259 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 1260 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 1261 CONVERT_ARG_HANDLE_CHECKED(String, source, 3); 1262 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); 1263 CONVERT_ARG_HANDLE_CHECKED(HeapObject, context_extension, 5); 1264 1265 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); 1266 1267 Handle<Object> result; 1268 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1269 isolate, result, 1270 DebugEvaluate::Local(isolate, id, inlined_jsframe_index, source, 1271 disable_break, context_extension)); 1272 return *result; 1273 } 1274 1275 1276 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { 1277 HandleScope scope(isolate); 1278 1279 // Check the execution state and decode arguments frame and source to be 1280 // evaluated. 1281 DCHECK(args.length() == 4); 1282 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 1283 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); 1284 1285 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 1286 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); 1287 CONVERT_ARG_HANDLE_CHECKED(HeapObject, context_extension, 3); 1288 1289 Handle<Object> result; 1290 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1291 isolate, result, 1292 DebugEvaluate::Global(isolate, source, disable_break, context_extension)); 1293 return *result; 1294 } 1295 1296 1297 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) { 1298 HandleScope scope(isolate); 1299 DCHECK(args.length() == 0); 1300 RUNTIME_ASSERT(isolate->debug()->is_active()); 1301 1302 Handle<FixedArray> instances; 1303 { 1304 DebugScope debug_scope(isolate->debug()); 1305 if (debug_scope.failed()) { 1306 DCHECK(isolate->has_pending_exception()); 1307 return isolate->heap()->exception(); 1308 } 1309 // Fill the script objects. 1310 instances = isolate->debug()->GetLoadedScripts(); 1311 } 1312 1313 // Convert the script objects to proper JS objects. 1314 for (int i = 0; i < instances->length(); i++) { 1315 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); 1316 // Get the script wrapper in a local handle before calling GetScriptWrapper, 1317 // because using 1318 // instances->set(i, *GetScriptWrapper(script)) 1319 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might 1320 // already have dereferenced the instances handle. 1321 Handle<JSObject> wrapper = Script::GetWrapper(script); 1322 instances->set(i, *wrapper); 1323 } 1324 1325 // Return result as a JS array. 1326 Handle<JSObject> result = 1327 isolate->factory()->NewJSObject(isolate->array_function()); 1328 JSArray::SetContent(Handle<JSArray>::cast(result), instances); 1329 return *result; 1330 } 1331 1332 1333 static bool HasInPrototypeChainIgnoringProxies(Isolate* isolate, Object* object, 1334 Object* proto) { 1335 PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER); 1336 while (true) { 1337 iter.AdvanceIgnoringProxies(); 1338 if (iter.IsAtEnd()) return false; 1339 if (iter.IsAtEnd(proto)) return true; 1340 } 1341 } 1342 1343 1344 // Scan the heap for objects with direct references to an object 1345 // args[0]: the object to find references to 1346 // args[1]: constructor function for instances to exclude (Mirror) 1347 // args[2]: the the maximum number of objects to return 1348 RUNTIME_FUNCTION(Runtime_DebugReferencedBy) { 1349 HandleScope scope(isolate); 1350 DCHECK(args.length() == 3); 1351 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0); 1352 CONVERT_ARG_HANDLE_CHECKED(Object, filter, 1); 1353 RUNTIME_ASSERT(filter->IsUndefined() || filter->IsJSObject()); 1354 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); 1355 RUNTIME_ASSERT(max_references >= 0); 1356 1357 List<Handle<JSObject> > instances; 1358 Heap* heap = isolate->heap(); 1359 { 1360 HeapIterator iterator(heap, HeapIterator::kFilterUnreachable); 1361 // Get the constructor function for context extension and arguments array. 1362 Object* arguments_fun = isolate->sloppy_arguments_map()->GetConstructor(); 1363 HeapObject* heap_obj; 1364 while ((heap_obj = iterator.next())) { 1365 if (!heap_obj->IsJSObject()) continue; 1366 JSObject* obj = JSObject::cast(heap_obj); 1367 if (obj->IsJSContextExtensionObject()) continue; 1368 if (obj->map()->GetConstructor() == arguments_fun) continue; 1369 if (!obj->ReferencesObject(*target)) continue; 1370 // Check filter if supplied. This is normally used to avoid 1371 // references from mirror objects. 1372 if (!filter->IsUndefined() && 1373 HasInPrototypeChainIgnoringProxies(isolate, obj, *filter)) { 1374 continue; 1375 } 1376 if (obj->IsJSGlobalObject()) { 1377 obj = JSGlobalObject::cast(obj)->global_proxy(); 1378 } 1379 instances.Add(Handle<JSObject>(obj)); 1380 if (instances.length() == max_references) break; 1381 } 1382 // Iterate the rest of the heap to satisfy HeapIterator constraints. 1383 while (iterator.next()) { 1384 } 1385 } 1386 1387 Handle<FixedArray> result; 1388 if (instances.length() == 1 && instances.last().is_identical_to(target)) { 1389 // Check for circular reference only. This can happen when the object is 1390 // only referenced from mirrors and has a circular reference in which case 1391 // the object is not really alive and would have been garbage collected if 1392 // not referenced from the mirror. 1393 result = isolate->factory()->empty_fixed_array(); 1394 } else { 1395 result = isolate->factory()->NewFixedArray(instances.length()); 1396 for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]); 1397 } 1398 return *isolate->factory()->NewJSArrayWithElements(result); 1399 } 1400 1401 1402 // Scan the heap for objects constructed by a specific function. 1403 // args[0]: the constructor to find instances of 1404 // args[1]: the the maximum number of objects to return 1405 RUNTIME_FUNCTION(Runtime_DebugConstructedBy) { 1406 HandleScope scope(isolate); 1407 DCHECK(args.length() == 2); 1408 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0); 1409 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); 1410 RUNTIME_ASSERT(max_references >= 0); 1411 1412 List<Handle<JSObject> > instances; 1413 Heap* heap = isolate->heap(); 1414 { 1415 HeapIterator iterator(heap, HeapIterator::kFilterUnreachable); 1416 HeapObject* heap_obj; 1417 while ((heap_obj = iterator.next())) { 1418 if (!heap_obj->IsJSObject()) continue; 1419 JSObject* obj = JSObject::cast(heap_obj); 1420 if (obj->map()->GetConstructor() != *constructor) continue; 1421 instances.Add(Handle<JSObject>(obj)); 1422 if (instances.length() == max_references) break; 1423 } 1424 // Iterate the rest of the heap to satisfy HeapIterator constraints. 1425 while (iterator.next()) { 1426 } 1427 } 1428 1429 Handle<FixedArray> result = 1430 isolate->factory()->NewFixedArray(instances.length()); 1431 for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]); 1432 return *isolate->factory()->NewJSArrayWithElements(result); 1433 } 1434 1435 1436 // Find the effective prototype object as returned by __proto__. 1437 // args[0]: the object to find the prototype for. 1438 RUNTIME_FUNCTION(Runtime_DebugGetPrototype) { 1439 HandleScope shs(isolate); 1440 DCHECK(args.length() == 1); 1441 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 1442 Handle<Object> prototype; 1443 // TODO(1543): Come up with a solution for clients to handle potential errors 1444 // thrown by an intermediate proxy. 1445 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, prototype, 1446 Object::GetPrototype(isolate, obj)); 1447 return *prototype; 1448 } 1449 1450 1451 // Patches script source (should be called upon BeforeCompile event). 1452 RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) { 1453 HandleScope scope(isolate); 1454 DCHECK(args.length() == 2); 1455 1456 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0); 1457 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 1458 1459 RUNTIME_ASSERT(script_wrapper->value()->IsScript()); 1460 Handle<Script> script(Script::cast(script_wrapper->value())); 1461 1462 int compilation_state = script->compilation_state(); 1463 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL); 1464 script->set_source(*source); 1465 1466 return isolate->heap()->undefined_value(); 1467 } 1468 1469 1470 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) { 1471 SealHandleScope shs(isolate); 1472 DCHECK_EQ(1, args.length()); 1473 1474 CONVERT_ARG_CHECKED(Object, f, 0); 1475 if (f->IsJSFunction()) { 1476 return JSFunction::cast(f)->shared()->inferred_name(); 1477 } 1478 return isolate->heap()->empty_string(); 1479 } 1480 1481 1482 RUNTIME_FUNCTION(Runtime_FunctionGetDebugName) { 1483 HandleScope scope(isolate); 1484 DCHECK_EQ(1, args.length()); 1485 1486 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0); 1487 1488 if (function->IsJSBoundFunction()) { 1489 return Handle<JSBoundFunction>::cast(function)->name(); 1490 } 1491 Handle<Object> name = 1492 JSFunction::GetDebugName(Handle<JSFunction>::cast(function)); 1493 return *name; 1494 } 1495 1496 1497 // A testing entry. Returns statement position which is the closest to 1498 // source_position. 1499 RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) { 1500 HandleScope scope(isolate); 1501 CHECK(isolate->debug()->live_edit_enabled()); 1502 DCHECK(args.length() == 2); 1503 RUNTIME_ASSERT(isolate->debug()->is_active()); 1504 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 1505 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 1506 1507 Handle<Code> code(function->code(), isolate); 1508 1509 if (code->kind() != Code::FUNCTION && 1510 code->kind() != Code::OPTIMIZED_FUNCTION) { 1511 return isolate->heap()->undefined_value(); 1512 } 1513 1514 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION)); 1515 int closest_pc = 0; 1516 int distance = kMaxInt; 1517 while (!it.done()) { 1518 int statement_position = static_cast<int>(it.rinfo()->data()); 1519 // Check if this break point is closer that what was previously found. 1520 if (source_position <= statement_position && 1521 statement_position - source_position < distance) { 1522 closest_pc = 1523 static_cast<int>(it.rinfo()->pc() - code->instruction_start()); 1524 distance = statement_position - source_position; 1525 // Check whether we can't get any closer. 1526 if (distance == 0) break; 1527 } 1528 it.next(); 1529 } 1530 1531 return Smi::FromInt(closest_pc); 1532 } 1533 1534 1535 // Calls specified function with or without entering the debugger. 1536 // This is used in unit tests to run code as if debugger is entered or simply 1537 // to have a stack with C++ frame in the middle. 1538 RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) { 1539 HandleScope scope(isolate); 1540 DCHECK(args.length() == 1); 1541 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 1542 1543 DebugScope debug_scope(isolate->debug()); 1544 if (debug_scope.failed()) { 1545 DCHECK(isolate->has_pending_exception()); 1546 return isolate->heap()->exception(); 1547 } 1548 1549 Handle<Object> result; 1550 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1551 isolate, result, 1552 Execution::Call(isolate, function, handle(function->global_proxy()), 0, 1553 NULL)); 1554 return *result; 1555 } 1556 1557 1558 RUNTIME_FUNCTION(Runtime_GetDebugContext) { 1559 HandleScope scope(isolate); 1560 DCHECK(args.length() == 0); 1561 Handle<Context> context; 1562 { 1563 DebugScope debug_scope(isolate->debug()); 1564 if (debug_scope.failed()) { 1565 DCHECK(isolate->has_pending_exception()); 1566 return isolate->heap()->exception(); 1567 } 1568 context = isolate->debug()->GetDebugContext(); 1569 } 1570 if (context.is_null()) return isolate->heap()->undefined_value(); 1571 context->set_security_token(isolate->native_context()->security_token()); 1572 return context->global_proxy(); 1573 } 1574 1575 1576 // Performs a GC. 1577 // Presently, it only does a full GC. 1578 RUNTIME_FUNCTION(Runtime_CollectGarbage) { 1579 SealHandleScope shs(isolate); 1580 DCHECK(args.length() == 1); 1581 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage"); 1582 return isolate->heap()->undefined_value(); 1583 } 1584 1585 1586 // Gets the current heap usage. 1587 RUNTIME_FUNCTION(Runtime_GetHeapUsage) { 1588 SealHandleScope shs(isolate); 1589 DCHECK(args.length() == 0); 1590 int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); 1591 if (!Smi::IsValid(usage)) { 1592 return *isolate->factory()->NewNumberFromInt(usage); 1593 } 1594 return Smi::FromInt(usage); 1595 } 1596 1597 1598 // Finds the script object from the script data. NOTE: This operation uses 1599 // heap traversal to find the function generated for the source position 1600 // for the requested break point. For lazily compiled functions several heap 1601 // traversals might be required rendering this operation as a rather slow 1602 // operation. However for setting break points which is normally done through 1603 // some kind of user interaction the performance is not crucial. 1604 RUNTIME_FUNCTION(Runtime_GetScript) { 1605 HandleScope scope(isolate); 1606 DCHECK(args.length() == 1); 1607 CONVERT_ARG_HANDLE_CHECKED(String, script_name, 0); 1608 1609 Handle<Script> found; 1610 { 1611 Script::Iterator iterator(isolate); 1612 Script* script = NULL; 1613 while ((script = iterator.Next()) != NULL) { 1614 if (!script->name()->IsString()) continue; 1615 String* name = String::cast(script->name()); 1616 if (name->Equals(*script_name)) { 1617 found = Handle<Script>(script, isolate); 1618 break; 1619 } 1620 } 1621 } 1622 1623 if (found.is_null()) return isolate->heap()->undefined_value(); 1624 return *Script::GetWrapper(found); 1625 } 1626 1627 1628 // Set one shot breakpoints for the callback function that is passed to a 1629 // built-in function such as Array.forEach to enable stepping into the callback, 1630 // if we are indeed stepping and the callback is subject to debugging. 1631 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) { 1632 DCHECK(args.length() == 1); 1633 HandleScope scope(isolate); 1634 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 1635 RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject()); 1636 Handle<JSFunction> fun; 1637 if (object->IsJSFunction()) { 1638 fun = Handle<JSFunction>::cast(object); 1639 } else { 1640 fun = Handle<JSFunction>( 1641 Handle<JSGeneratorObject>::cast(object)->function(), isolate); 1642 } 1643 1644 isolate->debug()->PrepareStepIn(fun); 1645 return isolate->heap()->undefined_value(); 1646 } 1647 1648 1649 RUNTIME_FUNCTION(Runtime_DebugPushPromise) { 1650 DCHECK(args.length() == 2); 1651 HandleScope scope(isolate); 1652 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); 1653 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1); 1654 isolate->PushPromise(promise, function); 1655 // If we are in step-in mode, flood the handler. 1656 isolate->debug()->EnableStepIn(); 1657 return isolate->heap()->undefined_value(); 1658 } 1659 1660 1661 RUNTIME_FUNCTION(Runtime_DebugPopPromise) { 1662 DCHECK(args.length() == 0); 1663 SealHandleScope shs(isolate); 1664 isolate->PopPromise(); 1665 return isolate->heap()->undefined_value(); 1666 } 1667 1668 1669 RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) { 1670 DCHECK(args.length() == 1); 1671 HandleScope scope(isolate); 1672 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0); 1673 isolate->debug()->OnPromiseEvent(data); 1674 return isolate->heap()->undefined_value(); 1675 } 1676 1677 1678 RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) { 1679 DCHECK(args.length() == 1); 1680 HandleScope scope(isolate); 1681 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0); 1682 isolate->debug()->OnAsyncTaskEvent(data); 1683 return isolate->heap()->undefined_value(); 1684 } 1685 1686 1687 RUNTIME_FUNCTION(Runtime_DebugIsActive) { 1688 SealHandleScope shs(isolate); 1689 return Smi::FromInt(isolate->debug()->is_active()); 1690 } 1691 1692 1693 RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode) { 1694 UNIMPLEMENTED(); 1695 return NULL; 1696 } 1697 } // namespace internal 1698 } // namespace v8 1699