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 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 return frame_->Parameter(index); | 415 return frame_->Parameter(index); |
416 | 416 |
417 case Slot::LOCAL: | 417 case Slot::LOCAL: |
418 return frame_->Local(index); | 418 return frame_->Local(index); |
419 | 419 |
420 case Slot::CONTEXT: { | 420 case Slot::CONTEXT: { |
421 // Follow the context chain if necessary. | 421 // Follow the context chain if necessary. |
422 ASSERT(!tmp.is(esi)); // do not overwrite context register | 422 ASSERT(!tmp.is(esi)); // do not overwrite context register |
423 Register context = esi; | 423 Register context = esi; |
424 int chain_length = scope()->ContextChainLength(slot->var()->scope()); | 424 int chain_length = scope()->ContextChainLength(slot->var()->scope()); |
425 for (int i = chain_length; i-- > 0;) { | 425 for (int i = 0; i < chain_length; i++) { |
426 // Load the closure. | 426 // Load the closure. |
427 // (All contexts, even 'with' contexts, have a closure, | 427 // (All contexts, even 'with' contexts, have a closure, |
428 // and it is the same for all contexts inside a function. | 428 // and it is the same for all contexts inside a function. |
429 // There is no need to go to the function context first.) | 429 // There is no need to go to the function context first.) |
430 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); | 430 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
431 // Load the function context (which is the incoming, outer context). | 431 // Load the function context (which is the incoming, outer context). |
432 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); | 432 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); |
433 context = tmp; | 433 context = tmp; |
434 } | 434 } |
435 // We may have a 'with' context now. Get the function context. | 435 // We may have a 'with' context now. Get the function context. |
436 // (In fact this mov may never be the needed, since the scope analysis | 436 // (In fact this mov may never be the needed, since the scope analysis |
437 // may not permit a direct context access in this case and thus we are | 437 // may not permit a direct context access in this case and thus we are |
438 // always at a function context. However it is safe to dereference be- | 438 // always at a function context. However it is safe to dereference be- |
439 // cause the function context of a function context is itself. Before | 439 // cause the function context of a function context is itself. Before |
440 // deleting this mov we should try to create a counter-example first, | 440 // deleting this mov we should try to create a counter-example first, |
441 // though...) | 441 // though...) |
442 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 442 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
443 return ContextOperand(tmp, index); | 443 return ContextOperand(tmp, index); |
444 } | 444 } |
445 | 445 |
446 default: | 446 default: |
447 UNREACHABLE(); | 447 UNREACHABLE(); |
448 return Operand(eax); | 448 return Operand(eax); |
449 } | 449 } |
450 } | 450 } |
451 | 451 |
452 | 452 |
| 453 Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, |
| 454 Register tmp, |
| 455 Label* slow) { |
| 456 ASSERT(slot->type() == Slot::CONTEXT); |
| 457 int index = slot->index(); |
| 458 __ mov(tmp, Operand(esi)); |
| 459 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { |
| 460 if (s->num_heap_slots() > 0) { |
| 461 if (s->calls_eval()) { |
| 462 // Check that extension is NULL. |
| 463 __ cmp(ContextOperand(tmp, Context::EXTENSION_INDEX), Immediate(0)); |
| 464 __ j(not_equal, slow, not_taken); |
| 465 } |
| 466 __ mov(tmp, ContextOperand(tmp, Context::CLOSURE_INDEX)); |
| 467 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); |
| 468 } |
| 469 } |
| 470 // Check that last extension is NULL. |
| 471 __ cmp(ContextOperand(tmp, Context::EXTENSION_INDEX), Immediate(0)); |
| 472 __ j(not_equal, slow, not_taken); |
| 473 __ mov(tmp, ContextOperand(tmp, Context::FCONTEXT_INDEX)); |
| 474 return ContextOperand(tmp, index); |
| 475 } |
| 476 |
| 477 |
| 478 |
453 // Loads a value on TOS. If it is a boolean value, the result may have been | 479 // Loads a value on TOS. If it is a boolean value, the result may have been |
454 // (partially) translated into branches, or it may have set the condition | 480 // (partially) translated into branches, or it may have set the condition |
455 // code register. If force_cc is set, the value is forced to set the | 481 // code register. If force_cc is set, the value is forced to set the |
456 // condition code register and no value is pushed. If the condition code | 482 // condition code register and no value is pushed. If the condition code |
457 // register was set, has_cc() is true and cc_reg_ contains the condition to | 483 // register was set, has_cc() is true and cc_reg_ contains the condition to |
458 // test for 'true'. | 484 // test for 'true'. |
459 void CodeGenerator::LoadCondition(Expression* x, | 485 void CodeGenerator::LoadCondition(Expression* x, |
460 TypeofState typeof_state, | 486 TypeofState typeof_state, |
461 Label* true_target, | 487 Label* true_target, |
462 Label* false_target, | 488 Label* false_target, |
(...skipping 934 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1397 Variable* var = node->proxy()->var(); | 1423 Variable* var = node->proxy()->var(); |
1398 ASSERT(var != NULL); // must have been resolved | 1424 ASSERT(var != NULL); // must have been resolved |
1399 Slot* slot = var->slot(); | 1425 Slot* slot = var->slot(); |
1400 | 1426 |
1401 // If it was not possible to allocate the variable at compile time, | 1427 // If it was not possible to allocate the variable at compile time, |
1402 // we need to "declare" it at runtime to make sure it actually | 1428 // we need to "declare" it at runtime to make sure it actually |
1403 // exists in the local context. | 1429 // exists in the local context. |
1404 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1430 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
1405 // Variables with a "LOOKUP" slot were introduced as non-locals | 1431 // Variables with a "LOOKUP" slot were introduced as non-locals |
1406 // during variable resolution and must have mode DYNAMIC. | 1432 // during variable resolution and must have mode DYNAMIC. |
1407 ASSERT(var->mode() == Variable::DYNAMIC); | 1433 ASSERT(var->is_dynamic()); |
1408 // For now, just do a runtime call. | 1434 // For now, just do a runtime call. |
1409 frame_->Push(esi); | 1435 frame_->Push(esi); |
1410 frame_->Push(Immediate(var->name())); | 1436 frame_->Push(Immediate(var->name())); |
1411 // Declaration nodes are always introduced in one of two modes. | 1437 // Declaration nodes are always introduced in one of two modes. |
1412 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); | 1438 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
1413 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; | 1439 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
1414 frame_->Push(Immediate(Smi::FromInt(attr))); | 1440 frame_->Push(Immediate(Smi::FromInt(attr))); |
1415 // Push initial value, if any. | 1441 // Push initial value, if any. |
1416 // Note: For variables we must not push an initial value (such as | 1442 // Note: For variables we must not push an initial value (such as |
1417 // 'undefined') because we may have a (legal) redeclaration and we | 1443 // 'undefined') because we may have a (legal) redeclaration and we |
(...skipping 898 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2316 Load(node->then_expression(), typeof_state()); | 2342 Load(node->then_expression(), typeof_state()); |
2317 __ jmp(&exit); | 2343 __ jmp(&exit); |
2318 __ bind(&else_); | 2344 __ bind(&else_); |
2319 Load(node->else_expression(), typeof_state()); | 2345 Load(node->else_expression(), typeof_state()); |
2320 __ bind(&exit); | 2346 __ bind(&exit); |
2321 } | 2347 } |
2322 | 2348 |
2323 | 2349 |
2324 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2350 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
2325 if (slot->type() == Slot::LOOKUP) { | 2351 if (slot->type() == Slot::LOOKUP) { |
2326 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2352 ASSERT(slot->var()->is_dynamic()); |
2327 | 2353 |
2328 // For now, just do a runtime call. | 2354 Label slow, done; |
| 2355 |
| 2356 // Generate fast-case code for variables that might be shadowed by |
| 2357 // eval-introduced variables. Eval is used a lot without |
| 2358 // introducing variables. In those cases, we do not want to |
| 2359 // perform a runtime call for all variables in the scope |
| 2360 // containing the eval. |
| 2361 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { |
| 2362 LoadFromGlobalSlotCheckExtensions(slot, typeof_state, ebx, &slow); |
| 2363 __ jmp(&done); |
| 2364 |
| 2365 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { |
| 2366 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot(); |
| 2367 __ mov(eax, |
| 2368 ContextSlotOperandCheckExtensions(potential_slot, |
| 2369 ebx, |
| 2370 &slow)); |
| 2371 __ jmp(&done); |
| 2372 } |
| 2373 |
| 2374 __ bind(&slow); |
2329 frame_->Push(esi); | 2375 frame_->Push(esi); |
2330 frame_->Push(Immediate(slot->var()->name())); | 2376 frame_->Push(Immediate(slot->var()->name())); |
2331 | |
2332 if (typeof_state == INSIDE_TYPEOF) { | 2377 if (typeof_state == INSIDE_TYPEOF) { |
2333 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2378 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
2334 } else { | 2379 } else { |
2335 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2380 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
2336 } | 2381 } |
| 2382 |
| 2383 __ bind(&done); |
2337 frame_->Push(eax); | 2384 frame_->Push(eax); |
2338 | 2385 |
2339 } else { | 2386 } else { |
2340 // Note: We would like to keep the assert below, but it fires because of | 2387 // Note: We would like to keep the assert below, but it fires because of |
2341 // some nasty code in LoadTypeofExpression() which should be removed... | 2388 // some nasty code in LoadTypeofExpression() which should be removed... |
2342 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 2389 // ASSERT(!slot->var()->is_dynamic()); |
2343 if (slot->var()->mode() == Variable::CONST) { | 2390 if (slot->var()->mode() == Variable::CONST) { |
2344 // Const slots may contain 'the hole' value (the constant hasn't been | 2391 // Const slots may contain 'the hole' value (the constant hasn't been |
2345 // initialized yet) which needs to be converted into the 'undefined' | 2392 // initialized yet) which needs to be converted into the 'undefined' |
2346 // value. | 2393 // value. |
2347 Comment cmnt(masm_, "[ Load const"); | 2394 Comment cmnt(masm_, "[ Load const"); |
2348 Label exit; | 2395 Label exit; |
2349 __ mov(eax, SlotOperand(slot, ecx)); | 2396 __ mov(eax, SlotOperand(slot, ecx)); |
2350 __ cmp(eax, Factory::the_hole_value()); | 2397 __ cmp(eax, Factory::the_hole_value()); |
2351 __ j(not_equal, &exit); | 2398 __ j(not_equal, &exit); |
2352 __ mov(eax, Factory::undefined_value()); | 2399 __ mov(eax, Factory::undefined_value()); |
2353 __ bind(&exit); | 2400 __ bind(&exit); |
2354 frame_->Push(eax); | 2401 frame_->Push(eax); |
2355 } else { | 2402 } else { |
2356 frame_->Push(SlotOperand(slot, ecx)); | 2403 frame_->Push(SlotOperand(slot, ecx)); |
2357 } | 2404 } |
2358 } | 2405 } |
2359 } | 2406 } |
2360 | 2407 |
2361 | 2408 |
| 2409 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, |
| 2410 TypeofState typeof_state, |
| 2411 Register tmp, |
| 2412 Label* slow) { |
| 2413 // Check that no extension objects have been created by calls to |
| 2414 // eval from the current scope to the global scope. |
| 2415 __ mov(tmp, Operand(esi)); |
| 2416 for (Scope* s = scope(); s != NULL; s = s->outer_scope()) { |
| 2417 if (s->num_heap_slots() > 0) { |
| 2418 if (s->calls_eval()) { |
| 2419 // Check that extension is NULL. |
| 2420 __ cmp(ContextOperand(tmp, Context::EXTENSION_INDEX), Immediate(0)); |
| 2421 __ j(not_equal, slow, not_taken); |
| 2422 } |
| 2423 // Load next context in chain. |
| 2424 __ mov(tmp, ContextOperand(tmp, Context::CLOSURE_INDEX)); |
| 2425 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); |
| 2426 } |
| 2427 // If no outer scope calls eval, we do not need to check more |
| 2428 // context extensions. |
| 2429 if (!s->outer_scope_calls_eval()) break; |
| 2430 } |
| 2431 |
| 2432 // All extension objects were empty and it is safe to use a global |
| 2433 // load IC call. |
| 2434 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 2435 // Load the global object. |
| 2436 LoadGlobal(); |
| 2437 // Setup the name register. |
| 2438 __ mov(ecx, slot->var()->name()); |
| 2439 // Call IC stub. |
| 2440 if (typeof_state == INSIDE_TYPEOF) { |
| 2441 __ call(ic, RelocInfo::CODE_TARGET); |
| 2442 } else { |
| 2443 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 2444 } |
| 2445 |
| 2446 // Pop the global object. The result is in eax. |
| 2447 frame_->Pop(); |
| 2448 } |
| 2449 |
| 2450 |
2362 void CodeGenerator::VisitSlot(Slot* node) { | 2451 void CodeGenerator::VisitSlot(Slot* node) { |
2363 Comment cmnt(masm_, "[ Slot"); | 2452 Comment cmnt(masm_, "[ Slot"); |
2364 LoadFromSlot(node, typeof_state()); | 2453 LoadFromSlot(node, typeof_state()); |
2365 } | 2454 } |
2366 | 2455 |
2367 | 2456 |
2368 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2457 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
2369 Comment cmnt(masm_, "[ VariableProxy"); | 2458 Comment cmnt(masm_, "[ VariableProxy"); |
2370 Variable* var = node->var(); | 2459 Variable* var = node->var(); |
2371 Expression* expr = var->rewrite(); | 2460 Expression* expr = var->rewrite(); |
(...skipping 1634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4006 ASSERT(!is_illegal()); | 4095 ASSERT(!is_illegal()); |
4007 ASSERT(!cgen_->has_cc()); | 4096 ASSERT(!cgen_->has_cc()); |
4008 MacroAssembler* masm = cgen_->masm(); | 4097 MacroAssembler* masm = cgen_->masm(); |
4009 VirtualFrame* frame = cgen_->frame(); | 4098 VirtualFrame* frame = cgen_->frame(); |
4010 switch (type_) { | 4099 switch (type_) { |
4011 case SLOT: { | 4100 case SLOT: { |
4012 Comment cmnt(masm, "[ Store to Slot"); | 4101 Comment cmnt(masm, "[ Store to Slot"); |
4013 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4102 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
4014 ASSERT(slot != NULL); | 4103 ASSERT(slot != NULL); |
4015 if (slot->type() == Slot::LOOKUP) { | 4104 if (slot->type() == Slot::LOOKUP) { |
4016 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 4105 ASSERT(slot->var()->is_dynamic()); |
4017 | 4106 |
4018 // For now, just do a runtime call. | 4107 // For now, just do a runtime call. |
4019 frame->Push(esi); | 4108 frame->Push(esi); |
4020 frame->Push(Immediate(slot->var()->name())); | 4109 frame->Push(Immediate(slot->var()->name())); |
4021 | 4110 |
4022 if (init_state == CONST_INIT) { | 4111 if (init_state == CONST_INIT) { |
4023 // Same as the case for a normal store, but ignores attribute | 4112 // Same as the case for a normal store, but ignores attribute |
4024 // (e.g. READ_ONLY) of context slot so that we can initialize | 4113 // (e.g. READ_ONLY) of context slot so that we can initialize |
4025 // const properties (introduced via eval("const foo = (some | 4114 // const properties (introduced via eval("const foo = (some |
4026 // expr);")). Also, uses the current function context instead of | 4115 // expr);")). Also, uses the current function context instead of |
(...skipping 11 matching lines...) Expand all Loading... |
4038 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 4127 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
4039 } else { | 4128 } else { |
4040 __ CallRuntime(Runtime::kStoreContextSlot, 3); | 4129 __ CallRuntime(Runtime::kStoreContextSlot, 3); |
4041 } | 4130 } |
4042 // Storing a variable must keep the (new) value on the expression | 4131 // Storing a variable must keep the (new) value on the expression |
4043 // stack. This is necessary for compiling chained assignment | 4132 // stack. This is necessary for compiling chained assignment |
4044 // expressions. | 4133 // expressions. |
4045 frame->Push(eax); | 4134 frame->Push(eax); |
4046 | 4135 |
4047 } else { | 4136 } else { |
4048 ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 4137 ASSERT(!slot->var()->is_dynamic()); |
4049 | 4138 |
4050 Label exit; | 4139 Label exit; |
4051 if (init_state == CONST_INIT) { | 4140 if (init_state == CONST_INIT) { |
4052 ASSERT(slot->var()->mode() == Variable::CONST); | 4141 ASSERT(slot->var()->mode() == Variable::CONST); |
4053 // Only the first const initialization must be executed (the slot | 4142 // Only the first const initialization must be executed (the slot |
4054 // still contains 'the hole' value). When the assignment is | 4143 // still contains 'the hole' value). When the assignment is |
4055 // executed, the code is identical to a normal store (see below). | 4144 // executed, the code is identical to a normal store (see below). |
4056 Comment cmnt(masm, "[ Init const"); | 4145 Comment cmnt(masm, "[ Init const"); |
4057 __ mov(eax, cgen_->SlotOperand(slot, ecx)); | 4146 __ mov(eax, cgen_->SlotOperand(slot, ecx)); |
4058 __ cmp(eax, Factory::the_hole_value()); | 4147 __ cmp(eax, Factory::the_hole_value()); |
(...skipping 1272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5331 | 5420 |
5332 // Slow-case: Go through the JavaScript implementation. | 5421 // Slow-case: Go through the JavaScript implementation. |
5333 __ bind(&slow); | 5422 __ bind(&slow); |
5334 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5423 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
5335 } | 5424 } |
5336 | 5425 |
5337 | 5426 |
5338 #undef __ | 5427 #undef __ |
5339 | 5428 |
5340 } } // namespace v8::internal | 5429 } } // namespace v8::internal |
OLD | NEW |