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 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 return Operand(eax); | 383 return Operand(eax); |
384 } | 384 } |
385 } | 385 } |
386 | 386 |
387 | 387 |
388 Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, | 388 Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, |
389 Result tmp, | 389 Result tmp, |
390 JumpTarget* slow) { | 390 JumpTarget* slow) { |
391 ASSERT(slot->type() == Slot::CONTEXT); | 391 ASSERT(slot->type() == Slot::CONTEXT); |
392 ASSERT(tmp.is_register()); | 392 ASSERT(tmp.is_register()); |
393 Result context(esi); | 393 Register context = esi; |
394 | 394 |
395 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { | 395 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { |
396 if (s->num_heap_slots() > 0) { | 396 if (s->num_heap_slots() > 0) { |
397 if (s->calls_eval()) { | 397 if (s->calls_eval()) { |
398 // Check that extension is NULL. | 398 // Check that extension is NULL. |
399 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX), | 399 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), |
400 Immediate(0)); | 400 Immediate(0)); |
401 slow->Branch(not_equal, not_taken); | 401 slow->Branch(not_equal, not_taken); |
402 } | 402 } |
403 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::CLOSURE_INDEX)); | 403 __ mov(tmp.reg(), ContextOperand(context, Context::CLOSURE_INDEX)); |
404 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); | 404 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); |
405 context = tmp; | 405 context = tmp.reg(); |
406 } | 406 } |
407 } | 407 } |
408 // Check that last extension is NULL. | 408 // Check that last extension is NULL. |
409 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX), | 409 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); |
410 Immediate(0)); | |
411 slow->Branch(not_equal, not_taken); | 410 slow->Branch(not_equal, not_taken); |
412 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::FCONTEXT_INDEX)); | 411 __ mov(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX)); |
413 return ContextOperand(tmp.reg(), slot->index()); | 412 return ContextOperand(tmp.reg(), slot->index()); |
414 } | 413 } |
415 | 414 |
416 | 415 |
417 // Emit code to load the value of an expression to the top of the | 416 // Emit code to load the value of an expression to the top of the |
418 // frame. If the expression is boolean-valued it may be compiled (or | 417 // frame. If the expression is boolean-valued it may be compiled (or |
419 // partially compiled) into control flow to the control destination. | 418 // partially compiled) into control flow to the control destination. |
420 // If force_control is true, control flow is forced. | 419 // If force_control is true, control flow is forced. |
421 void CodeGenerator::LoadCondition(Expression* x, | 420 void CodeGenerator::LoadCondition(Expression* x, |
422 TypeofState typeof_state, | 421 TypeofState typeof_state, |
(...skipping 1342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1765 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | 1764 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
1766 VisitStatements(node->statements()); | 1765 VisitStatements(node->statements()); |
1767 if (node->break_target()->is_linked()) { | 1766 if (node->break_target()->is_linked()) { |
1768 node->break_target()->Bind(); | 1767 node->break_target()->Bind(); |
1769 } | 1768 } |
1770 node->break_target()->Unuse(); | 1769 node->break_target()->Unuse(); |
1771 } | 1770 } |
1772 | 1771 |
1773 | 1772 |
1774 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1773 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
1775 frame_->Push(pairs); | 1774 // Call the runtime to declare the globals. The inevitable call |
| 1775 // will sync frame elements to memory anyway, so we do it eagerly to |
| 1776 // allow us to push the arguments directly into place. |
| 1777 frame_->SyncRange(0, frame_->element_count() - 1); |
1776 | 1778 |
1777 // Duplicate the context register. | 1779 frame_->EmitPush(Immediate(pairs)); |
1778 Result context(esi); | 1780 frame_->EmitPush(esi); // The context is the second argument. |
1779 frame_->Push(&context); | 1781 frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
1780 | |
1781 frame_->Push(Smi::FromInt(is_eval() ? 1 : 0)); | |
1782 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 1782 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
1783 // Return value is ignored. | 1783 // Return value is ignored. |
1784 } | 1784 } |
1785 | 1785 |
1786 | 1786 |
1787 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1787 void CodeGenerator::VisitDeclaration(Declaration* node) { |
1788 Comment cmnt(masm_, "[ Declaration"); | 1788 Comment cmnt(masm_, "[ Declaration"); |
1789 CodeForStatementPosition(node); | 1789 CodeForStatementPosition(node); |
1790 Variable* var = node->proxy()->var(); | 1790 Variable* var = node->proxy()->var(); |
1791 ASSERT(var != NULL); // must have been resolved | 1791 ASSERT(var != NULL); // must have been resolved |
1792 Slot* slot = var->slot(); | 1792 Slot* slot = var->slot(); |
1793 | 1793 |
1794 // If it was not possible to allocate the variable at compile time, | 1794 // If it was not possible to allocate the variable at compile time, |
1795 // we need to "declare" it at runtime to make sure it actually | 1795 // we need to "declare" it at runtime to make sure it actually |
1796 // exists in the local context. | 1796 // exists in the local context. |
1797 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1797 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
1798 // Variables with a "LOOKUP" slot were introduced as non-locals | 1798 // Variables with a "LOOKUP" slot were introduced as non-locals |
1799 // during variable resolution and must have mode DYNAMIC. | 1799 // during variable resolution and must have mode DYNAMIC. |
1800 ASSERT(var->is_dynamic()); | 1800 ASSERT(var->is_dynamic()); |
1801 // For now, just do a runtime call. Duplicate the context register. | 1801 // For now, just do a runtime call. Sync the virtual frame eagerly |
1802 Result context(esi); | 1802 // so we can simply push the arguments into place. |
1803 frame_->Push(&context); | 1803 frame_->SyncRange(0, frame_->element_count() - 1); |
1804 frame_->Push(var->name()); | 1804 frame_->EmitPush(esi); |
| 1805 frame_->EmitPush(Immediate(var->name())); |
1805 // Declaration nodes are always introduced in one of two modes. | 1806 // Declaration nodes are always introduced in one of two modes. |
1806 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); | 1807 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
1807 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; | 1808 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
1808 frame_->Push(Smi::FromInt(attr)); | 1809 frame_->EmitPush(Immediate(Smi::FromInt(attr))); |
1809 // Push initial value, if any. | 1810 // Push initial value, if any. |
1810 // Note: For variables we must not push an initial value (such as | 1811 // Note: For variables we must not push an initial value (such as |
1811 // 'undefined') because we may have a (legal) redeclaration and we | 1812 // 'undefined') because we may have a (legal) redeclaration and we |
1812 // must not destroy the current value. | 1813 // must not destroy the current value. |
1813 if (node->mode() == Variable::CONST) { | 1814 if (node->mode() == Variable::CONST) { |
1814 frame_->Push(Factory::the_hole_value()); | 1815 frame_->EmitPush(Immediate(Factory::the_hole_value())); |
1815 } else if (node->fun() != NULL) { | 1816 } else if (node->fun() != NULL) { |
1816 Load(node->fun()); | 1817 Load(node->fun()); |
1817 } else { | 1818 } else { |
1818 frame_->Push(Smi::FromInt(0)); // no initial value! | 1819 frame_->EmitPush(Immediate(Smi::FromInt(0))); // no initial value! |
1819 } | 1820 } |
1820 Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); | 1821 Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); |
1821 // Ignore the return value (declarations are statements). | 1822 // Ignore the return value (declarations are statements). |
1822 return; | 1823 return; |
1823 } | 1824 } |
1824 | 1825 |
1825 ASSERT(!var->is_global()); | 1826 ASSERT(!var->is_global()); |
1826 | 1827 |
1827 // If we have a function or a constant, we need to initialize the variable. | 1828 // If we have a function or a constant, we need to initialize the variable. |
1828 Expression* val = NULL; | 1829 Expression* val = NULL; |
(...skipping 1353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3182 #ifdef ENABLE_DEBUGGER_SUPPORT | 3183 #ifdef ENABLE_DEBUGGER_SUPPORT |
3183 // Spill everything, even constants, to the frame. | 3184 // Spill everything, even constants, to the frame. |
3184 frame_->SpillAll(); | 3185 frame_->SpillAll(); |
3185 frame_->CallRuntime(Runtime::kDebugBreak, 0); | 3186 frame_->CallRuntime(Runtime::kDebugBreak, 0); |
3186 // Ignore the return value. | 3187 // Ignore the return value. |
3187 #endif | 3188 #endif |
3188 } | 3189 } |
3189 | 3190 |
3190 | 3191 |
3191 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 3192 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 3193 // Call the runtime to instantiate the function boilerplate object. |
| 3194 // The inevitable call will sync frame elements to memory anyway, so |
| 3195 // we do it eagerly to allow us to push the arguments directly into |
| 3196 // place. |
3192 ASSERT(boilerplate->IsBoilerplate()); | 3197 ASSERT(boilerplate->IsBoilerplate()); |
| 3198 frame_->SyncRange(0, frame_->element_count() - 1); |
3193 | 3199 |
3194 // Push the boilerplate on the stack. | 3200 // Push the boilerplate on the stack. |
3195 frame_->Push(boilerplate); | 3201 frame_->EmitPush(Immediate(boilerplate)); |
3196 | 3202 |
3197 // Create a new closure. | 3203 // Create a new closure. |
3198 frame_->Push(esi); | 3204 frame_->EmitPush(esi); |
3199 Result result = frame_->CallRuntime(Runtime::kNewClosure, 2); | 3205 Result result = frame_->CallRuntime(Runtime::kNewClosure, 2); |
3200 frame_->Push(&result); | 3206 frame_->Push(&result); |
3201 } | 3207 } |
3202 | 3208 |
3203 | 3209 |
3204 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 3210 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
3205 Comment cmnt(masm_, "[ FunctionLiteral"); | 3211 Comment cmnt(masm_, "[ FunctionLiteral"); |
3206 | 3212 |
3207 // Build the function boilerplate and instantiate it. | 3213 // Build the function boilerplate and instantiate it. |
3208 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 3214 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3294 __ mov(value.reg(), Factory::undefined_value()); | 3300 __ mov(value.reg(), Factory::undefined_value()); |
3295 } | 3301 } |
3296 // There is always control flow to slow from | 3302 // There is always control flow to slow from |
3297 // ContextSlotOperandCheckExtensions so we have to jump around | 3303 // ContextSlotOperandCheckExtensions so we have to jump around |
3298 // it. | 3304 // it. |
3299 done.Jump(&value); | 3305 done.Jump(&value); |
3300 } | 3306 } |
3301 } | 3307 } |
3302 | 3308 |
3303 slow.Bind(); | 3309 slow.Bind(); |
3304 frame_->Push(esi); | 3310 // A runtime call is inevitable. We eagerly sync frame elements |
3305 frame_->Push(slot->var()->name()); | 3311 // to memory so that we can push the arguments directly into place |
| 3312 // on top of the frame. |
| 3313 frame_->SyncRange(0, frame_->element_count() - 1); |
| 3314 frame_->EmitPush(esi); |
| 3315 frame_->EmitPush(Immediate(slot->var()->name())); |
3306 if (typeof_state == INSIDE_TYPEOF) { | 3316 if (typeof_state == INSIDE_TYPEOF) { |
3307 value = | 3317 value = |
3308 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3318 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
3309 } else { | 3319 } else { |
3310 value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 3320 value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
3311 } | 3321 } |
3312 | 3322 |
3313 done.Bind(&value); | 3323 done.Bind(&value); |
3314 frame_->Push(&value); | 3324 frame_->Push(&value); |
3315 | 3325 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3350 } | 3360 } |
3351 } | 3361 } |
3352 | 3362 |
3353 | 3363 |
3354 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( | 3364 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( |
3355 Slot* slot, | 3365 Slot* slot, |
3356 TypeofState typeof_state, | 3366 TypeofState typeof_state, |
3357 JumpTarget* slow) { | 3367 JumpTarget* slow) { |
3358 // Check that no extension objects have been created by calls to | 3368 // Check that no extension objects have been created by calls to |
3359 // eval from the current scope to the global scope. | 3369 // eval from the current scope to the global scope. |
3360 Result context(esi); | 3370 Register context = esi; |
3361 Result tmp = allocator_->Allocate(); | 3371 Result tmp = allocator_->Allocate(); |
3362 ASSERT(tmp.is_valid()); // All non-reserved registers were available. | 3372 ASSERT(tmp.is_valid()); // All non-reserved registers were available. |
3363 | 3373 |
3364 Scope* s = scope(); | 3374 Scope* s = scope(); |
3365 while (s != NULL) { | 3375 while (s != NULL) { |
3366 if (s->num_heap_slots() > 0) { | 3376 if (s->num_heap_slots() > 0) { |
3367 if (s->calls_eval()) { | 3377 if (s->calls_eval()) { |
3368 // Check that extension is NULL. | 3378 // Check that extension is NULL. |
3369 __ cmp(ContextOperand(context.reg(), Context::EXTENSION_INDEX), | 3379 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), |
3370 Immediate(0)); | 3380 Immediate(0)); |
3371 slow->Branch(not_equal, not_taken); | 3381 slow->Branch(not_equal, not_taken); |
3372 } | 3382 } |
3373 // Load next context in chain. | 3383 // Load next context in chain. |
3374 __ mov(tmp.reg(), ContextOperand(context.reg(), Context::CLOSURE_INDEX)); | 3384 __ mov(tmp.reg(), ContextOperand(context, Context::CLOSURE_INDEX)); |
3375 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); | 3385 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); |
3376 context = tmp; | 3386 context = tmp.reg(); |
3377 } | 3387 } |
3378 // If no outer scope calls eval, we do not need to check more | 3388 // If no outer scope calls eval, we do not need to check more |
3379 // context extensions. If we have reached an eval scope, we check | 3389 // context extensions. If we have reached an eval scope, we check |
3380 // all extensions from this point. | 3390 // all extensions from this point. |
3381 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; | 3391 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; |
3382 s = s->outer_scope(); | 3392 s = s->outer_scope(); |
3383 } | 3393 } |
3384 | 3394 |
3385 if (s->is_eval_scope()) { | 3395 if (s->is_eval_scope()) { |
3386 // Loop up the context chain. There is no frame effect so it is | 3396 // Loop up the context chain. There is no frame effect so it is |
3387 // safe to use raw labels here. | 3397 // safe to use raw labels here. |
3388 Label next, fast; | 3398 Label next, fast; |
3389 if (!context.reg().is(tmp.reg())) { | 3399 if (!context.is(tmp.reg())) { |
3390 __ mov(tmp.reg(), context.reg()); | 3400 __ mov(tmp.reg(), context); |
3391 } | 3401 } |
3392 __ bind(&next); | 3402 __ bind(&next); |
3393 // Terminate at global context. | 3403 // Terminate at global context. |
3394 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), | 3404 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), |
3395 Immediate(Factory::global_context_map())); | 3405 Immediate(Factory::global_context_map())); |
3396 __ j(equal, &fast); | 3406 __ j(equal, &fast); |
3397 // Check that extension is NULL. | 3407 // Check that extension is NULL. |
3398 __ cmp(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0)); | 3408 __ cmp(ContextOperand(tmp.reg(), Context::EXTENSION_INDEX), Immediate(0)); |
3399 slow->Branch(not_equal, not_taken); | 3409 slow->Branch(not_equal, not_taken); |
3400 // Load next context in chain. | 3410 // Load next context in chain. |
3401 __ mov(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX)); | 3411 __ mov(tmp.reg(), ContextOperand(tmp.reg(), Context::CLOSURE_INDEX)); |
3402 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); | 3412 __ mov(tmp.reg(), FieldOperand(tmp.reg(), JSFunction::kContextOffset)); |
3403 __ jmp(&next); | 3413 __ jmp(&next); |
3404 __ bind(&fast); | 3414 __ bind(&fast); |
3405 } | 3415 } |
3406 context.Unuse(); | |
3407 tmp.Unuse(); | 3416 tmp.Unuse(); |
3408 | 3417 |
3409 // All extension objects were empty and it is safe to use a global | 3418 // All extension objects were empty and it is safe to use a global |
3410 // load IC call. | 3419 // load IC call. |
3411 LoadGlobal(); | 3420 LoadGlobal(); |
3412 frame_->Push(slot->var()->name()); | 3421 frame_->Push(slot->var()->name()); |
3413 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 3422 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
3414 ? RelocInfo::CODE_TARGET | 3423 ? RelocInfo::CODE_TARGET |
3415 : RelocInfo::CODE_TARGET_CONTEXT; | 3424 : RelocInfo::CODE_TARGET_CONTEXT; |
3416 Result answer = frame_->CallLoadIC(mode); | 3425 Result answer = frame_->CallLoadIC(mode); |
3417 // A test eax instruction following the call signals that the inobject | 3426 // A test eax instruction following the call signals that the inobject |
3418 // property case was inlined. Ensure that there is not a test eax | 3427 // property case was inlined. Ensure that there is not a test eax |
3419 // instruction here. | 3428 // instruction here. |
3420 __ nop(); | 3429 __ nop(); |
3421 // Discard the global object. The result is in answer. | 3430 // Discard the global object. The result is in answer. |
3422 frame_->Drop(); | 3431 frame_->Drop(); |
3423 return answer; | 3432 return answer; |
3424 } | 3433 } |
3425 | 3434 |
3426 | 3435 |
3427 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | 3436 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
3428 if (slot->type() == Slot::LOOKUP) { | 3437 if (slot->type() == Slot::LOOKUP) { |
3429 ASSERT(slot->var()->is_dynamic()); | 3438 ASSERT(slot->var()->is_dynamic()); |
3430 | 3439 |
3431 // For now, just do a runtime call. | 3440 // For now, just do a runtime call. Since the call is inevitable, |
3432 frame_->Push(esi); | 3441 // we eagerly sync the virtual frame so we can directly push the |
3433 frame_->Push(slot->var()->name()); | 3442 // arguments into place. |
| 3443 frame_->SyncRange(0, frame_->element_count() - 1); |
| 3444 |
| 3445 frame_->EmitPush(esi); |
| 3446 frame_->EmitPush(Immediate(slot->var()->name())); |
3434 | 3447 |
3435 Result value; | 3448 Result value; |
3436 if (init_state == CONST_INIT) { | 3449 if (init_state == CONST_INIT) { |
3437 // Same as the case for a normal store, but ignores attribute | 3450 // Same as the case for a normal store, but ignores attribute |
3438 // (e.g. READ_ONLY) of context slot so that we can initialize const | 3451 // (e.g. READ_ONLY) of context slot so that we can initialize const |
3439 // properties (introduced via eval("const foo = (some expr);")). Also, | 3452 // properties (introduced via eval("const foo = (some expr);")). Also, |
3440 // uses the current function context instead of the top context. | 3453 // uses the current function context instead of the top context. |
3441 // | 3454 // |
3442 // Note that we must declare the foo upon entry of eval(), via a | 3455 // Note that we must declare the foo upon entry of eval(), via a |
3443 // context slot declaration, but we cannot initialize it at the same | 3456 // context slot declaration, but we cannot initialize it at the same |
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4054 frame_->RestoreContextRegister(); | 4067 frame_->RestoreContextRegister(); |
4055 // Replace the function on the stack with the result. | 4068 // Replace the function on the stack with the result. |
4056 frame_->SetElementAt(0, &result); | 4069 frame_->SetElementAt(0, &result); |
4057 | 4070 |
4058 } else if (var != NULL && var->slot() != NULL && | 4071 } else if (var != NULL && var->slot() != NULL && |
4059 var->slot()->type() == Slot::LOOKUP) { | 4072 var->slot()->type() == Slot::LOOKUP) { |
4060 // ---------------------------------- | 4073 // ---------------------------------- |
4061 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj | 4074 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj |
4062 // ---------------------------------- | 4075 // ---------------------------------- |
4063 | 4076 |
4064 // Load the function | 4077 // Load the function from the context. Sync the frame so we can |
4065 frame_->Push(esi); | 4078 // push the arguments directly into place. |
4066 frame_->Push(var->name()); | 4079 frame_->SyncRange(0, frame_->element_count() - 1); |
| 4080 frame_->EmitPush(esi); |
| 4081 frame_->EmitPush(Immediate(var->name())); |
4067 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 4082 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
4068 // eax: slot value; edx: receiver | 4083 // The runtime call returns a pair of values in eax and edx. The |
| 4084 // looked-up function is in eax and the receiver is in edx. These |
| 4085 // register references are not ref counted here. We spill them |
| 4086 // eagerly since they are arguments to an inevitable call (and are |
| 4087 // not sharable by the arguments). |
| 4088 ASSERT(!allocator()->is_used(eax)); |
| 4089 frame_->EmitPush(eax); |
4069 | 4090 |
4070 // Load the receiver. | 4091 // Load the receiver. |
4071 frame_->Push(eax); | 4092 ASSERT(!allocator()->is_used(edx)); |
4072 frame_->Push(edx); | 4093 frame_->EmitPush(edx); |
4073 | 4094 |
4074 // Call the function. | 4095 // Call the function. |
4075 CallWithArguments(args, node->position()); | 4096 CallWithArguments(args, node->position()); |
4076 | 4097 |
4077 } else if (property != NULL) { | 4098 } else if (property != NULL) { |
4078 // Check if the key is a literal string. | 4099 // Check if the key is a literal string. |
4079 Literal* literal = property->key()->AsLiteral(); | 4100 Literal* literal = property->key()->AsLiteral(); |
4080 | 4101 |
4081 if (literal != NULL && literal->handle()->IsSymbol()) { | 4102 if (literal != NULL && literal->handle()->IsSymbol()) { |
4082 // ------------------------------------------------------------------ | 4103 // ------------------------------------------------------------------ |
(...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4631 Slot* slot = variable->slot(); | 4652 Slot* slot = variable->slot(); |
4632 if (variable->is_global()) { | 4653 if (variable->is_global()) { |
4633 LoadGlobal(); | 4654 LoadGlobal(); |
4634 frame_->Push(variable->name()); | 4655 frame_->Push(variable->name()); |
4635 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, | 4656 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, |
4636 CALL_FUNCTION, 2); | 4657 CALL_FUNCTION, 2); |
4637 frame_->Push(&answer); | 4658 frame_->Push(&answer); |
4638 return; | 4659 return; |
4639 | 4660 |
4640 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 4661 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
4641 // lookup the context holding the named variable | 4662 // Call the runtime to look up the context holding the named |
4642 frame_->Push(esi); | 4663 // variable. Sync the virtual frame eagerly so we can push the |
4643 frame_->Push(variable->name()); | 4664 // arguments directly into place. |
| 4665 frame_->SyncRange(0, frame_->element_count() - 1); |
| 4666 frame_->EmitPush(esi); |
| 4667 frame_->EmitPush(Immediate(variable->name())); |
4644 Result context = frame_->CallRuntime(Runtime::kLookupContext, 2); | 4668 Result context = frame_->CallRuntime(Runtime::kLookupContext, 2); |
4645 frame_->Push(&context); | 4669 ASSERT(context.is_register()); |
4646 frame_->Push(variable->name()); | 4670 frame_->EmitPush(context.reg()); |
| 4671 context.Unuse(); |
| 4672 frame_->EmitPush(Immediate(variable->name())); |
4647 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, | 4673 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, |
4648 CALL_FUNCTION, 2); | 4674 CALL_FUNCTION, 2); |
4649 frame_->Push(&answer); | 4675 frame_->Push(&answer); |
4650 return; | 4676 return; |
4651 } | 4677 } |
4652 | 4678 |
4653 // Default: Result of deleting non-global, not dynamically | 4679 // Default: Result of deleting non-global, not dynamically |
4654 // introduced variables is false. | 4680 // introduced variables is false. |
4655 frame_->Push(Factory::false_value()); | 4681 frame_->Push(Factory::false_value()); |
4656 | 4682 |
(...skipping 2622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7279 | 7305 |
7280 // Slow-case: Go through the JavaScript implementation. | 7306 // Slow-case: Go through the JavaScript implementation. |
7281 __ bind(&slow); | 7307 __ bind(&slow); |
7282 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 7308 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
7283 } | 7309 } |
7284 | 7310 |
7285 | 7311 |
7286 #undef __ | 7312 #undef __ |
7287 | 7313 |
7288 } } // namespace v8::internal | 7314 } } // namespace v8::internal |
OLD | NEW |