| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 <stdlib.h> | 5 #include <stdlib.h> |
| 6 #include <limits> | 6 #include <limits> |
| 7 | 7 |
| 8 #include "src/v8.h" | 8 #include "src/v8.h" |
| 9 | 9 |
| 10 #include "src/accessors.h" | 10 #include "src/accessors.h" |
| 11 #include "src/allocation-site-scopes.h" | 11 #include "src/allocation-site-scopes.h" |
| 12 #include "src/api.h" | 12 #include "src/api.h" |
| 13 #include "src/arguments.h" | 13 #include "src/arguments.h" |
| 14 #include "src/bailout-reason.h" | 14 #include "src/bailout-reason.h" |
| 15 #include "src/base/cpu.h" | 15 #include "src/base/cpu.h" |
| 16 #include "src/base/platform/platform.h" | 16 #include "src/base/platform/platform.h" |
| 17 #include "src/bootstrapper.h" | 17 #include "src/bootstrapper.h" |
| 18 #include "src/codegen.h" | 18 #include "src/codegen.h" |
| 19 #include "src/compilation-cache.h" | 19 #include "src/compilation-cache.h" |
| 20 #include "src/compiler.h" | 20 #include "src/compiler.h" |
| 21 #include "src/conversions.h" | 21 #include "src/conversions.h" |
| 22 #include "src/cpu-profiler.h" | |
| 23 #include "src/date.h" | |
| 24 #include "src/dateparser-inl.h" | |
| 25 #include "src/debug.h" | |
| 26 #include "src/deoptimizer.h" | 22 #include "src/deoptimizer.h" |
| 27 #include "src/execution.h" | 23 #include "src/execution.h" |
| 28 #include "src/full-codegen.h" | 24 #include "src/full-codegen.h" |
| 29 #include "src/global-handles.h" | 25 #include "src/global-handles.h" |
| 30 #include "src/isolate-inl.h" | 26 #include "src/isolate-inl.h" |
| 31 #include "src/liveedit.h" | |
| 32 #include "src/misc-intrinsics.h" | |
| 33 #include "src/parser.h" | 27 #include "src/parser.h" |
| 34 #include "src/prototype.h" | 28 #include "src/prototype.h" |
| 35 #include "src/runtime/runtime.h" | 29 #include "src/runtime/runtime.h" |
| 36 #include "src/runtime/runtime-utils.h" | 30 #include "src/runtime/runtime-utils.h" |
| 37 #include "src/runtime-profiler.h" | |
| 38 #include "src/scopeinfo.h" | 31 #include "src/scopeinfo.h" |
| 39 #include "src/smart-pointers.h" | 32 #include "src/smart-pointers.h" |
| 40 #include "src/utils.h" | 33 #include "src/utils.h" |
| 41 #include "src/v8threads.h" | 34 #include "src/v8threads.h" |
| 42 #include "src/vm-state-inl.h" | |
| 43 | 35 |
| 44 | 36 |
| 45 namespace v8 { | 37 namespace v8 { |
| 46 namespace internal { | 38 namespace internal { |
| 47 | 39 |
| 48 // Header of runtime functions. | 40 // Header of runtime functions. |
| 49 #define F(name, number_of_args, result_size) \ | 41 #define F(name, number_of_args, result_size) \ |
| 50 Object* Runtime_##name(int args_length, Object** args_object, \ | 42 Object* Runtime_##name(int args_length, Object** args_object, \ |
| 51 Isolate* isolate); | 43 Isolate* isolate); |
| 52 | 44 |
| (...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 } | 652 } |
| 661 iter.AdvanceIgnoringProxies(); | 653 iter.AdvanceIgnoringProxies(); |
| 662 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | 654 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
| 663 return *PrototypeIterator::GetCurrent(iter); | 655 return *PrototypeIterator::GetCurrent(iter); |
| 664 } | 656 } |
| 665 } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)); | 657 } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)); |
| 666 return *PrototypeIterator::GetCurrent(iter); | 658 return *PrototypeIterator::GetCurrent(iter); |
| 667 } | 659 } |
| 668 | 660 |
| 669 | 661 |
| 670 static inline Handle<Object> GetPrototypeSkipHiddenPrototypes( | |
| 671 Isolate* isolate, Handle<Object> receiver) { | |
| 672 PrototypeIterator iter(isolate, receiver); | |
| 673 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) { | |
| 674 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | |
| 675 return PrototypeIterator::GetCurrent(iter); | |
| 676 } | |
| 677 iter.Advance(); | |
| 678 } | |
| 679 return PrototypeIterator::GetCurrent(iter); | |
| 680 } | |
| 681 | |
| 682 | |
| 683 RUNTIME_FUNCTION(Runtime_InternalSetPrototype) { | 662 RUNTIME_FUNCTION(Runtime_InternalSetPrototype) { |
| 684 HandleScope scope(isolate); | 663 HandleScope scope(isolate); |
| 685 DCHECK(args.length() == 2); | 664 DCHECK(args.length() == 2); |
| 686 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | 665 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
| 687 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); | 666 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); |
| 688 DCHECK(!obj->IsAccessCheckNeeded()); | 667 DCHECK(!obj->IsAccessCheckNeeded()); |
| 689 DCHECK(!obj->map()->is_observed()); | 668 DCHECK(!obj->map()->is_observed()); |
| 690 Handle<Object> result; | 669 Handle<Object> result; |
| 691 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 670 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 692 isolate, result, JSObject::SetPrototype(obj, prototype, false)); | 671 isolate, result, JSObject::SetPrototype(obj, prototype, false)); |
| 693 return *result; | 672 return *result; |
| 694 } | 673 } |
| 695 | 674 |
| 696 | 675 |
| 697 RUNTIME_FUNCTION(Runtime_SetPrototype) { | 676 RUNTIME_FUNCTION(Runtime_SetPrototype) { |
| 698 HandleScope scope(isolate); | 677 HandleScope scope(isolate); |
| 699 DCHECK(args.length() == 2); | 678 DCHECK(args.length() == 2); |
| 700 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | 679 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); |
| 701 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); | 680 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); |
| 702 if (obj->IsAccessCheckNeeded() && | 681 if (obj->IsAccessCheckNeeded() && |
| 703 !isolate->MayNamedAccess(obj, isolate->factory()->proto_string(), | 682 !isolate->MayNamedAccess(obj, isolate->factory()->proto_string(), |
| 704 v8::ACCESS_SET)) { | 683 v8::ACCESS_SET)) { |
| 705 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET); | 684 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET); |
| 706 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); | 685 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); |
| 707 return isolate->heap()->undefined_value(); | 686 return isolate->heap()->undefined_value(); |
| 708 } | 687 } |
| 709 if (obj->map()->is_observed()) { | 688 if (obj->map()->is_observed()) { |
| 710 Handle<Object> old_value = GetPrototypeSkipHiddenPrototypes(isolate, obj); | 689 Handle<Object> old_value = |
| 690 Object::GetPrototypeSkipHiddenPrototypes(isolate, obj); |
| 711 Handle<Object> result; | 691 Handle<Object> result; |
| 712 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 692 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 713 isolate, result, JSObject::SetPrototype(obj, prototype, true)); | 693 isolate, result, JSObject::SetPrototype(obj, prototype, true)); |
| 714 | 694 |
| 715 Handle<Object> new_value = GetPrototypeSkipHiddenPrototypes(isolate, obj); | 695 Handle<Object> new_value = |
| 696 Object::GetPrototypeSkipHiddenPrototypes(isolate, obj); |
| 716 if (!new_value->SameValue(*old_value)) { | 697 if (!new_value->SameValue(*old_value)) { |
| 717 JSObject::EnqueueChangeRecord( | 698 JSObject::EnqueueChangeRecord( |
| 718 obj, "setPrototype", isolate->factory()->proto_string(), old_value); | 699 obj, "setPrototype", isolate->factory()->proto_string(), old_value); |
| 719 } | 700 } |
| 720 return *result; | 701 return *result; |
| 721 } | 702 } |
| 722 Handle<Object> result; | 703 Handle<Object> result; |
| 723 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 704 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 724 isolate, result, JSObject::SetPrototype(obj, prototype, true)); | 705 isolate, result, JSObject::SetPrototype(obj, prototype, true)); |
| 725 return *result; | 706 return *result; |
| (...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1475 | 1456 |
| 1476 RUNTIME_FUNCTION(Runtime_FunctionMarkNameShouldPrintAsAnonymous) { | 1457 RUNTIME_FUNCTION(Runtime_FunctionMarkNameShouldPrintAsAnonymous) { |
| 1477 SealHandleScope shs(isolate); | 1458 SealHandleScope shs(isolate); |
| 1478 DCHECK(args.length() == 1); | 1459 DCHECK(args.length() == 1); |
| 1479 CONVERT_ARG_CHECKED(JSFunction, f, 0); | 1460 CONVERT_ARG_CHECKED(JSFunction, f, 0); |
| 1480 f->shared()->set_name_should_print_as_anonymous(true); | 1461 f->shared()->set_name_should_print_as_anonymous(true); |
| 1481 return isolate->heap()->undefined_value(); | 1462 return isolate->heap()->undefined_value(); |
| 1482 } | 1463 } |
| 1483 | 1464 |
| 1484 | 1465 |
| 1485 RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) { | |
| 1486 SealHandleScope shs(isolate); | |
| 1487 DCHECK(args.length() == 1); | |
| 1488 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
| 1489 return isolate->heap()->ToBoolean(f->shared()->is_generator()); | |
| 1490 } | |
| 1491 | |
| 1492 | |
| 1493 RUNTIME_FUNCTION(Runtime_FunctionIsArrow) { | 1466 RUNTIME_FUNCTION(Runtime_FunctionIsArrow) { |
| 1494 SealHandleScope shs(isolate); | 1467 SealHandleScope shs(isolate); |
| 1495 DCHECK(args.length() == 1); | 1468 DCHECK(args.length() == 1); |
| 1496 CONVERT_ARG_CHECKED(JSFunction, f, 0); | 1469 CONVERT_ARG_CHECKED(JSFunction, f, 0); |
| 1497 return isolate->heap()->ToBoolean(f->shared()->is_arrow()); | 1470 return isolate->heap()->ToBoolean(f->shared()->is_arrow()); |
| 1498 } | 1471 } |
| 1499 | 1472 |
| 1500 | 1473 |
| 1501 RUNTIME_FUNCTION(Runtime_FunctionIsConciseMethod) { | 1474 RUNTIME_FUNCTION(Runtime_FunctionIsConciseMethod) { |
| 1502 SealHandleScope shs(isolate); | 1475 SealHandleScope shs(isolate); |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1676 if (isolate->logger()->is_logging_code_events() || | 1649 if (isolate->logger()->is_logging_code_events() || |
| 1677 isolate->cpu_profiler()->is_profiling()) { | 1650 isolate->cpu_profiler()->is_profiling()) { |
| 1678 isolate->logger()->LogExistingFunction(source_shared, | 1651 isolate->logger()->LogExistingFunction(source_shared, |
| 1679 Handle<Code>(source_shared->code())); | 1652 Handle<Code>(source_shared->code())); |
| 1680 } | 1653 } |
| 1681 | 1654 |
| 1682 return *target; | 1655 return *target; |
| 1683 } | 1656 } |
| 1684 | 1657 |
| 1685 | 1658 |
| 1686 RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) { | |
| 1687 HandleScope scope(isolate); | |
| 1688 DCHECK(args.length() == 0); | |
| 1689 | |
| 1690 JavaScriptFrameIterator it(isolate); | |
| 1691 JavaScriptFrame* frame = it.frame(); | |
| 1692 Handle<JSFunction> function(frame->function()); | |
| 1693 RUNTIME_ASSERT(function->shared()->is_generator()); | |
| 1694 | |
| 1695 Handle<JSGeneratorObject> generator; | |
| 1696 if (frame->IsConstructor()) { | |
| 1697 generator = handle(JSGeneratorObject::cast(frame->receiver())); | |
| 1698 } else { | |
| 1699 generator = isolate->factory()->NewJSGeneratorObject(function); | |
| 1700 } | |
| 1701 generator->set_function(*function); | |
| 1702 generator->set_context(Context::cast(frame->context())); | |
| 1703 generator->set_receiver(frame->receiver()); | |
| 1704 generator->set_continuation(0); | |
| 1705 generator->set_operand_stack(isolate->heap()->empty_fixed_array()); | |
| 1706 generator->set_stack_handler_index(-1); | |
| 1707 | |
| 1708 return *generator; | |
| 1709 } | |
| 1710 | |
| 1711 | |
| 1712 RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) { | |
| 1713 HandleScope handle_scope(isolate); | |
| 1714 DCHECK(args.length() == 1); | |
| 1715 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0); | |
| 1716 | |
| 1717 JavaScriptFrameIterator stack_iterator(isolate); | |
| 1718 JavaScriptFrame* frame = stack_iterator.frame(); | |
| 1719 RUNTIME_ASSERT(frame->function()->shared()->is_generator()); | |
| 1720 DCHECK_EQ(frame->function(), generator_object->function()); | |
| 1721 | |
| 1722 // The caller should have saved the context and continuation already. | |
| 1723 DCHECK_EQ(generator_object->context(), Context::cast(frame->context())); | |
| 1724 DCHECK_LT(0, generator_object->continuation()); | |
| 1725 | |
| 1726 // We expect there to be at least two values on the operand stack: the return | |
| 1727 // value of the yield expression, and the argument to this runtime call. | |
| 1728 // Neither of those should be saved. | |
| 1729 int operands_count = frame->ComputeOperandsCount(); | |
| 1730 DCHECK_GE(operands_count, 2); | |
| 1731 operands_count -= 2; | |
| 1732 | |
| 1733 if (operands_count == 0) { | |
| 1734 // Although it's semantically harmless to call this function with an | |
| 1735 // operands_count of zero, it is also unnecessary. | |
| 1736 DCHECK_EQ(generator_object->operand_stack(), | |
| 1737 isolate->heap()->empty_fixed_array()); | |
| 1738 DCHECK_EQ(generator_object->stack_handler_index(), -1); | |
| 1739 // If there are no operands on the stack, there shouldn't be a handler | |
| 1740 // active either. | |
| 1741 DCHECK(!frame->HasHandler()); | |
| 1742 } else { | |
| 1743 int stack_handler_index = -1; | |
| 1744 Handle<FixedArray> operand_stack = | |
| 1745 isolate->factory()->NewFixedArray(operands_count); | |
| 1746 frame->SaveOperandStack(*operand_stack, &stack_handler_index); | |
| 1747 generator_object->set_operand_stack(*operand_stack); | |
| 1748 generator_object->set_stack_handler_index(stack_handler_index); | |
| 1749 } | |
| 1750 | |
| 1751 return isolate->heap()->undefined_value(); | |
| 1752 } | |
| 1753 | |
| 1754 | |
| 1755 // Note that this function is the slow path for resuming generators. It is only | |
| 1756 // called if the suspended activation had operands on the stack, stack handlers | |
| 1757 // needing rewinding, or if the resume should throw an exception. The fast path | |
| 1758 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is | |
| 1759 // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is | |
| 1760 // called in any case, as it needs to reconstruct the stack frame and make space | |
| 1761 // for arguments and operands. | |
| 1762 RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) { | |
| 1763 SealHandleScope shs(isolate); | |
| 1764 DCHECK(args.length() == 3); | |
| 1765 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); | |
| 1766 CONVERT_ARG_CHECKED(Object, value, 1); | |
| 1767 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2); | |
| 1768 JavaScriptFrameIterator stack_iterator(isolate); | |
| 1769 JavaScriptFrame* frame = stack_iterator.frame(); | |
| 1770 | |
| 1771 DCHECK_EQ(frame->function(), generator_object->function()); | |
| 1772 DCHECK(frame->function()->is_compiled()); | |
| 1773 | |
| 1774 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0); | |
| 1775 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0); | |
| 1776 | |
| 1777 Address pc = generator_object->function()->code()->instruction_start(); | |
| 1778 int offset = generator_object->continuation(); | |
| 1779 DCHECK(offset > 0); | |
| 1780 frame->set_pc(pc + offset); | |
| 1781 if (FLAG_enable_ool_constant_pool) { | |
| 1782 frame->set_constant_pool( | |
| 1783 generator_object->function()->code()->constant_pool()); | |
| 1784 } | |
| 1785 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting); | |
| 1786 | |
| 1787 FixedArray* operand_stack = generator_object->operand_stack(); | |
| 1788 int operands_count = operand_stack->length(); | |
| 1789 if (operands_count != 0) { | |
| 1790 frame->RestoreOperandStack(operand_stack, | |
| 1791 generator_object->stack_handler_index()); | |
| 1792 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array()); | |
| 1793 generator_object->set_stack_handler_index(-1); | |
| 1794 } | |
| 1795 | |
| 1796 JSGeneratorObject::ResumeMode resume_mode = | |
| 1797 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int); | |
| 1798 switch (resume_mode) { | |
| 1799 case JSGeneratorObject::NEXT: | |
| 1800 return value; | |
| 1801 case JSGeneratorObject::THROW: | |
| 1802 return isolate->Throw(value); | |
| 1803 } | |
| 1804 | |
| 1805 UNREACHABLE(); | |
| 1806 return isolate->ThrowIllegalOperation(); | |
| 1807 } | |
| 1808 | |
| 1809 | |
| 1810 RUNTIME_FUNCTION(Runtime_ThrowGeneratorStateError) { | |
| 1811 HandleScope scope(isolate); | |
| 1812 DCHECK(args.length() == 1); | |
| 1813 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
| 1814 int continuation = generator->continuation(); | |
| 1815 const char* message = continuation == JSGeneratorObject::kGeneratorClosed | |
| 1816 ? "generator_finished" | |
| 1817 : "generator_running"; | |
| 1818 Vector<Handle<Object> > argv = HandleVector<Object>(NULL, 0); | |
| 1819 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewError(message, argv)); | |
| 1820 } | |
| 1821 | |
| 1822 | |
| 1823 RUNTIME_FUNCTION(Runtime_ObjectFreeze) { | 1659 RUNTIME_FUNCTION(Runtime_ObjectFreeze) { |
| 1824 HandleScope scope(isolate); | 1660 HandleScope scope(isolate); |
| 1825 DCHECK(args.length() == 1); | 1661 DCHECK(args.length() == 1); |
| 1826 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | 1662 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
| 1827 | 1663 |
| 1828 // %ObjectFreeze is a fast path and these cases are handled elsewhere. | 1664 // %ObjectFreeze is a fast path and these cases are handled elsewhere. |
| 1829 RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && | 1665 RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && |
| 1830 !object->map()->is_observed() && !object->IsJSProxy()); | 1666 !object->map()->is_observed() && !object->IsJSProxy()); |
| 1831 | 1667 |
| 1832 Handle<Object> result; | 1668 Handle<Object> result; |
| (...skipping 751 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2584 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); | 2420 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); |
| 2585 } | 2421 } |
| 2586 } | 2422 } |
| 2587 FixedArray* object_array = FixedArray::cast(object->elements()); | 2423 FixedArray* object_array = FixedArray::cast(object->elements()); |
| 2588 object_array->set(store_index, *value); | 2424 object_array->set(store_index, *value); |
| 2589 } | 2425 } |
| 2590 return *object; | 2426 return *object; |
| 2591 } | 2427 } |
| 2592 | 2428 |
| 2593 | 2429 |
| 2594 // Check whether debugger and is about to step into the callback that is passed | |
| 2595 // to a built-in function such as Array.forEach. | |
| 2596 RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) { | |
| 2597 DCHECK(args.length() == 1); | |
| 2598 if (!isolate->debug()->is_active() || !isolate->debug()->StepInActive()) { | |
| 2599 return isolate->heap()->false_value(); | |
| 2600 } | |
| 2601 CONVERT_ARG_CHECKED(Object, callback, 0); | |
| 2602 // We do not step into the callback if it's a builtin or not even a function. | |
| 2603 return isolate->heap()->ToBoolean(callback->IsJSFunction() && | |
| 2604 !JSFunction::cast(callback)->IsBuiltin()); | |
| 2605 } | |
| 2606 | |
| 2607 | |
| 2608 // Set one shot breakpoints for the callback function that is passed to a | |
| 2609 // built-in function such as Array.forEach to enable stepping into the callback. | |
| 2610 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) { | |
| 2611 DCHECK(args.length() == 1); | |
| 2612 Debug* debug = isolate->debug(); | |
| 2613 if (!debug->IsStepping()) return isolate->heap()->undefined_value(); | |
| 2614 | |
| 2615 HandleScope scope(isolate); | |
| 2616 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); | |
| 2617 RUNTIME_ASSERT(object->IsJSFunction() || object->IsJSGeneratorObject()); | |
| 2618 Handle<JSFunction> fun; | |
| 2619 if (object->IsJSFunction()) { | |
| 2620 fun = Handle<JSFunction>::cast(object); | |
| 2621 } else { | |
| 2622 fun = Handle<JSFunction>( | |
| 2623 Handle<JSGeneratorObject>::cast(object)->function(), isolate); | |
| 2624 } | |
| 2625 // When leaving the function, step out has been activated, but not performed | |
| 2626 // if we do not leave the builtin. To be able to step into the function | |
| 2627 // again, we need to clear the step out at this point. | |
| 2628 debug->ClearStepOut(); | |
| 2629 debug->FloodWithOneShot(fun); | |
| 2630 return isolate->heap()->undefined_value(); | |
| 2631 } | |
| 2632 | |
| 2633 | |
| 2634 RUNTIME_FUNCTION(Runtime_DebugPushPromise) { | |
| 2635 DCHECK(args.length() == 1); | |
| 2636 HandleScope scope(isolate); | |
| 2637 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); | |
| 2638 isolate->PushPromise(promise); | |
| 2639 return isolate->heap()->undefined_value(); | |
| 2640 } | |
| 2641 | |
| 2642 | |
| 2643 RUNTIME_FUNCTION(Runtime_DebugPopPromise) { | |
| 2644 DCHECK(args.length() == 0); | |
| 2645 SealHandleScope shs(isolate); | |
| 2646 isolate->PopPromise(); | |
| 2647 return isolate->heap()->undefined_value(); | |
| 2648 } | |
| 2649 | |
| 2650 | |
| 2651 RUNTIME_FUNCTION(Runtime_DebugPromiseEvent) { | |
| 2652 DCHECK(args.length() == 1); | |
| 2653 HandleScope scope(isolate); | |
| 2654 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0); | |
| 2655 isolate->debug()->OnPromiseEvent(data); | |
| 2656 return isolate->heap()->undefined_value(); | |
| 2657 } | |
| 2658 | |
| 2659 | |
| 2660 RUNTIME_FUNCTION(Runtime_DebugPromiseRejectEvent) { | 2430 RUNTIME_FUNCTION(Runtime_DebugPromiseRejectEvent) { |
| 2661 DCHECK(args.length() == 2); | 2431 DCHECK(args.length() == 2); |
| 2662 HandleScope scope(isolate); | 2432 HandleScope scope(isolate); |
| 2663 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); | 2433 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0); |
| 2664 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); | 2434 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); |
| 2665 isolate->debug()->OnPromiseReject(promise, value); | 2435 isolate->debug()->OnPromiseReject(promise, value); |
| 2666 return isolate->heap()->undefined_value(); | 2436 return isolate->heap()->undefined_value(); |
| 2667 } | 2437 } |
| 2668 | 2438 |
| 2669 | 2439 |
| 2670 RUNTIME_FUNCTION(Runtime_DebugAsyncTaskEvent) { | |
| 2671 DCHECK(args.length() == 1); | |
| 2672 HandleScope scope(isolate); | |
| 2673 CONVERT_ARG_HANDLE_CHECKED(JSObject, data, 0); | |
| 2674 isolate->debug()->OnAsyncTaskEvent(data); | |
| 2675 return isolate->heap()->undefined_value(); | |
| 2676 } | |
| 2677 | |
| 2678 | |
| 2679 RUNTIME_FUNCTION(Runtime_DeleteProperty) { | 2440 RUNTIME_FUNCTION(Runtime_DeleteProperty) { |
| 2680 HandleScope scope(isolate); | 2441 HandleScope scope(isolate); |
| 2681 DCHECK(args.length() == 3); | 2442 DCHECK(args.length() == 3); |
| 2682 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); | 2443 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); |
| 2683 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); | 2444 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); |
| 2684 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2); | 2445 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2); |
| 2685 JSReceiver::DeleteMode delete_mode = strict_mode == STRICT | 2446 JSReceiver::DeleteMode delete_mode = strict_mode == STRICT |
| 2686 ? JSReceiver::STRICT_DELETION | 2447 ? JSReceiver::STRICT_DELETION |
| 2687 : JSReceiver::NORMAL_DELETION; | 2448 : JSReceiver::NORMAL_DELETION; |
| 2688 Handle<Object> result; | 2449 Handle<Object> result; |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3266 } | 3027 } |
| 3267 | 3028 |
| 3268 | 3029 |
| 3269 RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) { | 3030 RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) { |
| 3270 HandleScope scope(isolate); | 3031 HandleScope scope(isolate); |
| 3271 DCHECK(args.length() == 0); | 3032 DCHECK(args.length() == 0); |
| 3272 return *isolate->factory()->NewHeapNumber(0); | 3033 return *isolate->factory()->NewHeapNumber(0); |
| 3273 } | 3034 } |
| 3274 | 3035 |
| 3275 | 3036 |
| 3276 | |
| 3277 | |
| 3278 | |
| 3279 RUNTIME_FUNCTION(Runtime_DateMakeDay) { | |
| 3280 SealHandleScope shs(isolate); | |
| 3281 DCHECK(args.length() == 2); | |
| 3282 | |
| 3283 CONVERT_SMI_ARG_CHECKED(year, 0); | |
| 3284 CONVERT_SMI_ARG_CHECKED(month, 1); | |
| 3285 | |
| 3286 int days = isolate->date_cache()->DaysFromYearMonth(year, month); | |
| 3287 RUNTIME_ASSERT(Smi::IsValid(days)); | |
| 3288 return Smi::FromInt(days); | |
| 3289 } | |
| 3290 | |
| 3291 | |
| 3292 RUNTIME_FUNCTION(Runtime_DateSetValue) { | |
| 3293 HandleScope scope(isolate); | |
| 3294 DCHECK(args.length() == 3); | |
| 3295 | |
| 3296 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0); | |
| 3297 CONVERT_DOUBLE_ARG_CHECKED(time, 1); | |
| 3298 CONVERT_SMI_ARG_CHECKED(is_utc, 2); | |
| 3299 | |
| 3300 DateCache* date_cache = isolate->date_cache(); | |
| 3301 | |
| 3302 Handle<Object> value; | |
| 3303 ; | |
| 3304 bool is_value_nan = false; | |
| 3305 if (std::isnan(time)) { | |
| 3306 value = isolate->factory()->nan_value(); | |
| 3307 is_value_nan = true; | |
| 3308 } else if (!is_utc && (time < -DateCache::kMaxTimeBeforeUTCInMs || | |
| 3309 time > DateCache::kMaxTimeBeforeUTCInMs)) { | |
| 3310 value = isolate->factory()->nan_value(); | |
| 3311 is_value_nan = true; | |
| 3312 } else { | |
| 3313 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time)); | |
| 3314 if (time < -DateCache::kMaxTimeInMs || time > DateCache::kMaxTimeInMs) { | |
| 3315 value = isolate->factory()->nan_value(); | |
| 3316 is_value_nan = true; | |
| 3317 } else { | |
| 3318 value = isolate->factory()->NewNumber(DoubleToInteger(time)); | |
| 3319 } | |
| 3320 } | |
| 3321 date->SetValue(*value, is_value_nan); | |
| 3322 return *value; | |
| 3323 } | |
| 3324 | |
| 3325 | |
| 3326 static Handle<JSObject> NewSloppyArguments(Isolate* isolate, | 3037 static Handle<JSObject> NewSloppyArguments(Isolate* isolate, |
| 3327 Handle<JSFunction> callee, | 3038 Handle<JSFunction> callee, |
| 3328 Object** parameters, | 3039 Object** parameters, |
| 3329 int argument_count) { | 3040 int argument_count) { |
| 3330 Handle<JSObject> result = | 3041 Handle<JSObject> result = |
| 3331 isolate->factory()->NewArgumentsObject(callee, argument_count); | 3042 isolate->factory()->NewArgumentsObject(callee, argument_count); |
| 3332 | 3043 |
| 3333 // Allocate the elements if needed. | 3044 // Allocate the elements if needed. |
| 3334 int parameter_count = callee->shared()->formal_parameter_count(); | 3045 int parameter_count = callee->shared()->formal_parameter_count(); |
| 3335 if (argument_count > 0) { | 3046 if (argument_count > 0) { |
| (...skipping 1003 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4339 | 4050 |
| 4340 RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) { | 4051 RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) { |
| 4341 HandleScope scope(isolate); | 4052 HandleScope scope(isolate); |
| 4342 DCHECK(args.length() == 0); | 4053 DCHECK(args.length() == 0); |
| 4343 THROW_NEW_ERROR_RETURN_FAILURE( | 4054 THROW_NEW_ERROR_RETURN_FAILURE( |
| 4344 isolate, | 4055 isolate, |
| 4345 NewReferenceError("unsupported_super", HandleVector<Object>(NULL, 0))); | 4056 NewReferenceError("unsupported_super", HandleVector<Object>(NULL, 0))); |
| 4346 } | 4057 } |
| 4347 | 4058 |
| 4348 | 4059 |
| 4349 RUNTIME_FUNCTION(Runtime_ThrowNotDateError) { | |
| 4350 HandleScope scope(isolate); | |
| 4351 DCHECK(args.length() == 0); | |
| 4352 THROW_NEW_ERROR_RETURN_FAILURE( | |
| 4353 isolate, NewTypeError("not_date_object", HandleVector<Object>(NULL, 0))); | |
| 4354 } | |
| 4355 | |
| 4356 | |
| 4357 RUNTIME_FUNCTION(Runtime_StackGuard) { | 4060 RUNTIME_FUNCTION(Runtime_StackGuard) { |
| 4358 SealHandleScope shs(isolate); | 4061 SealHandleScope shs(isolate); |
| 4359 DCHECK(args.length() == 0); | 4062 DCHECK(args.length() == 0); |
| 4360 | 4063 |
| 4361 // First check if this is a real stack overflow. | 4064 // First check if this is a real stack overflow. |
| 4362 StackLimitCheck check(isolate); | 4065 StackLimitCheck check(isolate); |
| 4363 if (check.JsHasOverflowed()) { | 4066 if (check.JsHasOverflowed()) { |
| 4364 return isolate->StackOverflow(); | 4067 return isolate->StackOverflow(); |
| 4365 } | 4068 } |
| 4366 | 4069 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4415 | 4118 |
| 4416 RUNTIME_FUNCTION(Runtime_TraceExit) { | 4119 RUNTIME_FUNCTION(Runtime_TraceExit) { |
| 4417 SealHandleScope shs(isolate); | 4120 SealHandleScope shs(isolate); |
| 4418 DCHECK(args.length() == 1); | 4121 DCHECK(args.length() == 1); |
| 4419 CONVERT_ARG_CHECKED(Object, obj, 0); | 4122 CONVERT_ARG_CHECKED(Object, obj, 0); |
| 4420 PrintTransition(isolate, obj); | 4123 PrintTransition(isolate, obj); |
| 4421 return obj; // return TOS | 4124 return obj; // return TOS |
| 4422 } | 4125 } |
| 4423 | 4126 |
| 4424 | 4127 |
| 4425 RUNTIME_FUNCTION(Runtime_DateCurrentTime) { | |
| 4426 HandleScope scope(isolate); | |
| 4427 DCHECK(args.length() == 0); | |
| 4428 if (FLAG_log_timer_events) LOG(isolate, CurrentTimeEvent()); | |
| 4429 | |
| 4430 // According to ECMA-262, section 15.9.1, page 117, the precision of | |
| 4431 // the number in a Date object representing a particular instant in | |
| 4432 // time is milliseconds. Therefore, we floor the result of getting | |
| 4433 // the OS time. | |
| 4434 double millis; | |
| 4435 if (FLAG_verify_predictable) { | |
| 4436 millis = 1388534400000.0; // Jan 1 2014 00:00:00 GMT+0000 | |
| 4437 millis += Floor(isolate->heap()->synthetic_time()); | |
| 4438 } else { | |
| 4439 millis = Floor(base::OS::TimeCurrentMillis()); | |
| 4440 } | |
| 4441 return *isolate->factory()->NewNumber(millis); | |
| 4442 } | |
| 4443 | |
| 4444 | |
| 4445 RUNTIME_FUNCTION(Runtime_DateParseString) { | |
| 4446 HandleScope scope(isolate); | |
| 4447 DCHECK(args.length() == 2); | |
| 4448 CONVERT_ARG_HANDLE_CHECKED(String, str, 0); | |
| 4449 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1); | |
| 4450 | |
| 4451 RUNTIME_ASSERT(output->HasFastElements()); | |
| 4452 JSObject::EnsureCanContainHeapObjectElements(output); | |
| 4453 RUNTIME_ASSERT(output->HasFastObjectElements()); | |
| 4454 Handle<FixedArray> output_array(FixedArray::cast(output->elements())); | |
| 4455 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); | |
| 4456 | |
| 4457 str = String::Flatten(str); | |
| 4458 DisallowHeapAllocation no_gc; | |
| 4459 | |
| 4460 bool result; | |
| 4461 String::FlatContent str_content = str->GetFlatContent(); | |
| 4462 if (str_content.IsOneByte()) { | |
| 4463 result = DateParser::Parse(str_content.ToOneByteVector(), *output_array, | |
| 4464 isolate->unicode_cache()); | |
| 4465 } else { | |
| 4466 DCHECK(str_content.IsTwoByte()); | |
| 4467 result = DateParser::Parse(str_content.ToUC16Vector(), *output_array, | |
| 4468 isolate->unicode_cache()); | |
| 4469 } | |
| 4470 | |
| 4471 if (result) { | |
| 4472 return *output; | |
| 4473 } else { | |
| 4474 return isolate->heap()->null_value(); | |
| 4475 } | |
| 4476 } | |
| 4477 | |
| 4478 | |
| 4479 RUNTIME_FUNCTION(Runtime_DateLocalTimezone) { | |
| 4480 HandleScope scope(isolate); | |
| 4481 DCHECK(args.length() == 1); | |
| 4482 | |
| 4483 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
| 4484 RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs && | |
| 4485 x <= DateCache::kMaxTimeBeforeUTCInMs); | |
| 4486 const char* zone = | |
| 4487 isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x)); | |
| 4488 Handle<String> result = | |
| 4489 isolate->factory()->NewStringFromUtf8(CStrVector(zone)).ToHandleChecked(); | |
| 4490 return *result; | |
| 4491 } | |
| 4492 | |
| 4493 | |
| 4494 RUNTIME_FUNCTION(Runtime_DateToUTC) { | |
| 4495 HandleScope scope(isolate); | |
| 4496 DCHECK(args.length() == 1); | |
| 4497 | |
| 4498 CONVERT_DOUBLE_ARG_CHECKED(x, 0); | |
| 4499 RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs && | |
| 4500 x <= DateCache::kMaxTimeBeforeUTCInMs); | |
| 4501 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x)); | |
| 4502 | |
| 4503 return *isolate->factory()->NewNumber(static_cast<double>(time)); | |
| 4504 } | |
| 4505 | |
| 4506 | |
| 4507 RUNTIME_FUNCTION(Runtime_DateCacheVersion) { | |
| 4508 HandleScope hs(isolate); | |
| 4509 DCHECK(args.length() == 0); | |
| 4510 if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) { | |
| 4511 Handle<FixedArray> date_cache_version = | |
| 4512 isolate->factory()->NewFixedArray(1, TENURED); | |
| 4513 date_cache_version->set(0, Smi::FromInt(0)); | |
| 4514 isolate->eternal_handles()->CreateSingleton( | |
| 4515 isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION); | |
| 4516 } | |
| 4517 Handle<FixedArray> date_cache_version = | |
| 4518 Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton( | |
| 4519 EternalHandles::DATE_CACHE_VERSION)); | |
| 4520 // Return result as a JS array. | |
| 4521 Handle<JSObject> result = | |
| 4522 isolate->factory()->NewJSObject(isolate->array_function()); | |
| 4523 JSArray::SetContent(Handle<JSArray>::cast(result), date_cache_version); | |
| 4524 return *result; | |
| 4525 } | |
| 4526 | |
| 4527 | |
| 4528 RUNTIME_FUNCTION(Runtime_GlobalProxy) { | 4128 RUNTIME_FUNCTION(Runtime_GlobalProxy) { |
| 4529 SealHandleScope shs(isolate); | 4129 SealHandleScope shs(isolate); |
| 4530 DCHECK(args.length() == 1); | 4130 DCHECK(args.length() == 1); |
| 4531 CONVERT_ARG_CHECKED(Object, global, 0); | 4131 CONVERT_ARG_CHECKED(Object, global, 0); |
| 4532 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value(); | 4132 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value(); |
| 4533 return JSGlobalObject::cast(global)->global_proxy(); | 4133 return JSGlobalObject::cast(global)->global_proxy(); |
| 4534 } | 4134 } |
| 4535 | 4135 |
| 4536 | 4136 |
| 4537 RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) { | 4137 RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) { |
| (...skipping 879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5417 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER; | 5017 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER; |
| 5418 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value(); | 5018 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value(); |
| 5419 Handle<Object> result; | 5019 Handle<Object> result; |
| 5420 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 5020 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 5421 isolate, result, | 5021 isolate, result, |
| 5422 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component)); | 5022 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component)); |
| 5423 return *result; | 5023 return *result; |
| 5424 } | 5024 } |
| 5425 | 5025 |
| 5426 | 5026 |
| 5427 RUNTIME_FUNCTION(Runtime_DebugBreak) { | |
| 5428 SealHandleScope shs(isolate); | |
| 5429 DCHECK(args.length() == 0); | |
| 5430 isolate->debug()->HandleDebugBreak(); | |
| 5431 return isolate->heap()->undefined_value(); | |
| 5432 } | |
| 5433 | |
| 5434 | |
| 5435 // Helper functions for wrapping and unwrapping stack frame ids. | |
| 5436 static Smi* WrapFrameId(StackFrame::Id id) { | |
| 5437 DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4))); | |
| 5438 return Smi::FromInt(id >> 2); | |
| 5439 } | |
| 5440 | |
| 5441 | |
| 5442 static StackFrame::Id UnwrapFrameId(int wrapped) { | |
| 5443 return static_cast<StackFrame::Id>(wrapped << 2); | |
| 5444 } | |
| 5445 | |
| 5446 | |
| 5447 // Adds a JavaScript function as a debug event listener. | |
| 5448 // args[0]: debug event listener function to set or null or undefined for | |
| 5449 // clearing the event listener function | |
| 5450 // args[1]: object supplied during callback | |
| 5451 RUNTIME_FUNCTION(Runtime_SetDebugEventListener) { | |
| 5452 SealHandleScope shs(isolate); | |
| 5453 DCHECK(args.length() == 2); | |
| 5454 RUNTIME_ASSERT(args[0]->IsJSFunction() || args[0]->IsUndefined() || | |
| 5455 args[0]->IsNull()); | |
| 5456 CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0); | |
| 5457 CONVERT_ARG_HANDLE_CHECKED(Object, data, 1); | |
| 5458 isolate->debug()->SetEventListener(callback, data); | |
| 5459 | |
| 5460 return isolate->heap()->undefined_value(); | |
| 5461 } | |
| 5462 | |
| 5463 | |
| 5464 RUNTIME_FUNCTION(Runtime_Break) { | |
| 5465 SealHandleScope shs(isolate); | |
| 5466 DCHECK(args.length() == 0); | |
| 5467 isolate->stack_guard()->RequestDebugBreak(); | |
| 5468 return isolate->heap()->undefined_value(); | |
| 5469 } | |
| 5470 | |
| 5471 | |
| 5472 static Handle<Object> DebugGetProperty(LookupIterator* it, | |
| 5473 bool* has_caught = NULL) { | |
| 5474 for (; it->IsFound(); it->Next()) { | |
| 5475 switch (it->state()) { | |
| 5476 case LookupIterator::NOT_FOUND: | |
| 5477 case LookupIterator::TRANSITION: | |
| 5478 UNREACHABLE(); | |
| 5479 case LookupIterator::ACCESS_CHECK: | |
| 5480 // Ignore access checks. | |
| 5481 break; | |
| 5482 case LookupIterator::INTERCEPTOR: | |
| 5483 case LookupIterator::JSPROXY: | |
| 5484 return it->isolate()->factory()->undefined_value(); | |
| 5485 case LookupIterator::ACCESSOR: { | |
| 5486 Handle<Object> accessors = it->GetAccessors(); | |
| 5487 if (!accessors->IsAccessorInfo()) { | |
| 5488 return it->isolate()->factory()->undefined_value(); | |
| 5489 } | |
| 5490 MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithAccessor( | |
| 5491 it->GetReceiver(), it->name(), it->GetHolder<JSObject>(), | |
| 5492 accessors); | |
| 5493 Handle<Object> result; | |
| 5494 if (!maybe_result.ToHandle(&result)) { | |
| 5495 result = handle(it->isolate()->pending_exception(), it->isolate()); | |
| 5496 it->isolate()->clear_pending_exception(); | |
| 5497 if (has_caught != NULL) *has_caught = true; | |
| 5498 } | |
| 5499 return result; | |
| 5500 } | |
| 5501 | |
| 5502 case LookupIterator::DATA: | |
| 5503 return it->GetDataValue(); | |
| 5504 } | |
| 5505 } | |
| 5506 | |
| 5507 return it->isolate()->factory()->undefined_value(); | |
| 5508 } | |
| 5509 | |
| 5510 | |
| 5511 // Get debugger related details for an object property, in the following format: | |
| 5512 // 0: Property value | |
| 5513 // 1: Property details | |
| 5514 // 2: Property value is exception | |
| 5515 // 3: Getter function if defined | |
| 5516 // 4: Setter function if defined | |
| 5517 // Items 2-4 are only filled if the property has either a getter or a setter. | |
| 5518 RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) { | |
| 5519 HandleScope scope(isolate); | |
| 5520 | |
| 5521 DCHECK(args.length() == 2); | |
| 5522 | |
| 5523 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
| 5524 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
| 5525 | |
| 5526 // Make sure to set the current context to the context before the debugger was | |
| 5527 // entered (if the debugger is entered). The reason for switching context here | |
| 5528 // is that for some property lookups (accessors and interceptors) callbacks | |
| 5529 // into the embedding application can occour, and the embedding application | |
| 5530 // could have the assumption that its own native context is the current | |
| 5531 // context and not some internal debugger context. | |
| 5532 SaveContext save(isolate); | |
| 5533 if (isolate->debug()->in_debug_scope()) { | |
| 5534 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); | |
| 5535 } | |
| 5536 | |
| 5537 // Check if the name is trivially convertible to an index and get the element | |
| 5538 // if so. | |
| 5539 uint32_t index; | |
| 5540 if (name->AsArrayIndex(&index)) { | |
| 5541 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); | |
| 5542 Handle<Object> element_or_char; | |
| 5543 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 5544 isolate, element_or_char, | |
| 5545 Runtime::GetElementOrCharAt(isolate, obj, index)); | |
| 5546 details->set(0, *element_or_char); | |
| 5547 details->set(1, | |
| 5548 PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi()); | |
| 5549 return *isolate->factory()->NewJSArrayWithElements(details); | |
| 5550 } | |
| 5551 | |
| 5552 LookupIterator it(obj, name, LookupIterator::HIDDEN); | |
| 5553 bool has_caught = false; | |
| 5554 Handle<Object> value = DebugGetProperty(&it, &has_caught); | |
| 5555 if (!it.IsFound()) return isolate->heap()->undefined_value(); | |
| 5556 | |
| 5557 Handle<Object> maybe_pair; | |
| 5558 if (it.state() == LookupIterator::ACCESSOR) { | |
| 5559 maybe_pair = it.GetAccessors(); | |
| 5560 } | |
| 5561 | |
| 5562 // If the callback object is a fixed array then it contains JavaScript | |
| 5563 // getter and/or setter. | |
| 5564 bool has_js_accessors = !maybe_pair.is_null() && maybe_pair->IsAccessorPair(); | |
| 5565 Handle<FixedArray> details = | |
| 5566 isolate->factory()->NewFixedArray(has_js_accessors ? 6 : 3); | |
| 5567 details->set(0, *value); | |
| 5568 // TODO(verwaest): Get rid of this random way of handling interceptors. | |
| 5569 PropertyDetails d = it.state() == LookupIterator::INTERCEPTOR | |
| 5570 ? PropertyDetails(NONE, NORMAL, 0) | |
| 5571 : it.property_details(); | |
| 5572 details->set(1, d.AsSmi()); | |
| 5573 details->set( | |
| 5574 2, isolate->heap()->ToBoolean(it.state() == LookupIterator::INTERCEPTOR)); | |
| 5575 if (has_js_accessors) { | |
| 5576 AccessorPair* accessors = AccessorPair::cast(*maybe_pair); | |
| 5577 details->set(3, isolate->heap()->ToBoolean(has_caught)); | |
| 5578 details->set(4, accessors->GetComponent(ACCESSOR_GETTER)); | |
| 5579 details->set(5, accessors->GetComponent(ACCESSOR_SETTER)); | |
| 5580 } | |
| 5581 | |
| 5582 return *isolate->factory()->NewJSArrayWithElements(details); | |
| 5583 } | |
| 5584 | |
| 5585 | |
| 5586 RUNTIME_FUNCTION(Runtime_DebugGetProperty) { | |
| 5587 HandleScope scope(isolate); | |
| 5588 | |
| 5589 DCHECK(args.length() == 2); | |
| 5590 | |
| 5591 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
| 5592 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
| 5593 | |
| 5594 LookupIterator it(obj, name); | |
| 5595 return *DebugGetProperty(&it); | |
| 5596 } | |
| 5597 | |
| 5598 | |
| 5599 // Return the property type calculated from the property details. | |
| 5600 // args[0]: smi with property details. | |
| 5601 RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) { | |
| 5602 SealHandleScope shs(isolate); | |
| 5603 DCHECK(args.length() == 1); | |
| 5604 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); | |
| 5605 return Smi::FromInt(static_cast<int>(details.type())); | |
| 5606 } | |
| 5607 | |
| 5608 | |
| 5609 // Return the property attribute calculated from the property details. | |
| 5610 // args[0]: smi with property details. | |
| 5611 RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) { | |
| 5612 SealHandleScope shs(isolate); | |
| 5613 DCHECK(args.length() == 1); | |
| 5614 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); | |
| 5615 return Smi::FromInt(static_cast<int>(details.attributes())); | |
| 5616 } | |
| 5617 | |
| 5618 | |
| 5619 // Return the property insertion index calculated from the property details. | |
| 5620 // args[0]: smi with property details. | |
| 5621 RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) { | |
| 5622 SealHandleScope shs(isolate); | |
| 5623 DCHECK(args.length() == 1); | |
| 5624 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); | |
| 5625 // TODO(verwaest): Depends on the type of details. | |
| 5626 return Smi::FromInt(details.dictionary_index()); | |
| 5627 } | |
| 5628 | |
| 5629 | |
| 5630 // Return property value from named interceptor. | |
| 5631 // args[0]: object | |
| 5632 // args[1]: property name | |
| 5633 RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) { | |
| 5634 HandleScope scope(isolate); | |
| 5635 DCHECK(args.length() == 2); | |
| 5636 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
| 5637 RUNTIME_ASSERT(obj->HasNamedInterceptor()); | |
| 5638 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); | |
| 5639 | |
| 5640 Handle<Object> result; | |
| 5641 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | |
| 5642 JSObject::GetProperty(obj, name)); | |
| 5643 return *result; | |
| 5644 } | |
| 5645 | |
| 5646 | |
| 5647 // Return element value from indexed interceptor. | |
| 5648 // args[0]: object | |
| 5649 // args[1]: index | |
| 5650 RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) { | |
| 5651 HandleScope scope(isolate); | |
| 5652 DCHECK(args.length() == 2); | |
| 5653 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
| 5654 RUNTIME_ASSERT(obj->HasIndexedInterceptor()); | |
| 5655 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); | |
| 5656 Handle<Object> result; | |
| 5657 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 5658 isolate, result, JSObject::GetElementWithInterceptor(obj, obj, index)); | |
| 5659 return *result; | |
| 5660 } | |
| 5661 | |
| 5662 | |
| 5663 static bool CheckExecutionState(Isolate* isolate, int break_id) { | |
| 5664 return !isolate->debug()->debug_context().is_null() && | |
| 5665 isolate->debug()->break_id() != 0 && | |
| 5666 isolate->debug()->break_id() == break_id; | |
| 5667 } | |
| 5668 | |
| 5669 | |
| 5670 RUNTIME_FUNCTION(Runtime_CheckExecutionState) { | |
| 5671 SealHandleScope shs(isolate); | |
| 5672 DCHECK(args.length() == 1); | |
| 5673 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 5674 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 5675 return isolate->heap()->true_value(); | |
| 5676 } | |
| 5677 | |
| 5678 | |
| 5679 RUNTIME_FUNCTION(Runtime_GetFrameCount) { | |
| 5680 HandleScope scope(isolate); | |
| 5681 DCHECK(args.length() == 1); | |
| 5682 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 5683 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 5684 | |
| 5685 // Count all frames which are relevant to debugging stack trace. | |
| 5686 int n = 0; | |
| 5687 StackFrame::Id id = isolate->debug()->break_frame_id(); | |
| 5688 if (id == StackFrame::NO_ID) { | |
| 5689 // If there is no JavaScript stack frame count is 0. | |
| 5690 return Smi::FromInt(0); | |
| 5691 } | |
| 5692 | |
| 5693 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) { | |
| 5694 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | |
| 5695 it.frame()->Summarize(&frames); | |
| 5696 for (int i = frames.length() - 1; i >= 0; i--) { | |
| 5697 // Omit functions from native scripts. | |
| 5698 if (!frames[i].function()->IsFromNativeScript()) n++; | |
| 5699 } | |
| 5700 } | |
| 5701 return Smi::FromInt(n); | |
| 5702 } | |
| 5703 | |
| 5704 | |
| 5705 class FrameInspector { | |
| 5706 public: | |
| 5707 FrameInspector(JavaScriptFrame* frame, int inlined_jsframe_index, | |
| 5708 Isolate* isolate) | |
| 5709 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) { | |
| 5710 // Calculate the deoptimized frame. | |
| 5711 if (frame->is_optimized()) { | |
| 5712 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame( | |
| 5713 frame, inlined_jsframe_index, isolate); | |
| 5714 } | |
| 5715 has_adapted_arguments_ = frame_->has_adapted_arguments(); | |
| 5716 is_bottommost_ = inlined_jsframe_index == 0; | |
| 5717 is_optimized_ = frame_->is_optimized(); | |
| 5718 } | |
| 5719 | |
| 5720 ~FrameInspector() { | |
| 5721 // Get rid of the calculated deoptimized frame if any. | |
| 5722 if (deoptimized_frame_ != NULL) { | |
| 5723 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_); | |
| 5724 } | |
| 5725 } | |
| 5726 | |
| 5727 int GetParametersCount() { | |
| 5728 return is_optimized_ ? deoptimized_frame_->parameters_count() | |
| 5729 : frame_->ComputeParametersCount(); | |
| 5730 } | |
| 5731 int expression_count() { return deoptimized_frame_->expression_count(); } | |
| 5732 Object* GetFunction() { | |
| 5733 return is_optimized_ ? deoptimized_frame_->GetFunction() | |
| 5734 : frame_->function(); | |
| 5735 } | |
| 5736 Object* GetParameter(int index) { | |
| 5737 return is_optimized_ ? deoptimized_frame_->GetParameter(index) | |
| 5738 : frame_->GetParameter(index); | |
| 5739 } | |
| 5740 Object* GetExpression(int index) { | |
| 5741 return is_optimized_ ? deoptimized_frame_->GetExpression(index) | |
| 5742 : frame_->GetExpression(index); | |
| 5743 } | |
| 5744 int GetSourcePosition() { | |
| 5745 return is_optimized_ ? deoptimized_frame_->GetSourcePosition() | |
| 5746 : frame_->LookupCode()->SourcePosition(frame_->pc()); | |
| 5747 } | |
| 5748 bool IsConstructor() { | |
| 5749 return is_optimized_ && !is_bottommost_ | |
| 5750 ? deoptimized_frame_->HasConstructStub() | |
| 5751 : frame_->IsConstructor(); | |
| 5752 } | |
| 5753 Object* GetContext() { | |
| 5754 return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context(); | |
| 5755 } | |
| 5756 | |
| 5757 // To inspect all the provided arguments the frame might need to be | |
| 5758 // replaced with the arguments frame. | |
| 5759 void SetArgumentsFrame(JavaScriptFrame* frame) { | |
| 5760 DCHECK(has_adapted_arguments_); | |
| 5761 frame_ = frame; | |
| 5762 is_optimized_ = frame_->is_optimized(); | |
| 5763 DCHECK(!is_optimized_); | |
| 5764 } | |
| 5765 | |
| 5766 private: | |
| 5767 JavaScriptFrame* frame_; | |
| 5768 DeoptimizedFrameInfo* deoptimized_frame_; | |
| 5769 Isolate* isolate_; | |
| 5770 bool is_optimized_; | |
| 5771 bool is_bottommost_; | |
| 5772 bool has_adapted_arguments_; | |
| 5773 | |
| 5774 DISALLOW_COPY_AND_ASSIGN(FrameInspector); | |
| 5775 }; | |
| 5776 | |
| 5777 | |
| 5778 static const int kFrameDetailsFrameIdIndex = 0; | |
| 5779 static const int kFrameDetailsReceiverIndex = 1; | |
| 5780 static const int kFrameDetailsFunctionIndex = 2; | |
| 5781 static const int kFrameDetailsArgumentCountIndex = 3; | |
| 5782 static const int kFrameDetailsLocalCountIndex = 4; | |
| 5783 static const int kFrameDetailsSourcePositionIndex = 5; | |
| 5784 static const int kFrameDetailsConstructCallIndex = 6; | |
| 5785 static const int kFrameDetailsAtReturnIndex = 7; | |
| 5786 static const int kFrameDetailsFlagsIndex = 8; | |
| 5787 static const int kFrameDetailsFirstDynamicIndex = 9; | |
| 5788 | |
| 5789 | |
| 5790 static SaveContext* FindSavedContextForFrame(Isolate* isolate, | |
| 5791 JavaScriptFrame* frame) { | |
| 5792 SaveContext* save = isolate->save_context(); | |
| 5793 while (save != NULL && !save->IsBelowFrame(frame)) { | |
| 5794 save = save->prev(); | |
| 5795 } | |
| 5796 DCHECK(save != NULL); | |
| 5797 return save; | |
| 5798 } | |
| 5799 | |
| 5800 | |
| 5801 // Advances the iterator to the frame that matches the index and returns the | |
| 5802 // inlined frame index, or -1 if not found. Skips native JS functions. | |
| 5803 static int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index) { | |
| 5804 int count = -1; | |
| 5805 for (; !it->done(); it->Advance()) { | |
| 5806 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | |
| 5807 it->frame()->Summarize(&frames); | |
| 5808 for (int i = frames.length() - 1; i >= 0; i--) { | |
| 5809 // Omit functions from native scripts. | |
| 5810 if (frames[i].function()->IsFromNativeScript()) continue; | |
| 5811 if (++count == index) return i; | |
| 5812 } | |
| 5813 } | |
| 5814 return -1; | |
| 5815 } | |
| 5816 | |
| 5817 | |
| 5818 // Return an array with frame details | |
| 5819 // args[0]: number: break id | |
| 5820 // args[1]: number: frame index | |
| 5821 // | |
| 5822 // The array returned contains the following information: | |
| 5823 // 0: Frame id | |
| 5824 // 1: Receiver | |
| 5825 // 2: Function | |
| 5826 // 3: Argument count | |
| 5827 // 4: Local count | |
| 5828 // 5: Source position | |
| 5829 // 6: Constructor call | |
| 5830 // 7: Is at return | |
| 5831 // 8: Flags | |
| 5832 // Arguments name, value | |
| 5833 // Locals name, value | |
| 5834 // Return value if any | |
| 5835 RUNTIME_FUNCTION(Runtime_GetFrameDetails) { | |
| 5836 HandleScope scope(isolate); | |
| 5837 DCHECK(args.length() == 2); | |
| 5838 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 5839 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 5840 | |
| 5841 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); | |
| 5842 Heap* heap = isolate->heap(); | |
| 5843 | |
| 5844 // Find the relevant frame with the requested index. | |
| 5845 StackFrame::Id id = isolate->debug()->break_frame_id(); | |
| 5846 if (id == StackFrame::NO_ID) { | |
| 5847 // If there are no JavaScript stack frames return undefined. | |
| 5848 return heap->undefined_value(); | |
| 5849 } | |
| 5850 | |
| 5851 JavaScriptFrameIterator it(isolate, id); | |
| 5852 // Inlined frame index in optimized frame, starting from outer function. | |
| 5853 int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index); | |
| 5854 if (inlined_jsframe_index == -1) return heap->undefined_value(); | |
| 5855 | |
| 5856 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate); | |
| 5857 bool is_optimized = it.frame()->is_optimized(); | |
| 5858 | |
| 5859 // Traverse the saved contexts chain to find the active context for the | |
| 5860 // selected frame. | |
| 5861 SaveContext* save = FindSavedContextForFrame(isolate, it.frame()); | |
| 5862 | |
| 5863 // Get the frame id. | |
| 5864 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate); | |
| 5865 | |
| 5866 // Find source position in unoptimized code. | |
| 5867 int position = frame_inspector.GetSourcePosition(); | |
| 5868 | |
| 5869 // Check for constructor frame. | |
| 5870 bool constructor = frame_inspector.IsConstructor(); | |
| 5871 | |
| 5872 // Get scope info and read from it for local variable information. | |
| 5873 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); | |
| 5874 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 5875 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 5876 DCHECK(*scope_info != ScopeInfo::Empty(isolate)); | |
| 5877 | |
| 5878 // Get the locals names and values into a temporary array. | |
| 5879 int local_count = scope_info->LocalCount(); | |
| 5880 for (int slot = 0; slot < scope_info->LocalCount(); ++slot) { | |
| 5881 // Hide compiler-introduced temporary variables, whether on the stack or on | |
| 5882 // the context. | |
| 5883 if (scope_info->LocalIsSynthetic(slot)) local_count--; | |
| 5884 } | |
| 5885 | |
| 5886 Handle<FixedArray> locals = | |
| 5887 isolate->factory()->NewFixedArray(local_count * 2); | |
| 5888 | |
| 5889 // Fill in the values of the locals. | |
| 5890 int local = 0; | |
| 5891 int i = 0; | |
| 5892 for (; i < scope_info->StackLocalCount(); ++i) { | |
| 5893 // Use the value from the stack. | |
| 5894 if (scope_info->LocalIsSynthetic(i)) continue; | |
| 5895 locals->set(local * 2, scope_info->LocalName(i)); | |
| 5896 locals->set(local * 2 + 1, frame_inspector.GetExpression(i)); | |
| 5897 local++; | |
| 5898 } | |
| 5899 if (local < local_count) { | |
| 5900 // Get the context containing declarations. | |
| 5901 Handle<Context> context( | |
| 5902 Context::cast(frame_inspector.GetContext())->declaration_context()); | |
| 5903 for (; i < scope_info->LocalCount(); ++i) { | |
| 5904 if (scope_info->LocalIsSynthetic(i)) continue; | |
| 5905 Handle<String> name(scope_info->LocalName(i)); | |
| 5906 VariableMode mode; | |
| 5907 InitializationFlag init_flag; | |
| 5908 MaybeAssignedFlag maybe_assigned_flag; | |
| 5909 locals->set(local * 2, *name); | |
| 5910 int context_slot_index = ScopeInfo::ContextSlotIndex( | |
| 5911 scope_info, name, &mode, &init_flag, &maybe_assigned_flag); | |
| 5912 Object* value = context->get(context_slot_index); | |
| 5913 locals->set(local * 2 + 1, value); | |
| 5914 local++; | |
| 5915 } | |
| 5916 } | |
| 5917 | |
| 5918 // Check whether this frame is positioned at return. If not top | |
| 5919 // frame or if the frame is optimized it cannot be at a return. | |
| 5920 bool at_return = false; | |
| 5921 if (!is_optimized && index == 0) { | |
| 5922 at_return = isolate->debug()->IsBreakAtReturn(it.frame()); | |
| 5923 } | |
| 5924 | |
| 5925 // If positioned just before return find the value to be returned and add it | |
| 5926 // to the frame information. | |
| 5927 Handle<Object> return_value = isolate->factory()->undefined_value(); | |
| 5928 if (at_return) { | |
| 5929 StackFrameIterator it2(isolate); | |
| 5930 Address internal_frame_sp = NULL; | |
| 5931 while (!it2.done()) { | |
| 5932 if (it2.frame()->is_internal()) { | |
| 5933 internal_frame_sp = it2.frame()->sp(); | |
| 5934 } else { | |
| 5935 if (it2.frame()->is_java_script()) { | |
| 5936 if (it2.frame()->id() == it.frame()->id()) { | |
| 5937 // The internal frame just before the JavaScript frame contains the | |
| 5938 // value to return on top. A debug break at return will create an | |
| 5939 // internal frame to store the return value (eax/rax/r0) before | |
| 5940 // entering the debug break exit frame. | |
| 5941 if (internal_frame_sp != NULL) { | |
| 5942 return_value = | |
| 5943 Handle<Object>(Memory::Object_at(internal_frame_sp), isolate); | |
| 5944 break; | |
| 5945 } | |
| 5946 } | |
| 5947 } | |
| 5948 | |
| 5949 // Indicate that the previous frame was not an internal frame. | |
| 5950 internal_frame_sp = NULL; | |
| 5951 } | |
| 5952 it2.Advance(); | |
| 5953 } | |
| 5954 } | |
| 5955 | |
| 5956 // Now advance to the arguments adapter frame (if any). It contains all | |
| 5957 // the provided parameters whereas the function frame always have the number | |
| 5958 // of arguments matching the functions parameters. The rest of the | |
| 5959 // information (except for what is collected above) is the same. | |
| 5960 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) { | |
| 5961 it.AdvanceToArgumentsFrame(); | |
| 5962 frame_inspector.SetArgumentsFrame(it.frame()); | |
| 5963 } | |
| 5964 | |
| 5965 // Find the number of arguments to fill. At least fill the number of | |
| 5966 // parameters for the function and fill more if more parameters are provided. | |
| 5967 int argument_count = scope_info->ParameterCount(); | |
| 5968 if (argument_count < frame_inspector.GetParametersCount()) { | |
| 5969 argument_count = frame_inspector.GetParametersCount(); | |
| 5970 } | |
| 5971 | |
| 5972 // Calculate the size of the result. | |
| 5973 int details_size = kFrameDetailsFirstDynamicIndex + | |
| 5974 2 * (argument_count + local_count) + (at_return ? 1 : 0); | |
| 5975 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); | |
| 5976 | |
| 5977 // Add the frame id. | |
| 5978 details->set(kFrameDetailsFrameIdIndex, *frame_id); | |
| 5979 | |
| 5980 // Add the function (same as in function frame). | |
| 5981 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction()); | |
| 5982 | |
| 5983 // Add the arguments count. | |
| 5984 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); | |
| 5985 | |
| 5986 // Add the locals count | |
| 5987 details->set(kFrameDetailsLocalCountIndex, Smi::FromInt(local_count)); | |
| 5988 | |
| 5989 // Add the source position. | |
| 5990 if (position != RelocInfo::kNoPosition) { | |
| 5991 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); | |
| 5992 } else { | |
| 5993 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value()); | |
| 5994 } | |
| 5995 | |
| 5996 // Add the constructor information. | |
| 5997 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor)); | |
| 5998 | |
| 5999 // Add the at return information. | |
| 6000 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); | |
| 6001 | |
| 6002 // Add flags to indicate information on whether this frame is | |
| 6003 // bit 0: invoked in the debugger context. | |
| 6004 // bit 1: optimized frame. | |
| 6005 // bit 2: inlined in optimized frame | |
| 6006 int flags = 0; | |
| 6007 if (*save->context() == *isolate->debug()->debug_context()) { | |
| 6008 flags |= 1 << 0; | |
| 6009 } | |
| 6010 if (is_optimized) { | |
| 6011 flags |= 1 << 1; | |
| 6012 flags |= inlined_jsframe_index << 2; | |
| 6013 } | |
| 6014 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); | |
| 6015 | |
| 6016 // Fill the dynamic part. | |
| 6017 int details_index = kFrameDetailsFirstDynamicIndex; | |
| 6018 | |
| 6019 // Add arguments name and value. | |
| 6020 for (int i = 0; i < argument_count; i++) { | |
| 6021 // Name of the argument. | |
| 6022 if (i < scope_info->ParameterCount()) { | |
| 6023 details->set(details_index++, scope_info->ParameterName(i)); | |
| 6024 } else { | |
| 6025 details->set(details_index++, heap->undefined_value()); | |
| 6026 } | |
| 6027 | |
| 6028 // Parameter value. | |
| 6029 if (i < frame_inspector.GetParametersCount()) { | |
| 6030 // Get the value from the stack. | |
| 6031 details->set(details_index++, frame_inspector.GetParameter(i)); | |
| 6032 } else { | |
| 6033 details->set(details_index++, heap->undefined_value()); | |
| 6034 } | |
| 6035 } | |
| 6036 | |
| 6037 // Add locals name and value from the temporary copy from the function frame. | |
| 6038 for (int i = 0; i < local_count * 2; i++) { | |
| 6039 details->set(details_index++, locals->get(i)); | |
| 6040 } | |
| 6041 | |
| 6042 // Add the value being returned. | |
| 6043 if (at_return) { | |
| 6044 details->set(details_index++, *return_value); | |
| 6045 } | |
| 6046 | |
| 6047 // Add the receiver (same as in function frame). | |
| 6048 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE | |
| 6049 // THE FRAME ITERATOR TO WRAP THE RECEIVER. | |
| 6050 Handle<Object> receiver(it.frame()->receiver(), isolate); | |
| 6051 if (!receiver->IsJSObject() && shared->strict_mode() == SLOPPY && | |
| 6052 !function->IsBuiltin()) { | |
| 6053 // If the receiver is not a JSObject and the function is not a | |
| 6054 // builtin or strict-mode we have hit an optimization where a | |
| 6055 // value object is not converted into a wrapped JS objects. To | |
| 6056 // hide this optimization from the debugger, we wrap the receiver | |
| 6057 // by creating correct wrapper object based on the calling frame's | |
| 6058 // native context. | |
| 6059 it.Advance(); | |
| 6060 if (receiver->IsUndefined()) { | |
| 6061 receiver = handle(function->global_proxy()); | |
| 6062 } else { | |
| 6063 Context* context = Context::cast(it.frame()->context()); | |
| 6064 Handle<Context> native_context(Context::cast(context->native_context())); | |
| 6065 if (!Object::ToObject(isolate, receiver, native_context) | |
| 6066 .ToHandle(&receiver)) { | |
| 6067 // This only happens if the receiver is forcibly set in %_CallFunction. | |
| 6068 return heap->undefined_value(); | |
| 6069 } | |
| 6070 } | |
| 6071 } | |
| 6072 details->set(kFrameDetailsReceiverIndex, *receiver); | |
| 6073 | |
| 6074 DCHECK_EQ(details_size, details_index); | |
| 6075 return *isolate->factory()->NewJSArrayWithElements(details); | |
| 6076 } | |
| 6077 | |
| 6078 | |
| 6079 static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info, | |
| 6080 Handle<String> parameter_name) { | |
| 6081 VariableMode mode; | |
| 6082 InitializationFlag init_flag; | |
| 6083 MaybeAssignedFlag maybe_assigned_flag; | |
| 6084 return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag, | |
| 6085 &maybe_assigned_flag) != -1; | |
| 6086 } | |
| 6087 | |
| 6088 | |
| 6089 // Create a plain JSObject which materializes the local scope for the specified | |
| 6090 // frame. | |
| 6091 MUST_USE_RESULT | |
| 6092 static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector( | |
| 6093 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function, | |
| 6094 FrameInspector* frame_inspector) { | |
| 6095 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 6096 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 6097 | |
| 6098 // First fill all parameters. | |
| 6099 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | |
| 6100 // Do not materialize the parameter if it is shadowed by a context local. | |
| 6101 Handle<String> name(scope_info->ParameterName(i)); | |
| 6102 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; | |
| 6103 | |
| 6104 HandleScope scope(isolate); | |
| 6105 Handle<Object> value(i < frame_inspector->GetParametersCount() | |
| 6106 ? frame_inspector->GetParameter(i) | |
| 6107 : isolate->heap()->undefined_value(), | |
| 6108 isolate); | |
| 6109 DCHECK(!value->IsTheHole()); | |
| 6110 | |
| 6111 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty( | |
| 6112 isolate, target, name, value, SLOPPY), | |
| 6113 JSObject); | |
| 6114 } | |
| 6115 | |
| 6116 // Second fill all stack locals. | |
| 6117 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
| 6118 if (scope_info->LocalIsSynthetic(i)) continue; | |
| 6119 Handle<String> name(scope_info->StackLocalName(i)); | |
| 6120 Handle<Object> value(frame_inspector->GetExpression(i), isolate); | |
| 6121 if (value->IsTheHole()) continue; | |
| 6122 | |
| 6123 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty( | |
| 6124 isolate, target, name, value, SLOPPY), | |
| 6125 JSObject); | |
| 6126 } | |
| 6127 | |
| 6128 return target; | |
| 6129 } | |
| 6130 | |
| 6131 | |
| 6132 static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate, | |
| 6133 Handle<JSObject> target, | |
| 6134 Handle<JSFunction> function, | |
| 6135 JavaScriptFrame* frame, | |
| 6136 int inlined_jsframe_index) { | |
| 6137 if (inlined_jsframe_index != 0 || frame->is_optimized()) { | |
| 6138 // Optimized frames are not supported. | |
| 6139 // TODO(yangguo): make sure all code deoptimized when debugger is active | |
| 6140 // and assert that this cannot happen. | |
| 6141 return; | |
| 6142 } | |
| 6143 | |
| 6144 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 6145 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 6146 | |
| 6147 // Parameters. | |
| 6148 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | |
| 6149 // Shadowed parameters were not materialized. | |
| 6150 Handle<String> name(scope_info->ParameterName(i)); | |
| 6151 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; | |
| 6152 | |
| 6153 DCHECK(!frame->GetParameter(i)->IsTheHole()); | |
| 6154 HandleScope scope(isolate); | |
| 6155 Handle<Object> value = | |
| 6156 Object::GetPropertyOrElement(target, name).ToHandleChecked(); | |
| 6157 frame->SetParameterValue(i, *value); | |
| 6158 } | |
| 6159 | |
| 6160 // Stack locals. | |
| 6161 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
| 6162 if (scope_info->LocalIsSynthetic(i)) continue; | |
| 6163 if (frame->GetExpression(i)->IsTheHole()) continue; | |
| 6164 HandleScope scope(isolate); | |
| 6165 Handle<Object> value = Object::GetPropertyOrElement( | |
| 6166 target, handle(scope_info->StackLocalName(i), | |
| 6167 isolate)).ToHandleChecked(); | |
| 6168 frame->SetExpression(i, *value); | |
| 6169 } | |
| 6170 } | |
| 6171 | |
| 6172 | |
| 6173 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext( | |
| 6174 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function, | |
| 6175 JavaScriptFrame* frame) { | |
| 6176 HandleScope scope(isolate); | |
| 6177 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 6178 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 6179 | |
| 6180 if (!scope_info->HasContext()) return target; | |
| 6181 | |
| 6182 // Third fill all context locals. | |
| 6183 Handle<Context> frame_context(Context::cast(frame->context())); | |
| 6184 Handle<Context> function_context(frame_context->declaration_context()); | |
| 6185 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, function_context, | |
| 6186 target)) { | |
| 6187 return MaybeHandle<JSObject>(); | |
| 6188 } | |
| 6189 | |
| 6190 // Finally copy any properties from the function context extension. | |
| 6191 // These will be variables introduced by eval. | |
| 6192 if (function_context->closure() == *function) { | |
| 6193 if (function_context->has_extension() && | |
| 6194 !function_context->IsNativeContext()) { | |
| 6195 Handle<JSObject> ext(JSObject::cast(function_context->extension())); | |
| 6196 Handle<FixedArray> keys; | |
| 6197 ASSIGN_RETURN_ON_EXCEPTION( | |
| 6198 isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), | |
| 6199 JSObject); | |
| 6200 | |
| 6201 for (int i = 0; i < keys->length(); i++) { | |
| 6202 // Names of variables introduced by eval are strings. | |
| 6203 DCHECK(keys->get(i)->IsString()); | |
| 6204 Handle<String> key(String::cast(keys->get(i))); | |
| 6205 Handle<Object> value; | |
| 6206 ASSIGN_RETURN_ON_EXCEPTION( | |
| 6207 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject); | |
| 6208 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty( | |
| 6209 isolate, target, key, value, SLOPPY), | |
| 6210 JSObject); | |
| 6211 } | |
| 6212 } | |
| 6213 } | |
| 6214 | |
| 6215 return target; | |
| 6216 } | |
| 6217 | |
| 6218 | |
| 6219 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope( | |
| 6220 Isolate* isolate, JavaScriptFrame* frame, int inlined_jsframe_index) { | |
| 6221 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | |
| 6222 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); | |
| 6223 | |
| 6224 Handle<JSObject> local_scope = | |
| 6225 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 6226 ASSIGN_RETURN_ON_EXCEPTION( | |
| 6227 isolate, local_scope, | |
| 6228 MaterializeStackLocalsWithFrameInspector(isolate, local_scope, function, | |
| 6229 &frame_inspector), | |
| 6230 JSObject); | |
| 6231 | |
| 6232 return MaterializeLocalContext(isolate, local_scope, function, frame); | |
| 6233 } | |
| 6234 | |
| 6235 | |
| 6236 // Set the context local variable value. | |
| 6237 static bool SetContextLocalValue(Isolate* isolate, Handle<ScopeInfo> scope_info, | |
| 6238 Handle<Context> context, | |
| 6239 Handle<String> variable_name, | |
| 6240 Handle<Object> new_value) { | |
| 6241 for (int i = 0; i < scope_info->ContextLocalCount(); i++) { | |
| 6242 Handle<String> next_name(scope_info->ContextLocalName(i)); | |
| 6243 if (String::Equals(variable_name, next_name)) { | |
| 6244 VariableMode mode; | |
| 6245 InitializationFlag init_flag; | |
| 6246 MaybeAssignedFlag maybe_assigned_flag; | |
| 6247 int context_index = ScopeInfo::ContextSlotIndex( | |
| 6248 scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag); | |
| 6249 context->set(context_index, *new_value); | |
| 6250 return true; | |
| 6251 } | |
| 6252 } | |
| 6253 | |
| 6254 return false; | |
| 6255 } | |
| 6256 | |
| 6257 | |
| 6258 static bool SetLocalVariableValue(Isolate* isolate, JavaScriptFrame* frame, | |
| 6259 int inlined_jsframe_index, | |
| 6260 Handle<String> variable_name, | |
| 6261 Handle<Object> new_value) { | |
| 6262 if (inlined_jsframe_index != 0 || frame->is_optimized()) { | |
| 6263 // Optimized frames are not supported. | |
| 6264 return false; | |
| 6265 } | |
| 6266 | |
| 6267 Handle<JSFunction> function(frame->function()); | |
| 6268 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 6269 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 6270 | |
| 6271 bool default_result = false; | |
| 6272 | |
| 6273 // Parameters. | |
| 6274 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | |
| 6275 HandleScope scope(isolate); | |
| 6276 if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) { | |
| 6277 frame->SetParameterValue(i, *new_value); | |
| 6278 // Argument might be shadowed in heap context, don't stop here. | |
| 6279 default_result = true; | |
| 6280 } | |
| 6281 } | |
| 6282 | |
| 6283 // Stack locals. | |
| 6284 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
| 6285 HandleScope scope(isolate); | |
| 6286 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) { | |
| 6287 frame->SetExpression(i, *new_value); | |
| 6288 return true; | |
| 6289 } | |
| 6290 } | |
| 6291 | |
| 6292 if (scope_info->HasContext()) { | |
| 6293 // Context locals. | |
| 6294 Handle<Context> frame_context(Context::cast(frame->context())); | |
| 6295 Handle<Context> function_context(frame_context->declaration_context()); | |
| 6296 if (SetContextLocalValue(isolate, scope_info, function_context, | |
| 6297 variable_name, new_value)) { | |
| 6298 return true; | |
| 6299 } | |
| 6300 | |
| 6301 // Function context extension. These are variables introduced by eval. | |
| 6302 if (function_context->closure() == *function) { | |
| 6303 if (function_context->has_extension() && | |
| 6304 !function_context->IsNativeContext()) { | |
| 6305 Handle<JSObject> ext(JSObject::cast(function_context->extension())); | |
| 6306 | |
| 6307 Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name); | |
| 6308 DCHECK(maybe.has_value); | |
| 6309 if (maybe.value) { | |
| 6310 // We don't expect this to do anything except replacing | |
| 6311 // property value. | |
| 6312 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value, | |
| 6313 SLOPPY).Assert(); | |
| 6314 return true; | |
| 6315 } | |
| 6316 } | |
| 6317 } | |
| 6318 } | |
| 6319 | |
| 6320 return default_result; | |
| 6321 } | |
| 6322 | |
| 6323 | |
| 6324 // Create a plain JSObject which materializes the closure content for the | |
| 6325 // context. | |
| 6326 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure( | |
| 6327 Isolate* isolate, Handle<Context> context) { | |
| 6328 DCHECK(context->IsFunctionContext()); | |
| 6329 | |
| 6330 Handle<SharedFunctionInfo> shared(context->closure()->shared()); | |
| 6331 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 6332 | |
| 6333 // Allocate and initialize a JSObject with all the content of this function | |
| 6334 // closure. | |
| 6335 Handle<JSObject> closure_scope = | |
| 6336 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 6337 | |
| 6338 // Fill all context locals to the context extension. | |
| 6339 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, | |
| 6340 closure_scope)) { | |
| 6341 return MaybeHandle<JSObject>(); | |
| 6342 } | |
| 6343 | |
| 6344 // Finally copy any properties from the function context extension. This will | |
| 6345 // be variables introduced by eval. | |
| 6346 if (context->has_extension()) { | |
| 6347 Handle<JSObject> ext(JSObject::cast(context->extension())); | |
| 6348 Handle<FixedArray> keys; | |
| 6349 ASSIGN_RETURN_ON_EXCEPTION( | |
| 6350 isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), | |
| 6351 JSObject); | |
| 6352 | |
| 6353 for (int i = 0; i < keys->length(); i++) { | |
| 6354 HandleScope scope(isolate); | |
| 6355 // Names of variables introduced by eval are strings. | |
| 6356 DCHECK(keys->get(i)->IsString()); | |
| 6357 Handle<String> key(String::cast(keys->get(i))); | |
| 6358 Handle<Object> value; | |
| 6359 ASSIGN_RETURN_ON_EXCEPTION( | |
| 6360 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject); | |
| 6361 RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty( | |
| 6362 closure_scope, key, value, NONE), | |
| 6363 JSObject); | |
| 6364 } | |
| 6365 } | |
| 6366 | |
| 6367 return closure_scope; | |
| 6368 } | |
| 6369 | |
| 6370 | |
| 6371 // This method copies structure of MaterializeClosure method above. | |
| 6372 static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> context, | |
| 6373 Handle<String> variable_name, | |
| 6374 Handle<Object> new_value) { | |
| 6375 DCHECK(context->IsFunctionContext()); | |
| 6376 | |
| 6377 Handle<SharedFunctionInfo> shared(context->closure()->shared()); | |
| 6378 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 6379 | |
| 6380 // Context locals to the context extension. | |
| 6381 if (SetContextLocalValue(isolate, scope_info, context, variable_name, | |
| 6382 new_value)) { | |
| 6383 return true; | |
| 6384 } | |
| 6385 | |
| 6386 // Properties from the function context extension. This will | |
| 6387 // be variables introduced by eval. | |
| 6388 if (context->has_extension()) { | |
| 6389 Handle<JSObject> ext(JSObject::cast(context->extension())); | |
| 6390 Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name); | |
| 6391 DCHECK(maybe.has_value); | |
| 6392 if (maybe.value) { | |
| 6393 // We don't expect this to do anything except replacing property value. | |
| 6394 Runtime::DefineObjectProperty(ext, variable_name, new_value, NONE) | |
| 6395 .Assert(); | |
| 6396 return true; | |
| 6397 } | |
| 6398 } | |
| 6399 | |
| 6400 return false; | |
| 6401 } | |
| 6402 | |
| 6403 | |
| 6404 // Create a plain JSObject which materializes the scope for the specified | |
| 6405 // catch context. | |
| 6406 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope( | |
| 6407 Isolate* isolate, Handle<Context> context) { | |
| 6408 DCHECK(context->IsCatchContext()); | |
| 6409 Handle<String> name(String::cast(context->extension())); | |
| 6410 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX), | |
| 6411 isolate); | |
| 6412 Handle<JSObject> catch_scope = | |
| 6413 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 6414 RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty( | |
| 6415 catch_scope, name, thrown_object, NONE), | |
| 6416 JSObject); | |
| 6417 return catch_scope; | |
| 6418 } | |
| 6419 | |
| 6420 | |
| 6421 static bool SetCatchVariableValue(Isolate* isolate, Handle<Context> context, | |
| 6422 Handle<String> variable_name, | |
| 6423 Handle<Object> new_value) { | |
| 6424 DCHECK(context->IsCatchContext()); | |
| 6425 Handle<String> name(String::cast(context->extension())); | |
| 6426 if (!String::Equals(name, variable_name)) { | |
| 6427 return false; | |
| 6428 } | |
| 6429 context->set(Context::THROWN_OBJECT_INDEX, *new_value); | |
| 6430 return true; | |
| 6431 } | |
| 6432 | |
| 6433 | |
| 6434 // Create a plain JSObject which materializes the block scope for the specified | |
| 6435 // block context. | |
| 6436 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope( | |
| 6437 Isolate* isolate, Handle<Context> context) { | |
| 6438 DCHECK(context->IsBlockContext()); | |
| 6439 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); | |
| 6440 | |
| 6441 // Allocate and initialize a JSObject with all the arguments, stack locals | |
| 6442 // heap locals and extension properties of the debugged function. | |
| 6443 Handle<JSObject> block_scope = | |
| 6444 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 6445 | |
| 6446 // Fill all context locals. | |
| 6447 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, | |
| 6448 block_scope)) { | |
| 6449 return MaybeHandle<JSObject>(); | |
| 6450 } | |
| 6451 | |
| 6452 return block_scope; | |
| 6453 } | |
| 6454 | |
| 6455 | |
| 6456 // Create a plain JSObject which materializes the module scope for the specified | |
| 6457 // module context. | |
| 6458 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope( | |
| 6459 Isolate* isolate, Handle<Context> context) { | |
| 6460 DCHECK(context->IsModuleContext()); | |
| 6461 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); | |
| 6462 | |
| 6463 // Allocate and initialize a JSObject with all the members of the debugged | |
| 6464 // module. | |
| 6465 Handle<JSObject> module_scope = | |
| 6466 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 6467 | |
| 6468 // Fill all context locals. | |
| 6469 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, | |
| 6470 module_scope)) { | |
| 6471 return MaybeHandle<JSObject>(); | |
| 6472 } | |
| 6473 | |
| 6474 return module_scope; | |
| 6475 } | |
| 6476 | |
| 6477 | |
| 6478 // Iterate over the actual scopes visible from a stack frame or from a closure. | |
| 6479 // The iteration proceeds from the innermost visible nested scope outwards. | |
| 6480 // All scopes are backed by an actual context except the local scope, | |
| 6481 // which is inserted "artificially" in the context chain. | |
| 6482 class ScopeIterator { | |
| 6483 public: | |
| 6484 enum ScopeType { | |
| 6485 ScopeTypeGlobal = 0, | |
| 6486 ScopeTypeLocal, | |
| 6487 ScopeTypeWith, | |
| 6488 ScopeTypeClosure, | |
| 6489 ScopeTypeCatch, | |
| 6490 ScopeTypeBlock, | |
| 6491 ScopeTypeModule | |
| 6492 }; | |
| 6493 | |
| 6494 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame, | |
| 6495 int inlined_jsframe_index, bool ignore_nested_scopes = false) | |
| 6496 : isolate_(isolate), | |
| 6497 frame_(frame), | |
| 6498 inlined_jsframe_index_(inlined_jsframe_index), | |
| 6499 function_(frame->function()), | |
| 6500 context_(Context::cast(frame->context())), | |
| 6501 nested_scope_chain_(4), | |
| 6502 failed_(false) { | |
| 6503 // Catch the case when the debugger stops in an internal function. | |
| 6504 Handle<SharedFunctionInfo> shared_info(function_->shared()); | |
| 6505 Handle<ScopeInfo> scope_info(shared_info->scope_info()); | |
| 6506 if (shared_info->script() == isolate->heap()->undefined_value()) { | |
| 6507 while (context_->closure() == *function_) { | |
| 6508 context_ = Handle<Context>(context_->previous(), isolate_); | |
| 6509 } | |
| 6510 return; | |
| 6511 } | |
| 6512 | |
| 6513 // Get the debug info (create it if it does not exist). | |
| 6514 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) { | |
| 6515 // Return if ensuring debug info failed. | |
| 6516 return; | |
| 6517 } | |
| 6518 | |
| 6519 // Currently it takes too much time to find nested scopes due to script | |
| 6520 // parsing. Sometimes we want to run the ScopeIterator as fast as possible | |
| 6521 // (for example, while collecting async call stacks on every | |
| 6522 // addEventListener call), even if we drop some nested scopes. | |
| 6523 // Later we may optimize getting the nested scopes (cache the result?) | |
| 6524 // and include nested scopes into the "fast" iteration case as well. | |
| 6525 if (!ignore_nested_scopes) { | |
| 6526 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info); | |
| 6527 | |
| 6528 // Find the break point where execution has stopped. | |
| 6529 BreakLocationIterator break_location_iterator(debug_info, | |
| 6530 ALL_BREAK_LOCATIONS); | |
| 6531 // pc points to the instruction after the current one, possibly a break | |
| 6532 // location as well. So the "- 1" to exclude it from the search. | |
| 6533 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); | |
| 6534 | |
| 6535 // Within the return sequence at the moment it is not possible to | |
| 6536 // get a source position which is consistent with the current scope chain. | |
| 6537 // Thus all nested with, catch and block contexts are skipped and we only | |
| 6538 // provide the function scope. | |
| 6539 ignore_nested_scopes = break_location_iterator.IsExit(); | |
| 6540 } | |
| 6541 | |
| 6542 if (ignore_nested_scopes) { | |
| 6543 if (scope_info->HasContext()) { | |
| 6544 context_ = Handle<Context>(context_->declaration_context(), isolate_); | |
| 6545 } else { | |
| 6546 while (context_->closure() == *function_) { | |
| 6547 context_ = Handle<Context>(context_->previous(), isolate_); | |
| 6548 } | |
| 6549 } | |
| 6550 if (scope_info->scope_type() == FUNCTION_SCOPE) { | |
| 6551 nested_scope_chain_.Add(scope_info); | |
| 6552 } | |
| 6553 } else { | |
| 6554 // Reparse the code and analyze the scopes. | |
| 6555 Handle<Script> script(Script::cast(shared_info->script())); | |
| 6556 Scope* scope = NULL; | |
| 6557 | |
| 6558 // Check whether we are in global, eval or function code. | |
| 6559 Handle<ScopeInfo> scope_info(shared_info->scope_info()); | |
| 6560 if (scope_info->scope_type() != FUNCTION_SCOPE) { | |
| 6561 // Global or eval code. | |
| 6562 CompilationInfoWithZone info(script); | |
| 6563 if (scope_info->scope_type() == GLOBAL_SCOPE) { | |
| 6564 info.MarkAsGlobal(); | |
| 6565 } else { | |
| 6566 DCHECK(scope_info->scope_type() == EVAL_SCOPE); | |
| 6567 info.MarkAsEval(); | |
| 6568 info.SetContext(Handle<Context>(function_->context())); | |
| 6569 } | |
| 6570 if (Parser::Parse(&info) && Scope::Analyze(&info)) { | |
| 6571 scope = info.function()->scope(); | |
| 6572 } | |
| 6573 RetrieveScopeChain(scope, shared_info); | |
| 6574 } else { | |
| 6575 // Function code | |
| 6576 CompilationInfoWithZone info(shared_info); | |
| 6577 if (Parser::Parse(&info) && Scope::Analyze(&info)) { | |
| 6578 scope = info.function()->scope(); | |
| 6579 } | |
| 6580 RetrieveScopeChain(scope, shared_info); | |
| 6581 } | |
| 6582 } | |
| 6583 } | |
| 6584 | |
| 6585 ScopeIterator(Isolate* isolate, Handle<JSFunction> function) | |
| 6586 : isolate_(isolate), | |
| 6587 frame_(NULL), | |
| 6588 inlined_jsframe_index_(0), | |
| 6589 function_(function), | |
| 6590 context_(function->context()), | |
| 6591 failed_(false) { | |
| 6592 if (function->IsBuiltin()) { | |
| 6593 context_ = Handle<Context>(); | |
| 6594 } | |
| 6595 } | |
| 6596 | |
| 6597 // More scopes? | |
| 6598 bool Done() { | |
| 6599 DCHECK(!failed_); | |
| 6600 return context_.is_null(); | |
| 6601 } | |
| 6602 | |
| 6603 bool Failed() { return failed_; } | |
| 6604 | |
| 6605 // Move to the next scope. | |
| 6606 void Next() { | |
| 6607 DCHECK(!failed_); | |
| 6608 ScopeType scope_type = Type(); | |
| 6609 if (scope_type == ScopeTypeGlobal) { | |
| 6610 // The global scope is always the last in the chain. | |
| 6611 DCHECK(context_->IsNativeContext()); | |
| 6612 context_ = Handle<Context>(); | |
| 6613 return; | |
| 6614 } | |
| 6615 if (nested_scope_chain_.is_empty()) { | |
| 6616 context_ = Handle<Context>(context_->previous(), isolate_); | |
| 6617 } else { | |
| 6618 if (nested_scope_chain_.last()->HasContext()) { | |
| 6619 DCHECK(context_->previous() != NULL); | |
| 6620 context_ = Handle<Context>(context_->previous(), isolate_); | |
| 6621 } | |
| 6622 nested_scope_chain_.RemoveLast(); | |
| 6623 } | |
| 6624 } | |
| 6625 | |
| 6626 // Return the type of the current scope. | |
| 6627 ScopeType Type() { | |
| 6628 DCHECK(!failed_); | |
| 6629 if (!nested_scope_chain_.is_empty()) { | |
| 6630 Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); | |
| 6631 switch (scope_info->scope_type()) { | |
| 6632 case FUNCTION_SCOPE: | |
| 6633 DCHECK(context_->IsFunctionContext() || !scope_info->HasContext()); | |
| 6634 return ScopeTypeLocal; | |
| 6635 case MODULE_SCOPE: | |
| 6636 DCHECK(context_->IsModuleContext()); | |
| 6637 return ScopeTypeModule; | |
| 6638 case GLOBAL_SCOPE: | |
| 6639 DCHECK(context_->IsNativeContext()); | |
| 6640 return ScopeTypeGlobal; | |
| 6641 case WITH_SCOPE: | |
| 6642 DCHECK(context_->IsWithContext()); | |
| 6643 return ScopeTypeWith; | |
| 6644 case CATCH_SCOPE: | |
| 6645 DCHECK(context_->IsCatchContext()); | |
| 6646 return ScopeTypeCatch; | |
| 6647 case BLOCK_SCOPE: | |
| 6648 DCHECK(!scope_info->HasContext() || context_->IsBlockContext()); | |
| 6649 return ScopeTypeBlock; | |
| 6650 case EVAL_SCOPE: | |
| 6651 UNREACHABLE(); | |
| 6652 } | |
| 6653 } | |
| 6654 if (context_->IsNativeContext()) { | |
| 6655 DCHECK(context_->global_object()->IsGlobalObject()); | |
| 6656 return ScopeTypeGlobal; | |
| 6657 } | |
| 6658 if (context_->IsFunctionContext()) { | |
| 6659 return ScopeTypeClosure; | |
| 6660 } | |
| 6661 if (context_->IsCatchContext()) { | |
| 6662 return ScopeTypeCatch; | |
| 6663 } | |
| 6664 if (context_->IsBlockContext()) { | |
| 6665 return ScopeTypeBlock; | |
| 6666 } | |
| 6667 if (context_->IsModuleContext()) { | |
| 6668 return ScopeTypeModule; | |
| 6669 } | |
| 6670 DCHECK(context_->IsWithContext()); | |
| 6671 return ScopeTypeWith; | |
| 6672 } | |
| 6673 | |
| 6674 // Return the JavaScript object with the content of the current scope. | |
| 6675 MaybeHandle<JSObject> ScopeObject() { | |
| 6676 DCHECK(!failed_); | |
| 6677 switch (Type()) { | |
| 6678 case ScopeIterator::ScopeTypeGlobal: | |
| 6679 return Handle<JSObject>(CurrentContext()->global_object()); | |
| 6680 case ScopeIterator::ScopeTypeLocal: | |
| 6681 // Materialize the content of the local scope into a JSObject. | |
| 6682 DCHECK(nested_scope_chain_.length() == 1); | |
| 6683 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_); | |
| 6684 case ScopeIterator::ScopeTypeWith: | |
| 6685 // Return the with object. | |
| 6686 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); | |
| 6687 case ScopeIterator::ScopeTypeCatch: | |
| 6688 return MaterializeCatchScope(isolate_, CurrentContext()); | |
| 6689 case ScopeIterator::ScopeTypeClosure: | |
| 6690 // Materialize the content of the closure scope into a JSObject. | |
| 6691 return MaterializeClosure(isolate_, CurrentContext()); | |
| 6692 case ScopeIterator::ScopeTypeBlock: | |
| 6693 return MaterializeBlockScope(isolate_, CurrentContext()); | |
| 6694 case ScopeIterator::ScopeTypeModule: | |
| 6695 return MaterializeModuleScope(isolate_, CurrentContext()); | |
| 6696 } | |
| 6697 UNREACHABLE(); | |
| 6698 return Handle<JSObject>(); | |
| 6699 } | |
| 6700 | |
| 6701 bool SetVariableValue(Handle<String> variable_name, | |
| 6702 Handle<Object> new_value) { | |
| 6703 DCHECK(!failed_); | |
| 6704 switch (Type()) { | |
| 6705 case ScopeIterator::ScopeTypeGlobal: | |
| 6706 break; | |
| 6707 case ScopeIterator::ScopeTypeLocal: | |
| 6708 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_, | |
| 6709 variable_name, new_value); | |
| 6710 case ScopeIterator::ScopeTypeWith: | |
| 6711 break; | |
| 6712 case ScopeIterator::ScopeTypeCatch: | |
| 6713 return SetCatchVariableValue(isolate_, CurrentContext(), variable_name, | |
| 6714 new_value); | |
| 6715 case ScopeIterator::ScopeTypeClosure: | |
| 6716 return SetClosureVariableValue(isolate_, CurrentContext(), | |
| 6717 variable_name, new_value); | |
| 6718 case ScopeIterator::ScopeTypeBlock: | |
| 6719 // TODO(2399): should we implement it? | |
| 6720 break; | |
| 6721 case ScopeIterator::ScopeTypeModule: | |
| 6722 // TODO(2399): should we implement it? | |
| 6723 break; | |
| 6724 } | |
| 6725 return false; | |
| 6726 } | |
| 6727 | |
| 6728 Handle<ScopeInfo> CurrentScopeInfo() { | |
| 6729 DCHECK(!failed_); | |
| 6730 if (!nested_scope_chain_.is_empty()) { | |
| 6731 return nested_scope_chain_.last(); | |
| 6732 } else if (context_->IsBlockContext()) { | |
| 6733 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension())); | |
| 6734 } else if (context_->IsFunctionContext()) { | |
| 6735 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info()); | |
| 6736 } | |
| 6737 return Handle<ScopeInfo>::null(); | |
| 6738 } | |
| 6739 | |
| 6740 // Return the context for this scope. For the local context there might not | |
| 6741 // be an actual context. | |
| 6742 Handle<Context> CurrentContext() { | |
| 6743 DCHECK(!failed_); | |
| 6744 if (Type() == ScopeTypeGlobal || nested_scope_chain_.is_empty()) { | |
| 6745 return context_; | |
| 6746 } else if (nested_scope_chain_.last()->HasContext()) { | |
| 6747 return context_; | |
| 6748 } else { | |
| 6749 return Handle<Context>(); | |
| 6750 } | |
| 6751 } | |
| 6752 | |
| 6753 #ifdef DEBUG | |
| 6754 // Debug print of the content of the current scope. | |
| 6755 void DebugPrint() { | |
| 6756 OFStream os(stdout); | |
| 6757 DCHECK(!failed_); | |
| 6758 switch (Type()) { | |
| 6759 case ScopeIterator::ScopeTypeGlobal: | |
| 6760 os << "Global:\n"; | |
| 6761 CurrentContext()->Print(os); | |
| 6762 break; | |
| 6763 | |
| 6764 case ScopeIterator::ScopeTypeLocal: { | |
| 6765 os << "Local:\n"; | |
| 6766 function_->shared()->scope_info()->Print(); | |
| 6767 if (!CurrentContext().is_null()) { | |
| 6768 CurrentContext()->Print(os); | |
| 6769 if (CurrentContext()->has_extension()) { | |
| 6770 Handle<Object> extension(CurrentContext()->extension(), isolate_); | |
| 6771 if (extension->IsJSContextExtensionObject()) { | |
| 6772 extension->Print(os); | |
| 6773 } | |
| 6774 } | |
| 6775 } | |
| 6776 break; | |
| 6777 } | |
| 6778 | |
| 6779 case ScopeIterator::ScopeTypeWith: | |
| 6780 os << "With:\n"; | |
| 6781 CurrentContext()->extension()->Print(os); | |
| 6782 break; | |
| 6783 | |
| 6784 case ScopeIterator::ScopeTypeCatch: | |
| 6785 os << "Catch:\n"; | |
| 6786 CurrentContext()->extension()->Print(os); | |
| 6787 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os); | |
| 6788 break; | |
| 6789 | |
| 6790 case ScopeIterator::ScopeTypeClosure: | |
| 6791 os << "Closure:\n"; | |
| 6792 CurrentContext()->Print(os); | |
| 6793 if (CurrentContext()->has_extension()) { | |
| 6794 Handle<Object> extension(CurrentContext()->extension(), isolate_); | |
| 6795 if (extension->IsJSContextExtensionObject()) { | |
| 6796 extension->Print(os); | |
| 6797 } | |
| 6798 } | |
| 6799 break; | |
| 6800 | |
| 6801 default: | |
| 6802 UNREACHABLE(); | |
| 6803 } | |
| 6804 PrintF("\n"); | |
| 6805 } | |
| 6806 #endif | |
| 6807 | |
| 6808 private: | |
| 6809 Isolate* isolate_; | |
| 6810 JavaScriptFrame* frame_; | |
| 6811 int inlined_jsframe_index_; | |
| 6812 Handle<JSFunction> function_; | |
| 6813 Handle<Context> context_; | |
| 6814 List<Handle<ScopeInfo> > nested_scope_chain_; | |
| 6815 bool failed_; | |
| 6816 | |
| 6817 void RetrieveScopeChain(Scope* scope, | |
| 6818 Handle<SharedFunctionInfo> shared_info) { | |
| 6819 if (scope != NULL) { | |
| 6820 int source_position = shared_info->code()->SourcePosition(frame_->pc()); | |
| 6821 scope->GetNestedScopeChain(&nested_scope_chain_, source_position); | |
| 6822 } else { | |
| 6823 // A failed reparse indicates that the preparser has diverged from the | |
| 6824 // parser or that the preparse data given to the initial parse has been | |
| 6825 // faulty. We fail in debug mode but in release mode we only provide the | |
| 6826 // information we get from the context chain but nothing about | |
| 6827 // completely stack allocated scopes or stack allocated locals. | |
| 6828 // Or it could be due to stack overflow. | |
| 6829 DCHECK(isolate_->has_pending_exception()); | |
| 6830 failed_ = true; | |
| 6831 } | |
| 6832 } | |
| 6833 | |
| 6834 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); | |
| 6835 }; | |
| 6836 | |
| 6837 | |
| 6838 RUNTIME_FUNCTION(Runtime_GetScopeCount) { | |
| 6839 HandleScope scope(isolate); | |
| 6840 DCHECK(args.length() == 2); | |
| 6841 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 6842 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 6843 | |
| 6844 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
| 6845 | |
| 6846 // Get the frame where the debugging is performed. | |
| 6847 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
| 6848 JavaScriptFrameIterator it(isolate, id); | |
| 6849 JavaScriptFrame* frame = it.frame(); | |
| 6850 | |
| 6851 // Count the visible scopes. | |
| 6852 int n = 0; | |
| 6853 for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) { | |
| 6854 n++; | |
| 6855 } | |
| 6856 | |
| 6857 return Smi::FromInt(n); | |
| 6858 } | |
| 6859 | |
| 6860 | |
| 6861 // Returns the list of step-in positions (text offset) in a function of the | |
| 6862 // stack frame in a range from the current debug break position to the end | |
| 6863 // of the corresponding statement. | |
| 6864 RUNTIME_FUNCTION(Runtime_GetStepInPositions) { | |
| 6865 HandleScope scope(isolate); | |
| 6866 DCHECK(args.length() == 2); | |
| 6867 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 6868 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 6869 | |
| 6870 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
| 6871 | |
| 6872 // Get the frame where the debugging is performed. | |
| 6873 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
| 6874 JavaScriptFrameIterator frame_it(isolate, id); | |
| 6875 RUNTIME_ASSERT(!frame_it.done()); | |
| 6876 | |
| 6877 JavaScriptFrame* frame = frame_it.frame(); | |
| 6878 | |
| 6879 Handle<JSFunction> fun = Handle<JSFunction>(frame->function()); | |
| 6880 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared()); | |
| 6881 | |
| 6882 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) { | |
| 6883 return isolate->heap()->undefined_value(); | |
| 6884 } | |
| 6885 | |
| 6886 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared); | |
| 6887 | |
| 6888 int len = 0; | |
| 6889 Handle<JSArray> array(isolate->factory()->NewJSArray(10)); | |
| 6890 // Find the break point where execution has stopped. | |
| 6891 BreakLocationIterator break_location_iterator(debug_info, | |
| 6892 ALL_BREAK_LOCATIONS); | |
| 6893 | |
| 6894 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); | |
| 6895 int current_statement_pos = break_location_iterator.statement_position(); | |
| 6896 | |
| 6897 while (!break_location_iterator.Done()) { | |
| 6898 bool accept; | |
| 6899 if (break_location_iterator.pc() > frame->pc()) { | |
| 6900 accept = true; | |
| 6901 } else { | |
| 6902 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id(); | |
| 6903 // The break point is near our pc. Could be a step-in possibility, | |
| 6904 // that is currently taken by active debugger call. | |
| 6905 if (break_frame_id == StackFrame::NO_ID) { | |
| 6906 // We are not stepping. | |
| 6907 accept = false; | |
| 6908 } else { | |
| 6909 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id); | |
| 6910 // If our frame is a top frame and we are stepping, we can do step-in | |
| 6911 // at this place. | |
| 6912 accept = additional_frame_it.frame()->id() == id; | |
| 6913 } | |
| 6914 } | |
| 6915 if (accept) { | |
| 6916 if (break_location_iterator.IsStepInLocation(isolate)) { | |
| 6917 Smi* position_value = Smi::FromInt(break_location_iterator.position()); | |
| 6918 RETURN_FAILURE_ON_EXCEPTION( | |
| 6919 isolate, JSObject::SetElement( | |
| 6920 array, len, Handle<Object>(position_value, isolate), | |
| 6921 NONE, SLOPPY)); | |
| 6922 len++; | |
| 6923 } | |
| 6924 } | |
| 6925 // Advance iterator. | |
| 6926 break_location_iterator.Next(); | |
| 6927 if (current_statement_pos != break_location_iterator.statement_position()) { | |
| 6928 break; | |
| 6929 } | |
| 6930 } | |
| 6931 return *array; | |
| 6932 } | |
| 6933 | |
| 6934 | |
| 6935 static const int kScopeDetailsTypeIndex = 0; | |
| 6936 static const int kScopeDetailsObjectIndex = 1; | |
| 6937 static const int kScopeDetailsSize = 2; | |
| 6938 | |
| 6939 | |
| 6940 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails( | |
| 6941 Isolate* isolate, ScopeIterator* it) { | |
| 6942 // Calculate the size of the result. | |
| 6943 int details_size = kScopeDetailsSize; | |
| 6944 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); | |
| 6945 | |
| 6946 // Fill in scope details. | |
| 6947 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type())); | |
| 6948 Handle<JSObject> scope_object; | |
| 6949 ASSIGN_RETURN_ON_EXCEPTION(isolate, scope_object, it->ScopeObject(), | |
| 6950 JSObject); | |
| 6951 details->set(kScopeDetailsObjectIndex, *scope_object); | |
| 6952 | |
| 6953 return isolate->factory()->NewJSArrayWithElements(details); | |
| 6954 } | |
| 6955 | |
| 6956 | |
| 6957 // Return an array with scope details | |
| 6958 // args[0]: number: break id | |
| 6959 // args[1]: number: frame index | |
| 6960 // args[2]: number: inlined frame index | |
| 6961 // args[3]: number: scope index | |
| 6962 // | |
| 6963 // The array returned contains the following information: | |
| 6964 // 0: Scope type | |
| 6965 // 1: Scope object | |
| 6966 RUNTIME_FUNCTION(Runtime_GetScopeDetails) { | |
| 6967 HandleScope scope(isolate); | |
| 6968 DCHECK(args.length() == 4); | |
| 6969 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 6970 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 6971 | |
| 6972 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
| 6973 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | |
| 6974 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); | |
| 6975 | |
| 6976 // Get the frame where the debugging is performed. | |
| 6977 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
| 6978 JavaScriptFrameIterator frame_it(isolate, id); | |
| 6979 JavaScriptFrame* frame = frame_it.frame(); | |
| 6980 | |
| 6981 // Find the requested scope. | |
| 6982 int n = 0; | |
| 6983 ScopeIterator it(isolate, frame, inlined_jsframe_index); | |
| 6984 for (; !it.Done() && n < index; it.Next()) { | |
| 6985 n++; | |
| 6986 } | |
| 6987 if (it.Done()) { | |
| 6988 return isolate->heap()->undefined_value(); | |
| 6989 } | |
| 6990 Handle<JSObject> details; | |
| 6991 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, | |
| 6992 MaterializeScopeDetails(isolate, &it)); | |
| 6993 return *details; | |
| 6994 } | |
| 6995 | |
| 6996 | |
| 6997 // Return an array of scope details | |
| 6998 // args[0]: number: break id | |
| 6999 // args[1]: number: frame index | |
| 7000 // args[2]: number: inlined frame index | |
| 7001 // args[3]: boolean: ignore nested scopes | |
| 7002 // | |
| 7003 // The array returned contains arrays with the following information: | |
| 7004 // 0: Scope type | |
| 7005 // 1: Scope object | |
| 7006 RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) { | |
| 7007 HandleScope scope(isolate); | |
| 7008 DCHECK(args.length() == 3 || args.length() == 4); | |
| 7009 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 7010 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 7011 | |
| 7012 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
| 7013 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | |
| 7014 | |
| 7015 bool ignore_nested_scopes = false; | |
| 7016 if (args.length() == 4) { | |
| 7017 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3); | |
| 7018 ignore_nested_scopes = flag; | |
| 7019 } | |
| 7020 | |
| 7021 // Get the frame where the debugging is performed. | |
| 7022 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
| 7023 JavaScriptFrameIterator frame_it(isolate, id); | |
| 7024 JavaScriptFrame* frame = frame_it.frame(); | |
| 7025 | |
| 7026 List<Handle<JSObject> > result(4); | |
| 7027 ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes); | |
| 7028 for (; !it.Done(); it.Next()) { | |
| 7029 Handle<JSObject> details; | |
| 7030 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, | |
| 7031 MaterializeScopeDetails(isolate, &it)); | |
| 7032 result.Add(details); | |
| 7033 } | |
| 7034 | |
| 7035 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length()); | |
| 7036 for (int i = 0; i < result.length(); ++i) { | |
| 7037 array->set(i, *result[i]); | |
| 7038 } | |
| 7039 return *isolate->factory()->NewJSArrayWithElements(array); | |
| 7040 } | |
| 7041 | |
| 7042 | |
| 7043 RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) { | |
| 7044 HandleScope scope(isolate); | |
| 7045 DCHECK(args.length() == 1); | |
| 7046 | |
| 7047 // Check arguments. | |
| 7048 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | |
| 7049 | |
| 7050 // Count the visible scopes. | |
| 7051 int n = 0; | |
| 7052 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) { | |
| 7053 n++; | |
| 7054 } | |
| 7055 | |
| 7056 return Smi::FromInt(n); | |
| 7057 } | |
| 7058 | |
| 7059 | |
| 7060 RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) { | |
| 7061 HandleScope scope(isolate); | |
| 7062 DCHECK(args.length() == 2); | |
| 7063 | |
| 7064 // Check arguments. | |
| 7065 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | |
| 7066 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); | |
| 7067 | |
| 7068 // Find the requested scope. | |
| 7069 int n = 0; | |
| 7070 ScopeIterator it(isolate, fun); | |
| 7071 for (; !it.Done() && n < index; it.Next()) { | |
| 7072 n++; | |
| 7073 } | |
| 7074 if (it.Done()) { | |
| 7075 return isolate->heap()->undefined_value(); | |
| 7076 } | |
| 7077 | |
| 7078 Handle<JSObject> details; | |
| 7079 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details, | |
| 7080 MaterializeScopeDetails(isolate, &it)); | |
| 7081 return *details; | |
| 7082 } | |
| 7083 | |
| 7084 | |
| 7085 static bool SetScopeVariableValue(ScopeIterator* it, int index, | |
| 7086 Handle<String> variable_name, | |
| 7087 Handle<Object> new_value) { | |
| 7088 for (int n = 0; !it->Done() && n < index; it->Next()) { | |
| 7089 n++; | |
| 7090 } | |
| 7091 if (it->Done()) { | |
| 7092 return false; | |
| 7093 } | |
| 7094 return it->SetVariableValue(variable_name, new_value); | |
| 7095 } | |
| 7096 | |
| 7097 | |
| 7098 // Change variable value in closure or local scope | |
| 7099 // args[0]: number or JsFunction: break id or function | |
| 7100 // args[1]: number: frame index (when arg[0] is break id) | |
| 7101 // args[2]: number: inlined frame index (when arg[0] is break id) | |
| 7102 // args[3]: number: scope index | |
| 7103 // args[4]: string: variable name | |
| 7104 // args[5]: object: new value | |
| 7105 // | |
| 7106 // Return true if success and false otherwise | |
| 7107 RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) { | |
| 7108 HandleScope scope(isolate); | |
| 7109 DCHECK(args.length() == 6); | |
| 7110 | |
| 7111 // Check arguments. | |
| 7112 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); | |
| 7113 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4); | |
| 7114 CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5); | |
| 7115 | |
| 7116 bool res; | |
| 7117 if (args[0]->IsNumber()) { | |
| 7118 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 7119 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 7120 | |
| 7121 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
| 7122 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | |
| 7123 | |
| 7124 // Get the frame where the debugging is performed. | |
| 7125 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
| 7126 JavaScriptFrameIterator frame_it(isolate, id); | |
| 7127 JavaScriptFrame* frame = frame_it.frame(); | |
| 7128 | |
| 7129 ScopeIterator it(isolate, frame, inlined_jsframe_index); | |
| 7130 res = SetScopeVariableValue(&it, index, variable_name, new_value); | |
| 7131 } else { | |
| 7132 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | |
| 7133 ScopeIterator it(isolate, fun); | |
| 7134 res = SetScopeVariableValue(&it, index, variable_name, new_value); | |
| 7135 } | |
| 7136 | |
| 7137 return isolate->heap()->ToBoolean(res); | |
| 7138 } | |
| 7139 | |
| 7140 | |
| 7141 RUNTIME_FUNCTION(Runtime_DebugPrintScopes) { | |
| 7142 HandleScope scope(isolate); | |
| 7143 DCHECK(args.length() == 0); | |
| 7144 | |
| 7145 #ifdef DEBUG | |
| 7146 // Print the scopes for the top frame. | |
| 7147 StackFrameLocator locator(isolate); | |
| 7148 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); | |
| 7149 for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) { | |
| 7150 it.DebugPrint(); | |
| 7151 } | |
| 7152 #endif | |
| 7153 return isolate->heap()->undefined_value(); | |
| 7154 } | |
| 7155 | |
| 7156 | |
| 7157 RUNTIME_FUNCTION(Runtime_GetThreadCount) { | |
| 7158 HandleScope scope(isolate); | |
| 7159 DCHECK(args.length() == 1); | |
| 7160 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 7161 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 7162 | |
| 7163 // Count all archived V8 threads. | |
| 7164 int n = 0; | |
| 7165 for (ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse(); | |
| 7166 thread != NULL; thread = thread->Next()) { | |
| 7167 n++; | |
| 7168 } | |
| 7169 | |
| 7170 // Total number of threads is current thread and archived threads. | |
| 7171 return Smi::FromInt(n + 1); | |
| 7172 } | |
| 7173 | |
| 7174 | |
| 7175 static const int kThreadDetailsCurrentThreadIndex = 0; | |
| 7176 static const int kThreadDetailsThreadIdIndex = 1; | |
| 7177 static const int kThreadDetailsSize = 2; | |
| 7178 | |
| 7179 // Return an array with thread details | |
| 7180 // args[0]: number: break id | |
| 7181 // args[1]: number: thread index | |
| 7182 // | |
| 7183 // The array returned contains the following information: | |
| 7184 // 0: Is current thread? | |
| 7185 // 1: Thread id | |
| 7186 RUNTIME_FUNCTION(Runtime_GetThreadDetails) { | |
| 7187 HandleScope scope(isolate); | |
| 7188 DCHECK(args.length() == 2); | |
| 7189 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 7190 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 7191 | |
| 7192 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); | |
| 7193 | |
| 7194 // Allocate array for result. | |
| 7195 Handle<FixedArray> details = | |
| 7196 isolate->factory()->NewFixedArray(kThreadDetailsSize); | |
| 7197 | |
| 7198 // Thread index 0 is current thread. | |
| 7199 if (index == 0) { | |
| 7200 // Fill the details. | |
| 7201 details->set(kThreadDetailsCurrentThreadIndex, | |
| 7202 isolate->heap()->true_value()); | |
| 7203 details->set(kThreadDetailsThreadIdIndex, | |
| 7204 Smi::FromInt(ThreadId::Current().ToInteger())); | |
| 7205 } else { | |
| 7206 // Find the thread with the requested index. | |
| 7207 int n = 1; | |
| 7208 ThreadState* thread = isolate->thread_manager()->FirstThreadStateInUse(); | |
| 7209 while (index != n && thread != NULL) { | |
| 7210 thread = thread->Next(); | |
| 7211 n++; | |
| 7212 } | |
| 7213 if (thread == NULL) { | |
| 7214 return isolate->heap()->undefined_value(); | |
| 7215 } | |
| 7216 | |
| 7217 // Fill the details. | |
| 7218 details->set(kThreadDetailsCurrentThreadIndex, | |
| 7219 isolate->heap()->false_value()); | |
| 7220 details->set(kThreadDetailsThreadIdIndex, | |
| 7221 Smi::FromInt(thread->id().ToInteger())); | |
| 7222 } | |
| 7223 | |
| 7224 // Convert to JS array and return. | |
| 7225 return *isolate->factory()->NewJSArrayWithElements(details); | |
| 7226 } | |
| 7227 | |
| 7228 | |
| 7229 // Sets the disable break state | |
| 7230 // args[0]: disable break state | |
| 7231 RUNTIME_FUNCTION(Runtime_SetDisableBreak) { | |
| 7232 HandleScope scope(isolate); | |
| 7233 DCHECK(args.length() == 1); | |
| 7234 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0); | |
| 7235 isolate->debug()->set_disable_break(disable_break); | |
| 7236 return isolate->heap()->undefined_value(); | |
| 7237 } | |
| 7238 | |
| 7239 | |
| 7240 static bool IsPositionAlignmentCodeCorrect(int alignment) { | |
| 7241 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED; | |
| 7242 } | |
| 7243 | |
| 7244 | |
| 7245 RUNTIME_FUNCTION(Runtime_GetBreakLocations) { | |
| 7246 HandleScope scope(isolate); | |
| 7247 DCHECK(args.length() == 2); | |
| 7248 | |
| 7249 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); | |
| 7250 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]); | |
| 7251 | |
| 7252 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { | |
| 7253 return isolate->ThrowIllegalOperation(); | |
| 7254 } | |
| 7255 BreakPositionAlignment alignment = | |
| 7256 static_cast<BreakPositionAlignment>(statement_aligned_code); | |
| 7257 | |
| 7258 Handle<SharedFunctionInfo> shared(fun->shared()); | |
| 7259 // Find the number of break points | |
| 7260 Handle<Object> break_locations = | |
| 7261 Debug::GetSourceBreakLocations(shared, alignment); | |
| 7262 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value(); | |
| 7263 // Return array as JS array | |
| 7264 return *isolate->factory()->NewJSArrayWithElements( | |
| 7265 Handle<FixedArray>::cast(break_locations)); | |
| 7266 } | |
| 7267 | |
| 7268 | |
| 7269 // Set a break point in a function. | |
| 7270 // args[0]: function | |
| 7271 // args[1]: number: break source position (within the function source) | |
| 7272 // args[2]: number: break point object | |
| 7273 RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) { | |
| 7274 HandleScope scope(isolate); | |
| 7275 DCHECK(args.length() == 3); | |
| 7276 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
| 7277 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); | |
| 7278 RUNTIME_ASSERT(source_position >= function->shared()->start_position() && | |
| 7279 source_position <= function->shared()->end_position()); | |
| 7280 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2); | |
| 7281 | |
| 7282 // Set break point. | |
| 7283 RUNTIME_ASSERT(isolate->debug()->SetBreakPoint( | |
| 7284 function, break_point_object_arg, &source_position)); | |
| 7285 | |
| 7286 return Smi::FromInt(source_position); | |
| 7287 } | |
| 7288 | |
| 7289 | |
| 7290 // Changes the state of a break point in a script and returns source position | |
| 7291 // where break point was set. NOTE: Regarding performance see the NOTE for | |
| 7292 // GetScriptFromScriptData. | |
| 7293 // args[0]: script to set break point in | |
| 7294 // args[1]: number: break source position (within the script source) | |
| 7295 // args[2]: number, breakpoint position alignment | |
| 7296 // args[3]: number: break point object | |
| 7297 RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) { | |
| 7298 HandleScope scope(isolate); | |
| 7299 DCHECK(args.length() == 4); | |
| 7300 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0); | |
| 7301 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); | |
| 7302 RUNTIME_ASSERT(source_position >= 0); | |
| 7303 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]); | |
| 7304 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3); | |
| 7305 | |
| 7306 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { | |
| 7307 return isolate->ThrowIllegalOperation(); | |
| 7308 } | |
| 7309 BreakPositionAlignment alignment = | |
| 7310 static_cast<BreakPositionAlignment>(statement_aligned_code); | |
| 7311 | |
| 7312 // Get the script from the script wrapper. | |
| 7313 RUNTIME_ASSERT(wrapper->value()->IsScript()); | |
| 7314 Handle<Script> script(Script::cast(wrapper->value())); | |
| 7315 | |
| 7316 // Set break point. | |
| 7317 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg, | |
| 7318 &source_position, alignment)) { | |
| 7319 return isolate->heap()->undefined_value(); | |
| 7320 } | |
| 7321 | |
| 7322 return Smi::FromInt(source_position); | |
| 7323 } | |
| 7324 | |
| 7325 | |
| 7326 // Clear a break point | |
| 7327 // args[0]: number: break point object | |
| 7328 RUNTIME_FUNCTION(Runtime_ClearBreakPoint) { | |
| 7329 HandleScope scope(isolate); | |
| 7330 DCHECK(args.length() == 1); | |
| 7331 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0); | |
| 7332 | |
| 7333 // Clear break point. | |
| 7334 isolate->debug()->ClearBreakPoint(break_point_object_arg); | |
| 7335 | |
| 7336 return isolate->heap()->undefined_value(); | |
| 7337 } | |
| 7338 | |
| 7339 | |
| 7340 // Change the state of break on exceptions. | |
| 7341 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions. | |
| 7342 // args[1]: Boolean indicating on/off. | |
| 7343 RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) { | |
| 7344 HandleScope scope(isolate); | |
| 7345 DCHECK(args.length() == 2); | |
| 7346 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); | |
| 7347 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1); | |
| 7348 | |
| 7349 // If the number doesn't match an enum value, the ChangeBreakOnException | |
| 7350 // function will default to affecting caught exceptions. | |
| 7351 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); | |
| 7352 // Update break point state. | |
| 7353 isolate->debug()->ChangeBreakOnException(type, enable); | |
| 7354 return isolate->heap()->undefined_value(); | |
| 7355 } | |
| 7356 | |
| 7357 | |
| 7358 // Returns the state of break on exceptions | |
| 7359 // args[0]: boolean indicating uncaught exceptions | |
| 7360 RUNTIME_FUNCTION(Runtime_IsBreakOnException) { | |
| 7361 HandleScope scope(isolate); | |
| 7362 DCHECK(args.length() == 1); | |
| 7363 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); | |
| 7364 | |
| 7365 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); | |
| 7366 bool result = isolate->debug()->IsBreakOnException(type); | |
| 7367 return Smi::FromInt(result); | |
| 7368 } | |
| 7369 | |
| 7370 | |
| 7371 // Prepare for stepping | |
| 7372 // args[0]: break id for checking execution state | |
| 7373 // args[1]: step action from the enumeration StepAction | |
| 7374 // args[2]: number of times to perform the step, for step out it is the number | |
| 7375 // of frames to step down. | |
| 7376 RUNTIME_FUNCTION(Runtime_PrepareStep) { | |
| 7377 HandleScope scope(isolate); | |
| 7378 DCHECK(args.length() == 4); | |
| 7379 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 7380 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 7381 | |
| 7382 if (!args[1]->IsNumber() || !args[2]->IsNumber()) { | |
| 7383 return isolate->Throw(isolate->heap()->illegal_argument_string()); | |
| 7384 } | |
| 7385 | |
| 7386 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]); | |
| 7387 | |
| 7388 StackFrame::Id frame_id; | |
| 7389 if (wrapped_frame_id == 0) { | |
| 7390 frame_id = StackFrame::NO_ID; | |
| 7391 } else { | |
| 7392 frame_id = UnwrapFrameId(wrapped_frame_id); | |
| 7393 } | |
| 7394 | |
| 7395 // Get the step action and check validity. | |
| 7396 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); | |
| 7397 if (step_action != StepIn && step_action != StepNext && | |
| 7398 step_action != StepOut && step_action != StepInMin && | |
| 7399 step_action != StepMin) { | |
| 7400 return isolate->Throw(isolate->heap()->illegal_argument_string()); | |
| 7401 } | |
| 7402 | |
| 7403 if (frame_id != StackFrame::NO_ID && step_action != StepNext && | |
| 7404 step_action != StepMin && step_action != StepOut) { | |
| 7405 return isolate->ThrowIllegalOperation(); | |
| 7406 } | |
| 7407 | |
| 7408 // Get the number of steps. | |
| 7409 int step_count = NumberToInt32(args[2]); | |
| 7410 if (step_count < 1) { | |
| 7411 return isolate->Throw(isolate->heap()->illegal_argument_string()); | |
| 7412 } | |
| 7413 | |
| 7414 // Clear all current stepping setup. | |
| 7415 isolate->debug()->ClearStepping(); | |
| 7416 | |
| 7417 // Prepare step. | |
| 7418 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action), | |
| 7419 step_count, frame_id); | |
| 7420 return isolate->heap()->undefined_value(); | |
| 7421 } | |
| 7422 | |
| 7423 | |
| 7424 // Clear all stepping set by PrepareStep. | |
| 7425 RUNTIME_FUNCTION(Runtime_ClearStepping) { | |
| 7426 HandleScope scope(isolate); | |
| 7427 DCHECK(args.length() == 0); | |
| 7428 isolate->debug()->ClearStepping(); | |
| 7429 return isolate->heap()->undefined_value(); | |
| 7430 } | |
| 7431 | |
| 7432 | |
| 7433 // Helper function to find or create the arguments object for | |
| 7434 // Runtime_DebugEvaluate. | |
| 7435 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject( | |
| 7436 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function) { | |
| 7437 // Do not materialize the arguments object for eval or top-level code. | |
| 7438 // Skip if "arguments" is already taken. | |
| 7439 if (!function->shared()->is_function()) return target; | |
| 7440 Maybe<bool> maybe = JSReceiver::HasOwnProperty( | |
| 7441 target, isolate->factory()->arguments_string()); | |
| 7442 if (!maybe.has_value) return MaybeHandle<JSObject>(); | |
| 7443 if (maybe.value) return target; | |
| 7444 | |
| 7445 // FunctionGetArguments can't throw an exception. | |
| 7446 Handle<JSObject> arguments = | |
| 7447 Handle<JSObject>::cast(Accessors::FunctionGetArguments(function)); | |
| 7448 Handle<String> arguments_str = isolate->factory()->arguments_string(); | |
| 7449 RETURN_ON_EXCEPTION(isolate, Runtime::DefineObjectProperty( | |
| 7450 target, arguments_str, arguments, NONE), | |
| 7451 JSObject); | |
| 7452 return target; | |
| 7453 } | |
| 7454 | |
| 7455 | |
| 7456 // Compile and evaluate source for the given context. | |
| 7457 static MaybeHandle<Object> DebugEvaluate(Isolate* isolate, | |
| 7458 Handle<Context> context, | |
| 7459 Handle<Object> context_extension, | |
| 7460 Handle<Object> receiver, | |
| 7461 Handle<String> source) { | |
| 7462 if (context_extension->IsJSObject()) { | |
| 7463 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension); | |
| 7464 Handle<JSFunction> closure(context->closure(), isolate); | |
| 7465 context = isolate->factory()->NewWithContext(closure, context, extension); | |
| 7466 } | |
| 7467 | |
| 7468 Handle<JSFunction> eval_fun; | |
| 7469 ASSIGN_RETURN_ON_EXCEPTION( | |
| 7470 isolate, eval_fun, Compiler::GetFunctionFromEval(source, context, SLOPPY, | |
| 7471 NO_PARSE_RESTRICTION, | |
| 7472 RelocInfo::kNoPosition), | |
| 7473 Object); | |
| 7474 | |
| 7475 Handle<Object> result; | |
| 7476 ASSIGN_RETURN_ON_EXCEPTION( | |
| 7477 isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL), | |
| 7478 Object); | |
| 7479 | |
| 7480 // Skip the global proxy as it has no properties and always delegates to the | |
| 7481 // real global object. | |
| 7482 if (result->IsJSGlobalProxy()) { | |
| 7483 PrototypeIterator iter(isolate, result); | |
| 7484 // TODO(verwaest): This will crash when the global proxy is detached. | |
| 7485 result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
| 7486 } | |
| 7487 | |
| 7488 // Clear the oneshot breakpoints so that the debugger does not step further. | |
| 7489 isolate->debug()->ClearStepping(); | |
| 7490 return result; | |
| 7491 } | |
| 7492 | |
| 7493 | |
| 7494 static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) { | |
| 7495 Handle<JSObject> result = | |
| 7496 isolate->factory()->NewJSObject(isolate->object_function()); | |
| 7497 Handle<Map> new_map = Map::Copy(Handle<Map>(result->map())); | |
| 7498 new_map->set_prototype(*isolate->factory()->null_value()); | |
| 7499 JSObject::MigrateToMap(result, new_map); | |
| 7500 return result; | |
| 7501 } | |
| 7502 | |
| 7503 | |
| 7504 // Evaluate a piece of JavaScript in the context of a stack frame for | |
| 7505 // debugging. Things that need special attention are: | |
| 7506 // - Parameters and stack-allocated locals need to be materialized. Altered | |
| 7507 // values need to be written back to the stack afterwards. | |
| 7508 // - The arguments object needs to materialized. | |
| 7509 RUNTIME_FUNCTION(Runtime_DebugEvaluate) { | |
| 7510 HandleScope scope(isolate); | |
| 7511 | |
| 7512 // Check the execution state and decode arguments frame and source to be | |
| 7513 // evaluated. | |
| 7514 DCHECK(args.length() == 6); | |
| 7515 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 7516 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 7517 | |
| 7518 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); | |
| 7519 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); | |
| 7520 CONVERT_ARG_HANDLE_CHECKED(String, source, 3); | |
| 7521 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); | |
| 7522 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5); | |
| 7523 | |
| 7524 // Handle the processing of break. | |
| 7525 DisableBreak disable_break_scope(isolate->debug(), disable_break); | |
| 7526 | |
| 7527 // Get the frame where the debugging is performed. | |
| 7528 StackFrame::Id id = UnwrapFrameId(wrapped_id); | |
| 7529 JavaScriptFrameIterator it(isolate, id); | |
| 7530 JavaScriptFrame* frame = it.frame(); | |
| 7531 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | |
| 7532 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); | |
| 7533 | |
| 7534 // Traverse the saved contexts chain to find the active context for the | |
| 7535 // selected frame. | |
| 7536 SaveContext* save = FindSavedContextForFrame(isolate, frame); | |
| 7537 | |
| 7538 SaveContext savex(isolate); | |
| 7539 isolate->set_context(*(save->context())); | |
| 7540 | |
| 7541 // Materialize stack locals and the arguments object. | |
| 7542 Handle<JSObject> materialized = NewJSObjectWithNullProto(isolate); | |
| 7543 | |
| 7544 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 7545 isolate, materialized, | |
| 7546 MaterializeStackLocalsWithFrameInspector(isolate, materialized, function, | |
| 7547 &frame_inspector)); | |
| 7548 | |
| 7549 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 7550 isolate, materialized, | |
| 7551 MaterializeArgumentsObject(isolate, materialized, function)); | |
| 7552 | |
| 7553 // At this point, the lookup chain may look like this: | |
| 7554 // [inner context] -> [function stack]+[function context] -> [outer context] | |
| 7555 // The function stack is not an actual context, it complements the function | |
| 7556 // context. In order to have the same lookup chain when debug-evaluating, | |
| 7557 // we materialize the stack and insert it into the context chain as a | |
| 7558 // with-context before the function context. | |
| 7559 // [inner context] -> [with context] -> [function context] -> [outer context] | |
| 7560 // Ordering the with-context before the function context forces a dynamic | |
| 7561 // lookup instead of a static lookup that could fail as the scope info is | |
| 7562 // outdated and may expect variables to still be stack-allocated. | |
| 7563 // Afterwards, we write changes to the with-context back to the stack | |
| 7564 // and remove it from the context chain. | |
| 7565 // This could cause lookup failures if debug-evaluate creates a closure that | |
| 7566 // uses this temporary context chain. | |
| 7567 | |
| 7568 Handle<Context> eval_context(Context::cast(frame_inspector.GetContext())); | |
| 7569 DCHECK(!eval_context.is_null()); | |
| 7570 Handle<Context> function_context = eval_context; | |
| 7571 Handle<Context> outer_context(function->context(), isolate); | |
| 7572 Handle<Context> inner_context; | |
| 7573 // We iterate to find the function's context. If the function has no | |
| 7574 // context-allocated variables, we iterate until we hit the outer context. | |
| 7575 while (!function_context->IsFunctionContext() && | |
| 7576 !function_context.is_identical_to(outer_context)) { | |
| 7577 inner_context = function_context; | |
| 7578 function_context = Handle<Context>(function_context->previous(), isolate); | |
| 7579 } | |
| 7580 | |
| 7581 Handle<Context> materialized_context = isolate->factory()->NewWithContext( | |
| 7582 function, function_context, materialized); | |
| 7583 | |
| 7584 if (inner_context.is_null()) { | |
| 7585 // No inner context. The with-context is now inner-most. | |
| 7586 eval_context = materialized_context; | |
| 7587 } else { | |
| 7588 inner_context->set_previous(*materialized_context); | |
| 7589 } | |
| 7590 | |
| 7591 Handle<Object> receiver(frame->receiver(), isolate); | |
| 7592 MaybeHandle<Object> maybe_result = | |
| 7593 DebugEvaluate(isolate, eval_context, context_extension, receiver, source); | |
| 7594 | |
| 7595 // Remove with-context if it was inserted in between. | |
| 7596 if (!inner_context.is_null()) inner_context->set_previous(*function_context); | |
| 7597 | |
| 7598 Handle<Object> result; | |
| 7599 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result); | |
| 7600 | |
| 7601 // Write back potential changes to materialized stack locals to the stack. | |
| 7602 UpdateStackLocalsFromMaterializedObject(isolate, materialized, function, | |
| 7603 frame, inlined_jsframe_index); | |
| 7604 | |
| 7605 return *result; | |
| 7606 } | |
| 7607 | |
| 7608 | |
| 7609 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { | |
| 7610 HandleScope scope(isolate); | |
| 7611 | |
| 7612 // Check the execution state and decode arguments frame and source to be | |
| 7613 // evaluated. | |
| 7614 DCHECK(args.length() == 4); | |
| 7615 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 7616 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 7617 | |
| 7618 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); | |
| 7619 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); | |
| 7620 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3); | |
| 7621 | |
| 7622 // Handle the processing of break. | |
| 7623 DisableBreak disable_break_scope(isolate->debug(), disable_break); | |
| 7624 | |
| 7625 // Enter the top context from before the debugger was invoked. | |
| 7626 SaveContext save(isolate); | |
| 7627 SaveContext* top = &save; | |
| 7628 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) { | |
| 7629 top = top->prev(); | |
| 7630 } | |
| 7631 if (top != NULL) { | |
| 7632 isolate->set_context(*top->context()); | |
| 7633 } | |
| 7634 | |
| 7635 // Get the native context now set to the top context from before the | |
| 7636 // debugger was invoked. | |
| 7637 Handle<Context> context = isolate->native_context(); | |
| 7638 Handle<JSObject> receiver(context->global_proxy()); | |
| 7639 Handle<Object> result; | |
| 7640 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 7641 isolate, result, | |
| 7642 DebugEvaluate(isolate, context, context_extension, receiver, source)); | |
| 7643 return *result; | |
| 7644 } | |
| 7645 | |
| 7646 | |
| 7647 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) { | |
| 7648 HandleScope scope(isolate); | |
| 7649 DCHECK(args.length() == 0); | |
| 7650 | |
| 7651 // Fill the script objects. | |
| 7652 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts(); | |
| 7653 | |
| 7654 // Convert the script objects to proper JS objects. | |
| 7655 for (int i = 0; i < instances->length(); i++) { | |
| 7656 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); | |
| 7657 // Get the script wrapper in a local handle before calling GetScriptWrapper, | |
| 7658 // because using | |
| 7659 // instances->set(i, *GetScriptWrapper(script)) | |
| 7660 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might | |
| 7661 // already have dereferenced the instances handle. | |
| 7662 Handle<JSObject> wrapper = Script::GetWrapper(script); | |
| 7663 instances->set(i, *wrapper); | |
| 7664 } | |
| 7665 | |
| 7666 // Return result as a JS array. | |
| 7667 Handle<JSObject> result = | |
| 7668 isolate->factory()->NewJSObject(isolate->array_function()); | |
| 7669 JSArray::SetContent(Handle<JSArray>::cast(result), instances); | |
| 7670 return *result; | |
| 7671 } | |
| 7672 | |
| 7673 | |
| 7674 // Helper function used by Runtime_DebugReferencedBy below. | |
| 7675 static int DebugReferencedBy(HeapIterator* iterator, JSObject* target, | |
| 7676 Object* instance_filter, int max_references, | |
| 7677 FixedArray* instances, int instances_size, | |
| 7678 JSFunction* arguments_function) { | |
| 7679 Isolate* isolate = target->GetIsolate(); | |
| 7680 SealHandleScope shs(isolate); | |
| 7681 DisallowHeapAllocation no_allocation; | |
| 7682 | |
| 7683 // Iterate the heap. | |
| 7684 int count = 0; | |
| 7685 JSObject* last = NULL; | |
| 7686 HeapObject* heap_obj = NULL; | |
| 7687 while (((heap_obj = iterator->next()) != NULL) && | |
| 7688 (max_references == 0 || count < max_references)) { | |
| 7689 // Only look at all JSObjects. | |
| 7690 if (heap_obj->IsJSObject()) { | |
| 7691 // Skip context extension objects and argument arrays as these are | |
| 7692 // checked in the context of functions using them. | |
| 7693 JSObject* obj = JSObject::cast(heap_obj); | |
| 7694 if (obj->IsJSContextExtensionObject() || | |
| 7695 obj->map()->constructor() == arguments_function) { | |
| 7696 continue; | |
| 7697 } | |
| 7698 | |
| 7699 // Check if the JS object has a reference to the object looked for. | |
| 7700 if (obj->ReferencesObject(target)) { | |
| 7701 // Check instance filter if supplied. This is normally used to avoid | |
| 7702 // references from mirror objects (see Runtime_IsInPrototypeChain). | |
| 7703 if (!instance_filter->IsUndefined()) { | |
| 7704 for (PrototypeIterator iter(isolate, obj); !iter.IsAtEnd(); | |
| 7705 iter.Advance()) { | |
| 7706 if (iter.GetCurrent() == instance_filter) { | |
| 7707 obj = NULL; // Don't add this object. | |
| 7708 break; | |
| 7709 } | |
| 7710 } | |
| 7711 } | |
| 7712 | |
| 7713 if (obj != NULL) { | |
| 7714 // Valid reference found add to instance array if supplied an update | |
| 7715 // count. | |
| 7716 if (instances != NULL && count < instances_size) { | |
| 7717 instances->set(count, obj); | |
| 7718 } | |
| 7719 last = obj; | |
| 7720 count++; | |
| 7721 } | |
| 7722 } | |
| 7723 } | |
| 7724 } | |
| 7725 | |
| 7726 // Check for circular reference only. This can happen when the object is only | |
| 7727 // referenced from mirrors and has a circular reference in which case the | |
| 7728 // object is not really alive and would have been garbage collected if not | |
| 7729 // referenced from the mirror. | |
| 7730 if (count == 1 && last == target) { | |
| 7731 count = 0; | |
| 7732 } | |
| 7733 | |
| 7734 // Return the number of referencing objects found. | |
| 7735 return count; | |
| 7736 } | |
| 7737 | |
| 7738 | |
| 7739 // Scan the heap for objects with direct references to an object | |
| 7740 // args[0]: the object to find references to | |
| 7741 // args[1]: constructor function for instances to exclude (Mirror) | |
| 7742 // args[2]: the the maximum number of objects to return | |
| 7743 RUNTIME_FUNCTION(Runtime_DebugReferencedBy) { | |
| 7744 HandleScope scope(isolate); | |
| 7745 DCHECK(args.length() == 3); | |
| 7746 | |
| 7747 // Check parameters. | |
| 7748 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0); | |
| 7749 CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1); | |
| 7750 RUNTIME_ASSERT(instance_filter->IsUndefined() || | |
| 7751 instance_filter->IsJSObject()); | |
| 7752 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); | |
| 7753 RUNTIME_ASSERT(max_references >= 0); | |
| 7754 | |
| 7755 | |
| 7756 // Get the constructor function for context extension and arguments array. | |
| 7757 Handle<JSFunction> arguments_function( | |
| 7758 JSFunction::cast(isolate->sloppy_arguments_map()->constructor())); | |
| 7759 | |
| 7760 // Get the number of referencing objects. | |
| 7761 int count; | |
| 7762 // First perform a full GC in order to avoid dead objects and to make the heap | |
| 7763 // iterable. | |
| 7764 Heap* heap = isolate->heap(); | |
| 7765 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); | |
| 7766 { | |
| 7767 HeapIterator heap_iterator(heap); | |
| 7768 count = DebugReferencedBy(&heap_iterator, *target, *instance_filter, | |
| 7769 max_references, NULL, 0, *arguments_function); | |
| 7770 } | |
| 7771 | |
| 7772 // Allocate an array to hold the result. | |
| 7773 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count); | |
| 7774 | |
| 7775 // Fill the referencing objects. | |
| 7776 { | |
| 7777 HeapIterator heap_iterator(heap); | |
| 7778 count = DebugReferencedBy(&heap_iterator, *target, *instance_filter, | |
| 7779 max_references, *instances, count, | |
| 7780 *arguments_function); | |
| 7781 } | |
| 7782 | |
| 7783 // Return result as JS array. | |
| 7784 Handle<JSFunction> constructor = isolate->array_function(); | |
| 7785 | |
| 7786 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); | |
| 7787 JSArray::SetContent(Handle<JSArray>::cast(result), instances); | |
| 7788 return *result; | |
| 7789 } | |
| 7790 | |
| 7791 | |
| 7792 // Helper function used by Runtime_DebugConstructedBy below. | |
| 7793 static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor, | |
| 7794 int max_references, FixedArray* instances, | |
| 7795 int instances_size) { | |
| 7796 DisallowHeapAllocation no_allocation; | |
| 7797 | |
| 7798 // Iterate the heap. | |
| 7799 int count = 0; | |
| 7800 HeapObject* heap_obj = NULL; | |
| 7801 while (((heap_obj = iterator->next()) != NULL) && | |
| 7802 (max_references == 0 || count < max_references)) { | |
| 7803 // Only look at all JSObjects. | |
| 7804 if (heap_obj->IsJSObject()) { | |
| 7805 JSObject* obj = JSObject::cast(heap_obj); | |
| 7806 if (obj->map()->constructor() == constructor) { | |
| 7807 // Valid reference found add to instance array if supplied an update | |
| 7808 // count. | |
| 7809 if (instances != NULL && count < instances_size) { | |
| 7810 instances->set(count, obj); | |
| 7811 } | |
| 7812 count++; | |
| 7813 } | |
| 7814 } | |
| 7815 } | |
| 7816 | |
| 7817 // Return the number of referencing objects found. | |
| 7818 return count; | |
| 7819 } | |
| 7820 | |
| 7821 | |
| 7822 // Scan the heap for objects constructed by a specific function. | |
| 7823 // args[0]: the constructor to find instances of | |
| 7824 // args[1]: the the maximum number of objects to return | |
| 7825 RUNTIME_FUNCTION(Runtime_DebugConstructedBy) { | |
| 7826 HandleScope scope(isolate); | |
| 7827 DCHECK(args.length() == 2); | |
| 7828 | |
| 7829 | |
| 7830 // Check parameters. | |
| 7831 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0); | |
| 7832 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); | |
| 7833 RUNTIME_ASSERT(max_references >= 0); | |
| 7834 | |
| 7835 // Get the number of referencing objects. | |
| 7836 int count; | |
| 7837 // First perform a full GC in order to avoid dead objects and to make the heap | |
| 7838 // iterable. | |
| 7839 Heap* heap = isolate->heap(); | |
| 7840 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); | |
| 7841 { | |
| 7842 HeapIterator heap_iterator(heap); | |
| 7843 count = DebugConstructedBy(&heap_iterator, *constructor, max_references, | |
| 7844 NULL, 0); | |
| 7845 } | |
| 7846 | |
| 7847 // Allocate an array to hold the result. | |
| 7848 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count); | |
| 7849 | |
| 7850 // Fill the referencing objects. | |
| 7851 { | |
| 7852 HeapIterator heap_iterator2(heap); | |
| 7853 count = DebugConstructedBy(&heap_iterator2, *constructor, max_references, | |
| 7854 *instances, count); | |
| 7855 } | |
| 7856 | |
| 7857 // Return result as JS array. | |
| 7858 Handle<JSFunction> array_function = isolate->array_function(); | |
| 7859 Handle<JSObject> result = isolate->factory()->NewJSObject(array_function); | |
| 7860 JSArray::SetContent(Handle<JSArray>::cast(result), instances); | |
| 7861 return *result; | |
| 7862 } | |
| 7863 | |
| 7864 | |
| 7865 // Find the effective prototype object as returned by __proto__. | |
| 7866 // args[0]: the object to find the prototype for. | |
| 7867 RUNTIME_FUNCTION(Runtime_DebugGetPrototype) { | |
| 7868 HandleScope shs(isolate); | |
| 7869 DCHECK(args.length() == 1); | |
| 7870 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); | |
| 7871 return *GetPrototypeSkipHiddenPrototypes(isolate, obj); | |
| 7872 } | |
| 7873 | |
| 7874 | |
| 7875 // Patches script source (should be called upon BeforeCompile event). | |
| 7876 RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) { | |
| 7877 HandleScope scope(isolate); | |
| 7878 DCHECK(args.length() == 2); | |
| 7879 | |
| 7880 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0); | |
| 7881 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); | |
| 7882 | |
| 7883 RUNTIME_ASSERT(script_wrapper->value()->IsScript()); | |
| 7884 Handle<Script> script(Script::cast(script_wrapper->value())); | |
| 7885 | |
| 7886 int compilation_state = script->compilation_state(); | |
| 7887 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL); | |
| 7888 script->set_source(*source); | |
| 7889 | |
| 7890 return isolate->heap()->undefined_value(); | |
| 7891 } | |
| 7892 | |
| 7893 | |
| 7894 RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) { | |
| 7895 HandleScope scope(isolate); | |
| 7896 #ifdef DEBUG | |
| 7897 DCHECK(args.length() == 1); | |
| 7898 // Get the function and make sure it is compiled. | |
| 7899 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); | |
| 7900 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) { | |
| 7901 return isolate->heap()->exception(); | |
| 7902 } | |
| 7903 OFStream os(stdout); | |
| 7904 func->code()->Print(os); | |
| 7905 os << endl; | |
| 7906 #endif // DEBUG | |
| 7907 return isolate->heap()->undefined_value(); | |
| 7908 } | |
| 7909 | |
| 7910 | |
| 7911 RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) { | |
| 7912 HandleScope scope(isolate); | |
| 7913 #ifdef DEBUG | |
| 7914 DCHECK(args.length() == 1); | |
| 7915 // Get the function and make sure it is compiled. | |
| 7916 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); | |
| 7917 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) { | |
| 7918 return isolate->heap()->exception(); | |
| 7919 } | |
| 7920 OFStream os(stdout); | |
| 7921 func->shared()->construct_stub()->Print(os); | |
| 7922 os << endl; | |
| 7923 #endif // DEBUG | |
| 7924 return isolate->heap()->undefined_value(); | |
| 7925 } | |
| 7926 | |
| 7927 | |
| 7928 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) { | |
| 7929 SealHandleScope shs(isolate); | |
| 7930 DCHECK(args.length() == 1); | |
| 7931 | |
| 7932 CONVERT_ARG_CHECKED(JSFunction, f, 0); | |
| 7933 return f->shared()->inferred_name(); | |
| 7934 } | |
| 7935 | |
| 7936 | |
| 7937 static int FindSharedFunctionInfosForScript(HeapIterator* iterator, | |
| 7938 Script* script, | |
| 7939 FixedArray* buffer) { | |
| 7940 DisallowHeapAllocation no_allocation; | |
| 7941 int counter = 0; | |
| 7942 int buffer_size = buffer->length(); | |
| 7943 for (HeapObject* obj = iterator->next(); obj != NULL; | |
| 7944 obj = iterator->next()) { | |
| 7945 DCHECK(obj != NULL); | |
| 7946 if (!obj->IsSharedFunctionInfo()) { | |
| 7947 continue; | |
| 7948 } | |
| 7949 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); | |
| 7950 if (shared->script() != script) { | |
| 7951 continue; | |
| 7952 } | |
| 7953 if (counter < buffer_size) { | |
| 7954 buffer->set(counter, shared); | |
| 7955 } | |
| 7956 counter++; | |
| 7957 } | |
| 7958 return counter; | |
| 7959 } | |
| 7960 | |
| 7961 | |
| 7962 // For a script finds all SharedFunctionInfo's in the heap that points | |
| 7963 // to this script. Returns JSArray of SharedFunctionInfo wrapped | |
| 7964 // in OpaqueReferences. | |
| 7965 RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) { | |
| 7966 HandleScope scope(isolate); | |
| 7967 CHECK(isolate->debug()->live_edit_enabled()); | |
| 7968 DCHECK(args.length() == 1); | |
| 7969 CONVERT_ARG_CHECKED(JSValue, script_value, 0); | |
| 7970 | |
| 7971 RUNTIME_ASSERT(script_value->value()->IsScript()); | |
| 7972 Handle<Script> script = Handle<Script>(Script::cast(script_value->value())); | |
| 7973 | |
| 7974 const int kBufferSize = 32; | |
| 7975 | |
| 7976 Handle<FixedArray> array; | |
| 7977 array = isolate->factory()->NewFixedArray(kBufferSize); | |
| 7978 int number; | |
| 7979 Heap* heap = isolate->heap(); | |
| 7980 { | |
| 7981 HeapIterator heap_iterator(heap); | |
| 7982 Script* scr = *script; | |
| 7983 FixedArray* arr = *array; | |
| 7984 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); | |
| 7985 } | |
| 7986 if (number > kBufferSize) { | |
| 7987 array = isolate->factory()->NewFixedArray(number); | |
| 7988 HeapIterator heap_iterator(heap); | |
| 7989 Script* scr = *script; | |
| 7990 FixedArray* arr = *array; | |
| 7991 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); | |
| 7992 } | |
| 7993 | |
| 7994 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array); | |
| 7995 result->set_length(Smi::FromInt(number)); | |
| 7996 | |
| 7997 LiveEdit::WrapSharedFunctionInfos(result); | |
| 7998 | |
| 7999 return *result; | |
| 8000 } | |
| 8001 | |
| 8002 | |
| 8003 // For a script calculates compilation information about all its functions. | |
| 8004 // The script source is explicitly specified by the second argument. | |
| 8005 // The source of the actual script is not used, however it is important that | |
| 8006 // all generated code keeps references to this particular instance of script. | |
| 8007 // Returns a JSArray of compilation infos. The array is ordered so that | |
| 8008 // each function with all its descendant is always stored in a continues range | |
| 8009 // with the function itself going first. The root function is a script function. | |
| 8010 RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) { | |
| 8011 HandleScope scope(isolate); | |
| 8012 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8013 DCHECK(args.length() == 2); | |
| 8014 CONVERT_ARG_CHECKED(JSValue, script, 0); | |
| 8015 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); | |
| 8016 | |
| 8017 RUNTIME_ASSERT(script->value()->IsScript()); | |
| 8018 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); | |
| 8019 | |
| 8020 Handle<JSArray> result; | |
| 8021 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 8022 isolate, result, LiveEdit::GatherCompileInfo(script_handle, source)); | |
| 8023 return *result; | |
| 8024 } | |
| 8025 | |
| 8026 | |
| 8027 // Changes the source of the script to a new_source. | |
| 8028 // If old_script_name is provided (i.e. is a String), also creates a copy of | |
| 8029 // the script with its original source and sends notification to debugger. | |
| 8030 RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) { | |
| 8031 HandleScope scope(isolate); | |
| 8032 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8033 DCHECK(args.length() == 3); | |
| 8034 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0); | |
| 8035 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1); | |
| 8036 CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2); | |
| 8037 | |
| 8038 RUNTIME_ASSERT(original_script_value->value()->IsScript()); | |
| 8039 Handle<Script> original_script(Script::cast(original_script_value->value())); | |
| 8040 | |
| 8041 Handle<Object> old_script = LiveEdit::ChangeScriptSource( | |
| 8042 original_script, new_source, old_script_name); | |
| 8043 | |
| 8044 if (old_script->IsScript()) { | |
| 8045 Handle<Script> script_handle = Handle<Script>::cast(old_script); | |
| 8046 return *Script::GetWrapper(script_handle); | |
| 8047 } else { | |
| 8048 return isolate->heap()->null_value(); | |
| 8049 } | |
| 8050 } | |
| 8051 | |
| 8052 | |
| 8053 RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) { | |
| 8054 HandleScope scope(isolate); | |
| 8055 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8056 DCHECK(args.length() == 1); | |
| 8057 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0); | |
| 8058 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info)); | |
| 8059 | |
| 8060 LiveEdit::FunctionSourceUpdated(shared_info); | |
| 8061 return isolate->heap()->undefined_value(); | |
| 8062 } | |
| 8063 | |
| 8064 | |
| 8065 // Replaces code of SharedFunctionInfo with a new one. | |
| 8066 RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) { | |
| 8067 HandleScope scope(isolate); | |
| 8068 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8069 DCHECK(args.length() == 2); | |
| 8070 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0); | |
| 8071 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1); | |
| 8072 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info)); | |
| 8073 | |
| 8074 LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); | |
| 8075 return isolate->heap()->undefined_value(); | |
| 8076 } | |
| 8077 | |
| 8078 | |
| 8079 // Connects SharedFunctionInfo to another script. | |
| 8080 RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) { | |
| 8081 HandleScope scope(isolate); | |
| 8082 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8083 DCHECK(args.length() == 2); | |
| 8084 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); | |
| 8085 CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1); | |
| 8086 | |
| 8087 if (function_object->IsJSValue()) { | |
| 8088 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object); | |
| 8089 if (script_object->IsJSValue()) { | |
| 8090 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript()); | |
| 8091 Script* script = Script::cast(JSValue::cast(*script_object)->value()); | |
| 8092 script_object = Handle<Object>(script, isolate); | |
| 8093 } | |
| 8094 RUNTIME_ASSERT(function_wrapper->value()->IsSharedFunctionInfo()); | |
| 8095 LiveEdit::SetFunctionScript(function_wrapper, script_object); | |
| 8096 } else { | |
| 8097 // Just ignore this. We may not have a SharedFunctionInfo for some functions | |
| 8098 // and we check it in this function. | |
| 8099 } | |
| 8100 | |
| 8101 return isolate->heap()->undefined_value(); | |
| 8102 } | |
| 8103 | |
| 8104 | |
| 8105 // In a code of a parent function replaces original function as embedded object | |
| 8106 // with a substitution one. | |
| 8107 RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) { | |
| 8108 HandleScope scope(isolate); | |
| 8109 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8110 DCHECK(args.length() == 3); | |
| 8111 | |
| 8112 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0); | |
| 8113 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1); | |
| 8114 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2); | |
| 8115 RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo()); | |
| 8116 RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo()); | |
| 8117 RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo()); | |
| 8118 | |
| 8119 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper, | |
| 8120 subst_wrapper); | |
| 8121 return isolate->heap()->undefined_value(); | |
| 8122 } | |
| 8123 | |
| 8124 | |
| 8125 // Updates positions of a shared function info (first parameter) according | |
| 8126 // to script source change. Text change is described in second parameter as | |
| 8127 // array of groups of 3 numbers: | |
| 8128 // (change_begin, change_end, change_end_new_position). | |
| 8129 // Each group describes a change in text; groups are sorted by change_begin. | |
| 8130 RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) { | |
| 8131 HandleScope scope(isolate); | |
| 8132 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8133 DCHECK(args.length() == 2); | |
| 8134 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); | |
| 8135 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1); | |
| 8136 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array)) | |
| 8137 | |
| 8138 LiveEdit::PatchFunctionPositions(shared_array, position_change_array); | |
| 8139 return isolate->heap()->undefined_value(); | |
| 8140 } | |
| 8141 | |
| 8142 | |
| 8143 // For array of SharedFunctionInfo's (each wrapped in JSValue) | |
| 8144 // checks that none of them have activations on stacks (of any thread). | |
| 8145 // Returns array of the same length with corresponding results of | |
| 8146 // LiveEdit::FunctionPatchabilityStatus type. | |
| 8147 RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) { | |
| 8148 HandleScope scope(isolate); | |
| 8149 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8150 DCHECK(args.length() == 2); | |
| 8151 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); | |
| 8152 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1); | |
| 8153 RUNTIME_ASSERT(shared_array->length()->IsSmi()); | |
| 8154 RUNTIME_ASSERT(shared_array->HasFastElements()) | |
| 8155 int array_length = Smi::cast(shared_array->length())->value(); | |
| 8156 for (int i = 0; i < array_length; i++) { | |
| 8157 Handle<Object> element = | |
| 8158 Object::GetElement(isolate, shared_array, i).ToHandleChecked(); | |
| 8159 RUNTIME_ASSERT( | |
| 8160 element->IsJSValue() && | |
| 8161 Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo()); | |
| 8162 } | |
| 8163 | |
| 8164 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop); | |
| 8165 } | |
| 8166 | |
| 8167 | |
| 8168 // Compares 2 strings line-by-line, then token-wise and returns diff in form | |
| 8169 // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list | |
| 8170 // of diff chunks. | |
| 8171 RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) { | |
| 8172 HandleScope scope(isolate); | |
| 8173 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8174 DCHECK(args.length() == 2); | |
| 8175 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0); | |
| 8176 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1); | |
| 8177 | |
| 8178 return *LiveEdit::CompareStrings(s1, s2); | |
| 8179 } | |
| 8180 | |
| 8181 | |
| 8182 // Restarts a call frame and completely drops all frames above. | |
| 8183 // Returns true if successful. Otherwise returns undefined or an error message. | |
| 8184 RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) { | |
| 8185 HandleScope scope(isolate); | |
| 8186 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8187 DCHECK(args.length() == 2); | |
| 8188 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); | |
| 8189 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); | |
| 8190 | |
| 8191 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); | |
| 8192 Heap* heap = isolate->heap(); | |
| 8193 | |
| 8194 // Find the relevant frame with the requested index. | |
| 8195 StackFrame::Id id = isolate->debug()->break_frame_id(); | |
| 8196 if (id == StackFrame::NO_ID) { | |
| 8197 // If there are no JavaScript stack frames return undefined. | |
| 8198 return heap->undefined_value(); | |
| 8199 } | |
| 8200 | |
| 8201 JavaScriptFrameIterator it(isolate, id); | |
| 8202 int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index); | |
| 8203 if (inlined_jsframe_index == -1) return heap->undefined_value(); | |
| 8204 // We don't really care what the inlined frame index is, since we are | |
| 8205 // throwing away the entire frame anyways. | |
| 8206 const char* error_message = LiveEdit::RestartFrame(it.frame()); | |
| 8207 if (error_message) { | |
| 8208 return *(isolate->factory()->InternalizeUtf8String(error_message)); | |
| 8209 } | |
| 8210 return heap->true_value(); | |
| 8211 } | |
| 8212 | |
| 8213 | |
| 8214 // A testing entry. Returns statement position which is the closest to | |
| 8215 // source_position. | |
| 8216 RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) { | |
| 8217 HandleScope scope(isolate); | |
| 8218 CHECK(isolate->debug()->live_edit_enabled()); | |
| 8219 DCHECK(args.length() == 2); | |
| 8220 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
| 8221 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); | |
| 8222 | |
| 8223 Handle<Code> code(function->code(), isolate); | |
| 8224 | |
| 8225 if (code->kind() != Code::FUNCTION && | |
| 8226 code->kind() != Code::OPTIMIZED_FUNCTION) { | |
| 8227 return isolate->heap()->undefined_value(); | |
| 8228 } | |
| 8229 | |
| 8230 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION)); | |
| 8231 int closest_pc = 0; | |
| 8232 int distance = kMaxInt; | |
| 8233 while (!it.done()) { | |
| 8234 int statement_position = static_cast<int>(it.rinfo()->data()); | |
| 8235 // Check if this break point is closer that what was previously found. | |
| 8236 if (source_position <= statement_position && | |
| 8237 statement_position - source_position < distance) { | |
| 8238 closest_pc = | |
| 8239 static_cast<int>(it.rinfo()->pc() - code->instruction_start()); | |
| 8240 distance = statement_position - source_position; | |
| 8241 // Check whether we can't get any closer. | |
| 8242 if (distance == 0) break; | |
| 8243 } | |
| 8244 it.next(); | |
| 8245 } | |
| 8246 | |
| 8247 return Smi::FromInt(closest_pc); | |
| 8248 } | |
| 8249 | |
| 8250 | |
| 8251 // Calls specified function with or without entering the debugger. | |
| 8252 // This is used in unit tests to run code as if debugger is entered or simply | |
| 8253 // to have a stack with C++ frame in the middle. | |
| 8254 RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) { | |
| 8255 HandleScope scope(isolate); | |
| 8256 DCHECK(args.length() == 2); | |
| 8257 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); | |
| 8258 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1); | |
| 8259 | |
| 8260 MaybeHandle<Object> maybe_result; | |
| 8261 if (without_debugger) { | |
| 8262 maybe_result = Execution::Call(isolate, function, | |
| 8263 handle(function->global_proxy()), 0, NULL); | |
| 8264 } else { | |
| 8265 DebugScope debug_scope(isolate->debug()); | |
| 8266 maybe_result = Execution::Call(isolate, function, | |
| 8267 handle(function->global_proxy()), 0, NULL); | |
| 8268 } | |
| 8269 Handle<Object> result; | |
| 8270 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result); | |
| 8271 return *result; | |
| 8272 } | |
| 8273 | |
| 8274 | |
| 8275 // Performs a GC. | |
| 8276 // Presently, it only does a full GC. | |
| 8277 RUNTIME_FUNCTION(Runtime_CollectGarbage) { | |
| 8278 SealHandleScope shs(isolate); | |
| 8279 DCHECK(args.length() == 1); | |
| 8280 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage"); | |
| 8281 return isolate->heap()->undefined_value(); | |
| 8282 } | |
| 8283 | |
| 8284 | |
| 8285 // Gets the current heap usage. | |
| 8286 RUNTIME_FUNCTION(Runtime_GetHeapUsage) { | |
| 8287 SealHandleScope shs(isolate); | |
| 8288 DCHECK(args.length() == 0); | |
| 8289 int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); | |
| 8290 if (!Smi::IsValid(usage)) { | |
| 8291 return *isolate->factory()->NewNumberFromInt(usage); | |
| 8292 } | |
| 8293 return Smi::FromInt(usage); | |
| 8294 } | |
| 8295 | |
| 8296 | |
| 8297 // Finds the script object from the script data. NOTE: This operation uses | |
| 8298 // heap traversal to find the function generated for the source position | |
| 8299 // for the requested break point. For lazily compiled functions several heap | |
| 8300 // traversals might be required rendering this operation as a rather slow | |
| 8301 // operation. However for setting break points which is normally done through | |
| 8302 // some kind of user interaction the performance is not crucial. | |
| 8303 static Handle<Object> Runtime_GetScriptFromScriptName( | |
| 8304 Handle<String> script_name) { | |
| 8305 // Scan the heap for Script objects to find the script with the requested | |
| 8306 // script data. | |
| 8307 Handle<Script> script; | |
| 8308 Factory* factory = script_name->GetIsolate()->factory(); | |
| 8309 Heap* heap = script_name->GetHeap(); | |
| 8310 HeapIterator iterator(heap); | |
| 8311 HeapObject* obj = NULL; | |
| 8312 while (script.is_null() && ((obj = iterator.next()) != NULL)) { | |
| 8313 // If a script is found check if it has the script data requested. | |
| 8314 if (obj->IsScript()) { | |
| 8315 if (Script::cast(obj)->name()->IsString()) { | |
| 8316 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) { | |
| 8317 script = Handle<Script>(Script::cast(obj)); | |
| 8318 } | |
| 8319 } | |
| 8320 } | |
| 8321 } | |
| 8322 | |
| 8323 // If no script with the requested script data is found return undefined. | |
| 8324 if (script.is_null()) return factory->undefined_value(); | |
| 8325 | |
| 8326 // Return the script found. | |
| 8327 return Script::GetWrapper(script); | |
| 8328 } | |
| 8329 | |
| 8330 | |
| 8331 // Get the script object from script data. NOTE: Regarding performance | |
| 8332 // see the NOTE for GetScriptFromScriptData. | |
| 8333 // args[0]: script data for the script to find the source for | |
| 8334 RUNTIME_FUNCTION(Runtime_GetScript) { | |
| 8335 HandleScope scope(isolate); | |
| 8336 | |
| 8337 DCHECK(args.length() == 1); | |
| 8338 | |
| 8339 CONVERT_ARG_CHECKED(String, script_name, 0); | |
| 8340 | |
| 8341 // Find the requested script. | |
| 8342 Handle<Object> result = | |
| 8343 Runtime_GetScriptFromScriptName(Handle<String>(script_name)); | |
| 8344 return *result; | |
| 8345 } | |
| 8346 | |
| 8347 | |
| 8348 // Collect the raw data for a stack trace. Returns an array of 4 | 5027 // Collect the raw data for a stack trace. Returns an array of 4 |
| 8349 // element segments each containing a receiver, function, code and | 5028 // element segments each containing a receiver, function, code and |
| 8350 // native code offset. | 5029 // native code offset. |
| 8351 RUNTIME_FUNCTION(Runtime_CollectStackTrace) { | 5030 RUNTIME_FUNCTION(Runtime_CollectStackTrace) { |
| 8352 HandleScope scope(isolate); | 5031 HandleScope scope(isolate); |
| 8353 DCHECK(args.length() == 2); | 5032 DCHECK(args.length() == 2); |
| 8354 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); | 5033 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); |
| 8355 CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1); | 5034 CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1); |
| 8356 | 5035 |
| 8357 if (!isolate->bootstrapper()->IsActive()) { | 5036 if (!isolate->bootstrapper()->IsActive()) { |
| 8358 // Optionally capture a more detailed stack trace for the message. | 5037 // Optionally capture a more detailed stack trace for the message. |
| 8359 isolate->CaptureAndSetDetailedStackTrace(error_object); | 5038 isolate->CaptureAndSetDetailedStackTrace(error_object); |
| 8360 // Capture a simple stack trace for the stack property. | 5039 // Capture a simple stack trace for the stack property. |
| 8361 isolate->CaptureAndSetSimpleStackTrace(error_object, caller); | 5040 isolate->CaptureAndSetSimpleStackTrace(error_object, caller); |
| 8362 } | 5041 } |
| 8363 return isolate->heap()->undefined_value(); | 5042 return isolate->heap()->undefined_value(); |
| 8364 } | 5043 } |
| 8365 | 5044 |
| 8366 | 5045 |
| 8367 // Returns V8 version as a string. | |
| 8368 RUNTIME_FUNCTION(Runtime_GetV8Version) { | |
| 8369 HandleScope scope(isolate); | |
| 8370 DCHECK(args.length() == 0); | |
| 8371 | |
| 8372 const char* version_string = v8::V8::GetVersion(); | |
| 8373 | |
| 8374 return *isolate->factory()->NewStringFromAsciiChecked(version_string); | |
| 8375 } | |
| 8376 | |
| 8377 | |
| 8378 // Returns function of generator activation. | |
| 8379 RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) { | |
| 8380 HandleScope scope(isolate); | |
| 8381 DCHECK(args.length() == 1); | |
| 8382 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
| 8383 | |
| 8384 return generator->function(); | |
| 8385 } | |
| 8386 | |
| 8387 | |
| 8388 // Returns context of generator activation. | |
| 8389 RUNTIME_FUNCTION(Runtime_GeneratorGetContext) { | |
| 8390 HandleScope scope(isolate); | |
| 8391 DCHECK(args.length() == 1); | |
| 8392 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
| 8393 | |
| 8394 return generator->context(); | |
| 8395 } | |
| 8396 | |
| 8397 | |
| 8398 // Returns receiver of generator activation. | |
| 8399 RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) { | |
| 8400 HandleScope scope(isolate); | |
| 8401 DCHECK(args.length() == 1); | |
| 8402 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
| 8403 | |
| 8404 return generator->receiver(); | |
| 8405 } | |
| 8406 | |
| 8407 | |
| 8408 // Returns generator continuation as a PC offset, or the magic -1 or 0 values. | |
| 8409 RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) { | |
| 8410 HandleScope scope(isolate); | |
| 8411 DCHECK(args.length() == 1); | |
| 8412 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
| 8413 | |
| 8414 return Smi::FromInt(generator->continuation()); | |
| 8415 } | |
| 8416 | |
| 8417 | |
| 8418 RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) { | |
| 8419 HandleScope scope(isolate); | |
| 8420 DCHECK(args.length() == 1); | |
| 8421 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); | |
| 8422 | |
| 8423 if (generator->is_suspended()) { | |
| 8424 Handle<Code> code(generator->function()->code(), isolate); | |
| 8425 int offset = generator->continuation(); | |
| 8426 | |
| 8427 RUNTIME_ASSERT(0 <= offset && offset < code->Size()); | |
| 8428 Address pc = code->address() + offset; | |
| 8429 | |
| 8430 return Smi::FromInt(code->SourcePosition(pc)); | |
| 8431 } | |
| 8432 | |
| 8433 return isolate->heap()->undefined_value(); | |
| 8434 } | |
| 8435 | |
| 8436 | |
| 8437 RUNTIME_FUNCTION(Runtime_LoadMutableDouble) { | 5046 RUNTIME_FUNCTION(Runtime_LoadMutableDouble) { |
| 8438 HandleScope scope(isolate); | 5047 HandleScope scope(isolate); |
| 8439 DCHECK(args.length() == 2); | 5048 DCHECK(args.length() == 2); |
| 8440 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); | 5049 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); |
| 8441 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1); | 5050 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1); |
| 8442 RUNTIME_ASSERT((index->value() & 1) == 1); | 5051 RUNTIME_ASSERT((index->value() & 1) == 1); |
| 8443 FieldIndex field_index = | 5052 FieldIndex field_index = |
| 8444 FieldIndex::ForLoadByFieldIndex(object->map(), index->value()); | 5053 FieldIndex::ForLoadByFieldIndex(object->map(), index->value()); |
| 8445 if (field_index.is_inobject()) { | 5054 if (field_index.is_inobject()) { |
| 8446 RUNTIME_ASSERT(field_index.property_index() < | 5055 RUNTIME_ASSERT(field_index.property_index() < |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8576 | 5185 |
| 8577 | 5186 |
| 8578 RUNTIME_FUNCTION(Runtime_MessageGetScript) { | 5187 RUNTIME_FUNCTION(Runtime_MessageGetScript) { |
| 8579 SealHandleScope shs(isolate); | 5188 SealHandleScope shs(isolate); |
| 8580 DCHECK(args.length() == 1); | 5189 DCHECK(args.length() == 1); |
| 8581 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); | 5190 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); |
| 8582 return message->script(); | 5191 return message->script(); |
| 8583 } | 5192 } |
| 8584 | 5193 |
| 8585 | 5194 |
| 8586 #ifdef DEBUG | |
| 8587 // ListNatives is ONLY used by the fuzz-natives.js in debug mode | |
| 8588 // Exclude the code in release mode. | |
| 8589 RUNTIME_FUNCTION(Runtime_ListNatives) { | |
| 8590 HandleScope scope(isolate); | |
| 8591 DCHECK(args.length() == 0); | |
| 8592 #define COUNT_ENTRY(Name, argc, ressize) +1 | |
| 8593 int entry_count = | |
| 8594 0 RUNTIME_FUNCTION_LIST(COUNT_ENTRY) INLINE_FUNCTION_LIST(COUNT_ENTRY) | |
| 8595 INLINE_OPTIMIZED_FUNCTION_LIST(COUNT_ENTRY); | |
| 8596 #undef COUNT_ENTRY | |
| 8597 Factory* factory = isolate->factory(); | |
| 8598 Handle<FixedArray> elements = factory->NewFixedArray(entry_count); | |
| 8599 int index = 0; | |
| 8600 bool inline_runtime_functions = false; | |
| 8601 #define ADD_ENTRY(Name, argc, ressize) \ | |
| 8602 { \ | |
| 8603 HandleScope inner(isolate); \ | |
| 8604 Handle<String> name; \ | |
| 8605 /* Inline runtime functions have an underscore in front of the name. */ \ | |
| 8606 if (inline_runtime_functions) { \ | |
| 8607 name = factory->NewStringFromStaticChars("_" #Name); \ | |
| 8608 } else { \ | |
| 8609 name = factory->NewStringFromStaticChars(#Name); \ | |
| 8610 } \ | |
| 8611 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \ | |
| 8612 pair_elements->set(0, *name); \ | |
| 8613 pair_elements->set(1, Smi::FromInt(argc)); \ | |
| 8614 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \ | |
| 8615 elements->set(index++, *pair); \ | |
| 8616 } | |
| 8617 inline_runtime_functions = false; | |
| 8618 RUNTIME_FUNCTION_LIST(ADD_ENTRY) | |
| 8619 INLINE_OPTIMIZED_FUNCTION_LIST(ADD_ENTRY) | |
| 8620 inline_runtime_functions = true; | |
| 8621 INLINE_FUNCTION_LIST(ADD_ENTRY) | |
| 8622 #undef ADD_ENTRY | |
| 8623 DCHECK_EQ(index, entry_count); | |
| 8624 Handle<JSArray> result = factory->NewJSArrayWithElements(elements); | |
| 8625 return *result; | |
| 8626 } | |
| 8627 #endif | |
| 8628 | |
| 8629 | |
| 8630 RUNTIME_FUNCTION(Runtime_IS_VAR) { | 5195 RUNTIME_FUNCTION(Runtime_IS_VAR) { |
| 8631 UNREACHABLE(); // implemented as macro in the parser | 5196 UNREACHABLE(); // implemented as macro in the parser |
| 8632 return NULL; | 5197 return NULL; |
| 8633 } | 5198 } |
| 8634 | 5199 |
| 8635 | 5200 |
| 8636 #define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \ | |
| 8637 RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) { \ | |
| 8638 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ | |
| 8639 return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \ | |
| 8640 } | |
| 8641 | |
| 8642 TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) | |
| 8643 | |
| 8644 #undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION | |
| 8645 | |
| 8646 | |
| 8647 #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \ | |
| 8648 RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \ | |
| 8649 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ | |
| 8650 return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \ | |
| 8651 } | |
| 8652 | |
| 8653 TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) | |
| 8654 | |
| 8655 #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION | |
| 8656 | |
| 8657 | |
| 8658 RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) { | 5201 RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) { |
| 8659 SealHandleScope shs(isolate); | 5202 SealHandleScope shs(isolate); |
| 8660 DCHECK(args.length() == 1); | 5203 DCHECK(args.length() == 1); |
| 8661 CONVERT_ARG_CHECKED(Object, obj, 0); | 5204 CONVERT_ARG_CHECKED(Object, obj, 0); |
| 8662 return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy()); | 5205 return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy()); |
| 8663 } | 5206 } |
| 8664 | 5207 |
| 8665 | 5208 |
| 8666 RUNTIME_FUNCTION(Runtime_IsObserved) { | 5209 RUNTIME_FUNCTION(Runtime_IsObserved) { |
| 8667 SealHandleScope shs(isolate); | 5210 SealHandleScope shs(isolate); |
| (...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9105 SealHandleScope shs(isolate); | 5648 SealHandleScope shs(isolate); |
| 9106 DCHECK(args.length() == 2); | 5649 DCHECK(args.length() == 2); |
| 9107 CONVERT_ARG_CHECKED(Object, obj, 0); | 5650 CONVERT_ARG_CHECKED(Object, obj, 0); |
| 9108 CONVERT_ARG_CHECKED(Object, value, 1); | 5651 CONVERT_ARG_CHECKED(Object, value, 1); |
| 9109 if (!obj->IsJSValue()) return value; | 5652 if (!obj->IsJSValue()) return value; |
| 9110 JSValue::cast(obj)->set_value(value); | 5653 JSValue::cast(obj)->set_value(value); |
| 9111 return value; | 5654 return value; |
| 9112 } | 5655 } |
| 9113 | 5656 |
| 9114 | 5657 |
| 9115 RUNTIME_FUNCTION(RuntimeReference_DateField) { | |
| 9116 SealHandleScope shs(isolate); | |
| 9117 DCHECK(args.length() == 2); | |
| 9118 CONVERT_ARG_CHECKED(Object, obj, 0); | |
| 9119 CONVERT_SMI_ARG_CHECKED(index, 1); | |
| 9120 if (!obj->IsJSDate()) { | |
| 9121 HandleScope scope(isolate); | |
| 9122 THROW_NEW_ERROR_RETURN_FAILURE( | |
| 9123 isolate, | |
| 9124 NewTypeError("not_date_object", HandleVector<Object>(NULL, 0))); | |
| 9125 } | |
| 9126 JSDate* date = JSDate::cast(obj); | |
| 9127 if (index == 0) return date->value(); | |
| 9128 return JSDate::GetField(date, Smi::FromInt(index)); | |
| 9129 } | |
| 9130 | |
| 9131 | |
| 9132 RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) { | 5658 RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) { |
| 9133 SealHandleScope shs(isolate); | 5659 SealHandleScope shs(isolate); |
| 9134 DCHECK(args.length() == 2); | 5660 DCHECK(args.length() == 2); |
| 9135 CONVERT_ARG_CHECKED(Object, obj1, 0); | 5661 CONVERT_ARG_CHECKED(Object, obj1, 0); |
| 9136 CONVERT_ARG_CHECKED(Object, obj2, 1); | 5662 CONVERT_ARG_CHECKED(Object, obj2, 1); |
| 9137 return isolate->heap()->ToBoolean(obj1 == obj2); | 5663 return isolate->heap()->ToBoolean(obj1 == obj2); |
| 9138 } | 5664 } |
| 9139 | 5665 |
| 9140 | 5666 |
| 9141 RUNTIME_FUNCTION(RuntimeReference_IsObject) { | 5667 RUNTIME_FUNCTION(RuntimeReference_IsObject) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9191 } | 5717 } |
| 9192 | 5718 |
| 9193 | 5719 |
| 9194 RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) { | 5720 RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) { |
| 9195 SealHandleScope shs(isolate); | 5721 SealHandleScope shs(isolate); |
| 9196 DCHECK(args.length() == 2); | 5722 DCHECK(args.length() == 2); |
| 9197 return isolate->heap()->undefined_value(); | 5723 return isolate->heap()->undefined_value(); |
| 9198 } | 5724 } |
| 9199 | 5725 |
| 9200 | 5726 |
| 9201 RUNTIME_FUNCTION(RuntimeReference_GeneratorNext) { | |
| 9202 UNREACHABLE(); // Optimization disabled in SetUpGenerators(). | |
| 9203 return NULL; | |
| 9204 } | |
| 9205 | |
| 9206 | |
| 9207 RUNTIME_FUNCTION(RuntimeReference_GeneratorThrow) { | |
| 9208 UNREACHABLE(); // Optimization disabled in SetUpGenerators(). | |
| 9209 return NULL; | |
| 9210 } | |
| 9211 | |
| 9212 | |
| 9213 RUNTIME_FUNCTION(RuntimeReference_ClassOf) { | 5727 RUNTIME_FUNCTION(RuntimeReference_ClassOf) { |
| 9214 SealHandleScope shs(isolate); | 5728 SealHandleScope shs(isolate); |
| 9215 DCHECK(args.length() == 1); | 5729 DCHECK(args.length() == 1); |
| 9216 CONVERT_ARG_CHECKED(Object, obj, 0); | 5730 CONVERT_ARG_CHECKED(Object, obj, 0); |
| 9217 if (!obj->IsJSReceiver()) return isolate->heap()->null_value(); | 5731 if (!obj->IsJSReceiver()) return isolate->heap()->null_value(); |
| 9218 return JSReceiver::cast(obj)->class_name(); | 5732 return JSReceiver::cast(obj)->class_name(); |
| 9219 } | 5733 } |
| 9220 | 5734 |
| 9221 | 5735 |
| 9222 RUNTIME_FUNCTION(RuntimeReference_GetFromCache) { | 5736 RUNTIME_FUNCTION(RuntimeReference_GetFromCache) { |
| 9223 HandleScope scope(isolate); | 5737 HandleScope scope(isolate); |
| 9224 DCHECK(args.length() == 2); | 5738 DCHECK(args.length() == 2); |
| 9225 CONVERT_SMI_ARG_CHECKED(id, 0); | 5739 CONVERT_SMI_ARG_CHECKED(id, 0); |
| 9226 args[0] = isolate->native_context()->jsfunction_result_caches()->get(id); | 5740 args[0] = isolate->native_context()->jsfunction_result_caches()->get(id); |
| 9227 return __RT_impl_Runtime_GetFromCache(args, isolate); | 5741 return __RT_impl_Runtime_GetFromCache(args, isolate); |
| 9228 } | 5742 } |
| 9229 | 5743 |
| 9230 | 5744 |
| 9231 RUNTIME_FUNCTION(RuntimeReference_DebugIsActive) { | |
| 9232 SealHandleScope shs(isolate); | |
| 9233 return Smi::FromInt(isolate->debug()->is_active()); | |
| 9234 } | |
| 9235 | |
| 9236 | |
| 9237 // ---------------------------------------------------------------------------- | 5745 // ---------------------------------------------------------------------------- |
| 9238 // Implementation of Runtime | 5746 // Implementation of Runtime |
| 9239 | 5747 |
| 9240 #define F(name, number_of_args, result_size) \ | 5748 #define F(name, number_of_args, result_size) \ |
| 9241 { \ | 5749 { \ |
| 9242 Runtime::k##name, Runtime::RUNTIME, #name, FUNCTION_ADDR(Runtime_##name), \ | 5750 Runtime::k##name, Runtime::RUNTIME, #name, FUNCTION_ADDR(Runtime_##name), \ |
| 9243 number_of_args, result_size \ | 5751 number_of_args, result_size \ |
| 9244 } \ | 5752 } \ |
| 9245 , | 5753 , |
| 9246 | 5754 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9307 } | 5815 } |
| 9308 return NULL; | 5816 return NULL; |
| 9309 } | 5817 } |
| 9310 | 5818 |
| 9311 | 5819 |
| 9312 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { | 5820 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { |
| 9313 return &(kIntrinsicFunctions[static_cast<int>(id)]); | 5821 return &(kIntrinsicFunctions[static_cast<int>(id)]); |
| 9314 } | 5822 } |
| 9315 } | 5823 } |
| 9316 } // namespace v8::internal | 5824 } // namespace v8::internal |
| OLD | NEW |