OLD | NEW |
---|---|
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
168 allocator_->Initialize(); | 168 allocator_->Initialize(); |
169 frame_->Enter(); | 169 frame_->Enter(); |
170 | 170 |
171 // Allocate space for locals and initialize them. | 171 // Allocate space for locals and initialize them. |
172 frame_->AllocateStackSlots(); | 172 frame_->AllocateStackSlots(); |
173 // Initialize the function return target after the locals are set | 173 // Initialize the function return target after the locals are set |
174 // up, because it needs the expected frame height from the frame. | 174 // up, because it needs the expected frame height from the frame. |
175 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); | 175 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); |
176 function_return_is_shadowed_ = false; | 176 function_return_is_shadowed_ = false; |
177 | 177 |
178 // Allocate the arguments object and copy the parameters into it. | 178 // Allocate the local context if needed. |
179 if (scope_->arguments() != NULL) { | |
180 ASSERT(scope_->arguments_shadow() != NULL); | |
181 Comment cmnt(masm_, "[ Allocate arguments object"); | |
182 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | |
183 frame_->PushFunction(); | |
184 frame_->PushReceiverSlotAddress(); | |
185 frame_->Push(Smi::FromInt(scope_->num_parameters())); | |
186 Result answer = frame_->CallStub(&stub, 3); | |
187 frame_->Push(&answer); | |
188 } | |
189 | |
190 if (scope_->num_heap_slots() > 0) { | 179 if (scope_->num_heap_slots() > 0) { |
191 Comment cmnt(masm_, "[ allocate local context"); | 180 Comment cmnt(masm_, "[ allocate local context"); |
192 // Allocate local context. | 181 // Allocate local context. |
193 // Get outer context and create a new context based on it. | 182 // Get outer context and create a new context based on it. |
194 frame_->PushFunction(); | 183 frame_->PushFunction(); |
195 Result context = frame_->CallRuntime(Runtime::kNewContext, 1); | 184 Result context = frame_->CallRuntime(Runtime::kNewContext, 1); |
196 | 185 |
197 // Update context local. | 186 // Update context local. |
198 frame_->SaveContextRegister(); | 187 frame_->SaveContextRegister(); |
199 | 188 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
240 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 229 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
241 Result scratch = allocator_->Allocate(); | 230 Result scratch = allocator_->Allocate(); |
242 ASSERT(scratch.is_valid()); | 231 ASSERT(scratch.is_valid()); |
243 frame_->Spill(context.reg()); | 232 frame_->Spill(context.reg()); |
244 frame_->Spill(value.reg()); | 233 frame_->Spill(value.reg()); |
245 __ RecordWrite(context.reg(), offset, value.reg(), scratch.reg()); | 234 __ RecordWrite(context.reg(), offset, value.reg(), scratch.reg()); |
246 } | 235 } |
247 } | 236 } |
248 } | 237 } |
249 | 238 |
250 // This section stores the pointer to the arguments object that | |
251 // was allocated and copied into above. If the address was not | |
252 // saved to TOS, we push ecx onto the stack. | |
253 // | |
254 // Store the arguments object. This must happen after context | 239 // Store the arguments object. This must happen after context |
255 // initialization because the arguments object may be stored in the | 240 // initialization because the arguments object may be stored in |
256 // context. | 241 // the context. |
257 if (scope_->arguments() != NULL) { | 242 if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) { |
258 Comment cmnt(masm_, "[ store arguments object"); | 243 StoreArgumentsObject(true); |
259 { Reference shadow_ref(this, scope_->arguments_shadow()); | |
260 ASSERT(shadow_ref.is_slot()); | |
261 { Reference arguments_ref(this, scope_->arguments()); | |
262 ASSERT(arguments_ref.is_slot()); | |
263 // Here we rely on the convenient property that references to slot | |
264 // take up zero space in the frame (ie, it doesn't matter that the | |
265 // stored value is actually below the reference on the frame). | |
266 arguments_ref.SetValue(NOT_CONST_INIT); | |
267 } | |
268 shadow_ref.SetValue(NOT_CONST_INIT); | |
269 } | |
270 frame_->Drop(); // Value is no longer needed. | |
271 } | 244 } |
272 | 245 |
273 // Generate code to 'execute' declarations and initialize functions | 246 // Generate code to 'execute' declarations and initialize functions |
274 // (source elements). In case of an illegal redeclaration we need to | 247 // (source elements). In case of an illegal redeclaration we need to |
275 // handle that instead of processing the declarations. | 248 // handle that instead of processing the declarations. |
276 if (scope_->HasIllegalRedeclaration()) { | 249 if (scope_->HasIllegalRedeclaration()) { |
277 Comment cmnt(masm_, "[ illegal redeclarations"); | 250 Comment cmnt(masm_, "[ illegal redeclarations"); |
278 scope_->VisitIllegalRedeclaration(this); | 251 scope_->VisitIllegalRedeclaration(this); |
279 } else { | 252 } else { |
280 Comment cmnt(masm_, "[ declarations"); | 253 Comment cmnt(masm_, "[ declarations"); |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
584 // TODO(1241834): Fetch the position from the variable instead of using | 557 // TODO(1241834): Fetch the position from the variable instead of using |
585 // no position. | 558 // no position. |
586 Property property(&global, &key, RelocInfo::kNoPosition); | 559 Property property(&global, &key, RelocInfo::kNoPosition); |
587 Load(&property); | 560 Load(&property); |
588 } else { | 561 } else { |
589 Load(x, INSIDE_TYPEOF); | 562 Load(x, INSIDE_TYPEOF); |
590 } | 563 } |
591 } | 564 } |
592 | 565 |
593 | 566 |
567 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() const { | |
568 if (scope_->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; | |
569 ASSERT(scope_->arguments_shadow() != NULL); | |
570 return (scope_->num_heap_slots() > 0) | |
Mads Ager (chromium)
2009/06/24 07:52:17
Could you add a short comment explaining the reaso
| |
571 ? EAGER_ARGUMENTS_ALLOCATION | |
572 : LAZY_ARGUMENTS_ALLOCATION; | |
573 } | |
574 | |
575 | |
576 Result CodeGenerator::StoreArgumentsObject(bool initial) { | |
577 ArgumentsAllocationMode mode = ArgumentsMode(); | |
578 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); | |
579 | |
580 Comment cmnt(masm_, "[ store arguments object"); | |
581 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { | |
582 // When using lazy arguments allocation, we store the hole value | |
583 // as a sentinel indicating that the arguments object hasn't been | |
584 // allocated yet. | |
585 frame_->Push(Factory::the_hole_value()); | |
586 } else { | |
587 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | |
588 frame_->PushFunction(); | |
589 frame_->PushReceiverSlotAddress(); | |
590 frame_->Push(Smi::FromInt(scope_->num_parameters())); | |
591 Result result = frame_->CallStub(&stub, 3); | |
592 frame_->Push(&result); | |
593 } | |
594 | |
595 { Reference shadow_ref(this, scope_->arguments_shadow()); | |
596 Reference arguments_ref(this, scope_->arguments()); | |
597 ASSERT(shadow_ref.is_slot() && arguments_ref.is_slot()); | |
598 // Here we rely on the convenient property that references to slot | |
599 // take up zero space in the frame (ie, it doesn't matter that the | |
600 // stored value is actually below the reference on the frame). | |
601 JumpTarget done; | |
602 bool skip_arguments = false; | |
603 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { | |
604 // We have to skip storing into the arguments slot if it has | |
605 // already been written to. This can happen if the a function | |
606 // has a local variable named 'arguments'. | |
607 LoadFromSlot(scope_->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | |
608 Result arguments = frame_->Pop(); | |
609 if (arguments.is_constant()) { | |
610 // We have to skip updating the arguments object if it has | |
611 // been assigned a proper value. | |
612 skip_arguments = !arguments.handle()->IsTheHole(); | |
613 } else { | |
614 __ cmp(Operand(arguments.reg()), Immediate(Factory::the_hole_value())); | |
615 arguments.Unuse(); | |
616 done.Branch(not_equal); | |
617 } | |
618 } | |
619 if (!skip_arguments) { | |
620 arguments_ref.SetValue(NOT_CONST_INIT); | |
621 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); | |
622 } | |
623 shadow_ref.SetValue(NOT_CONST_INIT); | |
624 } | |
625 return frame_->Pop(); | |
626 } | |
627 | |
628 | |
594 Reference::Reference(CodeGenerator* cgen, Expression* expression) | 629 Reference::Reference(CodeGenerator* cgen, Expression* expression) |
595 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { | 630 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { |
596 cgen->LoadReference(this); | 631 cgen->LoadReference(this); |
597 } | 632 } |
598 | 633 |
599 | 634 |
600 Reference::~Reference() { | 635 Reference::~Reference() { |
601 cgen_->UnloadReference(this); | 636 cgen_->UnloadReference(this); |
602 } | 637 } |
603 | 638 |
(...skipping 1479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2083 InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; | 2118 InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; |
2084 CallFunctionStub call_function(arg_count, in_loop); | 2119 CallFunctionStub call_function(arg_count, in_loop); |
2085 Result answer = frame_->CallStub(&call_function, arg_count + 1); | 2120 Result answer = frame_->CallStub(&call_function, arg_count + 1); |
2086 // Restore context and replace function on the stack with the | 2121 // Restore context and replace function on the stack with the |
2087 // result of the stub invocation. | 2122 // result of the stub invocation. |
2088 frame_->RestoreContextRegister(); | 2123 frame_->RestoreContextRegister(); |
2089 frame_->SetElementAt(0, &answer); | 2124 frame_->SetElementAt(0, &answer); |
2090 } | 2125 } |
2091 | 2126 |
2092 | 2127 |
2128 void CodeGenerator::CallApplyLazy(Property* apply, | |
2129 Expression* receiver, | |
2130 VariableProxy* arguments, | |
2131 int position) { | |
2132 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); | |
2133 ASSERT(arguments->IsArguments()); | |
2134 | |
2135 JumpTarget slow, done; | |
2136 | |
2137 // Load the apply function onto the stack. This will usually | |
2138 // give us a megamorphic load site. Not super, but it works. | |
2139 Reference ref(this, apply); | |
2140 ref.GetValue(NOT_INSIDE_TYPEOF); | |
2141 ASSERT(ref.type() == Reference::NAMED); | |
2142 | |
2143 // Load the receiver and the existing arguments object onto the | |
2144 // expression stack. Avoid allocating the arguments object here. | |
2145 Load(receiver); | |
2146 LoadFromSlot(scope_->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | |
2147 | |
2148 // Emit the source position information after having loaded the | |
2149 // receiver and the arguments. | |
2150 CodeForSourcePosition(position); | |
2151 | |
2152 // Check if the arguments object has been lazily allocated | |
2153 // already. If so, just use that instead of copying the arguments | |
2154 // from the stack. This also deals with cases where a local variable | |
2155 // named 'arguments' has been introduced. | |
2156 frame_->Dup(); | |
2157 Result probe = frame_->Pop(); | |
2158 bool try_lazy = true; | |
2159 if (probe.is_constant()) { | |
2160 try_lazy = probe.handle()->IsTheHole(); | |
2161 } else { | |
2162 __ cmp(Operand(probe.reg()), Immediate(Factory::the_hole_value())); | |
2163 probe.Unuse(); | |
2164 slow.Branch(not_equal); | |
2165 } | |
2166 | |
2167 if (try_lazy) { | |
2168 JumpTarget build_args; | |
2169 | |
2170 // Get rid of the arguments object probe. | |
2171 frame_->Pop(); | |
2172 | |
2173 // Before messing with the execution stack, we sync all | |
2174 // elements. This is bound to happen anyway because we're | |
2175 // about to call a function. | |
2176 frame_->SyncRange(0, frame_->element_count() - 1); | |
2177 | |
2178 // Check that the receiver really is a JavaScript object. | |
2179 __ mov(edx, Operand(esp, 0 * kPointerSize)); | |
2180 __ test(edx, Immediate(kSmiTagMask)); | |
2181 build_args.Branch(zero); | |
2182 __ CmpObjectType(edx, FIRST_JS_OBJECT_TYPE, ecx); | |
2183 build_args.Branch(less); | |
2184 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | |
2185 build_args.Branch(greater); | |
2186 | |
2187 // Verify that we're invoking is Function.prototype.apply. | |
Mads Ager (chromium)
2009/06/24 07:52:17
invoking is -> invoking
| |
2188 __ mov(edx, Operand(esp, 1 * kPointerSize)); | |
2189 __ test(edx, Immediate(kSmiTagMask)); | |
2190 build_args.Branch(zero); | |
2191 __ CmpObjectType(edx, JS_FUNCTION_TYPE, ecx); | |
2192 build_args.Branch(not_equal); | |
2193 __ mov(edx, FieldOperand(edx, JSFunction::kSharedFunctionInfoOffset)); | |
2194 Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply)); | |
2195 __ cmp(FieldOperand(edx, SharedFunctionInfo::kCodeOffset), | |
2196 Immediate(apply_code)); | |
2197 build_args.Branch(not_equal); | |
2198 | |
2199 // Get the function receiver from the stack. Check that it | |
2200 // really is a function. | |
2201 __ mov(edi, Operand(esp, 2 * kPointerSize)); | |
2202 __ test(edi, Immediate(kSmiTagMask)); | |
2203 build_args.Branch(zero); | |
2204 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | |
2205 build_args.Branch(not_equal); | |
2206 | |
2207 // Copy the arguments to this function possibly from the | |
2208 // adaptor frame below it. | |
2209 Label invoke, adapted; | |
2210 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | |
2211 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); | |
2212 __ cmp(ecx, ArgumentsAdaptorFrame::SENTINEL); | |
2213 __ j(equal, &adapted); | |
2214 | |
2215 // No arguments adaptor frame. Copy fixed number of arguments. | |
2216 __ mov(eax, Immediate(scope_->num_parameters())); | |
2217 for (int i = 0; i < scope_->num_parameters(); i++) { | |
2218 __ push(frame_->ParameterAt(i)); | |
2219 } | |
2220 __ jmp(&invoke); | |
2221 | |
2222 // Arguments adaptor frame present. Copy arguments from there, but | |
2223 // avoid copying too many arguments to avoid stack overflows. | |
2224 __ bind(&adapted); | |
2225 static const uint32_t kArgumentsLimit = 1 * KB; | |
2226 __ mov(eax, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | |
2227 __ shr(eax, kSmiTagSize); | |
2228 __ mov(ecx, Operand(eax)); | |
2229 __ cmp(eax, kArgumentsLimit); | |
2230 build_args.Branch(above); | |
2231 | |
2232 // Loop through the arguments pushing them onto the execution | |
2233 // stack. We don't inform the virtual frame of the push, so we don't | |
2234 // have to worry about getting rid of the elements from the virtual | |
2235 // frame. | |
2236 Label loop; | |
2237 __ bind(&loop); | |
2238 __ test(ecx, Operand(ecx)); | |
2239 __ j(zero, &invoke); | |
2240 __ push(Operand(edx, ecx, times_4, 1 * kPointerSize)); | |
2241 __ dec(ecx); | |
2242 __ jmp(&loop); | |
2243 | |
2244 // Invoke the function. The virtual frame knows about the receiver | |
2245 // so make sure to forget that explicitly. | |
2246 __ bind(&invoke); | |
2247 ParameterCount actual(eax); | |
2248 __ InvokeFunction(edi, actual, CALL_FUNCTION); | |
2249 frame_->Forget(1); | |
2250 Result result = allocator()->Allocate(eax); | |
2251 frame_->SetElementAt(0, &result); | |
2252 done.Jump(); | |
2253 | |
2254 // Slow-case: Allocate the arguments object since we know it isn't | |
2255 // there, and fall-through to the slow-case where we call | |
2256 // Function.prototype.apply. | |
2257 build_args.Bind(); | |
2258 Result arguments_object = StoreArgumentsObject(false); | |
2259 frame_->Push(&arguments_object); | |
2260 slow.Bind(); | |
2261 } | |
2262 | |
2263 // Flip the apply function and the function we to call on the stack, | |
Mads Ager (chromium)
2009/06/24 07:52:17
we to -> to
| |
2264 // so the function looks like the receiver of the apply call. This | |
2265 // way, the generic Function.prototype.apply implementation can deal | |
2266 // with the call like it usually does. | |
2267 Result a2 = frame_->Pop(); | |
Kasper Lund
2009/06/24 06:55:07
It would be nice to find a better way of achieving
| |
2268 Result a1 = frame_->Pop(); | |
2269 Result ap = frame_->Pop(); | |
2270 Result fn = frame_->Pop(); | |
2271 frame_->Push(&ap); | |
2272 frame_->Push(&fn); | |
2273 frame_->Push(&a1); | |
2274 frame_->Push(&a2); | |
2275 CallFunctionStub call_function(2, NOT_IN_LOOP); | |
2276 Result res = frame_->CallStub(&call_function, 3); | |
2277 frame_->Push(&res); | |
2278 | |
2279 // All done. Restore context register after call. | |
2280 if (try_lazy) done.Bind(); | |
2281 frame_->RestoreContextRegister(); | |
2282 } | |
2283 | |
2284 | |
2093 class DeferredStackCheck: public DeferredCode { | 2285 class DeferredStackCheck: public DeferredCode { |
2094 public: | 2286 public: |
2095 DeferredStackCheck() { | 2287 DeferredStackCheck() { |
2096 set_comment("[ DeferredStackCheck"); | 2288 set_comment("[ DeferredStackCheck"); |
2097 } | 2289 } |
2098 | 2290 |
2099 virtual void Generate(); | 2291 virtual void Generate(); |
2100 }; | 2292 }; |
2101 | 2293 |
2102 | 2294 |
(...skipping 1505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3608 // because it will always be a context slot. | 3800 // because it will always be a context slot. |
3609 ASSERT(slot->type() == Slot::CONTEXT); | 3801 ASSERT(slot->type() == Slot::CONTEXT); |
3610 Result temp = allocator_->Allocate(); | 3802 Result temp = allocator_->Allocate(); |
3611 ASSERT(temp.is_valid()); | 3803 ASSERT(temp.is_valid()); |
3612 __ mov(temp.reg(), SlotOperand(slot, temp.reg())); | 3804 __ mov(temp.reg(), SlotOperand(slot, temp.reg())); |
3613 frame_->Push(&temp); | 3805 frame_->Push(&temp); |
3614 } | 3806 } |
3615 } | 3807 } |
3616 | 3808 |
3617 | 3809 |
3810 void CodeGenerator::LoadFromSlotCheckForArguments(Slot* slot, | |
3811 TypeofState state) { | |
3812 LoadFromSlot(slot, state); | |
3813 | |
3814 // Bail out quickly if we're not using lazy arguments allocation. | |
3815 if (ArgumentsMode() != LAZY_ARGUMENTS_ALLOCATION) return; | |
3816 | |
3817 // ... or if the slot isn't a non-parameter arguments slot. | |
3818 if (slot->type() == Slot::PARAMETER || !slot->is_arguments()) return; | |
3819 | |
3820 // Pop the loaded value from the stack. | |
3821 Result value = frame_->Pop(); | |
3822 | |
3823 // If the loaded value is a constant, we know if the arguments | |
3824 // object has been lazily loaded yet. | |
3825 if (value.is_constant()) { | |
3826 if (value.handle()->IsTheHole()) { | |
3827 Result arguments = StoreArgumentsObject(false); | |
3828 frame_->Push(&arguments); | |
3829 } else { | |
3830 frame_->Push(&value); | |
3831 } | |
3832 return; | |
3833 } | |
3834 | |
3835 // The loaded value is in a register. If it is the sentinel that | |
3836 // indicates that we haven't loaded the arguments object yet, we | |
3837 // need to do it now. | |
3838 JumpTarget exit; | |
3839 __ cmp(Operand(value.reg()), Immediate(Factory::the_hole_value())); | |
3840 frame_->Push(&value); | |
3841 exit.Branch(not_equal); | |
3842 Result arguments = StoreArgumentsObject(false); | |
3843 frame_->SetElementAt(0, &arguments); | |
3844 exit.Bind(); | |
3845 } | |
3846 | |
3847 | |
3618 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( | 3848 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( |
3619 Slot* slot, | 3849 Slot* slot, |
3620 TypeofState typeof_state, | 3850 TypeofState typeof_state, |
3621 JumpTarget* slow) { | 3851 JumpTarget* slow) { |
3622 // Check that no extension objects have been created by calls to | 3852 // Check that no extension objects have been created by calls to |
3623 // eval from the current scope to the global scope. | 3853 // eval from the current scope to the global scope. |
3624 Register context = esi; | 3854 Register context = esi; |
3625 Result tmp = allocator_->Allocate(); | 3855 Result tmp = allocator_->Allocate(); |
3626 ASSERT(tmp.is_valid()); // All non-reserved registers were available. | 3856 ASSERT(tmp.is_valid()); // All non-reserved registers were available. |
3627 | 3857 |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3780 // scope. | 4010 // scope. |
3781 } | 4011 } |
3782 | 4012 |
3783 exit.Bind(); | 4013 exit.Bind(); |
3784 } | 4014 } |
3785 } | 4015 } |
3786 | 4016 |
3787 | 4017 |
3788 void CodeGenerator::VisitSlot(Slot* node) { | 4018 void CodeGenerator::VisitSlot(Slot* node) { |
3789 Comment cmnt(masm_, "[ Slot"); | 4019 Comment cmnt(masm_, "[ Slot"); |
3790 LoadFromSlot(node, typeof_state()); | 4020 LoadFromSlotCheckForArguments(node, typeof_state()); |
3791 } | 4021 } |
3792 | 4022 |
3793 | 4023 |
3794 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 4024 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
3795 Comment cmnt(masm_, "[ VariableProxy"); | 4025 Comment cmnt(masm_, "[ VariableProxy"); |
3796 Variable* var = node->var(); | 4026 Variable* var = node->var(); |
3797 Expression* expr = var->rewrite(); | 4027 Expression* expr = var->rewrite(); |
3798 if (expr != NULL) { | 4028 if (expr != NULL) { |
3799 Visit(expr); | 4029 Visit(expr); |
3800 } else { | 4030 } else { |
(...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4342 | 4572 |
4343 } else if (property != NULL) { | 4573 } else if (property != NULL) { |
4344 // Check if the key is a literal string. | 4574 // Check if the key is a literal string. |
4345 Literal* literal = property->key()->AsLiteral(); | 4575 Literal* literal = property->key()->AsLiteral(); |
4346 | 4576 |
4347 if (literal != NULL && literal->handle()->IsSymbol()) { | 4577 if (literal != NULL && literal->handle()->IsSymbol()) { |
4348 // ------------------------------------------------------------------ | 4578 // ------------------------------------------------------------------ |
4349 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' | 4579 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' |
4350 // ------------------------------------------------------------------ | 4580 // ------------------------------------------------------------------ |
4351 | 4581 |
4352 // Push the name of the function and the receiver onto the stack. | 4582 Handle<String> name = Handle<String>::cast(literal->handle()); |
4353 frame_->Push(literal->handle()); | |
4354 Load(property->obj()); | |
4355 | 4583 |
4356 // Load the arguments. | 4584 if (ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION && |
4357 int arg_count = args->length(); | 4585 name->IsEqualTo(CStrVector("apply")) && |
4358 for (int i = 0; i < arg_count; i++) { | 4586 args->length() == 2 && |
4359 Load(args->at(i)); | 4587 args->at(1)->AsVariableProxy() != NULL && |
4588 args->at(1)->AsVariableProxy()->IsArguments()) { | |
4589 // Use the optimized Function.prototype.apply that avoids | |
4590 // allocating lazily allocated arguments objects. | |
4591 CallApplyLazy(property, | |
4592 args->at(0), | |
4593 args->at(1)->AsVariableProxy(), | |
4594 node->position()); | |
4595 | |
4596 } else { | |
4597 // Push the name of the function and the receiver onto the stack. | |
4598 frame_->Push(name); | |
4599 Load(property->obj()); | |
4600 | |
4601 // Load the arguments. | |
4602 int arg_count = args->length(); | |
4603 for (int i = 0; i < arg_count; i++) { | |
4604 Load(args->at(i)); | |
4605 } | |
4606 | |
4607 // Call the IC initialization code. | |
4608 CodeForSourcePosition(node->position()); | |
4609 Result result = | |
4610 frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, | |
4611 loop_nesting()); | |
4612 frame_->RestoreContextRegister(); | |
4613 // Replace the function on the stack with the result. | |
4614 frame_->SetElementAt(0, &result); | |
4360 } | 4615 } |
4361 | 4616 |
4362 // Call the IC initialization code. | |
4363 CodeForSourcePosition(node->position()); | |
4364 Result result = | |
4365 frame_->CallCallIC(RelocInfo::CODE_TARGET, arg_count, loop_nesting()); | |
4366 frame_->RestoreContextRegister(); | |
4367 // Replace the function on the stack with the result. | |
4368 frame_->SetElementAt(0, &result); | |
4369 | |
4370 } else { | 4617 } else { |
4371 // ------------------------------------------- | 4618 // ------------------------------------------- |
4372 // JavaScript example: 'array[index](1, 2, 3)' | 4619 // JavaScript example: 'array[index](1, 2, 3)' |
4373 // ------------------------------------------- | 4620 // ------------------------------------------- |
4374 | 4621 |
4375 // Load the function to call from the property through a reference. | 4622 // Load the function to call from the property through a reference. |
4376 Reference ref(this, property); | 4623 Reference ref(this, property); |
4377 ref.GetValue(NOT_INSIDE_TYPEOF); | 4624 ref.GetValue(NOT_INSIDE_TYPEOF); |
4378 | 4625 |
4379 // Pass receiver to called function. | 4626 // Pass receiver to called function. |
(...skipping 1451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5831 void Reference::GetValue(TypeofState typeof_state) { | 6078 void Reference::GetValue(TypeofState typeof_state) { |
5832 ASSERT(!cgen_->in_spilled_code()); | 6079 ASSERT(!cgen_->in_spilled_code()); |
5833 ASSERT(cgen_->HasValidEntryRegisters()); | 6080 ASSERT(cgen_->HasValidEntryRegisters()); |
5834 ASSERT(!is_illegal()); | 6081 ASSERT(!is_illegal()); |
5835 MacroAssembler* masm = cgen_->masm(); | 6082 MacroAssembler* masm = cgen_->masm(); |
5836 switch (type_) { | 6083 switch (type_) { |
5837 case SLOT: { | 6084 case SLOT: { |
5838 Comment cmnt(masm, "[ Load from Slot"); | 6085 Comment cmnt(masm, "[ Load from Slot"); |
5839 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 6086 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
5840 ASSERT(slot != NULL); | 6087 ASSERT(slot != NULL); |
5841 cgen_->LoadFromSlot(slot, typeof_state); | 6088 cgen_->LoadFromSlotCheckForArguments(slot, typeof_state); |
5842 break; | 6089 break; |
5843 } | 6090 } |
5844 | 6091 |
5845 case NAMED: { | 6092 case NAMED: { |
5846 // TODO(1241834): Make sure that it is safe to ignore the | 6093 // TODO(1241834): Make sure that it is safe to ignore the |
5847 // distinction between expressions in a typeof and not in a | 6094 // distinction between expressions in a typeof and not in a |
5848 // typeof. If there is a chance that reference errors can be | 6095 // typeof. If there is a chance that reference errors can be |
5849 // thrown below, we must distinguish between the two kinds of | 6096 // thrown below, we must distinguish between the two kinds of |
5850 // loads (typeof expression loads must not throw a reference | 6097 // loads (typeof expression loads must not throw a reference |
5851 // error). | 6098 // error). |
(...skipping 1691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7543 | 7790 |
7544 // Slow-case: Go through the JavaScript implementation. | 7791 // Slow-case: Go through the JavaScript implementation. |
7545 __ bind(&slow); | 7792 __ bind(&slow); |
7546 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 7793 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
7547 } | 7794 } |
7548 | 7795 |
7549 | 7796 |
7550 #undef __ | 7797 #undef __ |
7551 | 7798 |
7552 } } // namespace v8::internal | 7799 } } // namespace v8::internal |
OLD | NEW |