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 |