| 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 |