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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 | 48 |
49 #include "mips/code-stubs-mips.h" | 49 #include "mips/code-stubs-mips.h" |
50 | 50 |
51 namespace v8 { | 51 namespace v8 { |
52 namespace internal { | 52 namespace internal { |
53 | 53 |
54 #define __ ACCESS_MASM(masm_) | 54 #define __ ACCESS_MASM(masm_) |
55 | 55 |
56 | 56 |
57 static unsigned GetPropertyId(Property* property) { | 57 static unsigned GetPropertyId(Property* property) { |
58 if (property->is_synthetic()) return AstNode::kNoNumber; | |
59 return property->id(); | 58 return property->id(); |
60 } | 59 } |
61 | 60 |
62 | 61 |
63 // A patch site is a location in the code which it is possible to patch. This | 62 // A patch site is a location in the code which it is possible to patch. This |
64 // class has a number of methods to emit the code which is patchable and the | 63 // class has a number of methods to emit the code which is patchable and the |
65 // method EmitPatchInfo to record a marker back to the patchable code. This | 64 // method EmitPatchInfo to record a marker back to the patchable code. This |
66 // marker is a andi at, rx, #yyy instruction, and x * 0x0000ffff + yyy (raw 16 | 65 // marker is a andi at, rx, #yyy instruction, and x * 0x0000ffff + yyy (raw 16 |
67 // bit immediate value is used) is the delta from the pc to the first | 66 // bit immediate value is used) is the delta from the pc to the first |
68 // instruction of the patchable code. | 67 // instruction of the patchable code. |
(...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 } | 689 } |
691 } | 690 } |
692 | 691 |
693 | 692 |
694 void FullCodeGenerator::EmitDeclaration(Variable* variable, | 693 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
695 Variable::Mode mode, | 694 Variable::Mode mode, |
696 FunctionLiteral* function) { | 695 FunctionLiteral* function) { |
697 Comment cmnt(masm_, "[ Declaration"); | 696 Comment cmnt(masm_, "[ Declaration"); |
698 ASSERT(variable != NULL); // Must have been resolved. | 697 ASSERT(variable != NULL); // Must have been resolved. |
699 Slot* slot = variable->AsSlot(); | 698 Slot* slot = variable->AsSlot(); |
700 Property* prop = variable->AsProperty(); | 699 ASSERT(slot != NULL); |
| 700 switch (slot->type()) { |
| 701 case Slot::PARAMETER: |
| 702 case Slot::LOCAL: |
| 703 if (mode == Variable::CONST) { |
| 704 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
| 705 __ sw(t0, MemOperand(fp, SlotOffset(slot))); |
| 706 } else if (function != NULL) { |
| 707 VisitForAccumulatorValue(function); |
| 708 __ sw(result_register(), MemOperand(fp, SlotOffset(slot))); |
| 709 } |
| 710 break; |
701 | 711 |
702 if (slot != NULL) { | 712 case Slot::CONTEXT: |
703 switch (slot->type()) { | 713 // We bypass the general EmitSlotSearch because we know more about |
704 case Slot::PARAMETER: | 714 // this specific context. |
705 case Slot::LOCAL: | |
706 if (mode == Variable::CONST) { | |
707 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | |
708 __ sw(t0, MemOperand(fp, SlotOffset(slot))); | |
709 } else if (function != NULL) { | |
710 VisitForAccumulatorValue(function); | |
711 __ sw(result_register(), MemOperand(fp, SlotOffset(slot))); | |
712 } | |
713 break; | |
714 | 715 |
715 case Slot::CONTEXT: | 716 // The variable in the decl always resides in the current function |
716 // We bypass the general EmitSlotSearch because we know more about | 717 // context. |
717 // this specific context. | 718 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 719 if (FLAG_debug_code) { |
| 720 // Check that we're not inside a with or catch context. |
| 721 __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset)); |
| 722 __ LoadRoot(t0, Heap::kWithContextMapRootIndex); |
| 723 __ Check(ne, "Declaration in with context.", |
| 724 a1, Operand(t0)); |
| 725 __ LoadRoot(t0, Heap::kCatchContextMapRootIndex); |
| 726 __ Check(ne, "Declaration in catch context.", |
| 727 a1, Operand(t0)); |
| 728 } |
| 729 if (mode == Variable::CONST) { |
| 730 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 731 __ sw(at, ContextOperand(cp, slot->index())); |
| 732 // No write barrier since the_hole_value is in old space. |
| 733 } else if (function != NULL) { |
| 734 VisitForAccumulatorValue(function); |
| 735 __ sw(result_register(), ContextOperand(cp, slot->index())); |
| 736 int offset = Context::SlotOffset(slot->index()); |
| 737 // We know that we have written a function, which is not a smi. |
| 738 __ mov(a1, cp); |
| 739 __ RecordWrite(a1, Operand(offset), a2, result_register()); |
| 740 } |
| 741 break; |
718 | 742 |
719 // The variable in the decl always resides in the current function | 743 case Slot::LOOKUP: { |
720 // context. | 744 __ li(a2, Operand(variable->name())); |
721 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 745 // Declaration nodes are always introduced in one of two modes. |
722 if (FLAG_debug_code) { | 746 ASSERT(mode == Variable::VAR || |
723 // Check that we're not inside a with or catch context. | 747 mode == Variable::CONST || |
724 __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset)); | 748 mode == Variable::LET); |
725 __ LoadRoot(t0, Heap::kWithContextMapRootIndex); | 749 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; |
726 __ Check(ne, "Declaration in with context.", | 750 __ li(a1, Operand(Smi::FromInt(attr))); |
727 a1, Operand(t0)); | 751 // Push initial value, if any. |
728 __ LoadRoot(t0, Heap::kCatchContextMapRootIndex); | 752 // Note: For variables we must not push an initial value (such as |
729 __ Check(ne, "Declaration in catch context.", | 753 // 'undefined') because we may have a (legal) redeclaration and we |
730 a1, Operand(t0)); | 754 // must not destroy the current value. |
731 } | 755 if (mode == Variable::CONST) { |
732 if (mode == Variable::CONST) { | 756 __ LoadRoot(a0, Heap::kTheHoleValueRootIndex); |
733 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 757 __ Push(cp, a2, a1, a0); |
734 __ sw(at, ContextOperand(cp, slot->index())); | 758 } else if (function != NULL) { |
735 // No write barrier since the_hole_value is in old space. | 759 __ Push(cp, a2, a1); |
736 } else if (function != NULL) { | 760 // Push initial value for function declaration. |
737 VisitForAccumulatorValue(function); | 761 VisitForStackValue(function); |
738 __ sw(result_register(), ContextOperand(cp, slot->index())); | 762 } else { |
739 int offset = Context::SlotOffset(slot->index()); | 763 ASSERT(Smi::FromInt(0) == 0); |
740 // We know that we have written a function, which is not a smi. | 764 // No initial value! |
741 __ mov(a1, cp); | 765 __ mov(a0, zero_reg); // Operand(Smi::FromInt(0))); |
742 __ RecordWrite(a1, Operand(offset), a2, result_register()); | 766 __ Push(cp, a2, a1, a0); |
743 } | |
744 break; | |
745 | |
746 case Slot::LOOKUP: { | |
747 __ li(a2, Operand(variable->name())); | |
748 // Declaration nodes are always introduced in one of two modes. | |
749 ASSERT(mode == Variable::VAR || | |
750 mode == Variable::CONST || | |
751 mode == Variable::LET); | |
752 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; | |
753 __ li(a1, Operand(Smi::FromInt(attr))); | |
754 // Push initial value, if any. | |
755 // Note: For variables we must not push an initial value (such as | |
756 // 'undefined') because we may have a (legal) redeclaration and we | |
757 // must not destroy the current value. | |
758 if (mode == Variable::CONST) { | |
759 __ LoadRoot(a0, Heap::kTheHoleValueRootIndex); | |
760 __ Push(cp, a2, a1, a0); | |
761 } else if (function != NULL) { | |
762 __ Push(cp, a2, a1); | |
763 // Push initial value for function declaration. | |
764 VisitForStackValue(function); | |
765 } else { | |
766 ASSERT(Smi::FromInt(0) == 0); | |
767 // No initial value! | |
768 __ mov(a0, zero_reg); // Operand(Smi::FromInt(0))); | |
769 __ Push(cp, a2, a1, a0); | |
770 } | |
771 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | |
772 break; | |
773 } | 767 } |
774 } | 768 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
775 | 769 break; |
776 } else if (prop != NULL) { | |
777 // A const declaration aliasing a parameter is an illegal redeclaration. | |
778 ASSERT(mode != Variable::CONST); | |
779 if (function != NULL) { | |
780 // We are declaring a function that rewrites to a property. | |
781 // Use (keyed) IC to set the initial value. We cannot visit the | |
782 // rewrite because it's shared and we risk recording duplicate AST | |
783 // IDs for bailouts from optimized code. | |
784 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
785 { AccumulatorValueContext for_object(this); | |
786 EmitVariableLoad(prop->obj()->AsVariableProxy()); | |
787 } | |
788 | |
789 __ push(result_register()); | |
790 VisitForAccumulatorValue(function); | |
791 __ mov(a0, result_register()); | |
792 __ pop(a2); | |
793 | |
794 ASSERT(prop->key()->AsLiteral() != NULL && | |
795 prop->key()->AsLiteral()->handle()->IsSmi()); | |
796 __ li(a1, Operand(prop->key()->AsLiteral()->handle())); | |
797 | |
798 Handle<Code> ic = is_strict_mode() | |
799 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | |
800 : isolate()->builtins()->KeyedStoreIC_Initialize(); | |
801 __ Call(ic); | |
802 // Value in v0 is ignored (declarations are statements). | |
803 } | 770 } |
804 } | 771 } |
805 } | 772 } |
806 | 773 |
807 | 774 |
808 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 775 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
809 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 776 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
810 } | 777 } |
811 | 778 |
812 | 779 |
(...skipping 1466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2279 Property* prop = fun->AsProperty(); | 2246 Property* prop = fun->AsProperty(); |
2280 Literal* key = prop->key()->AsLiteral(); | 2247 Literal* key = prop->key()->AsLiteral(); |
2281 if (key != NULL && key->handle()->IsSymbol()) { | 2248 if (key != NULL && key->handle()->IsSymbol()) { |
2282 // Call to a named property, use call IC. | 2249 // Call to a named property, use call IC. |
2283 { PreservePositionScope scope(masm()->positions_recorder()); | 2250 { PreservePositionScope scope(masm()->positions_recorder()); |
2284 VisitForStackValue(prop->obj()); | 2251 VisitForStackValue(prop->obj()); |
2285 } | 2252 } |
2286 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2253 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
2287 } else { | 2254 } else { |
2288 // Call to a keyed property. | 2255 // Call to a keyed property. |
2289 // For a synthetic property use keyed load IC followed by function call, | 2256 { PreservePositionScope scope(masm()->positions_recorder()); |
2290 // for a regular property use EmitKeyedCallWithIC. | 2257 VisitForStackValue(prop->obj()); |
2291 if (prop->is_synthetic()) { | |
2292 // Do not visit the object and key subexpressions (they are shared | |
2293 // by all occurrences of the same rewritten parameter). | |
2294 ASSERT(prop->obj()->AsVariableProxy() != NULL); | |
2295 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | |
2296 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); | |
2297 MemOperand operand = EmitSlotSearch(slot, a1); | |
2298 __ lw(a1, operand); | |
2299 | |
2300 ASSERT(prop->key()->AsLiteral() != NULL); | |
2301 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); | |
2302 __ li(a0, Operand(prop->key()->AsLiteral()->handle())); | |
2303 | |
2304 // Record source code position for IC call. | |
2305 SetSourcePosition(prop->position()); | |
2306 | |
2307 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | |
2308 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | |
2309 __ lw(a1, GlobalObjectOperand()); | |
2310 __ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset)); | |
2311 __ Push(v0, a1); // Function, receiver. | |
2312 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); | |
2313 } else { | |
2314 { PreservePositionScope scope(masm()->positions_recorder()); | |
2315 VisitForStackValue(prop->obj()); | |
2316 } | |
2317 EmitKeyedCallWithIC(expr, prop->key()); | |
2318 } | 2258 } |
| 2259 EmitKeyedCallWithIC(expr, prop->key()); |
2319 } | 2260 } |
2320 } else { | 2261 } else { |
2321 { PreservePositionScope scope(masm()->positions_recorder()); | 2262 { PreservePositionScope scope(masm()->positions_recorder()); |
2322 VisitForStackValue(fun); | 2263 VisitForStackValue(fun); |
2323 } | 2264 } |
2324 // Load global receiver object. | 2265 // Load global receiver object. |
2325 __ lw(a1, GlobalObjectOperand()); | 2266 __ lw(a1, GlobalObjectOperand()); |
2326 __ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset)); | 2267 __ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset)); |
2327 __ push(a1); | 2268 __ push(a1); |
2328 // Emit function call. | 2269 // Emit function call. |
(...skipping 1350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3679 | 3620 |
3680 | 3621 |
3681 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3622 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
3682 switch (expr->op()) { | 3623 switch (expr->op()) { |
3683 case Token::DELETE: { | 3624 case Token::DELETE: { |
3684 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3625 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
3685 Property* prop = expr->expression()->AsProperty(); | 3626 Property* prop = expr->expression()->AsProperty(); |
3686 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 3627 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
3687 | 3628 |
3688 if (prop != NULL) { | 3629 if (prop != NULL) { |
3689 if (prop->is_synthetic()) { | 3630 VisitForStackValue(prop->obj()); |
3690 // Result of deleting parameters is false, even when they rewrite | 3631 VisitForStackValue(prop->key()); |
3691 // to accesses on the arguments object. | 3632 __ li(a1, Operand(Smi::FromInt(strict_mode_flag()))); |
3692 context()->Plug(false); | 3633 __ push(a1); |
3693 } else { | 3634 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
3694 VisitForStackValue(prop->obj()); | 3635 context()->Plug(v0); |
3695 VisitForStackValue(prop->key()); | |
3696 __ li(a1, Operand(Smi::FromInt(strict_mode_flag()))); | |
3697 __ push(a1); | |
3698 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | |
3699 context()->Plug(v0); | |
3700 } | |
3701 } else if (var != NULL) { | 3636 } else if (var != NULL) { |
3702 // Delete of an unqualified identifier is disallowed in strict mode | 3637 // Delete of an unqualified identifier is disallowed in strict mode |
3703 // but "delete this" is. | 3638 // but "delete this" is. |
3704 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); | 3639 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); |
3705 if (var->is_global()) { | 3640 if (var->is_global()) { |
3706 __ lw(a2, GlobalObjectOperand()); | 3641 __ lw(a2, GlobalObjectOperand()); |
3707 __ li(a1, Operand(var->name())); | 3642 __ li(a1, Operand(var->name())); |
3708 __ li(a0, Operand(Smi::FromInt(kNonStrictMode))); | 3643 __ li(a0, Operand(Smi::FromInt(kNonStrictMode))); |
3709 __ Push(a2, a1, a0); | 3644 __ Push(a2, a1, a0); |
3710 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3645 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
(...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4318 __ Addu(at, a1, Operand(masm_->CodeObject())); | 4253 __ Addu(at, a1, Operand(masm_->CodeObject())); |
4319 __ Jump(at); | 4254 __ Jump(at); |
4320 } | 4255 } |
4321 | 4256 |
4322 | 4257 |
4323 #undef __ | 4258 #undef __ |
4324 | 4259 |
4325 } } // namespace v8::internal | 4260 } } // namespace v8::internal |
4326 | 4261 |
4327 #endif // V8_TARGET_ARCH_MIPS | 4262 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |