Chromium Code Reviews| 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 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 496 } | 496 } |
| 497 | 497 |
| 498 | 498 |
| 499 void CodeGenerator::LoadReference(Reference* ref) { | 499 void CodeGenerator::LoadReference(Reference* ref) { |
| 500 Comment cmnt(masm_, "[ LoadReference"); | 500 Comment cmnt(masm_, "[ LoadReference"); |
| 501 Expression* e = ref->expression(); | 501 Expression* e = ref->expression(); |
| 502 Property* property = e->AsProperty(); | 502 Property* property = e->AsProperty(); |
| 503 Variable* var = e->AsVariableProxy()->AsVariable(); | 503 Variable* var = e->AsVariableProxy()->AsVariable(); |
| 504 | 504 |
| 505 if (property != NULL) { | 505 if (property != NULL) { |
| 506 VirtualFrame::SpilledScope spilled_scope(this); | |
| 507 // The expression is either a property or a variable proxy that rewrites | 506 // The expression is either a property or a variable proxy that rewrites |
| 508 // to a property. | 507 // to a property. |
| 509 LoadAndSpill(property->obj()); | 508 Load(property->obj()); |
| 510 // We use a named reference if the key is a literal symbol, unless it is | 509 // We use a named reference if the key is a literal symbol, unless it is |
| 511 // a string that can be legally parsed as an integer. This is because | 510 // a string that can be legally parsed as an integer. This is because |
| 512 // otherwise we will not get into the slow case code that handles [] on | 511 // otherwise we will not get into the slow case code that handles [] on |
| 513 // String objects. | 512 // String objects. |
| 514 Literal* literal = property->key()->AsLiteral(); | 513 Literal* literal = property->key()->AsLiteral(); |
| 515 uint32_t dummy; | 514 uint32_t dummy; |
| 516 if (literal != NULL && | 515 if (literal != NULL && |
| 517 literal->handle()->IsSymbol() && | 516 literal->handle()->IsSymbol() && |
| 518 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { | 517 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) { |
| 519 ref->set_type(Reference::NAMED); | 518 ref->set_type(Reference::NAMED); |
| 520 } else { | 519 } else { |
| 521 LoadAndSpill(property->key()); | 520 Load(property->key()); |
| 522 ref->set_type(Reference::KEYED); | 521 ref->set_type(Reference::KEYED); |
| 523 } | 522 } |
| 524 } else if (var != NULL) { | 523 } else if (var != NULL) { |
| 525 // The expression is a variable proxy that does not rewrite to a | 524 // The expression is a variable proxy that does not rewrite to a |
| 526 // property. Global variables are treated as named property references. | 525 // property. Global variables are treated as named property references. |
| 527 if (var->is_global()) { | 526 if (var->is_global()) { |
| 528 VirtualFrame::SpilledScope spilled_scope(this); | 527 VirtualFrame::SpilledScope spilled_scope(this); |
| 529 LoadGlobal(); | 528 LoadGlobal(); |
| 530 ref->set_type(Reference::NAMED); | 529 ref->set_type(Reference::NAMED); |
| 531 } else { | 530 } else { |
| 532 ASSERT(var->slot() != NULL); | 531 ASSERT(var->slot() != NULL); |
| 533 ref->set_type(Reference::SLOT); | 532 ref->set_type(Reference::SLOT); |
| 534 } | 533 } |
| 535 } else { | 534 } else { |
| 536 VirtualFrame::SpilledScope spilled_scope(this); | |
| 537 // Anything else is a runtime error. | 535 // Anything else is a runtime error. |
| 538 LoadAndSpill(e); | 536 Load(e); |
| 539 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); | 537 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); |
| 540 } | 538 } |
| 541 } | 539 } |
| 542 | 540 |
| 543 | 541 |
| 544 void CodeGenerator::UnloadReference(Reference* ref) { | 542 void CodeGenerator::UnloadReference(Reference* ref) { |
| 545 // Pop a reference from the stack while preserving TOS. | 543 // Pop a reference from the stack while preserving TOS. |
| 546 Comment cmnt(masm_, "[ UnloadReference"); | 544 Comment cmnt(masm_, "[ UnloadReference"); |
| 547 int size = ref->size(); | 545 int size = ref->size(); |
| 548 if (size == 1) { | 546 if (size == 1) { |
| 547 VirtualFrame::SpilledScope spilled_scope(this); | |
| 549 frame_->EmitPop(eax); | 548 frame_->EmitPop(eax); |
| 550 __ mov(frame_->Top(), eax); | 549 __ mov(frame_->Top(), eax); |
| 551 } else if (size > 1) { | 550 } else if (size > 1) { |
| 551 VirtualFrame::SpilledScope spilled_scope(this); | |
| 552 frame_->EmitPop(eax); | 552 frame_->EmitPop(eax); |
| 553 frame_->Drop(size); | 553 frame_->Drop(size); |
| 554 frame_->EmitPush(eax); | 554 frame_->EmitPush(eax); |
| 555 } | 555 } |
| 556 } | 556 } |
| 557 | 557 |
| 558 | 558 |
| 559 class ToBooleanStub: public CodeStub { | 559 class ToBooleanStub: public CodeStub { |
| 560 public: | 560 public: |
| 561 ToBooleanStub() { } | 561 ToBooleanStub() { } |
| (...skipping 1637 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2199 | 2199 |
| 2200 // If the property has been removed while iterating, we just skip it. | 2200 // If the property has been removed while iterating, we just skip it. |
| 2201 __ cmp(ebx, Factory::null_value()); | 2201 __ cmp(ebx, Factory::null_value()); |
| 2202 node->continue_target()->Branch(equal); | 2202 node->continue_target()->Branch(equal); |
| 2203 | 2203 |
| 2204 end_del_check.Bind(); | 2204 end_del_check.Bind(); |
| 2205 // Store the entry in the 'each' expression and take another spin in the | 2205 // Store the entry in the 'each' expression and take another spin in the |
| 2206 // loop. edx: i'th entry of the enum cache (or string there of) | 2206 // loop. edx: i'th entry of the enum cache (or string there of) |
| 2207 frame_->EmitPush(ebx); | 2207 frame_->EmitPush(ebx); |
| 2208 { Reference each(this, node->each()); | 2208 { Reference each(this, node->each()); |
| 2209 // Loading a reference may leave the frame in an unspilled state. | |
| 2210 frame_->SpillAll(); | |
| 2209 if (!each.is_illegal()) { | 2211 if (!each.is_illegal()) { |
| 2210 if (each.size() > 0) { | 2212 if (each.size() > 0) { |
| 2211 frame_->EmitPush(frame_->ElementAt(each.size())); | 2213 frame_->EmitPush(frame_->ElementAt(each.size())); |
| 2212 } | 2214 } |
| 2213 // If the reference was to a slot we rely on the convenient property | 2215 // If the reference was to a slot we rely on the convenient property |
| 2214 // that it doesn't matter whether a value (eg, ebx pushed above) is | 2216 // that it doesn't matter whether a value (eg, ebx pushed above) is |
| 2215 // right on top of or right underneath a zero-sized reference. | 2217 // right on top of or right underneath a zero-sized reference. |
| 2216 each.SetValue(NOT_CONST_INIT); | 2218 each.SetValue(NOT_CONST_INIT); |
| 2217 if (each.size() > 0) { | 2219 if (each.size() > 0) { |
| 2218 // It's safe to pop the value lying on top of the reference before | 2220 // It's safe to pop the value lying on top of the reference before |
| 2219 // unloading the reference itself (which preserves the top of stack, | 2221 // unloading the reference itself (which preserves the top of stack, |
| 2220 // ie, now the topmost value of the non-zero sized reference), since | 2222 // ie, now the topmost value of the non-zero sized reference), since |
| 2221 // we will discard the top of stack after unloading the reference | 2223 // we will discard the top of stack after unloading the reference |
| 2222 // anyway. | 2224 // anyway. |
| 2223 frame_->Drop(); | 2225 frame_->Drop(); |
| 2224 } | 2226 } |
| 2225 } | 2227 } |
| 2226 } | 2228 } |
| 2229 // Unloading a reference may leave the frame in an unspilled state. | |
| 2230 frame_->SpillAll(); | |
| 2231 | |
| 2227 // Discard the i'th entry pushed above or else the remainder of the | 2232 // Discard the i'th entry pushed above or else the remainder of the |
| 2228 // reference, whichever is currently on top of the stack. | 2233 // reference, whichever is currently on top of the stack. |
| 2229 frame_->Drop(); | 2234 frame_->Drop(); |
| 2230 | 2235 |
| 2231 // Body. | 2236 // Body. |
| 2232 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2237 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 2233 VisitAndSpill(node->body()); | 2238 VisitAndSpill(node->body()); |
| 2234 | 2239 |
| 2235 // Next. | 2240 // Next. |
| 2236 node->continue_target()->Bind(); | 2241 node->continue_target()->Bind(); |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2522 frame_->CallRuntime(Runtime::kReThrow, 1); | 2527 frame_->CallRuntime(Runtime::kReThrow, 1); |
| 2523 | 2528 |
| 2524 // Done. | 2529 // Done. |
| 2525 exit.Bind(); | 2530 exit.Bind(); |
| 2526 } | 2531 } |
| 2527 } | 2532 } |
| 2528 | 2533 |
| 2529 | 2534 |
| 2530 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2535 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 2531 ASSERT(!in_spilled_code()); | 2536 ASSERT(!in_spilled_code()); |
| 2532 VirtualFrame::SpilledScope spilled_scope(this); | |
| 2533 Comment cmnt(masm_, "[ DebuggerStatement"); | 2537 Comment cmnt(masm_, "[ DebuggerStatement"); |
| 2534 CodeForStatement(node); | 2538 CodeForStatement(node); |
| 2539 // Spill everything, even constants, to the frame. | |
| 2540 frame_->SpillAll(); | |
| 2535 frame_->CallRuntime(Runtime::kDebugBreak, 0); | 2541 frame_->CallRuntime(Runtime::kDebugBreak, 0); |
| 2536 // Ignore the return value. | 2542 // Ignore the return value. |
| 2537 } | 2543 } |
| 2538 | 2544 |
| 2539 | 2545 |
| 2540 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 2546 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 2541 ASSERT(boilerplate->IsBoilerplate()); | 2547 ASSERT(boilerplate->IsBoilerplate()); |
| 2542 | 2548 |
| 2543 // Push the boilerplate on the stack. | 2549 // Push the boilerplate on the stack. |
| 2544 frame_->EmitPush(Immediate(boilerplate)); | 2550 frame_->Push(boilerplate); |
| 2545 | 2551 |
| 2546 // Create a new closure. | 2552 // Create a new closure. |
| 2547 frame_->EmitPush(esi); | 2553 frame_->Push(esi); |
| 2548 frame_->CallRuntime(Runtime::kNewClosure, 2); | 2554 Result result = frame_->CallRuntime(Runtime::kNewClosure, 2); |
| 2549 frame_->EmitPush(eax); | 2555 frame_->Push(&result); |
| 2550 } | 2556 } |
| 2551 | 2557 |
| 2552 | 2558 |
| 2553 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 2559 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 2554 VirtualFrame::SpilledScope spilled_scope(this); | |
| 2555 Comment cmnt(masm_, "[ FunctionLiteral"); | 2560 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 2556 | 2561 |
| 2557 // Build the function boilerplate and instantiate it. | 2562 // Build the function boilerplate and instantiate it. |
| 2558 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 2563 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
| 2559 // Check for stack-overflow exception. | 2564 // Check for stack-overflow exception. |
| 2560 if (HasStackOverflow()) return; | 2565 if (HasStackOverflow()) return; |
| 2561 InstantiateBoilerplate(boilerplate); | 2566 InstantiateBoilerplate(boilerplate); |
| 2562 } | 2567 } |
| 2563 | 2568 |
| 2564 | 2569 |
| 2565 void CodeGenerator::VisitFunctionBoilerplateLiteral( | 2570 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
| 2566 FunctionBoilerplateLiteral* node) { | 2571 FunctionBoilerplateLiteral* node) { |
| 2567 VirtualFrame::SpilledScope spilled_scope(this); | |
| 2568 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 2572 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
| 2569 InstantiateBoilerplate(node->boilerplate()); | 2573 InstantiateBoilerplate(node->boilerplate()); |
| 2570 } | 2574 } |
| 2571 | 2575 |
| 2572 | 2576 |
| 2573 void CodeGenerator::VisitConditional(Conditional* node) { | 2577 void CodeGenerator::VisitConditional(Conditional* node) { |
| 2574 VirtualFrame::SpilledScope spilled_scope(this); | |
| 2575 Comment cmnt(masm_, "[ Conditional"); | 2578 Comment cmnt(masm_, "[ Conditional"); |
| 2576 JumpTarget then(this); | 2579 JumpTarget then(this); |
| 2577 JumpTarget else_(this); | 2580 JumpTarget else_(this); |
| 2578 JumpTarget exit(this); | 2581 JumpTarget exit(this); |
| 2579 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF, | 2582 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 2580 &then, &else_, true); | |
| 2581 if (has_valid_frame()) { | 2583 if (has_valid_frame()) { |
| 2582 Branch(false, &else_); | 2584 Branch(false, &else_); |
| 2583 } | 2585 } |
| 2584 if (has_valid_frame() || then.is_linked()) { | 2586 if (then.is_linked()) { |
| 2585 then.Bind(); | 2587 then.Bind(); |
| 2586 LoadAndSpill(node->then_expression(), typeof_state()); | 2588 } |
| 2589 if (has_valid_frame()) { | |
| 2590 Load(node->then_expression(), typeof_state()); | |
| 2587 exit.Jump(); | 2591 exit.Jump(); |
| 2588 } | 2592 } |
| 2589 if (else_.is_linked()) { | 2593 if (else_.is_linked()) { |
| 2590 else_.Bind(); | 2594 else_.Bind(); |
| 2591 LoadAndSpill(node->else_expression(), typeof_state()); | 2595 Load(node->else_expression(), typeof_state()); |
| 2592 } | 2596 } |
| 2593 exit.Bind(); | 2597 exit.Bind(); |
| 2594 } | 2598 } |
| 2595 | 2599 |
| 2596 | 2600 |
| 2597 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2601 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2598 if (slot->type() == Slot::LOOKUP) { | 2602 if (slot->type() == Slot::LOOKUP) { |
| 2599 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2603 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2600 | 2604 |
| 2601 // For now, just do a runtime call. | 2605 // For now, just do a runtime call. |
| 2602 VirtualFrame::SpilledScope spilled_scope(this); | 2606 frame_->Push(esi); |
| 2603 frame_->EmitPush(esi); | 2607 frame_->Push(slot->var()->name()); |
| 2604 frame_->EmitPush(Immediate(slot->var()->name())); | |
| 2605 | 2608 |
| 2609 Result value(this); | |
| 2606 if (typeof_state == INSIDE_TYPEOF) { | 2610 if (typeof_state == INSIDE_TYPEOF) { |
| 2607 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2611 value = |
| 2612 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | |
| 2608 } else { | 2613 } else { |
| 2609 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 2614 value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2610 } | 2615 } |
| 2611 frame_->EmitPush(eax); | 2616 frame_->Push(&value); |
| 2617 | |
| 2618 } else if (slot->var()->mode() == Variable::CONST) { | |
| 2619 // Const slots may contain 'the hole' value (the constant hasn't been | |
| 2620 // initialized yet) which needs to be converted into the 'undefined' | |
| 2621 // value. | |
| 2622 Comment cmnt(masm_, "[ Load const"); | |
| 2623 JumpTarget exit(this); | |
| 2624 Result temp = allocator_->Allocate(); | |
| 2625 ASSERT(temp.is_valid()); | |
| 2626 __ mov(temp.reg(), SlotOperand(slot, temp.reg())); | |
|
William Hesse
2009/01/06 14:40:27
This was __mov(eax, SlotOperand(slot, ecx)).
What
| |
| 2627 __ cmp(temp.reg(), Factory::the_hole_value()); | |
| 2628 exit.Branch(not_equal, &temp); | |
| 2629 __ mov(temp.reg(), Factory::undefined_value()); | |
| 2630 exit.Bind(&temp); | |
| 2631 frame_->Push(&temp); | |
| 2632 | |
| 2633 } else if (slot->type() == Slot::PARAMETER) { | |
| 2634 frame_->LoadParameterAt(slot->index()); | |
| 2635 | |
| 2636 } else if (slot->type() == Slot::LOCAL) { | |
| 2637 frame_->LoadLocalAt(slot->index()); | |
| 2612 | 2638 |
| 2613 } else { | 2639 } else { |
| 2614 // Note: We would like to keep the assert below, but it fires because of | 2640 // The other remaining slot types (LOOKUP and GLOBAL) cannot reach |
| 2615 // some nasty code in LoadTypeofExpression() which should be removed... | 2641 // here. |
| 2616 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 2642 ASSERT(slot->type() == Slot::CONTEXT); |
| 2617 if (slot->var()->mode() == Variable::CONST) { | 2643 Result temp = allocator_->Allocate(); |
| 2618 // Const slots may contain 'the hole' value (the constant hasn't been | 2644 ASSERT(temp.is_valid()); |
| 2619 // initialized yet) which needs to be converted into the 'undefined' | 2645 __ mov(temp.reg(), SlotOperand(slot, temp.reg())); |
|
William Hesse
2009/01/06 14:40:27
Same here, second arg of SlotOperand() was ecx.
| |
| 2620 // value. | 2646 frame_->Push(&temp); |
| 2621 VirtualFrame::SpilledScope spilled_scope(this); | |
| 2622 Comment cmnt(masm_, "[ Load const"); | |
| 2623 JumpTarget exit(this); | |
| 2624 __ mov(eax, SlotOperand(slot, ecx)); | |
| 2625 __ cmp(eax, Factory::the_hole_value()); | |
| 2626 exit.Branch(not_equal); | |
| 2627 __ mov(eax, Factory::undefined_value()); | |
| 2628 exit.Bind(); | |
| 2629 frame_->EmitPush(eax); | |
| 2630 } else { | |
| 2631 if (slot->type() == Slot::PARAMETER) { | |
| 2632 frame_->LoadParameterAt(slot->index()); | |
| 2633 } else if (slot->type() == Slot::LOCAL) { | |
| 2634 frame_->LoadLocalAt(slot->index()); | |
| 2635 } else { | |
| 2636 // The other remaining slot types (LOOKUP and GLOBAL) cannot reach | |
| 2637 // here. | |
| 2638 ASSERT(slot->type() == Slot::CONTEXT); | |
| 2639 VirtualFrame::SpilledScope spilled_scope(this); | |
| 2640 frame_->EmitPush(SlotOperand(slot, ecx)); | |
| 2641 } | |
| 2642 } | |
| 2643 } | 2647 } |
| 2644 } | 2648 } |
| 2645 | 2649 |
| 2646 | 2650 |
| 2647 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | 2651 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
| 2648 if (slot->type() == Slot::LOOKUP) { | 2652 if (slot->type() == Slot::LOOKUP) { |
| 2649 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2653 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2650 | 2654 |
| 2651 // For now, just do a runtime call. | 2655 // For now, just do a runtime call. |
| 2652 VirtualFrame::SpilledScope spilled_scope(this); | 2656 frame_->Push(esi); |
| 2653 frame_->EmitPush(esi); | 2657 frame_->Push(slot->var()->name()); |
| 2654 frame_->EmitPush(Immediate(slot->var()->name())); | |
| 2655 | 2658 |
| 2659 Result value(this); | |
| 2656 if (init_state == CONST_INIT) { | 2660 if (init_state == CONST_INIT) { |
| 2657 // Same as the case for a normal store, but ignores attribute | 2661 // Same as the case for a normal store, but ignores attribute |
| 2658 // (e.g. READ_ONLY) of context slot so that we can initialize const | 2662 // (e.g. READ_ONLY) of context slot so that we can initialize const |
| 2659 // properties (introduced via eval("const foo = (some expr);")). Also, | 2663 // properties (introduced via eval("const foo = (some expr);")). Also, |
| 2660 // uses the current function context instead of the top context. | 2664 // uses the current function context instead of the top context. |
| 2661 // | 2665 // |
| 2662 // Note that we must declare the foo upon entry of eval(), via a | 2666 // Note that we must declare the foo upon entry of eval(), via a |
| 2663 // context slot declaration, but we cannot initialize it at the same | 2667 // context slot declaration, but we cannot initialize it at the same |
| 2664 // time, because the const declaration may be at the end of the eval | 2668 // time, because the const declaration may be at the end of the eval |
| 2665 // code (sigh...) and the const variable may have been used before | 2669 // code (sigh...) and the const variable may have been used before |
| 2666 // (where its value is 'undefined'). Thus, we can only do the | 2670 // (where its value is 'undefined'). Thus, we can only do the |
| 2667 // initialization when we actually encounter the expression and when | 2671 // initialization when we actually encounter the expression and when |
| 2668 // the expression operands are defined and valid, and thus we need the | 2672 // the expression operands are defined and valid, and thus we need the |
| 2669 // split into 2 operations: declaration of the context slot followed | 2673 // split into 2 operations: declaration of the context slot followed |
| 2670 // by initialization. | 2674 // by initialization. |
| 2671 frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 2675 value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 2672 } else { | 2676 } else { |
| 2673 frame_->CallRuntime(Runtime::kStoreContextSlot, 3); | 2677 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3); |
| 2674 } | 2678 } |
| 2675 // Storing a variable must keep the (new) value on the expression | 2679 // Storing a variable must keep the (new) value on the expression |
| 2676 // stack. This is necessary for compiling chained assignment | 2680 // stack. This is necessary for compiling chained assignment |
| 2677 // expressions. | 2681 // expressions. |
| 2678 frame_->EmitPush(eax); | 2682 frame_->Push(&value); |
| 2679 | 2683 |
| 2680 } else { | 2684 } else { |
| 2681 ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 2685 ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
| 2682 | 2686 |
| 2683 JumpTarget exit(this); | 2687 JumpTarget exit(this); |
| 2684 if (init_state == CONST_INIT) { | 2688 if (init_state == CONST_INIT) { |
| 2685 ASSERT(slot->var()->mode() == Variable::CONST); | 2689 ASSERT(slot->var()->mode() == Variable::CONST); |
| 2686 // Only the first const initialization must be executed (the slot | 2690 // Only the first const initialization must be executed (the slot |
| 2687 // still contains 'the hole' value). When the assignment is executed, | 2691 // still contains 'the hole' value). When the assignment is executed, |
| 2688 // the code is identical to a normal store (see below). | 2692 // the code is identical to a normal store (see below). |
| 2689 Comment cmnt(masm_, "[ Init const"); | 2693 Comment cmnt(masm_, "[ Init const"); |
| 2690 VirtualFrame::SpilledScope spilled_scope(this); | 2694 Result temp = allocator_->Allocate(); |
| 2691 __ mov(eax, SlotOperand(slot, ecx)); | 2695 ASSERT(temp.is_valid()); |
| 2692 __ cmp(eax, Factory::the_hole_value()); | 2696 __ mov(temp.reg(), SlotOperand(slot, temp.reg())); |
|
William Hesse
2009/01/06 14:40:27
Same, ecx versus eax.
| |
| 2697 __ cmp(temp.reg(), Factory::the_hole_value()); | |
| 2698 temp.Unuse(); | |
| 2693 exit.Branch(not_equal); | 2699 exit.Branch(not_equal); |
| 2694 } | 2700 } |
| 2695 | 2701 |
| 2696 // We must execute the store. Storing a variable must keep the (new) | 2702 // We must execute the store. Storing a variable must keep the (new) |
| 2697 // value on the stack. This is necessary for compiling assignment | 2703 // value on the stack. This is necessary for compiling assignment |
| 2698 // expressions. | 2704 // expressions. |
| 2699 // | 2705 // |
| 2700 // Note: We will reach here even with slot->var()->mode() == | 2706 // Note: We will reach here even with slot->var()->mode() == |
| 2701 // Variable::CONST because of const declarations which will initialize | 2707 // Variable::CONST because of const declarations which will initialize |
| 2702 // consts to 'the hole' value and by doing so, end up calling this code. | 2708 // consts to 'the hole' value and by doing so, end up calling this code. |
| 2703 if (slot->type() == Slot::PARAMETER) { | 2709 if (slot->type() == Slot::PARAMETER) { |
| 2704 frame_->StoreToParameterAt(slot->index()); | 2710 frame_->StoreToParameterAt(slot->index()); |
| 2705 } else if (slot->type() == Slot::LOCAL) { | 2711 } else if (slot->type() == Slot::LOCAL) { |
| 2706 frame_->StoreToLocalAt(slot->index()); | 2712 frame_->StoreToLocalAt(slot->index()); |
| 2707 } else { | 2713 } else { |
| 2708 // The other slot types (LOOKUP and GLOBAL) cannot reach here. | 2714 // The other slot types (LOOKUP and GLOBAL) cannot reach here. |
| 2709 ASSERT(slot->type() == Slot::CONTEXT); | 2715 ASSERT(slot->type() == Slot::CONTEXT); |
| 2710 VirtualFrame::SpilledScope spilled_scope(this); | 2716 frame_->Dup(); |
| 2711 frame_->EmitPop(eax); | 2717 Result value = frame_->Pop(); |
| 2712 __ mov(SlotOperand(slot, ecx), eax); | 2718 value.ToRegister(); |
| 2713 frame_->EmitPush(eax); // RecordWrite may destroy the value in eax. | 2719 Result start = allocator_->Allocate(); |
| 2720 ASSERT(start.is_valid()); | |
| 2721 __ mov(SlotOperand(slot, start.reg()), value.reg()); | |
| 2722 // RecordWrite may destroy the value registers. | |
| 2723 // | |
| 2724 // TODO(): Avoid actually spilling when the value is not needed | |
| 2725 // (probably the common case). | |
| 2726 frame_->Spill(value.reg()); | |
| 2714 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 2727 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 2715 __ RecordWrite(ecx, offset, eax, ebx); | 2728 Result temp = allocator_->Allocate(); |
| 2729 ASSERT(temp.is_valid()); | |
| 2730 __ RecordWrite(start.reg(), offset, value.reg(), temp.reg()); | |
| 2731 // The results start, value, and temp are unused by going out of | |
| 2732 // scope. | |
| 2716 } | 2733 } |
| 2717 | 2734 |
| 2718 // If we definitely did not jump over the assignment, we do not need | 2735 // If we definitely did not jump over the assignment, we do not need |
| 2719 // to bind the exit label. Doing so can defeat peephole | 2736 // to bind the exit label. Doing so can defeat peephole |
| 2720 // optimization. | 2737 // optimization. |
| 2721 if (init_state == CONST_INIT) { | 2738 if (exit.is_linked()) { |
| 2722 exit.Bind(); | 2739 exit.Bind(); |
| 2723 } | 2740 } |
| 2724 } | 2741 } |
| 2725 } | 2742 } |
| 2726 | 2743 |
| 2727 | 2744 |
| 2728 void CodeGenerator::VisitSlot(Slot* node) { | 2745 void CodeGenerator::VisitSlot(Slot* node) { |
| 2729 Comment cmnt(masm_, "[ Slot"); | 2746 Comment cmnt(masm_, "[ Slot"); |
| 2730 LoadFromSlot(node, typeof_state()); | 2747 LoadFromSlot(node, typeof_state()); |
| 2731 } | 2748 } |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3017 | 3034 |
| 3018 | 3035 |
| 3019 void CodeGenerator::VisitAssignment(Assignment* node) { | 3036 void CodeGenerator::VisitAssignment(Assignment* node) { |
| 3020 Comment cmnt(masm_, "[ Assignment"); | 3037 Comment cmnt(masm_, "[ Assignment"); |
| 3021 CodeForStatement(node); | 3038 CodeForStatement(node); |
| 3022 | 3039 |
| 3023 { Reference target(this, node->target()); | 3040 { Reference target(this, node->target()); |
| 3024 if (target.is_illegal()) { | 3041 if (target.is_illegal()) { |
| 3025 // Fool the virtual frame into thinking that we left the assignment's | 3042 // Fool the virtual frame into thinking that we left the assignment's |
| 3026 // value on the frame. | 3043 // value on the frame. |
| 3027 frame_->EmitPush(Immediate(Smi::FromInt(0))); | 3044 frame_->Push(Handle<Object>(Smi::FromInt(0))); |
| 3028 return; | 3045 return; |
| 3029 } | 3046 } |
| 3030 | 3047 |
| 3031 if (node->op() == Token::ASSIGN || | 3048 if (node->op() == Token::ASSIGN || |
| 3032 node->op() == Token::INIT_VAR || | 3049 node->op() == Token::INIT_VAR || |
| 3033 node->op() == Token::INIT_CONST) { | 3050 node->op() == Token::INIT_CONST) { |
| 3034 Load(node->value()); | 3051 Load(node->value()); |
| 3035 | 3052 |
| 3036 } else { | 3053 } else { |
| 3037 VirtualFrame::SpilledScope spilled_scope(this); | 3054 VirtualFrame::SpilledScope spilled_scope(this); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3071 Comment cmnt(masm_, "[ Throw"); | 3088 Comment cmnt(masm_, "[ Throw"); |
| 3072 CodeForStatement(node); | 3089 CodeForStatement(node); |
| 3073 | 3090 |
| 3074 LoadAndSpill(node->exception()); | 3091 LoadAndSpill(node->exception()); |
| 3075 frame_->CallRuntime(Runtime::kThrow, 1); | 3092 frame_->CallRuntime(Runtime::kThrow, 1); |
| 3076 frame_->EmitPush(eax); | 3093 frame_->EmitPush(eax); |
| 3077 } | 3094 } |
| 3078 | 3095 |
| 3079 | 3096 |
| 3080 void CodeGenerator::VisitProperty(Property* node) { | 3097 void CodeGenerator::VisitProperty(Property* node) { |
| 3081 VirtualFrame::SpilledScope spilled_scope(this); | |
| 3082 Comment cmnt(masm_, "[ Property"); | 3098 Comment cmnt(masm_, "[ Property"); |
| 3083 Reference property(this, node); | 3099 Reference property(this, node); |
| 3084 property.GetValueAndSpill(typeof_state()); | 3100 property.GetValue(typeof_state()); |
| 3085 } | 3101 } |
| 3086 | 3102 |
| 3087 | 3103 |
| 3088 void CodeGenerator::VisitCall(Call* node) { | 3104 void CodeGenerator::VisitCall(Call* node) { |
| 3089 VirtualFrame::SpilledScope spilled_scope(this); | 3105 VirtualFrame::SpilledScope spilled_scope(this); |
| 3090 Comment cmnt(masm_, "[ Call"); | 3106 Comment cmnt(masm_, "[ Call"); |
| 3091 | 3107 |
| 3092 ZoneList<Expression*>* args = node->arguments(); | 3108 ZoneList<Expression*>* args = node->arguments(); |
| 3093 | 3109 |
| 3094 CodeForStatement(node); | 3110 CodeForStatement(node); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3186 // Overwrite the function on the stack with the result. | 3202 // Overwrite the function on the stack with the result. |
| 3187 __ mov(frame_->Top(), eax); | 3203 __ mov(frame_->Top(), eax); |
| 3188 | 3204 |
| 3189 } else { | 3205 } else { |
| 3190 // ------------------------------------------- | 3206 // ------------------------------------------- |
| 3191 // JavaScript example: 'array[index](1, 2, 3)' | 3207 // JavaScript example: 'array[index](1, 2, 3)' |
| 3192 // ------------------------------------------- | 3208 // ------------------------------------------- |
| 3193 | 3209 |
| 3194 // Load the function to call from the property through a reference. | 3210 // Load the function to call from the property through a reference. |
| 3195 Reference ref(this, property); | 3211 Reference ref(this, property); |
| 3212 frame_->SpillAll(); | |
| 3196 ref.GetValueAndSpill(NOT_INSIDE_TYPEOF); | 3213 ref.GetValueAndSpill(NOT_INSIDE_TYPEOF); |
| 3197 | 3214 |
| 3198 // Pass receiver to called function. | 3215 // Pass receiver to called function. |
| 3199 // The reference's size is non-negative. | 3216 // The reference's size is non-negative. |
| 3200 frame_->EmitPush(frame_->ElementAt(ref.size())); | 3217 frame_->EmitPush(frame_->ElementAt(ref.size())); |
| 3201 | 3218 |
| 3202 // Call the function. | 3219 // Call the function. |
| 3203 CallWithArguments(args, node->position()); | 3220 CallWithArguments(args, node->position()); |
| 3204 } | 3221 } |
| 3205 | 3222 |
| (...skipping 2601 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5807 | 5824 |
| 5808 // Slow-case: Go through the JavaScript implementation. | 5825 // Slow-case: Go through the JavaScript implementation. |
| 5809 __ bind(&slow); | 5826 __ bind(&slow); |
| 5810 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5827 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5811 } | 5828 } |
| 5812 | 5829 |
| 5813 | 5830 |
| 5814 #undef __ | 5831 #undef __ |
| 5815 | 5832 |
| 5816 } } // namespace v8::internal | 5833 } } // namespace v8::internal |
| OLD | NEW |