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