Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: src/ia32/codegen-ia32.cc

Issue 147075: Allocate arguments object on-demand instead of at function entry.... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/codegen-ia32.h ('k') | src/parser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ia32/codegen-ia32.h ('k') | src/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698