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

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

Issue 6697023: Merge 6800:7180 from the bleeding edge branch to the experimental/gc branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 9 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
« no previous file with comments | « src/x64/frames-x64.cc ('k') | src/x64/ic-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 __ lea(rdx, 193 __ lea(rdx,
194 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); 194 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
195 __ push(rdx); 195 __ push(rdx);
196 __ Push(Smi::FromInt(scope()->num_parameters())); 196 __ Push(Smi::FromInt(scope()->num_parameters()));
197 // Arguments to ArgumentsAccessStub: 197 // Arguments to ArgumentsAccessStub:
198 // function, receiver address, parameter count. 198 // function, receiver address, parameter count.
199 // The stub will rewrite receiver and parameter count if the previous 199 // The stub will rewrite receiver and parameter count if the previous
200 // stack frame was an arguments adapter frame. 200 // stack frame was an arguments adapter frame.
201 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); 201 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
202 __ CallStub(&stub); 202 __ CallStub(&stub);
203 // Store new arguments object in both "arguments" and ".arguments" slots. 203
204 __ movq(rcx, rax); 204 Variable* arguments_shadow = scope()->arguments_shadow();
205 if (arguments_shadow != NULL) {
206 // Store new arguments object in both "arguments" and ".arguments" slots.
207 __ movq(rcx, rax);
208 Move(arguments_shadow->AsSlot(), rcx, rbx, rdx);
209 }
205 Move(arguments->AsSlot(), rax, rbx, rdx); 210 Move(arguments->AsSlot(), rax, rbx, rdx);
206 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
207 Move(dot_arguments_slot, rcx, rbx, rdx);
208 }
209
210 { Comment cmnt(masm_, "[ Declarations");
211 // For named function expressions, declare the function name as a
212 // constant.
213 if (scope()->is_function_scope() && scope()->function() != NULL) {
214 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
215 }
216 // Visit all the explicit declarations unless there is an illegal
217 // redeclaration.
218 if (scope()->HasIllegalRedeclaration()) {
219 scope()->VisitIllegalRedeclaration(this);
220 } else {
221 VisitDeclarations(scope()->declarations());
222 }
223 } 211 }
224 212
225 if (FLAG_trace) { 213 if (FLAG_trace) {
226 __ CallRuntime(Runtime::kTraceEnter, 0); 214 __ CallRuntime(Runtime::kTraceEnter, 0);
227 } 215 }
228 216
229 { Comment cmnt(masm_, "[ Stack check"); 217 // Visit the declarations and body unless there is an illegal
230 PrepareForBailout(info->function(), NO_REGISTERS); 218 // redeclaration.
231 NearLabel ok; 219 if (scope()->HasIllegalRedeclaration()) {
232 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 220 Comment cmnt(masm_, "[ Declarations");
233 __ j(above_equal, &ok); 221 scope()->VisitIllegalRedeclaration(this);
234 StackCheckStub stub; 222 } else {
235 __ CallStub(&stub); 223 { Comment cmnt(masm_, "[ Declarations");
236 __ bind(&ok); 224 // For named function expressions, declare the function name as a
225 // constant.
226 if (scope()->is_function_scope() && scope()->function() != NULL) {
227 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
228 }
229 VisitDeclarations(scope()->declarations());
230 }
231
232 { Comment cmnt(masm_, "[ Stack check");
233 PrepareForBailout(info->function(), NO_REGISTERS);
234 NearLabel ok;
235 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
236 __ j(above_equal, &ok);
237 StackCheckStub stub;
238 __ CallStub(&stub);
239 __ bind(&ok);
240 }
241
242 { Comment cmnt(masm_, "[ Body");
243 ASSERT(loop_depth() == 0);
244 VisitStatements(function()->body());
245 ASSERT(loop_depth() == 0);
246 }
237 } 247 }
238 248
239 { Comment cmnt(masm_, "[ Body"); 249 // Always emit a 'return undefined' in case control fell off the end of
240 ASSERT(loop_depth() == 0); 250 // the body.
241 VisitStatements(function()->body());
242 ASSERT(loop_depth() == 0);
243 }
244
245 { Comment cmnt(masm_, "[ return <undefined>;"); 251 { Comment cmnt(masm_, "[ return <undefined>;");
246 // Emit a 'return undefined' in case control fell off the end of the body.
247 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); 252 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
248 EmitReturnSequence(); 253 EmitReturnSequence();
249 } 254 }
250 } 255 }
251 256
252 257
253 void FullCodeGenerator::ClearAccumulator() { 258 void FullCodeGenerator::ClearAccumulator() {
254 __ Set(rax, 0); 259 __ Set(rax, 0);
255 } 260 }
256 261
257 262
258 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { 263 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
259 Comment cmnt(masm_, "[ Stack check"); 264 Comment cmnt(masm_, "[ Stack check");
260 NearLabel ok; 265 NearLabel ok;
261 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 266 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
262 __ j(above_equal, &ok); 267 __ j(above_equal, &ok);
263 StackCheckStub stub; 268 StackCheckStub stub;
264 __ CallStub(&stub); 269 __ CallStub(&stub);
265 // Record a mapping of this PC offset to the OSR id. This is used to find 270 // Record a mapping of this PC offset to the OSR id. This is used to find
266 // the AST id from the unoptimized code in order to use it as a key into 271 // the AST id from the unoptimized code in order to use it as a key into
267 // the deoptimization input data found in the optimized code. 272 // the deoptimization input data found in the optimized code.
268 RecordStackCheck(stmt->OsrEntryId()); 273 RecordStackCheck(stmt->OsrEntryId());
269 274
275 // Loop stack checks can be patched to perform on-stack replacement. In
276 // order to decide whether or not to perform OSR we embed the loop depth
277 // in a test instruction after the call so we can extract it from the OSR
278 // builtin.
279 ASSERT(loop_depth() > 0);
280 __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
281
270 __ bind(&ok); 282 __ bind(&ok);
271 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); 283 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
272 // Record a mapping of the OSR id to this PC. This is used if the OSR 284 // Record a mapping of the OSR id to this PC. This is used if the OSR
273 // entry becomes the target of a bailout. We don't expect it to be, but 285 // entry becomes the target of a bailout. We don't expect it to be, but
274 // we want it to work if it is. 286 // we want it to work if it is.
275 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); 287 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
276 } 288 }
277 289
278 290
279 void FullCodeGenerator::EmitReturnSequence() { 291 void FullCodeGenerator::EmitReturnSequence() {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 } 323 }
312 // Check that the size of the code used for returning is large enough 324 // Check that the size of the code used for returning is large enough
313 // for the debugger's requirements. 325 // for the debugger's requirements.
314 ASSERT(Assembler::kJSReturnSequenceLength <= 326 ASSERT(Assembler::kJSReturnSequenceLength <=
315 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); 327 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
316 #endif 328 #endif
317 } 329 }
318 } 330 }
319 331
320 332
321 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
322 Token::Value op, Expression* left, Expression* right) {
323 ASSERT(ShouldInlineSmiCase(op));
324 return kNoConstants;
325 }
326
327
328 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { 333 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
329 } 334 }
330 335
331 336
332 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { 337 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
333 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); 338 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
334 __ movq(result_register(), slot_operand); 339 __ movq(result_register(), slot_operand);
335 } 340 }
336 341
337 342
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 void FullCodeGenerator::DoTest(Label* if_true, 541 void FullCodeGenerator::DoTest(Label* if_true,
537 Label* if_false, 542 Label* if_false,
538 Label* fall_through) { 543 Label* fall_through) {
539 // Emit the inlined tests assumed by the stub. 544 // Emit the inlined tests assumed by the stub.
540 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex); 545 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex);
541 __ j(equal, if_false); 546 __ j(equal, if_false);
542 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); 547 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
543 __ j(equal, if_true); 548 __ j(equal, if_true);
544 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex); 549 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex);
545 __ j(equal, if_false); 550 __ j(equal, if_false);
546 ASSERT_EQ(0, kSmiTag); 551 STATIC_ASSERT(kSmiTag == 0);
547 __ SmiCompare(result_register(), Smi::FromInt(0)); 552 __ Cmp(result_register(), Smi::FromInt(0));
548 __ j(equal, if_false); 553 __ j(equal, if_false);
549 Condition is_smi = masm_->CheckSmi(result_register()); 554 Condition is_smi = masm_->CheckSmi(result_register());
550 __ j(is_smi, if_true); 555 __ j(is_smi, if_true);
551 556
552 // Call the ToBoolean stub for all other cases. 557 // Call the ToBoolean stub for all other cases.
553 ToBooleanStub stub; 558 ToBooleanStub stub;
554 __ push(result_register()); 559 __ push(result_register());
555 __ CallStub(&stub); 560 __ CallStub(&stub);
556 __ testq(rax, rax); 561 __ testq(rax, rax);
557 562
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 VisitForAccumulatorValue(function); 731 VisitForAccumulatorValue(function);
727 __ pop(rdx); 732 __ pop(rdx);
728 } else { 733 } else {
729 __ movq(rdx, rax); 734 __ movq(rdx, rax);
730 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); 735 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex);
731 } 736 }
732 ASSERT(prop->key()->AsLiteral() != NULL && 737 ASSERT(prop->key()->AsLiteral() != NULL &&
733 prop->key()->AsLiteral()->handle()->IsSmi()); 738 prop->key()->AsLiteral()->handle()->IsSmi());
734 __ Move(rcx, prop->key()->AsLiteral()->handle()); 739 __ Move(rcx, prop->key()->AsLiteral()->handle());
735 740
736 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 741 Handle<Code> ic(Builtins::builtin(
742 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
743 : Builtins::KeyedStoreIC_Initialize));
737 EmitCallIC(ic, RelocInfo::CODE_TARGET); 744 EmitCallIC(ic, RelocInfo::CODE_TARGET);
738 } 745 }
739 } 746 }
740 } 747 }
741 748
742 749
743 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { 750 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
744 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); 751 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
745 } 752 }
746 753
747 754
748 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 755 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
749 // Call the runtime to declare the globals. 756 // Call the runtime to declare the globals.
750 __ push(rsi); // The context is the first argument. 757 __ push(rsi); // The context is the first argument.
751 __ Push(pairs); 758 __ Push(pairs);
752 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); 759 __ Push(Smi::FromInt(is_eval() ? 1 : 0));
753 __ CallRuntime(Runtime::kDeclareGlobals, 3); 760 __ Push(Smi::FromInt(strict_mode_flag()));
761 __ CallRuntime(Runtime::kDeclareGlobals, 4);
754 // Return value is ignored. 762 // Return value is ignored.
755 } 763 }
756 764
757 765
758 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 766 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
759 Comment cmnt(masm_, "[ SwitchStatement"); 767 Comment cmnt(masm_, "[ SwitchStatement");
760 Breakable nested_statement(this, stmt); 768 Breakable nested_statement(this, stmt);
761 SetStatementPosition(stmt); 769 SetStatementPosition(stmt);
762 770
763 // Keep the switch value on the stack until a case matches. 771 // Keep the switch value on the stack until a case matches.
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
822 __ jmp(nested_statement.break_target()); 830 __ jmp(nested_statement.break_target());
823 } else { 831 } else {
824 __ jmp(default_clause->body_target()->entry_label()); 832 __ jmp(default_clause->body_target()->entry_label());
825 } 833 }
826 834
827 // Compile all the case bodies. 835 // Compile all the case bodies.
828 for (int i = 0; i < clauses->length(); i++) { 836 for (int i = 0; i < clauses->length(); i++) {
829 Comment cmnt(masm_, "[ Case body"); 837 Comment cmnt(masm_, "[ Case body");
830 CaseClause* clause = clauses->at(i); 838 CaseClause* clause = clauses->at(i);
831 __ bind(clause->body_target()->entry_label()); 839 __ bind(clause->body_target()->entry_label());
840 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
832 VisitStatements(clause->statements()); 841 VisitStatements(clause->statements());
833 } 842 }
834 843
835 __ bind(nested_statement.break_target()); 844 __ bind(nested_statement.break_target());
836 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 845 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
837 } 846 }
838 847
839 848
840 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { 849 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
841 Comment cmnt(masm_, "[ ForInStatement"); 850 Comment cmnt(masm_, "[ ForInStatement");
842 SetStatementPosition(stmt); 851 SetStatementPosition(stmt);
843 852
844 Label loop, exit; 853 Label loop, exit;
845 ForIn loop_statement(this, stmt); 854 ForIn loop_statement(this, stmt);
846 increment_loop_depth(); 855 increment_loop_depth();
847 856
848 // Get the object to enumerate over. Both SpiderMonkey and JSC 857 // Get the object to enumerate over. Both SpiderMonkey and JSC
849 // ignore null and undefined in contrast to the specification; see 858 // ignore null and undefined in contrast to the specification; see
850 // ECMA-262 section 12.6.4. 859 // ECMA-262 section 12.6.4.
851 VisitForAccumulatorValue(stmt->enumerable()); 860 VisitForAccumulatorValue(stmt->enumerable());
852 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); 861 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
853 __ j(equal, &exit); 862 __ j(equal, &exit);
854 __ CompareRoot(rax, Heap::kNullValueRootIndex); 863 Register null_value = rdi;
864 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
865 __ cmpq(rax, null_value);
855 __ j(equal, &exit); 866 __ j(equal, &exit);
856 867
857 // Convert the object to a JS object. 868 // Convert the object to a JS object.
858 Label convert, done_convert; 869 Label convert, done_convert;
859 __ JumpIfSmi(rax, &convert); 870 __ JumpIfSmi(rax, &convert);
860 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); 871 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
861 __ j(above_equal, &done_convert); 872 __ j(above_equal, &done_convert);
862 __ bind(&convert); 873 __ bind(&convert);
863 __ push(rax); 874 __ push(rax);
864 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 875 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
865 __ bind(&done_convert); 876 __ bind(&done_convert);
866 __ push(rax); 877 __ push(rax);
867 878
868 // BUG(867): Check cache validity in generated code. This is a fast 879 // Check cache validity in generated code. This is a fast case for
869 // case for the JSObject::IsSimpleEnum cache validity checks. If we 880 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
870 // cannot guarantee cache validity, call the runtime system to check 881 // guarantee cache validity, call the runtime system to check cache
871 // cache validity or get the property names in a fixed array. 882 // validity or get the property names in a fixed array.
883 Label next, call_runtime;
884 Register empty_fixed_array_value = r8;
885 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
886 Register empty_descriptor_array_value = r9;
887 __ LoadRoot(empty_descriptor_array_value,
888 Heap::kEmptyDescriptorArrayRootIndex);
889 __ movq(rcx, rax);
890 __ bind(&next);
891
892 // Check that there are no elements. Register rcx contains the
893 // current JS object we've reached through the prototype chain.
894 __ cmpq(empty_fixed_array_value,
895 FieldOperand(rcx, JSObject::kElementsOffset));
896 __ j(not_equal, &call_runtime);
897
898 // Check that instance descriptors are not empty so that we can
899 // check for an enum cache. Leave the map in rbx for the subsequent
900 // prototype load.
901 __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
902 __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset));
903 __ cmpq(rdx, empty_descriptor_array_value);
904 __ j(equal, &call_runtime);
905
906 // Check that there is an enum cache in the non-empty instance
907 // descriptors (rdx). This is the case if the next enumeration
908 // index field does not contain a smi.
909 __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
910 __ JumpIfSmi(rdx, &call_runtime);
911
912 // For all objects but the receiver, check that the cache is empty.
913 NearLabel check_prototype;
914 __ cmpq(rcx, rax);
915 __ j(equal, &check_prototype);
916 __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset));
917 __ cmpq(rdx, empty_fixed_array_value);
918 __ j(not_equal, &call_runtime);
919
920 // Load the prototype from the map and loop if non-null.
921 __ bind(&check_prototype);
922 __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
923 __ cmpq(rcx, null_value);
924 __ j(not_equal, &next);
925
926 // The enum cache is valid. Load the map of the object being
927 // iterated over and use the cache for the iteration.
928 NearLabel use_cache;
929 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
930 __ jmp(&use_cache);
872 931
873 // Get the set of properties to enumerate. 932 // Get the set of properties to enumerate.
933 __ bind(&call_runtime);
874 __ push(rax); // Duplicate the enumerable object on the stack. 934 __ push(rax); // Duplicate the enumerable object on the stack.
875 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); 935 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
876 936
877 // If we got a map from the runtime call, we can do a fast 937 // If we got a map from the runtime call, we can do a fast
878 // modification check. Otherwise, we got a fixed array, and we have 938 // modification check. Otherwise, we got a fixed array, and we have
879 // to do a slow check. 939 // to do a slow check.
880 NearLabel fixed_array; 940 NearLabel fixed_array;
881 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), 941 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
882 Heap::kMetaMapRootIndex); 942 Heap::kMetaMapRootIndex);
883 __ j(not_equal, &fixed_array); 943 __ j(not_equal, &fixed_array);
884 944
885 // We got a map in register rax. Get the enumeration cache from it. 945 // We got a map in register rax. Get the enumeration cache from it.
946 __ bind(&use_cache);
886 __ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset)); 947 __ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset));
887 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset)); 948 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
888 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset)); 949 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
889 950
890 // Setup the four remaining stack slots. 951 // Setup the four remaining stack slots.
891 __ push(rax); // Map. 952 __ push(rax); // Map.
892 __ push(rdx); // Enumeration cache. 953 __ push(rdx); // Enumeration cache.
893 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset)); 954 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
894 __ push(rax); // Enumeration cache length (as smi). 955 __ push(rax); // Enumeration cache length (as smi).
895 __ Push(Smi::FromInt(0)); // Initial index. 956 __ Push(Smi::FromInt(0)); // Initial index.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
927 __ movq(rcx, Operand(rsp, 4 * kPointerSize)); 988 __ movq(rcx, Operand(rsp, 4 * kPointerSize));
928 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset)); 989 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
929 __ j(equal, &update_each); 990 __ j(equal, &update_each);
930 991
931 // Convert the entry to a string or null if it isn't a property 992 // Convert the entry to a string or null if it isn't a property
932 // anymore. If the property has been removed while iterating, we 993 // anymore. If the property has been removed while iterating, we
933 // just skip it. 994 // just skip it.
934 __ push(rcx); // Enumerable. 995 __ push(rcx); // Enumerable.
935 __ push(rbx); // Current entry. 996 __ push(rbx); // Current entry.
936 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); 997 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
937 __ SmiCompare(rax, Smi::FromInt(0)); 998 __ Cmp(rax, Smi::FromInt(0));
938 __ j(equal, loop_statement.continue_target()); 999 __ j(equal, loop_statement.continue_target());
939 __ movq(rbx, rax); 1000 __ movq(rbx, rax);
940 1001
941 // Update the 'each' property or variable from the possibly filtered 1002 // Update the 'each' property or variable from the possibly filtered
942 // entry in register rbx. 1003 // entry in register rbx.
943 __ bind(&update_each); 1004 __ bind(&update_each);
944 __ movq(result_register(), rbx); 1005 __ movq(result_register(), rbx);
945 // Perform the assignment as if via '='. 1006 // Perform the assignment as if via '='.
946 { EffectContext context(this); 1007 { EffectContext context(this);
947 EmitAssignment(stmt->each(), stmt->AssignmentId()); 1008 EmitAssignment(stmt->each(), stmt->AssignmentId());
(...skipping 16 matching lines...) Expand all
964 1025
965 // Exit and decrement the loop depth. 1026 // Exit and decrement the loop depth.
966 __ bind(&exit); 1027 __ bind(&exit);
967 decrement_loop_depth(); 1028 decrement_loop_depth();
968 } 1029 }
969 1030
970 1031
971 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, 1032 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
972 bool pretenure) { 1033 bool pretenure) {
973 // Use the fast case closure allocation code that allocates in new 1034 // Use the fast case closure allocation code that allocates in new
974 // space for nested functions that don't need literals cloning. 1035 // space for nested functions that don't need literals cloning. If
975 if (scope()->is_function_scope() && 1036 // we're running with the --always-opt or the --prepare-always-opt
1037 // flag, we need to use the runtime function so that the new function
1038 // we are creating here gets a chance to have its code optimized and
1039 // doesn't just get a copy of the existing unoptimized code.
1040 if (!FLAG_always_opt &&
1041 !FLAG_prepare_always_opt &&
1042 scope()->is_function_scope() &&
976 info->num_literals() == 0 && 1043 info->num_literals() == 0 &&
977 !pretenure) { 1044 !pretenure) {
978 FastNewClosureStub stub; 1045 FastNewClosureStub stub;
979 __ Push(info); 1046 __ Push(info);
980 __ CallStub(&stub); 1047 __ CallStub(&stub);
981 } else { 1048 } else {
982 __ push(rsi); 1049 __ push(rsi);
983 __ Push(info); 1050 __ Push(info);
984 __ Push(pretenure ? Factory::true_value() : Factory::false_value()); 1051 __ Push(pretenure ? Factory::true_value() : Factory::false_value());
985 __ CallRuntime(Runtime::kNewClosure, 3); 1052 __ CallRuntime(Runtime::kNewClosure, 3);
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
1075 } 1142 }
1076 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); 1143 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1077 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); 1144 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset));
1078 // Walk the rest of the chain without clobbering rsi. 1145 // Walk the rest of the chain without clobbering rsi.
1079 context = temp; 1146 context = temp;
1080 } 1147 }
1081 } 1148 }
1082 // Check that last extension is NULL. 1149 // Check that last extension is NULL.
1083 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); 1150 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1084 __ j(not_equal, slow); 1151 __ j(not_equal, slow);
1085 __ movq(temp, ContextOperand(context, Context::FCONTEXT_INDEX)); 1152
1086 return ContextOperand(temp, slot->index()); 1153 // This function is used only for loads, not stores, so it's safe to
1154 // return an rsi-based operand (the write barrier cannot be allowed to
1155 // destroy the rsi register).
1156 return ContextOperand(context, slot->index());
1087 } 1157 }
1088 1158
1089 1159
1090 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( 1160 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1091 Slot* slot, 1161 Slot* slot,
1092 TypeofState typeof_state, 1162 TypeofState typeof_state,
1093 Label* slow, 1163 Label* slow,
1094 Label* done) { 1164 Label* done) {
1095 // Generate fast-case code for variables that might be shadowed by 1165 // Generate fast-case code for variables that might be shadowed by
1096 // eval-introduced variables. Eval is used a lot without 1166 // eval-introduced variables. Eval is used a lot without
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
1326 PrepareForBailoutForId(key->id(), NO_REGISTERS); 1396 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1327 } 1397 }
1328 break; 1398 break;
1329 } 1399 }
1330 // Fall through. 1400 // Fall through.
1331 case ObjectLiteral::Property::PROTOTYPE: 1401 case ObjectLiteral::Property::PROTOTYPE:
1332 __ push(Operand(rsp, 0)); // Duplicate receiver. 1402 __ push(Operand(rsp, 0)); // Duplicate receiver.
1333 VisitForStackValue(key); 1403 VisitForStackValue(key);
1334 VisitForStackValue(value); 1404 VisitForStackValue(value);
1335 if (property->emit_store()) { 1405 if (property->emit_store()) {
1336 __ CallRuntime(Runtime::kSetProperty, 3); 1406 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1407 __ CallRuntime(Runtime::kSetProperty, 4);
1337 } else { 1408 } else {
1338 __ Drop(3); 1409 __ Drop(3);
1339 } 1410 }
1340 break; 1411 break;
1341 case ObjectLiteral::Property::SETTER: 1412 case ObjectLiteral::Property::SETTER:
1342 case ObjectLiteral::Property::GETTER: 1413 case ObjectLiteral::Property::GETTER:
1343 __ push(Operand(rsp, 0)); // Duplicate receiver. 1414 __ push(Operand(rsp, 0)); // Duplicate receiver.
1344 VisitForStackValue(key); 1415 VisitForStackValue(key);
1345 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? 1416 __ Push(property->kind() == ObjectLiteral::Property::SETTER ?
1346 Smi::FromInt(1) : 1417 Smi::FromInt(1) :
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
1502 } 1573 }
1503 } 1574 }
1504 1575
1505 // For property compound assignments we need another deoptimization 1576 // For property compound assignments we need another deoptimization
1506 // point after the property load. 1577 // point after the property load.
1507 if (property != NULL) { 1578 if (property != NULL) {
1508 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); 1579 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
1509 } 1580 }
1510 1581
1511 Token::Value op = expr->binary_op(); 1582 Token::Value op = expr->binary_op();
1512 ConstantOperand constant = ShouldInlineSmiCase(op) 1583 __ push(rax); // Left operand goes on the stack.
1513 ? GetConstantOperand(op, expr->target(), expr->value()) 1584 VisitForAccumulatorValue(expr->value());
1514 : kNoConstants;
1515 ASSERT(constant == kRightConstant || constant == kNoConstants);
1516 if (constant == kNoConstants) {
1517 __ push(rax); // Left operand goes on the stack.
1518 VisitForAccumulatorValue(expr->value());
1519 }
1520 1585
1521 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() 1586 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1522 ? OVERWRITE_RIGHT 1587 ? OVERWRITE_RIGHT
1523 : NO_OVERWRITE; 1588 : NO_OVERWRITE;
1524 SetSourcePosition(expr->position() + 1); 1589 SetSourcePosition(expr->position() + 1);
1525 AccumulatorValueContext context(this); 1590 AccumulatorValueContext context(this);
1526 if (ShouldInlineSmiCase(op)) { 1591 if (ShouldInlineSmiCase(op)) {
1527 EmitInlineSmiBinaryOp(expr, 1592 EmitInlineSmiBinaryOp(expr,
1528 op, 1593 op,
1529 mode, 1594 mode,
1530 expr->target(), 1595 expr->target(),
1531 expr->value(), 1596 expr->value());
1532 constant);
1533 } else { 1597 } else {
1534 EmitBinaryOp(op, mode); 1598 EmitBinaryOp(op, mode);
1535 } 1599 }
1536 // Deoptimization point in case the binary operation may have side effects. 1600 // Deoptimization point in case the binary operation may have side effects.
1537 PrepareForBailout(expr->binary_operation(), TOS_REG); 1601 PrepareForBailout(expr->binary_operation(), TOS_REG);
1538 } else { 1602 } else {
1539 VisitForAccumulatorValue(expr->value()); 1603 VisitForAccumulatorValue(expr->value());
1540 } 1604 }
1541 1605
1542 // Record source position before possible IC call. 1606 // Record source position before possible IC call.
(...skipping 30 matching lines...) Expand all
1573 SetSourcePosition(prop->position()); 1637 SetSourcePosition(prop->position());
1574 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 1638 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1575 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1639 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1576 } 1640 }
1577 1641
1578 1642
1579 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, 1643 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
1580 Token::Value op, 1644 Token::Value op,
1581 OverwriteMode mode, 1645 OverwriteMode mode,
1582 Expression* left, 1646 Expression* left,
1583 Expression* right, 1647 Expression* right) {
1584 ConstantOperand constant) {
1585 ASSERT(constant == kNoConstants); // Only handled case.
1586
1587 // Do combined smi check of the operands. Left operand is on the 1648 // Do combined smi check of the operands. Left operand is on the
1588 // stack (popped into rdx). Right operand is in rax but moved into 1649 // stack (popped into rdx). Right operand is in rax but moved into
1589 // rcx to make the shifts easier. 1650 // rcx to make the shifts easier.
1590 NearLabel done, stub_call, smi_case; 1651 NearLabel done, stub_call, smi_case;
1591 __ pop(rdx); 1652 __ pop(rdx);
1592 __ movq(rcx, rax); 1653 __ movq(rcx, rax);
1593 __ or_(rax, rdx); 1654 __ or_(rax, rdx);
1594 JumpPatchSite patch_site(masm_); 1655 JumpPatchSite patch_site(masm_);
1595 patch_site.EmitJumpIfSmi(rax, &smi_case); 1656 patch_site.EmitJumpIfSmi(rax, &smi_case);
1596 1657
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1673 EffectContext context(this); 1734 EffectContext context(this);
1674 EmitVariableAssignment(var, Token::ASSIGN); 1735 EmitVariableAssignment(var, Token::ASSIGN);
1675 break; 1736 break;
1676 } 1737 }
1677 case NAMED_PROPERTY: { 1738 case NAMED_PROPERTY: {
1678 __ push(rax); // Preserve value. 1739 __ push(rax); // Preserve value.
1679 VisitForAccumulatorValue(prop->obj()); 1740 VisitForAccumulatorValue(prop->obj());
1680 __ movq(rdx, rax); 1741 __ movq(rdx, rax);
1681 __ pop(rax); // Restore value. 1742 __ pop(rax); // Restore value.
1682 __ Move(rcx, prop->key()->AsLiteral()->handle()); 1743 __ Move(rcx, prop->key()->AsLiteral()->handle());
1683 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 1744 Handle<Code> ic(Builtins::builtin(
1745 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
1746 : Builtins::StoreIC_Initialize));
1684 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1747 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1685 break; 1748 break;
1686 } 1749 }
1687 case KEYED_PROPERTY: { 1750 case KEYED_PROPERTY: {
1688 __ push(rax); // Preserve value. 1751 __ push(rax); // Preserve value.
1689 if (prop->is_synthetic()) { 1752 if (prop->is_synthetic()) {
1690 ASSERT(prop->obj()->AsVariableProxy() != NULL); 1753 ASSERT(prop->obj()->AsVariableProxy() != NULL);
1691 ASSERT(prop->key()->AsLiteral() != NULL); 1754 ASSERT(prop->key()->AsLiteral() != NULL);
1692 { AccumulatorValueContext for_object(this); 1755 { AccumulatorValueContext for_object(this);
1693 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); 1756 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
1694 } 1757 }
1695 __ movq(rdx, rax); 1758 __ movq(rdx, rax);
1696 __ Move(rcx, prop->key()->AsLiteral()->handle()); 1759 __ Move(rcx, prop->key()->AsLiteral()->handle());
1697 } else { 1760 } else {
1698 VisitForStackValue(prop->obj()); 1761 VisitForStackValue(prop->obj());
1699 VisitForAccumulatorValue(prop->key()); 1762 VisitForAccumulatorValue(prop->key());
1700 __ movq(rcx, rax); 1763 __ movq(rcx, rax);
1701 __ pop(rdx); 1764 __ pop(rdx);
1702 } 1765 }
1703 __ pop(rax); // Restore value. 1766 __ pop(rax); // Restore value.
1704 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 1767 Handle<Code> ic(Builtins::builtin(
1768 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
1769 : Builtins::KeyedStoreIC_Initialize));
1705 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1770 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1706 break; 1771 break;
1707 } 1772 }
1708 } 1773 }
1709 PrepareForBailoutForId(bailout_ast_id, TOS_REG); 1774 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1710 context()->Plug(rax); 1775 context()->Plug(rax);
1711 } 1776 }
1712 1777
1713 1778
1714 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1779 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
1715 Token::Value op) { 1780 Token::Value op) {
1716 // Left-hand sides that rewrite to explicit property accesses do not reach 1781 // Left-hand sides that rewrite to explicit property accesses do not reach
1717 // here. 1782 // here.
1718 ASSERT(var != NULL); 1783 ASSERT(var != NULL);
1719 ASSERT(var->is_global() || var->AsSlot() != NULL); 1784 ASSERT(var->is_global() || var->AsSlot() != NULL);
1720 1785
1721 if (var->is_global()) { 1786 if (var->is_global()) {
1722 ASSERT(!var->is_this()); 1787 ASSERT(!var->is_this());
1723 // Assignment to a global variable. Use inline caching for the 1788 // Assignment to a global variable. Use inline caching for the
1724 // assignment. Right-hand-side value is passed in rax, variable name in 1789 // assignment. Right-hand-side value is passed in rax, variable name in
1725 // rcx, and the global object on the stack. 1790 // rcx, and the global object on the stack.
1726 __ Move(rcx, var->name()); 1791 __ Move(rcx, var->name());
1727 __ movq(rdx, GlobalObjectOperand()); 1792 __ movq(rdx, GlobalObjectOperand());
1728 Handle<Code> ic(Builtins::builtin(is_strict() 1793 Handle<Code> ic(Builtins::builtin(
1729 ? Builtins::StoreIC_Initialize_Strict 1794 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
1730 : Builtins::StoreIC_Initialize)); 1795 : Builtins::StoreIC_Initialize));
1731 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); 1796 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
1732 1797
1733 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { 1798 } else if (op == Token::INIT_CONST) {
1734 // Perform the assignment for non-const variables and for initialization 1799 // Like var declarations, const declarations are hoisted to function
1735 // of const variables. Const assignments are simply skipped. 1800 // scope. However, unlike var initializers, const initializers are able
1736 Label done; 1801 // to drill a hole to that function context, even from inside a 'with'
1802 // context. We thus bypass the normal static scope lookup.
1803 Slot* slot = var->AsSlot();
1804 Label skip;
1805 switch (slot->type()) {
1806 case Slot::PARAMETER:
1807 // No const parameters.
1808 UNREACHABLE();
1809 break;
1810 case Slot::LOCAL:
1811 __ movq(rdx, Operand(rbp, SlotOffset(slot)));
1812 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1813 __ j(not_equal, &skip);
1814 __ movq(Operand(rbp, SlotOffset(slot)), rax);
1815 break;
1816 case Slot::CONTEXT: {
1817 __ movq(rcx, ContextOperand(rsi, Context::FCONTEXT_INDEX));
1818 __ movq(rdx, ContextOperand(rcx, slot->index()));
1819 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1820 __ j(not_equal, &skip);
1821 __ movq(ContextOperand(rcx, slot->index()), rax);
1822 int offset = Context::SlotOffset(slot->index());
1823 __ movq(rdx, rax); // Preserve the stored value in eax.
1824 __ RecordWrite(rcx, offset, rdx, rbx);
1825 break;
1826 }
1827 case Slot::LOOKUP:
1828 __ push(rax);
1829 __ push(rsi);
1830 __ Push(var->name());
1831 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1832 break;
1833 }
1834 __ bind(&skip);
1835
1836 } else if (var->mode() != Variable::CONST) {
1837 // Perform the assignment for non-const variables. Const assignments
1838 // are simply skipped.
1737 Slot* slot = var->AsSlot(); 1839 Slot* slot = var->AsSlot();
1738 switch (slot->type()) { 1840 switch (slot->type()) {
1739 case Slot::PARAMETER: 1841 case Slot::PARAMETER:
1740 case Slot::LOCAL: 1842 case Slot::LOCAL:
1741 if (op == Token::INIT_CONST) {
1742 // Detect const reinitialization by checking for the hole value.
1743 __ movq(rdx, Operand(rbp, SlotOffset(slot)));
1744 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1745 __ j(not_equal, &done);
1746 }
1747 // Perform the assignment. 1843 // Perform the assignment.
1748 __ movq(Operand(rbp, SlotOffset(slot)), rax); 1844 __ movq(Operand(rbp, SlotOffset(slot)), rax);
1749 break; 1845 break;
1750 1846
1751 case Slot::CONTEXT: { 1847 case Slot::CONTEXT: {
1752 MemOperand target = EmitSlotSearch(slot, rcx); 1848 MemOperand target = EmitSlotSearch(slot, rcx);
1753 if (op == Token::INIT_CONST) {
1754 // Detect const reinitialization by checking for the hole value.
1755 __ movq(rdx, target);
1756 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1757 __ j(not_equal, &done);
1758 }
1759 // Perform the assignment and issue the write barrier. 1849 // Perform the assignment and issue the write barrier.
1760 __ movq(target, rax); 1850 __ movq(target, rax);
1761 1851
1762 // The value of the assignment is in rax. RecordWrite clobbers its 1852 // The value of the assignment is in rax. RecordWrite clobbers its
1763 // register arguments. 1853 // register arguments.
1764 __ movq(rdx, rax); 1854 __ movq(rdx, rax);
1765 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 1855 int offset = Context::SlotOffset(slot->index());
1766 __ RecordWrite(rcx, offset, rdx, rbx, kDontSaveFPRegs); 1856 __ RecordWrite(rcx, offset, rdx, rbx, kDontSaveFPRegs);
1767 break; 1857 break;
1768 } 1858 }
1769 1859
1770 case Slot::LOOKUP: 1860 case Slot::LOOKUP:
1771 // Call the runtime for the assignment. The runtime will ignore 1861 // Call the runtime for the assignment.
1772 // const reinitialization.
1773 __ push(rax); // Value. 1862 __ push(rax); // Value.
1774 __ push(rsi); // Context. 1863 __ push(rsi); // Context.
1775 __ Push(var->name()); 1864 __ Push(var->name());
1776 if (op == Token::INIT_CONST) { 1865 __ Push(Smi::FromInt(strict_mode_flag()));
1777 // The runtime will ignore const redeclaration. 1866 __ CallRuntime(Runtime::kStoreContextSlot, 4);
1778 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1779 } else {
1780 __ CallRuntime(Runtime::kStoreContextSlot, 3);
1781 }
1782 break; 1867 break;
1783 } 1868 }
1784 __ bind(&done);
1785 } 1869 }
1786 } 1870 }
1787 1871
1788 1872
1789 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { 1873 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1790 // Assignment to a property, using a named store IC. 1874 // Assignment to a property, using a named store IC.
1791 Property* prop = expr->target()->AsProperty(); 1875 Property* prop = expr->target()->AsProperty();
1792 ASSERT(prop != NULL); 1876 ASSERT(prop != NULL);
1793 ASSERT(prop->key()->AsLiteral() != NULL); 1877 ASSERT(prop->key()->AsLiteral() != NULL);
1794 1878
1795 // If the assignment starts a block of assignments to the same object, 1879 // If the assignment starts a block of assignments to the same object,
1796 // change to slow case to avoid the quadratic behavior of repeatedly 1880 // change to slow case to avoid the quadratic behavior of repeatedly
1797 // adding fast properties. 1881 // adding fast properties.
1798 if (expr->starts_initialization_block()) { 1882 if (expr->starts_initialization_block()) {
1799 __ push(result_register()); 1883 __ push(result_register());
1800 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value. 1884 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value.
1801 __ CallRuntime(Runtime::kToSlowProperties, 1); 1885 __ CallRuntime(Runtime::kToSlowProperties, 1);
1802 __ pop(result_register()); 1886 __ pop(result_register());
1803 } 1887 }
1804 1888
1805 // Record source code position before IC call. 1889 // Record source code position before IC call.
1806 SetSourcePosition(expr->position()); 1890 SetSourcePosition(expr->position());
1807 __ Move(rcx, prop->key()->AsLiteral()->handle()); 1891 __ Move(rcx, prop->key()->AsLiteral()->handle());
1808 if (expr->ends_initialization_block()) { 1892 if (expr->ends_initialization_block()) {
1809 __ movq(rdx, Operand(rsp, 0)); 1893 __ movq(rdx, Operand(rsp, 0));
1810 } else { 1894 } else {
1811 __ pop(rdx); 1895 __ pop(rdx);
1812 } 1896 }
1813 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 1897 Handle<Code> ic(Builtins::builtin(
1898 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
1899 : Builtins::StoreIC_Initialize));
1814 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1900 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1815 1901
1816 // If the assignment ends an initialization block, revert to fast case. 1902 // If the assignment ends an initialization block, revert to fast case.
1817 if (expr->ends_initialization_block()) { 1903 if (expr->ends_initialization_block()) {
1818 __ push(rax); // Result of assignment, saved even if not needed. 1904 __ push(rax); // Result of assignment, saved even if not needed.
1819 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. 1905 __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
1820 __ CallRuntime(Runtime::kToFastProperties, 1); 1906 __ CallRuntime(Runtime::kToFastProperties, 1);
1821 __ pop(rax); 1907 __ pop(rax);
1822 __ Drop(1); 1908 __ Drop(1);
1823 } 1909 }
(...skipping 17 matching lines...) Expand all
1841 } 1927 }
1842 1928
1843 __ pop(rcx); 1929 __ pop(rcx);
1844 if (expr->ends_initialization_block()) { 1930 if (expr->ends_initialization_block()) {
1845 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later. 1931 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later.
1846 } else { 1932 } else {
1847 __ pop(rdx); 1933 __ pop(rdx);
1848 } 1934 }
1849 // Record source code position before IC call. 1935 // Record source code position before IC call.
1850 SetSourcePosition(expr->position()); 1936 SetSourcePosition(expr->position());
1851 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 1937 Handle<Code> ic(Builtins::builtin(
1938 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
1939 : Builtins::KeyedStoreIC_Initialize));
1852 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1940 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1853 1941
1854 // If the assignment ends an initialization block, revert to fast case. 1942 // If the assignment ends an initialization block, revert to fast case.
1855 if (expr->ends_initialization_block()) { 1943 if (expr->ends_initialization_block()) {
1856 __ pop(rdx); 1944 __ pop(rdx);
1857 __ push(rax); // Result of assignment, saved even if not needed. 1945 __ push(rax); // Result of assignment, saved even if not needed.
1858 __ push(rdx); 1946 __ push(rdx);
1859 __ CallRuntime(Runtime::kToFastProperties, 1); 1947 __ CallRuntime(Runtime::kToFastProperties, 1);
1860 __ pop(rax); 1948 __ pop(rax);
1861 } 1949 }
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
1957 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); 2045 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1958 __ CallStub(&stub); 2046 __ CallStub(&stub);
1959 RecordJSReturnSite(expr); 2047 RecordJSReturnSite(expr);
1960 // Restore context register. 2048 // Restore context register.
1961 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 2049 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1962 // Discard the function left on TOS. 2050 // Discard the function left on TOS.
1963 context()->DropAndPlug(1, rax); 2051 context()->DropAndPlug(1, rax);
1964 } 2052 }
1965 2053
1966 2054
2055 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2056 int arg_count) {
2057 // Push copy of the first argument or undefined if it doesn't exist.
2058 if (arg_count > 0) {
2059 __ push(Operand(rsp, arg_count * kPointerSize));
2060 } else {
2061 __ PushRoot(Heap::kUndefinedValueRootIndex);
2062 }
2063
2064 // Push the receiver of the enclosing function and do runtime call.
2065 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
2066
2067 // Push the strict mode flag.
2068 __ Push(Smi::FromInt(strict_mode_flag()));
2069
2070 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2071 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2072 : Runtime::kResolvePossiblyDirectEval, 4);
2073 }
2074
2075
1967 void FullCodeGenerator::VisitCall(Call* expr) { 2076 void FullCodeGenerator::VisitCall(Call* expr) {
1968 #ifdef DEBUG 2077 #ifdef DEBUG
1969 // We want to verify that RecordJSReturnSite gets called on all paths 2078 // We want to verify that RecordJSReturnSite gets called on all paths
1970 // through this function. Avoid early returns. 2079 // through this function. Avoid early returns.
1971 expr->return_is_recorded_ = false; 2080 expr->return_is_recorded_ = false;
1972 #endif 2081 #endif
1973 2082
1974 Comment cmnt(masm_, "[ Call"); 2083 Comment cmnt(masm_, "[ Call");
1975 Expression* fun = expr->expression(); 2084 Expression* fun = expr->expression();
1976 Variable* var = fun->AsVariableProxy()->AsVariable(); 2085 Variable* var = fun->AsVariableProxy()->AsVariable();
1977 2086
1978 if (var != NULL && var->is_possibly_eval()) { 2087 if (var != NULL && var->is_possibly_eval()) {
1979 // In a call to eval, we first call %ResolvePossiblyDirectEval to 2088 // In a call to eval, we first call %ResolvePossiblyDirectEval to
1980 // resolve the function we need to call and the receiver of the 2089 // resolve the function we need to call and the receiver of the
1981 // call. Then we call the resolved function using the given 2090 // call. Then we call the resolved function using the given
1982 // arguments. 2091 // arguments.
1983 ZoneList<Expression*>* args = expr->arguments(); 2092 ZoneList<Expression*>* args = expr->arguments();
1984 int arg_count = args->length(); 2093 int arg_count = args->length();
1985 { PreservePositionScope pos_scope(masm()->positions_recorder()); 2094 { PreservePositionScope pos_scope(masm()->positions_recorder());
1986 VisitForStackValue(fun); 2095 VisitForStackValue(fun);
1987 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. 2096 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
1988 2097
1989 // Push the arguments. 2098 // Push the arguments.
1990 for (int i = 0; i < arg_count; i++) { 2099 for (int i = 0; i < arg_count; i++) {
1991 VisitForStackValue(args->at(i)); 2100 VisitForStackValue(args->at(i));
1992 } 2101 }
1993 2102
1994 // Push copy of the function - found below the arguments. 2103 // If we know that eval can only be shadowed by eval-introduced
1995 __ push(Operand(rsp, (arg_count + 1) * kPointerSize)); 2104 // variables we attempt to load the global eval function directly
1996 2105 // in generated code. If we succeed, there is no need to perform a
1997 // Push copy of the first argument or undefined if it doesn't exist. 2106 // context lookup in the runtime system.
1998 if (arg_count > 0) { 2107 Label done;
1999 __ push(Operand(rsp, arg_count * kPointerSize)); 2108 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2000 } else { 2109 Label slow;
2001 __ PushRoot(Heap::kUndefinedValueRootIndex); 2110 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2111 NOT_INSIDE_TYPEOF,
2112 &slow);
2113 // Push the function and resolve eval.
2114 __ push(rax);
2115 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2116 __ jmp(&done);
2117 __ bind(&slow);
2002 } 2118 }
2003 2119
2004 // Push the receiver of the enclosing function and do runtime call. 2120 // Push copy of the function (found below the arguments) and
2005 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize)); 2121 // resolve eval.
2006 // Push the strict mode flag. 2122 __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
2007 __ Push(Smi::FromInt(strict_mode_flag())); 2123 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2008 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); 2124 if (done.is_linked()) {
2125 __ bind(&done);
2126 }
2009 2127
2010 // The runtime call returns a pair of values in rax (function) and 2128 // The runtime call returns a pair of values in rax (function) and
2011 // rdx (receiver). Touch up the stack with the right values. 2129 // rdx (receiver). Touch up the stack with the right values.
2012 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); 2130 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
2013 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax); 2131 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
2014 } 2132 }
2015 // Record source position for debugger. 2133 // Record source position for debugger.
2016 SetSourcePosition(expr->position()); 2134 SetSourcePosition(expr->position());
2017 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 2135 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2018 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); 2136 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after
2378 Label* if_false = NULL; 2496 Label* if_false = NULL;
2379 Label* fall_through = NULL; 2497 Label* fall_through = NULL;
2380 context()->PrepareTest(&materialize_true, &materialize_false, 2498 context()->PrepareTest(&materialize_true, &materialize_false,
2381 &if_true, &if_false, &fall_through); 2499 &if_true, &if_false, &fall_through);
2382 2500
2383 // Get the frame pointer for the calling frame. 2501 // Get the frame pointer for the calling frame.
2384 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 2502 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2385 2503
2386 // Skip the arguments adaptor frame if it exists. 2504 // Skip the arguments adaptor frame if it exists.
2387 Label check_frame_marker; 2505 Label check_frame_marker;
2388 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), 2506 __ Cmp(Operand(rax, StandardFrameConstants::kContextOffset),
2389 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 2507 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2390 __ j(not_equal, &check_frame_marker); 2508 __ j(not_equal, &check_frame_marker);
2391 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); 2509 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
2392 2510
2393 // Check the marker in the calling frame. 2511 // Check the marker in the calling frame.
2394 __ bind(&check_frame_marker); 2512 __ bind(&check_frame_marker);
2395 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), 2513 __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
2396 Smi::FromInt(StackFrame::CONSTRUCT)); 2514 Smi::FromInt(StackFrame::CONSTRUCT));
2397 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); 2515 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2398 Split(equal, if_true, if_false, fall_through); 2516 Split(equal, if_true, if_false, fall_through);
2399 2517
2400 context()->Plug(if_true, if_false); 2518 context()->Plug(if_true, if_false);
2401 } 2519 }
2402 2520
2403 2521
2404 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { 2522 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2405 ASSERT(args->length() == 2); 2523 ASSERT(args->length() == 2);
2406 2524
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
2440 2558
2441 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { 2559 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2442 ASSERT(args->length() == 0); 2560 ASSERT(args->length() == 0);
2443 2561
2444 NearLabel exit; 2562 NearLabel exit;
2445 // Get the number of formal parameters. 2563 // Get the number of formal parameters.
2446 __ Move(rax, Smi::FromInt(scope()->num_parameters())); 2564 __ Move(rax, Smi::FromInt(scope()->num_parameters()));
2447 2565
2448 // Check if the calling frame is an arguments adaptor frame. 2566 // Check if the calling frame is an arguments adaptor frame.
2449 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 2567 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2450 __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset), 2568 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
2451 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 2569 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2452 __ j(not_equal, &exit); 2570 __ j(not_equal, &exit);
2453 2571
2454 // Arguments adaptor case: Read the arguments length from the 2572 // Arguments adaptor case: Read the arguments length from the
2455 // adaptor frame. 2573 // adaptor frame.
2456 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 2574 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2457 2575
2458 __ bind(&exit); 2576 __ bind(&exit);
2459 if (FLAG_debug_code) __ AbortIfNotSmi(rax); 2577 if (FLAG_debug_code) __ AbortIfNotSmi(rax);
2460 context()->Plug(rax); 2578 context()->Plug(rax);
2461 } 2579 }
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
2615 __ bind(&done); 2733 __ bind(&done);
2616 context()->Plug(rax); 2734 context()->Plug(rax);
2617 } 2735 }
2618 2736
2619 2737
2620 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) { 2738 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2621 // Load the arguments on the stack and call the runtime function. 2739 // Load the arguments on the stack and call the runtime function.
2622 ASSERT(args->length() == 2); 2740 ASSERT(args->length() == 2);
2623 VisitForStackValue(args->at(0)); 2741 VisitForStackValue(args->at(0));
2624 VisitForStackValue(args->at(1)); 2742 VisitForStackValue(args->at(1));
2625 __ CallRuntime(Runtime::kMath_pow, 2); 2743 MathPowStub stub;
2744 __ CallStub(&stub);
2626 context()->Plug(rax); 2745 context()->Plug(rax);
2627 } 2746 }
2628 2747
2629 2748
2630 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { 2749 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2631 ASSERT(args->length() == 2); 2750 ASSERT(args->length() == 2);
2632 2751
2633 VisitForStackValue(args->at(0)); // Load the object. 2752 VisitForStackValue(args->at(0)); // Load the object.
2634 VisitForAccumulatorValue(args->at(1)); // Load the value. 2753 VisitForAccumulatorValue(args->at(1)); // Load the value.
2635 __ pop(rbx); // rax = value. rbx = object. 2754 __ pop(rbx); // rax = value. rbx = object.
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
2799 VisitForStackValue(args->at(1)); 2918 VisitForStackValue(args->at(1));
2800 2919
2801 StringCompareStub stub; 2920 StringCompareStub stub;
2802 __ CallStub(&stub); 2921 __ CallStub(&stub);
2803 context()->Plug(rax); 2922 context()->Plug(rax);
2804 } 2923 }
2805 2924
2806 2925
2807 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { 2926 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2808 // Load the argument on the stack and call the stub. 2927 // Load the argument on the stack and call the stub.
2809 TranscendentalCacheStub stub(TranscendentalCache::SIN); 2928 TranscendentalCacheStub stub(TranscendentalCache::SIN,
2929 TranscendentalCacheStub::TAGGED);
2810 ASSERT(args->length() == 1); 2930 ASSERT(args->length() == 1);
2811 VisitForStackValue(args->at(0)); 2931 VisitForStackValue(args->at(0));
2812 __ CallStub(&stub); 2932 __ CallStub(&stub);
2813 context()->Plug(rax); 2933 context()->Plug(rax);
2814 } 2934 }
2815 2935
2816 2936
2817 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { 2937 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2818 // Load the argument on the stack and call the stub. 2938 // Load the argument on the stack and call the stub.
2819 TranscendentalCacheStub stub(TranscendentalCache::COS); 2939 TranscendentalCacheStub stub(TranscendentalCache::COS,
2940 TranscendentalCacheStub::TAGGED);
2820 ASSERT(args->length() == 1); 2941 ASSERT(args->length() == 1);
2821 VisitForStackValue(args->at(0)); 2942 VisitForStackValue(args->at(0));
2822 __ CallStub(&stub); 2943 __ CallStub(&stub);
2823 context()->Plug(rax); 2944 context()->Plug(rax);
2824 } 2945 }
2825 2946
2826 2947
2827 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) { 2948 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
2828 // Load the argument on the stack and call the stub. 2949 // Load the argument on the stack and call the stub.
2829 TranscendentalCacheStub stub(TranscendentalCache::LOG); 2950 TranscendentalCacheStub stub(TranscendentalCache::LOG,
2951 TranscendentalCacheStub::TAGGED);
2830 ASSERT(args->length() == 1); 2952 ASSERT(args->length() == 1);
2831 VisitForStackValue(args->at(0)); 2953 VisitForStackValue(args->at(0));
2832 __ CallStub(&stub); 2954 __ CallStub(&stub);
2833 context()->Plug(rax); 2955 context()->Plug(rax);
2834 } 2956 }
2835 2957
2836 2958
2837 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) { 2959 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2838 // Load the argument on the stack and call the runtime function. 2960 // Load the argument on the stack and call the runtime function.
2839 ASSERT(args->length() == 1); 2961 ASSERT(args->length() == 1);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2871 __ CallStub(&stub); 2993 __ CallStub(&stub);
2872 context()->Plug(rax); 2994 context()->Plug(rax);
2873 } 2995 }
2874 2996
2875 2997
2876 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { 2998 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2877 ASSERT(args->length() == 3); 2999 ASSERT(args->length() == 3);
2878 VisitForStackValue(args->at(0)); 3000 VisitForStackValue(args->at(0));
2879 VisitForStackValue(args->at(1)); 3001 VisitForStackValue(args->at(1));
2880 VisitForStackValue(args->at(2)); 3002 VisitForStackValue(args->at(2));
3003 Label done;
3004 Label slow_case;
3005 Register object = rax;
3006 Register index_1 = rbx;
3007 Register index_2 = rcx;
3008 Register elements = rdi;
3009 Register temp = rdx;
3010 __ movq(object, Operand(rsp, 2 * kPointerSize));
3011 // Fetch the map and check if array is in fast case.
3012 // Check that object doesn't require security checks and
3013 // has no indexed interceptor.
3014 __ CmpObjectType(object, JS_ARRAY_TYPE, temp);
3015 __ j(not_equal, &slow_case);
3016 __ testb(FieldOperand(temp, Map::kBitFieldOffset),
3017 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
3018 __ j(not_zero, &slow_case);
3019
3020 // Check the object's elements are in fast case and writable.
3021 __ movq(elements, FieldOperand(object, JSObject::kElementsOffset));
3022 __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
3023 Heap::kFixedArrayMapRootIndex);
3024 __ j(not_equal, &slow_case);
3025
3026 // Check that both indices are smis.
3027 __ movq(index_1, Operand(rsp, 1 * kPointerSize));
3028 __ movq(index_2, Operand(rsp, 0 * kPointerSize));
3029 __ JumpIfNotBothSmi(index_1, index_2, &slow_case);
3030
3031 // Check that both indices are valid.
3032 // The JSArray length field is a smi since the array is in fast case mode.
3033 __ movq(temp, FieldOperand(object, JSArray::kLengthOffset));
3034 __ SmiCompare(temp, index_1);
3035 __ j(below_equal, &slow_case);
3036 __ SmiCompare(temp, index_2);
3037 __ j(below_equal, &slow_case);
3038
3039 __ SmiToInteger32(index_1, index_1);
3040 __ SmiToInteger32(index_2, index_2);
3041 // Bring addresses into index1 and index2.
3042 __ lea(index_1, FieldOperand(elements, index_1, times_pointer_size,
3043 FixedArray::kHeaderSize));
3044 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size,
3045 FixedArray::kHeaderSize));
3046
3047 // Swap elements. Use object and temp as scratch registers.
3048 __ movq(object, Operand(index_1, 0));
3049 __ movq(temp, Operand(index_2, 0));
3050 __ movq(Operand(index_2, 0), object);
3051 __ movq(Operand(index_1, 0), temp);
3052
3053 Label new_space;
3054 __ InNewSpace(elements, temp, equal, &new_space);
3055
3056 __ movq(object, elements);
3057 __ RecordWriteHelper(object, index_1, temp);
3058 __ RecordWriteHelper(elements, index_2, temp);
3059
3060 __ bind(&new_space);
3061 // We are done. Drop elements from the stack, and return undefined.
3062 __ addq(rsp, Immediate(3 * kPointerSize));
3063 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3064 __ jmp(&done);
3065
3066 __ bind(&slow_case);
2881 __ CallRuntime(Runtime::kSwapElements, 3); 3067 __ CallRuntime(Runtime::kSwapElements, 3);
3068
3069 __ bind(&done);
2882 context()->Plug(rax); 3070 context()->Plug(rax);
2883 } 3071 }
2884 3072
2885 3073
2886 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { 3074 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
2887 ASSERT_EQ(2, args->length()); 3075 ASSERT_EQ(2, args->length());
2888 3076
2889 ASSERT_NE(NULL, args->at(0)->AsLiteral()); 3077 ASSERT_NE(NULL, args->at(0)->AsLiteral());
2890 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); 3078 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
2891 3079
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
2994 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); 3182 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2995 __ j(zero, if_true); 3183 __ j(zero, if_true);
2996 __ jmp(if_false); 3184 __ jmp(if_false);
2997 3185
2998 context()->Plug(if_true, if_false); 3186 context()->Plug(if_true, if_false);
2999 } 3187 }
3000 3188
3001 3189
3002 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { 3190 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3003 ASSERT(args->length() == 1); 3191 ASSERT(args->length() == 1);
3192 VisitForAccumulatorValue(args->at(0));
3004 3193
3005 VisitForAccumulatorValue(args->at(0)); 3194 if (FLAG_debug_code) {
3195 __ AbortIfNotString(rax);
3196 }
3006 3197
3007 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset)); 3198 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
3008 ASSERT(String::kHashShift >= kSmiTagSize); 3199 ASSERT(String::kHashShift >= kSmiTagSize);
3009 __ IndexFromHash(rax, rax); 3200 __ IndexFromHash(rax, rax);
3010 3201
3011 context()->Plug(rax); 3202 context()->Plug(rax);
3012 } 3203 }
3013 3204
3014 3205
3015 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { 3206 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
3069 context()->Plug(false); 3260 context()->Plug(false);
3070 } else { 3261 } else {
3071 VisitForStackValue(prop->obj()); 3262 VisitForStackValue(prop->obj());
3072 VisitForStackValue(prop->key()); 3263 VisitForStackValue(prop->key());
3073 __ Push(Smi::FromInt(strict_mode_flag())); 3264 __ Push(Smi::FromInt(strict_mode_flag()));
3074 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); 3265 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3075 context()->Plug(rax); 3266 context()->Plug(rax);
3076 } 3267 }
3077 } else if (var != NULL) { 3268 } else if (var != NULL) {
3078 // Delete of an unqualified identifier is disallowed in strict mode 3269 // Delete of an unqualified identifier is disallowed in strict mode
3079 // so this code can only be reached in non-strict mode. 3270 // but "delete this" is.
3080 ASSERT(strict_mode_flag() == kNonStrictMode); 3271 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
3081 if (var->is_global()) { 3272 if (var->is_global()) {
3082 __ push(GlobalObjectOperand()); 3273 __ push(GlobalObjectOperand());
3083 __ Push(var->name()); 3274 __ Push(var->name());
3084 __ Push(Smi::FromInt(kNonStrictMode)); 3275 __ Push(Smi::FromInt(kNonStrictMode));
3085 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); 3276 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3086 context()->Plug(rax); 3277 context()->Plug(rax);
3087 } else if (var->AsSlot() != NULL && 3278 } else if (var->AsSlot() != NULL &&
3088 var->AsSlot()->type() != Slot::LOOKUP) { 3279 var->AsSlot()->type() != Slot::LOOKUP) {
3089 // Result of deleting non-global, non-dynamic variables is false. 3280 // Result of deleting non-global, non-dynamic variables is false.
3090 // The subexpression does not have side effects. 3281 // The subexpression does not have side effects.
(...skipping 17 matching lines...) Expand all
3108 3299
3109 case Token::VOID: { 3300 case Token::VOID: {
3110 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 3301 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3111 VisitForEffect(expr->expression()); 3302 VisitForEffect(expr->expression());
3112 context()->Plug(Heap::kUndefinedValueRootIndex); 3303 context()->Plug(Heap::kUndefinedValueRootIndex);
3113 break; 3304 break;
3114 } 3305 }
3115 3306
3116 case Token::NOT: { 3307 case Token::NOT: {
3117 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 3308 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
3118 Label materialize_true, materialize_false; 3309 if (context()->IsEffect()) {
3119 Label* if_true = NULL; 3310 // Unary NOT has no side effects so it's only necessary to visit the
3120 Label* if_false = NULL; 3311 // subexpression. Match the optimizing compiler by not branching.
3121 Label* fall_through = NULL; 3312 VisitForEffect(expr->expression());
3122 // Notice that the labels are swapped. 3313 } else {
3123 context()->PrepareTest(&materialize_true, &materialize_false, 3314 Label materialize_true, materialize_false;
3124 &if_false, &if_true, &fall_through); 3315 Label* if_true = NULL;
3125 if (context()->IsTest()) ForwardBailoutToChild(expr); 3316 Label* if_false = NULL;
3126 VisitForControl(expr->expression(), if_true, if_false, fall_through); 3317 Label* fall_through = NULL;
3127 context()->Plug(if_false, if_true); // Labels swapped. 3318 // Notice that the labels are swapped.
3319 context()->PrepareTest(&materialize_true, &materialize_false,
3320 &if_false, &if_true, &fall_through);
3321 if (context()->IsTest()) ForwardBailoutToChild(expr);
3322 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3323 context()->Plug(if_false, if_true); // Labels swapped.
3324 }
3128 break; 3325 break;
3129 } 3326 }
3130 3327
3131 case Token::TYPEOF: { 3328 case Token::TYPEOF: {
3132 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 3329 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
3133 { StackValueContext context(this); 3330 { StackValueContext context(this);
3134 VisitForTypeofValue(expr->expression()); 3331 VisitForTypeofValue(expr->expression());
3135 } 3332 }
3136 __ CallRuntime(Runtime::kTypeof, 1); 3333 __ CallRuntime(Runtime::kTypeof, 1);
3137 context()->Plug(rax); 3334 context()->Plug(rax);
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
3343 // Perform the assignment as if via '='. 3540 // Perform the assignment as if via '='.
3344 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 3541 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3345 Token::ASSIGN); 3542 Token::ASSIGN);
3346 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3543 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3347 context()->Plug(rax); 3544 context()->Plug(rax);
3348 } 3545 }
3349 break; 3546 break;
3350 case NAMED_PROPERTY: { 3547 case NAMED_PROPERTY: {
3351 __ Move(rcx, prop->key()->AsLiteral()->handle()); 3548 __ Move(rcx, prop->key()->AsLiteral()->handle());
3352 __ pop(rdx); 3549 __ pop(rdx);
3353 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 3550 Handle<Code> ic(Builtins::builtin(
3551 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
3552 : Builtins::StoreIC_Initialize));
3354 EmitCallIC(ic, RelocInfo::CODE_TARGET); 3553 EmitCallIC(ic, RelocInfo::CODE_TARGET);
3355 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3554 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3356 if (expr->is_postfix()) { 3555 if (expr->is_postfix()) {
3357 if (!context()->IsEffect()) { 3556 if (!context()->IsEffect()) {
3358 context()->PlugTOS(); 3557 context()->PlugTOS();
3359 } 3558 }
3360 } else { 3559 } else {
3361 context()->Plug(rax); 3560 context()->Plug(rax);
3362 } 3561 }
3363 break; 3562 break;
3364 } 3563 }
3365 case KEYED_PROPERTY: { 3564 case KEYED_PROPERTY: {
3366 __ pop(rcx); 3565 __ pop(rcx);
3367 __ pop(rdx); 3566 __ pop(rdx);
3368 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 3567 Handle<Code> ic(Builtins::builtin(
3568 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
3569 : Builtins::KeyedStoreIC_Initialize));
3369 EmitCallIC(ic, RelocInfo::CODE_TARGET); 3570 EmitCallIC(ic, RelocInfo::CODE_TARGET);
3370 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3571 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3371 if (expr->is_postfix()) { 3572 if (expr->is_postfix()) {
3372 if (!context()->IsEffect()) { 3573 if (!context()->IsEffect()) {
3373 context()->PlugTOS(); 3574 context()->PlugTOS();
3374 } 3575 }
3375 } else { 3576 } else {
3376 context()->Plug(rax); 3577 context()->Plug(rax);
3377 } 3578 }
3378 break; 3579 break;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
3437 UnaryOperation* left_unary = left->AsUnaryOperation(); 3638 UnaryOperation* left_unary = left->AsUnaryOperation();
3438 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; 3639 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
3439 Handle<String> check = Handle<String>::cast(right_literal_value); 3640 Handle<String> check = Handle<String>::cast(right_literal_value);
3440 3641
3441 { AccumulatorValueContext context(this); 3642 { AccumulatorValueContext context(this);
3442 VisitForTypeofValue(left_unary->expression()); 3643 VisitForTypeofValue(left_unary->expression());
3443 } 3644 }
3444 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); 3645 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3445 3646
3446 if (check->Equals(Heap::number_symbol())) { 3647 if (check->Equals(Heap::number_symbol())) {
3447 Condition is_smi = masm_->CheckSmi(rax); 3648 __ JumpIfSmi(rax, if_true);
3448 __ j(is_smi, if_true);
3449 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); 3649 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
3450 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); 3650 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
3451 Split(equal, if_true, if_false, fall_through); 3651 Split(equal, if_true, if_false, fall_through);
3452 } else if (check->Equals(Heap::string_symbol())) { 3652 } else if (check->Equals(Heap::string_symbol())) {
3453 Condition is_smi = masm_->CheckSmi(rax); 3653 __ JumpIfSmi(rax, if_false);
3454 __ j(is_smi, if_false);
3455 // Check for undetectable objects => false. 3654 // Check for undetectable objects => false.
3456 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); 3655 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx);
3656 __ j(above_equal, if_false);
3457 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), 3657 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
3458 Immediate(1 << Map::kIsUndetectable)); 3658 Immediate(1 << Map::kIsUndetectable));
3459 __ j(not_zero, if_false); 3659 Split(zero, if_true, if_false, fall_through);
3460 __ CmpInstanceType(rdx, FIRST_NONSTRING_TYPE);
3461 Split(below, if_true, if_false, fall_through);
3462 } else if (check->Equals(Heap::boolean_symbol())) { 3660 } else if (check->Equals(Heap::boolean_symbol())) {
3463 __ CompareRoot(rax, Heap::kTrueValueRootIndex); 3661 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
3464 __ j(equal, if_true); 3662 __ j(equal, if_true);
3465 __ CompareRoot(rax, Heap::kFalseValueRootIndex); 3663 __ CompareRoot(rax, Heap::kFalseValueRootIndex);
3466 Split(equal, if_true, if_false, fall_through); 3664 Split(equal, if_true, if_false, fall_through);
3467 } else if (check->Equals(Heap::undefined_symbol())) { 3665 } else if (check->Equals(Heap::undefined_symbol())) {
3468 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); 3666 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
3469 __ j(equal, if_true); 3667 __ j(equal, if_true);
3470 Condition is_smi = masm_->CheckSmi(rax); 3668 __ JumpIfSmi(rax, if_false);
3471 __ j(is_smi, if_false);
3472 // Check for undetectable objects => true. 3669 // Check for undetectable objects => true.
3473 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); 3670 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
3474 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), 3671 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
3475 Immediate(1 << Map::kIsUndetectable)); 3672 Immediate(1 << Map::kIsUndetectable));
3476 Split(not_zero, if_true, if_false, fall_through); 3673 Split(not_zero, if_true, if_false, fall_through);
3477 } else if (check->Equals(Heap::function_symbol())) { 3674 } else if (check->Equals(Heap::function_symbol())) {
3478 Condition is_smi = masm_->CheckSmi(rax); 3675 __ JumpIfSmi(rax, if_false);
3479 __ j(is_smi, if_false); 3676 __ CmpObjectType(rax, FIRST_FUNCTION_CLASS_TYPE, rdx);
3480 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx); 3677 Split(above_equal, if_true, if_false, fall_through);
3481 __ j(equal, if_true);
3482 // Regular expressions => 'function' (they are callable).
3483 __ CmpInstanceType(rdx, JS_REGEXP_TYPE);
3484 Split(equal, if_true, if_false, fall_through);
3485 } else if (check->Equals(Heap::object_symbol())) { 3678 } else if (check->Equals(Heap::object_symbol())) {
3486 Condition is_smi = masm_->CheckSmi(rax); 3679 __ JumpIfSmi(rax, if_false);
3487 __ j(is_smi, if_false);
3488 __ CompareRoot(rax, Heap::kNullValueRootIndex); 3680 __ CompareRoot(rax, Heap::kNullValueRootIndex);
3489 __ j(equal, if_true); 3681 __ j(equal, if_true);
3490 // Regular expressions => 'function', not 'object'. 3682 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rdx);
3491 __ CmpObjectType(rax, JS_REGEXP_TYPE, rdx); 3683 __ j(below, if_false);
3492 __ j(equal, if_false); 3684 __ CmpInstanceType(rdx, FIRST_FUNCTION_CLASS_TYPE);
3685 __ j(above_equal, if_false);
3493 // Check for undetectable objects => false. 3686 // Check for undetectable objects => false.
3494 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), 3687 __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
3495 Immediate(1 << Map::kIsUndetectable)); 3688 Immediate(1 << Map::kIsUndetectable));
3496 __ j(not_zero, if_false); 3689 Split(zero, if_true, if_false, fall_through);
3497 // Check for JS objects => true.
3498 __ CmpInstanceType(rdx, FIRST_JS_OBJECT_TYPE);
3499 __ j(below, if_false);
3500 __ CmpInstanceType(rdx, LAST_JS_OBJECT_TYPE);
3501 Split(below_equal, if_true, if_false, fall_through);
3502 } else { 3690 } else {
3503 if (if_false != fall_through) __ jmp(if_false); 3691 if (if_false != fall_through) __ jmp(if_false);
3504 } 3692 }
3505 3693
3506 return true; 3694 return true;
3507 } 3695 }
3508 3696
3509 3697
3510 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 3698 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3511 Comment cmnt(masm_, "[ CompareOperation"); 3699 Comment cmnt(masm_, "[ CompareOperation");
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
3703 __ nop(); // Signals no inlined code. 3891 __ nop(); // Signals no inlined code.
3704 break; 3892 break;
3705 default: 3893 default:
3706 // Do nothing. 3894 // Do nothing.
3707 break; 3895 break;
3708 } 3896 }
3709 } 3897 }
3710 3898
3711 3899
3712 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { 3900 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
3901 switch (ic->kind()) {
3902 case Code::LOAD_IC:
3903 __ IncrementCounter(&Counters::named_load_full, 1);
3904 break;
3905 case Code::KEYED_LOAD_IC:
3906 __ IncrementCounter(&Counters::keyed_load_full, 1);
3907 break;
3908 case Code::STORE_IC:
3909 __ IncrementCounter(&Counters::named_store_full, 1);
3910 break;
3911 case Code::KEYED_STORE_IC:
3912 __ IncrementCounter(&Counters::keyed_store_full, 1);
3913 default:
3914 break;
3915 }
3916
3713 __ call(ic, RelocInfo::CODE_TARGET); 3917 __ call(ic, RelocInfo::CODE_TARGET);
3714 if (patch_site != NULL && patch_site->is_bound()) { 3918 if (patch_site != NULL && patch_site->is_bound()) {
3715 patch_site->EmitPatchInfo(); 3919 patch_site->EmitPatchInfo();
3716 } else { 3920 } else {
3717 __ nop(); // Signals no inlined code. 3921 __ nop(); // Signals no inlined code.
3718 } 3922 }
3719 } 3923 }
3720 3924
3721 3925
3722 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { 3926 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
3763 __ ret(0); 3967 __ ret(0);
3764 } 3968 }
3765 3969
3766 3970
3767 #undef __ 3971 #undef __
3768 3972
3769 3973
3770 } } // namespace v8::internal 3974 } } // namespace v8::internal
3771 3975
3772 #endif // V8_TARGET_ARCH_X64 3976 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/frames-x64.cc ('k') | src/x64/ic-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698