| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/accessors.h" | |
| 8 #include "src/arguments.h" | 7 #include "src/arguments.h" |
| 9 #include "src/compiler.h" | |
| 10 #include "src/debug/debug.h" | 8 #include "src/debug/debug.h" |
| 11 #include "src/deoptimizer.h" | 9 #include "src/debug/debug-evaluate.h" |
| 12 #include "src/parser.h" | 10 #include "src/debug/debug-frames.h" |
| 11 #include "src/debug/debug-scopes.h" |
| 13 #include "src/runtime/runtime.h" | 12 #include "src/runtime/runtime.h" |
| 14 #include "src/runtime/runtime-utils.h" | 13 #include "src/runtime/runtime-utils.h" |
| 15 | 14 |
| 16 namespace v8 { | 15 namespace v8 { |
| 17 namespace internal { | 16 namespace internal { |
| 18 | 17 |
| 19 RUNTIME_FUNCTION(Runtime_DebugBreak) { | 18 RUNTIME_FUNCTION(Runtime_DebugBreak) { |
| 20 SealHandleScope shs(isolate); | 19 SealHandleScope shs(isolate); |
| 21 DCHECK(args.length() == 0); | 20 DCHECK(args.length() == 0); |
| 22 // Get the top-most JavaScript frame. | 21 // Get the top-most JavaScript frame. |
| 23 JavaScriptFrameIterator it(isolate); | 22 JavaScriptFrameIterator it(isolate); |
| 24 isolate->debug()->Break(args, it.frame()); | 23 isolate->debug()->Break(args, it.frame()); |
| 25 isolate->debug()->SetAfterBreakTarget(it.frame()); | 24 isolate->debug()->SetAfterBreakTarget(it.frame()); |
| 26 return isolate->heap()->undefined_value(); | 25 return isolate->heap()->undefined_value(); |
| 27 } | 26 } |
| 28 | 27 |
| 29 | 28 |
| 30 RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) { | 29 RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) { |
| 31 SealHandleScope shs(isolate); | 30 SealHandleScope shs(isolate); |
| 32 DCHECK(args.length() == 0); | 31 DCHECK(args.length() == 0); |
| 33 isolate->debug()->HandleDebugBreak(); | 32 isolate->debug()->HandleDebugBreak(); |
| 34 return isolate->heap()->undefined_value(); | 33 return isolate->heap()->undefined_value(); |
| 35 } | 34 } |
| 36 | 35 |
| 37 | 36 |
| 38 // Helper functions for wrapping and unwrapping stack frame ids. | |
| 39 static Smi* WrapFrameId(StackFrame::Id id) { | |
| 40 DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4))); | |
| 41 return Smi::FromInt(id >> 2); | |
| 42 } | |
| 43 | |
| 44 | |
| 45 static StackFrame::Id UnwrapFrameId(int wrapped) { | |
| 46 return static_cast<StackFrame::Id>(wrapped << 2); | |
| 47 } | |
| 48 | |
| 49 | |
| 50 // Adds a JavaScript function as a debug event listener. | 37 // Adds a JavaScript function as a debug event listener. |
| 51 // args[0]: debug event listener function to set or null or undefined for | 38 // args[0]: debug event listener function to set or null or undefined for |
| 52 // clearing the event listener function | 39 // clearing the event listener function |
| 53 // args[1]: object supplied during callback | 40 // args[1]: object supplied during callback |
| 54 RUNTIME_FUNCTION(Runtime_SetDebugEventListener) { | 41 RUNTIME_FUNCTION(Runtime_SetDebugEventListener) { |
| 55 SealHandleScope shs(isolate); | 42 SealHandleScope shs(isolate); |
| 56 DCHECK(args.length() == 2); | 43 DCHECK(args.length() == 2); |
| 57 RUNTIME_ASSERT(args[0]->IsJSFunction() || args[0]->IsUndefined() || | 44 RUNTIME_ASSERT(args[0]->IsJSFunction() || args[0]->IsUndefined() || |
| 58 args[0]->IsNull()); | 45 args[0]->IsNull()); |
| 59 CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0); | 46 CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0); |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 it.frame()->Summarize(&frames); | 455 it.frame()->Summarize(&frames); |
| 469 for (int i = frames.length() - 1; i >= 0; i--) { | 456 for (int i = frames.length() - 1; i >= 0; i--) { |
| 470 // Omit functions from native and extension scripts. | 457 // Omit functions from native and extension scripts. |
| 471 if (frames[i].function()->IsSubjectToDebugging()) n++; | 458 if (frames[i].function()->IsSubjectToDebugging()) n++; |
| 472 } | 459 } |
| 473 } | 460 } |
| 474 return Smi::FromInt(n); | 461 return Smi::FromInt(n); |
| 475 } | 462 } |
| 476 | 463 |
| 477 | 464 |
| 478 class FrameInspector { | |
| 479 public: | |
| 480 FrameInspector(JavaScriptFrame* frame, int inlined_jsframe_index, | |
| 481 Isolate* isolate) | |
| 482 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) { | |
| 483 has_adapted_arguments_ = frame_->has_adapted_arguments(); | |
| 484 is_bottommost_ = inlined_jsframe_index == 0; | |
| 485 is_optimized_ = frame_->is_optimized(); | |
| 486 // Calculate the deoptimized frame. | |
| 487 if (frame->is_optimized()) { | |
| 488 // TODO(turbofan): Revisit once we support deoptimization. | |
| 489 if (frame->LookupCode()->is_turbofanned() && | |
| 490 frame->function()->shared()->asm_function() && | |
| 491 !FLAG_turbo_asm_deoptimization) { | |
| 492 is_optimized_ = false; | |
| 493 return; | |
| 494 } | |
| 495 | |
| 496 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame( | |
| 497 frame, inlined_jsframe_index, isolate); | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 ~FrameInspector() { | |
| 502 // Get rid of the calculated deoptimized frame if any. | |
| 503 if (deoptimized_frame_ != NULL) { | |
| 504 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_); | |
| 505 } | |
| 506 } | |
| 507 | |
| 508 int GetParametersCount() { | |
| 509 return is_optimized_ ? deoptimized_frame_->parameters_count() | |
| 510 : frame_->ComputeParametersCount(); | |
| 511 } | |
| 512 int expression_count() { return deoptimized_frame_->expression_count(); } | |
| 513 Object* GetFunction() { | |
| 514 return is_optimized_ ? deoptimized_frame_->GetFunction() | |
| 515 : frame_->function(); | |
| 516 } | |
| 517 Object* GetParameter(int index) { | |
| 518 return is_optimized_ ? deoptimized_frame_->GetParameter(index) | |
| 519 : frame_->GetParameter(index); | |
| 520 } | |
| 521 Object* GetExpression(int index) { | |
| 522 // TODO(turbofan): Revisit once we support deoptimization. | |
| 523 if (frame_->LookupCode()->is_turbofanned() && | |
| 524 frame_->function()->shared()->asm_function() && | |
| 525 !FLAG_turbo_asm_deoptimization) { | |
| 526 return isolate_->heap()->undefined_value(); | |
| 527 } | |
| 528 return is_optimized_ ? deoptimized_frame_->GetExpression(index) | |
| 529 : frame_->GetExpression(index); | |
| 530 } | |
| 531 int GetSourcePosition() { | |
| 532 return is_optimized_ ? deoptimized_frame_->GetSourcePosition() | |
| 533 : frame_->LookupCode()->SourcePosition(frame_->pc()); | |
| 534 } | |
| 535 bool IsConstructor() { | |
| 536 return is_optimized_ && !is_bottommost_ | |
| 537 ? deoptimized_frame_->HasConstructStub() | |
| 538 : frame_->IsConstructor(); | |
| 539 } | |
| 540 Object* GetContext() { | |
| 541 return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context(); | |
| 542 } | |
| 543 JavaScriptFrame* GetArgumentsFrame() { return frame_; } | |
| 544 | |
| 545 // To inspect all the provided arguments the frame might need to be | |
| 546 // replaced with the arguments frame. | |
| 547 void SetArgumentsFrame(JavaScriptFrame* frame) { | |
| 548 DCHECK(has_adapted_arguments_); | |
| 549 frame_ = frame; | |
| 550 is_optimized_ = frame_->is_optimized(); | |
| 551 DCHECK(!is_optimized_); | |
| 552 } | |
| 553 | |
| 554 private: | |
| 555 JavaScriptFrame* frame_; | |
| 556 DeoptimizedFrameInfo* deoptimized_frame_; | |
| 557 Isolate* isolate_; | |
| 558 bool is_optimized_; | |
| 559 bool is_bottommost_; | |
| 560 bool has_adapted_arguments_; | |
| 561 | |
| 562 DISALLOW_COPY_AND_ASSIGN(FrameInspector); | |
| 563 }; | |
| 564 | |
| 565 | |
| 566 static const int kFrameDetailsFrameIdIndex = 0; | 465 static const int kFrameDetailsFrameIdIndex = 0; |
| 567 static const int kFrameDetailsReceiverIndex = 1; | 466 static const int kFrameDetailsReceiverIndex = 1; |
| 568 static const int kFrameDetailsFunctionIndex = 2; | 467 static const int kFrameDetailsFunctionIndex = 2; |
| 569 static const int kFrameDetailsArgumentCountIndex = 3; | 468 static const int kFrameDetailsArgumentCountIndex = 3; |
| 570 static const int kFrameDetailsLocalCountIndex = 4; | 469 static const int kFrameDetailsLocalCountIndex = 4; |
| 571 static const int kFrameDetailsSourcePositionIndex = 5; | 470 static const int kFrameDetailsSourcePositionIndex = 5; |
| 572 static const int kFrameDetailsConstructCallIndex = 6; | 471 static const int kFrameDetailsConstructCallIndex = 6; |
| 573 static const int kFrameDetailsAtReturnIndex = 7; | 472 static const int kFrameDetailsAtReturnIndex = 7; |
| 574 static const int kFrameDetailsFlagsIndex = 8; | 473 static const int kFrameDetailsFlagsIndex = 8; |
| 575 static const int kFrameDetailsFirstDynamicIndex = 9; | 474 static const int kFrameDetailsFirstDynamicIndex = 9; |
| 576 | 475 |
| 577 | 476 |
| 578 static SaveContext* FindSavedContextForFrame(Isolate* isolate, | |
| 579 JavaScriptFrame* frame) { | |
| 580 SaveContext* save = isolate->save_context(); | |
| 581 while (save != NULL && !save->IsBelowFrame(frame)) { | |
| 582 save = save->prev(); | |
| 583 } | |
| 584 DCHECK(save != NULL); | |
| 585 return save; | |
| 586 } | |
| 587 | |
| 588 | |
| 589 // Advances the iterator to the frame that matches the index and returns the | |
| 590 // inlined frame index, or -1 if not found. Skips native JS functions. | |
| 591 int Runtime::FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index) { | |
| 592 int count = -1; | |
| 593 for (; !it->done(); it->Advance()) { | |
| 594 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | |
| 595 it->frame()->Summarize(&frames); | |
| 596 for (int i = frames.length() - 1; i >= 0; i--) { | |
| 597 // Omit functions from native and extension scripts. | |
| 598 if (!frames[i].function()->IsSubjectToDebugging()) continue; | |
| 599 if (++count == index) return i; | |
| 600 } | |
| 601 } | |
| 602 return -1; | |
| 603 } | |
| 604 | |
| 605 | |
| 606 // Return an array with frame details | 477 // Return an array with frame details |
| 607 // args[0]: number: break id | 478 // args[0]: number: break id |
| 608 // args[1]: number: frame index | 479 // args[1]: number: frame index |
| 609 // | 480 // |
| 610 // The array returned contains the following information: | 481 // The array returned contains the following information: |
| 611 // 0: Frame id | 482 // 0: Frame id |
| 612 // 1: Receiver | 483 // 1: Receiver |
| 613 // 2: Function | 484 // 2: Function |
| 614 // 3: Argument count | 485 // 3: Argument count |
| 615 // 4: Local count | 486 // 4: Local count |
| (...skipping 15 matching lines...) Expand all Loading... |
| 631 | 502 |
| 632 // Find the relevant frame with the requested index. | 503 // Find the relevant frame with the requested index. |
| 633 StackFrame::Id id = isolate->debug()->break_frame_id(); | 504 StackFrame::Id id = isolate->debug()->break_frame_id(); |
| 634 if (id == StackFrame::NO_ID) { | 505 if (id == StackFrame::NO_ID) { |
| 635 // If there are no JavaScript stack frames return undefined. | 506 // If there are no JavaScript stack frames return undefined. |
| 636 return heap->undefined_value(); | 507 return heap->undefined_value(); |
| 637 } | 508 } |
| 638 | 509 |
| 639 JavaScriptFrameIterator it(isolate, id); | 510 JavaScriptFrameIterator it(isolate, id); |
| 640 // Inlined frame index in optimized frame, starting from outer function. | 511 // Inlined frame index in optimized frame, starting from outer function. |
| 641 int inlined_jsframe_index = Runtime::FindIndexedNonNativeFrame(&it, index); | 512 int inlined_jsframe_index = |
| 513 DebugFrameHelper::FindIndexedNonNativeFrame(&it, index); |
| 642 if (inlined_jsframe_index == -1) return heap->undefined_value(); | 514 if (inlined_jsframe_index == -1) return heap->undefined_value(); |
| 643 | 515 |
| 644 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate); | 516 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate); |
| 645 bool is_optimized = it.frame()->is_optimized(); | 517 bool is_optimized = it.frame()->is_optimized(); |
| 646 | 518 |
| 647 // Traverse the saved contexts chain to find the active context for the | 519 // Traverse the saved contexts chain to find the active context for the |
| 648 // selected frame. | 520 // selected frame. |
| 649 SaveContext* save = FindSavedContextForFrame(isolate, it.frame()); | 521 SaveContext* save = |
| 522 DebugFrameHelper::FindSavedContextForFrame(isolate, it.frame()); |
| 650 | 523 |
| 651 // Get the frame id. | 524 // Get the frame id. |
| 652 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate); | 525 Handle<Object> frame_id(DebugFrameHelper::WrapFrameId(it.frame()->id()), |
| 526 isolate); |
| 653 | 527 |
| 654 // Find source position in unoptimized code. | 528 // Find source position in unoptimized code. |
| 655 int position = frame_inspector.GetSourcePosition(); | 529 int position = frame_inspector.GetSourcePosition(); |
| 656 | 530 |
| 657 // Check for constructor frame. | 531 // Check for constructor frame. |
| 658 bool constructor = frame_inspector.IsConstructor(); | 532 bool constructor = frame_inspector.IsConstructor(); |
| 659 | 533 |
| 660 // Get scope info and read from it for local variable information. | 534 // Get scope info and read from it for local variable information. |
| 661 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); | 535 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); |
| 662 Handle<SharedFunctionInfo> shared(function->shared()); | 536 Handle<SharedFunctionInfo> shared(function->shared()); |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 859 } | 733 } |
| 860 } | 734 } |
| 861 } | 735 } |
| 862 details->set(kFrameDetailsReceiverIndex, *receiver); | 736 details->set(kFrameDetailsReceiverIndex, *receiver); |
| 863 | 737 |
| 864 DCHECK_EQ(details_size, details_index); | 738 DCHECK_EQ(details_size, details_index); |
| 865 return *isolate->factory()->NewJSArrayWithElements(details); | 739 return *isolate->factory()->NewJSArrayWithElements(details); |
| 866 } | 740 } |
| 867 | 741 |
| 868 | 742 |
| 869 static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info, | |
| 870 Handle<String> parameter_name) { | |
| 871 VariableMode mode; | |
| 872 VariableLocation location; | |
| 873 InitializationFlag init_flag; | |
| 874 MaybeAssignedFlag maybe_assigned_flag; | |
| 875 return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &location, | |
| 876 &init_flag, &maybe_assigned_flag) != -1; | |
| 877 } | |
| 878 | |
| 879 | |
| 880 static Handle<Context> MaterializeReceiver(Isolate* isolate, | |
| 881 Handle<Context> target, | |
| 882 Handle<JSFunction> function, | |
| 883 JavaScriptFrame* frame) { | |
| 884 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 885 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 886 Handle<Object> receiver; | |
| 887 switch (scope_info->scope_type()) { | |
| 888 case FUNCTION_SCOPE: { | |
| 889 VariableMode mode; | |
| 890 VariableLocation location; | |
| 891 InitializationFlag init_flag; | |
| 892 MaybeAssignedFlag maybe_assigned_flag; | |
| 893 | |
| 894 // Don't bother creating a fake context node if "this" is in the context | |
| 895 // already. | |
| 896 if (ScopeInfo::ContextSlotIndex( | |
| 897 scope_info, isolate->factory()->this_string(), &mode, &location, | |
| 898 &init_flag, &maybe_assigned_flag) >= 0) { | |
| 899 return target; | |
| 900 } | |
| 901 receiver = handle(frame->receiver(), isolate); | |
| 902 break; | |
| 903 } | |
| 904 case MODULE_SCOPE: | |
| 905 receiver = isolate->factory()->undefined_value(); | |
| 906 break; | |
| 907 case SCRIPT_SCOPE: | |
| 908 receiver = handle(function->global_proxy(), isolate); | |
| 909 break; | |
| 910 default: | |
| 911 // For eval code, arrow functions, and the like, there's no "this" binding | |
| 912 // to materialize. | |
| 913 return target; | |
| 914 } | |
| 915 | |
| 916 return isolate->factory()->NewCatchContext( | |
| 917 function, target, isolate->factory()->this_string(), receiver); | |
| 918 } | |
| 919 | |
| 920 | |
| 921 // Create a plain JSObject which materializes the local scope for the specified | |
| 922 // frame. | |
| 923 static void MaterializeStackLocalsWithFrameInspector( | |
| 924 Isolate* isolate, Handle<JSObject> target, Handle<ScopeInfo> scope_info, | |
| 925 FrameInspector* frame_inspector) { | |
| 926 // First fill all parameters. | |
| 927 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | |
| 928 // Do not materialize the parameter if it is shadowed by a context local. | |
| 929 Handle<String> name(scope_info->ParameterName(i)); | |
| 930 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; | |
| 931 | |
| 932 DCHECK_NOT_NULL(frame_inspector); | |
| 933 | |
| 934 HandleScope scope(isolate); | |
| 935 Handle<Object> value(i < frame_inspector->GetParametersCount() | |
| 936 ? frame_inspector->GetParameter(i) | |
| 937 : isolate->heap()->undefined_value(), | |
| 938 isolate); | |
| 939 DCHECK(!value->IsTheHole()); | |
| 940 | |
| 941 JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check(); | |
| 942 } | |
| 943 | |
| 944 // Second fill all stack locals. | |
| 945 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
| 946 if (scope_info->LocalIsSynthetic(i)) continue; | |
| 947 Handle<String> name(scope_info->StackLocalName(i)); | |
| 948 Handle<Object> value( | |
| 949 frame_inspector->GetExpression(scope_info->StackLocalIndex(i)), | |
| 950 isolate); | |
| 951 if (value->IsTheHole()) { | |
| 952 value = isolate->factory()->undefined_value(); | |
| 953 } | |
| 954 | |
| 955 JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check(); | |
| 956 } | |
| 957 } | |
| 958 | |
| 959 static void MaterializeStackLocalsWithFrameInspector( | |
| 960 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function, | |
| 961 FrameInspector* frame_inspector) { | |
| 962 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 963 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 964 | |
| 965 MaterializeStackLocalsWithFrameInspector(isolate, target, scope_info, | |
| 966 frame_inspector); | |
| 967 } | |
| 968 | |
| 969 | |
| 970 static void UpdateStackLocalsFromMaterializedObject( | |
| 971 Isolate* isolate, Handle<JSObject> target, Handle<ScopeInfo> scope_info, | |
| 972 JavaScriptFrame* frame, int inlined_jsframe_index) { | |
| 973 if (inlined_jsframe_index != 0 || frame->is_optimized()) { | |
| 974 // Optimized frames are not supported. Simply give up. | |
| 975 return; | |
| 976 } | |
| 977 | |
| 978 // Parameters. | |
| 979 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | |
| 980 // Shadowed parameters were not materialized. | |
| 981 Handle<String> name(scope_info->ParameterName(i)); | |
| 982 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; | |
| 983 | |
| 984 DCHECK(!frame->GetParameter(i)->IsTheHole()); | |
| 985 HandleScope scope(isolate); | |
| 986 Handle<Object> value = | |
| 987 Object::GetPropertyOrElement(target, name).ToHandleChecked(); | |
| 988 frame->SetParameterValue(i, *value); | |
| 989 } | |
| 990 | |
| 991 // Stack locals. | |
| 992 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
| 993 if (scope_info->LocalIsSynthetic(i)) continue; | |
| 994 int index = scope_info->StackLocalIndex(i); | |
| 995 if (frame->GetExpression(index)->IsTheHole()) continue; | |
| 996 HandleScope scope(isolate); | |
| 997 Handle<Object> value = Object::GetPropertyOrElement( | |
| 998 target, handle(scope_info->StackLocalName(i), | |
| 999 isolate)).ToHandleChecked(); | |
| 1000 frame->SetExpression(index, *value); | |
| 1001 } | |
| 1002 } | |
| 1003 | |
| 1004 | |
| 1005 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext( | |
| 1006 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function, | |
| 1007 Handle<Context> frame_context) { | |
| 1008 HandleScope scope(isolate); | |
| 1009 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 1010 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 1011 | |
| 1012 if (!scope_info->HasContext()) return target; | |
| 1013 | |
| 1014 // Third fill all context locals. | |
| 1015 Handle<Context> function_context(frame_context->declaration_context()); | |
| 1016 ScopeInfo::CopyContextLocalsToScopeObject(scope_info, function_context, | |
| 1017 target); | |
| 1018 | |
| 1019 // Finally copy any properties from the function context extension. | |
| 1020 // These will be variables introduced by eval. | |
| 1021 if (function_context->closure() == *function) { | |
| 1022 if (function_context->has_extension() && | |
| 1023 !function_context->IsNativeContext()) { | |
| 1024 Handle<JSObject> ext(JSObject::cast(function_context->extension())); | |
| 1025 Handle<FixedArray> keys; | |
| 1026 ASSIGN_RETURN_ON_EXCEPTION( | |
| 1027 isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), | |
| 1028 JSObject); | |
| 1029 | |
| 1030 for (int i = 0; i < keys->length(); i++) { | |
| 1031 // Names of variables introduced by eval are strings. | |
| 1032 DCHECK(keys->get(i)->IsString()); | |
| 1033 Handle<String> key(String::cast(keys->get(i))); | |
| 1034 Handle<Object> value; | |
| 1035 ASSIGN_RETURN_ON_EXCEPTION( | |
| 1036 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject); | |
| 1037 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty( | |
| 1038 isolate, target, key, value, SLOPPY), | |
| 1039 JSObject); | |
| 1040 } | |
| 1041 } | |
| 1042 } | |
| 1043 | |
| 1044 return target; | |
| 1045 } | |
| 1046 | |
| 1047 | |
| 1048 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScriptScope( | |
| 1049 Handle<GlobalObject> global) { | |
| 1050 Isolate* isolate = global->GetIsolate(); | |
| 1051 Handle<ScriptContextTable> script_contexts( | |
| 1052 global->native_context()->script_context_table()); | |
| 1053 | |
| 1054 Handle<JSObject> script_scope = | |
| 1055 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 1056 | |
| 1057 for (int context_index = 0; context_index < script_contexts->used(); | |
| 1058 context_index++) { | |
| 1059 Handle<Context> context = | |
| 1060 ScriptContextTable::GetContext(script_contexts, context_index); | |
| 1061 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); | |
| 1062 ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, | |
| 1063 script_scope); | |
| 1064 } | |
| 1065 return script_scope; | |
| 1066 } | |
| 1067 | |
| 1068 | |
| 1069 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope( | |
| 1070 Isolate* isolate, FrameInspector* frame_inspector) { | |
| 1071 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction())); | |
| 1072 | |
| 1073 Handle<JSObject> local_scope = | |
| 1074 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 1075 MaterializeStackLocalsWithFrameInspector(isolate, local_scope, function, | |
| 1076 frame_inspector); | |
| 1077 | |
| 1078 Handle<Context> frame_context(Context::cast(frame_inspector->GetContext())); | |
| 1079 | |
| 1080 return MaterializeLocalContext(isolate, local_scope, function, frame_context); | |
| 1081 } | |
| 1082 | |
| 1083 | |
| 1084 // Set the context local variable value. | |
| 1085 static bool SetContextLocalValue(Isolate* isolate, Handle<ScopeInfo> scope_info, | |
| 1086 Handle<Context> context, | |
| 1087 Handle<String> variable_name, | |
| 1088 Handle<Object> new_value) { | |
| 1089 for (int i = 0; i < scope_info->ContextLocalCount(); i++) { | |
| 1090 Handle<String> next_name(scope_info->ContextLocalName(i)); | |
| 1091 if (String::Equals(variable_name, next_name)) { | |
| 1092 VariableMode mode; | |
| 1093 VariableLocation location; | |
| 1094 InitializationFlag init_flag; | |
| 1095 MaybeAssignedFlag maybe_assigned_flag; | |
| 1096 int context_index = | |
| 1097 ScopeInfo::ContextSlotIndex(scope_info, next_name, &mode, &location, | |
| 1098 &init_flag, &maybe_assigned_flag); | |
| 1099 context->set(context_index, *new_value); | |
| 1100 return true; | |
| 1101 } | |
| 1102 } | |
| 1103 | |
| 1104 return false; | |
| 1105 } | |
| 1106 | |
| 1107 | |
| 1108 static bool SetLocalVariableValue(Isolate* isolate, JavaScriptFrame* frame, | |
| 1109 Handle<String> variable_name, | |
| 1110 Handle<Object> new_value) { | |
| 1111 // Optimized frames are not supported. | |
| 1112 if (frame->is_optimized()) return false; | |
| 1113 | |
| 1114 Handle<JSFunction> function(frame->function()); | |
| 1115 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 1116 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 1117 | |
| 1118 bool default_result = false; | |
| 1119 | |
| 1120 // Parameters. | |
| 1121 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | |
| 1122 HandleScope scope(isolate); | |
| 1123 if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) { | |
| 1124 frame->SetParameterValue(i, *new_value); | |
| 1125 // Argument might be shadowed in heap context, don't stop here. | |
| 1126 default_result = true; | |
| 1127 } | |
| 1128 } | |
| 1129 | |
| 1130 // Stack locals. | |
| 1131 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
| 1132 HandleScope scope(isolate); | |
| 1133 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) { | |
| 1134 frame->SetExpression(scope_info->StackLocalIndex(i), *new_value); | |
| 1135 return true; | |
| 1136 } | |
| 1137 } | |
| 1138 | |
| 1139 if (scope_info->HasContext()) { | |
| 1140 // Context locals. | |
| 1141 Handle<Context> frame_context(Context::cast(frame->context())); | |
| 1142 Handle<Context> function_context(frame_context->declaration_context()); | |
| 1143 if (SetContextLocalValue(isolate, scope_info, function_context, | |
| 1144 variable_name, new_value)) { | |
| 1145 return true; | |
| 1146 } | |
| 1147 | |
| 1148 // Function context extension. These are variables introduced by eval. | |
| 1149 if (function_context->closure() == *function) { | |
| 1150 if (function_context->has_extension() && | |
| 1151 !function_context->IsNativeContext()) { | |
| 1152 Handle<JSObject> ext(JSObject::cast(function_context->extension())); | |
| 1153 | |
| 1154 Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name); | |
| 1155 DCHECK(maybe.IsJust()); | |
| 1156 if (maybe.FromJust()) { | |
| 1157 // We don't expect this to do anything except replacing | |
| 1158 // property value. | |
| 1159 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value, | |
| 1160 SLOPPY).Assert(); | |
| 1161 return true; | |
| 1162 } | |
| 1163 } | |
| 1164 } | |
| 1165 } | |
| 1166 | |
| 1167 return default_result; | |
| 1168 } | |
| 1169 | |
| 1170 | |
| 1171 static bool SetBlockVariableValue(Isolate* isolate, | |
| 1172 Handle<Context> block_context, | |
| 1173 Handle<ScopeInfo> scope_info, | |
| 1174 JavaScriptFrame* frame, | |
| 1175 Handle<String> variable_name, | |
| 1176 Handle<Object> new_value) { | |
| 1177 if (frame != nullptr) { | |
| 1178 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
| 1179 HandleScope scope(isolate); | |
| 1180 if (String::Equals(handle(scope_info->StackLocalName(i)), | |
| 1181 variable_name)) { | |
| 1182 frame->SetExpression(scope_info->StackLocalIndex(i), *new_value); | |
| 1183 return true; | |
| 1184 } | |
| 1185 } | |
| 1186 } | |
| 1187 if (!block_context.is_null()) { | |
| 1188 return SetContextLocalValue(block_context->GetIsolate(), scope_info, | |
| 1189 block_context, variable_name, new_value); | |
| 1190 } | |
| 1191 return false; | |
| 1192 } | |
| 1193 | |
| 1194 | |
| 1195 // Create a plain JSObject which materializes the closure content for the | |
| 1196 // context. | |
| 1197 static Handle<JSObject> MaterializeClosure(Isolate* isolate, | |
| 1198 Handle<Context> context) { | |
| 1199 DCHECK(context->IsFunctionContext()); | |
| 1200 | |
| 1201 Handle<SharedFunctionInfo> shared(context->closure()->shared()); | |
| 1202 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 1203 | |
| 1204 // Allocate and initialize a JSObject with all the content of this function | |
| 1205 // closure. | |
| 1206 Handle<JSObject> closure_scope = | |
| 1207 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 1208 | |
| 1209 // Fill all context locals to the context extension. | |
| 1210 ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, closure_scope); | |
| 1211 | |
| 1212 // Finally copy any properties from the function context extension. This will | |
| 1213 // be variables introduced by eval. | |
| 1214 if (context->has_extension()) { | |
| 1215 Handle<JSObject> ext(JSObject::cast(context->extension())); | |
| 1216 DCHECK(ext->IsJSContextExtensionObject()); | |
| 1217 Handle<FixedArray> keys = | |
| 1218 JSReceiver::GetKeys(ext, JSReceiver::OWN_ONLY).ToHandleChecked(); | |
| 1219 | |
| 1220 for (int i = 0; i < keys->length(); i++) { | |
| 1221 HandleScope scope(isolate); | |
| 1222 // Names of variables introduced by eval are strings. | |
| 1223 DCHECK(keys->get(i)->IsString()); | |
| 1224 Handle<String> key(String::cast(keys->get(i))); | |
| 1225 Handle<Object> value = Object::GetProperty(ext, key).ToHandleChecked(); | |
| 1226 JSObject::SetOwnPropertyIgnoreAttributes(closure_scope, key, value, NONE) | |
| 1227 .Check(); | |
| 1228 } | |
| 1229 } | |
| 1230 | |
| 1231 return closure_scope; | |
| 1232 } | |
| 1233 | |
| 1234 | |
| 1235 // This method copies structure of MaterializeClosure method above. | |
| 1236 static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> context, | |
| 1237 Handle<String> variable_name, | |
| 1238 Handle<Object> new_value) { | |
| 1239 DCHECK(context->IsFunctionContext()); | |
| 1240 | |
| 1241 Handle<SharedFunctionInfo> shared(context->closure()->shared()); | |
| 1242 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 1243 | |
| 1244 // Context locals to the context extension. | |
| 1245 if (SetContextLocalValue(isolate, scope_info, context, variable_name, | |
| 1246 new_value)) { | |
| 1247 return true; | |
| 1248 } | |
| 1249 | |
| 1250 // Properties from the function context extension. This will | |
| 1251 // be variables introduced by eval. | |
| 1252 if (context->has_extension()) { | |
| 1253 Handle<JSObject> ext(JSObject::cast(context->extension())); | |
| 1254 DCHECK(ext->IsJSContextExtensionObject()); | |
| 1255 Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name); | |
| 1256 DCHECK(maybe.IsJust()); | |
| 1257 if (maybe.FromJust()) { | |
| 1258 // We don't expect this to do anything except replacing property value. | |
| 1259 JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value, | |
| 1260 NONE).Check(); | |
| 1261 return true; | |
| 1262 } | |
| 1263 } | |
| 1264 | |
| 1265 return false; | |
| 1266 } | |
| 1267 | |
| 1268 | |
| 1269 static bool SetScriptVariableValue(Handle<Context> context, | |
| 1270 Handle<String> variable_name, | |
| 1271 Handle<Object> new_value) { | |
| 1272 Handle<ScriptContextTable> script_contexts( | |
| 1273 context->global_object()->native_context()->script_context_table()); | |
| 1274 ScriptContextTable::LookupResult lookup_result; | |
| 1275 if (ScriptContextTable::Lookup(script_contexts, variable_name, | |
| 1276 &lookup_result)) { | |
| 1277 Handle<Context> script_context = ScriptContextTable::GetContext( | |
| 1278 script_contexts, lookup_result.context_index); | |
| 1279 script_context->set(lookup_result.slot_index, *new_value); | |
| 1280 return true; | |
| 1281 } | |
| 1282 | |
| 1283 return false; | |
| 1284 } | |
| 1285 | |
| 1286 | |
| 1287 // Create a plain JSObject which materializes the scope for the specified | |
| 1288 // catch context. | |
| 1289 static Handle<JSObject> MaterializeCatchScope(Isolate* isolate, | |
| 1290 Handle<Context> context) { | |
| 1291 DCHECK(context->IsCatchContext()); | |
| 1292 Handle<String> name(String::cast(context->extension())); | |
| 1293 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX), | |
| 1294 isolate); | |
| 1295 Handle<JSObject> catch_scope = | |
| 1296 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 1297 JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object, | |
| 1298 NONE).Check(); | |
| 1299 return catch_scope; | |
| 1300 } | |
| 1301 | |
| 1302 | |
| 1303 static bool SetCatchVariableValue(Isolate* isolate, Handle<Context> context, | |
| 1304 Handle<String> variable_name, | |
| 1305 Handle<Object> new_value) { | |
| 1306 DCHECK(context->IsCatchContext()); | |
| 1307 Handle<String> name(String::cast(context->extension())); | |
| 1308 if (!String::Equals(name, variable_name)) { | |
| 1309 return false; | |
| 1310 } | |
| 1311 context->set(Context::THROWN_OBJECT_INDEX, *new_value); | |
| 1312 return true; | |
| 1313 } | |
| 1314 | |
| 1315 | |
| 1316 // Create a plain JSObject which materializes the block scope for the specified | |
| 1317 // block context. | |
| 1318 static Handle<JSObject> MaterializeBlockScope(Isolate* isolate, | |
| 1319 Handle<ScopeInfo> scope_info, | |
| 1320 Handle<Context> context, | |
| 1321 FrameInspector* frame_inspector) { | |
| 1322 Handle<JSObject> block_scope = | |
| 1323 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 1324 | |
| 1325 if (frame_inspector != nullptr) { | |
| 1326 MaterializeStackLocalsWithFrameInspector(isolate, block_scope, scope_info, | |
| 1327 frame_inspector); | |
| 1328 } | |
| 1329 | |
| 1330 if (!context.is_null()) { | |
| 1331 Handle<ScopeInfo> scope_info_from_context( | |
| 1332 ScopeInfo::cast(context->extension())); | |
| 1333 // Fill all context locals. | |
| 1334 ScopeInfo::CopyContextLocalsToScopeObject(scope_info_from_context, context, | |
| 1335 block_scope); | |
| 1336 } | |
| 1337 | |
| 1338 return block_scope; | |
| 1339 } | |
| 1340 | |
| 1341 | |
| 1342 // Create a plain JSObject which materializes the module scope for the specified | |
| 1343 // module context. | |
| 1344 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope( | |
| 1345 Isolate* isolate, Handle<Context> context) { | |
| 1346 DCHECK(context->IsModuleContext()); | |
| 1347 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); | |
| 1348 | |
| 1349 // Allocate and initialize a JSObject with all the members of the debugged | |
| 1350 // module. | |
| 1351 Handle<JSObject> module_scope = | |
| 1352 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 1353 | |
| 1354 // Fill all context locals. | |
| 1355 ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, module_scope); | |
| 1356 | |
| 1357 return module_scope; | |
| 1358 } | |
| 1359 | |
| 1360 | |
| 1361 // Iterate over the actual scopes visible from a stack frame or from a closure. | |
| 1362 // The iteration proceeds from the innermost visible nested scope outwards. | |
| 1363 // All scopes are backed by an actual context except the local scope, | |
| 1364 // which is inserted "artificially" in the context chain. | |
| 1365 class ScopeIterator { | |
| 1366 public: | |
| 1367 enum ScopeType { | |
| 1368 ScopeTypeGlobal = 0, | |
| 1369 ScopeTypeLocal, | |
| 1370 ScopeTypeWith, | |
| 1371 ScopeTypeClosure, | |
| 1372 ScopeTypeCatch, | |
| 1373 ScopeTypeBlock, | |
| 1374 ScopeTypeScript, | |
| 1375 ScopeTypeModule | |
| 1376 }; | |
| 1377 | |
| 1378 ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, | |
| 1379 bool ignore_nested_scopes = false) | |
| 1380 : isolate_(isolate), | |
| 1381 frame_inspector_(frame_inspector), | |
| 1382 nested_scope_chain_(4), | |
| 1383 seen_script_scope_(false), | |
| 1384 failed_(false) { | |
| 1385 if (!frame_inspector->GetContext()->IsContext() || | |
| 1386 !frame_inspector->GetFunction()->IsJSFunction()) { | |
| 1387 // Optimized frame, context or function cannot be materialized. Give up. | |
| 1388 return; | |
| 1389 } | |
| 1390 | |
| 1391 context_ = Handle<Context>(Context::cast(frame_inspector->GetContext())); | |
| 1392 | |
| 1393 // Catch the case when the debugger stops in an internal function. | |
| 1394 Handle<SharedFunctionInfo> shared_info(function()->shared()); | |
| 1395 Handle<ScopeInfo> scope_info(shared_info->scope_info()); | |
| 1396 if (shared_info->script() == isolate->heap()->undefined_value()) { | |
| 1397 while (context_->closure() == function()) { | |
| 1398 context_ = Handle<Context>(context_->previous(), isolate_); | |
| 1399 } | |
| 1400 return; | |
| 1401 } | |
| 1402 | |
| 1403 // Currently it takes too much time to find nested scopes due to script | |
| 1404 // parsing. Sometimes we want to run the ScopeIterator as fast as possible | |
| 1405 // (for example, while collecting async call stacks on every | |
| 1406 // addEventListener call), even if we drop some nested scopes. | |
| 1407 // Later we may optimize getting the nested scopes (cache the result?) | |
| 1408 // and include nested scopes into the "fast" iteration case as well. | |
| 1409 | |
| 1410 if (!ignore_nested_scopes && shared_info->HasDebugInfo()) { | |
| 1411 // The source position at return is always the end of the function, | |
| 1412 // which is not consistent with the current scope chain. Therefore all | |
| 1413 // nested with, catch and block contexts are skipped, and we can only | |
| 1414 // inspect the function scope. | |
| 1415 // This can only happen if we set a break point inside right before the | |
| 1416 // return, which requires a debug info to be available. | |
| 1417 Handle<DebugInfo> debug_info(shared_info->GetDebugInfo()); | |
| 1418 | |
| 1419 // PC points to the instruction after the current one, possibly a break | |
| 1420 // location as well. So the "- 1" to exclude it from the search. | |
| 1421 Address call_pc = frame()->pc() - 1; | |
| 1422 | |
| 1423 // Find the break point where execution has stopped. | |
| 1424 BreakLocation location = | |
| 1425 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); | |
| 1426 | |
| 1427 ignore_nested_scopes = location.IsReturn(); | |
| 1428 } | |
| 1429 | |
| 1430 if (ignore_nested_scopes) { | |
| 1431 if (scope_info->HasContext()) { | |
| 1432 context_ = Handle<Context>(context_->declaration_context(), isolate_); | |
| 1433 } else { | |
| 1434 while (context_->closure() == function()) { | |
| 1435 context_ = Handle<Context>(context_->previous(), isolate_); | |
| 1436 } | |
| 1437 } | |
| 1438 if (scope_info->scope_type() == FUNCTION_SCOPE || | |
| 1439 scope_info->scope_type() == ARROW_SCOPE) { | |
| 1440 nested_scope_chain_.Add(scope_info); | |
| 1441 } | |
| 1442 } else { | |
| 1443 // Reparse the code and analyze the scopes. | |
| 1444 Handle<Script> script(Script::cast(shared_info->script())); | |
| 1445 Scope* scope = NULL; | |
| 1446 | |
| 1447 // Check whether we are in global, eval or function code. | |
| 1448 Handle<ScopeInfo> scope_info(shared_info->scope_info()); | |
| 1449 Zone zone; | |
| 1450 if (scope_info->scope_type() != FUNCTION_SCOPE && | |
| 1451 scope_info->scope_type() != ARROW_SCOPE) { | |
| 1452 // Global or eval code. | |
| 1453 ParseInfo info(&zone, script); | |
| 1454 if (scope_info->scope_type() == SCRIPT_SCOPE) { | |
| 1455 info.set_global(); | |
| 1456 } else { | |
| 1457 DCHECK(scope_info->scope_type() == EVAL_SCOPE); | |
| 1458 info.set_eval(); | |
| 1459 info.set_context(Handle<Context>(function()->context())); | |
| 1460 } | |
| 1461 if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) { | |
| 1462 scope = info.function()->scope(); | |
| 1463 } | |
| 1464 RetrieveScopeChain(scope, shared_info); | |
| 1465 } else { | |
| 1466 // Function code | |
| 1467 ParseInfo info(&zone, Handle<JSFunction>(function())); | |
| 1468 if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) { | |
| 1469 scope = info.function()->scope(); | |
| 1470 } | |
| 1471 RetrieveScopeChain(scope, shared_info); | |
| 1472 } | |
| 1473 } | |
| 1474 } | |
| 1475 | |
| 1476 ScopeIterator(Isolate* isolate, Handle<JSFunction> function) | |
| 1477 : isolate_(isolate), | |
| 1478 frame_inspector_(NULL), | |
| 1479 context_(function->context()), | |
| 1480 seen_script_scope_(false), | |
| 1481 failed_(false) { | |
| 1482 if (function->IsBuiltin()) context_ = Handle<Context>(); | |
| 1483 } | |
| 1484 | |
| 1485 // More scopes? | |
| 1486 bool Done() { | |
| 1487 DCHECK(!failed_); | |
| 1488 return context_.is_null(); | |
| 1489 } | |
| 1490 | |
| 1491 bool Failed() { return failed_; } | |
| 1492 | |
| 1493 // Move to the next scope. | |
| 1494 void Next() { | |
| 1495 DCHECK(!failed_); | |
| 1496 ScopeType scope_type = Type(); | |
| 1497 if (scope_type == ScopeTypeGlobal) { | |
| 1498 // The global scope is always the last in the chain. | |
| 1499 DCHECK(context_->IsNativeContext()); | |
| 1500 context_ = Handle<Context>(); | |
| 1501 return; | |
| 1502 } | |
| 1503 if (scope_type == ScopeTypeScript) { | |
| 1504 seen_script_scope_ = true; | |
| 1505 if (context_->IsScriptContext()) { | |
| 1506 context_ = Handle<Context>(context_->previous(), isolate_); | |
| 1507 } | |
| 1508 if (!nested_scope_chain_.is_empty()) { | |
| 1509 DCHECK_EQ(nested_scope_chain_.last()->scope_type(), SCRIPT_SCOPE); | |
| 1510 nested_scope_chain_.RemoveLast(); | |
| 1511 DCHECK(nested_scope_chain_.is_empty()); | |
| 1512 } | |
| 1513 CHECK(context_->IsNativeContext()); | |
| 1514 return; | |
| 1515 } | |
| 1516 if (nested_scope_chain_.is_empty()) { | |
| 1517 context_ = Handle<Context>(context_->previous(), isolate_); | |
| 1518 } else { | |
| 1519 if (nested_scope_chain_.last()->HasContext()) { | |
| 1520 DCHECK(context_->previous() != NULL); | |
| 1521 context_ = Handle<Context>(context_->previous(), isolate_); | |
| 1522 } | |
| 1523 nested_scope_chain_.RemoveLast(); | |
| 1524 } | |
| 1525 } | |
| 1526 | |
| 1527 // Return the type of the current scope. | |
| 1528 ScopeType Type() { | |
| 1529 DCHECK(!failed_); | |
| 1530 if (!nested_scope_chain_.is_empty()) { | |
| 1531 Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); | |
| 1532 switch (scope_info->scope_type()) { | |
| 1533 case FUNCTION_SCOPE: | |
| 1534 case ARROW_SCOPE: | |
| 1535 DCHECK(context_->IsFunctionContext() || !scope_info->HasContext()); | |
| 1536 return ScopeTypeLocal; | |
| 1537 case MODULE_SCOPE: | |
| 1538 DCHECK(context_->IsModuleContext()); | |
| 1539 return ScopeTypeModule; | |
| 1540 case SCRIPT_SCOPE: | |
| 1541 DCHECK(context_->IsScriptContext() || context_->IsNativeContext()); | |
| 1542 return ScopeTypeScript; | |
| 1543 case WITH_SCOPE: | |
| 1544 DCHECK(context_->IsWithContext()); | |
| 1545 return ScopeTypeWith; | |
| 1546 case CATCH_SCOPE: | |
| 1547 DCHECK(context_->IsCatchContext()); | |
| 1548 return ScopeTypeCatch; | |
| 1549 case BLOCK_SCOPE: | |
| 1550 DCHECK(!scope_info->HasContext() || context_->IsBlockContext()); | |
| 1551 return ScopeTypeBlock; | |
| 1552 case EVAL_SCOPE: | |
| 1553 UNREACHABLE(); | |
| 1554 } | |
| 1555 } | |
| 1556 if (context_->IsNativeContext()) { | |
| 1557 DCHECK(context_->global_object()->IsGlobalObject()); | |
| 1558 // If we are at the native context and have not yet seen script scope, | |
| 1559 // fake it. | |
| 1560 return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript; | |
| 1561 } | |
| 1562 if (context_->IsFunctionContext()) { | |
| 1563 return ScopeTypeClosure; | |
| 1564 } | |
| 1565 if (context_->IsCatchContext()) { | |
| 1566 return ScopeTypeCatch; | |
| 1567 } | |
| 1568 if (context_->IsBlockContext()) { | |
| 1569 return ScopeTypeBlock; | |
| 1570 } | |
| 1571 if (context_->IsModuleContext()) { | |
| 1572 return ScopeTypeModule; | |
| 1573 } | |
| 1574 if (context_->IsScriptContext()) { | |
| 1575 return ScopeTypeScript; | |
| 1576 } | |
| 1577 DCHECK(context_->IsWithContext()); | |
| 1578 return ScopeTypeWith; | |
| 1579 } | |
| 1580 | |
| 1581 // Return the JavaScript object with the content of the current scope. | |
| 1582 MaybeHandle<JSObject> ScopeObject() { | |
| 1583 DCHECK(!failed_); | |
| 1584 switch (Type()) { | |
| 1585 case ScopeIterator::ScopeTypeGlobal: | |
| 1586 return Handle<JSObject>(CurrentContext()->global_object()); | |
| 1587 case ScopeIterator::ScopeTypeScript: | |
| 1588 return MaterializeScriptScope( | |
| 1589 Handle<GlobalObject>(CurrentContext()->global_object())); | |
| 1590 case ScopeIterator::ScopeTypeLocal: | |
| 1591 // Materialize the content of the local scope into a JSObject. | |
| 1592 DCHECK(nested_scope_chain_.length() == 1); | |
| 1593 return MaterializeLocalScope(isolate_, frame_inspector_); | |
| 1594 case ScopeIterator::ScopeTypeWith: | |
| 1595 // Return the with object. | |
| 1596 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); | |
| 1597 case ScopeIterator::ScopeTypeCatch: | |
| 1598 return MaterializeCatchScope(isolate_, CurrentContext()); | |
| 1599 case ScopeIterator::ScopeTypeClosure: | |
| 1600 // Materialize the content of the closure scope into a JSObject. | |
| 1601 return MaterializeClosure(isolate_, CurrentContext()); | |
| 1602 case ScopeIterator::ScopeTypeBlock: { | |
| 1603 if (!nested_scope_chain_.is_empty()) { | |
| 1604 // this is a block scope on the stack. | |
| 1605 Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); | |
| 1606 Handle<Context> context = scope_info->HasContext() | |
| 1607 ? CurrentContext() | |
| 1608 : Handle<Context>::null(); | |
| 1609 return MaterializeBlockScope(isolate_, scope_info, context, | |
| 1610 frame_inspector_); | |
| 1611 } else { | |
| 1612 return MaterializeBlockScope(isolate_, Handle<ScopeInfo>::null(), | |
| 1613 CurrentContext(), nullptr); | |
| 1614 } | |
| 1615 } | |
| 1616 case ScopeIterator::ScopeTypeModule: | |
| 1617 return MaterializeModuleScope(isolate_, CurrentContext()); | |
| 1618 } | |
| 1619 UNREACHABLE(); | |
| 1620 return Handle<JSObject>(); | |
| 1621 } | |
| 1622 | |
| 1623 bool HasContext() { | |
| 1624 ScopeType type = Type(); | |
| 1625 if (type == ScopeTypeBlock || type == ScopeTypeLocal) { | |
| 1626 if (!nested_scope_chain_.is_empty()) { | |
| 1627 return nested_scope_chain_.last()->HasContext(); | |
| 1628 } | |
| 1629 } | |
| 1630 return true; | |
| 1631 } | |
| 1632 | |
| 1633 bool SetVariableValue(Handle<String> variable_name, | |
| 1634 Handle<Object> new_value) { | |
| 1635 DCHECK(!failed_); | |
| 1636 switch (Type()) { | |
| 1637 case ScopeIterator::ScopeTypeGlobal: | |
| 1638 break; | |
| 1639 case ScopeIterator::ScopeTypeLocal: | |
| 1640 return SetLocalVariableValue(isolate_, frame(), variable_name, | |
| 1641 new_value); | |
| 1642 case ScopeIterator::ScopeTypeWith: | |
| 1643 break; | |
| 1644 case ScopeIterator::ScopeTypeCatch: | |
| 1645 return SetCatchVariableValue(isolate_, CurrentContext(), variable_name, | |
| 1646 new_value); | |
| 1647 case ScopeIterator::ScopeTypeClosure: | |
| 1648 return SetClosureVariableValue(isolate_, CurrentContext(), | |
| 1649 variable_name, new_value); | |
| 1650 case ScopeIterator::ScopeTypeScript: | |
| 1651 return SetScriptVariableValue(CurrentContext(), variable_name, | |
| 1652 new_value); | |
| 1653 case ScopeIterator::ScopeTypeBlock: | |
| 1654 return SetBlockVariableValue( | |
| 1655 isolate_, HasContext() ? CurrentContext() : Handle<Context>::null(), | |
| 1656 CurrentScopeInfo(), frame(), variable_name, new_value); | |
| 1657 case ScopeIterator::ScopeTypeModule: | |
| 1658 // TODO(2399): should we implement it? | |
| 1659 break; | |
| 1660 } | |
| 1661 return false; | |
| 1662 } | |
| 1663 | |
| 1664 Handle<ScopeInfo> CurrentScopeInfo() { | |
| 1665 DCHECK(!failed_); | |
| 1666 if (!nested_scope_chain_.is_empty()) { | |
| 1667 return nested_scope_chain_.last(); | |
| 1668 } else if (context_->IsBlockContext()) { | |
| 1669 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension())); | |
| 1670 } else if (context_->IsFunctionContext()) { | |
| 1671 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info()); | |
| 1672 } | |
| 1673 return Handle<ScopeInfo>::null(); | |
| 1674 } | |
| 1675 | |
| 1676 // Return the context for this scope. For the local context there might not | |
| 1677 // be an actual context. | |
| 1678 Handle<Context> CurrentContext() { | |
| 1679 DCHECK(!failed_); | |
| 1680 if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript || | |
| 1681 nested_scope_chain_.is_empty()) { | |
| 1682 return context_; | |
| 1683 } else if (nested_scope_chain_.last()->HasContext()) { | |
| 1684 return context_; | |
| 1685 } else { | |
| 1686 return Handle<Context>(); | |
| 1687 } | |
| 1688 } | |
| 1689 | |
| 1690 #ifdef DEBUG | |
| 1691 // Debug print of the content of the current scope. | |
| 1692 void DebugPrint() { | |
| 1693 OFStream os(stdout); | |
| 1694 DCHECK(!failed_); | |
| 1695 switch (Type()) { | |
| 1696 case ScopeIterator::ScopeTypeGlobal: | |
| 1697 os << "Global:\n"; | |
| 1698 CurrentContext()->Print(os); | |
| 1699 break; | |
| 1700 | |
| 1701 case ScopeIterator::ScopeTypeLocal: { | |
| 1702 os << "Local:\n"; | |
| 1703 function()->shared()->scope_info()->Print(); | |
| 1704 if (!CurrentContext().is_null()) { | |
| 1705 CurrentContext()->Print(os); | |
| 1706 if (CurrentContext()->has_extension()) { | |
| 1707 Handle<Object> extension(CurrentContext()->extension(), isolate_); | |
| 1708 if (extension->IsJSContextExtensionObject()) { | |
| 1709 extension->Print(os); | |
| 1710 } | |
| 1711 } | |
| 1712 } | |
| 1713 break; | |
| 1714 } | |
| 1715 | |
| 1716 case ScopeIterator::ScopeTypeWith: | |
| 1717 os << "With:\n"; | |
| 1718 CurrentContext()->extension()->Print(os); | |
| 1719 break; | |
| 1720 | |
| 1721 case ScopeIterator::ScopeTypeCatch: | |
| 1722 os << "Catch:\n"; | |
| 1723 CurrentContext()->extension()->Print(os); | |
| 1724 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os); | |
| 1725 break; | |
| 1726 | |
| 1727 case ScopeIterator::ScopeTypeClosure: | |
| 1728 os << "Closure:\n"; | |
| 1729 CurrentContext()->Print(os); | |
| 1730 if (CurrentContext()->has_extension()) { | |
| 1731 Handle<Object> extension(CurrentContext()->extension(), isolate_); | |
| 1732 if (extension->IsJSContextExtensionObject()) { | |
| 1733 extension->Print(os); | |
| 1734 } | |
| 1735 } | |
| 1736 break; | |
| 1737 | |
| 1738 case ScopeIterator::ScopeTypeScript: | |
| 1739 os << "Script:\n"; | |
| 1740 CurrentContext() | |
| 1741 ->global_object() | |
| 1742 ->native_context() | |
| 1743 ->script_context_table() | |
| 1744 ->Print(os); | |
| 1745 break; | |
| 1746 | |
| 1747 default: | |
| 1748 UNREACHABLE(); | |
| 1749 } | |
| 1750 PrintF("\n"); | |
| 1751 } | |
| 1752 #endif | |
| 1753 | |
| 1754 private: | |
| 1755 Isolate* isolate_; | |
| 1756 FrameInspector* const frame_inspector_; | |
| 1757 Handle<Context> context_; | |
| 1758 List<Handle<ScopeInfo> > nested_scope_chain_; | |
| 1759 bool seen_script_scope_; | |
| 1760 bool failed_; | |
| 1761 | |
| 1762 inline JavaScriptFrame* frame() { | |
| 1763 return frame_inspector_->GetArgumentsFrame(); | |
| 1764 } | |
| 1765 | |
| 1766 inline JSFunction* function() { | |
| 1767 return JSFunction::cast(frame_inspector_->GetFunction()); | |
| 1768 } | |
| 1769 | |
| 1770 void RetrieveScopeChain(Scope* scope, | |
| 1771 Handle<SharedFunctionInfo> shared_info) { | |
| 1772 if (scope != NULL) { | |
| 1773 int source_position = frame_inspector_->GetSourcePosition(); | |
| 1774 scope->GetNestedScopeChain(isolate_, &nested_scope_chain_, | |
| 1775 source_position); | |
| 1776 } else { | |
| 1777 // A failed reparse indicates that the preparser has diverged from the | |
| 1778 // parser or that the preparse data given to the initial parse has been | |
| 1779 // faulty. We fail in debug mode but in release mode we only provide the | |
| 1780 // information we get from the context chain but nothing about | |
| 1781 // completely stack allocated scopes or stack allocated locals. | |
| 1782 // Or it could be due to stack overflow. | |
| 1783 DCHECK(isolate_->has_pending_exception()); | |
| 1784 failed_ = true; | |
| 1785 } | |
| 1786 } | |
| 1787 | |
| 1788 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); | |
| 1789 }; | |
| 1790 | |
| 1791 | |
| 1792 RUNTIME_FUNCTION(Runtime_GetScopeCount) { | 743 RUNTIME_FUNCTION(Runtime_GetScopeCount) { |
| 1793 HandleScope scope(isolate); | 744 HandleScope scope(isolate); |
| 1794 DCHECK(args.length() == 2); | 745 DCHECK(args.length() == 2); |
| 1795 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | 746 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); |
| 1796 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); | 747 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); |
| 1797 | 748 |
| 1798 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | 749 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); |
| 1799 | 750 |
| 1800 // Get the frame where the debugging is performed. | 751 // Get the frame where the debugging is performed. |
| 1801 StackFrame::Id id = UnwrapFrameId(wrapped_id); | 752 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); |
| 1802 JavaScriptFrameIterator it(isolate, id); | 753 JavaScriptFrameIterator it(isolate, id); |
| 1803 JavaScriptFrame* frame = it.frame(); | 754 JavaScriptFrame* frame = it.frame(); |
| 1804 FrameInspector frame_inspector(frame, 0, isolate); | 755 FrameInspector frame_inspector(frame, 0, isolate); |
| 1805 | 756 |
| 1806 // Count the visible scopes. | 757 // Count the visible scopes. |
| 1807 int n = 0; | 758 int n = 0; |
| 1808 for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) { | 759 for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) { |
| 1809 n++; | 760 n++; |
| 1810 } | 761 } |
| 1811 | 762 |
| 1812 return Smi::FromInt(n); | 763 return Smi::FromInt(n); |
| 1813 } | 764 } |
| 1814 | 765 |
| 1815 | 766 |
| 1816 // Returns the list of step-in positions (text offset) in a function of the | 767 // Returns the list of step-in positions (text offset) in a function of the |
| 1817 // stack frame in a range from the current debug break position to the end | 768 // stack frame in a range from the current debug break position to the end |
| 1818 // of the corresponding statement. | 769 // of the corresponding statement. |
| 1819 RUNTIME_FUNCTION(Runtime_GetStepInPositions) { | 770 RUNTIME_FUNCTION(Runtime_GetStepInPositions) { |
| 1820 HandleScope scope(isolate); | 771 HandleScope scope(isolate); |
| 1821 DCHECK(args.length() == 2); | 772 DCHECK(args.length() == 2); |
| 1822 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | 773 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); |
| 1823 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); | 774 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); |
| 1824 | 775 |
| 1825 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | 776 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); |
| 1826 | 777 |
| 1827 // Get the frame where the debugging is performed. | 778 // Get the frame where the debugging is performed. |
| 1828 StackFrame::Id id = UnwrapFrameId(wrapped_id); | 779 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); |
| 1829 JavaScriptFrameIterator frame_it(isolate, id); | 780 JavaScriptFrameIterator frame_it(isolate, id); |
| 1830 RUNTIME_ASSERT(!frame_it.done()); | 781 RUNTIME_ASSERT(!frame_it.done()); |
| 1831 | 782 |
| 1832 List<int> positions; | 783 List<int> positions; |
| 1833 isolate->debug()->GetStepinPositions(frame_it.frame(), id, &positions); | 784 isolate->debug()->GetStepinPositions(frame_it.frame(), id, &positions); |
| 1834 Factory* factory = isolate->factory(); | 785 Factory* factory = isolate->factory(); |
| 1835 Handle<FixedArray> array = factory->NewFixedArray(positions.length()); | 786 Handle<FixedArray> array = factory->NewFixedArray(positions.length()); |
| 1836 for (int i = 0; i < positions.length(); ++i) { | 787 for (int i = 0; i < positions.length(); ++i) { |
| 1837 array->set(i, Smi::FromInt(positions[i])); | 788 array->set(i, Smi::FromInt(positions[i])); |
| 1838 } | 789 } |
| 1839 return *factory->NewJSArrayWithElements(array, FAST_SMI_ELEMENTS); | 790 return *factory->NewJSArrayWithElements(array, FAST_SMI_ELEMENTS); |
| 1840 } | 791 } |
| 1841 | 792 |
| 1842 | 793 |
| 1843 static const int kScopeDetailsTypeIndex = 0; | |
| 1844 static const int kScopeDetailsObjectIndex = 1; | |
| 1845 static const int kScopeDetailsSize = 2; | |
| 1846 | |
| 1847 | |
| 1848 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails( | |
| 1849 Isolate* isolate, ScopeIterator* it) { | |
| 1850 // Calculate the size of the result. | |
| 1851 int details_size = kScopeDetailsSize; | |
| 1852 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); | |
| 1853 | |
| 1854 // Fill in scope details. | |
| 1855 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type())); | |
| 1856 Handle<JSObject> scope_object; | |
| 1857 ASSIGN_RETURN_ON_EXCEPTION(isolate, scope_object, it->ScopeObject(), | |
| 1858 JSObject); | |
| 1859 details->set(kScopeDetailsObjectIndex, *scope_object); | |
| 1860 | |
| 1861 return isolate->factory()->NewJSArrayWithElements(details); | |
| 1862 } | |
| 1863 | |
| 1864 | |
| 1865 // Return an array with scope details | 794 // Return an array with scope details |
| 1866 // args[0]: number: break id | 795 // args[0]: number: break id |
| 1867 // args[1]: number: frame index | 796 // args[1]: number: frame index |
| 1868 // args[2]: number: inlined frame index | 797 // args[2]: number: inlined frame index |
| 1869 // args[3]: number: scope index | 798 // args[3]: number: scope index |
| 1870 // | 799 // |
| 1871 // The array returned contains the following information: | 800 // The array returned contains the following information: |
| 1872 // 0: Scope type | 801 // 0: Scope type |
| 1873 // 1: Scope object | 802 // 1: Scope object |
| 1874 RUNTIME_FUNCTION(Runtime_GetScopeDetails) { | 803 RUNTIME_FUNCTION(Runtime_GetScopeDetails) { |
| 1875 HandleScope scope(isolate); | 804 HandleScope scope(isolate); |
| 1876 DCHECK(args.length() == 4); | 805 DCHECK(args.length() == 4); |
| 1877 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | 806 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); |
| 1878 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); | 807 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); |
| 1879 | 808 |
| 1880 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | 809 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); |
| 1881 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | 810 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); |
| 1882 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); | 811 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); |
| 1883 | 812 |
| 1884 // Get the frame where the debugging is performed. | 813 // Get the frame where the debugging is performed. |
| 1885 StackFrame::Id id = UnwrapFrameId(wrapped_id); | 814 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); |
| 1886 JavaScriptFrameIterator frame_it(isolate, id); | 815 JavaScriptFrameIterator frame_it(isolate, id); |
| 1887 JavaScriptFrame* frame = frame_it.frame(); | 816 JavaScriptFrame* frame = frame_it.frame(); |
| 1888 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | 817 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); |
| 1889 | 818 |
| 1890 // Find the requested scope. | 819 // Find the requested scope. |
| 1891 int n = 0; | 820 int n = 0; |
| 1892 ScopeIterator it(isolate, &frame_inspector); | 821 ScopeIterator it(isolate, &frame_inspector); |
| 1893 for (; !it.Done() && n < index; it.Next()) { | 822 for (; !it.Done() && n < index; it.Next()) { |
| 1894 n++; | 823 n++; |
| 1895 } | 824 } |
| 1896 if (it.Done()) { | 825 if (it.Done()) { |
| 1897 return isolate->heap()->undefined_value(); | 826 return isolate->heap()->undefined_value(); |
| 1898 } | 827 } |
| 1899 Handle<JSObject> details; | 828 Handle<JSObject> details; |
| 1900 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, | 829 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, |
| 1901 MaterializeScopeDetails(isolate, &it)); | 830 it.MaterializeScopeDetails()); |
| 1902 return *details; | 831 return *details; |
| 1903 } | 832 } |
| 1904 | 833 |
| 1905 | 834 |
| 1906 // Return an array of scope details | 835 // Return an array of scope details |
| 1907 // args[0]: number: break id | 836 // args[0]: number: break id |
| 1908 // args[1]: number: frame index | 837 // args[1]: number: frame index |
| 1909 // args[2]: number: inlined frame index | 838 // args[2]: number: inlined frame index |
| 1910 // args[3]: boolean: ignore nested scopes | 839 // args[3]: boolean: ignore nested scopes |
| 1911 // | 840 // |
| 1912 // The array returned contains arrays with the following information: | 841 // The array returned contains arrays with the following information: |
| 1913 // 0: Scope type | 842 // 0: Scope type |
| 1914 // 1: Scope object | 843 // 1: Scope object |
| 1915 RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) { | 844 RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) { |
| 1916 HandleScope scope(isolate); | 845 HandleScope scope(isolate); |
| 1917 DCHECK(args.length() == 3 || args.length() == 4); | 846 DCHECK(args.length() == 3 || args.length() == 4); |
| 1918 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | 847 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); |
| 1919 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); | 848 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); |
| 1920 | 849 |
| 1921 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | 850 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); |
| 1922 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | 851 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); |
| 1923 | 852 |
| 1924 bool ignore_nested_scopes = false; | 853 bool ignore_nested_scopes = false; |
| 1925 if (args.length() == 4) { | 854 if (args.length() == 4) { |
| 1926 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3); | 855 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3); |
| 1927 ignore_nested_scopes = flag; | 856 ignore_nested_scopes = flag; |
| 1928 } | 857 } |
| 1929 | 858 |
| 1930 // Get the frame where the debugging is performed. | 859 // Get the frame where the debugging is performed. |
| 1931 StackFrame::Id id = UnwrapFrameId(wrapped_id); | 860 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); |
| 1932 JavaScriptFrameIterator frame_it(isolate, id); | 861 JavaScriptFrameIterator frame_it(isolate, id); |
| 1933 JavaScriptFrame* frame = frame_it.frame(); | 862 JavaScriptFrame* frame = frame_it.frame(); |
| 1934 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | 863 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); |
| 1935 | 864 |
| 1936 List<Handle<JSObject> > result(4); | 865 List<Handle<JSObject> > result(4); |
| 1937 ScopeIterator it(isolate, &frame_inspector, ignore_nested_scopes); | 866 ScopeIterator it(isolate, &frame_inspector, ignore_nested_scopes); |
| 1938 for (; !it.Done(); it.Next()) { | 867 for (; !it.Done(); it.Next()) { |
| 1939 Handle<JSObject> details; | 868 Handle<JSObject> details; |
| 1940 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, | 869 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, |
| 1941 MaterializeScopeDetails(isolate, &it)); | 870 it.MaterializeScopeDetails()); |
| 1942 result.Add(details); | 871 result.Add(details); |
| 1943 } | 872 } |
| 1944 | 873 |
| 1945 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length()); | 874 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length()); |
| 1946 for (int i = 0; i < result.length(); ++i) { | 875 for (int i = 0; i < result.length(); ++i) { |
| 1947 array->set(i, *result[i]); | 876 array->set(i, *result[i]); |
| 1948 } | 877 } |
| 1949 return *isolate->factory()->NewJSArrayWithElements(array); | 878 return *isolate->factory()->NewJSArrayWithElements(array); |
| 1950 } | 879 } |
| 1951 | 880 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1980 ScopeIterator it(isolate, fun); | 909 ScopeIterator it(isolate, fun); |
| 1981 for (; !it.Done() && n < index; it.Next()) { | 910 for (; !it.Done() && n < index; it.Next()) { |
| 1982 n++; | 911 n++; |
| 1983 } | 912 } |
| 1984 if (it.Done()) { | 913 if (it.Done()) { |
| 1985 return isolate->heap()->undefined_value(); | 914 return isolate->heap()->undefined_value(); |
| 1986 } | 915 } |
| 1987 | 916 |
| 1988 Handle<JSObject> details; | 917 Handle<JSObject> details; |
| 1989 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, | 918 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, |
| 1990 MaterializeScopeDetails(isolate, &it)); | 919 it.MaterializeScopeDetails()); |
| 1991 return *details; | 920 return *details; |
| 1992 } | 921 } |
| 1993 | 922 |
| 1994 | 923 |
| 1995 static bool SetScopeVariableValue(ScopeIterator* it, int index, | 924 static bool SetScopeVariableValue(ScopeIterator* it, int index, |
| 1996 Handle<String> variable_name, | 925 Handle<String> variable_name, |
| 1997 Handle<Object> new_value) { | 926 Handle<Object> new_value) { |
| 1998 for (int n = 0; !it->Done() && n < index; it->Next()) { | 927 for (int n = 0; !it->Done() && n < index; it->Next()) { |
| 1999 n++; | 928 n++; |
| 2000 } | 929 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2025 | 954 |
| 2026 bool res; | 955 bool res; |
| 2027 if (args[0]->IsNumber()) { | 956 if (args[0]->IsNumber()) { |
| 2028 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | 957 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); |
| 2029 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); | 958 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); |
| 2030 | 959 |
| 2031 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | 960 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); |
| 2032 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | 961 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); |
| 2033 | 962 |
| 2034 // Get the frame where the debugging is performed. | 963 // Get the frame where the debugging is performed. |
| 2035 StackFrame::Id id = UnwrapFrameId(wrapped_id); | 964 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); |
| 2036 JavaScriptFrameIterator frame_it(isolate, id); | 965 JavaScriptFrameIterator frame_it(isolate, id); |
| 2037 JavaScriptFrame* frame = frame_it.frame(); | 966 JavaScriptFrame* frame = frame_it.frame(); |
| 2038 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | 967 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); |
| 2039 | 968 |
| 2040 ScopeIterator it(isolate, &frame_inspector); | 969 ScopeIterator it(isolate, &frame_inspector); |
| 2041 res = SetScopeVariableValue(&it, index, variable_name, new_value); | 970 res = SetScopeVariableValue(&it, index, variable_name, new_value); |
| 2042 } else { | 971 } else { |
| 2043 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | 972 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); |
| 2044 ScopeIterator it(isolate, fun); | 973 ScopeIterator it(isolate, fun); |
| 2045 res = SetScopeVariableValue(&it, index, variable_name, new_value); | 974 res = SetScopeVariableValue(&it, index, variable_name, new_value); |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2298 if (!args[1]->IsNumber() || !args[2]->IsNumber()) { | 1227 if (!args[1]->IsNumber() || !args[2]->IsNumber()) { |
| 2299 return isolate->Throw(isolate->heap()->illegal_argument_string()); | 1228 return isolate->Throw(isolate->heap()->illegal_argument_string()); |
| 2300 } | 1229 } |
| 2301 | 1230 |
| 2302 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]); | 1231 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]); |
| 2303 | 1232 |
| 2304 StackFrame::Id frame_id; | 1233 StackFrame::Id frame_id; |
| 2305 if (wrapped_frame_id == 0) { | 1234 if (wrapped_frame_id == 0) { |
| 2306 frame_id = StackFrame::NO_ID; | 1235 frame_id = StackFrame::NO_ID; |
| 2307 } else { | 1236 } else { |
| 2308 frame_id = UnwrapFrameId(wrapped_frame_id); | 1237 frame_id = DebugFrameHelper::UnwrapFrameId(wrapped_frame_id); |
| 2309 } | 1238 } |
| 2310 | 1239 |
| 2311 // Get the step action and check validity. | 1240 // Get the step action and check validity. |
| 2312 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); | 1241 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); |
| 2313 if (step_action != StepIn && step_action != StepNext && | 1242 if (step_action != StepIn && step_action != StepNext && |
| 2314 step_action != StepOut && step_action != StepInMin && | 1243 step_action != StepOut && step_action != StepInMin && |
| 2315 step_action != StepMin && step_action != StepFrame) { | 1244 step_action != StepMin && step_action != StepFrame) { |
| 2316 return isolate->Throw(isolate->heap()->illegal_argument_string()); | 1245 return isolate->Throw(isolate->heap()->illegal_argument_string()); |
| 2317 } | 1246 } |
| 2318 | 1247 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2340 // Clear all stepping set by PrepareStep. | 1269 // Clear all stepping set by PrepareStep. |
| 2341 RUNTIME_FUNCTION(Runtime_ClearStepping) { | 1270 RUNTIME_FUNCTION(Runtime_ClearStepping) { |
| 2342 HandleScope scope(isolate); | 1271 HandleScope scope(isolate); |
| 2343 DCHECK(args.length() == 0); | 1272 DCHECK(args.length() == 0); |
| 2344 RUNTIME_ASSERT(isolate->debug()->is_active()); | 1273 RUNTIME_ASSERT(isolate->debug()->is_active()); |
| 2345 isolate->debug()->ClearStepping(); | 1274 isolate->debug()->ClearStepping(); |
| 2346 return isolate->heap()->undefined_value(); | 1275 return isolate->heap()->undefined_value(); |
| 2347 } | 1276 } |
| 2348 | 1277 |
| 2349 | 1278 |
| 2350 // Helper function to find or create the arguments object for | |
| 2351 // Runtime_DebugEvaluate. | |
| 2352 static void MaterializeArgumentsObject(Isolate* isolate, | |
| 2353 Handle<JSObject> target, | |
| 2354 Handle<JSFunction> function) { | |
| 2355 // Do not materialize the arguments object for eval or top-level code. | |
| 2356 // Skip if "arguments" is already taken. | |
| 2357 if (!function->shared()->is_function()) return; | |
| 2358 Maybe<bool> maybe = JSReceiver::HasOwnProperty( | |
| 2359 target, isolate->factory()->arguments_string()); | |
| 2360 DCHECK(maybe.IsJust()); | |
| 2361 if (maybe.FromJust()) return; | |
| 2362 | |
| 2363 // FunctionGetArguments can't throw an exception. | |
| 2364 Handle<JSObject> arguments = | |
| 2365 Handle<JSObject>::cast(Accessors::FunctionGetArguments(function)); | |
| 2366 Handle<String> arguments_str = isolate->factory()->arguments_string(); | |
| 2367 JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments, | |
| 2368 NONE).Check(); | |
| 2369 } | |
| 2370 | |
| 2371 | |
| 2372 // Compile and evaluate source for the given context. | |
| 2373 static MaybeHandle<Object> DebugEvaluate(Isolate* isolate, | |
| 2374 Handle<SharedFunctionInfo> outer_info, | |
| 2375 Handle<Context> context, | |
| 2376 Handle<Object> context_extension, | |
| 2377 Handle<Object> receiver, | |
| 2378 Handle<String> source) { | |
| 2379 if (context_extension->IsJSObject()) { | |
| 2380 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension); | |
| 2381 Handle<JSFunction> closure(context->closure(), isolate); | |
| 2382 context = isolate->factory()->NewWithContext(closure, context, extension); | |
| 2383 } | |
| 2384 | |
| 2385 Handle<JSFunction> eval_fun; | |
| 2386 ASSIGN_RETURN_ON_EXCEPTION(isolate, eval_fun, | |
| 2387 Compiler::GetFunctionFromEval( | |
| 2388 source, outer_info, context, SLOPPY, | |
| 2389 NO_PARSE_RESTRICTION, RelocInfo::kNoPosition), | |
| 2390 Object); | |
| 2391 | |
| 2392 Handle<Object> result; | |
| 2393 ASSIGN_RETURN_ON_EXCEPTION( | |
| 2394 isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL), | |
| 2395 Object); | |
| 2396 | |
| 2397 // Skip the global proxy as it has no properties and always delegates to the | |
| 2398 // real global object. | |
| 2399 if (result->IsJSGlobalProxy()) { | |
| 2400 PrototypeIterator iter(isolate, result); | |
| 2401 // TODO(verwaest): This will crash when the global proxy is detached. | |
| 2402 result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
| 2403 } | |
| 2404 | |
| 2405 return result; | |
| 2406 } | |
| 2407 | |
| 2408 | |
| 2409 static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) { | |
| 2410 Handle<JSObject> result = | |
| 2411 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 2412 Handle<Map> new_map = | |
| 2413 Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto"); | |
| 2414 Map::SetPrototype(new_map, isolate->factory()->null_value()); | |
| 2415 JSObject::MigrateToMap(result, new_map); | |
| 2416 return result; | |
| 2417 } | |
| 2418 | |
| 2419 | |
| 2420 namespace { | |
| 2421 | |
| 2422 // This class builds a context chain for evaluation of expressions | |
| 2423 // in debugger. | |
| 2424 // The scope chain leading up to a breakpoint where evaluation occurs | |
| 2425 // looks like: | |
| 2426 // - [a mix of with, catch and block scopes] | |
| 2427 // - [function stack + context] | |
| 2428 // - [outer context] | |
| 2429 // The builder materializes all stack variables into properties of objects; | |
| 2430 // the expression is then evaluated as if it is inside a series of 'with' | |
| 2431 // statements using those objects. To this end, the builder builds a new | |
| 2432 // context chain, based on a scope chain: | |
| 2433 // - every With and Catch scope begets a cloned context | |
| 2434 // - Block scope begets one or two contexts: | |
| 2435 // - if a block has context-allocated varaibles, its context is cloned | |
| 2436 // - stack locals are materizalized as a With context | |
| 2437 // - Local scope begets a With context for materizalized locals, chained to | |
| 2438 // original function context. Original function context is the end of | |
| 2439 // the chain. | |
| 2440 class EvaluationContextBuilder { | |
| 2441 public: | |
| 2442 EvaluationContextBuilder(Isolate* isolate, JavaScriptFrame* frame, | |
| 2443 int inlined_jsframe_index) | |
| 2444 : isolate_(isolate), | |
| 2445 frame_(frame), | |
| 2446 inlined_jsframe_index_(inlined_jsframe_index) { | |
| 2447 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | |
| 2448 Handle<JSFunction> function = | |
| 2449 handle(JSFunction::cast(frame_inspector.GetFunction())); | |
| 2450 Handle<Context> outer_context = handle(function->context(), isolate); | |
| 2451 outer_info_ = handle(function->shared()); | |
| 2452 Handle<Context> inner_context; | |
| 2453 | |
| 2454 bool stop = false; | |
| 2455 for (ScopeIterator it(isolate, &frame_inspector); | |
| 2456 !it.Failed() && !it.Done() && !stop; it.Next()) { | |
| 2457 ScopeIterator::ScopeType scope_type = it.Type(); | |
| 2458 | |
| 2459 if (scope_type == ScopeIterator::ScopeTypeLocal) { | |
| 2460 Handle<Context> parent_context = | |
| 2461 it.HasContext() ? it.CurrentContext() : outer_context; | |
| 2462 | |
| 2463 // The "this" binding, if any, can't be bound via "with". If we need | |
| 2464 // to, add another node onto the outer context to bind "this". | |
| 2465 parent_context = | |
| 2466 MaterializeReceiver(isolate, parent_context, function, frame); | |
| 2467 | |
| 2468 Handle<JSObject> materialized_function = | |
| 2469 NewJSObjectWithNullProto(isolate); | |
| 2470 | |
| 2471 MaterializeStackLocalsWithFrameInspector(isolate, materialized_function, | |
| 2472 function, &frame_inspector); | |
| 2473 | |
| 2474 MaterializeArgumentsObject(isolate, materialized_function, function); | |
| 2475 | |
| 2476 Handle<Context> with_context = isolate->factory()->NewWithContext( | |
| 2477 function, parent_context, materialized_function); | |
| 2478 | |
| 2479 ContextChainElement context_chain_element; | |
| 2480 context_chain_element.original_context = it.CurrentContext(); | |
| 2481 context_chain_element.materialized_object = materialized_function; | |
| 2482 context_chain_element.scope_info = it.CurrentScopeInfo(); | |
| 2483 context_chain_.Add(context_chain_element); | |
| 2484 | |
| 2485 stop = true; | |
| 2486 RecordContextsInChain(&inner_context, with_context, with_context); | |
| 2487 } else if (scope_type == ScopeIterator::ScopeTypeCatch || | |
| 2488 scope_type == ScopeIterator::ScopeTypeWith) { | |
| 2489 Handle<Context> cloned_context = | |
| 2490 Handle<Context>::cast(FixedArray::CopySize( | |
| 2491 it.CurrentContext(), it.CurrentContext()->length())); | |
| 2492 | |
| 2493 ContextChainElement context_chain_element; | |
| 2494 context_chain_element.original_context = it.CurrentContext(); | |
| 2495 context_chain_element.cloned_context = cloned_context; | |
| 2496 context_chain_.Add(context_chain_element); | |
| 2497 | |
| 2498 RecordContextsInChain(&inner_context, cloned_context, cloned_context); | |
| 2499 } else if (scope_type == ScopeIterator::ScopeTypeBlock) { | |
| 2500 Handle<JSObject> materialized_object = | |
| 2501 NewJSObjectWithNullProto(isolate); | |
| 2502 MaterializeStackLocalsWithFrameInspector(isolate, materialized_object, | |
| 2503 it.CurrentScopeInfo(), | |
| 2504 &frame_inspector); | |
| 2505 if (it.HasContext()) { | |
| 2506 Handle<Context> cloned_context = | |
| 2507 Handle<Context>::cast(FixedArray::CopySize( | |
| 2508 it.CurrentContext(), it.CurrentContext()->length())); | |
| 2509 Handle<Context> with_context = isolate->factory()->NewWithContext( | |
| 2510 function, cloned_context, materialized_object); | |
| 2511 | |
| 2512 ContextChainElement context_chain_element; | |
| 2513 context_chain_element.original_context = it.CurrentContext(); | |
| 2514 context_chain_element.cloned_context = cloned_context; | |
| 2515 context_chain_element.materialized_object = materialized_object; | |
| 2516 context_chain_element.scope_info = it.CurrentScopeInfo(); | |
| 2517 context_chain_.Add(context_chain_element); | |
| 2518 | |
| 2519 RecordContextsInChain(&inner_context, cloned_context, with_context); | |
| 2520 } else { | |
| 2521 Handle<Context> with_context = isolate->factory()->NewWithContext( | |
| 2522 function, outer_context, materialized_object); | |
| 2523 | |
| 2524 ContextChainElement context_chain_element; | |
| 2525 context_chain_element.materialized_object = materialized_object; | |
| 2526 context_chain_element.scope_info = it.CurrentScopeInfo(); | |
| 2527 context_chain_.Add(context_chain_element); | |
| 2528 | |
| 2529 RecordContextsInChain(&inner_context, with_context, with_context); | |
| 2530 } | |
| 2531 } else { | |
| 2532 stop = true; | |
| 2533 } | |
| 2534 } | |
| 2535 if (innermost_context_.is_null()) { | |
| 2536 innermost_context_ = outer_context; | |
| 2537 } | |
| 2538 DCHECK(!innermost_context_.is_null()); | |
| 2539 } | |
| 2540 | |
| 2541 void UpdateVariables() { | |
| 2542 for (int i = 0; i < context_chain_.length(); i++) { | |
| 2543 ContextChainElement element = context_chain_[i]; | |
| 2544 if (!element.original_context.is_null() && | |
| 2545 !element.cloned_context.is_null()) { | |
| 2546 Handle<Context> cloned_context = element.cloned_context; | |
| 2547 cloned_context->CopyTo( | |
| 2548 Context::MIN_CONTEXT_SLOTS, *element.original_context, | |
| 2549 Context::MIN_CONTEXT_SLOTS, | |
| 2550 cloned_context->length() - Context::MIN_CONTEXT_SLOTS); | |
| 2551 } | |
| 2552 if (!element.materialized_object.is_null()) { | |
| 2553 // Write back potential changes to materialized stack locals to the | |
| 2554 // stack. | |
| 2555 UpdateStackLocalsFromMaterializedObject( | |
| 2556 isolate_, element.materialized_object, element.scope_info, frame_, | |
| 2557 inlined_jsframe_index_); | |
| 2558 } | |
| 2559 } | |
| 2560 } | |
| 2561 | |
| 2562 Handle<Context> innermost_context() const { return innermost_context_; } | |
| 2563 Handle<SharedFunctionInfo> outer_info() const { return outer_info_; } | |
| 2564 | |
| 2565 private: | |
| 2566 struct ContextChainElement { | |
| 2567 Handle<Context> original_context; | |
| 2568 Handle<Context> cloned_context; | |
| 2569 Handle<JSObject> materialized_object; | |
| 2570 Handle<ScopeInfo> scope_info; | |
| 2571 }; | |
| 2572 | |
| 2573 void RecordContextsInChain(Handle<Context>* inner_context, | |
| 2574 Handle<Context> first, Handle<Context> last) { | |
| 2575 if (!inner_context->is_null()) { | |
| 2576 (*inner_context)->set_previous(*last); | |
| 2577 } else { | |
| 2578 innermost_context_ = last; | |
| 2579 } | |
| 2580 *inner_context = first; | |
| 2581 } | |
| 2582 | |
| 2583 Handle<SharedFunctionInfo> outer_info_; | |
| 2584 Handle<Context> innermost_context_; | |
| 2585 List<ContextChainElement> context_chain_; | |
| 2586 Isolate* isolate_; | |
| 2587 JavaScriptFrame* frame_; | |
| 2588 int inlined_jsframe_index_; | |
| 2589 }; | |
| 2590 } | |
| 2591 | |
| 2592 | |
| 2593 // Evaluate a piece of JavaScript in the context of a stack frame for | |
| 2594 // debugging. Things that need special attention are: | |
| 2595 // - Parameters and stack-allocated locals need to be materialized. Altered | |
| 2596 // values need to be written back to the stack afterwards. | |
| 2597 // - The arguments object needs to materialized. | |
| 2598 RUNTIME_FUNCTION(Runtime_DebugEvaluate) { | 1279 RUNTIME_FUNCTION(Runtime_DebugEvaluate) { |
| 2599 HandleScope scope(isolate); | 1280 HandleScope scope(isolate); |
| 2600 | 1281 |
| 2601 // Check the execution state and decode arguments frame and source to be | 1282 // Check the execution state and decode arguments frame and source to be |
| 2602 // evaluated. | 1283 // evaluated. |
| 2603 DCHECK(args.length() == 6); | 1284 DCHECK(args.length() == 6); |
| 2604 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | 1285 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); |
| 2605 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); | 1286 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); |
| 2606 | 1287 |
| 2607 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | 1288 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); |
| 2608 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | 1289 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); |
| 2609 CONVERT_ARG_HANDLE_CHECKED(String, source, 3); | 1290 CONVERT_ARG_HANDLE_CHECKED(String, source, 3); |
| 2610 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); | 1291 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); |
| 2611 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5); | 1292 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5); |
| 2612 | 1293 |
| 2613 // Handle the processing of break. | 1294 StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id); |
| 2614 DisableBreak disable_break_scope(isolate->debug(), disable_break); | |
| 2615 | |
| 2616 // Get the frame where the debugging is performed. | |
| 2617 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
| 2618 JavaScriptFrameIterator it(isolate, id); | |
| 2619 JavaScriptFrame* frame = it.frame(); | |
| 2620 | |
| 2621 // Traverse the saved contexts chain to find the active context for the | |
| 2622 // selected frame. | |
| 2623 SaveContext* save = FindSavedContextForFrame(isolate, frame); | |
| 2624 | |
| 2625 SaveContext savex(isolate); | |
| 2626 isolate->set_context(*(save->context())); | |
| 2627 | |
| 2628 // Materialize stack locals and the arguments object. | |
| 2629 | |
| 2630 EvaluationContextBuilder context_builder(isolate, frame, | |
| 2631 inlined_jsframe_index); | |
| 2632 if (isolate->has_pending_exception()) { | |
| 2633 return isolate->heap()->exception(); | |
| 2634 } | |
| 2635 | |
| 2636 | |
| 2637 Handle<Object> receiver(frame->receiver(), isolate); | |
| 2638 MaybeHandle<Object> maybe_result = DebugEvaluate( | |
| 2639 isolate, context_builder.outer_info(), | |
| 2640 context_builder.innermost_context(), context_extension, receiver, source); | |
| 2641 | 1295 |
| 2642 Handle<Object> result; | 1296 Handle<Object> result; |
| 2643 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result); | 1297 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 2644 context_builder.UpdateVariables(); | 1298 isolate, result, |
| 1299 DebugEvaluate::Local(isolate, id, inlined_jsframe_index, source, |
| 1300 disable_break, context_extension)); |
| 2645 return *result; | 1301 return *result; |
| 2646 } | 1302 } |
| 2647 | 1303 |
| 2648 | 1304 |
| 2649 static inline bool IsDebugContext(Isolate* isolate, Context* context) { | |
| 2650 // Try to unwrap script context if it exist. | |
| 2651 if (context->IsScriptContext()) context = context->previous(); | |
| 2652 DCHECK_NOT_NULL(context); | |
| 2653 return context == *isolate->debug()->debug_context(); | |
| 2654 } | |
| 2655 | |
| 2656 | |
| 2657 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { | 1305 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { |
| 2658 HandleScope scope(isolate); | 1306 HandleScope scope(isolate); |
| 2659 | 1307 |
| 2660 // Check the execution state and decode arguments frame and source to be | 1308 // Check the execution state and decode arguments frame and source to be |
| 2661 // evaluated. | 1309 // evaluated. |
| 2662 DCHECK(args.length() == 4); | 1310 DCHECK(args.length() == 4); |
| 2663 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | 1311 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); |
| 2664 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); | 1312 RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id)); |
| 2665 | 1313 |
| 2666 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); | 1314 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); |
| 2667 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); | 1315 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); |
| 2668 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3); | 1316 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3); |
| 2669 | 1317 |
| 2670 // Handle the processing of break. | |
| 2671 DisableBreak disable_break_scope(isolate->debug(), disable_break); | |
| 2672 | |
| 2673 // Enter the top context from before the debugger was invoked. | |
| 2674 SaveContext save(isolate); | |
| 2675 SaveContext* top = &save; | |
| 2676 while (top != NULL && IsDebugContext(isolate, *top->context())) { | |
| 2677 top = top->prev(); | |
| 2678 } | |
| 2679 if (top != NULL) { | |
| 2680 isolate->set_context(*top->context()); | |
| 2681 } | |
| 2682 | |
| 2683 // Get the native context now set to the top context from before the | |
| 2684 // debugger was invoked. | |
| 2685 Handle<Context> context = isolate->native_context(); | |
| 2686 Handle<JSObject> receiver(context->global_proxy()); | |
| 2687 Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate); | |
| 2688 Handle<Object> result; | 1318 Handle<Object> result; |
| 2689 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 1319 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 2690 isolate, result, DebugEvaluate(isolate, outer_info, context, | 1320 isolate, result, |
| 2691 context_extension, receiver, source)); | 1321 DebugEvaluate::Global(isolate, source, disable_break, context_extension)); |
| 2692 return *result; | 1322 return *result; |
| 2693 } | 1323 } |
| 2694 | 1324 |
| 2695 | 1325 |
| 2696 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) { | 1326 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) { |
| 2697 HandleScope scope(isolate); | 1327 HandleScope scope(isolate); |
| 2698 DCHECK(args.length() == 0); | 1328 DCHECK(args.length() == 0); |
| 2699 RUNTIME_ASSERT(isolate->debug()->is_active()); | 1329 RUNTIME_ASSERT(isolate->debug()->is_active()); |
| 2700 | 1330 |
| 2701 Handle<FixedArray> instances; | 1331 Handle<FixedArray> instances; |
| (...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3191 return *isolate->factory()->undefined_value(); | 1821 return *isolate->factory()->undefined_value(); |
| 3192 } | 1822 } |
| 3193 | 1823 |
| 3194 | 1824 |
| 3195 RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode) { | 1825 RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode) { |
| 3196 UNIMPLEMENTED(); | 1826 UNIMPLEMENTED(); |
| 3197 return NULL; | 1827 return NULL; |
| 3198 } | 1828 } |
| 3199 } // namespace internal | 1829 } // namespace internal |
| 3200 } // namespace v8 | 1830 } // namespace v8 |
| OLD | NEW |