| 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 |