| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 #include "stub-cache.h" | 39 #include "stub-cache.h" |
| 40 | 40 |
| 41 namespace v8 { | 41 namespace v8 { |
| 42 namespace internal { | 42 namespace internal { |
| 43 | 43 |
| 44 | 44 |
| 45 #define __ ACCESS_MASM(masm_) | 45 #define __ ACCESS_MASM(masm_) |
| 46 | 46 |
| 47 | 47 |
| 48 static unsigned GetPropertyId(Property* property) { | 48 static unsigned GetPropertyId(Property* property) { |
| 49 if (property->is_synthetic()) return AstNode::kNoNumber; | |
| 50 return property->id(); | 49 return property->id(); |
| 51 } | 50 } |
| 52 | 51 |
| 53 | 52 |
| 54 class JumpPatchSite BASE_EMBEDDED { | 53 class JumpPatchSite BASE_EMBEDDED { |
| 55 public: | 54 public: |
| 56 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { | 55 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { |
| 57 #ifdef DEBUG | 56 #ifdef DEBUG |
| 58 info_emitted_ = false; | 57 info_emitted_ = false; |
| 59 #endif | 58 #endif |
| (...skipping 623 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 683 } | 682 } |
| 684 } | 683 } |
| 685 | 684 |
| 686 | 685 |
| 687 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 686 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 688 Variable::Mode mode, | 687 Variable::Mode mode, |
| 689 FunctionLiteral* function) { | 688 FunctionLiteral* function) { |
| 690 Comment cmnt(masm_, "[ Declaration"); | 689 Comment cmnt(masm_, "[ Declaration"); |
| 691 ASSERT(variable != NULL); // Must have been resolved. | 690 ASSERT(variable != NULL); // Must have been resolved. |
| 692 Slot* slot = variable->AsSlot(); | 691 Slot* slot = variable->AsSlot(); |
| 693 Property* prop = variable->AsProperty(); | 692 ASSERT(slot != NULL); |
| 693 switch (slot->type()) { |
| 694 case Slot::PARAMETER: |
| 695 case Slot::LOCAL: |
| 696 if (mode == Variable::CONST) { |
| 697 __ mov(Operand(ebp, SlotOffset(slot)), |
| 698 Immediate(isolate()->factory()->the_hole_value())); |
| 699 } else if (function != NULL) { |
| 700 VisitForAccumulatorValue(function); |
| 701 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); |
| 702 } |
| 703 break; |
| 694 | 704 |
| 695 if (slot != NULL) { | 705 case Slot::CONTEXT: |
| 696 switch (slot->type()) { | 706 // We bypass the general EmitSlotSearch because we know more about |
| 697 case Slot::PARAMETER: | 707 // this specific context. |
| 698 case Slot::LOCAL: | |
| 699 if (mode == Variable::CONST) { | |
| 700 __ mov(Operand(ebp, SlotOffset(slot)), | |
| 701 Immediate(isolate()->factory()->the_hole_value())); | |
| 702 } else if (function != NULL) { | |
| 703 VisitForAccumulatorValue(function); | |
| 704 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); | |
| 705 } | |
| 706 break; | |
| 707 | 708 |
| 708 case Slot::CONTEXT: | 709 // The variable in the decl always resides in the current function |
| 709 // We bypass the general EmitSlotSearch because we know more about | 710 // context. |
| 710 // this specific context. | 711 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 712 if (FLAG_debug_code) { |
| 713 // Check that we're not inside a with or catch context. |
| 714 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); |
| 715 __ cmp(ebx, isolate()->factory()->with_context_map()); |
| 716 __ Check(not_equal, "Declaration in with context."); |
| 717 __ cmp(ebx, isolate()->factory()->catch_context_map()); |
| 718 __ Check(not_equal, "Declaration in catch context."); |
| 719 } |
| 720 if (mode == Variable::CONST) { |
| 721 __ mov(ContextOperand(esi, slot->index()), |
| 722 Immediate(isolate()->factory()->the_hole_value())); |
| 723 // No write barrier since the hole value is in old space. |
| 724 } else if (function != NULL) { |
| 725 VisitForAccumulatorValue(function); |
| 726 __ mov(ContextOperand(esi, slot->index()), result_register()); |
| 727 int offset = Context::SlotOffset(slot->index()); |
| 728 __ mov(ebx, esi); |
| 729 __ RecordWrite(ebx, offset, result_register(), ecx); |
| 730 } |
| 731 break; |
| 711 | 732 |
| 712 // The variable in the decl always resides in the current function | 733 case Slot::LOOKUP: { |
| 713 // context. | 734 __ push(esi); |
| 714 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 735 __ push(Immediate(variable->name())); |
| 715 if (FLAG_debug_code) { | 736 // Declaration nodes are always introduced in one of two modes. |
| 716 // Check that we're not inside a with or catch context. | 737 ASSERT(mode == Variable::VAR || |
| 717 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); | 738 mode == Variable::CONST || |
| 718 __ cmp(ebx, isolate()->factory()->with_context_map()); | 739 mode == Variable::LET); |
| 719 __ Check(not_equal, "Declaration in with context."); | 740 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; |
| 720 __ cmp(ebx, isolate()->factory()->catch_context_map()); | 741 __ push(Immediate(Smi::FromInt(attr))); |
| 721 __ Check(not_equal, "Declaration in catch context."); | 742 // Push initial value, if any. |
| 722 } | 743 // Note: For variables we must not push an initial value (such as |
| 723 if (mode == Variable::CONST) { | 744 // 'undefined') because we may have a (legal) redeclaration and we |
| 724 __ mov(ContextOperand(esi, slot->index()), | 745 // must not destroy the current value. |
| 725 Immediate(isolate()->factory()->the_hole_value())); | 746 increment_stack_height(3); |
| 726 // No write barrier since the hole value is in old space. | 747 if (mode == Variable::CONST) { |
| 727 } else if (function != NULL) { | 748 __ push(Immediate(isolate()->factory()->the_hole_value())); |
| 728 VisitForAccumulatorValue(function); | 749 increment_stack_height(); |
| 729 __ mov(ContextOperand(esi, slot->index()), result_register()); | 750 } else if (function != NULL) { |
| 730 int offset = Context::SlotOffset(slot->index()); | 751 VisitForStackValue(function); |
| 731 __ mov(ebx, esi); | 752 } else { |
| 732 __ RecordWrite(ebx, offset, result_register(), ecx); | 753 __ push(Immediate(Smi::FromInt(0))); // No initial value! |
| 733 } | 754 increment_stack_height(); |
| 734 break; | |
| 735 | |
| 736 case Slot::LOOKUP: { | |
| 737 __ push(esi); | |
| 738 __ push(Immediate(variable->name())); | |
| 739 // Declaration nodes are always introduced in one of two modes. | |
| 740 ASSERT(mode == Variable::VAR || | |
| 741 mode == Variable::CONST || | |
| 742 mode == Variable::LET); | |
| 743 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; | |
| 744 __ push(Immediate(Smi::FromInt(attr))); | |
| 745 // Push initial value, if any. | |
| 746 // Note: For variables we must not push an initial value (such as | |
| 747 // 'undefined') because we may have a (legal) redeclaration and we | |
| 748 // must not destroy the current value. | |
| 749 increment_stack_height(3); | |
| 750 if (mode == Variable::CONST) { | |
| 751 __ push(Immediate(isolate()->factory()->the_hole_value())); | |
| 752 increment_stack_height(); | |
| 753 } else if (function != NULL) { | |
| 754 VisitForStackValue(function); | |
| 755 } else { | |
| 756 __ push(Immediate(Smi::FromInt(0))); // No initial value! | |
| 757 increment_stack_height(); | |
| 758 } | |
| 759 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | |
| 760 decrement_stack_height(4); | |
| 761 break; | |
| 762 } | 755 } |
| 763 } | 756 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 764 | 757 decrement_stack_height(4); |
| 765 } else if (prop != NULL) { | 758 break; |
| 766 // A const declaration aliasing a parameter is an illegal redeclaration. | |
| 767 ASSERT(mode != Variable::CONST); | |
| 768 if (function != NULL) { | |
| 769 // We are declaring a function that rewrites to a property. | |
| 770 // Use (keyed) IC to set the initial value. We cannot visit the | |
| 771 // rewrite because it's shared and we risk recording duplicate AST | |
| 772 // IDs for bailouts from optimized code. | |
| 773 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
| 774 { AccumulatorValueContext for_object(this); | |
| 775 EmitVariableLoad(prop->obj()->AsVariableProxy()); | |
| 776 } | |
| 777 | |
| 778 __ push(eax); | |
| 779 increment_stack_height(); | |
| 780 VisitForAccumulatorValue(function); | |
| 781 __ pop(edx); | |
| 782 decrement_stack_height(); | |
| 783 | |
| 784 ASSERT(prop->key()->AsLiteral() != NULL && | |
| 785 prop->key()->AsLiteral()->handle()->IsSmi()); | |
| 786 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle())); | |
| 787 | |
| 788 Handle<Code> ic = is_strict_mode() | |
| 789 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | |
| 790 : isolate()->builtins()->KeyedStoreIC_Initialize(); | |
| 791 __ call(ic); | |
| 792 } | 759 } |
| 793 } | 760 } |
| 794 } | 761 } |
| 795 | 762 |
| 796 | 763 |
| 797 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 764 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 798 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 765 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 799 } | 766 } |
| 800 | 767 |
| 801 | 768 |
| (...skipping 1015 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1817 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1784 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1818 Handle<Code> ic = is_strict_mode() | 1785 Handle<Code> ic = is_strict_mode() |
| 1819 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1786 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1820 : isolate()->builtins()->StoreIC_Initialize(); | 1787 : isolate()->builtins()->StoreIC_Initialize(); |
| 1821 __ call(ic); | 1788 __ call(ic); |
| 1822 break; | 1789 break; |
| 1823 } | 1790 } |
| 1824 case KEYED_PROPERTY: { | 1791 case KEYED_PROPERTY: { |
| 1825 __ push(eax); // Preserve value. | 1792 __ push(eax); // Preserve value. |
| 1826 increment_stack_height(); | 1793 increment_stack_height(); |
| 1827 if (prop->is_synthetic()) { | 1794 VisitForStackValue(prop->obj()); |
| 1828 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1795 VisitForAccumulatorValue(prop->key()); |
| 1829 ASSERT(prop->key()->AsLiteral() != NULL); | 1796 __ mov(ecx, eax); |
| 1830 { AccumulatorValueContext for_object(this); | 1797 __ pop(edx); |
| 1831 EmitVariableLoad(prop->obj()->AsVariableProxy()); | 1798 decrement_stack_height(); |
| 1832 } | |
| 1833 __ mov(edx, eax); | |
| 1834 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle())); | |
| 1835 } else { | |
| 1836 VisitForStackValue(prop->obj()); | |
| 1837 VisitForAccumulatorValue(prop->key()); | |
| 1838 __ mov(ecx, eax); | |
| 1839 __ pop(edx); | |
| 1840 decrement_stack_height(); | |
| 1841 } | |
| 1842 __ pop(eax); // Restore value. | 1799 __ pop(eax); // Restore value. |
| 1843 decrement_stack_height(); | 1800 decrement_stack_height(); |
| 1844 Handle<Code> ic = is_strict_mode() | 1801 Handle<Code> ic = is_strict_mode() |
| 1845 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 1802 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 1846 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 1803 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 1847 __ call(ic); | 1804 __ call(ic); |
| 1848 break; | 1805 break; |
| 1849 } | 1806 } |
| 1850 } | 1807 } |
| 1851 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1808 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2268 Property* prop = fun->AsProperty(); | 2225 Property* prop = fun->AsProperty(); |
| 2269 Literal* key = prop->key()->AsLiteral(); | 2226 Literal* key = prop->key()->AsLiteral(); |
| 2270 if (key != NULL && key->handle()->IsSymbol()) { | 2227 if (key != NULL && key->handle()->IsSymbol()) { |
| 2271 // Call to a named property, use call IC. | 2228 // Call to a named property, use call IC. |
| 2272 { PreservePositionScope scope(masm()->positions_recorder()); | 2229 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2273 VisitForStackValue(prop->obj()); | 2230 VisitForStackValue(prop->obj()); |
| 2274 } | 2231 } |
| 2275 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2232 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2276 } else { | 2233 } else { |
| 2277 // Call to a keyed property. | 2234 // Call to a keyed property. |
| 2278 // For a synthetic property use keyed load IC followed by function call, | 2235 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2279 // for a regular property use EmitKeyedCallWithIC. | 2236 VisitForStackValue(prop->obj()); |
| 2280 if (prop->is_synthetic()) { | |
| 2281 // Do not visit the object and key subexpressions (they are shared | |
| 2282 // by all occurrences of the same rewritten parameter). | |
| 2283 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
| 2284 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | |
| 2285 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); | |
| 2286 MemOperand operand = EmitSlotSearch(slot, edx); | |
| 2287 __ mov(edx, operand); | |
| 2288 | |
| 2289 ASSERT(prop->key()->AsLiteral() != NULL); | |
| 2290 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); | |
| 2291 __ mov(eax, prop->key()->AsLiteral()->handle()); | |
| 2292 | |
| 2293 // Record source code position for IC call. | |
| 2294 SetSourcePosition(prop->position()); | |
| 2295 | |
| 2296 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | |
| 2297 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | |
| 2298 // Push result (function). | |
| 2299 __ push(eax); | |
| 2300 increment_stack_height(); | |
| 2301 // Push Global receiver. | |
| 2302 __ mov(ecx, GlobalObjectOperand()); | |
| 2303 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); | |
| 2304 increment_stack_height(); | |
| 2305 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); | |
| 2306 } else { | |
| 2307 { PreservePositionScope scope(masm()->positions_recorder()); | |
| 2308 VisitForStackValue(prop->obj()); | |
| 2309 } | |
| 2310 EmitKeyedCallWithIC(expr, prop->key()); | |
| 2311 } | 2237 } |
| 2238 EmitKeyedCallWithIC(expr, prop->key()); |
| 2312 } | 2239 } |
| 2313 } else { | 2240 } else { |
| 2314 { PreservePositionScope scope(masm()->positions_recorder()); | 2241 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2315 VisitForStackValue(fun); | 2242 VisitForStackValue(fun); |
| 2316 } | 2243 } |
| 2317 // Load global receiver object. | 2244 // Load global receiver object. |
| 2318 __ mov(ebx, GlobalObjectOperand()); | 2245 __ mov(ebx, GlobalObjectOperand()); |
| 2319 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 2246 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
| 2320 increment_stack_height(); | 2247 increment_stack_height(); |
| 2321 // Emit function call. | 2248 // Emit function call. |
| (...skipping 1392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3714 | 3641 |
| 3715 | 3642 |
| 3716 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3643 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 3717 switch (expr->op()) { | 3644 switch (expr->op()) { |
| 3718 case Token::DELETE: { | 3645 case Token::DELETE: { |
| 3719 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3646 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 3720 Property* prop = expr->expression()->AsProperty(); | 3647 Property* prop = expr->expression()->AsProperty(); |
| 3721 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 3648 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 3722 | 3649 |
| 3723 if (prop != NULL) { | 3650 if (prop != NULL) { |
| 3724 if (prop->is_synthetic()) { | 3651 VisitForStackValue(prop->obj()); |
| 3725 // Result of deleting parameters is false, even when they rewrite | 3652 VisitForStackValue(prop->key()); |
| 3726 // to accesses on the arguments object. | 3653 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 3727 context()->Plug(false); | 3654 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3728 } else { | 3655 decrement_stack_height(2); |
| 3729 VisitForStackValue(prop->obj()); | 3656 context()->Plug(eax); |
| 3730 VisitForStackValue(prop->key()); | |
| 3731 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | |
| 3732 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | |
| 3733 decrement_stack_height(2); | |
| 3734 context()->Plug(eax); | |
| 3735 } | |
| 3736 } else if (var != NULL) { | 3657 } else if (var != NULL) { |
| 3737 // Delete of an unqualified identifier is disallowed in strict mode | 3658 // Delete of an unqualified identifier is disallowed in strict mode |
| 3738 // but "delete this" is. | 3659 // but "delete this" is. |
| 3739 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); | 3660 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); |
| 3740 if (var->is_global()) { | 3661 if (var->is_global()) { |
| 3741 __ push(GlobalObjectOperand()); | 3662 __ push(GlobalObjectOperand()); |
| 3742 __ push(Immediate(var->name())); | 3663 __ push(Immediate(var->name())); |
| 3743 __ push(Immediate(Smi::FromInt(kNonStrictMode))); | 3664 __ push(Immediate(Smi::FromInt(kNonStrictMode))); |
| 3744 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3665 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3745 context()->Plug(eax); | 3666 context()->Plug(eax); |
| (...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4372 __ add(Operand(edx), Immediate(masm_->CodeObject())); | 4293 __ add(Operand(edx), Immediate(masm_->CodeObject())); |
| 4373 __ jmp(Operand(edx)); | 4294 __ jmp(Operand(edx)); |
| 4374 } | 4295 } |
| 4375 | 4296 |
| 4376 | 4297 |
| 4377 #undef __ | 4298 #undef __ |
| 4378 | 4299 |
| 4379 } } // namespace v8::internal | 4300 } } // namespace v8::internal |
| 4380 | 4301 |
| 4381 #endif // V8_TARGET_ARCH_IA32 | 4302 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |