| 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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset)); | 59 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset)); |
| 60 __ j(not_equal, &miss); | 60 __ j(not_equal, &miss); |
| 61 | 61 |
| 62 // Check that the flags match what we're looking for. | 62 // Check that the flags match what we're looking for. |
| 63 __ mov(offset, FieldOperand(extra, Code::kFlagsOffset)); | 63 __ mov(offset, FieldOperand(extra, Code::kFlagsOffset)); |
| 64 __ and_(offset, ~Code::kFlagsNotUsedInLookup); | 64 __ and_(offset, ~Code::kFlagsNotUsedInLookup); |
| 65 __ cmp(offset, flags); | 65 __ cmp(offset, flags); |
| 66 __ j(not_equal, &miss); | 66 __ j(not_equal, &miss); |
| 67 | 67 |
| 68 // Jump to the first instruction in the code stub. | 68 // Jump to the first instruction in the code stub. |
| 69 __ add(Operand(extra), Immediate(Code::kHeaderSize - kHeapObjectTag)); | 69 __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 70 __ jmp(Operand(extra)); | 70 __ jmp(extra); |
| 71 | 71 |
| 72 __ bind(&miss); | 72 __ bind(&miss); |
| 73 } else { | 73 } else { |
| 74 // Save the offset on the stack. | 74 // Save the offset on the stack. |
| 75 __ push(offset); | 75 __ push(offset); |
| 76 | 76 |
| 77 // Check that the key in the entry matches the name. | 77 // Check that the key in the entry matches the name. |
| 78 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset)); | 78 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset)); |
| 79 __ j(not_equal, &miss); | 79 __ j(not_equal, &miss); |
| 80 | 80 |
| 81 // Get the code entry from the cache. | 81 // Get the code entry from the cache. |
| 82 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset)); | 82 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset)); |
| 83 | 83 |
| 84 // Check that the flags match what we're looking for. | 84 // Check that the flags match what we're looking for. |
| 85 __ mov(offset, FieldOperand(offset, Code::kFlagsOffset)); | 85 __ mov(offset, FieldOperand(offset, Code::kFlagsOffset)); |
| 86 __ and_(offset, ~Code::kFlagsNotUsedInLookup); | 86 __ and_(offset, ~Code::kFlagsNotUsedInLookup); |
| 87 __ cmp(offset, flags); | 87 __ cmp(offset, flags); |
| 88 __ j(not_equal, &miss); | 88 __ j(not_equal, &miss); |
| 89 | 89 |
| 90 // Restore offset and re-load code entry from cache. | 90 // Restore offset and re-load code entry from cache. |
| 91 __ pop(offset); | 91 __ pop(offset); |
| 92 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset)); | 92 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset)); |
| 93 | 93 |
| 94 // Jump to the first instruction in the code stub. | 94 // Jump to the first instruction in the code stub. |
| 95 __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag)); | 95 __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 96 __ jmp(Operand(offset)); | 96 __ jmp(offset); |
| 97 | 97 |
| 98 // Pop at miss. | 98 // Pop at miss. |
| 99 __ bind(&miss); | 99 __ bind(&miss); |
| 100 __ pop(offset); | 100 __ pop(offset); |
| 101 } | 101 } |
| 102 } | 102 } |
| 103 | 103 |
| 104 | 104 |
| 105 // Helper function used to check that the dictionary doesn't contain | 105 // Helper function used to check that the dictionary doesn't contain |
| 106 // the property. This function may return false negatives, so miss_label | 106 // the property. This function may return false negatives, so miss_label |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); | 197 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); |
| 198 | 198 |
| 199 // Probe the primary table. | 199 // Probe the primary table. |
| 200 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra); | 200 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra); |
| 201 | 201 |
| 202 // Primary miss: Compute hash for secondary probe. | 202 // Primary miss: Compute hash for secondary probe. |
| 203 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset)); | 203 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset)); |
| 204 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); | 204 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 205 __ xor_(scratch, flags); | 205 __ xor_(scratch, flags); |
| 206 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); | 206 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); |
| 207 __ sub(scratch, Operand(name)); | 207 __ sub(scratch, name); |
| 208 __ add(Operand(scratch), Immediate(flags)); | 208 __ add(scratch, Immediate(flags)); |
| 209 __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize); | 209 __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize); |
| 210 | 210 |
| 211 // Probe the secondary table. | 211 // Probe the secondary table. |
| 212 ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra); | 212 ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra); |
| 213 | 213 |
| 214 // Cache miss: Fall-through and let caller handle the miss by | 214 // Cache miss: Fall-through and let caller handle the miss by |
| 215 // entering the runtime system. | 215 // entering the runtime system. |
| 216 __ bind(&miss); | 216 __ bind(&miss); |
| 217 } | 217 } |
| 218 | 218 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 } | 311 } |
| 312 } | 312 } |
| 313 | 313 |
| 314 | 314 |
| 315 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, | 315 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, |
| 316 Register receiver, | 316 Register receiver, |
| 317 Register scratch1, | 317 Register scratch1, |
| 318 Register scratch2, | 318 Register scratch2, |
| 319 Label* miss_label) { | 319 Label* miss_label) { |
| 320 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); | 320 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); |
| 321 __ mov(eax, Operand(scratch1)); | 321 __ mov(eax, scratch1); |
| 322 __ ret(0); | 322 __ ret(0); |
| 323 } | 323 } |
| 324 | 324 |
| 325 | 325 |
| 326 // Load a fast property out of a holder object (src). In-object properties | 326 // Load a fast property out of a holder object (src). In-object properties |
| 327 // are loaded directly otherwise the property is loaded from the properties | 327 // are loaded directly otherwise the property is loaded from the properties |
| 328 // fixed array. | 328 // fixed array. |
| 329 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, | 329 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, |
| 330 Register dst, Register src, | 330 Register dst, Register src, |
| 331 JSObject* holder, int index) { | 331 JSObject* holder, int index) { |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { | 399 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { |
| 400 // ----------- S t a t e ------------- | 400 // ----------- S t a t e ------------- |
| 401 // -- esp[0] : return address. | 401 // -- esp[0] : return address. |
| 402 // -- esp[4] : last fast api call extra argument. | 402 // -- esp[4] : last fast api call extra argument. |
| 403 // -- ... | 403 // -- ... |
| 404 // -- esp[kFastApiCallArguments * 4] : first fast api call extra argument. | 404 // -- esp[kFastApiCallArguments * 4] : first fast api call extra argument. |
| 405 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal | 405 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal |
| 406 // frame. | 406 // frame. |
| 407 // ----------------------------------- | 407 // ----------------------------------- |
| 408 __ pop(scratch); | 408 __ pop(scratch); |
| 409 __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments)); | 409 __ add(esp, Immediate(kPointerSize * kFastApiCallArguments)); |
| 410 __ push(scratch); | 410 __ push(scratch); |
| 411 } | 411 } |
| 412 | 412 |
| 413 | 413 |
| 414 // Generates call to API function. | 414 // Generates call to API function. |
| 415 static MaybeObject* GenerateFastApiCall(MacroAssembler* masm, | 415 static MaybeObject* GenerateFastApiCall(MacroAssembler* masm, |
| 416 const CallOptimization& optimization, | 416 const CallOptimization& optimization, |
| 417 int argc) { | 417 int argc) { |
| 418 // ----------- S t a t e ------------- | 418 // ----------- S t a t e ------------- |
| 419 // -- esp[0] : return address | 419 // -- esp[0] : return address |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 | 455 |
| 456 const int kApiArgc = 1; // API function gets reference to the v8::Arguments. | 456 const int kApiArgc = 1; // API function gets reference to the v8::Arguments. |
| 457 | 457 |
| 458 // Allocate the v8::Arguments structure in the arguments' space since | 458 // Allocate the v8::Arguments structure in the arguments' space since |
| 459 // it's not controlled by GC. | 459 // it's not controlled by GC. |
| 460 const int kApiStackSpace = 4; | 460 const int kApiStackSpace = 4; |
| 461 | 461 |
| 462 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); | 462 __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); |
| 463 | 463 |
| 464 __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. | 464 __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. |
| 465 __ add(Operand(eax), Immediate(argc * kPointerSize)); | 465 __ add(eax, Immediate(argc * kPointerSize)); |
| 466 __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_. | 466 __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_. |
| 467 __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_. | 467 __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_. |
| 468 // v8::Arguments::is_construct_call_. | 468 // v8::Arguments::is_construct_call_. |
| 469 __ Set(ApiParameterOperand(4), Immediate(0)); | 469 __ Set(ApiParameterOperand(4), Immediate(0)); |
| 470 | 470 |
| 471 // v8::InvocationCallback's argument. | 471 // v8::InvocationCallback's argument. |
| 472 __ lea(eax, ApiParameterOperand(1)); | 472 __ lea(eax, ApiParameterOperand(1)); |
| 473 __ mov(ApiParameterOperand(0), eax); | 473 __ mov(ApiParameterOperand(0), eax); |
| 474 | 474 |
| 475 // Emitting a stub call may try to allocate (if the code is not | 475 // Emitting a stub call may try to allocate (if the code is not |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 Register scratch2, | 644 Register scratch2, |
| 645 Register scratch3, | 645 Register scratch3, |
| 646 String* name, | 646 String* name, |
| 647 JSObject* interceptor_holder, | 647 JSObject* interceptor_holder, |
| 648 Label* miss_label) { | 648 Label* miss_label) { |
| 649 Register holder = | 649 Register holder = |
| 650 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, | 650 stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
| 651 scratch1, scratch2, scratch3, name, | 651 scratch1, scratch2, scratch3, name, |
| 652 miss_label); | 652 miss_label); |
| 653 | 653 |
| 654 __ EnterInternalFrame(); | 654 FrameScope scope(masm, StackFrame::INTERNAL); |
| 655 // Save the name_ register across the call. | 655 // Save the name_ register across the call. |
| 656 __ push(name_); | 656 __ push(name_); |
| 657 | 657 |
| 658 PushInterceptorArguments(masm, | 658 PushInterceptorArguments(masm, |
| 659 receiver, | 659 receiver, |
| 660 holder, | 660 holder, |
| 661 name_, | 661 name_, |
| 662 interceptor_holder); | 662 interceptor_holder); |
| 663 | 663 |
| 664 __ CallExternalReference( | 664 __ CallExternalReference( |
| 665 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), | 665 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), |
| 666 masm->isolate()), | 666 masm->isolate()), |
| 667 5); | 667 5); |
| 668 | 668 |
| 669 // Restore the name_ register. | 669 // Restore the name_ register. |
| 670 __ pop(name_); | 670 __ pop(name_); |
| 671 __ LeaveInternalFrame(); | 671 |
| 672 // Leave the internal frame. |
| 672 } | 673 } |
| 673 | 674 |
| 674 void LoadWithInterceptor(MacroAssembler* masm, | 675 void LoadWithInterceptor(MacroAssembler* masm, |
| 675 Register receiver, | 676 Register receiver, |
| 676 Register holder, | 677 Register holder, |
| 677 JSObject* holder_obj, | 678 JSObject* holder_obj, |
| 678 Label* interceptor_succeeded) { | 679 Label* interceptor_succeeded) { |
| 679 __ EnterInternalFrame(); | 680 { |
| 680 __ push(holder); // Save the holder. | 681 FrameScope scope(masm, StackFrame::INTERNAL); |
| 681 __ push(name_); // Save the name. | 682 __ push(holder); // Save the holder. |
| 683 __ push(name_); // Save the name. |
| 682 | 684 |
| 683 CompileCallLoadPropertyWithInterceptor(masm, | 685 CompileCallLoadPropertyWithInterceptor(masm, |
| 684 receiver, | 686 receiver, |
| 685 holder, | 687 holder, |
| 686 name_, | 688 name_, |
| 687 holder_obj); | 689 holder_obj); |
| 688 | 690 |
| 689 __ pop(name_); // Restore the name. | 691 __ pop(name_); // Restore the name. |
| 690 __ pop(receiver); // Restore the holder. | 692 __ pop(receiver); // Restore the holder. |
| 691 __ LeaveInternalFrame(); | 693 // Leave the internal frame. |
| 694 } |
| 692 | 695 |
| 693 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel()); | 696 __ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel()); |
| 694 __ j(not_equal, interceptor_succeeded); | 697 __ j(not_equal, interceptor_succeeded); |
| 695 } | 698 } |
| 696 | 699 |
| 697 StubCompiler* stub_compiler_; | 700 StubCompiler* stub_compiler_; |
| 698 const ParameterCount& arguments_; | 701 const ParameterCount& arguments_; |
| 699 Register name_; | 702 Register name_; |
| 700 Code::ExtraICState extra_ic_state_; | 703 Code::ExtraICState extra_ic_state_; |
| 701 }; | 704 }; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 779 // object and the number of in-object properties is not going to change. | 782 // object and the number of in-object properties is not going to change. |
| 780 index -= object->map()->inobject_properties(); | 783 index -= object->map()->inobject_properties(); |
| 781 | 784 |
| 782 if (index < 0) { | 785 if (index < 0) { |
| 783 // Set the property straight into the object. | 786 // Set the property straight into the object. |
| 784 int offset = object->map()->instance_size() + (index * kPointerSize); | 787 int offset = object->map()->instance_size() + (index * kPointerSize); |
| 785 __ mov(FieldOperand(receiver_reg, offset), eax); | 788 __ mov(FieldOperand(receiver_reg, offset), eax); |
| 786 | 789 |
| 787 // Update the write barrier for the array address. | 790 // Update the write barrier for the array address. |
| 788 // Pass the value being stored in the now unused name_reg. | 791 // Pass the value being stored in the now unused name_reg. |
| 789 __ mov(name_reg, Operand(eax)); | 792 __ mov(name_reg, eax); |
| 790 __ RecordWrite(receiver_reg, offset, name_reg, scratch); | 793 __ RecordWriteField(receiver_reg, |
| 794 offset, |
| 795 name_reg, |
| 796 scratch, |
| 797 kDontSaveFPRegs); |
| 791 } else { | 798 } else { |
| 792 // Write to the properties array. | 799 // Write to the properties array. |
| 793 int offset = index * kPointerSize + FixedArray::kHeaderSize; | 800 int offset = index * kPointerSize + FixedArray::kHeaderSize; |
| 794 // Get the properties array (optimistically). | 801 // Get the properties array (optimistically). |
| 795 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); | 802 __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset)); |
| 796 __ mov(FieldOperand(scratch, offset), eax); | 803 __ mov(FieldOperand(scratch, offset), eax); |
| 797 | 804 |
| 798 // Update the write barrier for the array address. | 805 // Update the write barrier for the array address. |
| 799 // Pass the value being stored in the now unused name_reg. | 806 // Pass the value being stored in the now unused name_reg. |
| 800 __ mov(name_reg, Operand(eax)); | 807 __ mov(name_reg, eax); |
| 801 __ RecordWrite(scratch, offset, name_reg, receiver_reg); | 808 __ RecordWriteField(scratch, |
| 809 offset, |
| 810 name_reg, |
| 811 receiver_reg, |
| 812 kDontSaveFPRegs); |
| 802 } | 813 } |
| 803 | 814 |
| 804 // Return the value (register eax). | 815 // Return the value (register eax). |
| 805 __ ret(0); | 816 __ ret(0); |
| 806 } | 817 } |
| 807 | 818 |
| 808 | 819 |
| 809 // Generate code to check that a global property cell is empty. Create | 820 // Generate code to check that a global property cell is empty. Create |
| 810 // the property cell at compilation time if no cell exists for the | 821 // the property cell at compilation time if no cell exists for the |
| 811 // property. | 822 // property. |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 925 set_failure(Failure::cast(negative_lookup)); | 936 set_failure(Failure::cast(negative_lookup)); |
| 926 return reg; | 937 return reg; |
| 927 } | 938 } |
| 928 | 939 |
| 929 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 940 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 930 reg = holder_reg; // from now the object is in holder_reg | 941 reg = holder_reg; // from now the object is in holder_reg |
| 931 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 942 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
| 932 } else if (heap()->InNewSpace(prototype)) { | 943 } else if (heap()->InNewSpace(prototype)) { |
| 933 // Get the map of the current object. | 944 // Get the map of the current object. |
| 934 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 945 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 935 __ cmp(Operand(scratch1), Immediate(Handle<Map>(current->map()))); | 946 __ cmp(scratch1, Immediate(Handle<Map>(current->map()))); |
| 936 // Branch on the result of the map check. | 947 // Branch on the result of the map check. |
| 937 __ j(not_equal, miss); | 948 __ j(not_equal, miss); |
| 938 // Check access rights to the global object. This has to happen | 949 // Check access rights to the global object. This has to happen |
| 939 // after the map check so that we know that the object is | 950 // after the map check so that we know that the object is |
| 940 // actually a global object. | 951 // actually a global object. |
| 941 if (current->IsJSGlobalProxy()) { | 952 if (current->IsJSGlobalProxy()) { |
| 942 __ CheckAccessGlobalProxy(reg, scratch1, miss); | 953 __ CheckAccessGlobalProxy(reg, scratch1, miss); |
| 943 | 954 |
| 944 // Restore scratch register to be the map of the object. | 955 // Restore scratch register to be the map of the object. |
| 945 // We load the prototype from the map in the scratch register. | 956 // We load the prototype from the map in the scratch register. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1046 CheckPrototypes(object, receiver, holder, scratch1, | 1057 CheckPrototypes(object, receiver, holder, scratch1, |
| 1047 scratch2, scratch3, name, miss); | 1058 scratch2, scratch3, name, miss); |
| 1048 | 1059 |
| 1049 Handle<AccessorInfo> callback_handle(callback); | 1060 Handle<AccessorInfo> callback_handle(callback); |
| 1050 | 1061 |
| 1051 // Insert additional parameters into the stack frame above return address. | 1062 // Insert additional parameters into the stack frame above return address. |
| 1052 ASSERT(!scratch3.is(reg)); | 1063 ASSERT(!scratch3.is(reg)); |
| 1053 __ pop(scratch3); // Get return address to place it below. | 1064 __ pop(scratch3); // Get return address to place it below. |
| 1054 | 1065 |
| 1055 __ push(receiver); // receiver | 1066 __ push(receiver); // receiver |
| 1056 __ mov(scratch2, Operand(esp)); | 1067 __ mov(scratch2, esp); |
| 1057 ASSERT(!scratch2.is(reg)); | 1068 ASSERT(!scratch2.is(reg)); |
| 1058 __ push(reg); // holder | 1069 __ push(reg); // holder |
| 1059 // Push data from AccessorInfo. | 1070 // Push data from AccessorInfo. |
| 1060 if (isolate()->heap()->InNewSpace(callback_handle->data())) { | 1071 if (isolate()->heap()->InNewSpace(callback_handle->data())) { |
| 1061 __ mov(scratch1, Immediate(callback_handle)); | 1072 __ mov(scratch1, Immediate(callback_handle)); |
| 1062 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); | 1073 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); |
| 1063 } else { | 1074 } else { |
| 1064 __ push(Immediate(Handle<Object>(callback_handle->data()))); | 1075 __ push(Immediate(Handle<Object>(callback_handle->data()))); |
| 1065 } | 1076 } |
| 1066 | 1077 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1077 Address getter_address = v8::ToCData<Address>(callback->getter()); | 1088 Address getter_address = v8::ToCData<Address>(callback->getter()); |
| 1078 ApiFunction fun(getter_address); | 1089 ApiFunction fun(getter_address); |
| 1079 | 1090 |
| 1080 // 3 elements array for v8::Agruments::values_, handler for name and pointer | 1091 // 3 elements array for v8::Agruments::values_, handler for name and pointer |
| 1081 // to the values (it considered as smi in GC). | 1092 // to the values (it considered as smi in GC). |
| 1082 const int kStackSpace = 5; | 1093 const int kStackSpace = 5; |
| 1083 const int kApiArgc = 2; | 1094 const int kApiArgc = 2; |
| 1084 | 1095 |
| 1085 __ PrepareCallApiFunction(kApiArgc); | 1096 __ PrepareCallApiFunction(kApiArgc); |
| 1086 __ mov(ApiParameterOperand(0), ebx); // name. | 1097 __ mov(ApiParameterOperand(0), ebx); // name. |
| 1087 __ add(Operand(ebx), Immediate(kPointerSize)); | 1098 __ add(ebx, Immediate(kPointerSize)); |
| 1088 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. | 1099 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. |
| 1089 | 1100 |
| 1090 // Emitting a stub call may try to allocate (if the code is not | 1101 // Emitting a stub call may try to allocate (if the code is not |
| 1091 // already generated). Do not allow the assembler to perform a | 1102 // already generated). Do not allow the assembler to perform a |
| 1092 // garbage collection but instead return the allocation failure | 1103 // garbage collection but instead return the allocation failure |
| 1093 // object. | 1104 // object. |
| 1094 return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); | 1105 return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); |
| 1095 } | 1106 } |
| 1096 | 1107 |
| 1097 | 1108 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1151 // Compile the interceptor call, followed by inline code to load the | 1162 // Compile the interceptor call, followed by inline code to load the |
| 1152 // property from further up the prototype chain if the call fails. | 1163 // property from further up the prototype chain if the call fails. |
| 1153 // Check that the maps haven't changed. | 1164 // Check that the maps haven't changed. |
| 1154 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | 1165 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, |
| 1155 scratch1, scratch2, scratch3, | 1166 scratch1, scratch2, scratch3, |
| 1156 name, miss); | 1167 name, miss); |
| 1157 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); | 1168 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); |
| 1158 | 1169 |
| 1159 // Save necessary data before invoking an interceptor. | 1170 // Save necessary data before invoking an interceptor. |
| 1160 // Requires a frame to make GC aware of pushed pointers. | 1171 // Requires a frame to make GC aware of pushed pointers. |
| 1161 __ EnterInternalFrame(); | 1172 { |
| 1173 FrameScope frame_scope(masm(), StackFrame::INTERNAL); |
| 1162 | 1174 |
| 1163 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { | 1175 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
| 1164 // CALLBACKS case needs a receiver to be passed into C++ callback. | 1176 // CALLBACKS case needs a receiver to be passed into C++ callback. |
| 1165 __ push(receiver); | 1177 __ push(receiver); |
| 1178 } |
| 1179 __ push(holder_reg); |
| 1180 __ push(name_reg); |
| 1181 |
| 1182 // Invoke an interceptor. Note: map checks from receiver to |
| 1183 // interceptor's holder has been compiled before (see a caller |
| 1184 // of this method.) |
| 1185 CompileCallLoadPropertyWithInterceptor(masm(), |
| 1186 receiver, |
| 1187 holder_reg, |
| 1188 name_reg, |
| 1189 interceptor_holder); |
| 1190 |
| 1191 // Check if interceptor provided a value for property. If it's |
| 1192 // the case, return immediately. |
| 1193 Label interceptor_failed; |
| 1194 __ cmp(eax, factory()->no_interceptor_result_sentinel()); |
| 1195 __ j(equal, &interceptor_failed); |
| 1196 frame_scope.GenerateLeaveFrame(); |
| 1197 __ ret(0); |
| 1198 |
| 1199 __ bind(&interceptor_failed); |
| 1200 __ pop(name_reg); |
| 1201 __ pop(holder_reg); |
| 1202 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
| 1203 __ pop(receiver); |
| 1204 } |
| 1205 |
| 1206 // Leave the internal frame. |
| 1166 } | 1207 } |
| 1167 __ push(holder_reg); | |
| 1168 __ push(name_reg); | |
| 1169 | |
| 1170 // Invoke an interceptor. Note: map checks from receiver to | |
| 1171 // interceptor's holder has been compiled before (see a caller | |
| 1172 // of this method.) | |
| 1173 CompileCallLoadPropertyWithInterceptor(masm(), | |
| 1174 receiver, | |
| 1175 holder_reg, | |
| 1176 name_reg, | |
| 1177 interceptor_holder); | |
| 1178 | |
| 1179 // Check if interceptor provided a value for property. If it's | |
| 1180 // the case, return immediately. | |
| 1181 Label interceptor_failed; | |
| 1182 __ cmp(eax, factory()->no_interceptor_result_sentinel()); | |
| 1183 __ j(equal, &interceptor_failed); | |
| 1184 __ LeaveInternalFrame(); | |
| 1185 __ ret(0); | |
| 1186 | |
| 1187 __ bind(&interceptor_failed); | |
| 1188 __ pop(name_reg); | |
| 1189 __ pop(holder_reg); | |
| 1190 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { | |
| 1191 __ pop(receiver); | |
| 1192 } | |
| 1193 | |
| 1194 __ LeaveInternalFrame(); | |
| 1195 | 1208 |
| 1196 // Check that the maps from interceptor's holder to lookup's holder | 1209 // Check that the maps from interceptor's holder to lookup's holder |
| 1197 // haven't changed. And load lookup's holder into holder_reg. | 1210 // haven't changed. And load lookup's holder into holder_reg. |
| 1198 if (interceptor_holder != lookup->holder()) { | 1211 if (interceptor_holder != lookup->holder()) { |
| 1199 holder_reg = CheckPrototypes(interceptor_holder, | 1212 holder_reg = CheckPrototypes(interceptor_holder, |
| 1200 holder_reg, | 1213 holder_reg, |
| 1201 lookup->holder(), | 1214 lookup->holder(), |
| 1202 scratch1, | 1215 scratch1, |
| 1203 scratch2, | 1216 scratch2, |
| 1204 scratch3, | 1217 scratch3, |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1252 ExternalReference ref = | 1265 ExternalReference ref = |
| 1253 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), | 1266 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), |
| 1254 isolate()); | 1267 isolate()); |
| 1255 __ TailCallExternalReference(ref, 5, 1); | 1268 __ TailCallExternalReference(ref, 5, 1); |
| 1256 } | 1269 } |
| 1257 } | 1270 } |
| 1258 | 1271 |
| 1259 | 1272 |
| 1260 void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { | 1273 void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { |
| 1261 if (kind_ == Code::KEYED_CALL_IC) { | 1274 if (kind_ == Code::KEYED_CALL_IC) { |
| 1262 __ cmp(Operand(ecx), Immediate(Handle<String>(name))); | 1275 __ cmp(ecx, Immediate(Handle<String>(name))); |
| 1263 __ j(not_equal, miss); | 1276 __ j(not_equal, miss); |
| 1264 } | 1277 } |
| 1265 } | 1278 } |
| 1266 | 1279 |
| 1267 | 1280 |
| 1268 void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, | 1281 void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, |
| 1269 JSObject* holder, | 1282 JSObject* holder, |
| 1270 String* name, | 1283 String* name, |
| 1271 Label* miss) { | 1284 Label* miss) { |
| 1272 ASSERT(holder->IsGlobalObject()); | 1285 ASSERT(holder->IsGlobalObject()); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1309 // function, we have to verify that it still is a function. | 1322 // function, we have to verify that it still is a function. |
| 1310 __ JumpIfSmi(edi, miss); | 1323 __ JumpIfSmi(edi, miss); |
| 1311 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); | 1324 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); |
| 1312 __ j(not_equal, miss); | 1325 __ j(not_equal, miss); |
| 1313 | 1326 |
| 1314 // Check the shared function info. Make sure it hasn't changed. | 1327 // Check the shared function info. Make sure it hasn't changed. |
| 1315 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), | 1328 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), |
| 1316 Immediate(Handle<SharedFunctionInfo>(function->shared()))); | 1329 Immediate(Handle<SharedFunctionInfo>(function->shared()))); |
| 1317 __ j(not_equal, miss); | 1330 __ j(not_equal, miss); |
| 1318 } else { | 1331 } else { |
| 1319 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); | 1332 __ cmp(edi, Immediate(Handle<JSFunction>(function))); |
| 1320 __ j(not_equal, miss); | 1333 __ j(not_equal, miss); |
| 1321 } | 1334 } |
| 1322 } | 1335 } |
| 1323 | 1336 |
| 1324 | 1337 |
| 1325 MaybeObject* CallStubCompiler::GenerateMissBranch() { | 1338 MaybeObject* CallStubCompiler::GenerateMissBranch() { |
| 1326 MaybeObject* maybe_obj = | 1339 MaybeObject* maybe_obj = |
| 1327 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), | 1340 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), |
| 1328 kind_, | 1341 kind_, |
| 1329 extra_ic_state_); | 1342 extra_ic_state_); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1434 | 1447 |
| 1435 // Get the elements array of the object. | 1448 // Get the elements array of the object. |
| 1436 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); | 1449 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| 1437 | 1450 |
| 1438 // Check that the elements are in fast mode and writable. | 1451 // Check that the elements are in fast mode and writable. |
| 1439 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1452 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1440 Immediate(factory()->fixed_array_map())); | 1453 Immediate(factory()->fixed_array_map())); |
| 1441 __ j(not_equal, &call_builtin); | 1454 __ j(not_equal, &call_builtin); |
| 1442 | 1455 |
| 1443 if (argc == 1) { // Otherwise fall through to call builtin. | 1456 if (argc == 1) { // Otherwise fall through to call builtin. |
| 1444 Label exit, with_write_barrier, attempt_to_grow_elements; | 1457 Label attempt_to_grow_elements, with_write_barrier; |
| 1445 | 1458 |
| 1446 // Get the array's length into eax and calculate new length. | 1459 // Get the array's length into eax and calculate new length. |
| 1447 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); | 1460 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1448 STATIC_ASSERT(kSmiTagSize == 1); | 1461 STATIC_ASSERT(kSmiTagSize == 1); |
| 1449 STATIC_ASSERT(kSmiTag == 0); | 1462 STATIC_ASSERT(kSmiTag == 0); |
| 1450 __ add(Operand(eax), Immediate(Smi::FromInt(argc))); | 1463 __ add(eax, Immediate(Smi::FromInt(argc))); |
| 1451 | 1464 |
| 1452 // Get the element's length into ecx. | 1465 // Get the element's length into ecx. |
| 1453 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); | 1466 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); |
| 1454 | 1467 |
| 1455 // Check if we could survive without allocation. | 1468 // Check if we could survive without allocation. |
| 1456 __ cmp(eax, Operand(ecx)); | 1469 __ cmp(eax, ecx); |
| 1457 __ j(greater, &attempt_to_grow_elements); | 1470 __ j(greater, &attempt_to_grow_elements); |
| 1458 | 1471 |
| 1472 // Check if value is a smi. |
| 1473 __ mov(ecx, Operand(esp, argc * kPointerSize)); |
| 1474 __ JumpIfNotSmi(ecx, &with_write_barrier); |
| 1475 |
| 1459 // Save new length. | 1476 // Save new length. |
| 1460 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); | 1477 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 1461 | 1478 |
| 1462 // Push the element. | 1479 // Push the element. |
| 1463 __ lea(edx, FieldOperand(ebx, | 1480 __ lea(edx, FieldOperand(ebx, |
| 1464 eax, times_half_pointer_size, | 1481 eax, times_half_pointer_size, |
| 1465 FixedArray::kHeaderSize - argc * kPointerSize)); | 1482 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 1466 __ mov(ecx, Operand(esp, argc * kPointerSize)); | |
| 1467 __ mov(Operand(edx, 0), ecx); | 1483 __ mov(Operand(edx, 0), ecx); |
| 1468 | 1484 |
| 1469 // Check if value is a smi. | |
| 1470 __ JumpIfNotSmi(ecx, &with_write_barrier); | |
| 1471 | |
| 1472 __ bind(&exit); | |
| 1473 __ ret((argc + 1) * kPointerSize); | 1485 __ ret((argc + 1) * kPointerSize); |
| 1474 | 1486 |
| 1475 __ bind(&with_write_barrier); | 1487 __ bind(&with_write_barrier); |
| 1476 | 1488 |
| 1477 __ InNewSpace(ebx, ecx, equal, &exit); | 1489 if (FLAG_smi_only_arrays) { |
| 1490 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
| 1491 __ CheckFastObjectElements(edi, &call_builtin); |
| 1492 } |
| 1478 | 1493 |
| 1479 __ RecordWriteHelper(ebx, edx, ecx); | 1494 // Save new length. |
| 1495 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 1496 |
| 1497 // Push the element. |
| 1498 __ lea(edx, FieldOperand(ebx, |
| 1499 eax, times_half_pointer_size, |
| 1500 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 1501 __ mov(Operand(edx, 0), ecx); |
| 1502 |
| 1503 __ RecordWrite( |
| 1504 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 1505 |
| 1480 __ ret((argc + 1) * kPointerSize); | 1506 __ ret((argc + 1) * kPointerSize); |
| 1481 | 1507 |
| 1482 __ bind(&attempt_to_grow_elements); | 1508 __ bind(&attempt_to_grow_elements); |
| 1483 if (!FLAG_inline_new) { | 1509 if (!FLAG_inline_new) { |
| 1484 __ jmp(&call_builtin); | 1510 __ jmp(&call_builtin); |
| 1485 } | 1511 } |
| 1486 | 1512 |
| 1513 __ mov(edi, Operand(esp, argc * kPointerSize)); |
| 1514 if (FLAG_smi_only_arrays) { |
| 1515 // Growing elements that are SMI-only requires special handling in case |
| 1516 // the new element is non-Smi. For now, delegate to the builtin. |
| 1517 Label no_fast_elements_check; |
| 1518 __ JumpIfSmi(edi, &no_fast_elements_check); |
| 1519 __ mov(esi, FieldOperand(edx, HeapObject::kMapOffset)); |
| 1520 __ CheckFastObjectElements(esi, &call_builtin, Label::kFar); |
| 1521 __ bind(&no_fast_elements_check); |
| 1522 } |
| 1523 |
| 1524 // We could be lucky and the elements array could be at the top of |
| 1525 // new-space. In this case we can just grow it in place by moving the |
| 1526 // allocation pointer up. |
| 1527 |
| 1487 ExternalReference new_space_allocation_top = | 1528 ExternalReference new_space_allocation_top = |
| 1488 ExternalReference::new_space_allocation_top_address(isolate()); | 1529 ExternalReference::new_space_allocation_top_address(isolate()); |
| 1489 ExternalReference new_space_allocation_limit = | 1530 ExternalReference new_space_allocation_limit = |
| 1490 ExternalReference::new_space_allocation_limit_address(isolate()); | 1531 ExternalReference::new_space_allocation_limit_address(isolate()); |
| 1491 | 1532 |
| 1492 const int kAllocationDelta = 4; | 1533 const int kAllocationDelta = 4; |
| 1493 // Load top. | 1534 // Load top. |
| 1494 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top)); | 1535 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top)); |
| 1495 | 1536 |
| 1496 // Check if it's the end of elements. | 1537 // Check if it's the end of elements. |
| 1497 __ lea(edx, FieldOperand(ebx, | 1538 __ lea(edx, FieldOperand(ebx, |
| 1498 eax, times_half_pointer_size, | 1539 eax, times_half_pointer_size, |
| 1499 FixedArray::kHeaderSize - argc * kPointerSize)); | 1540 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 1500 __ cmp(edx, Operand(ecx)); | 1541 __ cmp(edx, ecx); |
| 1501 __ j(not_equal, &call_builtin); | 1542 __ j(not_equal, &call_builtin); |
| 1502 __ add(Operand(ecx), Immediate(kAllocationDelta * kPointerSize)); | 1543 __ add(ecx, Immediate(kAllocationDelta * kPointerSize)); |
| 1503 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit)); | 1544 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit)); |
| 1504 __ j(above, &call_builtin); | 1545 __ j(above, &call_builtin); |
| 1505 | 1546 |
| 1506 // We fit and could grow elements. | 1547 // We fit and could grow elements. |
| 1507 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx); | 1548 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx); |
| 1508 __ mov(ecx, Operand(esp, argc * kPointerSize)); | |
| 1509 | 1549 |
| 1510 // Push the argument... | 1550 // Push the argument... |
| 1511 __ mov(Operand(edx, 0), ecx); | 1551 __ mov(Operand(edx, 0), edi); |
| 1512 // ... and fill the rest with holes. | 1552 // ... and fill the rest with holes. |
| 1513 for (int i = 1; i < kAllocationDelta; i++) { | 1553 for (int i = 1; i < kAllocationDelta; i++) { |
| 1514 __ mov(Operand(edx, i * kPointerSize), | 1554 __ mov(Operand(edx, i * kPointerSize), |
| 1515 Immediate(factory()->the_hole_value())); | 1555 Immediate(factory()->the_hole_value())); |
| 1516 } | 1556 } |
| 1517 | 1557 |
| 1558 // We know the elements array is in new space so we don't need the |
| 1559 // remembered set, but we just pushed a value onto it so we may have to |
| 1560 // tell the incremental marker to rescan the object that we just grew. We |
| 1561 // don't need to worry about the holes because they are in old space and |
| 1562 // already marked black. |
| 1563 __ RecordWrite(ebx, edx, edi, kDontSaveFPRegs, OMIT_REMEMBERED_SET); |
| 1564 |
| 1518 // Restore receiver to edx as finish sequence assumes it's here. | 1565 // Restore receiver to edx as finish sequence assumes it's here. |
| 1519 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1566 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1520 | 1567 |
| 1521 // Increment element's and array's sizes. | 1568 // Increment element's and array's sizes. |
| 1522 __ add(FieldOperand(ebx, FixedArray::kLengthOffset), | 1569 __ add(FieldOperand(ebx, FixedArray::kLengthOffset), |
| 1523 Immediate(Smi::FromInt(kAllocationDelta))); | 1570 Immediate(Smi::FromInt(kAllocationDelta))); |
| 1571 |
| 1572 // NOTE: This only happen in new-space, where we don't |
| 1573 // care about the black-byte-count on pages. Otherwise we should |
| 1574 // update that too if the object is black. |
| 1575 |
| 1524 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); | 1576 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 1525 | 1577 |
| 1526 // Elements are in new space, so write barrier is not required. | |
| 1527 __ ret((argc + 1) * kPointerSize); | 1578 __ ret((argc + 1) * kPointerSize); |
| 1528 } | 1579 } |
| 1529 | 1580 |
| 1530 __ bind(&call_builtin); | 1581 __ bind(&call_builtin); |
| 1531 __ TailCallExternalReference( | 1582 __ TailCallExternalReference( |
| 1532 ExternalReference(Builtins::c_ArrayPush, isolate()), | 1583 ExternalReference(Builtins::c_ArrayPush, isolate()), |
| 1533 argc + 1, | 1584 argc + 1, |
| 1534 1); | 1585 1); |
| 1535 } | 1586 } |
| 1536 | 1587 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1578 // Get the elements array of the object. | 1629 // Get the elements array of the object. |
| 1579 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); | 1630 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| 1580 | 1631 |
| 1581 // Check that the elements are in fast mode and writable. | 1632 // Check that the elements are in fast mode and writable. |
| 1582 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1633 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1583 Immediate(factory()->fixed_array_map())); | 1634 Immediate(factory()->fixed_array_map())); |
| 1584 __ j(not_equal, &call_builtin); | 1635 __ j(not_equal, &call_builtin); |
| 1585 | 1636 |
| 1586 // Get the array's length into ecx and calculate new length. | 1637 // Get the array's length into ecx and calculate new length. |
| 1587 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset)); | 1638 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1588 __ sub(Operand(ecx), Immediate(Smi::FromInt(1))); | 1639 __ sub(ecx, Immediate(Smi::FromInt(1))); |
| 1589 __ j(negative, &return_undefined); | 1640 __ j(negative, &return_undefined); |
| 1590 | 1641 |
| 1591 // Get the last element. | 1642 // Get the last element. |
| 1592 STATIC_ASSERT(kSmiTagSize == 1); | 1643 STATIC_ASSERT(kSmiTagSize == 1); |
| 1593 STATIC_ASSERT(kSmiTag == 0); | 1644 STATIC_ASSERT(kSmiTag == 0); |
| 1594 __ mov(eax, FieldOperand(ebx, | 1645 __ mov(eax, FieldOperand(ebx, |
| 1595 ecx, times_half_pointer_size, | 1646 ecx, times_half_pointer_size, |
| 1596 FixedArray::kHeaderSize)); | 1647 FixedArray::kHeaderSize)); |
| 1597 __ cmp(Operand(eax), Immediate(factory()->the_hole_value())); | 1648 __ cmp(eax, Immediate(factory()->the_hole_value())); |
| 1598 __ j(equal, &call_builtin); | 1649 __ j(equal, &call_builtin); |
| 1599 | 1650 |
| 1600 // Set the array's length. | 1651 // Set the array's length. |
| 1601 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx); | 1652 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx); |
| 1602 | 1653 |
| 1603 // Fill with the hole. | 1654 // Fill with the hole. |
| 1604 __ mov(FieldOperand(ebx, | 1655 __ mov(FieldOperand(ebx, |
| 1605 ecx, times_half_pointer_size, | 1656 ecx, times_half_pointer_size, |
| 1606 FixedArray::kHeaderSize), | 1657 FixedArray::kHeaderSize), |
| 1607 Immediate(factory()->the_hole_value())); | 1658 Immediate(factory()->the_hole_value())); |
| (...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2051 Label not_smi; | 2102 Label not_smi; |
| 2052 STATIC_ASSERT(kSmiTag == 0); | 2103 STATIC_ASSERT(kSmiTag == 0); |
| 2053 __ JumpIfNotSmi(eax, ¬_smi); | 2104 __ JumpIfNotSmi(eax, ¬_smi); |
| 2054 | 2105 |
| 2055 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0 | 2106 // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0 |
| 2056 // otherwise. | 2107 // otherwise. |
| 2057 __ mov(ebx, eax); | 2108 __ mov(ebx, eax); |
| 2058 __ sar(ebx, kBitsPerInt - 1); | 2109 __ sar(ebx, kBitsPerInt - 1); |
| 2059 | 2110 |
| 2060 // Do bitwise not or do nothing depending on ebx. | 2111 // Do bitwise not or do nothing depending on ebx. |
| 2061 __ xor_(eax, Operand(ebx)); | 2112 __ xor_(eax, ebx); |
| 2062 | 2113 |
| 2063 // Add 1 or do nothing depending on ebx. | 2114 // Add 1 or do nothing depending on ebx. |
| 2064 __ sub(eax, Operand(ebx)); | 2115 __ sub(eax, ebx); |
| 2065 | 2116 |
| 2066 // If the result is still negative, go to the slow case. | 2117 // If the result is still negative, go to the slow case. |
| 2067 // This only happens for the most negative smi. | 2118 // This only happens for the most negative smi. |
| 2068 Label slow; | 2119 Label slow; |
| 2069 __ j(negative, &slow); | 2120 __ j(negative, &slow); |
| 2070 | 2121 |
| 2071 // Smi case done. | 2122 // Smi case done. |
| 2072 __ ret(2 * kPointerSize); | 2123 __ ret(2 * kPointerSize); |
| 2073 | 2124 |
| 2074 // Check if the argument is a heap number and load its exponent and | 2125 // Check if the argument is a heap number and load its exponent and |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2137 | 2188 |
| 2138 // Check that the receiver isn't a smi. | 2189 // Check that the receiver isn't a smi. |
| 2139 __ JumpIfSmi(edx, &miss_before_stack_reserved); | 2190 __ JumpIfSmi(edx, &miss_before_stack_reserved); |
| 2140 | 2191 |
| 2141 Counters* counters = isolate()->counters(); | 2192 Counters* counters = isolate()->counters(); |
| 2142 __ IncrementCounter(counters->call_const(), 1); | 2193 __ IncrementCounter(counters->call_const(), 1); |
| 2143 __ IncrementCounter(counters->call_const_fast_api(), 1); | 2194 __ IncrementCounter(counters->call_const_fast_api(), 1); |
| 2144 | 2195 |
| 2145 // Allocate space for v8::Arguments implicit values. Must be initialized | 2196 // Allocate space for v8::Arguments implicit values. Must be initialized |
| 2146 // before calling any runtime function. | 2197 // before calling any runtime function. |
| 2147 __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); | 2198 __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize)); |
| 2148 | 2199 |
| 2149 // Check that the maps haven't changed and find a Holder as a side effect. | 2200 // Check that the maps haven't changed and find a Holder as a side effect. |
| 2150 CheckPrototypes(JSObject::cast(object), edx, holder, | 2201 CheckPrototypes(JSObject::cast(object), edx, holder, |
| 2151 ebx, eax, edi, name, depth, &miss); | 2202 ebx, eax, edi, name, depth, &miss); |
| 2152 | 2203 |
| 2153 // Move the return address on top of the stack. | 2204 // Move the return address on top of the stack. |
| 2154 __ mov(eax, Operand(esp, 3 * kPointerSize)); | 2205 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
| 2155 __ mov(Operand(esp, 0 * kPointerSize), eax); | 2206 __ mov(Operand(esp, 0 * kPointerSize), eax); |
| 2156 | 2207 |
| 2157 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains | 2208 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains |
| 2158 // duplicate of return address and will be overwritten. | 2209 // duplicate of return address and will be overwritten. |
| 2159 MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc); | 2210 MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc); |
| 2160 if (result->IsFailure()) return result; | 2211 if (result->IsFailure()) return result; |
| 2161 | 2212 |
| 2162 __ bind(&miss); | 2213 __ bind(&miss); |
| 2163 __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); | 2214 __ add(esp, Immediate(kFastApiCallArguments * kPointerSize)); |
| 2164 | 2215 |
| 2165 __ bind(&miss_before_stack_reserved); | 2216 __ bind(&miss_before_stack_reserved); |
| 2166 MaybeObject* maybe_result = GenerateMissBranch(); | 2217 MaybeObject* maybe_result = GenerateMissBranch(); |
| 2167 if (maybe_result->IsFailure()) return maybe_result; | 2218 if (maybe_result->IsFailure()) return maybe_result; |
| 2168 | 2219 |
| 2169 // Return the generated code. | 2220 // Return the generated code. |
| 2170 return GetCode(function); | 2221 return GetCode(function); |
| 2171 } | 2222 } |
| 2172 | 2223 |
| 2173 | 2224 |
| (...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2592 // -- edx : receiver | 2643 // -- edx : receiver |
| 2593 // -- esp[0] : return address | 2644 // -- esp[0] : return address |
| 2594 // ----------------------------------- | 2645 // ----------------------------------- |
| 2595 Label miss; | 2646 Label miss; |
| 2596 | 2647 |
| 2597 // Check that the map of the global has not changed. | 2648 // Check that the map of the global has not changed. |
| 2598 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 2649 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 2599 Immediate(Handle<Map>(object->map()))); | 2650 Immediate(Handle<Map>(object->map()))); |
| 2600 __ j(not_equal, &miss); | 2651 __ j(not_equal, &miss); |
| 2601 | 2652 |
| 2602 | |
| 2603 // Compute the cell operand to use. | 2653 // Compute the cell operand to use. |
| 2604 Operand cell_operand = Operand::Cell(Handle<JSGlobalPropertyCell>(cell)); | 2654 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
| 2605 if (Serializer::enabled()) { | 2655 Operand cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset); |
| 2606 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); | |
| 2607 cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset); | |
| 2608 } | |
| 2609 | 2656 |
| 2610 // Check that the value in the cell is not the hole. If it is, this | 2657 // Check that the value in the cell is not the hole. If it is, this |
| 2611 // cell could have been deleted and reintroducing the global needs | 2658 // cell could have been deleted and reintroducing the global needs |
| 2612 // to update the property details in the property dictionary of the | 2659 // to update the property details in the property dictionary of the |
| 2613 // global object. We bail out to the runtime system to do that. | 2660 // global object. We bail out to the runtime system to do that. |
| 2614 __ cmp(cell_operand, factory()->the_hole_value()); | 2661 __ cmp(cell_operand, factory()->the_hole_value()); |
| 2615 __ j(equal, &miss); | 2662 __ j(equal, &miss); |
| 2616 | 2663 |
| 2617 // Store the value in the cell. | 2664 // Store the value in the cell. |
| 2618 __ mov(cell_operand, eax); | 2665 __ mov(cell_operand, eax); |
| 2666 Label done; |
| 2667 __ test(eax, Immediate(kSmiTagMask)); |
| 2668 __ j(zero, &done); |
| 2669 |
| 2670 __ mov(ecx, eax); |
| 2671 __ lea(edx, cell_operand); |
| 2672 // Cells are always in the remembered set. |
| 2673 __ RecordWrite(ebx, // Object. |
| 2674 edx, // Address. |
| 2675 ecx, // Value. |
| 2676 kDontSaveFPRegs, |
| 2677 OMIT_REMEMBERED_SET, |
| 2678 OMIT_SMI_CHECK); |
| 2619 | 2679 |
| 2620 // Return the value (register eax). | 2680 // Return the value (register eax). |
| 2681 __ bind(&done); |
| 2682 |
| 2621 Counters* counters = isolate()->counters(); | 2683 Counters* counters = isolate()->counters(); |
| 2622 __ IncrementCounter(counters->named_store_global_inline(), 1); | 2684 __ IncrementCounter(counters->named_store_global_inline(), 1); |
| 2623 __ ret(0); | 2685 __ ret(0); |
| 2624 | 2686 |
| 2625 // Handle store cache miss. | 2687 // Handle store cache miss. |
| 2626 __ bind(&miss); | 2688 __ bind(&miss); |
| 2627 __ IncrementCounter(counters->named_store_global_inline_miss(), 1); | 2689 __ IncrementCounter(counters->named_store_global_inline_miss(), 1); |
| 2628 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); | 2690 Handle<Code> ic = isolate()->builtins()->StoreIC_Miss(); |
| 2629 __ jmp(ic, RelocInfo::CODE_TARGET); | 2691 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2630 | 2692 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2642 // -- ecx : key | 2704 // -- ecx : key |
| 2643 // -- edx : receiver | 2705 // -- edx : receiver |
| 2644 // -- esp[0] : return address | 2706 // -- esp[0] : return address |
| 2645 // ----------------------------------- | 2707 // ----------------------------------- |
| 2646 Label miss; | 2708 Label miss; |
| 2647 | 2709 |
| 2648 Counters* counters = isolate()->counters(); | 2710 Counters* counters = isolate()->counters(); |
| 2649 __ IncrementCounter(counters->keyed_store_field(), 1); | 2711 __ IncrementCounter(counters->keyed_store_field(), 1); |
| 2650 | 2712 |
| 2651 // Check that the name has not changed. | 2713 // Check that the name has not changed. |
| 2652 __ cmp(Operand(ecx), Immediate(Handle<String>(name))); | 2714 __ cmp(ecx, Immediate(Handle<String>(name))); |
| 2653 __ j(not_equal, &miss); | 2715 __ j(not_equal, &miss); |
| 2654 | 2716 |
| 2655 // Generate store field code. Trashes the name register. | 2717 // Generate store field code. Trashes the name register. |
| 2656 GenerateStoreField(masm(), | 2718 GenerateStoreField(masm(), |
| 2657 object, | 2719 object, |
| 2658 index, | 2720 index, |
| 2659 transition, | 2721 transition, |
| 2660 edx, ecx, ebx, | 2722 edx, ecx, ebx, |
| 2661 &miss); | 2723 &miss); |
| 2662 | 2724 |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2934 // -- eax : key | 2996 // -- eax : key |
| 2935 // -- edx : receiver | 2997 // -- edx : receiver |
| 2936 // -- esp[0] : return address | 2998 // -- esp[0] : return address |
| 2937 // ----------------------------------- | 2999 // ----------------------------------- |
| 2938 Label miss; | 3000 Label miss; |
| 2939 | 3001 |
| 2940 Counters* counters = isolate()->counters(); | 3002 Counters* counters = isolate()->counters(); |
| 2941 __ IncrementCounter(counters->keyed_load_field(), 1); | 3003 __ IncrementCounter(counters->keyed_load_field(), 1); |
| 2942 | 3004 |
| 2943 // Check that the name has not changed. | 3005 // Check that the name has not changed. |
| 2944 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3006 __ cmp(eax, Immediate(Handle<String>(name))); |
| 2945 __ j(not_equal, &miss); | 3007 __ j(not_equal, &miss); |
| 2946 | 3008 |
| 2947 GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss); | 3009 GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss); |
| 2948 | 3010 |
| 2949 __ bind(&miss); | 3011 __ bind(&miss); |
| 2950 __ DecrementCounter(counters->keyed_load_field(), 1); | 3012 __ DecrementCounter(counters->keyed_load_field(), 1); |
| 2951 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3013 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 2952 | 3014 |
| 2953 // Return the generated code. | 3015 // Return the generated code. |
| 2954 return GetCode(FIELD, name); | 3016 return GetCode(FIELD, name); |
| 2955 } | 3017 } |
| 2956 | 3018 |
| 2957 | 3019 |
| 2958 MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( | 3020 MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( |
| 2959 String* name, | 3021 String* name, |
| 2960 JSObject* receiver, | 3022 JSObject* receiver, |
| 2961 JSObject* holder, | 3023 JSObject* holder, |
| 2962 AccessorInfo* callback) { | 3024 AccessorInfo* callback) { |
| 2963 // ----------- S t a t e ------------- | 3025 // ----------- S t a t e ------------- |
| 2964 // -- eax : key | 3026 // -- eax : key |
| 2965 // -- edx : receiver | 3027 // -- edx : receiver |
| 2966 // -- esp[0] : return address | 3028 // -- esp[0] : return address |
| 2967 // ----------------------------------- | 3029 // ----------------------------------- |
| 2968 Label miss; | 3030 Label miss; |
| 2969 | 3031 |
| 2970 Counters* counters = isolate()->counters(); | 3032 Counters* counters = isolate()->counters(); |
| 2971 __ IncrementCounter(counters->keyed_load_callback(), 1); | 3033 __ IncrementCounter(counters->keyed_load_callback(), 1); |
| 2972 | 3034 |
| 2973 // Check that the name has not changed. | 3035 // Check that the name has not changed. |
| 2974 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3036 __ cmp(eax, Immediate(Handle<String>(name))); |
| 2975 __ j(not_equal, &miss); | 3037 __ j(not_equal, &miss); |
| 2976 | 3038 |
| 2977 MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx, | 3039 MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx, |
| 2978 ecx, edi, callback, name, &miss); | 3040 ecx, edi, callback, name, &miss); |
| 2979 if (result->IsFailure()) { | 3041 if (result->IsFailure()) { |
| 2980 miss.Unuse(); | 3042 miss.Unuse(); |
| 2981 return result; | 3043 return result; |
| 2982 } | 3044 } |
| 2983 | 3045 |
| 2984 __ bind(&miss); | 3046 __ bind(&miss); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2999 // -- eax : key | 3061 // -- eax : key |
| 3000 // -- edx : receiver | 3062 // -- edx : receiver |
| 3001 // -- esp[0] : return address | 3063 // -- esp[0] : return address |
| 3002 // ----------------------------------- | 3064 // ----------------------------------- |
| 3003 Label miss; | 3065 Label miss; |
| 3004 | 3066 |
| 3005 Counters* counters = isolate()->counters(); | 3067 Counters* counters = isolate()->counters(); |
| 3006 __ IncrementCounter(counters->keyed_load_constant_function(), 1); | 3068 __ IncrementCounter(counters->keyed_load_constant_function(), 1); |
| 3007 | 3069 |
| 3008 // Check that the name has not changed. | 3070 // Check that the name has not changed. |
| 3009 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3071 __ cmp(eax, Immediate(Handle<String>(name))); |
| 3010 __ j(not_equal, &miss); | 3072 __ j(not_equal, &miss); |
| 3011 | 3073 |
| 3012 GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi, | 3074 GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi, |
| 3013 value, name, &miss); | 3075 value, name, &miss); |
| 3014 __ bind(&miss); | 3076 __ bind(&miss); |
| 3015 __ DecrementCounter(counters->keyed_load_constant_function(), 1); | 3077 __ DecrementCounter(counters->keyed_load_constant_function(), 1); |
| 3016 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3078 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3017 | 3079 |
| 3018 // Return the generated code. | 3080 // Return the generated code. |
| 3019 return GetCode(CONSTANT_FUNCTION, name); | 3081 return GetCode(CONSTANT_FUNCTION, name); |
| 3020 } | 3082 } |
| 3021 | 3083 |
| 3022 | 3084 |
| 3023 MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, | 3085 MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, |
| 3024 JSObject* holder, | 3086 JSObject* holder, |
| 3025 String* name) { | 3087 String* name) { |
| 3026 // ----------- S t a t e ------------- | 3088 // ----------- S t a t e ------------- |
| 3027 // -- eax : key | 3089 // -- eax : key |
| 3028 // -- edx : receiver | 3090 // -- edx : receiver |
| 3029 // -- esp[0] : return address | 3091 // -- esp[0] : return address |
| 3030 // ----------------------------------- | 3092 // ----------------------------------- |
| 3031 Label miss; | 3093 Label miss; |
| 3032 | 3094 |
| 3033 Counters* counters = isolate()->counters(); | 3095 Counters* counters = isolate()->counters(); |
| 3034 __ IncrementCounter(counters->keyed_load_interceptor(), 1); | 3096 __ IncrementCounter(counters->keyed_load_interceptor(), 1); |
| 3035 | 3097 |
| 3036 // Check that the name has not changed. | 3098 // Check that the name has not changed. |
| 3037 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3099 __ cmp(eax, Immediate(Handle<String>(name))); |
| 3038 __ j(not_equal, &miss); | 3100 __ j(not_equal, &miss); |
| 3039 | 3101 |
| 3040 LookupResult lookup; | 3102 LookupResult lookup; |
| 3041 LookupPostInterceptor(holder, name, &lookup); | 3103 LookupPostInterceptor(holder, name, &lookup); |
| 3042 GenerateLoadInterceptor(receiver, | 3104 GenerateLoadInterceptor(receiver, |
| 3043 holder, | 3105 holder, |
| 3044 &lookup, | 3106 &lookup, |
| 3045 edx, | 3107 edx, |
| 3046 eax, | 3108 eax, |
| 3047 ecx, | 3109 ecx, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3063 // -- eax : key | 3125 // -- eax : key |
| 3064 // -- edx : receiver | 3126 // -- edx : receiver |
| 3065 // -- esp[0] : return address | 3127 // -- esp[0] : return address |
| 3066 // ----------------------------------- | 3128 // ----------------------------------- |
| 3067 Label miss; | 3129 Label miss; |
| 3068 | 3130 |
| 3069 Counters* counters = isolate()->counters(); | 3131 Counters* counters = isolate()->counters(); |
| 3070 __ IncrementCounter(counters->keyed_load_array_length(), 1); | 3132 __ IncrementCounter(counters->keyed_load_array_length(), 1); |
| 3071 | 3133 |
| 3072 // Check that the name has not changed. | 3134 // Check that the name has not changed. |
| 3073 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3135 __ cmp(eax, Immediate(Handle<String>(name))); |
| 3074 __ j(not_equal, &miss); | 3136 __ j(not_equal, &miss); |
| 3075 | 3137 |
| 3076 GenerateLoadArrayLength(masm(), edx, ecx, &miss); | 3138 GenerateLoadArrayLength(masm(), edx, ecx, &miss); |
| 3077 __ bind(&miss); | 3139 __ bind(&miss); |
| 3078 __ DecrementCounter(counters->keyed_load_array_length(), 1); | 3140 __ DecrementCounter(counters->keyed_load_array_length(), 1); |
| 3079 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3141 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3080 | 3142 |
| 3081 // Return the generated code. | 3143 // Return the generated code. |
| 3082 return GetCode(CALLBACKS, name); | 3144 return GetCode(CALLBACKS, name); |
| 3083 } | 3145 } |
| 3084 | 3146 |
| 3085 | 3147 |
| 3086 MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { | 3148 MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { |
| 3087 // ----------- S t a t e ------------- | 3149 // ----------- S t a t e ------------- |
| 3088 // -- eax : key | 3150 // -- eax : key |
| 3089 // -- edx : receiver | 3151 // -- edx : receiver |
| 3090 // -- esp[0] : return address | 3152 // -- esp[0] : return address |
| 3091 // ----------------------------------- | 3153 // ----------------------------------- |
| 3092 Label miss; | 3154 Label miss; |
| 3093 | 3155 |
| 3094 Counters* counters = isolate()->counters(); | 3156 Counters* counters = isolate()->counters(); |
| 3095 __ IncrementCounter(counters->keyed_load_string_length(), 1); | 3157 __ IncrementCounter(counters->keyed_load_string_length(), 1); |
| 3096 | 3158 |
| 3097 // Check that the name has not changed. | 3159 // Check that the name has not changed. |
| 3098 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3160 __ cmp(eax, Immediate(Handle<String>(name))); |
| 3099 __ j(not_equal, &miss); | 3161 __ j(not_equal, &miss); |
| 3100 | 3162 |
| 3101 GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true); | 3163 GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true); |
| 3102 __ bind(&miss); | 3164 __ bind(&miss); |
| 3103 __ DecrementCounter(counters->keyed_load_string_length(), 1); | 3165 __ DecrementCounter(counters->keyed_load_string_length(), 1); |
| 3104 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3166 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3105 | 3167 |
| 3106 // Return the generated code. | 3168 // Return the generated code. |
| 3107 return GetCode(CALLBACKS, name); | 3169 return GetCode(CALLBACKS, name); |
| 3108 } | 3170 } |
| 3109 | 3171 |
| 3110 | 3172 |
| 3111 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { | 3173 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { |
| 3112 // ----------- S t a t e ------------- | 3174 // ----------- S t a t e ------------- |
| 3113 // -- eax : key | 3175 // -- eax : key |
| 3114 // -- edx : receiver | 3176 // -- edx : receiver |
| 3115 // -- esp[0] : return address | 3177 // -- esp[0] : return address |
| 3116 // ----------------------------------- | 3178 // ----------------------------------- |
| 3117 Label miss; | 3179 Label miss; |
| 3118 | 3180 |
| 3119 Counters* counters = isolate()->counters(); | 3181 Counters* counters = isolate()->counters(); |
| 3120 __ IncrementCounter(counters->keyed_load_function_prototype(), 1); | 3182 __ IncrementCounter(counters->keyed_load_function_prototype(), 1); |
| 3121 | 3183 |
| 3122 // Check that the name has not changed. | 3184 // Check that the name has not changed. |
| 3123 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3185 __ cmp(eax, Immediate(Handle<String>(name))); |
| 3124 __ j(not_equal, &miss); | 3186 __ j(not_equal, &miss); |
| 3125 | 3187 |
| 3126 GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); | 3188 GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); |
| 3127 __ bind(&miss); | 3189 __ bind(&miss); |
| 3128 __ DecrementCounter(counters->keyed_load_function_prototype(), 1); | 3190 __ DecrementCounter(counters->keyed_load_function_prototype(), 1); |
| 3129 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3191 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3130 | 3192 |
| 3131 // Return the generated code. | 3193 // Return the generated code. |
| 3132 return GetCode(CALLBACKS, name); | 3194 return GetCode(CALLBACKS, name); |
| 3133 } | 3195 } |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3291 ASSERT(function->has_initial_map()); | 3353 ASSERT(function->has_initial_map()); |
| 3292 for (int i = shared->this_property_assignments_count(); | 3354 for (int i = shared->this_property_assignments_count(); |
| 3293 i < function->initial_map()->inobject_properties(); | 3355 i < function->initial_map()->inobject_properties(); |
| 3294 i++) { | 3356 i++) { |
| 3295 __ mov(Operand(edx, i * kPointerSize), edi); | 3357 __ mov(Operand(edx, i * kPointerSize), edi); |
| 3296 } | 3358 } |
| 3297 | 3359 |
| 3298 // Move argc to ebx and retrieve and tag the JSObject to return. | 3360 // Move argc to ebx and retrieve and tag the JSObject to return. |
| 3299 __ mov(ebx, eax); | 3361 __ mov(ebx, eax); |
| 3300 __ pop(eax); | 3362 __ pop(eax); |
| 3301 __ or_(Operand(eax), Immediate(kHeapObjectTag)); | 3363 __ or_(eax, Immediate(kHeapObjectTag)); |
| 3302 | 3364 |
| 3303 // Remove caller arguments and receiver from the stack and return. | 3365 // Remove caller arguments and receiver from the stack and return. |
| 3304 __ pop(ecx); | 3366 __ pop(ecx); |
| 3305 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize)); | 3367 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize)); |
| 3306 __ push(ecx); | 3368 __ push(ecx); |
| 3307 Counters* counters = isolate()->counters(); | 3369 Counters* counters = isolate()->counters(); |
| 3308 __ IncrementCounter(counters->constructed_objects(), 1); | 3370 __ IncrementCounter(counters->constructed_objects(), 1); |
| 3309 __ IncrementCounter(counters->constructed_objects_stub(), 1); | 3371 __ IncrementCounter(counters->constructed_objects_stub(), 1); |
| 3310 __ ret(0); | 3372 __ ret(0); |
| 3311 | 3373 |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3672 } | 3734 } |
| 3673 } else { | 3735 } else { |
| 3674 if (CpuFeatures::IsSupported(SSE3)) { | 3736 if (CpuFeatures::IsSupported(SSE3)) { |
| 3675 CpuFeatures::Scope scope(SSE3); | 3737 CpuFeatures::Scope scope(SSE3); |
| 3676 // fisttp stores values as signed integers. To represent the | 3738 // fisttp stores values as signed integers. To represent the |
| 3677 // entire range of int and unsigned int arrays, store as a | 3739 // entire range of int and unsigned int arrays, store as a |
| 3678 // 64-bit int and discard the high 32 bits. | 3740 // 64-bit int and discard the high 32 bits. |
| 3679 // If the value is NaN or +/-infinity, the result is 0x80000000, | 3741 // If the value is NaN or +/-infinity, the result is 0x80000000, |
| 3680 // which is automatically zero when taken mod 2^n, n < 32. | 3742 // which is automatically zero when taken mod 2^n, n < 32. |
| 3681 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3743 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3682 __ sub(Operand(esp), Immediate(2 * kPointerSize)); | 3744 __ sub(esp, Immediate(2 * kPointerSize)); |
| 3683 __ fisttp_d(Operand(esp, 0)); | 3745 __ fisttp_d(Operand(esp, 0)); |
| 3684 __ pop(ebx); | 3746 __ pop(ebx); |
| 3685 __ add(Operand(esp), Immediate(kPointerSize)); | 3747 __ add(esp, Immediate(kPointerSize)); |
| 3686 } else { | 3748 } else { |
| 3687 ASSERT(CpuFeatures::IsSupported(SSE2)); | 3749 ASSERT(CpuFeatures::IsSupported(SSE2)); |
| 3688 CpuFeatures::Scope scope(SSE2); | 3750 CpuFeatures::Scope scope(SSE2); |
| 3689 // We can easily implement the correct rounding behavior for the | 3751 // We can easily implement the correct rounding behavior for the |
| 3690 // range [0, 2^31-1]. For the time being, to keep this code simple, | 3752 // range [0, 2^31-1]. For the time being, to keep this code simple, |
| 3691 // make the slow runtime call for values outside this range. | 3753 // make the slow runtime call for values outside this range. |
| 3692 // Note: we could do better for signed int arrays. | 3754 // Note: we could do better for signed int arrays. |
| 3693 __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); | 3755 __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3694 // We will need the key if we have to make the slow runtime call. | 3756 // We will need the key if we have to make the slow runtime call. |
| 3695 __ push(ebx); | 3757 __ push(ebx); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3831 masm->isolate()->builtins()->KeyedLoadIC_Slow(); | 3893 masm->isolate()->builtins()->KeyedLoadIC_Slow(); |
| 3832 __ jmp(slow_ic, RelocInfo::CODE_TARGET); | 3894 __ jmp(slow_ic, RelocInfo::CODE_TARGET); |
| 3833 | 3895 |
| 3834 __ bind(&miss_force_generic); | 3896 __ bind(&miss_force_generic); |
| 3835 Handle<Code> miss_ic = | 3897 Handle<Code> miss_ic = |
| 3836 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); | 3898 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); |
| 3837 __ jmp(miss_ic, RelocInfo::CODE_TARGET); | 3899 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
| 3838 } | 3900 } |
| 3839 | 3901 |
| 3840 | 3902 |
| 3841 void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, | 3903 void KeyedStoreStubCompiler::GenerateStoreFastElement( |
| 3842 bool is_js_array) { | 3904 MacroAssembler* masm, |
| 3905 bool is_js_array, |
| 3906 ElementsKind elements_kind) { |
| 3843 // ----------- S t a t e ------------- | 3907 // ----------- S t a t e ------------- |
| 3844 // -- eax : value | 3908 // -- eax : value |
| 3845 // -- ecx : key | 3909 // -- ecx : key |
| 3846 // -- edx : receiver | 3910 // -- edx : receiver |
| 3847 // -- esp[0] : return address | 3911 // -- esp[0] : return address |
| 3848 // ----------------------------------- | 3912 // ----------------------------------- |
| 3849 Label miss_force_generic; | 3913 Label miss_force_generic; |
| 3850 | 3914 |
| 3851 // This stub is meant to be tail-jumped to, the receiver must already | 3915 // This stub is meant to be tail-jumped to, the receiver must already |
| 3852 // have been verified by the caller to not be a smi. | 3916 // have been verified by the caller to not be a smi. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3863 if (is_js_array) { | 3927 if (is_js_array) { |
| 3864 // Check that the key is within bounds. | 3928 // Check that the key is within bounds. |
| 3865 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. | 3929 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. |
| 3866 __ j(above_equal, &miss_force_generic); | 3930 __ j(above_equal, &miss_force_generic); |
| 3867 } else { | 3931 } else { |
| 3868 // Check that the key is within bounds. | 3932 // Check that the key is within bounds. |
| 3869 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. | 3933 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. |
| 3870 __ j(above_equal, &miss_force_generic); | 3934 __ j(above_equal, &miss_force_generic); |
| 3871 } | 3935 } |
| 3872 | 3936 |
| 3873 // Do the store and update the write barrier. Make sure to preserve | 3937 if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
| 3874 // the value in register eax. | 3938 __ JumpIfNotSmi(eax, &miss_force_generic); |
| 3875 __ mov(edx, Operand(eax)); | 3939 // ecx is a smi, use times_half_pointer_size instead of |
| 3876 __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax); | 3940 // times_pointer_size |
| 3877 __ RecordWrite(edi, 0, edx, ecx); | 3941 __ mov(FieldOperand(edi, |
| 3942 ecx, |
| 3943 times_half_pointer_size, |
| 3944 FixedArray::kHeaderSize), eax); |
| 3945 } else { |
| 3946 ASSERT(elements_kind == FAST_ELEMENTS); |
| 3947 // Do the store and update the write barrier. |
| 3948 // ecx is a smi, use times_half_pointer_size instead of |
| 3949 // times_pointer_size |
| 3950 __ lea(ecx, FieldOperand(edi, |
| 3951 ecx, |
| 3952 times_half_pointer_size, |
| 3953 FixedArray::kHeaderSize)); |
| 3954 __ mov(Operand(ecx, 0), eax); |
| 3955 // Make sure to preserve the value in register eax. |
| 3956 __ mov(edx, eax); |
| 3957 __ RecordWrite(edi, ecx, edx, kDontSaveFPRegs); |
| 3958 } |
| 3878 | 3959 |
| 3879 // Done. | 3960 // Done. |
| 3880 __ ret(0); | 3961 __ ret(0); |
| 3881 | 3962 |
| 3882 // Handle store cache miss, replacing the ic with the generic stub. | 3963 // Handle store cache miss, replacing the ic with the generic stub. |
| 3883 __ bind(&miss_force_generic); | 3964 __ bind(&miss_force_generic); |
| 3884 Handle<Code> ic_force_generic = | 3965 Handle<Code> ic_force_generic = |
| 3885 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); | 3966 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
| 3886 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); | 3967 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); |
| 3887 } | 3968 } |
| 3888 | 3969 |
| 3889 | 3970 |
| 3890 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( | 3971 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( |
| 3891 MacroAssembler* masm, | 3972 MacroAssembler* masm, |
| 3892 bool is_js_array) { | 3973 bool is_js_array) { |
| 3893 // ----------- S t a t e ------------- | 3974 // ----------- S t a t e ------------- |
| 3894 // -- eax : value | 3975 // -- eax : value |
| 3895 // -- ecx : key | 3976 // -- ecx : key |
| 3896 // -- edx : receiver | 3977 // -- edx : receiver |
| 3897 // -- esp[0] : return address | 3978 // -- esp[0] : return address |
| 3898 // ----------------------------------- | 3979 // ----------------------------------- |
| 3899 Label miss_force_generic, smi_value, is_nan, maybe_nan; | 3980 Label miss_force_generic; |
| 3900 Label have_double_value, not_nan; | |
| 3901 | 3981 |
| 3902 // This stub is meant to be tail-jumped to, the receiver must already | 3982 // This stub is meant to be tail-jumped to, the receiver must already |
| 3903 // have been verified by the caller to not be a smi. | 3983 // have been verified by the caller to not be a smi. |
| 3904 | 3984 |
| 3905 // Check that the key is a smi. | 3985 // Check that the key is a smi. |
| 3906 __ JumpIfNotSmi(ecx, &miss_force_generic); | 3986 __ JumpIfNotSmi(ecx, &miss_force_generic); |
| 3907 | 3987 |
| 3908 // Get the elements array. | 3988 // Get the elements array. |
| 3909 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 3989 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3910 __ AssertFastElements(edi); | 3990 __ AssertFastElements(edi); |
| 3911 | 3991 |
| 3912 if (is_js_array) { | 3992 if (is_js_array) { |
| 3913 // Check that the key is within bounds. | 3993 // Check that the key is within bounds. |
| 3914 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. | 3994 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. |
| 3915 } else { | 3995 } else { |
| 3916 // Check that the key is within bounds. | 3996 // Check that the key is within bounds. |
| 3917 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. | 3997 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. |
| 3918 } | 3998 } |
| 3919 __ j(above_equal, &miss_force_generic); | 3999 __ j(above_equal, &miss_force_generic); |
| 3920 | 4000 |
| 3921 __ JumpIfSmi(eax, &smi_value, Label::kNear); | 4001 __ StoreNumberToDoubleElements(eax, |
| 3922 | 4002 edi, |
| 3923 __ CheckMap(eax, | 4003 ecx, |
| 3924 masm->isolate()->factory()->heap_number_map(), | 4004 edx, |
| 3925 &miss_force_generic, | 4005 xmm0, |
| 3926 DONT_DO_SMI_CHECK); | 4006 &miss_force_generic, |
| 3927 | 4007 true); |
| 3928 // Double value, canonicalize NaN. | |
| 3929 uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); | |
| 3930 __ cmp(FieldOperand(eax, offset), Immediate(kNaNOrInfinityLowerBoundUpper32)); | |
| 3931 __ j(greater_equal, &maybe_nan, Label::kNear); | |
| 3932 | |
| 3933 __ bind(¬_nan); | |
| 3934 ExternalReference canonical_nan_reference = | |
| 3935 ExternalReference::address_of_canonical_non_hole_nan(); | |
| 3936 if (CpuFeatures::IsSupported(SSE2)) { | |
| 3937 CpuFeatures::Scope use_sse2(SSE2); | |
| 3938 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 3939 __ bind(&have_double_value); | |
| 3940 __ movdbl(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize), | |
| 3941 xmm0); | |
| 3942 __ ret(0); | |
| 3943 } else { | |
| 3944 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 3945 __ bind(&have_double_value); | |
| 3946 __ fstp_d(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize)); | |
| 3947 __ ret(0); | |
| 3948 } | |
| 3949 | |
| 3950 __ bind(&maybe_nan); | |
| 3951 // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise | |
| 3952 // it's an Infinity, and the non-NaN code path applies. | |
| 3953 __ j(greater, &is_nan, Label::kNear); | |
| 3954 __ cmp(FieldOperand(eax, HeapNumber::kValueOffset), Immediate(0)); | |
| 3955 __ j(zero, ¬_nan); | |
| 3956 __ bind(&is_nan); | |
| 3957 if (CpuFeatures::IsSupported(SSE2)) { | |
| 3958 CpuFeatures::Scope use_sse2(SSE2); | |
| 3959 __ movdbl(xmm0, Operand::StaticVariable(canonical_nan_reference)); | |
| 3960 } else { | |
| 3961 __ fld_d(Operand::StaticVariable(canonical_nan_reference)); | |
| 3962 } | |
| 3963 __ jmp(&have_double_value, Label::kNear); | |
| 3964 | |
| 3965 __ bind(&smi_value); | |
| 3966 // Value is a smi. convert to a double and store. | |
| 3967 // Preserve original value. | |
| 3968 __ mov(edx, eax); | |
| 3969 __ SmiUntag(edx); | |
| 3970 __ push(edx); | |
| 3971 __ fild_s(Operand(esp, 0)); | |
| 3972 __ pop(edx); | |
| 3973 __ fstp_d(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize)); | |
| 3974 __ ret(0); | 4008 __ ret(0); |
| 3975 | 4009 |
| 3976 // Handle store cache miss, replacing the ic with the generic stub. | 4010 // Handle store cache miss, replacing the ic with the generic stub. |
| 3977 __ bind(&miss_force_generic); | 4011 __ bind(&miss_force_generic); |
| 3978 Handle<Code> ic_force_generic = | 4012 Handle<Code> ic_force_generic = |
| 3979 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); | 4013 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
| 3980 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); | 4014 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); |
| 3981 } | 4015 } |
| 3982 | 4016 |
| 3983 | 4017 |
| 3984 #undef __ | 4018 #undef __ |
| 3985 | 4019 |
| 3986 } } // namespace v8::internal | 4020 } } // namespace v8::internal |
| 3987 | 4021 |
| 3988 #endif // V8_TARGET_ARCH_IA32 | 4022 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |