Chromium Code Reviews| 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 |