OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 23 matching lines...) Expand all Loading... |
34 #include "compiler.h" | 34 #include "compiler.h" |
35 #include "debug.h" | 35 #include "debug.h" |
36 #include "full-codegen.h" | 36 #include "full-codegen.h" |
37 #include "parser.h" | 37 #include "parser.h" |
38 #include "scopes.h" | 38 #include "scopes.h" |
39 #include "stub-cache.h" | 39 #include "stub-cache.h" |
40 | 40 |
41 namespace v8 { | 41 namespace v8 { |
42 namespace internal { | 42 namespace internal { |
43 | 43 |
44 | |
45 #define __ ACCESS_MASM(masm_) | 44 #define __ ACCESS_MASM(masm_) |
46 | 45 |
47 | 46 |
48 static unsigned GetPropertyId(Property* property) { | 47 static unsigned GetPropertyId(Property* property) { |
49 return property->id(); | 48 return property->id(); |
50 } | 49 } |
51 | 50 |
52 | 51 |
53 class JumpPatchSite BASE_EMBEDDED { | 52 class JumpPatchSite BASE_EMBEDDED { |
54 public: | 53 public: |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 __ CallRuntime(Runtime::kNewFunctionContext, 1); | 184 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
186 } | 185 } |
187 function_in_register = false; | 186 function_in_register = false; |
188 // Context is returned in both eax and esi. It replaces the context | 187 // Context is returned in both eax and esi. It replaces the context |
189 // passed to us. It's saved in the stack and kept live in esi. | 188 // passed to us. It's saved in the stack and kept live in esi. |
190 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); | 189 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
191 | 190 |
192 // Copy parameters into context if necessary. | 191 // Copy parameters into context if necessary. |
193 int num_parameters = info->scope()->num_parameters(); | 192 int num_parameters = info->scope()->num_parameters(); |
194 for (int i = 0; i < num_parameters; i++) { | 193 for (int i = 0; i < num_parameters; i++) { |
195 Slot* slot = scope()->parameter(i)->AsSlot(); | 194 Variable* var = scope()->parameter(i); |
196 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 195 if (var->IsContextSlot()) { |
197 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 196 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
198 (num_parameters - 1 - i) * kPointerSize; | 197 (num_parameters - 1 - i) * kPointerSize; |
199 // Load parameter from stack. | 198 // Load parameter from stack. |
200 __ mov(eax, Operand(ebp, parameter_offset)); | 199 __ mov(eax, Operand(ebp, parameter_offset)); |
201 // Store it in the context. | 200 // Store it in the context. |
202 int context_offset = Context::SlotOffset(slot->index()); | 201 int context_offset = Context::SlotOffset(var->index()); |
203 __ mov(Operand(esi, context_offset), eax); | 202 __ mov(Operand(esi, context_offset), eax); |
204 // Update the write barrier. This clobbers all involved | 203 // Update the write barrier. This clobbers all involved |
205 // registers, so we have use a third register to avoid | 204 // registers, so we have use a third register to avoid |
206 // clobbering esi. | 205 // clobbering esi. |
207 __ mov(ecx, esi); | 206 __ mov(ecx, esi); |
208 __ RecordWrite(ecx, context_offset, eax, ebx); | 207 __ RecordWrite(ecx, context_offset, eax, ebx); |
209 } | 208 } |
210 } | 209 } |
211 } | 210 } |
212 | 211 |
(...skipping 21 matching lines...) Expand all Loading... |
234 if (is_strict_mode()) { | 233 if (is_strict_mode()) { |
235 type = ArgumentsAccessStub::NEW_STRICT; | 234 type = ArgumentsAccessStub::NEW_STRICT; |
236 } else if (function()->has_duplicate_parameters()) { | 235 } else if (function()->has_duplicate_parameters()) { |
237 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; | 236 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; |
238 } else { | 237 } else { |
239 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST; | 238 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST; |
240 } | 239 } |
241 ArgumentsAccessStub stub(type); | 240 ArgumentsAccessStub stub(type); |
242 __ CallStub(&stub); | 241 __ CallStub(&stub); |
243 | 242 |
244 Move(arguments->AsSlot(), eax, ebx, edx); | 243 SetVar(arguments, eax, ebx, edx); |
245 } | 244 } |
246 | 245 |
247 if (FLAG_trace) { | 246 if (FLAG_trace) { |
248 __ CallRuntime(Runtime::kTraceEnter, 0); | 247 __ CallRuntime(Runtime::kTraceEnter, 0); |
249 } | 248 } |
250 | 249 |
251 // Visit the declarations and body unless there is an illegal | 250 // Visit the declarations and body unless there is an illegal |
252 // redeclaration. | 251 // redeclaration. |
253 if (scope()->HasIllegalRedeclaration()) { | 252 if (scope()->HasIllegalRedeclaration()) { |
254 Comment cmnt(masm_, "[ Declarations"); | 253 Comment cmnt(masm_, "[ Declarations"); |
255 scope()->VisitIllegalRedeclaration(this); | 254 scope()->VisitIllegalRedeclaration(this); |
256 | 255 |
257 } else { | 256 } else { |
258 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 257 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
259 { Comment cmnt(masm_, "[ Declarations"); | 258 { Comment cmnt(masm_, "[ Declarations"); |
260 // For named function expressions, declare the function name as a | 259 // For named function expressions, declare the function name as a |
261 // constant. | 260 // constant. |
262 if (scope()->is_function_scope() && scope()->function() != NULL) { | 261 if (scope()->is_function_scope() && scope()->function() != NULL) { |
263 EmitDeclaration(scope()->function(), Variable::CONST, NULL); | 262 int ignored = 0; |
| 263 EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored); |
264 } | 264 } |
265 VisitDeclarations(scope()->declarations()); | 265 VisitDeclarations(scope()->declarations()); |
266 } | 266 } |
267 | 267 |
268 { Comment cmnt(masm_, "[ Stack check"); | 268 { Comment cmnt(masm_, "[ Stack check"); |
269 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 269 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
270 Label ok; | 270 Label ok; |
271 ExternalReference stack_limit = | 271 ExternalReference stack_limit = |
272 ExternalReference::address_of_stack_limit(isolate()); | 272 ExternalReference::address_of_stack_limit(isolate()); |
273 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 273 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 | 365 |
366 void FullCodeGenerator::verify_stack_height() { | 366 void FullCodeGenerator::verify_stack_height() { |
367 ASSERT(FLAG_verify_stack_height); | 367 ASSERT(FLAG_verify_stack_height); |
368 __ sub(Operand(ebp), Immediate(kPointerSize * stack_height())); | 368 __ sub(Operand(ebp), Immediate(kPointerSize * stack_height())); |
369 __ cmp(ebp, Operand(esp)); | 369 __ cmp(ebp, Operand(esp)); |
370 __ Assert(equal, "Full codegen stack height not as expected."); | 370 __ Assert(equal, "Full codegen stack height not as expected."); |
371 __ add(Operand(ebp), Immediate(kPointerSize * stack_height())); | 371 __ add(Operand(ebp), Immediate(kPointerSize * stack_height())); |
372 } | 372 } |
373 | 373 |
374 | 374 |
375 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { | 375 void FullCodeGenerator::EffectContext::Plug(Variable* var) const { |
| 376 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
376 } | 377 } |
377 | 378 |
378 | 379 |
379 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { | 380 void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const { |
380 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); | 381 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
381 __ mov(result_register(), slot_operand); | 382 codegen()->GetVar(result_register(), var); |
382 } | 383 } |
383 | 384 |
384 | 385 |
385 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { | 386 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { |
386 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); | 387 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
| 388 MemOperand operand = codegen()->VarOperand(var, result_register()); |
387 // Memory operands can be pushed directly. | 389 // Memory operands can be pushed directly. |
388 __ push(slot_operand); | 390 __ push(operand); |
389 codegen()->increment_stack_height(); | 391 codegen()->increment_stack_height(); |
390 } | 392 } |
391 | 393 |
392 | 394 |
393 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { | 395 void FullCodeGenerator::TestContext::Plug(Variable* var) const { |
394 // For simplicity we always test the accumulator register. | 396 // For simplicity we always test the accumulator register. |
395 codegen()->Move(result_register(), slot); | 397 codegen()->GetVar(result_register(), var); |
396 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 398 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
397 codegen()->DoTest(this); | 399 codegen()->DoTest(this); |
398 } | 400 } |
399 | 401 |
400 | 402 |
401 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { | 403 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { |
402 UNREACHABLE(); // Not used on IA32. | 404 UNREACHABLE(); // Not used on IA32. |
403 } | 405 } |
404 | 406 |
405 | 407 |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 __ j(cc, if_true); | 611 __ j(cc, if_true); |
610 } else if (if_true == fall_through) { | 612 } else if (if_true == fall_through) { |
611 __ j(NegateCondition(cc), if_false); | 613 __ j(NegateCondition(cc), if_false); |
612 } else { | 614 } else { |
613 __ j(cc, if_true); | 615 __ j(cc, if_true); |
614 __ jmp(if_false); | 616 __ jmp(if_false); |
615 } | 617 } |
616 } | 618 } |
617 | 619 |
618 | 620 |
619 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { | 621 MemOperand FullCodeGenerator::StackOperand(Variable* var) { |
620 switch (slot->type()) { | 622 ASSERT(var->IsStackAllocated()); |
621 case Slot::PARAMETER: | 623 // Offset is negative because higher indexes are at lower addresses. |
622 case Slot::LOCAL: | 624 int offset = -var->index() * kPointerSize; |
623 return Operand(ebp, SlotOffset(slot)); | 625 // Adjust by a (parameter or local) base offset. |
624 case Slot::CONTEXT: { | 626 if (var->IsParameter()) { |
625 int context_chain_length = | 627 offset += (info_->scope()->num_parameters() + 1) * kPointerSize; |
626 scope()->ContextChainLength(slot->var()->scope()); | 628 } else { |
627 __ LoadContext(scratch, context_chain_length); | 629 offset += JavaScriptFrameConstants::kLocal0Offset; |
628 return ContextOperand(scratch, slot->index()); | |
629 } | |
630 case Slot::LOOKUP: | |
631 UNREACHABLE(); | |
632 } | 630 } |
633 UNREACHABLE(); | 631 return Operand(ebp, offset); |
634 return Operand(eax, 0); | |
635 } | 632 } |
636 | 633 |
637 | 634 |
638 void FullCodeGenerator::Move(Register destination, Slot* source) { | 635 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) { |
639 MemOperand location = EmitSlotSearch(source, destination); | 636 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); |
640 __ mov(destination, location); | 637 if (var->IsContextSlot()) { |
| 638 int context_chain_length = scope()->ContextChainLength(var->scope()); |
| 639 __ LoadContext(scratch, context_chain_length); |
| 640 return ContextOperand(scratch, var->index()); |
| 641 } else { |
| 642 return StackOperand(var); |
| 643 } |
641 } | 644 } |
642 | 645 |
643 | 646 |
644 void FullCodeGenerator::Move(Slot* dst, | 647 void FullCodeGenerator::GetVar(Register dest, Variable* var) { |
645 Register src, | 648 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); |
646 Register scratch1, | 649 MemOperand location = VarOperand(var, dest); |
647 Register scratch2) { | 650 __ mov(dest, location); |
648 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. | 651 } |
649 ASSERT(!scratch1.is(src) && !scratch2.is(src)); | 652 |
650 MemOperand location = EmitSlotSearch(dst, scratch1); | 653 |
| 654 void FullCodeGenerator::SetVar(Variable* var, |
| 655 Register src, |
| 656 Register scratch0, |
| 657 Register scratch1) { |
| 658 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); |
| 659 ASSERT(!scratch0.is(src)); |
| 660 ASSERT(!scratch0.is(scratch1)); |
| 661 ASSERT(!scratch1.is(src)); |
| 662 MemOperand location = VarOperand(var, scratch0); |
651 __ mov(location, src); | 663 __ mov(location, src); |
652 // Emit the write barrier code if the location is in the heap. | 664 // Emit the write barrier code if the location is in the heap. |
653 if (dst->type() == Slot::CONTEXT) { | 665 if (var->IsContextSlot()) { |
654 int offset = Context::SlotOffset(dst->index()); | 666 int offset = Context::SlotOffset(var->index()); |
655 ASSERT(!scratch1.is(esi) && !src.is(esi) && !scratch2.is(esi)); | 667 ASSERT(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi)); |
656 __ RecordWrite(scratch1, offset, src, scratch2); | 668 __ RecordWrite(scratch0, offset, src, scratch1); |
657 } | 669 } |
658 } | 670 } |
659 | 671 |
660 | 672 |
661 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 673 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
662 bool should_normalize, | 674 bool should_normalize, |
663 Label* if_true, | 675 Label* if_true, |
664 Label* if_false) { | 676 Label* if_false) { |
665 // Only prepare for bailouts before splits if we're in a test | 677 // Only prepare for bailouts before splits if we're in a test |
666 // context. Otherwise, we let the Visit function deal with the | 678 // context. Otherwise, we let the Visit function deal with the |
(...skipping 12 matching lines...) Expand all Loading... |
679 if (should_normalize) { | 691 if (should_normalize) { |
680 __ cmp(eax, isolate()->factory()->true_value()); | 692 __ cmp(eax, isolate()->factory()->true_value()); |
681 Split(equal, if_true, if_false, NULL); | 693 Split(equal, if_true, if_false, NULL); |
682 __ bind(&skip); | 694 __ bind(&skip); |
683 } | 695 } |
684 } | 696 } |
685 | 697 |
686 | 698 |
687 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 699 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
688 Variable::Mode mode, | 700 Variable::Mode mode, |
689 FunctionLiteral* function) { | 701 FunctionLiteral* function, |
690 Comment cmnt(masm_, "[ Declaration"); | 702 int* global_count) { |
| 703 // If it was not possible to allocate the variable at compile time, we |
| 704 // need to "declare" it at runtime to make sure it actually exists in the |
| 705 // local context. |
691 Variable* variable = proxy->var(); | 706 Variable* variable = proxy->var(); |
692 ASSERT(variable != NULL); // Must have been resolved. | 707 switch (variable->location()) { |
693 Slot* slot = variable->AsSlot(); | 708 case Variable::UNALLOCATED: |
694 ASSERT(slot != NULL); | 709 ++(*global_count); |
695 switch (slot->type()) { | 710 break; |
696 case Slot::PARAMETER: | 711 |
697 case Slot::LOCAL: | 712 case Variable::PARAMETER: |
| 713 case Variable::LOCAL: |
698 if (function != NULL) { | 714 if (function != NULL) { |
| 715 Comment cmnt(masm_, "[ Declaration"); |
699 VisitForAccumulatorValue(function); | 716 VisitForAccumulatorValue(function); |
700 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); | 717 __ mov(StackOperand(variable), result_register()); |
701 } else if (mode == Variable::CONST || mode == Variable::LET) { | 718 } else if (mode == Variable::CONST || mode == Variable::LET) { |
702 __ mov(Operand(ebp, SlotOffset(slot)), | 719 Comment cmnt(masm_, "[ Declaration"); |
| 720 __ mov(StackOperand(variable), |
703 Immediate(isolate()->factory()->the_hole_value())); | 721 Immediate(isolate()->factory()->the_hole_value())); |
704 } | 722 } |
705 break; | 723 break; |
706 | 724 |
707 case Slot::CONTEXT: | 725 case Variable::CONTEXT: |
708 // We bypass the general EmitSlotSearch because we know more about | |
709 // this specific context. | |
710 | |
711 // The variable in the decl always resides in the current function | 726 // The variable in the decl always resides in the current function |
712 // context. | 727 // context. |
713 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 728 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
714 if (FLAG_debug_code) { | 729 if (FLAG_debug_code) { |
715 // Check that we're not inside a with or catch context. | 730 // Check that we're not inside a with or catch context. |
716 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); | 731 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); |
717 __ cmp(ebx, isolate()->factory()->with_context_map()); | 732 __ cmp(ebx, isolate()->factory()->with_context_map()); |
718 __ Check(not_equal, "Declaration in with context."); | 733 __ Check(not_equal, "Declaration in with context."); |
719 __ cmp(ebx, isolate()->factory()->catch_context_map()); | 734 __ cmp(ebx, isolate()->factory()->catch_context_map()); |
720 __ Check(not_equal, "Declaration in catch context."); | 735 __ Check(not_equal, "Declaration in catch context."); |
721 } | 736 } |
722 if (function != NULL) { | 737 if (function != NULL) { |
| 738 Comment cmnt(masm_, "[ Declaration"); |
723 VisitForAccumulatorValue(function); | 739 VisitForAccumulatorValue(function); |
724 __ mov(ContextOperand(esi, slot->index()), result_register()); | 740 __ mov(ContextOperand(esi, variable->index()), result_register()); |
725 int offset = Context::SlotOffset(slot->index()); | 741 int offset = Context::SlotOffset(variable->index()); |
726 __ mov(ebx, esi); | 742 __ mov(ebx, esi); |
727 __ RecordWrite(ebx, offset, result_register(), ecx); | 743 __ RecordWrite(ebx, offset, result_register(), ecx); |
728 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 744 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
729 } else if (mode == Variable::CONST || mode == Variable::LET) { | 745 } else if (mode == Variable::CONST || mode == Variable::LET) { |
730 __ mov(ContextOperand(esi, slot->index()), | 746 Comment cmnt(masm_, "[ Declaration"); |
| 747 __ mov(ContextOperand(esi, variable->index()), |
731 Immediate(isolate()->factory()->the_hole_value())); | 748 Immediate(isolate()->factory()->the_hole_value())); |
732 // No write barrier since the hole value is in old space. | 749 // No write barrier since the hole value is in old space. |
733 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 750 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
734 } | 751 } |
735 break; | 752 break; |
736 | 753 |
737 case Slot::LOOKUP: { | 754 case Variable::LOOKUP: { |
| 755 Comment cmnt(masm_, "[ Declaration"); |
738 __ push(esi); | 756 __ push(esi); |
739 __ push(Immediate(variable->name())); | 757 __ push(Immediate(variable->name())); |
740 // Declaration nodes are always introduced in one of two modes. | 758 // Declaration nodes are always introduced in one of three modes. |
741 ASSERT(mode == Variable::VAR || | 759 ASSERT(mode == Variable::VAR || |
742 mode == Variable::CONST || | 760 mode == Variable::CONST || |
743 mode == Variable::LET); | 761 mode == Variable::LET); |
744 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; | 762 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; |
745 __ push(Immediate(Smi::FromInt(attr))); | 763 __ push(Immediate(Smi::FromInt(attr))); |
746 // Push initial value, if any. | 764 // Push initial value, if any. |
747 // Note: For variables we must not push an initial value (such as | 765 // Note: For variables we must not push an initial value (such as |
748 // 'undefined') because we may have a (legal) redeclaration and we | 766 // 'undefined') because we may have a (legal) redeclaration and we |
749 // must not destroy the current value. | 767 // must not destroy the current value. |
750 increment_stack_height(3); | 768 increment_stack_height(3); |
751 if (function != NULL) { | 769 if (function != NULL) { |
752 VisitForStackValue(function); | 770 VisitForStackValue(function); |
753 } else if (mode == Variable::CONST || mode == Variable::LET) { | 771 } else if (mode == Variable::CONST || mode == Variable::LET) { |
754 __ push(Immediate(isolate()->factory()->the_hole_value())); | 772 __ push(Immediate(isolate()->factory()->the_hole_value())); |
755 increment_stack_height(); | 773 increment_stack_height(); |
756 } else { | 774 } else { |
757 __ push(Immediate(Smi::FromInt(0))); // No initial value! | 775 __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value. |
758 increment_stack_height(); | 776 increment_stack_height(); |
759 } | 777 } |
760 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 778 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
761 decrement_stack_height(4); | 779 decrement_stack_height(4); |
762 break; | 780 break; |
763 } | 781 } |
764 } | 782 } |
765 } | 783 } |
766 | 784 |
767 | 785 |
768 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 786 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { } |
769 EmitDeclaration(decl->proxy(), decl->mode(), decl->fun()); | |
770 } | |
771 | 787 |
772 | 788 |
773 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 789 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
774 // Call the runtime to declare the globals. | 790 // Call the runtime to declare the globals. |
775 __ push(esi); // The context is the first argument. | 791 __ push(esi); // The context is the first argument. |
776 __ push(Immediate(pairs)); | 792 __ push(Immediate(pairs)); |
777 __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags()))); | 793 __ push(Immediate(Smi::FromInt(DeclareGlobalsFlags()))); |
778 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 794 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
779 // Return value is ignored. | 795 // Return value is ignored. |
780 } | 796 } |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1067 context()->Plug(eax); | 1083 context()->Plug(eax); |
1068 } | 1084 } |
1069 | 1085 |
1070 | 1086 |
1071 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 1087 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
1072 Comment cmnt(masm_, "[ VariableProxy"); | 1088 Comment cmnt(masm_, "[ VariableProxy"); |
1073 EmitVariableLoad(expr); | 1089 EmitVariableLoad(expr); |
1074 } | 1090 } |
1075 | 1091 |
1076 | 1092 |
1077 void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( | 1093 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, |
1078 Slot* slot, | 1094 TypeofState typeof_state, |
1079 TypeofState typeof_state, | 1095 Label* slow) { |
1080 Label* slow) { | |
1081 Register context = esi; | 1096 Register context = esi; |
1082 Register temp = edx; | 1097 Register temp = edx; |
1083 | 1098 |
1084 Scope* s = scope(); | 1099 Scope* s = scope(); |
1085 while (s != NULL) { | 1100 while (s != NULL) { |
1086 if (s->num_heap_slots() > 0) { | 1101 if (s->num_heap_slots() > 0) { |
1087 if (s->calls_eval()) { | 1102 if (s->calls_eval()) { |
1088 // Check that extension is NULL. | 1103 // Check that extension is NULL. |
1089 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), | 1104 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), |
1090 Immediate(0)); | 1105 Immediate(0)); |
(...skipping 28 matching lines...) Expand all Loading... |
1119 __ j(not_equal, slow); | 1134 __ j(not_equal, slow); |
1120 // Load next context in chain. | 1135 // Load next context in chain. |
1121 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX)); | 1136 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX)); |
1122 __ jmp(&next); | 1137 __ jmp(&next); |
1123 __ bind(&fast); | 1138 __ bind(&fast); |
1124 } | 1139 } |
1125 | 1140 |
1126 // All extension objects were empty and it is safe to use a global | 1141 // All extension objects were empty and it is safe to use a global |
1127 // load IC call. | 1142 // load IC call. |
1128 __ mov(eax, GlobalObjectOperand()); | 1143 __ mov(eax, GlobalObjectOperand()); |
1129 __ mov(ecx, slot->var()->name()); | 1144 __ mov(ecx, var->name()); |
1130 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1145 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
1131 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 1146 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
1132 ? RelocInfo::CODE_TARGET | 1147 ? RelocInfo::CODE_TARGET |
1133 : RelocInfo::CODE_TARGET_CONTEXT; | 1148 : RelocInfo::CODE_TARGET_CONTEXT; |
1134 __ call(ic, mode); | 1149 __ call(ic, mode); |
1135 } | 1150 } |
1136 | 1151 |
1137 | 1152 |
1138 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( | 1153 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, |
1139 Slot* slot, | 1154 Label* slow) { |
1140 Label* slow) { | 1155 ASSERT(var->IsContextSlot()); |
1141 ASSERT(slot->type() == Slot::CONTEXT); | |
1142 Register context = esi; | 1156 Register context = esi; |
1143 Register temp = ebx; | 1157 Register temp = ebx; |
1144 | 1158 |
1145 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { | 1159 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { |
1146 if (s->num_heap_slots() > 0) { | 1160 if (s->num_heap_slots() > 0) { |
1147 if (s->calls_eval()) { | 1161 if (s->calls_eval()) { |
1148 // Check that extension is NULL. | 1162 // Check that extension is NULL. |
1149 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), | 1163 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), |
1150 Immediate(0)); | 1164 Immediate(0)); |
1151 __ j(not_equal, slow); | 1165 __ j(not_equal, slow); |
1152 } | 1166 } |
1153 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); | 1167 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); |
1154 // Walk the rest of the chain without clobbering esi. | 1168 // Walk the rest of the chain without clobbering esi. |
1155 context = temp; | 1169 context = temp; |
1156 } | 1170 } |
1157 } | 1171 } |
1158 // Check that last extension is NULL. | 1172 // Check that last extension is NULL. |
1159 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); | 1173 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); |
1160 __ j(not_equal, slow); | 1174 __ j(not_equal, slow); |
1161 | 1175 |
1162 // This function is used only for loads, not stores, so it's safe to | 1176 // This function is used only for loads, not stores, so it's safe to |
1163 // return an esi-based operand (the write barrier cannot be allowed to | 1177 // return an esi-based operand (the write barrier cannot be allowed to |
1164 // destroy the esi register). | 1178 // destroy the esi register). |
1165 return ContextOperand(context, slot->index()); | 1179 return ContextOperand(context, var->index()); |
1166 } | 1180 } |
1167 | 1181 |
1168 | 1182 |
1169 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( | 1183 void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, |
1170 Slot* slot, | 1184 TypeofState typeof_state, |
1171 TypeofState typeof_state, | 1185 Label* slow, |
1172 Label* slow, | 1186 Label* done) { |
1173 Label* done) { | |
1174 // Generate fast-case code for variables that might be shadowed by | 1187 // Generate fast-case code for variables that might be shadowed by |
1175 // eval-introduced variables. Eval is used a lot without | 1188 // eval-introduced variables. Eval is used a lot without |
1176 // introducing variables. In those cases, we do not want to | 1189 // introducing variables. In those cases, we do not want to |
1177 // perform a runtime call for all variables in the scope | 1190 // perform a runtime call for all variables in the scope |
1178 // containing the eval. | 1191 // containing the eval. |
1179 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) { | 1192 if (var->mode() == Variable::DYNAMIC_GLOBAL) { |
1180 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow); | 1193 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
1181 __ jmp(done); | 1194 __ jmp(done); |
1182 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) { | 1195 } else if (var->mode() == Variable::DYNAMIC_LOCAL) { |
1183 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot(); | 1196 Variable* local = var->local_if_not_shadowed(); |
1184 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite(); | 1197 __ mov(eax, ContextSlotOperandCheckExtensions(local, slow)); |
1185 if (potential_slot != NULL) { | 1198 if (local->mode() == Variable::CONST) { |
1186 // Generate fast case for locals that rewrite to slots. | 1199 __ cmp(eax, isolate()->factory()->the_hole_value()); |
1187 __ mov(eax, | 1200 __ j(not_equal, done); |
1188 ContextSlotOperandCheckExtensions(potential_slot, slow)); | 1201 __ mov(eax, isolate()->factory()->undefined_value()); |
1189 if (potential_slot->var()->mode() == Variable::CONST) { | |
1190 __ cmp(eax, isolate()->factory()->the_hole_value()); | |
1191 __ j(not_equal, done); | |
1192 __ mov(eax, isolate()->factory()->undefined_value()); | |
1193 } | |
1194 __ jmp(done); | |
1195 } else if (rewrite != NULL) { | |
1196 // Generate fast case for calls of an argument function. | |
1197 Property* property = rewrite->AsProperty(); | |
1198 if (property != NULL) { | |
1199 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | |
1200 Literal* key_literal = property->key()->AsLiteral(); | |
1201 if (obj_proxy != NULL && | |
1202 key_literal != NULL && | |
1203 obj_proxy->IsArguments() && | |
1204 key_literal->handle()->IsSmi()) { | |
1205 // Load arguments object if there are no eval-introduced | |
1206 // variables. Then load the argument from the arguments | |
1207 // object using keyed load. | |
1208 __ mov(edx, | |
1209 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), | |
1210 slow)); | |
1211 __ SafeSet(eax, Immediate(key_literal->handle())); | |
1212 Handle<Code> ic = | |
1213 isolate()->builtins()->KeyedLoadIC_Initialize(); | |
1214 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | |
1215 __ jmp(done); | |
1216 } | |
1217 } | |
1218 } | 1202 } |
| 1203 __ jmp(done); |
1219 } | 1204 } |
1220 } | 1205 } |
1221 | 1206 |
1222 | 1207 |
1223 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1208 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
1224 // Record position before possible IC call. | 1209 // Record position before possible IC call. |
1225 SetSourcePosition(proxy->position()); | 1210 SetSourcePosition(proxy->position()); |
1226 Variable* var = proxy->var(); | 1211 Variable* var = proxy->var(); |
1227 | 1212 |
1228 // Three cases: non-this global variables, lookup slots, and all other | 1213 // Three cases: global variables, lookup variables, and all other types of |
1229 // types of slots. | 1214 // variables. |
1230 Slot* slot = var->AsSlot(); | 1215 switch (var->location()) { |
1231 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); | 1216 case Variable::UNALLOCATED: { |
| 1217 Comment cmnt(masm_, "Global variable"); |
| 1218 // Use inline caching. Variable name is passed in ecx and the global |
| 1219 // object in eax. |
| 1220 __ mov(eax, GlobalObjectOperand()); |
| 1221 __ mov(ecx, var->name()); |
| 1222 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1223 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1224 context()->Plug(eax); |
| 1225 break; |
| 1226 } |
1232 | 1227 |
1233 if (slot == NULL) { | 1228 case Variable::PARAMETER: |
1234 Comment cmnt(masm_, "Global variable"); | 1229 case Variable::LOCAL: |
1235 // Use inline caching. Variable name is passed in ecx and the global | 1230 case Variable::CONTEXT: { |
1236 // object on the stack. | 1231 Comment cmnt(masm_, var->IsContextSlot() |
1237 __ mov(eax, GlobalObjectOperand()); | 1232 ? "Context variable" |
1238 __ mov(ecx, var->name()); | 1233 : "Stack variable"); |
1239 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1234 if (var->mode() != Variable::LET && var->mode() != Variable::CONST) { |
1240 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1235 context()->Plug(var); |
1241 context()->Plug(eax); | 1236 } else { |
| 1237 // Let and const need a read barrier. |
| 1238 Label done; |
| 1239 GetVar(eax, var); |
| 1240 __ cmp(eax, isolate()->factory()->the_hole_value()); |
| 1241 __ j(not_equal, &done, Label::kNear); |
| 1242 if (var->mode() == Variable::LET) { |
| 1243 __ push(Immediate(var->name())); |
| 1244 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 1245 } else { // Variable::CONST |
| 1246 __ mov(eax, isolate()->factory()->undefined_value()); |
| 1247 } |
| 1248 __ bind(&done); |
| 1249 context()->Plug(eax); |
| 1250 } |
| 1251 break; |
| 1252 } |
1242 | 1253 |
1243 } else if (slot->type() == Slot::LOOKUP) { | 1254 case Variable::LOOKUP: { |
1244 Label done, slow; | 1255 Label done, slow; |
1245 | 1256 // Generate code for loading from variables potentially shadowed |
1246 // Generate code for loading from variables potentially shadowed | 1257 // by eval-introduced variables. |
1247 // by eval-introduced variables. | 1258 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); |
1248 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1259 __ bind(&slow); |
1249 | 1260 Comment cmnt(masm_, "Lookup variable"); |
1250 __ bind(&slow); | 1261 __ push(esi); // Context. |
1251 Comment cmnt(masm_, "Lookup slot"); | 1262 __ push(Immediate(var->name())); |
1252 __ push(esi); // Context. | 1263 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
1253 __ push(Immediate(var->name())); | |
1254 __ CallRuntime(Runtime::kLoadContextSlot, 2); | |
1255 __ bind(&done); | |
1256 | |
1257 context()->Plug(eax); | |
1258 | |
1259 } else { | |
1260 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | |
1261 ? "Context slot" | |
1262 : "Stack slot"); | |
1263 if (var->mode() == Variable::CONST) { | |
1264 // Constants may be the hole value if they have not been initialized. | |
1265 // Unhole them. | |
1266 Label done; | |
1267 MemOperand slot_operand = EmitSlotSearch(slot, eax); | |
1268 __ mov(eax, slot_operand); | |
1269 __ cmp(eax, isolate()->factory()->the_hole_value()); | |
1270 __ j(not_equal, &done, Label::kNear); | |
1271 __ mov(eax, isolate()->factory()->undefined_value()); | |
1272 __ bind(&done); | 1264 __ bind(&done); |
1273 context()->Plug(eax); | 1265 context()->Plug(eax); |
1274 } else if (var->mode() == Variable::LET) { | 1266 break; |
1275 // Let bindings may be the hole value if they have not been initialized. | |
1276 // Throw a type error in this case. | |
1277 Label done; | |
1278 MemOperand slot_operand = EmitSlotSearch(slot, eax); | |
1279 __ mov(eax, slot_operand); | |
1280 __ cmp(eax, isolate()->factory()->the_hole_value()); | |
1281 __ j(not_equal, &done, Label::kNear); | |
1282 __ push(Immediate(var->name())); | |
1283 __ CallRuntime(Runtime::kThrowReferenceError, 1); | |
1284 __ bind(&done); | |
1285 context()->Plug(eax); | |
1286 } else { | |
1287 context()->Plug(slot); | |
1288 } | 1267 } |
1289 } | 1268 } |
1290 } | 1269 } |
1291 | 1270 |
1292 | 1271 |
1293 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1272 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
1294 Comment cmnt(masm_, "[ RegExpLiteral"); | 1273 Comment cmnt(masm_, "[ RegExpLiteral"); |
1295 Label materialized; | 1274 Label materialized; |
1296 // Registers will be used as follows: | 1275 // Registers will be used as follows: |
1297 // edi = JS function. | 1276 // edi = JS function. |
(...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1820 break; | 1799 break; |
1821 } | 1800 } |
1822 } | 1801 } |
1823 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1802 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
1824 context()->Plug(eax); | 1803 context()->Plug(eax); |
1825 } | 1804 } |
1826 | 1805 |
1827 | 1806 |
1828 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1807 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
1829 Token::Value op) { | 1808 Token::Value op) { |
1830 ASSERT(var != NULL); | 1809 if (var->IsUnallocated()) { |
1831 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1810 // Global var, const, or let. |
1832 | |
1833 if (var->is_global()) { | |
1834 ASSERT(!var->is_this()); | |
1835 // Assignment to a global variable. Use inline caching for the | |
1836 // assignment. Right-hand-side value is passed in eax, variable name in | |
1837 // ecx, and the global object on the stack. | |
1838 __ mov(ecx, var->name()); | 1811 __ mov(ecx, var->name()); |
1839 __ mov(edx, GlobalObjectOperand()); | 1812 __ mov(edx, GlobalObjectOperand()); |
1840 Handle<Code> ic = is_strict_mode() | 1813 Handle<Code> ic = is_strict_mode() |
1841 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1814 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
1842 : isolate()->builtins()->StoreIC_Initialize(); | 1815 : isolate()->builtins()->StoreIC_Initialize(); |
1843 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1816 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
1844 | 1817 |
1845 } else if (op == Token::INIT_CONST) { | 1818 } else if (op == Token::INIT_CONST) { |
1846 // Like var declarations, const declarations are hoisted to function | 1819 // Const initializers need a write barrier. |
1847 // scope. However, unlike var initializers, const initializers are able | 1820 ASSERT(!var->IsParameter()); // No const parameters. |
1848 // to drill a hole to that function context, even from inside a 'with' | 1821 if (var->IsStackLocal()) { |
1849 // context. We thus bypass the normal static scope lookup. | 1822 Label skip; |
1850 Slot* slot = var->AsSlot(); | 1823 __ mov(edx, StackOperand(var)); |
1851 Label skip; | 1824 __ cmp(edx, isolate()->factory()->the_hole_value()); |
1852 switch (slot->type()) { | 1825 __ j(not_equal, &skip); |
1853 case Slot::PARAMETER: | 1826 __ mov(StackOperand(var), eax); |
1854 // No const parameters. | 1827 __ bind(&skip); |
1855 UNREACHABLE(); | 1828 } else { |
1856 break; | 1829 ASSERT(var->IsContextSlot() || var->IsLookupSlot()); |
1857 case Slot::LOCAL: | 1830 // Like var declarations, const declarations are hoisted to function |
1858 __ mov(edx, Operand(ebp, SlotOffset(slot))); | 1831 // scope. However, unlike var initializers, const initializers are |
1859 __ cmp(edx, isolate()->factory()->the_hole_value()); | 1832 // able to drill a hole to that function context, even from inside a |
1860 __ j(not_equal, &skip); | 1833 // 'with' context. We thus bypass the normal static scope lookup for |
1861 __ mov(Operand(ebp, SlotOffset(slot)), eax); | 1834 // var->IsContextSlot(). |
1862 break; | 1835 __ push(eax); |
1863 case Slot::CONTEXT: | 1836 __ push(esi); |
1864 case Slot::LOOKUP: | 1837 __ push(Immediate(var->name())); |
1865 __ push(eax); | 1838 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
1866 __ push(esi); | |
1867 __ push(Immediate(var->name())); | |
1868 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
1869 break; | |
1870 } | 1839 } |
1871 __ bind(&skip); | |
1872 | 1840 |
1873 } else if (var->mode() == Variable::LET && op != Token::INIT_LET) { | 1841 } else if (var->mode() == Variable::LET && op != Token::INIT_LET) { |
1874 // Perform the assignment for non-const variables. Const assignments | 1842 // Non-initializing assignment to let variable needs a write barrier. |
1875 // are simply skipped. | 1843 if (var->IsLookupSlot()) { |
1876 Slot* slot = var->AsSlot(); | 1844 __ push(eax); // Value. |
1877 switch (slot->type()) { | 1845 __ push(esi); // Context. |
1878 case Slot::PARAMETER: | 1846 __ push(Immediate(var->name())); |
1879 case Slot::LOCAL: { | 1847 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
1880 Label assign; | 1848 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1881 // Check for an initialized let binding. | 1849 } else { |
1882 __ mov(edx, Operand(ebp, SlotOffset(slot))); | 1850 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
1883 __ cmp(edx, isolate()->factory()->the_hole_value()); | 1851 Label assign; |
1884 __ j(not_equal, &assign); | 1852 MemOperand location = VarOperand(var, ecx); |
1885 __ push(Immediate(var->name())); | 1853 __ mov(edx, location); |
1886 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1854 __ cmp(edx, isolate()->factory()->the_hole_value()); |
1887 // Perform the assignment. | 1855 __ j(not_equal, &assign, Label::kNear); |
1888 __ bind(&assign); | 1856 __ push(Immediate(var->name())); |
1889 __ mov(Operand(ebp, SlotOffset(slot)), eax); | 1857 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1890 break; | 1858 __ bind(&assign); |
| 1859 __ mov(location, eax); |
| 1860 if (var->IsContextSlot()) { |
| 1861 __ mov(edx, eax); |
| 1862 __ RecordWrite(ecx, Context::SlotOffset(var->index()), edx, ebx); |
1891 } | 1863 } |
| 1864 } |
1892 | 1865 |
1893 case Slot::CONTEXT: { | |
1894 // Let variables may be the hole value if they have not been | |
1895 // initialized. Throw a type error in this case. | |
1896 Label assign; | |
1897 MemOperand target = EmitSlotSearch(slot, ecx); | |
1898 // Check for an initialized let binding. | |
1899 __ mov(edx, target); | |
1900 __ cmp(edx, isolate()->factory()->the_hole_value()); | |
1901 __ j(not_equal, &assign, Label::kNear); | |
1902 __ push(Immediate(var->name())); | |
1903 __ CallRuntime(Runtime::kThrowReferenceError, 1); | |
1904 // Perform the assignment. | |
1905 __ bind(&assign); | |
1906 __ mov(target, eax); | |
1907 // The value of the assignment is in eax. RecordWrite clobbers its | |
1908 // register arguments. | |
1909 __ mov(edx, eax); | |
1910 int offset = Context::SlotOffset(slot->index()); | |
1911 __ RecordWrite(ecx, offset, edx, ebx); | |
1912 break; | |
1913 } | |
1914 | |
1915 case Slot::LOOKUP: | |
1916 // Call the runtime for the assignment. | |
1917 __ push(eax); // Value. | |
1918 __ push(esi); // Context. | |
1919 __ push(Immediate(var->name())); | |
1920 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | |
1921 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
1922 break; | |
1923 } | |
1924 } else if (var->mode() != Variable::CONST) { | 1866 } else if (var->mode() != Variable::CONST) { |
1925 // Perform the assignment for non-const variables. Const assignments | 1867 // Assignment to var or initializing assignment to let. |
1926 // are simply skipped. | 1868 if (var->IsStackAllocated()) { |
1927 Slot* slot = var->AsSlot(); | 1869 __ mov(StackOperand(var), eax); |
1928 switch (slot->type()) { | 1870 } else if (var->IsContextSlot()) { |
1929 case Slot::PARAMETER: | 1871 // Preserve the value in eax against the write barrier. |
1930 case Slot::LOCAL: | 1872 __ mov(edx, eax); |
1931 // Perform the assignment. | 1873 SetVar(var, edx, ecx, ebx); |
1932 __ mov(Operand(ebp, SlotOffset(slot)), eax); | 1874 } else { |
1933 break; | 1875 ASSERT(var->IsLookupSlot()); |
1934 | 1876 __ push(eax); // Value. |
1935 case Slot::CONTEXT: { | 1877 __ push(esi); // Context. |
1936 MemOperand target = EmitSlotSearch(slot, ecx); | 1878 __ push(Immediate(var->name())); |
1937 // Perform the assignment and issue the write barrier. | 1879 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
1938 __ mov(target, eax); | 1880 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1939 // The value of the assignment is in eax. RecordWrite clobbers its | |
1940 // register arguments. | |
1941 __ mov(edx, eax); | |
1942 int offset = Context::SlotOffset(slot->index()); | |
1943 __ RecordWrite(ecx, offset, edx, ebx); | |
1944 break; | |
1945 } | |
1946 | |
1947 case Slot::LOOKUP: | |
1948 // Call the runtime for the assignment. | |
1949 __ push(eax); // Value. | |
1950 __ push(esi); // Context. | |
1951 __ push(Immediate(var->name())); | |
1952 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | |
1953 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
1954 break; | |
1955 } | 1881 } |
1956 } | 1882 } |
| 1883 // Non-initializing assignments to consts are ignored. |
1957 } | 1884 } |
1958 | 1885 |
1959 | 1886 |
1960 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1887 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
1961 // Assignment to a property, using a named store IC. | 1888 // Assignment to a property, using a named store IC. |
1962 Property* prop = expr->target()->AsProperty(); | 1889 Property* prop = expr->target()->AsProperty(); |
1963 ASSERT(prop != NULL); | 1890 ASSERT(prop != NULL); |
1964 ASSERT(prop->key()->AsLiteral() != NULL); | 1891 ASSERT(prop->key()->AsLiteral() != NULL); |
1965 | 1892 |
1966 // If the assignment starts a block of assignments to the same object, | 1893 // If the assignment starts a block of assignments to the same object, |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2175 | 2102 |
2176 | 2103 |
2177 void FullCodeGenerator::VisitCall(Call* expr) { | 2104 void FullCodeGenerator::VisitCall(Call* expr) { |
2178 #ifdef DEBUG | 2105 #ifdef DEBUG |
2179 // We want to verify that RecordJSReturnSite gets called on all paths | 2106 // We want to verify that RecordJSReturnSite gets called on all paths |
2180 // through this function. Avoid early returns. | 2107 // through this function. Avoid early returns. |
2181 expr->return_is_recorded_ = false; | 2108 expr->return_is_recorded_ = false; |
2182 #endif | 2109 #endif |
2183 | 2110 |
2184 Comment cmnt(masm_, "[ Call"); | 2111 Comment cmnt(masm_, "[ Call"); |
2185 Expression* fun = expr->expression(); | 2112 Expression* callee = expr->expression(); |
2186 Variable* var = fun->AsVariableProxy()->AsVariable(); | 2113 VariableProxy* proxy = callee->AsVariableProxy(); |
| 2114 Property* property = callee->AsProperty(); |
2187 | 2115 |
2188 if (var != NULL && var->is_possibly_eval()) { | 2116 if (proxy != NULL && proxy->var()->is_possibly_eval()) { |
2189 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 2117 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
2190 // resolve the function we need to call and the receiver of the | 2118 // resolve the function we need to call and the receiver of the call. |
2191 // call. Then we call the resolved function using the given | 2119 // Then we call the resolved function using the given arguments. |
2192 // arguments. | |
2193 ZoneList<Expression*>* args = expr->arguments(); | 2120 ZoneList<Expression*>* args = expr->arguments(); |
2194 int arg_count = args->length(); | 2121 int arg_count = args->length(); |
2195 { PreservePositionScope pos_scope(masm()->positions_recorder()); | 2122 { PreservePositionScope pos_scope(masm()->positions_recorder()); |
2196 VisitForStackValue(fun); | 2123 VisitForStackValue(callee); |
2197 // Reserved receiver slot. | 2124 // Reserved receiver slot. |
2198 __ push(Immediate(isolate()->factory()->undefined_value())); | 2125 __ push(Immediate(isolate()->factory()->undefined_value())); |
2199 increment_stack_height(); | 2126 increment_stack_height(); |
2200 // Push the arguments. | 2127 // Push the arguments. |
2201 for (int i = 0; i < arg_count; i++) { | 2128 for (int i = 0; i < arg_count; i++) { |
2202 VisitForStackValue(args->at(i)); | 2129 VisitForStackValue(args->at(i)); |
2203 } | 2130 } |
2204 | 2131 |
2205 // If we know that eval can only be shadowed by eval-introduced | 2132 // If we know that eval can only be shadowed by eval-introduced |
2206 // variables we attempt to load the global eval function directly | 2133 // variables we attempt to load the global eval function directly in |
2207 // in generated code. If we succeed, there is no need to perform a | 2134 // generated code. If we succeed, there is no need to perform a |
2208 // context lookup in the runtime system. | 2135 // context lookup in the runtime system. |
2209 Label done; | 2136 Label done; |
2210 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { | 2137 Variable* var = proxy->var(); |
| 2138 if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) { |
2211 Label slow; | 2139 Label slow; |
2212 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), | 2140 EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); |
2213 NOT_INSIDE_TYPEOF, | |
2214 &slow); | |
2215 // Push the function and resolve eval. | 2141 // Push the function and resolve eval. |
2216 __ push(eax); | 2142 __ push(eax); |
2217 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); | 2143 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); |
2218 __ jmp(&done); | 2144 __ jmp(&done); |
2219 __ bind(&slow); | 2145 __ bind(&slow); |
2220 } | 2146 } |
2221 | 2147 |
2222 // Push copy of the function (found below the arguments) and | 2148 // Push a copy of the function (found below the arguments) and |
2223 // resolve eval. | 2149 // resolve eval. |
2224 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); | 2150 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); |
2225 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count); | 2151 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count); |
2226 if (done.is_linked()) { | 2152 __ bind(&done); |
2227 __ bind(&done); | |
2228 } | |
2229 | 2153 |
2230 // The runtime call returns a pair of values in eax (function) and | 2154 // The runtime call returns a pair of values in eax (function) and |
2231 // edx (receiver). Touch up the stack with the right values. | 2155 // edx (receiver). Touch up the stack with the right values. |
2232 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); | 2156 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); |
2233 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); | 2157 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); |
2234 } | 2158 } |
2235 // Record source position for debugger. | 2159 // Record source position for debugger. |
2236 SetSourcePosition(expr->position()); | 2160 SetSourcePosition(expr->position()); |
2237 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2161 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
2238 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT); | 2162 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT); |
2239 __ CallStub(&stub); | 2163 __ CallStub(&stub); |
2240 RecordJSReturnSite(expr); | 2164 RecordJSReturnSite(expr); |
2241 // Restore context register. | 2165 // Restore context register. |
2242 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2166 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
2243 decrement_stack_height(arg_count + 1); // Function is left on the stack. | 2167 decrement_stack_height(arg_count + 1); // Function is left on the stack. |
2244 context()->DropAndPlug(1, eax); | 2168 context()->DropAndPlug(1, eax); |
2245 } else if (var != NULL && !var->is_this() && var->is_global()) { | 2169 |
| 2170 } else if (proxy != NULL && proxy->var()->IsUnallocated()) { |
2246 // Push global object as receiver for the call IC. | 2171 // Push global object as receiver for the call IC. |
2247 __ push(GlobalObjectOperand()); | 2172 __ push(GlobalObjectOperand()); |
2248 increment_stack_height(); | 2173 increment_stack_height(); |
2249 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); | 2174 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); |
2250 } else if (var != NULL && var->AsSlot() != NULL && | 2175 |
2251 var->AsSlot()->type() == Slot::LOOKUP) { | 2176 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { |
2252 // Call to a lookup slot (dynamically introduced variable). | 2177 // Call to a lookup slot (dynamically introduced variable). |
2253 Label slow, done; | 2178 Label slow, done; |
2254 | |
2255 { PreservePositionScope scope(masm()->positions_recorder()); | 2179 { PreservePositionScope scope(masm()->positions_recorder()); |
2256 // Generate code for loading from variables potentially shadowed | 2180 // Generate code for loading from variables potentially shadowed by |
2257 // by eval-introduced variables. | 2181 // eval-introduced variables. |
2258 EmitDynamicLoadFromSlotFastCase(var->AsSlot(), | 2182 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); |
2259 NOT_INSIDE_TYPEOF, | |
2260 &slow, | |
2261 &done); | |
2262 } | 2183 } |
2263 | |
2264 __ bind(&slow); | 2184 __ bind(&slow); |
2265 // Call the runtime to find the function to call (returned in eax) | 2185 // Call the runtime to find the function to call (returned in eax) and |
2266 // and the object holding it (returned in edx). | 2186 // the object holding it (returned in edx). |
2267 __ push(context_register()); | 2187 __ push(context_register()); |
2268 __ push(Immediate(var->name())); | 2188 __ push(Immediate(proxy->name())); |
2269 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2189 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
2270 __ push(eax); // Function. | 2190 __ push(eax); // Function. |
2271 increment_stack_height(); | |
2272 __ push(edx); // Receiver. | 2191 __ push(edx); // Receiver. |
2273 increment_stack_height(); | 2192 increment_stack_height(2); |
2274 | 2193 |
2275 // If fast case code has been generated, emit code to push the | 2194 // If fast case code has been generated, emit code to push the function |
2276 // function and receiver and have the slow path jump around this | 2195 // and receiver and have the slow path jump around this code. |
2277 // code. | |
2278 if (done.is_linked()) { | 2196 if (done.is_linked()) { |
2279 Label call; | 2197 Label call; |
2280 __ jmp(&call); | 2198 __ jmp(&call, Label::kNear); |
2281 __ bind(&done); | 2199 __ bind(&done); |
2282 // Push function. Stack height already incremented in slow case above. | 2200 // Push function. Stack height already incremented in slow case |
| 2201 // above. |
2283 __ push(eax); | 2202 __ push(eax); |
2284 // The receiver is implicitly the global receiver. Indicate this | 2203 // The receiver is implicitly the global receiver. Indicate this by |
2285 // by passing the hole to the call function stub. | 2204 // passing the hole to the call function stub. |
2286 __ push(Immediate(isolate()->factory()->the_hole_value())); | 2205 __ push(Immediate(isolate()->factory()->the_hole_value())); |
2287 __ bind(&call); | 2206 __ bind(&call); |
2288 } | 2207 } |
2289 | 2208 |
2290 // The receiver is either the global receiver or an object found | 2209 // The receiver is either the global receiver or an object found by |
2291 // by LoadContextSlot. That object could be the hole if the | 2210 // LoadContextSlot. That object could be the hole if the receiver is |
2292 // receiver is implicitly the global object. | 2211 // implicitly the global object. |
2293 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); | 2212 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); |
2294 } else if (fun->AsProperty() != NULL) { | 2213 |
2295 // Call to an object property. | 2214 } else if (property != NULL) { |
2296 Property* prop = fun->AsProperty(); | 2215 { PreservePositionScope scope(masm()->positions_recorder()); |
2297 Literal* key = prop->key()->AsLiteral(); | 2216 VisitForStackValue(property->obj()); |
2298 if (key != NULL && key->handle()->IsSymbol()) { | 2217 } |
2299 // Call to a named property, use call IC. | 2218 if (property->key()->IsPropertyName()) { |
2300 { PreservePositionScope scope(masm()->positions_recorder()); | 2219 EmitCallWithIC(expr, |
2301 VisitForStackValue(prop->obj()); | 2220 property->key()->AsLiteral()->handle(), |
2302 } | 2221 RelocInfo::CODE_TARGET); |
2303 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | |
2304 } else { | 2222 } else { |
2305 // Call to a keyed property. | 2223 EmitKeyedCallWithIC(expr, property->key()); |
2306 { PreservePositionScope scope(masm()->positions_recorder()); | |
2307 VisitForStackValue(prop->obj()); | |
2308 } | |
2309 EmitKeyedCallWithIC(expr, prop->key()); | |
2310 } | 2224 } |
| 2225 |
2311 } else { | 2226 } else { |
| 2227 // Call to an arbitrary expression not handled specially above. |
2312 { PreservePositionScope scope(masm()->positions_recorder()); | 2228 { PreservePositionScope scope(masm()->positions_recorder()); |
2313 VisitForStackValue(fun); | 2229 VisitForStackValue(callee); |
2314 } | 2230 } |
2315 // Load global receiver object. | 2231 // Load global receiver object. |
2316 __ mov(ebx, GlobalObjectOperand()); | 2232 __ mov(ebx, GlobalObjectOperand()); |
2317 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 2233 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); |
2318 increment_stack_height(); | 2234 increment_stack_height(); |
2319 // Emit function call. | 2235 // Emit function call. |
2320 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); | 2236 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); |
2321 } | 2237 } |
2322 | 2238 |
2323 #ifdef DEBUG | 2239 #ifdef DEBUG |
(...skipping 1351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3675 } | 3591 } |
3676 | 3592 |
3677 context()->Plug(eax); | 3593 context()->Plug(eax); |
3678 } | 3594 } |
3679 | 3595 |
3680 | 3596 |
3681 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3597 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
3682 switch (expr->op()) { | 3598 switch (expr->op()) { |
3683 case Token::DELETE: { | 3599 case Token::DELETE: { |
3684 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3600 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
3685 Property* prop = expr->expression()->AsProperty(); | 3601 Property* property = expr->expression()->AsProperty(); |
3686 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); | 3602 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
3687 | 3603 |
3688 if (prop != NULL) { | 3604 if (property != NULL) { |
3689 VisitForStackValue(prop->obj()); | 3605 VisitForStackValue(property->obj()); |
3690 VisitForStackValue(prop->key()); | 3606 VisitForStackValue(property->key()); |
3691 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | 3607 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
3692 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3608 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
3693 decrement_stack_height(2); | 3609 decrement_stack_height(2); |
3694 context()->Plug(eax); | 3610 context()->Plug(eax); |
3695 } else if (var != NULL) { | 3611 } else if (proxy != NULL) { |
| 3612 Variable* var = proxy->var(); |
3696 // Delete of an unqualified identifier is disallowed in strict mode | 3613 // Delete of an unqualified identifier is disallowed in strict mode |
3697 // but "delete this" is. | 3614 // but "delete this" is allowed. |
3698 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); | 3615 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); |
3699 if (var->is_global()) { | 3616 if (var->IsUnallocated()) { |
3700 __ push(GlobalObjectOperand()); | 3617 __ push(GlobalObjectOperand()); |
3701 __ push(Immediate(var->name())); | 3618 __ push(Immediate(var->name())); |
3702 __ push(Immediate(Smi::FromInt(kNonStrictMode))); | 3619 __ push(Immediate(Smi::FromInt(kNonStrictMode))); |
3703 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3620 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
3704 context()->Plug(eax); | 3621 context()->Plug(eax); |
3705 } else if (var->AsSlot() != NULL && | 3622 } else if (var->IsStackAllocated() || var->IsContextSlot()) { |
3706 var->AsSlot()->type() != Slot::LOOKUP) { | 3623 // Result of deleting non-global variables is false. 'this' is |
3707 // Result of deleting non-global, non-dynamic variables is false. | 3624 // not really a variable, though we implement it as one. The |
3708 // The subexpression does not have side effects. | 3625 // subexpression does not have side effects. |
3709 context()->Plug(false); | 3626 context()->Plug(var->is_this()); |
3710 } else { | 3627 } else { |
3711 // Non-global variable. Call the runtime to try to delete from the | 3628 // Non-global variable. Call the runtime to try to delete from the |
3712 // context where the variable was introduced. | 3629 // context where the variable was introduced. |
3713 __ push(context_register()); | 3630 __ push(context_register()); |
3714 __ push(Immediate(var->name())); | 3631 __ push(Immediate(var->name())); |
3715 __ CallRuntime(Runtime::kDeleteContextSlot, 2); | 3632 __ CallRuntime(Runtime::kDeleteContextSlot, 2); |
3716 context()->Plug(eax); | 3633 context()->Plug(eax); |
3717 } | 3634 } |
3718 } else { | 3635 } else { |
3719 // Result of deleting non-property, non-variable reference is true. | 3636 // Result of deleting non-property, non-variable reference is true. |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3996 } | 3913 } |
3997 } | 3914 } |
3998 } | 3915 } |
3999 | 3916 |
4000 | 3917 |
4001 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 3918 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
4002 VariableProxy* proxy = expr->AsVariableProxy(); | 3919 VariableProxy* proxy = expr->AsVariableProxy(); |
4003 ASSERT(!context()->IsEffect()); | 3920 ASSERT(!context()->IsEffect()); |
4004 ASSERT(!context()->IsTest()); | 3921 ASSERT(!context()->IsTest()); |
4005 | 3922 |
4006 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3923 if (proxy != NULL && proxy->var()->IsUnallocated()) { |
4007 Comment cmnt(masm_, "Global variable"); | 3924 Comment cmnt(masm_, "Global variable"); |
4008 __ mov(eax, GlobalObjectOperand()); | 3925 __ mov(eax, GlobalObjectOperand()); |
4009 __ mov(ecx, Immediate(proxy->name())); | 3926 __ mov(ecx, Immediate(proxy->name())); |
4010 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 3927 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
4011 // Use a regular load, not a contextual load, to avoid a reference | 3928 // Use a regular load, not a contextual load, to avoid a reference |
4012 // error. | 3929 // error. |
4013 __ call(ic); | 3930 __ call(ic); |
4014 PrepareForBailout(expr, TOS_REG); | 3931 PrepareForBailout(expr, TOS_REG); |
4015 context()->Plug(eax); | 3932 context()->Plug(eax); |
4016 } else if (proxy != NULL && | 3933 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { |
4017 proxy->var()->AsSlot() != NULL && | |
4018 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | |
4019 Label done, slow; | 3934 Label done, slow; |
4020 | 3935 |
4021 // Generate code for loading from variables potentially shadowed | 3936 // Generate code for loading from variables potentially shadowed |
4022 // by eval-introduced variables. | 3937 // by eval-introduced variables. |
4023 Slot* slot = proxy->var()->AsSlot(); | 3938 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); |
4024 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); | |
4025 | 3939 |
4026 __ bind(&slow); | 3940 __ bind(&slow); |
4027 __ push(esi); | 3941 __ push(esi); |
4028 __ push(Immediate(proxy->name())); | 3942 __ push(Immediate(proxy->name())); |
4029 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3943 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
4030 PrepareForBailout(expr, TOS_REG); | 3944 PrepareForBailout(expr, TOS_REG); |
4031 __ bind(&done); | 3945 __ bind(&done); |
4032 | 3946 |
4033 context()->Plug(eax); | 3947 context()->Plug(eax); |
4034 } else { | 3948 } else { |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4331 __ add(Operand(edx), Immediate(masm_->CodeObject())); | 4245 __ add(Operand(edx), Immediate(masm_->CodeObject())); |
4332 __ jmp(Operand(edx)); | 4246 __ jmp(Operand(edx)); |
4333 } | 4247 } |
4334 | 4248 |
4335 | 4249 |
4336 #undef __ | 4250 #undef __ |
4337 | 4251 |
4338 } } // namespace v8::internal | 4252 } } // namespace v8::internal |
4339 | 4253 |
4340 #endif // V8_TARGET_ARCH_IA32 | 4254 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |