| 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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 // Scratch registers: | 73 // Scratch registers: |
| 74 // scratch0: used to holds the receiver map. | 74 // scratch0: used to holds the receiver map. |
| 75 // scratch1: used to holds the receiver instance type, receiver bit mask | 75 // scratch1: used to holds the receiver instance type, receiver bit mask |
| 76 // and elements map. | 76 // and elements map. |
| 77 | 77 |
| 78 // Check that the receiver isn't a smi. | 78 // Check that the receiver isn't a smi. |
| 79 __ JumpIfSmi(receiver, miss); | 79 __ JumpIfSmi(receiver, miss); |
| 80 | 80 |
| 81 // Check that the receiver is a valid JS object. | 81 // Check that the receiver is a valid JS object. |
| 82 __ GetObjectType(receiver, scratch0, scratch1); | 82 __ GetObjectType(receiver, scratch0, scratch1); |
| 83 __ Branch(miss, lt, scratch1, Operand(FIRST_JS_OBJECT_TYPE)); | 83 __ Branch(miss, lt, scratch1, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 84 | 84 |
| 85 // If this assert fails, we have to check upper bound too. | 85 // If this assert fails, we have to check upper bound too. |
| 86 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 86 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); |
| 87 | 87 |
| 88 GenerateGlobalInstanceTypeCheck(masm, scratch1, miss); | 88 GenerateGlobalInstanceTypeCheck(masm, scratch1, miss); |
| 89 | 89 |
| 90 // Check that the global object does not require access checks. | 90 // Check that the global object does not require access checks. |
| 91 __ lbu(scratch1, FieldMemOperand(scratch0, Map::kBitFieldOffset)); | 91 __ lbu(scratch1, FieldMemOperand(scratch0, Map::kBitFieldOffset)); |
| 92 __ And(scratch1, scratch1, Operand((1 << Map::kIsAccessCheckNeeded) | | 92 __ And(scratch1, scratch1, Operand((1 << Map::kIsAccessCheckNeeded) | |
| 93 (1 << Map::kHasNamedInterceptor))); | 93 (1 << Map::kHasNamedInterceptor))); |
| 94 __ Branch(miss, ne, scratch1, Operand(zero_reg)); | 94 __ Branch(miss, ne, scratch1, Operand(zero_reg)); |
| 95 | 95 |
| 96 __ lw(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 96 __ lw(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 const int kValueOffset = kElementsStartOffset + kPointerSize; | 207 const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 208 __ Addu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag)); | 208 __ Addu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag)); |
| 209 __ sw(value, MemOperand(scratch2)); | 209 __ sw(value, MemOperand(scratch2)); |
| 210 | 210 |
| 211 // Update the write barrier. Make sure not to clobber the value. | 211 // Update the write barrier. Make sure not to clobber the value. |
| 212 __ mov(scratch1, value); | 212 __ mov(scratch1, value); |
| 213 __ RecordWrite(elements, scratch2, scratch1); | 213 __ RecordWrite(elements, scratch2, scratch1); |
| 214 } | 214 } |
| 215 | 215 |
| 216 | 216 |
| 217 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | |
| 218 Label* miss, | |
| 219 Register elements, | |
| 220 Register key, | |
| 221 Register result, | |
| 222 Register reg0, | |
| 223 Register reg1, | |
| 224 Register reg2) { | |
| 225 // Register use: | |
| 226 // | |
| 227 // elements - holds the slow-case elements of the receiver on entry. | |
| 228 // Unchanged unless 'result' is the same register. | |
| 229 // | |
| 230 // key - holds the smi key on entry. | |
| 231 // Unchanged unless 'result' is the same register. | |
| 232 // | |
| 233 // | |
| 234 // result - holds the result on exit if the load succeeded. | |
| 235 // Allowed to be the same as 'key' or 'result'. | |
| 236 // Unchanged on bailout so 'key' or 'result' can be used | |
| 237 // in further computation. | |
| 238 // | |
| 239 // Scratch registers: | |
| 240 // | |
| 241 // reg0 - holds the untagged key on entry and holds the hash once computed. | |
| 242 // | |
| 243 // reg1 - Used to hold the capacity mask of the dictionary. | |
| 244 // | |
| 245 // reg2 - Used for the index into the dictionary. | |
| 246 // at - Temporary (avoid MacroAssembler instructions also using 'at'). | |
| 247 Label done; | |
| 248 | |
| 249 // Compute the hash code from the untagged key. This must be kept in sync | |
| 250 // with ComputeIntegerHash in utils.h. | |
| 251 // | |
| 252 // hash = ~hash + (hash << 15); | |
| 253 __ nor(reg1, reg0, zero_reg); | |
| 254 __ sll(at, reg0, 15); | |
| 255 __ addu(reg0, reg1, at); | |
| 256 | |
| 257 // hash = hash ^ (hash >> 12); | |
| 258 __ srl(at, reg0, 12); | |
| 259 __ xor_(reg0, reg0, at); | |
| 260 | |
| 261 // hash = hash + (hash << 2); | |
| 262 __ sll(at, reg0, 2); | |
| 263 __ addu(reg0, reg0, at); | |
| 264 | |
| 265 // hash = hash ^ (hash >> 4); | |
| 266 __ srl(at, reg0, 4); | |
| 267 __ xor_(reg0, reg0, at); | |
| 268 | |
| 269 // hash = hash * 2057; | |
| 270 __ li(reg1, Operand(2057)); | |
| 271 __ mul(reg0, reg0, reg1); | |
| 272 | |
| 273 // hash = hash ^ (hash >> 16); | |
| 274 __ srl(at, reg0, 16); | |
| 275 __ xor_(reg0, reg0, at); | |
| 276 | |
| 277 // Compute the capacity mask. | |
| 278 __ lw(reg1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset)); | |
| 279 __ sra(reg1, reg1, kSmiTagSize); | |
| 280 __ Subu(reg1, reg1, Operand(1)); | |
| 281 | |
| 282 // Generate an unrolled loop that performs a few probes before giving up. | |
| 283 static const int kProbes = 4; | |
| 284 for (int i = 0; i < kProbes; i++) { | |
| 285 // Use reg2 for index calculations and keep the hash intact in reg0. | |
| 286 __ mov(reg2, reg0); | |
| 287 // Compute the masked index: (hash + i + i * i) & mask. | |
| 288 if (i > 0) { | |
| 289 __ Addu(reg2, reg2, Operand(NumberDictionary::GetProbeOffset(i))); | |
| 290 } | |
| 291 __ and_(reg2, reg2, reg1); | |
| 292 | |
| 293 // Scale the index by multiplying by the element size. | |
| 294 ASSERT(NumberDictionary::kEntrySize == 3); | |
| 295 __ sll(at, reg2, 1); // 2x. | |
| 296 __ addu(reg2, reg2, at); // reg2 = reg2 * 3. | |
| 297 | |
| 298 // Check if the key is identical to the name. | |
| 299 __ sll(at, reg2, kPointerSizeLog2); | |
| 300 __ addu(reg2, elements, at); | |
| 301 | |
| 302 __ lw(at, FieldMemOperand(reg2, NumberDictionary::kElementsStartOffset)); | |
| 303 if (i != kProbes - 1) { | |
| 304 __ Branch(&done, eq, key, Operand(at)); | |
| 305 } else { | |
| 306 __ Branch(miss, ne, key, Operand(at)); | |
| 307 } | |
| 308 } | |
| 309 | |
| 310 __ bind(&done); | |
| 311 // Check that the value is a normal property. | |
| 312 // reg2: elements + (index * kPointerSize). | |
| 313 const int kDetailsOffset = | |
| 314 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | |
| 315 __ lw(reg1, FieldMemOperand(reg2, kDetailsOffset)); | |
| 316 __ And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask()))); | |
| 317 __ Branch(miss, ne, at, Operand(zero_reg)); | |
| 318 | |
| 319 // Get the value at the masked, scaled index and return. | |
| 320 const int kValueOffset = | |
| 321 NumberDictionary::kElementsStartOffset + kPointerSize; | |
| 322 __ lw(result, FieldMemOperand(reg2, kValueOffset)); | |
| 323 } | |
| 324 | |
| 325 | |
| 326 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 217 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
| 327 // ----------- S t a t e ------------- | 218 // ----------- S t a t e ------------- |
| 328 // -- a2 : name | 219 // -- a2 : name |
| 329 // -- ra : return address | 220 // -- ra : return address |
| 330 // -- a0 : receiver | 221 // -- a0 : receiver |
| 331 // -- sp[0] : receiver | 222 // -- sp[0] : receiver |
| 332 // ----------------------------------- | 223 // ----------------------------------- |
| 333 Label miss; | 224 Label miss; |
| 334 | 225 |
| 335 StubCompiler::GenerateLoadArrayLength(masm, a0, a3, &miss); | 226 StubCompiler::GenerateLoadArrayLength(masm, a0, a3, &miss); |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 560 | 451 |
| 561 // Check that the value isn't a smi. | 452 // Check that the value isn't a smi. |
| 562 __ JumpIfSmi(a1, miss); | 453 __ JumpIfSmi(a1, miss); |
| 563 | 454 |
| 564 // Check that the value is a JSFunction. | 455 // Check that the value is a JSFunction. |
| 565 __ GetObjectType(a1, scratch, scratch); | 456 __ GetObjectType(a1, scratch, scratch); |
| 566 __ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE)); | 457 __ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE)); |
| 567 | 458 |
| 568 // Invoke the function. | 459 // Invoke the function. |
| 569 ParameterCount actual(argc); | 460 ParameterCount actual(argc); |
| 570 __ InvokeFunction(a1, actual, JUMP_FUNCTION); | 461 __ InvokeFunction(a1, actual, JUMP_FUNCTION, |
| 462 NullCallWrapper(), CALL_AS_METHOD); |
| 571 } | 463 } |
| 572 | 464 |
| 573 | 465 |
| 574 static void GenerateCallNormal(MacroAssembler* masm, int argc) { | 466 static void GenerateCallNormal(MacroAssembler* masm, int argc) { |
| 575 // ----------- S t a t e ------------- | 467 // ----------- S t a t e ------------- |
| 576 // -- a2 : name | 468 // -- a2 : name |
| 577 // -- ra : return address | 469 // -- ra : return address |
| 578 // ----------------------------------- | 470 // ----------------------------------- |
| 579 Label miss; | 471 Label miss; |
| 580 | 472 |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 | 635 |
| 744 __ bind(&check_number_dictionary); | 636 __ bind(&check_number_dictionary); |
| 745 // a2: key | 637 // a2: key |
| 746 // a3: elements map | 638 // a3: elements map |
| 747 // t0: elements pointer | 639 // t0: elements pointer |
| 748 // Check whether the elements is a number dictionary. | 640 // Check whether the elements is a number dictionary. |
| 749 __ LoadRoot(at, Heap::kHashTableMapRootIndex); | 641 __ LoadRoot(at, Heap::kHashTableMapRootIndex); |
| 750 __ Branch(&slow_load, ne, a3, Operand(at)); | 642 __ Branch(&slow_load, ne, a3, Operand(at)); |
| 751 __ sra(a0, a2, kSmiTagSize); | 643 __ sra(a0, a2, kSmiTagSize); |
| 752 // a0: untagged index | 644 // a0: untagged index |
| 753 GenerateNumberDictionaryLoad(masm, &slow_load, t0, a2, a1, a0, a3, t1); | 645 __ LoadFromNumberDictionary(&slow_load, t0, a2, a1, a0, a3, t1); |
| 754 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, a0, a3); | 646 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, a0, a3); |
| 755 __ jmp(&do_call); | 647 __ jmp(&do_call); |
| 756 | 648 |
| 757 __ bind(&slow_load); | 649 __ bind(&slow_load); |
| 758 // This branch is taken when calling KeyedCallIC_Miss is neither required | 650 // This branch is taken when calling KeyedCallIC_Miss is neither required |
| 759 // nor beneficial. | 651 // nor beneficial. |
| 760 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, a0, a3); | 652 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, a0, a3); |
| 761 __ EnterInternalFrame(); | 653 __ EnterInternalFrame(); |
| 762 __ push(a2); // Save the key. | 654 __ push(a2); // Save the key. |
| 763 __ Push(a1, a2); // Pass the receiver and the key. | 655 __ Push(a1, a2); // Pass the receiver and the key. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 885 | 777 |
| 886 __ mov(a3, a0); | 778 __ mov(a3, a0); |
| 887 __ Push(a3, a2); | 779 __ Push(a3, a2); |
| 888 | 780 |
| 889 // Perform tail call to the entry. | 781 // Perform tail call to the entry. |
| 890 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate); | 782 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate); |
| 891 __ TailCallExternalReference(ref, 2, 1); | 783 __ TailCallExternalReference(ref, 2, 1); |
| 892 } | 784 } |
| 893 | 785 |
| 894 | 786 |
| 787 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm, |
| 788 Register object, |
| 789 Register key, |
| 790 Register scratch1, |
| 791 Register scratch2, |
| 792 Register scratch3, |
| 793 Label* unmapped_case, |
| 794 Label* slow_case) { |
| 795 Heap* heap = masm->isolate()->heap(); |
| 796 |
| 797 // Check that the receiver is a JSObject. Because of the map check |
| 798 // later, we do not need to check for interceptors or whether it |
| 799 // requires access checks. |
| 800 __ JumpIfSmi(object, slow_case); |
| 801 // Check that the object is some kind of JSObject. |
| 802 __ GetObjectType(object, scratch1, scratch2); |
| 803 __ Branch(slow_case, lt, scratch2, Operand(FIRST_JS_RECEIVER_TYPE)); |
| 804 |
| 805 // Check that the key is a positive smi. |
| 806 __ And(scratch1, key, Operand(0x8000001)); |
| 807 __ Branch(slow_case, ne, scratch1, Operand(zero_reg)); |
| 808 |
| 809 // Load the elements into scratch1 and check its map. |
| 810 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map()); |
| 811 __ lw(scratch1, FieldMemOperand(object, JSObject::kElementsOffset)); |
| 812 __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK); |
| 813 |
| 814 // Check if element is in the range of mapped arguments. If not, jump |
| 815 // to the unmapped lookup with the parameter map in scratch1. |
| 816 __ lw(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset)); |
| 817 __ Subu(scratch2, scratch2, Operand(Smi::FromInt(2))); |
| 818 __ Branch(unmapped_case, Ugreater_equal, key, Operand(scratch2)); |
| 819 |
| 820 // Load element index and check whether it is the hole. |
| 821 const int kOffset = |
| 822 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag; |
| 823 |
| 824 __ li(scratch3, Operand(kPointerSize >> 1)); |
| 825 __ mul(scratch3, key, scratch3); |
| 826 __ Addu(scratch3, scratch3, Operand(kOffset)); |
| 827 |
| 828 __ Addu(scratch2, scratch1, scratch3); |
| 829 __ lw(scratch2, MemOperand(scratch2)); |
| 830 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex); |
| 831 __ Branch(unmapped_case, eq, scratch2, Operand(scratch3)); |
| 832 |
| 833 // Load value from context and return it. We can reuse scratch1 because |
| 834 // we do not jump to the unmapped lookup (which requires the parameter |
| 835 // map in scratch1). |
| 836 __ lw(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize)); |
| 837 __ li(scratch3, Operand(kPointerSize >> 1)); |
| 838 __ mul(scratch3, scratch2, scratch3); |
| 839 __ Addu(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag)); |
| 840 __ Addu(scratch2, scratch1, scratch3); |
| 841 return MemOperand(scratch2); |
| 842 } |
| 843 |
| 844 |
| 845 static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm, |
| 846 Register key, |
| 847 Register parameter_map, |
| 848 Register scratch, |
| 849 Label* slow_case) { |
| 850 // Element is in arguments backing store, which is referenced by the |
| 851 // second element of the parameter_map. The parameter_map register |
| 852 // must be loaded with the parameter map of the arguments object and is |
| 853 // overwritten. |
| 854 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize; |
| 855 Register backing_store = parameter_map; |
| 856 __ lw(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset)); |
| 857 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map()); |
| 858 __ CheckMap(backing_store, scratch, fixed_array_map, slow_case, |
| 859 DONT_DO_SMI_CHECK); |
| 860 __ lw(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset)); |
| 861 __ Branch(slow_case, Ugreater_equal, key, Operand(scratch)); |
| 862 __ li(scratch, Operand(kPointerSize >> 1)); |
| 863 __ mul(scratch, key, scratch); |
| 864 __ Addu(scratch, |
| 865 scratch, |
| 866 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 867 __ Addu(scratch, backing_store, scratch); |
| 868 return MemOperand(scratch); |
| 869 } |
| 870 |
| 871 |
| 872 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) { |
| 873 // ---------- S t a t e -------------- |
| 874 // -- lr : return address |
| 875 // -- a0 : key |
| 876 // -- a1 : receiver |
| 877 // ----------------------------------- |
| 878 Label slow, notin; |
| 879 MemOperand mapped_location = |
| 880 GenerateMappedArgumentsLookup(masm, a1, a0, a2, a3, t0, ¬in, &slow); |
| 881 __ lw(v0, mapped_location); |
| 882 __ Ret(); |
| 883 __ bind(¬in); |
| 884 // The unmapped lookup expects that the parameter map is in a2. |
| 885 MemOperand unmapped_location = |
| 886 GenerateUnmappedArgumentsLookup(masm, a0, a2, a3, &slow); |
| 887 __ lw(a2, unmapped_location); |
| 888 __ Branch(&slow, eq, a2, Operand(a3)); |
| 889 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex); |
| 890 __ mov(v0, a2); |
| 891 __ Ret(); |
| 892 __ bind(&slow); |
| 893 GenerateMiss(masm, false); |
| 894 } |
| 895 |
| 896 |
| 897 void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) { |
| 898 // ---------- S t a t e -------------- |
| 899 // -- a0 : value |
| 900 // -- a1 : key |
| 901 // -- a2 : receiver |
| 902 // -- lr : return address |
| 903 // ----------------------------------- |
| 904 Label slow, notin; |
| 905 MemOperand mapped_location = |
| 906 GenerateMappedArgumentsLookup(masm, a2, a1, a3, t0, t1, ¬in, &slow); |
| 907 __ sw(a0, mapped_location); |
| 908 // Verify mapped_location MemOperand is register, with no offset. |
| 909 ASSERT_EQ(mapped_location.offset(), 0); |
| 910 __ RecordWrite(a3, mapped_location.rm(), t5); |
| 911 __ Ret(USE_DELAY_SLOT); |
| 912 __ mov(v0, a0); // (In delay slot) return the value stored in v0. |
| 913 __ bind(¬in); |
| 914 // The unmapped lookup expects that the parameter map is in a3. |
| 915 MemOperand unmapped_location = |
| 916 GenerateUnmappedArgumentsLookup(masm, a1, a3, t0, &slow); |
| 917 __ sw(a0, unmapped_location); |
| 918 ASSERT_EQ(unmapped_location.offset(), 0); |
| 919 __ RecordWrite(a3, unmapped_location.rm(), t5); |
| 920 __ Ret(USE_DELAY_SLOT); |
| 921 __ mov(v0, a0); // (In delay slot) return the value stored in v0. |
| 922 __ bind(&slow); |
| 923 GenerateMiss(masm, false); |
| 924 } |
| 925 |
| 926 |
| 927 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm, |
| 928 int argc) { |
| 929 // ----------- S t a t e ------------- |
| 930 // -- a2 : name |
| 931 // -- lr : return address |
| 932 // ----------------------------------- |
| 933 Label slow, notin; |
| 934 // Load receiver. |
| 935 __ lw(a1, MemOperand(sp, argc * kPointerSize)); |
| 936 MemOperand mapped_location = |
| 937 GenerateMappedArgumentsLookup(masm, a1, a2, a3, t0, t1, ¬in, &slow); |
| 938 __ lw(a1, mapped_location); |
| 939 GenerateFunctionTailCall(masm, argc, &slow, a3); |
| 940 __ bind(¬in); |
| 941 // The unmapped lookup expects that the parameter map is in a3. |
| 942 MemOperand unmapped_location = |
| 943 GenerateUnmappedArgumentsLookup(masm, a2, a3, t0, &slow); |
| 944 __ lw(a1, unmapped_location); |
| 945 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex); |
| 946 __ Branch(&slow, eq, a1, Operand(a3)); |
| 947 GenerateFunctionTailCall(masm, argc, &slow, a3); |
| 948 __ bind(&slow); |
| 949 GenerateMiss(masm, argc); |
| 950 } |
| 951 |
| 952 |
| 953 Object* KeyedLoadIC_Miss(Arguments args); |
| 954 |
| 955 |
| 895 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) { | 956 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) { |
| 896 // ---------- S t a t e -------------- | 957 // ---------- S t a t e -------------- |
| 897 // -- ra : return address | 958 // -- ra : return address |
| 898 // -- a0 : key | 959 // -- a0 : key |
| 899 // -- a1 : receiver | 960 // -- a1 : receiver |
| 900 // ----------------------------------- | 961 // ----------------------------------- |
| 901 Isolate* isolate = masm->isolate(); | 962 Isolate* isolate = masm->isolate(); |
| 902 | 963 |
| 903 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0); | 964 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0); |
| 904 | 965 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 942 | 1003 |
| 943 // Check that the key is a smi. | 1004 // Check that the key is a smi. |
| 944 __ JumpIfNotSmi(key, &check_string); | 1005 __ JumpIfNotSmi(key, &check_string); |
| 945 __ bind(&index_smi); | 1006 __ bind(&index_smi); |
| 946 // Now the key is known to be a smi. This place is also jumped to from below | 1007 // Now the key is known to be a smi. This place is also jumped to from below |
| 947 // where a numeric string is converted to a smi. | 1008 // where a numeric string is converted to a smi. |
| 948 | 1009 |
| 949 GenerateKeyedLoadReceiverCheck( | 1010 GenerateKeyedLoadReceiverCheck( |
| 950 masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow); | 1011 masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow); |
| 951 | 1012 |
| 952 // Check the "has fast elements" bit in the receiver's map which is | 1013 // Check the receiver's map to see if it has fast elements. |
| 953 // now in a2. | 1014 __ CheckFastElements(a2, a3, &check_number_dictionary); |
| 954 __ lbu(a3, FieldMemOperand(a2, Map::kBitField2Offset)); | |
| 955 __ And(at, a3, Operand(1 << Map::kHasFastElements)); | |
| 956 __ Branch(&check_number_dictionary, eq, at, Operand(zero_reg)); | |
| 957 | 1015 |
| 958 GenerateFastArrayLoad( | 1016 GenerateFastArrayLoad( |
| 959 masm, receiver, key, t0, a3, a2, v0, NULL, &slow); | 1017 masm, receiver, key, t0, a3, a2, v0, NULL, &slow); |
| 960 | 1018 |
| 961 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a2, a3); | 1019 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a2, a3); |
| 962 __ Ret(); | 1020 __ Ret(); |
| 963 | 1021 |
| 964 __ bind(&check_number_dictionary); | 1022 __ bind(&check_number_dictionary); |
| 965 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 1023 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 966 __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset)); | 1024 __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset)); |
| 967 | 1025 |
| 968 // Check whether the elements is a number dictionary. | 1026 // Check whether the elements is a number dictionary. |
| 969 // a0: key | 1027 // a0: key |
| 970 // a3: elements map | 1028 // a3: elements map |
| 971 // t0: elements | 1029 // t0: elements |
| 972 __ LoadRoot(at, Heap::kHashTableMapRootIndex); | 1030 __ LoadRoot(at, Heap::kHashTableMapRootIndex); |
| 973 __ Branch(&slow, ne, a3, Operand(at)); | 1031 __ Branch(&slow, ne, a3, Operand(at)); |
| 974 __ sra(a2, a0, kSmiTagSize); | 1032 __ sra(a2, a0, kSmiTagSize); |
| 975 GenerateNumberDictionaryLoad(masm, &slow, t0, a0, v0, a2, a3, t1); | 1033 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1); |
| 976 __ Ret(); | 1034 __ Ret(); |
| 977 | 1035 |
| 978 // Slow case, key and receiver still in a0 and a1. | 1036 // Slow case, key and receiver still in a0 and a1. |
| 979 __ bind(&slow); | 1037 __ bind(&slow); |
| 980 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), | 1038 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), |
| 981 1, | 1039 1, |
| 982 a2, | 1040 a2, |
| 983 a3); | 1041 a3); |
| 984 GenerateRuntimeGetProperty(masm); | 1042 GenerateRuntimeGetProperty(masm); |
| 985 | 1043 |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1166 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 1224 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 1167 // Check that the receiver does not require access checks. We need | 1225 // Check that the receiver does not require access checks. We need |
| 1168 // to do this because this generic stub does not perform map checks. | 1226 // to do this because this generic stub does not perform map checks. |
| 1169 __ lbu(t0, FieldMemOperand(t3, Map::kBitFieldOffset)); | 1227 __ lbu(t0, FieldMemOperand(t3, Map::kBitFieldOffset)); |
| 1170 __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded)); | 1228 __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded)); |
| 1171 __ Branch(&slow, ne, t0, Operand(zero_reg)); | 1229 __ Branch(&slow, ne, t0, Operand(zero_reg)); |
| 1172 // Check if the object is a JS array or not. | 1230 // Check if the object is a JS array or not. |
| 1173 __ lbu(t3, FieldMemOperand(t3, Map::kInstanceTypeOffset)); | 1231 __ lbu(t3, FieldMemOperand(t3, Map::kInstanceTypeOffset)); |
| 1174 | 1232 |
| 1175 __ Branch(&array, eq, t3, Operand(JS_ARRAY_TYPE)); | 1233 __ Branch(&array, eq, t3, Operand(JS_ARRAY_TYPE)); |
| 1176 // Check that the object is some kind of JS object. | 1234 // Check that the object is some kind of JSObject. |
| 1177 __ Branch(&slow, lt, t3, Operand(FIRST_JS_OBJECT_TYPE)); | 1235 __ Branch(&slow, lt, t3, Operand(FIRST_JS_RECEIVER_TYPE)); |
| 1236 __ Branch(&slow, eq, t3, Operand(JS_PROXY_TYPE)); |
| 1237 __ Branch(&slow, eq, t3, Operand(JS_FUNCTION_PROXY_TYPE)); |
| 1178 | 1238 |
| 1179 // Object case: Check key against length in the elements array. | 1239 // Object case: Check key against length in the elements array. |
| 1180 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 1240 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 1181 // Check that the object is in fast mode and writable. | 1241 // Check that the object is in fast mode and writable. |
| 1182 __ lw(t3, FieldMemOperand(elements, HeapObject::kMapOffset)); | 1242 __ lw(t3, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| 1183 __ LoadRoot(t0, Heap::kFixedArrayMapRootIndex); | 1243 __ LoadRoot(t0, Heap::kFixedArrayMapRootIndex); |
| 1184 __ Branch(&slow, ne, t3, Operand(t0)); | 1244 __ Branch(&slow, ne, t3, Operand(t0)); |
| 1185 // Check array bounds. Both the key and the length of FixedArray are smis. | 1245 // Check array bounds. Both the key and the length of FixedArray are smis. |
| 1186 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); | 1246 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
| 1187 __ Branch(&fast, lo, key, Operand(t0)); | 1247 __ Branch(&fast, lo, key, Operand(t0)); |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1571 Register reg = Register::from_code(Assembler::GetRs(instr_at_patch)); | 1631 Register reg = Register::from_code(Assembler::GetRs(instr_at_patch)); |
| 1572 patcher.masm()->andi(at, reg, kSmiTagMask); | 1632 patcher.masm()->andi(at, reg, kSmiTagMask); |
| 1573 patcher.ChangeBranchCondition(eq); | 1633 patcher.ChangeBranchCondition(eq); |
| 1574 } | 1634 } |
| 1575 } | 1635 } |
| 1576 | 1636 |
| 1577 | 1637 |
| 1578 } } // namespace v8::internal | 1638 } } // namespace v8::internal |
| 1579 | 1639 |
| 1580 #endif // V8_TARGET_ARCH_MIPS | 1640 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |