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

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

Issue 6614010: [Isolates] Merge 6700:7030 from bleeding_edge to isolates. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/isolates/
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 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 // Store new arguments object in both "arguments" and ".arguments" slots.
204 __ movq(rcx, rax); 204 __ movq(rcx, rax);
205 Move(arguments->AsSlot(), rax, rbx, rdx); 205 Move(arguments->AsSlot(), rax, rbx, rdx);
206 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); 206 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
207 Move(dot_arguments_slot, rcx, rbx, rdx); 207 Move(dot_arguments_slot, rcx, rbx, rdx);
208 } 208 }
209 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 }
224
225 if (FLAG_trace) { 210 if (FLAG_trace) {
226 __ CallRuntime(Runtime::kTraceEnter, 0); 211 __ CallRuntime(Runtime::kTraceEnter, 0);
227 } 212 }
228 213
229 { Comment cmnt(masm_, "[ Stack check"); 214 // Visit the declarations and body unless there is an illegal
230 PrepareForBailout(info->function(), NO_REGISTERS); 215 // redeclaration.
231 NearLabel ok; 216 if (scope()->HasIllegalRedeclaration()) {
232 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 217 Comment cmnt(masm_, "[ Declarations");
233 __ j(above_equal, &ok); 218 scope()->VisitIllegalRedeclaration(this);
234 StackCheckStub stub; 219 } else {
235 __ CallStub(&stub); 220 { Comment cmnt(masm_, "[ Declarations");
236 __ bind(&ok); 221 // For named function expressions, declare the function name as a
222 // constant.
223 if (scope()->is_function_scope() && scope()->function() != NULL) {
224 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
225 }
226 VisitDeclarations(scope()->declarations());
227 }
228
229 { Comment cmnt(masm_, "[ Stack check");
230 PrepareForBailout(info->function(), NO_REGISTERS);
231 NearLabel ok;
232 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
233 __ j(above_equal, &ok);
234 StackCheckStub stub;
235 __ CallStub(&stub);
236 __ bind(&ok);
237 }
238
239 { Comment cmnt(masm_, "[ Body");
240 ASSERT(loop_depth() == 0);
241 VisitStatements(function()->body());
242 ASSERT(loop_depth() == 0);
243 }
237 } 244 }
238 245
239 { Comment cmnt(masm_, "[ Body"); 246 // Always emit a 'return undefined' in case control fell off the end of
240 ASSERT(loop_depth() == 0); 247 // the body.
241 VisitStatements(function()->body());
242 ASSERT(loop_depth() == 0);
243 }
244
245 { Comment cmnt(masm_, "[ return <undefined>;"); 248 { 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); 249 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
248 EmitReturnSequence(); 250 EmitReturnSequence();
249 } 251 }
250 } 252 }
251 253
252 254
253 void FullCodeGenerator::ClearAccumulator() { 255 void FullCodeGenerator::ClearAccumulator() {
254 __ Set(rax, 0); 256 __ Set(rax, 0);
255 } 257 }
256 258
257 259
258 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { 260 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
259 Comment cmnt(masm_, "[ Stack check"); 261 Comment cmnt(masm_, "[ Stack check");
260 NearLabel ok; 262 NearLabel ok;
261 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 263 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
262 __ j(above_equal, &ok); 264 __ j(above_equal, &ok);
263 StackCheckStub stub; 265 StackCheckStub stub;
264 __ CallStub(&stub); 266 __ CallStub(&stub);
265 // Record a mapping of this PC offset to the OSR id. This is used to find 267 // 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 268 // 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. 269 // the deoptimization input data found in the optimized code.
268 RecordStackCheck(stmt->OsrEntryId()); 270 RecordStackCheck(stmt->OsrEntryId());
269 271
272 // Loop stack checks can be patched to perform on-stack replacement. In
273 // order to decide whether or not to perform OSR we embed the loop depth
274 // in a test instruction after the call so we can extract it from the OSR
275 // builtin.
276 ASSERT(loop_depth() > 0);
277 __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker)));
278
270 __ bind(&ok); 279 __ bind(&ok);
271 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); 280 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
272 // Record a mapping of the OSR id to this PC. This is used if the OSR 281 // 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 282 // entry becomes the target of a bailout. We don't expect it to be, but
274 // we want it to work if it is. 283 // we want it to work if it is.
275 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); 284 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
276 } 285 }
277 286
278 287
279 void FullCodeGenerator::EmitReturnSequence() { 288 void FullCodeGenerator::EmitReturnSequence() {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 } 320 }
312 // Check that the size of the code used for returning is large enough 321 // Check that the size of the code used for returning is large enough
313 // for the debugger's requirements. 322 // for the debugger's requirements.
314 ASSERT(Assembler::kJSReturnSequenceLength <= 323 ASSERT(Assembler::kJSReturnSequenceLength <=
315 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); 324 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
316 #endif 325 #endif
317 } 326 }
318 } 327 }
319 328
320 329
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 { 330 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
329 } 331 }
330 332
331 333
332 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { 334 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
333 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); 335 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
334 __ movq(result_register(), slot_operand); 336 __ movq(result_register(), slot_operand);
335 } 337 }
336 338
337 339
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 void FullCodeGenerator::DoTest(Label* if_true, 538 void FullCodeGenerator::DoTest(Label* if_true,
537 Label* if_false, 539 Label* if_false,
538 Label* fall_through) { 540 Label* fall_through) {
539 // Emit the inlined tests assumed by the stub. 541 // Emit the inlined tests assumed by the stub.
540 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex); 542 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex);
541 __ j(equal, if_false); 543 __ j(equal, if_false);
542 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); 544 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
543 __ j(equal, if_true); 545 __ j(equal, if_true);
544 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex); 546 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex);
545 __ j(equal, if_false); 547 __ j(equal, if_false);
546 ASSERT_EQ(0, kSmiTag); 548 STATIC_ASSERT(kSmiTag == 0);
547 __ SmiCompare(result_register(), Smi::FromInt(0)); 549 __ SmiCompare(result_register(), Smi::FromInt(0));
548 __ j(equal, if_false); 550 __ j(equal, if_false);
549 Condition is_smi = masm_->CheckSmi(result_register()); 551 Condition is_smi = masm_->CheckSmi(result_register());
550 __ j(is_smi, if_true); 552 __ j(is_smi, if_true);
551 553
552 // Call the ToBoolean stub for all other cases. 554 // Call the ToBoolean stub for all other cases.
553 ToBooleanStub stub; 555 ToBooleanStub stub;
554 __ push(result_register()); 556 __ push(result_register());
555 __ CallStub(&stub); 557 __ CallStub(&stub);
556 __ testq(rax, rax); 558 __ testq(rax, rax);
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 VisitForAccumulatorValue(function); 728 VisitForAccumulatorValue(function);
727 __ pop(rdx); 729 __ pop(rdx);
728 } else { 730 } else {
729 __ movq(rdx, rax); 731 __ movq(rdx, rax);
730 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); 732 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex);
731 } 733 }
732 ASSERT(prop->key()->AsLiteral() != NULL && 734 ASSERT(prop->key()->AsLiteral() != NULL &&
733 prop->key()->AsLiteral()->handle()->IsSmi()); 735 prop->key()->AsLiteral()->handle()->IsSmi());
734 __ Move(rcx, prop->key()->AsLiteral()->handle()); 736 __ Move(rcx, prop->key()->AsLiteral()->handle());
735 737
736 Handle<Code> ic(isolate()->builtins()->builtin( 738 Handle<Code> ic(isolate()->builtins()->builtin(is_strict()
737 Builtins::KeyedStoreIC_Initialize)); 739 ? Builtins::KeyedStoreIC_Initialize_Strict
740 : Builtins::KeyedStoreIC_Initialize));
738 EmitCallIC(ic, RelocInfo::CODE_TARGET); 741 EmitCallIC(ic, RelocInfo::CODE_TARGET);
739 } 742 }
740 } 743 }
741 } 744 }
742 745
743 746
744 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { 747 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
745 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); 748 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
746 } 749 }
747 750
748 751
749 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 752 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
750 // Call the runtime to declare the globals. 753 // Call the runtime to declare the globals.
751 __ push(rsi); // The context is the first argument. 754 __ push(rsi); // The context is the first argument.
752 __ Push(pairs); 755 __ Push(pairs);
753 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); 756 __ Push(Smi::FromInt(is_eval() ? 1 : 0));
754 __ CallRuntime(Runtime::kDeclareGlobals, 3); 757 __ Push(Smi::FromInt(strict_mode_flag()));
758 __ CallRuntime(Runtime::kDeclareGlobals, 4);
755 // Return value is ignored. 759 // Return value is ignored.
756 } 760 }
757 761
758 762
759 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 763 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
760 Comment cmnt(masm_, "[ SwitchStatement"); 764 Comment cmnt(masm_, "[ SwitchStatement");
761 Breakable nested_statement(this, stmt); 765 Breakable nested_statement(this, stmt);
762 SetStatementPosition(stmt); 766 SetStatementPosition(stmt);
763 767
764 // Keep the switch value on the stack until a case matches. 768 // Keep the switch value on the stack until a case matches.
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
845 Label loop, exit; 849 Label loop, exit;
846 ForIn loop_statement(this, stmt); 850 ForIn loop_statement(this, stmt);
847 increment_loop_depth(); 851 increment_loop_depth();
848 852
849 // Get the object to enumerate over. Both SpiderMonkey and JSC 853 // Get the object to enumerate over. Both SpiderMonkey and JSC
850 // ignore null and undefined in contrast to the specification; see 854 // ignore null and undefined in contrast to the specification; see
851 // ECMA-262 section 12.6.4. 855 // ECMA-262 section 12.6.4.
852 VisitForAccumulatorValue(stmt->enumerable()); 856 VisitForAccumulatorValue(stmt->enumerable());
853 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); 857 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
854 __ j(equal, &exit); 858 __ j(equal, &exit);
855 __ CompareRoot(rax, Heap::kNullValueRootIndex); 859 Register null_value = rdi;
860 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
861 __ cmpq(rax, null_value);
856 __ j(equal, &exit); 862 __ j(equal, &exit);
857 863
858 // Convert the object to a JS object. 864 // Convert the object to a JS object.
859 Label convert, done_convert; 865 Label convert, done_convert;
860 __ JumpIfSmi(rax, &convert); 866 __ JumpIfSmi(rax, &convert);
861 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); 867 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
862 __ j(above_equal, &done_convert); 868 __ j(above_equal, &done_convert);
863 __ bind(&convert); 869 __ bind(&convert);
864 __ push(rax); 870 __ push(rax);
865 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 871 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
866 __ bind(&done_convert); 872 __ bind(&done_convert);
867 __ push(rax); 873 __ push(rax);
868 874
869 // BUG(867): Check cache validity in generated code. This is a fast 875 // Check cache validity in generated code. This is a fast case for
870 // case for the JSObject::IsSimpleEnum cache validity checks. If we 876 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
871 // cannot guarantee cache validity, call the runtime system to check 877 // guarantee cache validity, call the runtime system to check cache
872 // cache validity or get the property names in a fixed array. 878 // validity or get the property names in a fixed array.
879 Label next, call_runtime;
880 Register empty_fixed_array_value = r8;
881 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
882 Register empty_descriptor_array_value = r9;
883 __ LoadRoot(empty_descriptor_array_value,
884 Heap::kEmptyDescriptorArrayRootIndex);
885 __ movq(rcx, rax);
886 __ bind(&next);
887
888 // Check that there are no elements. Register rcx contains the
889 // current JS object we've reached through the prototype chain.
890 __ cmpq(empty_fixed_array_value,
891 FieldOperand(rcx, JSObject::kElementsOffset));
892 __ j(not_equal, &call_runtime);
893
894 // Check that instance descriptors are not empty so that we can
895 // check for an enum cache. Leave the map in rbx for the subsequent
896 // prototype load.
897 __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
898 __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset));
899 __ cmpq(rdx, empty_descriptor_array_value);
900 __ j(equal, &call_runtime);
901
902 // Check that there is an enum cache in the non-empty instance
903 // descriptors (rdx). This is the case if the next enumeration
904 // index field does not contain a smi.
905 __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
906 __ JumpIfSmi(rdx, &call_runtime);
907
908 // For all objects but the receiver, check that the cache is empty.
909 NearLabel check_prototype;
910 __ cmpq(rcx, rax);
911 __ j(equal, &check_prototype);
912 __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset));
913 __ cmpq(rdx, empty_fixed_array_value);
914 __ j(not_equal, &call_runtime);
915
916 // Load the prototype from the map and loop if non-null.
917 __ bind(&check_prototype);
918 __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
919 __ cmpq(rcx, null_value);
920 __ j(not_equal, &next);
921
922 // The enum cache is valid. Load the map of the object being
923 // iterated over and use the cache for the iteration.
924 NearLabel use_cache;
925 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
926 __ jmp(&use_cache);
873 927
874 // Get the set of properties to enumerate. 928 // Get the set of properties to enumerate.
929 __ bind(&call_runtime);
875 __ push(rax); // Duplicate the enumerable object on the stack. 930 __ push(rax); // Duplicate the enumerable object on the stack.
876 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); 931 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
877 932
878 // If we got a map from the runtime call, we can do a fast 933 // If we got a map from the runtime call, we can do a fast
879 // modification check. Otherwise, we got a fixed array, and we have 934 // modification check. Otherwise, we got a fixed array, and we have
880 // to do a slow check. 935 // to do a slow check.
881 NearLabel fixed_array; 936 NearLabel fixed_array;
882 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), 937 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
883 Heap::kMetaMapRootIndex); 938 Heap::kMetaMapRootIndex);
884 __ j(not_equal, &fixed_array); 939 __ j(not_equal, &fixed_array);
885 940
886 // We got a map in register rax. Get the enumeration cache from it. 941 // We got a map in register rax. Get the enumeration cache from it.
942 __ bind(&use_cache);
887 __ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset)); 943 __ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset));
888 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset)); 944 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
889 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset)); 945 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
890 946
891 // Setup the four remaining stack slots. 947 // Setup the four remaining stack slots.
892 __ push(rax); // Map. 948 __ push(rax); // Map.
893 __ push(rdx); // Enumeration cache. 949 __ push(rdx); // Enumeration cache.
894 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset)); 950 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
895 __ push(rax); // Enumeration cache length (as smi). 951 __ push(rax); // Enumeration cache length (as smi).
896 __ Push(Smi::FromInt(0)); // Initial index. 952 __ Push(Smi::FromInt(0)); // Initial index.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
965 1021
966 // Exit and decrement the loop depth. 1022 // Exit and decrement the loop depth.
967 __ bind(&exit); 1023 __ bind(&exit);
968 decrement_loop_depth(); 1024 decrement_loop_depth();
969 } 1025 }
970 1026
971 1027
972 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, 1028 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
973 bool pretenure) { 1029 bool pretenure) {
974 // Use the fast case closure allocation code that allocates in new 1030 // Use the fast case closure allocation code that allocates in new
975 // space for nested functions that don't need literals cloning. 1031 // space for nested functions that don't need literals cloning. If
976 if (scope()->is_function_scope() && 1032 // we're running with the --always-opt or the --prepare-always-opt
1033 // flag, we need to use the runtime function so that the new function
1034 // we are creating here gets a chance to have its code optimized and
1035 // doesn't just get a copy of the existing unoptimized code.
1036 if (!FLAG_always_opt &&
1037 !FLAG_prepare_always_opt &&
1038 scope()->is_function_scope() &&
977 info->num_literals() == 0 && 1039 info->num_literals() == 0 &&
978 !pretenure) { 1040 !pretenure) {
979 FastNewClosureStub stub; 1041 FastNewClosureStub stub;
980 __ Push(info); 1042 __ Push(info);
981 __ CallStub(&stub); 1043 __ CallStub(&stub);
982 } else { 1044 } else {
983 __ push(rsi); 1045 __ push(rsi);
984 __ Push(info); 1046 __ Push(info);
985 __ Push(pretenure 1047 __ Push(pretenure
986 ? isolate()->factory()->true_value() 1048 ? isolate()->factory()->true_value()
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
1079 } 1141 }
1080 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); 1142 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX));
1081 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); 1143 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset));
1082 // Walk the rest of the chain without clobbering rsi. 1144 // Walk the rest of the chain without clobbering rsi.
1083 context = temp; 1145 context = temp;
1084 } 1146 }
1085 } 1147 }
1086 // Check that last extension is NULL. 1148 // Check that last extension is NULL.
1087 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); 1149 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1088 __ j(not_equal, slow); 1150 __ j(not_equal, slow);
1089 __ movq(temp, ContextOperand(context, Context::FCONTEXT_INDEX)); 1151
1090 return ContextOperand(temp, slot->index()); 1152 // This function is used only for loads, not stores, so it's safe to
1153 // return an rsi-based operand (the write barrier cannot be allowed to
1154 // destroy the rsi register).
1155 return ContextOperand(context, slot->index());
1091 } 1156 }
1092 1157
1093 1158
1094 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( 1159 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1095 Slot* slot, 1160 Slot* slot,
1096 TypeofState typeof_state, 1161 TypeofState typeof_state,
1097 Label* slow, 1162 Label* slow,
1098 Label* done) { 1163 Label* done) {
1099 // Generate fast-case code for variables that might be shadowed by 1164 // Generate fast-case code for variables that might be shadowed by
1100 // eval-introduced variables. Eval is used a lot without 1165 // eval-introduced variables. Eval is used a lot without
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
1334 PrepareForBailoutForId(key->id(), NO_REGISTERS); 1399 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1335 } 1400 }
1336 break; 1401 break;
1337 } 1402 }
1338 // Fall through. 1403 // Fall through.
1339 case ObjectLiteral::Property::PROTOTYPE: 1404 case ObjectLiteral::Property::PROTOTYPE:
1340 __ push(Operand(rsp, 0)); // Duplicate receiver. 1405 __ push(Operand(rsp, 0)); // Duplicate receiver.
1341 VisitForStackValue(key); 1406 VisitForStackValue(key);
1342 VisitForStackValue(value); 1407 VisitForStackValue(value);
1343 if (property->emit_store()) { 1408 if (property->emit_store()) {
1344 __ CallRuntime(Runtime::kSetProperty, 3); 1409 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1410 __ CallRuntime(Runtime::kSetProperty, 4);
1345 } else { 1411 } else {
1346 __ Drop(3); 1412 __ Drop(3);
1347 } 1413 }
1348 break; 1414 break;
1349 case ObjectLiteral::Property::SETTER: 1415 case ObjectLiteral::Property::SETTER:
1350 case ObjectLiteral::Property::GETTER: 1416 case ObjectLiteral::Property::GETTER:
1351 __ push(Operand(rsp, 0)); // Duplicate receiver. 1417 __ push(Operand(rsp, 0)); // Duplicate receiver.
1352 VisitForStackValue(key); 1418 VisitForStackValue(key);
1353 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? 1419 __ Push(property->kind() == ObjectLiteral::Property::SETTER ?
1354 Smi::FromInt(1) : 1420 Smi::FromInt(1) :
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
1511 } 1577 }
1512 } 1578 }
1513 1579
1514 // For property compound assignments we need another deoptimization 1580 // For property compound assignments we need another deoptimization
1515 // point after the property load. 1581 // point after the property load.
1516 if (property != NULL) { 1582 if (property != NULL) {
1517 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); 1583 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
1518 } 1584 }
1519 1585
1520 Token::Value op = expr->binary_op(); 1586 Token::Value op = expr->binary_op();
1521 ConstantOperand constant = ShouldInlineSmiCase(op) 1587 __ push(rax); // Left operand goes on the stack.
1522 ? GetConstantOperand(op, expr->target(), expr->value()) 1588 VisitForAccumulatorValue(expr->value());
1523 : kNoConstants;
1524 ASSERT(constant == kRightConstant || constant == kNoConstants);
1525 if (constant == kNoConstants) {
1526 __ push(rax); // Left operand goes on the stack.
1527 VisitForAccumulatorValue(expr->value());
1528 }
1529 1589
1530 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() 1590 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1531 ? OVERWRITE_RIGHT 1591 ? OVERWRITE_RIGHT
1532 : NO_OVERWRITE; 1592 : NO_OVERWRITE;
1533 SetSourcePosition(expr->position() + 1); 1593 SetSourcePosition(expr->position() + 1);
1534 AccumulatorValueContext context(this); 1594 AccumulatorValueContext context(this);
1535 if (ShouldInlineSmiCase(op)) { 1595 if (ShouldInlineSmiCase(op)) {
1536 EmitInlineSmiBinaryOp(expr, 1596 EmitInlineSmiBinaryOp(expr,
1537 op, 1597 op,
1538 mode, 1598 mode,
1539 expr->target(), 1599 expr->target(),
1540 expr->value(), 1600 expr->value());
1541 constant);
1542 } else { 1601 } else {
1543 EmitBinaryOp(op, mode); 1602 EmitBinaryOp(op, mode);
1544 } 1603 }
1545 // Deoptimization point in case the binary operation may have side effects. 1604 // Deoptimization point in case the binary operation may have side effects.
1546 PrepareForBailout(expr->binary_operation(), TOS_REG); 1605 PrepareForBailout(expr->binary_operation(), TOS_REG);
1547 } else { 1606 } else {
1548 VisitForAccumulatorValue(expr->value()); 1607 VisitForAccumulatorValue(expr->value());
1549 } 1608 }
1550 1609
1551 // Record source position before possible IC call. 1610 // Record source position before possible IC call.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1584 Handle<Code> ic(isolate()->builtins()->builtin( 1643 Handle<Code> ic(isolate()->builtins()->builtin(
1585 Builtins::KeyedLoadIC_Initialize)); 1644 Builtins::KeyedLoadIC_Initialize));
1586 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1645 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1587 } 1646 }
1588 1647
1589 1648
1590 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, 1649 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
1591 Token::Value op, 1650 Token::Value op,
1592 OverwriteMode mode, 1651 OverwriteMode mode,
1593 Expression* left, 1652 Expression* left,
1594 Expression* right, 1653 Expression* right) {
1595 ConstantOperand constant) {
1596 ASSERT(constant == kNoConstants); // Only handled case.
1597
1598 // Do combined smi check of the operands. Left operand is on the 1654 // Do combined smi check of the operands. Left operand is on the
1599 // stack (popped into rdx). Right operand is in rax but moved into 1655 // stack (popped into rdx). Right operand is in rax but moved into
1600 // rcx to make the shifts easier. 1656 // rcx to make the shifts easier.
1601 NearLabel done, stub_call, smi_case; 1657 NearLabel done, stub_call, smi_case;
1602 __ pop(rdx); 1658 __ pop(rdx);
1603 __ movq(rcx, rax); 1659 __ movq(rcx, rax);
1604 __ or_(rax, rdx); 1660 __ or_(rax, rdx);
1605 JumpPatchSite patch_site(masm_); 1661 JumpPatchSite patch_site(masm_);
1606 patch_site.EmitJumpIfSmi(rax, &smi_case); 1662 patch_site.EmitJumpIfSmi(rax, &smi_case);
1607 1663
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1645 break; 1701 break;
1646 } 1702 }
1647 1703
1648 __ bind(&done); 1704 __ bind(&done);
1649 context()->Plug(rax); 1705 context()->Plug(rax);
1650 } 1706 }
1651 1707
1652 1708
1653 void FullCodeGenerator::EmitBinaryOp(Token::Value op, 1709 void FullCodeGenerator::EmitBinaryOp(Token::Value op,
1654 OverwriteMode mode) { 1710 OverwriteMode mode) {
1711 __ pop(rdx);
1655 TypeRecordingBinaryOpStub stub(op, mode); 1712 TypeRecordingBinaryOpStub stub(op, mode);
1656 __ pop(rdx); 1713 EmitCallIC(stub.GetCode(), NULL); // NULL signals no inlined smi code.
1657 __ CallStub(&stub);
1658 context()->Plug(rax); 1714 context()->Plug(rax);
1659 } 1715 }
1660 1716
1661 1717
1662 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { 1718 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
1663 // Invalid left-hand sides are rewritten to have a 'throw 1719 // Invalid left-hand sides are rewritten to have a 'throw
1664 // ReferenceError' on the left-hand side. 1720 // ReferenceError' on the left-hand side.
1665 if (!expr->IsValidLeftHandSide()) { 1721 if (!expr->IsValidLeftHandSide()) {
1666 VisitForEffect(expr); 1722 VisitForEffect(expr);
1667 return; 1723 return;
(...skipping 17 matching lines...) Expand all
1685 EmitVariableAssignment(var, Token::ASSIGN); 1741 EmitVariableAssignment(var, Token::ASSIGN);
1686 break; 1742 break;
1687 } 1743 }
1688 case NAMED_PROPERTY: { 1744 case NAMED_PROPERTY: {
1689 __ push(rax); // Preserve value. 1745 __ push(rax); // Preserve value.
1690 VisitForAccumulatorValue(prop->obj()); 1746 VisitForAccumulatorValue(prop->obj());
1691 __ movq(rdx, rax); 1747 __ movq(rdx, rax);
1692 __ pop(rax); // Restore value. 1748 __ pop(rax); // Restore value.
1693 __ Move(rcx, prop->key()->AsLiteral()->handle()); 1749 __ Move(rcx, prop->key()->AsLiteral()->handle());
1694 Handle<Code> ic(isolate()->builtins()->builtin( 1750 Handle<Code> ic(isolate()->builtins()->builtin(
1695 Builtins::StoreIC_Initialize)); 1751 is_strict() ? Builtins::StoreIC_Initialize_Strict
1752 : Builtins::StoreIC_Initialize));
1696 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1753 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1697 break; 1754 break;
1698 } 1755 }
1699 case KEYED_PROPERTY: { 1756 case KEYED_PROPERTY: {
1700 __ push(rax); // Preserve value. 1757 __ push(rax); // Preserve value.
1701 VisitForStackValue(prop->obj()); 1758 if (prop->is_synthetic()) {
1702 VisitForAccumulatorValue(prop->key()); 1759 ASSERT(prop->obj()->AsVariableProxy() != NULL);
1703 __ movq(rcx, rax); 1760 ASSERT(prop->key()->AsLiteral() != NULL);
1704 __ pop(rdx); 1761 { AccumulatorValueContext for_object(this);
1705 __ pop(rax); 1762 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
1763 }
1764 __ movq(rdx, rax);
1765 __ Move(rcx, prop->key()->AsLiteral()->handle());
1766 } else {
1767 VisitForStackValue(prop->obj());
1768 VisitForAccumulatorValue(prop->key());
1769 __ movq(rcx, rax);
1770 __ pop(rdx);
1771 }
1772 __ pop(rax); // Restore value.
1706 Handle<Code> ic(isolate()->builtins()->builtin( 1773 Handle<Code> ic(isolate()->builtins()->builtin(
1707 Builtins::KeyedStoreIC_Initialize)); 1774 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
1775 : Builtins::KeyedStoreIC_Initialize));
1708 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1776 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1709 break; 1777 break;
1710 } 1778 }
1711 } 1779 }
1712 PrepareForBailoutForId(bailout_ast_id, TOS_REG); 1780 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1713 context()->Plug(rax); 1781 context()->Plug(rax);
1714 } 1782 }
1715 1783
1716 1784
1717 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1785 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
1718 Token::Value op) { 1786 Token::Value op) {
1719 // Left-hand sides that rewrite to explicit property accesses do not reach 1787 // Left-hand sides that rewrite to explicit property accesses do not reach
1720 // here. 1788 // here.
1721 ASSERT(var != NULL); 1789 ASSERT(var != NULL);
1722 ASSERT(var->is_global() || var->AsSlot() != NULL); 1790 ASSERT(var->is_global() || var->AsSlot() != NULL);
1723 1791
1724 if (var->is_global()) { 1792 if (var->is_global()) {
1725 ASSERT(!var->is_this()); 1793 ASSERT(!var->is_this());
1726 // Assignment to a global variable. Use inline caching for the 1794 // Assignment to a global variable. Use inline caching for the
1727 // assignment. Right-hand-side value is passed in rax, variable name in 1795 // assignment. Right-hand-side value is passed in rax, variable name in
1728 // rcx, and the global object on the stack. 1796 // rcx, and the global object on the stack.
1729 __ Move(rcx, var->name()); 1797 __ Move(rcx, var->name());
1730 __ movq(rdx, GlobalObjectOperand()); 1798 __ movq(rdx, GlobalObjectOperand());
1731 Handle<Code> ic(isolate()->builtins()->builtin( 1799 Handle<Code> ic(isolate()->builtins()->builtin(is_strict()
1732 Builtins::StoreIC_Initialize)); 1800 ? Builtins::StoreIC_Initialize_Strict
1733 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1801 : Builtins::StoreIC_Initialize));
1802 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
1734 1803
1735 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { 1804 } else if (op == Token::INIT_CONST) {
1736 // Perform the assignment for non-const variables and for initialization 1805 // Like var declarations, const declarations are hoisted to function
1737 // of const variables. Const assignments are simply skipped. 1806 // scope. However, unlike var initializers, const initializers are able
1738 Label done; 1807 // to drill a hole to that function context, even from inside a 'with'
1808 // context. We thus bypass the normal static scope lookup.
1809 Slot* slot = var->AsSlot();
1810 Label skip;
1811 switch (slot->type()) {
1812 case Slot::PARAMETER:
1813 // No const parameters.
1814 UNREACHABLE();
1815 break;
1816 case Slot::LOCAL:
1817 __ movq(rdx, Operand(rbp, SlotOffset(slot)));
1818 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1819 __ j(not_equal, &skip);
1820 __ movq(Operand(rbp, SlotOffset(slot)), rax);
1821 break;
1822 case Slot::CONTEXT: {
1823 __ movq(rcx, ContextOperand(rsi, Context::FCONTEXT_INDEX));
1824 __ movq(rdx, ContextOperand(rcx, slot->index()));
1825 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1826 __ j(not_equal, &skip);
1827 __ movq(ContextOperand(rcx, slot->index()), rax);
1828 int offset = Context::SlotOffset(slot->index());
1829 __ movq(rdx, rax); // Preserve the stored value in eax.
1830 __ RecordWrite(rcx, offset, rdx, rbx);
1831 break;
1832 }
1833 case Slot::LOOKUP:
1834 __ push(rax);
1835 __ push(rsi);
1836 __ Push(var->name());
1837 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1838 break;
1839 }
1840 __ bind(&skip);
1841
1842 } else if (var->mode() != Variable::CONST) {
1843 // Perform the assignment for non-const variables. Const assignments
1844 // are simply skipped.
1739 Slot* slot = var->AsSlot(); 1845 Slot* slot = var->AsSlot();
1740 switch (slot->type()) { 1846 switch (slot->type()) {
1741 case Slot::PARAMETER: 1847 case Slot::PARAMETER:
1742 case Slot::LOCAL: 1848 case Slot::LOCAL:
1743 if (op == Token::INIT_CONST) {
1744 // Detect const reinitialization by checking for the hole value.
1745 __ movq(rdx, Operand(rbp, SlotOffset(slot)));
1746 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1747 __ j(not_equal, &done);
1748 }
1749 // Perform the assignment. 1849 // Perform the assignment.
1750 __ movq(Operand(rbp, SlotOffset(slot)), rax); 1850 __ movq(Operand(rbp, SlotOffset(slot)), rax);
1751 break; 1851 break;
1752 1852
1753 case Slot::CONTEXT: { 1853 case Slot::CONTEXT: {
1754 MemOperand target = EmitSlotSearch(slot, rcx); 1854 MemOperand target = EmitSlotSearch(slot, rcx);
1755 if (op == Token::INIT_CONST) {
1756 // Detect const reinitialization by checking for the hole value.
1757 __ movq(rdx, target);
1758 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1759 __ j(not_equal, &done);
1760 }
1761 // Perform the assignment and issue the write barrier. 1855 // Perform the assignment and issue the write barrier.
1762 __ movq(target, rax); 1856 __ movq(target, rax);
1763 // The value of the assignment is in rax. RecordWrite clobbers its 1857 // The value of the assignment is in rax. RecordWrite clobbers its
1764 // register arguments. 1858 // register arguments.
1765 __ movq(rdx, rax); 1859 __ movq(rdx, rax);
1766 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 1860 int offset = Context::SlotOffset(slot->index());
1767 __ RecordWrite(rcx, offset, rdx, rbx); 1861 __ RecordWrite(rcx, offset, rdx, rbx);
1768 break; 1862 break;
1769 } 1863 }
1770 1864
1771 case Slot::LOOKUP: 1865 case Slot::LOOKUP:
1772 // Call the runtime for the assignment. The runtime will ignore 1866 // Call the runtime for the assignment.
1773 // const reinitialization.
1774 __ push(rax); // Value. 1867 __ push(rax); // Value.
1775 __ push(rsi); // Context. 1868 __ push(rsi); // Context.
1776 __ Push(var->name()); 1869 __ Push(var->name());
1777 if (op == Token::INIT_CONST) { 1870 __ Push(Smi::FromInt(strict_mode_flag()));
1778 // The runtime will ignore const redeclaration. 1871 __ CallRuntime(Runtime::kStoreContextSlot, 4);
1779 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1780 } else {
1781 __ CallRuntime(Runtime::kStoreContextSlot, 3);
1782 }
1783 break; 1872 break;
1784 } 1873 }
1785 __ bind(&done);
1786 } 1874 }
1787 } 1875 }
1788 1876
1789 1877
1790 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { 1878 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1791 // Assignment to a property, using a named store IC. 1879 // Assignment to a property, using a named store IC.
1792 Property* prop = expr->target()->AsProperty(); 1880 Property* prop = expr->target()->AsProperty();
1793 ASSERT(prop != NULL); 1881 ASSERT(prop != NULL);
1794 ASSERT(prop->key()->AsLiteral() != NULL); 1882 ASSERT(prop->key()->AsLiteral() != NULL);
1795 1883
1796 // If the assignment starts a block of assignments to the same object, 1884 // If the assignment starts a block of assignments to the same object,
1797 // change to slow case to avoid the quadratic behavior of repeatedly 1885 // change to slow case to avoid the quadratic behavior of repeatedly
1798 // adding fast properties. 1886 // adding fast properties.
1799 if (expr->starts_initialization_block()) { 1887 if (expr->starts_initialization_block()) {
1800 __ push(result_register()); 1888 __ push(result_register());
1801 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value. 1889 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value.
1802 __ CallRuntime(Runtime::kToSlowProperties, 1); 1890 __ CallRuntime(Runtime::kToSlowProperties, 1);
1803 __ pop(result_register()); 1891 __ pop(result_register());
1804 } 1892 }
1805 1893
1806 // Record source code position before IC call. 1894 // Record source code position before IC call.
1807 SetSourcePosition(expr->position()); 1895 SetSourcePosition(expr->position());
1808 __ Move(rcx, prop->key()->AsLiteral()->handle()); 1896 __ Move(rcx, prop->key()->AsLiteral()->handle());
1809 if (expr->ends_initialization_block()) { 1897 if (expr->ends_initialization_block()) {
1810 __ movq(rdx, Operand(rsp, 0)); 1898 __ movq(rdx, Operand(rsp, 0));
1811 } else { 1899 } else {
1812 __ pop(rdx); 1900 __ pop(rdx);
1813 } 1901 }
1814 Handle<Code> ic(isolate()->builtins()->builtin( 1902 Handle<Code> ic(isolate()->builtins()->builtin(
1815 Builtins::StoreIC_Initialize)); 1903 is_strict() ? Builtins::StoreIC_Initialize_Strict
1904 : Builtins::StoreIC_Initialize));
1816 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1905 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1817 1906
1818 // If the assignment ends an initialization block, revert to fast case. 1907 // If the assignment ends an initialization block, revert to fast case.
1819 if (expr->ends_initialization_block()) { 1908 if (expr->ends_initialization_block()) {
1820 __ push(rax); // Result of assignment, saved even if not needed. 1909 __ push(rax); // Result of assignment, saved even if not needed.
1821 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. 1910 __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
1822 __ CallRuntime(Runtime::kToFastProperties, 1); 1911 __ CallRuntime(Runtime::kToFastProperties, 1);
1823 __ pop(rax); 1912 __ pop(rax);
1824 __ Drop(1); 1913 __ Drop(1);
1825 } 1914 }
(...skipping 18 matching lines...) Expand all
1844 1933
1845 __ pop(rcx); 1934 __ pop(rcx);
1846 if (expr->ends_initialization_block()) { 1935 if (expr->ends_initialization_block()) {
1847 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later. 1936 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later.
1848 } else { 1937 } else {
1849 __ pop(rdx); 1938 __ pop(rdx);
1850 } 1939 }
1851 // Record source code position before IC call. 1940 // Record source code position before IC call.
1852 SetSourcePosition(expr->position()); 1941 SetSourcePosition(expr->position());
1853 Handle<Code> ic(isolate()->builtins()->builtin( 1942 Handle<Code> ic(isolate()->builtins()->builtin(
1854 Builtins::KeyedStoreIC_Initialize)); 1943 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
1944 : Builtins::KeyedStoreIC_Initialize));
1855 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1945 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1856 1946
1857 // If the assignment ends an initialization block, revert to fast case. 1947 // If the assignment ends an initialization block, revert to fast case.
1858 if (expr->ends_initialization_block()) { 1948 if (expr->ends_initialization_block()) {
1859 __ pop(rdx); 1949 __ pop(rdx);
1860 __ push(rax); // Result of assignment, saved even if not needed. 1950 __ push(rax); // Result of assignment, saved even if not needed.
1861 __ push(rdx); 1951 __ push(rdx);
1862 __ CallRuntime(Runtime::kToFastProperties, 1); 1952 __ CallRuntime(Runtime::kToFastProperties, 1);
1863 __ pop(rax); 1953 __ pop(rax);
1864 } 1954 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1962 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); 2052 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1963 __ CallStub(&stub); 2053 __ CallStub(&stub);
1964 RecordJSReturnSite(expr); 2054 RecordJSReturnSite(expr);
1965 // Restore context register. 2055 // Restore context register.
1966 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 2056 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1967 // Discard the function left on TOS. 2057 // Discard the function left on TOS.
1968 context()->DropAndPlug(1, rax); 2058 context()->DropAndPlug(1, rax);
1969 } 2059 }
1970 2060
1971 2061
2062 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2063 int arg_count) {
2064 // Push copy of the first argument or undefined if it doesn't exist.
2065 if (arg_count > 0) {
2066 __ push(Operand(rsp, arg_count * kPointerSize));
2067 } else {
2068 __ PushRoot(Heap::kUndefinedValueRootIndex);
2069 }
2070
2071 // Push the receiver of the enclosing function and do runtime call.
2072 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
2073
2074 // Push the strict mode flag.
2075 __ Push(Smi::FromInt(strict_mode_flag()));
2076
2077 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2078 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2079 : Runtime::kResolvePossiblyDirectEval, 4);
2080 }
2081
2082
1972 void FullCodeGenerator::VisitCall(Call* expr) { 2083 void FullCodeGenerator::VisitCall(Call* expr) {
1973 #ifdef DEBUG 2084 #ifdef DEBUG
1974 // We want to verify that RecordJSReturnSite gets called on all paths 2085 // We want to verify that RecordJSReturnSite gets called on all paths
1975 // through this function. Avoid early returns. 2086 // through this function. Avoid early returns.
1976 expr->return_is_recorded_ = false; 2087 expr->return_is_recorded_ = false;
1977 #endif 2088 #endif
1978 2089
1979 Comment cmnt(masm_, "[ Call"); 2090 Comment cmnt(masm_, "[ Call");
1980 Expression* fun = expr->expression(); 2091 Expression* fun = expr->expression();
1981 Variable* var = fun->AsVariableProxy()->AsVariable(); 2092 Variable* var = fun->AsVariableProxy()->AsVariable();
1982 2093
1983 if (var != NULL && var->is_possibly_eval()) { 2094 if (var != NULL && var->is_possibly_eval()) {
1984 // In a call to eval, we first call %ResolvePossiblyDirectEval to 2095 // In a call to eval, we first call %ResolvePossiblyDirectEval to
1985 // resolve the function we need to call and the receiver of the 2096 // resolve the function we need to call and the receiver of the
1986 // call. Then we call the resolved function using the given 2097 // call. Then we call the resolved function using the given
1987 // arguments. 2098 // arguments.
1988 ZoneList<Expression*>* args = expr->arguments(); 2099 ZoneList<Expression*>* args = expr->arguments();
1989 int arg_count = args->length(); 2100 int arg_count = args->length();
1990 { PreservePositionScope pos_scope(masm()->positions_recorder()); 2101 { PreservePositionScope pos_scope(masm()->positions_recorder());
1991 VisitForStackValue(fun); 2102 VisitForStackValue(fun);
1992 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. 2103 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
1993 2104
1994 // Push the arguments. 2105 // Push the arguments.
1995 for (int i = 0; i < arg_count; i++) { 2106 for (int i = 0; i < arg_count; i++) {
1996 VisitForStackValue(args->at(i)); 2107 VisitForStackValue(args->at(i));
1997 } 2108 }
1998 2109
1999 // Push copy of the function - found below the arguments. 2110 // If we know that eval can only be shadowed by eval-introduced
2000 __ push(Operand(rsp, (arg_count + 1) * kPointerSize)); 2111 // variables we attempt to load the global eval function directly
2001 2112 // in generated code. If we succeed, there is no need to perform a
2002 // Push copy of the first argument or undefined if it doesn't exist. 2113 // context lookup in the runtime system.
2003 if (arg_count > 0) { 2114 Label done;
2004 __ push(Operand(rsp, arg_count * kPointerSize)); 2115 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2005 } else { 2116 Label slow;
2006 __ PushRoot(Heap::kUndefinedValueRootIndex); 2117 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2118 NOT_INSIDE_TYPEOF,
2119 &slow);
2120 // Push the function and resolve eval.
2121 __ push(rax);
2122 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2123 __ jmp(&done);
2124 __ bind(&slow);
2007 } 2125 }
2008 2126
2009 // Push the receiver of the enclosing function and do runtime call. 2127 // Push copy of the function (found below the arguments) and
2010 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize)); 2128 // resolve eval.
2011 // Push the strict mode flag. 2129 __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
2012 __ Push(Smi::FromInt(strict_mode_flag())); 2130 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2013 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); 2131 if (done.is_linked()) {
2132 __ bind(&done);
2133 }
2014 2134
2015 // The runtime call returns a pair of values in rax (function) and 2135 // The runtime call returns a pair of values in rax (function) and
2016 // rdx (receiver). Touch up the stack with the right values. 2136 // rdx (receiver). Touch up the stack with the right values.
2017 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); 2137 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
2018 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax); 2138 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
2019 } 2139 }
2020 // Record source position for debugger. 2140 // Record source position for debugger.
2021 SetSourcePosition(expr->position()); 2141 SetSourcePosition(expr->position());
2022 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 2142 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2023 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); 2143 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
(...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after
2622 __ bind(&done); 2742 __ bind(&done);
2623 context()->Plug(rax); 2743 context()->Plug(rax);
2624 } 2744 }
2625 2745
2626 2746
2627 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) { 2747 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2628 // Load the arguments on the stack and call the runtime function. 2748 // Load the arguments on the stack and call the runtime function.
2629 ASSERT(args->length() == 2); 2749 ASSERT(args->length() == 2);
2630 VisitForStackValue(args->at(0)); 2750 VisitForStackValue(args->at(0));
2631 VisitForStackValue(args->at(1)); 2751 VisitForStackValue(args->at(1));
2632 __ CallRuntime(Runtime::kMath_pow, 2); 2752 MathPowStub stub;
2753 __ CallStub(&stub);
2633 context()->Plug(rax); 2754 context()->Plug(rax);
2634 } 2755 }
2635 2756
2636 2757
2637 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { 2758 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2638 ASSERT(args->length() == 2); 2759 ASSERT(args->length() == 2);
2639 2760
2640 VisitForStackValue(args->at(0)); // Load the object. 2761 VisitForStackValue(args->at(0)); // Load the object.
2641 VisitForAccumulatorValue(args->at(1)); // Load the value. 2762 VisitForAccumulatorValue(args->at(1)); // Load the value.
2642 __ pop(rbx); // rax = value. rbx = object. 2763 __ pop(rbx); // rax = value. rbx = object.
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
2806 VisitForStackValue(args->at(1)); 2927 VisitForStackValue(args->at(1));
2807 2928
2808 StringCompareStub stub; 2929 StringCompareStub stub;
2809 __ CallStub(&stub); 2930 __ CallStub(&stub);
2810 context()->Plug(rax); 2931 context()->Plug(rax);
2811 } 2932 }
2812 2933
2813 2934
2814 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { 2935 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2815 // Load the argument on the stack and call the stub. 2936 // Load the argument on the stack and call the stub.
2816 TranscendentalCacheStub stub(TranscendentalCache::SIN); 2937 TranscendentalCacheStub stub(TranscendentalCache::SIN,
2938 TranscendentalCacheStub::TAGGED);
2817 ASSERT(args->length() == 1); 2939 ASSERT(args->length() == 1);
2818 VisitForStackValue(args->at(0)); 2940 VisitForStackValue(args->at(0));
2819 __ CallStub(&stub); 2941 __ CallStub(&stub);
2820 context()->Plug(rax); 2942 context()->Plug(rax);
2821 } 2943 }
2822 2944
2823 2945
2824 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { 2946 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2825 // Load the argument on the stack and call the stub. 2947 // Load the argument on the stack and call the stub.
2826 TranscendentalCacheStub stub(TranscendentalCache::COS); 2948 TranscendentalCacheStub stub(TranscendentalCache::COS,
2949 TranscendentalCacheStub::TAGGED);
2827 ASSERT(args->length() == 1); 2950 ASSERT(args->length() == 1);
2828 VisitForStackValue(args->at(0)); 2951 VisitForStackValue(args->at(0));
2829 __ CallStub(&stub); 2952 __ CallStub(&stub);
2830 context()->Plug(rax); 2953 context()->Plug(rax);
2831 } 2954 }
2832 2955
2833 2956
2834 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) { 2957 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
2835 // Load the argument on the stack and call the stub. 2958 // Load the argument on the stack and call the stub.
2836 TranscendentalCacheStub stub(TranscendentalCache::LOG); 2959 TranscendentalCacheStub stub(TranscendentalCache::LOG,
2960 TranscendentalCacheStub::TAGGED);
2837 ASSERT(args->length() == 1); 2961 ASSERT(args->length() == 1);
2838 VisitForStackValue(args->at(0)); 2962 VisitForStackValue(args->at(0));
2839 __ CallStub(&stub); 2963 __ CallStub(&stub);
2840 context()->Plug(rax); 2964 context()->Plug(rax);
2841 } 2965 }
2842 2966
2843 2967
2844 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) { 2968 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2845 // Load the argument on the stack and call the runtime function. 2969 // Load the argument on the stack and call the runtime function.
2846 ASSERT(args->length() == 1); 2970 ASSERT(args->length() == 1);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2878 __ CallStub(&stub); 3002 __ CallStub(&stub);
2879 context()->Plug(rax); 3003 context()->Plug(rax);
2880 } 3004 }
2881 3005
2882 3006
2883 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { 3007 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2884 ASSERT(args->length() == 3); 3008 ASSERT(args->length() == 3);
2885 VisitForStackValue(args->at(0)); 3009 VisitForStackValue(args->at(0));
2886 VisitForStackValue(args->at(1)); 3010 VisitForStackValue(args->at(1));
2887 VisitForStackValue(args->at(2)); 3011 VisitForStackValue(args->at(2));
3012 Label done;
3013 Label slow_case;
3014 Register object = rax;
3015 Register index_1 = rbx;
3016 Register index_2 = rcx;
3017 Register elements = rdi;
3018 Register temp = rdx;
3019 __ movq(object, Operand(rsp, 2 * kPointerSize));
3020 // Fetch the map and check if array is in fast case.
3021 // Check that object doesn't require security checks and
3022 // has no indexed interceptor.
3023 __ CmpObjectType(object, FIRST_JS_OBJECT_TYPE, temp);
3024 __ j(below, &slow_case);
3025 __ testb(FieldOperand(temp, Map::kBitFieldOffset),
3026 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
3027 __ j(not_zero, &slow_case);
3028
3029 // Check the object's elements are in fast case and writable.
3030 __ movq(elements, FieldOperand(object, JSObject::kElementsOffset));
3031 __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
3032 Heap::kFixedArrayMapRootIndex);
3033 __ j(not_equal, &slow_case);
3034
3035 // Check that both indices are smis.
3036 __ movq(index_1, Operand(rsp, 1 * kPointerSize));
3037 __ movq(index_2, Operand(rsp, 0 * kPointerSize));
3038 __ JumpIfNotBothSmi(index_1, index_2, &slow_case);
3039
3040 // Check that both indices are valid.
3041 // The JSArray length field is a smi since the array is in fast case mode.
3042 __ movq(temp, FieldOperand(object, JSArray::kLengthOffset));
3043 __ SmiCompare(temp, index_1);
3044 __ j(below_equal, &slow_case);
3045 __ SmiCompare(temp, index_2);
3046 __ j(below_equal, &slow_case);
3047
3048 __ SmiToInteger32(index_1, index_1);
3049 __ SmiToInteger32(index_2, index_2);
3050 // Bring addresses into index1 and index2.
3051 __ lea(index_1, FieldOperand(elements, index_1, times_pointer_size,
3052 FixedArray::kHeaderSize));
3053 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size,
3054 FixedArray::kHeaderSize));
3055
3056 // Swap elements. Use object and temp as scratch registers.
3057 __ movq(object, Operand(index_1, 0));
3058 __ movq(temp, Operand(index_2, 0));
3059 __ movq(Operand(index_2, 0), object);
3060 __ movq(Operand(index_1, 0), temp);
3061
3062 Label new_space;
3063 __ InNewSpace(elements, temp, equal, &new_space);
3064
3065 __ movq(object, elements);
3066 __ RecordWriteHelper(object, index_1, temp);
3067 __ RecordWriteHelper(elements, index_2, temp);
3068
3069 __ bind(&new_space);
3070 // We are done. Drop elements from the stack, and return undefined.
3071 __ addq(rsp, Immediate(3 * kPointerSize));
3072 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3073 __ jmp(&done);
3074
3075 __ bind(&slow_case);
2888 __ CallRuntime(Runtime::kSwapElements, 3); 3076 __ CallRuntime(Runtime::kSwapElements, 3);
3077
3078 __ bind(&done);
2889 context()->Plug(rax); 3079 context()->Plug(rax);
2890 } 3080 }
2891 3081
2892 3082
2893 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { 3083 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
2894 ASSERT_EQ(2, args->length()); 3084 ASSERT_EQ(2, args->length());
2895 3085
2896 ASSERT_NE(NULL, args->at(0)->AsLiteral()); 3086 ASSERT_NE(NULL, args->at(0)->AsLiteral());
2897 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); 3087 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
2898 3088
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
3001 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); 3191 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3002 __ j(zero, if_true); 3192 __ j(zero, if_true);
3003 __ jmp(if_false); 3193 __ jmp(if_false);
3004 3194
3005 context()->Plug(if_true, if_false); 3195 context()->Plug(if_true, if_false);
3006 } 3196 }
3007 3197
3008 3198
3009 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { 3199 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3010 ASSERT(args->length() == 1); 3200 ASSERT(args->length() == 1);
3201 VisitForAccumulatorValue(args->at(0));
3011 3202
3012 VisitForAccumulatorValue(args->at(0)); 3203 if (FLAG_debug_code) {
3204 __ AbortIfNotString(rax);
3205 }
3013 3206
3014 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset)); 3207 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
3015 ASSERT(String::kHashShift >= kSmiTagSize); 3208 ASSERT(String::kHashShift >= kSmiTagSize);
3016 __ IndexFromHash(rax, rax); 3209 __ IndexFromHash(rax, rax);
3017 3210
3018 context()->Plug(rax); 3211 context()->Plug(rax);
3019 } 3212 }
3020 3213
3021 3214
3022 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { 3215 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
3062 context()->Plug(rax); 3255 context()->Plug(rax);
3063 } 3256 }
3064 3257
3065 3258
3066 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 3259 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3067 switch (expr->op()) { 3260 switch (expr->op()) {
3068 case Token::DELETE: { 3261 case Token::DELETE: {
3069 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); 3262 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3070 Property* prop = expr->expression()->AsProperty(); 3263 Property* prop = expr->expression()->AsProperty();
3071 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); 3264 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
3072 if (prop == NULL && var == NULL) { 3265
3266 if (prop != NULL) {
3267 if (prop->is_synthetic()) {
3268 // Result of deleting parameters is false, even when they rewrite
3269 // to accesses on the arguments object.
3270 context()->Plug(false);
3271 } else {
3272 VisitForStackValue(prop->obj());
3273 VisitForStackValue(prop->key());
3274 __ Push(Smi::FromInt(strict_mode_flag()));
3275 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3276 context()->Plug(rax);
3277 }
3278 } else if (var != NULL) {
3279 // Delete of an unqualified identifier is disallowed in strict mode
3280 // but "delete this" is.
3281 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
3282 if (var->is_global()) {
3283 __ push(GlobalObjectOperand());
3284 __ Push(var->name());
3285 __ Push(Smi::FromInt(kNonStrictMode));
3286 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3287 context()->Plug(rax);
3288 } else if (var->AsSlot() != NULL &&
3289 var->AsSlot()->type() != Slot::LOOKUP) {
3290 // Result of deleting non-global, non-dynamic variables is false.
3291 // The subexpression does not have side effects.
3292 context()->Plug(false);
3293 } else {
3294 // Non-global variable. Call the runtime to try to delete from the
3295 // context where the variable was introduced.
3296 __ push(context_register());
3297 __ Push(var->name());
3298 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3299 context()->Plug(rax);
3300 }
3301 } else {
3073 // Result of deleting non-property, non-variable reference is true. 3302 // Result of deleting non-property, non-variable reference is true.
3074 // The subexpression may have side effects. 3303 // The subexpression may have side effects.
3075 VisitForEffect(expr->expression()); 3304 VisitForEffect(expr->expression());
3076 context()->Plug(true); 3305 context()->Plug(true);
3077 } else if (var != NULL &&
3078 !var->is_global() &&
3079 var->AsSlot() != NULL &&
3080 var->AsSlot()->type() != Slot::LOOKUP) {
3081 // Result of deleting non-global, non-dynamic variables is false.
3082 // The subexpression does not have side effects.
3083 context()->Plug(false);
3084 } else {
3085 // Property or variable reference. Call the delete builtin with
3086 // object and property name as arguments.
3087 if (prop != NULL) {
3088 VisitForStackValue(prop->obj());
3089 VisitForStackValue(prop->key());
3090 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3091 } else if (var->is_global()) {
3092 __ push(GlobalObjectOperand());
3093 __ Push(var->name());
3094 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3095 } else {
3096 // Non-global variable. Call the runtime to delete from the
3097 // context where the variable was introduced.
3098 __ push(context_register());
3099 __ Push(var->name());
3100 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3101 }
3102 context()->Plug(rax);
3103 } 3306 }
3104 break; 3307 break;
3105 } 3308 }
3106 3309
3107 case Token::VOID: { 3310 case Token::VOID: {
3108 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 3311 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3109 VisitForEffect(expr->expression()); 3312 VisitForEffect(expr->expression());
3110 context()->Plug(Heap::kUndefinedValueRootIndex); 3313 context()->Plug(Heap::kUndefinedValueRootIndex);
3111 break; 3314 break;
3112 } 3315 }
3113 3316
3114 case Token::NOT: { 3317 case Token::NOT: {
3115 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 3318 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
3116 Label materialize_true, materialize_false; 3319 if (context()->IsEffect()) {
3117 Label* if_true = NULL; 3320 // Unary NOT has no side effects so it's only necessary to visit the
3118 Label* if_false = NULL; 3321 // subexpression. Match the optimizing compiler by not branching.
3119 Label* fall_through = NULL; 3322 VisitForEffect(expr->expression());
3120 // Notice that the labels are swapped. 3323 } else {
3121 context()->PrepareTest(&materialize_true, &materialize_false, 3324 Label materialize_true, materialize_false;
3122 &if_false, &if_true, &fall_through); 3325 Label* if_true = NULL;
3123 if (context()->IsTest()) ForwardBailoutToChild(expr); 3326 Label* if_false = NULL;
3124 VisitForControl(expr->expression(), if_true, if_false, fall_through); 3327 Label* fall_through = NULL;
3125 context()->Plug(if_false, if_true); // Labels swapped. 3328 // Notice that the labels are swapped.
3329 context()->PrepareTest(&materialize_true, &materialize_false,
3330 &if_false, &if_true, &fall_through);
3331 if (context()->IsTest()) ForwardBailoutToChild(expr);
3332 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3333 context()->Plug(if_false, if_true); // Labels swapped.
3334 }
3126 break; 3335 break;
3127 } 3336 }
3128 3337
3129 case Token::TYPEOF: { 3338 case Token::TYPEOF: {
3130 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 3339 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
3131 { StackValueContext context(this); 3340 { StackValueContext context(this);
3132 VisitForTypeofValue(expr->expression()); 3341 VisitForTypeofValue(expr->expression());
3133 } 3342 }
3134 __ CallRuntime(Runtime::kTypeof, 1); 3343 __ CallRuntime(Runtime::kTypeof, 1);
3135 context()->Plug(rax); 3344 context()->Plug(rax);
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
3342 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 3551 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3343 Token::ASSIGN); 3552 Token::ASSIGN);
3344 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3553 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3345 context()->Plug(rax); 3554 context()->Plug(rax);
3346 } 3555 }
3347 break; 3556 break;
3348 case NAMED_PROPERTY: { 3557 case NAMED_PROPERTY: {
3349 __ Move(rcx, prop->key()->AsLiteral()->handle()); 3558 __ Move(rcx, prop->key()->AsLiteral()->handle());
3350 __ pop(rdx); 3559 __ pop(rdx);
3351 Handle<Code> ic(isolate()->builtins()->builtin( 3560 Handle<Code> ic(isolate()->builtins()->builtin(
3352 Builtins::StoreIC_Initialize)); 3561 is_strict() ? Builtins::StoreIC_Initialize_Strict
3562 : Builtins::StoreIC_Initialize));
3353 EmitCallIC(ic, RelocInfo::CODE_TARGET); 3563 EmitCallIC(ic, RelocInfo::CODE_TARGET);
3354 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3564 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3355 if (expr->is_postfix()) { 3565 if (expr->is_postfix()) {
3356 if (!context()->IsEffect()) { 3566 if (!context()->IsEffect()) {
3357 context()->PlugTOS(); 3567 context()->PlugTOS();
3358 } 3568 }
3359 } else { 3569 } else {
3360 context()->Plug(rax); 3570 context()->Plug(rax);
3361 } 3571 }
3362 break; 3572 break;
3363 } 3573 }
3364 case KEYED_PROPERTY: { 3574 case KEYED_PROPERTY: {
3365 __ pop(rcx); 3575 __ pop(rcx);
3366 __ pop(rdx); 3576 __ pop(rdx);
3367 Handle<Code> ic(isolate()->builtins()->builtin( 3577 Handle<Code> ic(isolate()->builtins()->builtin(
3368 Builtins::KeyedStoreIC_Initialize)); 3578 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
3579 : Builtins::KeyedStoreIC_Initialize));
3369 EmitCallIC(ic, RelocInfo::CODE_TARGET); 3580 EmitCallIC(ic, RelocInfo::CODE_TARGET);
3370 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3581 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3371 if (expr->is_postfix()) { 3582 if (expr->is_postfix()) {
3372 if (!context()->IsEffect()) { 3583 if (!context()->IsEffect()) {
3373 context()->PlugTOS(); 3584 context()->PlugTOS();
3374 } 3585 }
3375 } else { 3586 } else {
3376 context()->Plug(rax); 3587 context()->Plug(rax);
3377 } 3588 }
3378 break; 3589 break;
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
3704 __ nop(); // Signals no inlined code. 3915 __ nop(); // Signals no inlined code.
3705 break; 3916 break;
3706 default: 3917 default:
3707 // Do nothing. 3918 // Do nothing.
3708 break; 3919 break;
3709 } 3920 }
3710 } 3921 }
3711 3922
3712 3923
3713 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { 3924 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
3925 switch (ic->kind()) {
3926 case Code::LOAD_IC:
3927 __ IncrementCounter(COUNTERS->named_load_full(), 1);
3928 break;
3929 case Code::KEYED_LOAD_IC:
3930 __ IncrementCounter(COUNTERS->keyed_load_full(), 1);
3931 break;
3932 case Code::STORE_IC:
3933 __ IncrementCounter(COUNTERS->named_store_full(), 1);
3934 break;
3935 case Code::KEYED_STORE_IC:
3936 __ IncrementCounter(COUNTERS->keyed_store_full(), 1);
3937 default:
3938 break;
3939 }
3940
3714 __ call(ic, RelocInfo::CODE_TARGET); 3941 __ call(ic, RelocInfo::CODE_TARGET);
3715 if (patch_site != NULL && patch_site->is_bound()) { 3942 if (patch_site != NULL && patch_site->is_bound()) {
3716 patch_site->EmitPatchInfo(); 3943 patch_site->EmitPatchInfo();
3717 } else { 3944 } else {
3718 __ nop(); // Signals no inlined code. 3945 __ nop(); // Signals no inlined code.
3719 } 3946 }
3720 } 3947 }
3721 3948
3722 3949
3723 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { 3950 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
3764 __ ret(0); 3991 __ ret(0);
3765 } 3992 }
3766 3993
3767 3994
3768 #undef __ 3995 #undef __
3769 3996
3770 3997
3771 } } // namespace v8::internal 3998 } } // namespace v8::internal
3772 3999
3773 #endif // V8_TARGET_ARCH_X64 4000 #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