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 29 matching lines...) Expand all Loading... |
40 | 40 |
41 #include "arm/code-stubs-arm.h" | 41 #include "arm/code-stubs-arm.h" |
42 | 42 |
43 namespace v8 { | 43 namespace v8 { |
44 namespace internal { | 44 namespace internal { |
45 | 45 |
46 #define __ ACCESS_MASM(masm_) | 46 #define __ ACCESS_MASM(masm_) |
47 | 47 |
48 | 48 |
49 static unsigned GetPropertyId(Property* property) { | 49 static unsigned GetPropertyId(Property* property) { |
50 if (property->is_synthetic()) return AstNode::kNoNumber; | |
51 return property->id(); | 50 return property->id(); |
52 } | 51 } |
53 | 52 |
54 | 53 |
55 // A patch site is a location in the code which it is possible to patch. This | 54 // A patch site is a location in the code which it is possible to patch. This |
56 // class has a number of methods to emit the code which is patchable and the | 55 // class has a number of methods to emit the code which is patchable and the |
57 // method EmitPatchInfo to record a marker back to the patchable code. This | 56 // method EmitPatchInfo to record a marker back to the patchable code. This |
58 // marker is a cmp rx, #yyy instruction, and x * 0x00000fff + yyy (raw 12 bit | 57 // marker is a cmp rx, #yyy instruction, and x * 0x00000fff + yyy (raw 12 bit |
59 // immediate value is used) is the delta from the pc to the first instruction of | 58 // immediate value is used) is the delta from the pc to the first instruction of |
60 // the patchable code. | 59 // the patchable code. |
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
687 } | 686 } |
688 } | 687 } |
689 | 688 |
690 | 689 |
691 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 690 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
692 Variable::Mode mode, | 691 Variable::Mode mode, |
693 FunctionLiteral* function) { | 692 FunctionLiteral* function) { |
694 Comment cmnt(masm_, "[ Declaration"); | 693 Comment cmnt(masm_, "[ Declaration"); |
695 ASSERT(variable != NULL); // Must have been resolved. | 694 ASSERT(variable != NULL); // Must have been resolved. |
696 Slot* slot = variable->AsSlot(); | 695 Slot* slot = variable->AsSlot(); |
697 Property* prop = variable->AsProperty(); | 696 ASSERT(slot != NULL); |
| 697 switch (slot->type()) { |
| 698 case Slot::PARAMETER: |
| 699 case Slot::LOCAL: |
| 700 if (mode == Variable::CONST) { |
| 701 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 702 __ str(ip, MemOperand(fp, SlotOffset(slot))); |
| 703 } else if (function != NULL) { |
| 704 VisitForAccumulatorValue(function); |
| 705 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); |
| 706 } |
| 707 break; |
698 | 708 |
699 if (slot != NULL) { | 709 case Slot::CONTEXT: |
700 switch (slot->type()) { | 710 // We bypass the general EmitSlotSearch because we know more about |
701 case Slot::PARAMETER: | 711 // this specific context. |
702 case Slot::LOCAL: | |
703 if (mode == Variable::CONST) { | |
704 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | |
705 __ str(ip, MemOperand(fp, SlotOffset(slot))); | |
706 } else if (function != NULL) { | |
707 VisitForAccumulatorValue(function); | |
708 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); | |
709 } | |
710 break; | |
711 | 712 |
712 case Slot::CONTEXT: | 713 // The variable in the decl always resides in the current function |
713 // We bypass the general EmitSlotSearch because we know more about | 714 // context. |
714 // this specific context. | 715 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 716 if (FLAG_debug_code) { |
| 717 // Check that we're not inside a with or catch context. |
| 718 __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); |
| 719 __ CompareRoot(r1, Heap::kWithContextMapRootIndex); |
| 720 __ Check(ne, "Declaration in with context."); |
| 721 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); |
| 722 __ Check(ne, "Declaration in catch context."); |
| 723 } |
| 724 if (mode == Variable::CONST) { |
| 725 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 726 __ str(ip, ContextOperand(cp, slot->index())); |
| 727 // No write barrier since the_hole_value is in old space. |
| 728 } else if (function != NULL) { |
| 729 VisitForAccumulatorValue(function); |
| 730 __ str(result_register(), ContextOperand(cp, slot->index())); |
| 731 int offset = Context::SlotOffset(slot->index()); |
| 732 // We know that we have written a function, which is not a smi. |
| 733 __ mov(r1, Operand(cp)); |
| 734 __ RecordWrite(r1, Operand(offset), r2, result_register()); |
| 735 } |
| 736 break; |
715 | 737 |
716 // The variable in the decl always resides in the current function | 738 case Slot::LOOKUP: { |
717 // context. | 739 __ mov(r2, Operand(variable->name())); |
718 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 740 // Declaration nodes are always introduced in one of two modes. |
719 if (FLAG_debug_code) { | 741 ASSERT(mode == Variable::VAR || |
720 // Check that we're not inside a with or catch context. | 742 mode == Variable::CONST || |
721 __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset)); | 743 mode == Variable::LET); |
722 __ CompareRoot(r1, Heap::kWithContextMapRootIndex); | 744 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; |
723 __ Check(ne, "Declaration in with context."); | 745 __ mov(r1, Operand(Smi::FromInt(attr))); |
724 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); | 746 // Push initial value, if any. |
725 __ Check(ne, "Declaration in catch context."); | 747 // Note: For variables we must not push an initial value (such as |
726 } | 748 // 'undefined') because we may have a (legal) redeclaration and we |
727 if (mode == Variable::CONST) { | 749 // must not destroy the current value. |
728 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 750 if (mode == Variable::CONST) { |
729 __ str(ip, ContextOperand(cp, slot->index())); | 751 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); |
730 // No write barrier since the_hole_value is in old space. | 752 __ Push(cp, r2, r1, r0); |
731 } else if (function != NULL) { | 753 } else if (function != NULL) { |
732 VisitForAccumulatorValue(function); | 754 __ Push(cp, r2, r1); |
733 __ str(result_register(), ContextOperand(cp, slot->index())); | 755 // Push initial value for function declaration. |
734 int offset = Context::SlotOffset(slot->index()); | 756 VisitForStackValue(function); |
735 // We know that we have written a function, which is not a smi. | 757 } else { |
736 __ mov(r1, Operand(cp)); | 758 __ mov(r0, Operand(Smi::FromInt(0))); // No initial value! |
737 __ RecordWrite(r1, Operand(offset), r2, result_register()); | 759 __ Push(cp, r2, r1, r0); |
738 } | |
739 break; | |
740 | |
741 case Slot::LOOKUP: { | |
742 __ mov(r2, Operand(variable->name())); | |
743 // Declaration nodes are always introduced in one of two modes. | |
744 ASSERT(mode == Variable::VAR || | |
745 mode == Variable::CONST || | |
746 mode == Variable::LET); | |
747 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; | |
748 __ mov(r1, Operand(Smi::FromInt(attr))); | |
749 // Push initial value, if any. | |
750 // Note: For variables we must not push an initial value (such as | |
751 // 'undefined') because we may have a (legal) redeclaration and we | |
752 // must not destroy the current value. | |
753 if (mode == Variable::CONST) { | |
754 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); | |
755 __ Push(cp, r2, r1, r0); | |
756 } else if (function != NULL) { | |
757 __ Push(cp, r2, r1); | |
758 // Push initial value for function declaration. | |
759 VisitForStackValue(function); | |
760 } else { | |
761 __ mov(r0, Operand(Smi::FromInt(0))); // No initial value! | |
762 __ Push(cp, r2, r1, r0); | |
763 } | |
764 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | |
765 break; | |
766 } | 760 } |
767 } | 761 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
768 | 762 break; |
769 } else if (prop != NULL) { | |
770 // A const declaration aliasing a parameter is an illegal redeclaration. | |
771 ASSERT(mode != Variable::CONST); | |
772 if (function != NULL) { | |
773 // We are declaring a function that rewrites to a property. | |
774 // Use (keyed) IC to set the initial value. We cannot visit the | |
775 // rewrite because it's shared and we risk recording duplicate AST | |
776 // IDs for bailouts from optimized code. | |
777 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
778 { AccumulatorValueContext for_object(this); | |
779 EmitVariableLoad(prop->obj()->AsVariableProxy()); | |
780 } | |
781 | |
782 __ push(r0); | |
783 VisitForAccumulatorValue(function); | |
784 __ pop(r2); | |
785 | |
786 ASSERT(prop->key()->AsLiteral() != NULL && | |
787 prop->key()->AsLiteral()->handle()->IsSmi()); | |
788 __ mov(r1, Operand(prop->key()->AsLiteral()->handle())); | |
789 | |
790 Handle<Code> ic = is_strict_mode() | |
791 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | |
792 : isolate()->builtins()->KeyedStoreIC_Initialize(); | |
793 __ Call(ic); | |
794 // Value in r0 is ignored (declarations are statements). | |
795 } | 763 } |
796 } | 764 } |
797 } | 765 } |
798 | 766 |
799 | 767 |
800 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 768 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
801 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 769 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
802 } | 770 } |
803 | 771 |
804 | 772 |
(...skipping 1460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2265 Property* prop = fun->AsProperty(); | 2233 Property* prop = fun->AsProperty(); |
2266 Literal* key = prop->key()->AsLiteral(); | 2234 Literal* key = prop->key()->AsLiteral(); |
2267 if (key != NULL && key->handle()->IsSymbol()) { | 2235 if (key != NULL && key->handle()->IsSymbol()) { |
2268 // Call to a named property, use call IC. | 2236 // Call to a named property, use call IC. |
2269 { PreservePositionScope scope(masm()->positions_recorder()); | 2237 { PreservePositionScope scope(masm()->positions_recorder()); |
2270 VisitForStackValue(prop->obj()); | 2238 VisitForStackValue(prop->obj()); |
2271 } | 2239 } |
2272 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2240 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
2273 } else { | 2241 } else { |
2274 // Call to a keyed property. | 2242 // Call to a keyed property. |
2275 // For a synthetic property use keyed load IC followed by function call, | 2243 { PreservePositionScope scope(masm()->positions_recorder()); |
2276 // for a regular property use EmitKeyedCallWithIC. | 2244 VisitForStackValue(prop->obj()); |
2277 if (prop->is_synthetic()) { | |
2278 // Do not visit the object and key subexpressions (they are shared | |
2279 // by all occurrences of the same rewritten parameter). | |
2280 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
2281 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | |
2282 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); | |
2283 MemOperand operand = EmitSlotSearch(slot, r1); | |
2284 __ ldr(r1, operand); | |
2285 | |
2286 ASSERT(prop->key()->AsLiteral() != NULL); | |
2287 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); | |
2288 __ mov(r0, Operand(prop->key()->AsLiteral()->handle())); | |
2289 | |
2290 // Record source code position for IC call. | |
2291 SetSourcePosition(prop->position()); | |
2292 | |
2293 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | |
2294 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | |
2295 __ ldr(r1, GlobalObjectOperand()); | |
2296 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | |
2297 __ Push(r0, r1); // Function, receiver. | |
2298 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); | |
2299 } else { | |
2300 { PreservePositionScope scope(masm()->positions_recorder()); | |
2301 VisitForStackValue(prop->obj()); | |
2302 } | |
2303 EmitKeyedCallWithIC(expr, prop->key()); | |
2304 } | 2245 } |
| 2246 EmitKeyedCallWithIC(expr, prop->key()); |
2305 } | 2247 } |
2306 } else { | 2248 } else { |
2307 { PreservePositionScope scope(masm()->positions_recorder()); | 2249 { PreservePositionScope scope(masm()->positions_recorder()); |
2308 VisitForStackValue(fun); | 2250 VisitForStackValue(fun); |
2309 } | 2251 } |
2310 // Load global receiver object. | 2252 // Load global receiver object. |
2311 __ ldr(r1, GlobalObjectOperand()); | 2253 __ ldr(r1, GlobalObjectOperand()); |
2312 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); | 2254 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset)); |
2313 __ push(r1); | 2255 __ push(r1); |
2314 // Emit function call. | 2256 // Emit function call. |
(...skipping 1342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3657 | 3599 |
3658 | 3600 |
3659 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3601 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
3660 switch (expr->op()) { | 3602 switch (expr->op()) { |
3661 case Token::DELETE: { | 3603 case Token::DELETE: { |
3662 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3604 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
3663 Property* prop = expr->expression()->AsProperty(); | 3605 Property* prop = expr->expression()->AsProperty(); |
3664 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 3606 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
3665 | 3607 |
3666 if (prop != NULL) { | 3608 if (prop != NULL) { |
3667 if (prop->is_synthetic()) { | 3609 VisitForStackValue(prop->obj()); |
3668 // Result of deleting parameters is false, even when they rewrite | 3610 VisitForStackValue(prop->key()); |
3669 // to accesses on the arguments object. | 3611 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); |
3670 context()->Plug(false); | 3612 __ push(r1); |
3671 } else { | 3613 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
3672 VisitForStackValue(prop->obj()); | 3614 context()->Plug(r0); |
3673 VisitForStackValue(prop->key()); | |
3674 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); | |
3675 __ push(r1); | |
3676 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | |
3677 context()->Plug(r0); | |
3678 } | |
3679 } else if (var != NULL) { | 3615 } else if (var != NULL) { |
3680 // Delete of an unqualified identifier is disallowed in strict mode | 3616 // Delete of an unqualified identifier is disallowed in strict mode |
3681 // but "delete this" is. | 3617 // but "delete this" is. |
3682 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); | 3618 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); |
3683 if (var->is_global()) { | 3619 if (var->is_global()) { |
3684 __ ldr(r2, GlobalObjectOperand()); | 3620 __ ldr(r2, GlobalObjectOperand()); |
3685 __ mov(r1, Operand(var->name())); | 3621 __ mov(r1, Operand(var->name())); |
3686 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode))); | 3622 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode))); |
3687 __ Push(r2, r1, r0); | 3623 __ Push(r2, r1, r0); |
3688 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3624 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
(...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4295 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 4231 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
4296 __ add(pc, r1, Operand(masm_->CodeObject())); | 4232 __ add(pc, r1, Operand(masm_->CodeObject())); |
4297 } | 4233 } |
4298 | 4234 |
4299 | 4235 |
4300 #undef __ | 4236 #undef __ |
4301 | 4237 |
4302 } } // namespace v8::internal | 4238 } } // namespace v8::internal |
4303 | 4239 |
4304 #endif // V8_TARGET_ARCH_ARM | 4240 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |