| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 return frame_->ParameterAt(index); | 306 return frame_->ParameterAt(index); |
| 307 | 307 |
| 308 case Slot::LOCAL: | 308 case Slot::LOCAL: |
| 309 return frame_->LocalAt(index); | 309 return frame_->LocalAt(index); |
| 310 | 310 |
| 311 case Slot::CONTEXT: { | 311 case Slot::CONTEXT: { |
| 312 // Follow the context chain if necessary. | 312 // Follow the context chain if necessary. |
| 313 ASSERT(!tmp.is(cp)); // do not overwrite context register | 313 ASSERT(!tmp.is(cp)); // do not overwrite context register |
| 314 Register context = cp; | 314 Register context = cp; |
| 315 int chain_length = scope()->ContextChainLength(slot->var()->scope()); | 315 int chain_length = scope()->ContextChainLength(slot->var()->scope()); |
| 316 for (int i = chain_length; i-- > 0;) { | 316 for (int i = 0; i < chain_length; i++) { |
| 317 // Load the closure. | 317 // Load the closure. |
| 318 // (All contexts, even 'with' contexts, have a closure, | 318 // (All contexts, even 'with' contexts, have a closure, |
| 319 // and it is the same for all contexts inside a function. | 319 // and it is the same for all contexts inside a function. |
| 320 // There is no need to go to the function context first.) | 320 // There is no need to go to the function context first.) |
| 321 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); | 321 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 322 // Load the function context (which is the incoming, outer context). | 322 // Load the function context (which is the incoming, outer context). |
| 323 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); | 323 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); |
| 324 context = tmp; | 324 context = tmp; |
| 325 } | 325 } |
| 326 // We may have a 'with' context now. Get the function context. | 326 // We may have a 'with' context now. Get the function context. |
| 327 // (In fact this mov may never be the needed, since the scope analysis | 327 // (In fact this mov may never be the needed, since the scope analysis |
| 328 // may not permit a direct context access in this case and thus we are | 328 // may not permit a direct context access in this case and thus we are |
| 329 // always at a function context. However it is safe to dereference be- | 329 // always at a function context. However it is safe to dereference be- |
| 330 // cause the function context of a function context is itself. Before | 330 // cause the function context of a function context is itself. Before |
| 331 // deleting this mov we should try to create a counter-example first, | 331 // deleting this mov we should try to create a counter-example first, |
| 332 // though...) | 332 // though...) |
| 333 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 333 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
| 334 return ContextOperand(tmp, index); | 334 return ContextOperand(tmp, index); |
| 335 } | 335 } |
| 336 | 336 |
| 337 default: | 337 default: |
| 338 UNREACHABLE(); | 338 UNREACHABLE(); |
| 339 return MemOperand(r0, 0); | 339 return MemOperand(r0, 0); |
| 340 } | 340 } |
| 341 } | 341 } |
| 342 | 342 |
| 343 | 343 |
| 344 MemOperand CodeGenerator::ContextSlotOperandCheckExtensions( |
| 345 Slot* slot, |
| 346 Register tmp, |
| 347 Register tmp2, |
| 348 JumpTarget* slow) { |
| 349 ASSERT(slot->type() == Slot::CONTEXT); |
| 350 Register context = cp; |
| 351 |
| 352 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { |
| 353 if (s->num_heap_slots() > 0) { |
| 354 if (s->calls_eval()) { |
| 355 // Check that extension is NULL. |
| 356 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX)); |
| 357 __ tst(tmp2, tmp2); |
| 358 slow->Branch(ne); |
| 359 } |
| 360 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 361 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); |
| 362 context = tmp; |
| 363 } |
| 364 } |
| 365 // Check that last extension is NULL. |
| 366 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX)); |
| 367 __ tst(tmp2, tmp2); |
| 368 slow->Branch(ne); |
| 369 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
| 370 return ContextOperand(tmp, slot->index()); |
| 371 } |
| 372 |
| 373 |
| 344 // Loads a value on TOS. If it is a boolean value, the result may have been | 374 // Loads a value on TOS. If it is a boolean value, the result may have been |
| 345 // (partially) translated into branches, or it may have set the condition | 375 // (partially) translated into branches, or it may have set the condition |
| 346 // code register. If force_cc is set, the value is forced to set the | 376 // code register. If force_cc is set, the value is forced to set the |
| 347 // condition code register and no value is pushed. If the condition code | 377 // condition code register and no value is pushed. If the condition code |
| 348 // register was set, has_cc() is true and cc_reg_ contains the condition to | 378 // register was set, has_cc() is true and cc_reg_ contains the condition to |
| 349 // test for 'true'. | 379 // test for 'true'. |
| 350 void CodeGenerator::LoadCondition(Expression* x, | 380 void CodeGenerator::LoadCondition(Expression* x, |
| 351 TypeofState typeof_state, | 381 TypeofState typeof_state, |
| 352 JumpTarget* true_target, | 382 JumpTarget* true_target, |
| 353 JumpTarget* false_target, | 383 JumpTarget* false_target, |
| (...skipping 740 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1094 Variable* var = node->proxy()->var(); | 1124 Variable* var = node->proxy()->var(); |
| 1095 ASSERT(var != NULL); // must have been resolved | 1125 ASSERT(var != NULL); // must have been resolved |
| 1096 Slot* slot = var->slot(); | 1126 Slot* slot = var->slot(); |
| 1097 | 1127 |
| 1098 // If it was not possible to allocate the variable at compile time, | 1128 // If it was not possible to allocate the variable at compile time, |
| 1099 // we need to "declare" it at runtime to make sure it actually | 1129 // we need to "declare" it at runtime to make sure it actually |
| 1100 // exists in the local context. | 1130 // exists in the local context. |
| 1101 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1131 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1102 // Variables with a "LOOKUP" slot were introduced as non-locals | 1132 // Variables with a "LOOKUP" slot were introduced as non-locals |
| 1103 // during variable resolution and must have mode DYNAMIC. | 1133 // during variable resolution and must have mode DYNAMIC. |
| 1104 ASSERT(var->mode() == Variable::DYNAMIC); | 1134 ASSERT(var->is_dynamic()); |
| 1105 // For now, just do a runtime call. | 1135 // For now, just do a runtime call. |
| 1106 frame_->EmitPush(cp); | 1136 frame_->EmitPush(cp); |
| 1107 __ mov(r0, Operand(var->name())); | 1137 __ mov(r0, Operand(var->name())); |
| 1108 frame_->EmitPush(r0); | 1138 frame_->EmitPush(r0); |
| 1109 // Declaration nodes are always declared in only two modes. | 1139 // Declaration nodes are always declared in only two modes. |
| 1110 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); | 1140 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
| 1111 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; | 1141 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
| 1112 __ mov(r0, Operand(Smi::FromInt(attr))); | 1142 __ mov(r0, Operand(Smi::FromInt(attr))); |
| 1113 frame_->EmitPush(r0); | 1143 frame_->EmitPush(r0); |
| 1114 // Push initial value, if any. | 1144 // Push initial value, if any. |
| (...skipping 1090 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2205 exit.Jump(); | 2235 exit.Jump(); |
| 2206 else_.Bind(); | 2236 else_.Bind(); |
| 2207 LoadAndSpill(node->else_expression(), typeof_state()); | 2237 LoadAndSpill(node->else_expression(), typeof_state()); |
| 2208 exit.Bind(); | 2238 exit.Bind(); |
| 2209 } | 2239 } |
| 2210 | 2240 |
| 2211 | 2241 |
| 2212 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2242 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2213 VirtualFrame::SpilledScope spilled_scope(this); | 2243 VirtualFrame::SpilledScope spilled_scope(this); |
| 2214 if (slot->type() == Slot::LOOKUP) { | 2244 if (slot->type() == Slot::LOOKUP) { |
| 2215 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2245 ASSERT(slot->var()->is_dynamic()); |
| 2216 | 2246 |
| 2217 // For now, just do a runtime call. | 2247 JumpTarget slow(this); |
| 2248 JumpTarget done(this); |
| 2249 |
| 2250 // Generate fast-case code for variables that might be shadowed by |
| 2251 // eval-introduced variables. Eval is used a lot without |
| 2252 // introducing variables. In those cases, we do not want to |
| 2253 // perform a runtime call for all variables in the scope |
| 2254 // containing the eval. |
| 2255 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 2256 LoadFromGlobalSlotCheckExtensions(slot, typeof_state, r1, r2, &slow); |
| 2257 // If there was no control flow to slow, we can exit early. |
| 2258 if (!slow.is_linked()) { |
| 2259 frame_->EmitPush(r0); |
| 2260 return; |
| 2261 } |
| 2262 |
| 2263 done.Jump(); |
| 2264 |
| 2265 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 2266 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); |
| 2267 __ ldr(r0, |
| 2268 ContextSlotOperandCheckExtensions(potential_slot, |
| 2269 r1, |
| 2270 r2, |
| 2271 &slow)); |
| 2272 // There is always control flow to slow from |
| 2273 // ContextSlotOperandCheckExtensions. |
| 2274 done.Jump(); |
| 2275 } |
| 2276 |
| 2277 slow.Bind(); |
| 2218 frame_->EmitPush(cp); | 2278 frame_->EmitPush(cp); |
| 2219 __ mov(r0, Operand(slot->var()->name())); | 2279 __ mov(r0, Operand(slot->var()->name())); |
| 2220 frame_->EmitPush(r0); | 2280 frame_->EmitPush(r0); |
| 2221 | 2281 |
| 2222 if (typeof_state == INSIDE_TYPEOF) { | 2282 if (typeof_state == INSIDE_TYPEOF) { |
| 2223 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2283 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 2224 } else { | 2284 } else { |
| 2225 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 2285 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2226 } | 2286 } |
| 2287 |
| 2288 done.Bind(); |
| 2227 frame_->EmitPush(r0); | 2289 frame_->EmitPush(r0); |
| 2228 | 2290 |
| 2229 } else { | 2291 } else { |
| 2230 // Note: We would like to keep the assert below, but it fires because of | 2292 // Note: We would like to keep the assert below, but it fires because of |
| 2231 // some nasty code in LoadTypeofExpression() which should be removed... | 2293 // some nasty code in LoadTypeofExpression() which should be removed... |
| 2232 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 2294 // ASSERT(!slot->var()->is_dynamic()); |
| 2233 | 2295 |
| 2234 // Special handling for locals allocated in registers. | 2296 // Special handling for locals allocated in registers. |
| 2235 __ ldr(r0, SlotOperand(slot, r2)); | 2297 __ ldr(r0, SlotOperand(slot, r2)); |
| 2236 frame_->EmitPush(r0); | 2298 frame_->EmitPush(r0); |
| 2237 if (slot->var()->mode() == Variable::CONST) { | 2299 if (slot->var()->mode() == Variable::CONST) { |
| 2238 // Const slots may contain 'the hole' value (the constant hasn't been | 2300 // Const slots may contain 'the hole' value (the constant hasn't been |
| 2239 // initialized yet) which needs to be converted into the 'undefined' | 2301 // initialized yet) which needs to be converted into the 'undefined' |
| 2240 // value. | 2302 // value. |
| 2241 Comment cmnt(masm_, "[ Unhole const"); | 2303 Comment cmnt(masm_, "[ Unhole const"); |
| 2242 frame_->EmitPop(r0); | 2304 frame_->EmitPop(r0); |
| 2243 __ cmp(r0, Operand(Factory::the_hole_value())); | 2305 __ cmp(r0, Operand(Factory::the_hole_value())); |
| 2244 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); | 2306 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); |
| 2245 frame_->EmitPush(r0); | 2307 frame_->EmitPush(r0); |
| 2246 } | 2308 } |
| 2247 } | 2309 } |
| 2248 } | 2310 } |
| 2249 | 2311 |
| 2250 | 2312 |
| 2313 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, |
| 2314 TypeofState typeof_state, |
| 2315 Register tmp, |
| 2316 Register tmp2, |
| 2317 JumpTarget* slow) { |
| 2318 // Check that no extension objects have been created by calls to |
| 2319 // eval from the current scope to the global scope. |
| 2320 Register context = cp; |
| 2321 for (Scope* s = scope(); s != NULL; s = s->outer_scope()) { |
| 2322 if (s->num_heap_slots() > 0) { |
| 2323 if (s->calls_eval()) { |
| 2324 // Check that extension is NULL. |
| 2325 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX)); |
| 2326 __ tst(tmp2, tmp2); |
| 2327 slow->Branch(ne); |
| 2328 } |
| 2329 // Load next context in chain. |
| 2330 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 2331 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); |
| 2332 context = tmp; |
| 2333 } |
| 2334 // If no outer scope calls eval, we do not need to check more |
| 2335 // context extensions. |
| 2336 if (!s->outer_scope_calls_eval()) break; |
| 2337 } |
| 2338 |
| 2339 // All extension objects were empty and it is safe to use a global |
| 2340 // load IC call. |
| 2341 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 2342 // Load the global object. |
| 2343 LoadGlobal(); |
| 2344 // Setup the name register. |
| 2345 Result name = allocator_->Allocate(r2); |
| 2346 ASSERT(name.is_valid()); // We are in spilled code. |
| 2347 __ mov(name.reg(), Operand(slot->var()->name())); |
| 2348 // Call IC stub. |
| 2349 if (typeof_state == INSIDE_TYPEOF) { |
| 2350 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, &name, 0); |
| 2351 } else { |
| 2352 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, &name, 0); |
| 2353 } |
| 2354 |
| 2355 // Drop the global object. The result is in r0. |
| 2356 frame_->Drop(); |
| 2357 } |
| 2358 |
| 2359 |
| 2251 void CodeGenerator::VisitSlot(Slot* node) { | 2360 void CodeGenerator::VisitSlot(Slot* node) { |
| 2252 VirtualFrame::SpilledScope spilled_scope(this); | 2361 VirtualFrame::SpilledScope spilled_scope(this); |
| 2253 Comment cmnt(masm_, "[ Slot"); | 2362 Comment cmnt(masm_, "[ Slot"); |
| 2254 LoadFromSlot(node, typeof_state()); | 2363 LoadFromSlot(node, typeof_state()); |
| 2255 } | 2364 } |
| 2256 | 2365 |
| 2257 | 2366 |
| 2258 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2367 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 2259 VirtualFrame::SpilledScope spilled_scope(this); | 2368 VirtualFrame::SpilledScope spilled_scope(this); |
| 2260 Comment cmnt(masm_, "[ VariableProxy"); | 2369 Comment cmnt(masm_, "[ VariableProxy"); |
| (...skipping 1426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3687 if (property != NULL) { | 3796 if (property != NULL) { |
| 3688 cgen_->CodeForSourcePosition(property->position()); | 3797 cgen_->CodeForSourcePosition(property->position()); |
| 3689 } | 3798 } |
| 3690 | 3799 |
| 3691 switch (type_) { | 3800 switch (type_) { |
| 3692 case SLOT: { | 3801 case SLOT: { |
| 3693 Comment cmnt(masm, "[ Store to Slot"); | 3802 Comment cmnt(masm, "[ Store to Slot"); |
| 3694 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 3803 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 3695 ASSERT(slot != NULL); | 3804 ASSERT(slot != NULL); |
| 3696 if (slot->type() == Slot::LOOKUP) { | 3805 if (slot->type() == Slot::LOOKUP) { |
| 3697 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 3806 ASSERT(slot->var()->is_dynamic()); |
| 3698 | 3807 |
| 3699 // For now, just do a runtime call. | 3808 // For now, just do a runtime call. |
| 3700 frame->EmitPush(cp); | 3809 frame->EmitPush(cp); |
| 3701 __ mov(r0, Operand(slot->var()->name())); | 3810 __ mov(r0, Operand(slot->var()->name())); |
| 3702 frame->EmitPush(r0); | 3811 frame->EmitPush(r0); |
| 3703 | 3812 |
| 3704 if (init_state == CONST_INIT) { | 3813 if (init_state == CONST_INIT) { |
| 3705 // Same as the case for a normal store, but ignores attribute | 3814 // Same as the case for a normal store, but ignores attribute |
| 3706 // (e.g. READ_ONLY) of context slot so that we can initialize | 3815 // (e.g. READ_ONLY) of context slot so that we can initialize |
| 3707 // const properties (introduced via eval("const foo = (some | 3816 // const properties (introduced via eval("const foo = (some |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3719 // context slot followed by initialization. | 3828 // context slot followed by initialization. |
| 3720 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 3829 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 3721 } else { | 3830 } else { |
| 3722 frame->CallRuntime(Runtime::kStoreContextSlot, 3); | 3831 frame->CallRuntime(Runtime::kStoreContextSlot, 3); |
| 3723 } | 3832 } |
| 3724 // Storing a variable must keep the (new) value on the expression | 3833 // Storing a variable must keep the (new) value on the expression |
| 3725 // stack. This is necessary for compiling assignment expressions. | 3834 // stack. This is necessary for compiling assignment expressions. |
| 3726 frame->EmitPush(r0); | 3835 frame->EmitPush(r0); |
| 3727 | 3836 |
| 3728 } else { | 3837 } else { |
| 3729 ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 3838 ASSERT(!slot->var()->is_dynamic()); |
| 3730 | 3839 |
| 3731 JumpTarget exit(cgen_); | 3840 JumpTarget exit(cgen_); |
| 3732 if (init_state == CONST_INIT) { | 3841 if (init_state == CONST_INIT) { |
| 3733 ASSERT(slot->var()->mode() == Variable::CONST); | 3842 ASSERT(slot->var()->mode() == Variable::CONST); |
| 3734 // Only the first const initialization must be executed (the slot | 3843 // Only the first const initialization must be executed (the slot |
| 3735 // still contains 'the hole' value). When the assignment is | 3844 // still contains 'the hole' value). When the assignment is |
| 3736 // executed, the code is identical to a normal store (see below). | 3845 // executed, the code is identical to a normal store (see below). |
| 3737 Comment cmnt(masm, "[ Init const"); | 3846 Comment cmnt(masm, "[ Init const"); |
| 3738 __ ldr(r2, cgen_->SlotOperand(slot, r2)); | 3847 __ ldr(r2, cgen_->SlotOperand(slot, r2)); |
| 3739 __ cmp(r2, Operand(Factory::the_hole_value())); | 3848 __ cmp(r2, Operand(Factory::the_hole_value())); |
| (...skipping 980 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4720 __ mov(r2, Operand(0)); | 4829 __ mov(r2, Operand(0)); |
| 4721 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); | 4830 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); |
| 4722 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), | 4831 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), |
| 4723 RelocInfo::CODE_TARGET); | 4832 RelocInfo::CODE_TARGET); |
| 4724 } | 4833 } |
| 4725 | 4834 |
| 4726 | 4835 |
| 4727 #undef __ | 4836 #undef __ |
| 4728 | 4837 |
| 4729 } } // namespace v8::internal | 4838 } } // namespace v8::internal |
| OLD | NEW |