| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |