Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: src/ia32/full-codegen-ia32.cc

Issue 7824038: Remove variable rewrites and the unneccesary Slot class. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698