| 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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 | 43 |
| 44 #define __ ACCESS_MASM(masm) | 44 #define __ ACCESS_MASM(masm) |
| 45 | 45 |
| 46 | 46 |
| 47 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, | 47 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, |
| 48 Register type, | 48 Register type, |
| 49 Label* global_object) { | 49 Label* global_object) { |
| 50 // Register usage: | 50 // Register usage: |
| 51 // type: holds the receiver instance type on entry. | 51 // type: holds the receiver instance type on entry. |
| 52 __ cmp(type, JS_GLOBAL_OBJECT_TYPE); | 52 __ cmp(type, JS_GLOBAL_OBJECT_TYPE); |
| 53 __ j(equal, global_object, not_taken); | 53 __ j(equal, global_object); |
| 54 __ cmp(type, JS_BUILTINS_OBJECT_TYPE); | 54 __ cmp(type, JS_BUILTINS_OBJECT_TYPE); |
| 55 __ j(equal, global_object, not_taken); | 55 __ j(equal, global_object); |
| 56 __ cmp(type, JS_GLOBAL_PROXY_TYPE); | 56 __ cmp(type, JS_GLOBAL_PROXY_TYPE); |
| 57 __ j(equal, global_object, not_taken); | 57 __ j(equal, global_object); |
| 58 } | 58 } |
| 59 | 59 |
| 60 | 60 |
| 61 // Generated code falls through if the receiver is a regular non-global | 61 // Generated code falls through if the receiver is a regular non-global |
| 62 // JS object with slow properties and no interceptors. | 62 // JS object with slow properties and no interceptors. |
| 63 static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm, | 63 static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm, |
| 64 Register receiver, | 64 Register receiver, |
| 65 Register r0, | 65 Register r0, |
| 66 Register r1, | 66 Register r1, |
| 67 Label* miss) { | 67 Label* miss) { |
| 68 // Register usage: | 68 // Register usage: |
| 69 // receiver: holds the receiver on entry and is unchanged. | 69 // receiver: holds the receiver on entry and is unchanged. |
| 70 // r0: used to hold receiver instance type. | 70 // r0: used to hold receiver instance type. |
| 71 // Holds the property dictionary on fall through. | 71 // Holds the property dictionary on fall through. |
| 72 // r1: used to hold receivers map. | 72 // r1: used to hold receivers map. |
| 73 | 73 |
| 74 // Check that the receiver isn't a smi. | 74 // Check that the receiver isn't a smi. |
| 75 __ test(receiver, Immediate(kSmiTagMask)); | 75 __ test(receiver, Immediate(kSmiTagMask)); |
| 76 __ j(zero, miss, not_taken); | 76 __ j(zero, miss); |
| 77 | 77 |
| 78 // Check that the receiver is a valid JS object. | 78 // Check that the receiver is a valid JS object. |
| 79 __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset)); | 79 __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 80 __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset)); | 80 __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset)); |
| 81 __ cmp(r0, FIRST_JS_OBJECT_TYPE); | 81 __ cmp(r0, FIRST_JS_OBJECT_TYPE); |
| 82 __ j(below, miss, not_taken); | 82 __ j(below, miss); |
| 83 | 83 |
| 84 // If this assert fails, we have to check upper bound too. | 84 // If this assert fails, we have to check upper bound too. |
| 85 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 85 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| 86 | 86 |
| 87 GenerateGlobalInstanceTypeCheck(masm, r0, miss); | 87 GenerateGlobalInstanceTypeCheck(masm, r0, miss); |
| 88 | 88 |
| 89 // Check for non-global object that requires access check. | 89 // Check for non-global object that requires access check. |
| 90 __ test_b(FieldOperand(r1, Map::kBitFieldOffset), | 90 __ test_b(FieldOperand(r1, Map::kBitFieldOffset), |
| 91 (1 << Map::kIsAccessCheckNeeded) | | 91 (1 << Map::kIsAccessCheckNeeded) | |
| 92 (1 << Map::kHasNamedInterceptor)); | 92 (1 << Map::kHasNamedInterceptor)); |
| 93 __ j(not_zero, miss, not_taken); | 93 __ j(not_zero, miss); |
| 94 | 94 |
| 95 __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); | 95 __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
| 96 __ CheckMap(r0, FACTORY->hash_table_map(), miss, true); | 96 __ CheckMap(r0, FACTORY->hash_table_map(), miss, DONT_DO_SMI_CHECK); |
| 97 } | 97 } |
| 98 | 98 |
| 99 | 99 |
| 100 // Probe the string dictionary in the |elements| register. Jump to the | |
| 101 // |done| label if a property with the given name is found leaving the | |
| 102 // index into the dictionary in |r0|. Jump to the |miss| label | |
| 103 // otherwise. | |
| 104 static void GenerateStringDictionaryProbes(MacroAssembler* masm, | |
| 105 Label* miss, | |
| 106 Label* done, | |
| 107 Register elements, | |
| 108 Register name, | |
| 109 Register r0, | |
| 110 Register r1) { | |
| 111 // Assert that name contains a string. | |
| 112 if (FLAG_debug_code) __ AbortIfNotString(name); | |
| 113 | |
| 114 // Compute the capacity mask. | |
| 115 const int kCapacityOffset = | |
| 116 StringDictionary::kHeaderSize + | |
| 117 StringDictionary::kCapacityIndex * kPointerSize; | |
| 118 __ mov(r1, FieldOperand(elements, kCapacityOffset)); | |
| 119 __ shr(r1, kSmiTagSize); // convert smi to int | |
| 120 __ dec(r1); | |
| 121 | |
| 122 // Generate an unrolled loop that performs a few probes before | |
| 123 // giving up. Measurements done on Gmail indicate that 2 probes | |
| 124 // cover ~93% of loads from dictionaries. | |
| 125 static const int kProbes = 4; | |
| 126 const int kElementsStartOffset = | |
| 127 StringDictionary::kHeaderSize + | |
| 128 StringDictionary::kElementsStartIndex * kPointerSize; | |
| 129 for (int i = 0; i < kProbes; i++) { | |
| 130 // Compute the masked index: (hash + i + i * i) & mask. | |
| 131 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); | |
| 132 __ shr(r0, String::kHashShift); | |
| 133 if (i > 0) { | |
| 134 __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i))); | |
| 135 } | |
| 136 __ and_(r0, Operand(r1)); | |
| 137 | |
| 138 // Scale the index by multiplying by the entry size. | |
| 139 ASSERT(StringDictionary::kEntrySize == 3); | |
| 140 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 | |
| 141 | |
| 142 // Check if the key is identical to the name. | |
| 143 __ cmp(name, Operand(elements, r0, times_4, | |
| 144 kElementsStartOffset - kHeapObjectTag)); | |
| 145 if (i != kProbes - 1) { | |
| 146 __ j(equal, done, taken); | |
| 147 } else { | |
| 148 __ j(not_equal, miss, not_taken); | |
| 149 } | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 | |
| 154 | |
| 155 // Helper function used to load a property from a dictionary backing | 100 // Helper function used to load a property from a dictionary backing |
| 156 // storage. This function may fail to load a property even though it is | 101 // storage. This function may fail to load a property even though it is |
| 157 // in the dictionary, so code at miss_label must always call a backup | 102 // in the dictionary, so code at miss_label must always call a backup |
| 158 // property load that is complete. This function is safe to call if | 103 // property load that is complete. This function is safe to call if |
| 159 // name is not a symbol, and will jump to the miss_label in that | 104 // name is not a symbol, and will jump to the miss_label in that |
| 160 // case. The generated code assumes that the receiver has slow | 105 // case. The generated code assumes that the receiver has slow |
| 161 // properties, is not a global object and does not have interceptors. | 106 // properties, is not a global object and does not have interceptors. |
| 162 static void GenerateDictionaryLoad(MacroAssembler* masm, | 107 static void GenerateDictionaryLoad(MacroAssembler* masm, |
| 163 Label* miss_label, | 108 Label* miss_label, |
| 164 Register elements, | 109 Register elements, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 176 // | 121 // |
| 177 // r0 - used for the index into the property dictionary | 122 // r0 - used for the index into the property dictionary |
| 178 // | 123 // |
| 179 // r1 - used to hold the capacity of the property dictionary. | 124 // r1 - used to hold the capacity of the property dictionary. |
| 180 // | 125 // |
| 181 // result - holds the result on exit. | 126 // result - holds the result on exit. |
| 182 | 127 |
| 183 Label done; | 128 Label done; |
| 184 | 129 |
| 185 // Probe the dictionary. | 130 // Probe the dictionary. |
| 186 GenerateStringDictionaryProbes(masm, | 131 StringDictionaryLookupStub::GeneratePositiveLookup(masm, |
| 187 miss_label, | 132 miss_label, |
| 188 &done, | 133 &done, |
| 189 elements, | 134 elements, |
| 190 name, | 135 name, |
| 191 r0, | 136 r0, |
| 192 r1); | 137 r1); |
| 193 | 138 |
| 194 // If probing finds an entry in the dictionary, r0 contains the | 139 // If probing finds an entry in the dictionary, r0 contains the |
| 195 // index into the dictionary. Check that the value is a normal | 140 // index into the dictionary. Check that the value is a normal |
| 196 // property. | 141 // property. |
| 197 __ bind(&done); | 142 __ bind(&done); |
| 198 const int kElementsStartOffset = | 143 const int kElementsStartOffset = |
| 199 StringDictionary::kHeaderSize + | 144 StringDictionary::kHeaderSize + |
| 200 StringDictionary::kElementsStartIndex * kPointerSize; | 145 StringDictionary::kElementsStartIndex * kPointerSize; |
| 201 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 146 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
| 202 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), | 147 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), |
| 203 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 148 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
| 204 __ j(not_zero, miss_label, not_taken); | 149 __ j(not_zero, miss_label); |
| 205 | 150 |
| 206 // Get the value at the masked, scaled index. | 151 // Get the value at the masked, scaled index. |
| 207 const int kValueOffset = kElementsStartOffset + kPointerSize; | 152 const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 208 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); | 153 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); |
| 209 } | 154 } |
| 210 | 155 |
| 211 | 156 |
| 212 // Helper function used to store a property to a dictionary backing | 157 // Helper function used to store a property to a dictionary backing |
| 213 // storage. This function may fail to store a property eventhough it | 158 // storage. This function may fail to store a property eventhough it |
| 214 // is in the dictionary, so code at miss_label must always call a | 159 // is in the dictionary, so code at miss_label must always call a |
| (...skipping 16 matching lines...) Expand all Loading... |
| 231 // | 176 // |
| 232 // value - holds the value to store and is unchanged. | 177 // value - holds the value to store and is unchanged. |
| 233 // | 178 // |
| 234 // r0 - used for index into the property dictionary and is clobbered. | 179 // r0 - used for index into the property dictionary and is clobbered. |
| 235 // | 180 // |
| 236 // r1 - used to hold the capacity of the property dictionary and is clobbered. | 181 // r1 - used to hold the capacity of the property dictionary and is clobbered. |
| 237 Label done; | 182 Label done; |
| 238 | 183 |
| 239 | 184 |
| 240 // Probe the dictionary. | 185 // Probe the dictionary. |
| 241 GenerateStringDictionaryProbes(masm, | 186 StringDictionaryLookupStub::GeneratePositiveLookup(masm, |
| 242 miss_label, | 187 miss_label, |
| 243 &done, | 188 &done, |
| 244 elements, | 189 elements, |
| 245 name, | 190 name, |
| 246 r0, | 191 r0, |
| 247 r1); | 192 r1); |
| 248 | 193 |
| 249 // If probing finds an entry in the dictionary, r0 contains the | 194 // If probing finds an entry in the dictionary, r0 contains the |
| 250 // index into the dictionary. Check that the value is a normal | 195 // index into the dictionary. Check that the value is a normal |
| 251 // property that is not read only. | 196 // property that is not read only. |
| 252 __ bind(&done); | 197 __ bind(&done); |
| 253 const int kElementsStartOffset = | 198 const int kElementsStartOffset = |
| 254 StringDictionary::kHeaderSize + | 199 StringDictionary::kHeaderSize + |
| 255 StringDictionary::kElementsStartIndex * kPointerSize; | 200 StringDictionary::kElementsStartIndex * kPointerSize; |
| 256 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 201 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
| 257 const int kTypeAndReadOnlyMask | 202 const int kTypeAndReadOnlyMask |
| 258 = (PropertyDetails::TypeField::mask() | | 203 = (PropertyDetails::TypeField::mask() | |
| 259 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; | 204 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; |
| 260 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), | 205 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), |
| 261 Immediate(kTypeAndReadOnlyMask)); | 206 Immediate(kTypeAndReadOnlyMask)); |
| 262 __ j(not_zero, miss_label, not_taken); | 207 __ j(not_zero, miss_label); |
| 263 | 208 |
| 264 // Store the value at the masked, scaled index. | 209 // Store the value at the masked, scaled index. |
| 265 const int kValueOffset = kElementsStartOffset + kPointerSize; | 210 const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 266 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); | 211 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); |
| 267 __ mov(Operand(r0, 0), value); | 212 __ mov(Operand(r0, 0), value); |
| 268 | 213 |
| 269 // Update write barrier. Make sure not to clobber the value. | 214 // Update write barrier. Make sure not to clobber the value. |
| 270 __ mov(r1, value); | 215 __ mov(r1, value); |
| 271 __ RecordWrite(elements, r0, r1, kDontSaveFPRegs); | 216 __ RecordWrite(elements, r0, r1, kDontSaveFPRegs); |
| 272 } | 217 } |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 // Scale the index by multiplying by the entry size. | 287 // Scale the index by multiplying by the entry size. |
| 343 ASSERT(NumberDictionary::kEntrySize == 3); | 288 ASSERT(NumberDictionary::kEntrySize == 3); |
| 344 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 | 289 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 |
| 345 | 290 |
| 346 // Check if the key matches. | 291 // Check if the key matches. |
| 347 __ cmp(key, FieldOperand(elements, | 292 __ cmp(key, FieldOperand(elements, |
| 348 r2, | 293 r2, |
| 349 times_pointer_size, | 294 times_pointer_size, |
| 350 NumberDictionary::kElementsStartOffset)); | 295 NumberDictionary::kElementsStartOffset)); |
| 351 if (i != (kProbes - 1)) { | 296 if (i != (kProbes - 1)) { |
| 352 __ j(equal, &done, taken); | 297 __ j(equal, &done); |
| 353 } else { | 298 } else { |
| 354 __ j(not_equal, miss, not_taken); | 299 __ j(not_equal, miss); |
| 355 } | 300 } |
| 356 } | 301 } |
| 357 | 302 |
| 358 __ bind(&done); | 303 __ bind(&done); |
| 359 // Check that the value is a normal propety. | 304 // Check that the value is a normal propety. |
| 360 const int kDetailsOffset = | 305 const int kDetailsOffset = |
| 361 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | 306 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
| 362 ASSERT_EQ(NORMAL, 0); | 307 ASSERT_EQ(NORMAL, 0); |
| 363 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), | 308 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), |
| 364 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 309 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 Register map, | 367 Register map, |
| 423 int interceptor_bit, | 368 int interceptor_bit, |
| 424 Label* slow) { | 369 Label* slow) { |
| 425 // Register use: | 370 // Register use: |
| 426 // receiver - holds the receiver and is unchanged. | 371 // receiver - holds the receiver and is unchanged. |
| 427 // Scratch registers: | 372 // Scratch registers: |
| 428 // map - used to hold the map of the receiver. | 373 // map - used to hold the map of the receiver. |
| 429 | 374 |
| 430 // Check that the object isn't a smi. | 375 // Check that the object isn't a smi. |
| 431 __ test(receiver, Immediate(kSmiTagMask)); | 376 __ test(receiver, Immediate(kSmiTagMask)); |
| 432 __ j(zero, slow, not_taken); | 377 __ j(zero, slow); |
| 433 | 378 |
| 434 // Get the map of the receiver. | 379 // Get the map of the receiver. |
| 435 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset)); | 380 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 436 | 381 |
| 437 // Check bit field. | 382 // Check bit field. |
| 438 __ test_b(FieldOperand(map, Map::kBitFieldOffset), | 383 __ test_b(FieldOperand(map, Map::kBitFieldOffset), |
| 439 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)); | 384 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)); |
| 440 __ j(not_zero, slow, not_taken); | 385 __ j(not_zero, slow); |
| 441 // Check that the object is some kind of JS object EXCEPT JS Value type. | 386 // Check that the object is some kind of JS object EXCEPT JS Value type. |
| 442 // In the case that the object is a value-wrapper object, | 387 // In the case that the object is a value-wrapper object, |
| 443 // we enter the runtime system to make sure that indexing | 388 // we enter the runtime system to make sure that indexing |
| 444 // into string objects works as intended. | 389 // into string objects works as intended. |
| 445 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 390 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
| 446 | 391 |
| 447 __ CmpInstanceType(map, JS_OBJECT_TYPE); | 392 __ CmpInstanceType(map, JS_OBJECT_TYPE); |
| 448 __ j(below, slow, not_taken); | 393 __ j(below, slow); |
| 449 } | 394 } |
| 450 | 395 |
| 451 | 396 |
| 452 // Loads an indexed element from a fast case array. | 397 // Loads an indexed element from a fast case array. |
| 453 // If not_fast_array is NULL, doesn't perform the elements map check. | 398 // If not_fast_array is NULL, doesn't perform the elements map check. |
| 454 static void GenerateFastArrayLoad(MacroAssembler* masm, | 399 static void GenerateFastArrayLoad(MacroAssembler* masm, |
| 455 Register receiver, | 400 Register receiver, |
| 456 Register key, | 401 Register key, |
| 457 Register scratch, | 402 Register scratch, |
| 458 Register result, | 403 Register result, |
| 459 Label* not_fast_array, | 404 Label* not_fast_array, |
| 460 Label* out_of_range) { | 405 Label* out_of_range) { |
| 461 // Register use: | 406 // Register use: |
| 462 // receiver - holds the receiver and is unchanged. | 407 // receiver - holds the receiver and is unchanged. |
| 463 // key - holds the key and is unchanged (must be a smi). | 408 // key - holds the key and is unchanged (must be a smi). |
| 464 // Scratch registers: | 409 // Scratch registers: |
| 465 // scratch - used to hold elements of the receiver and the loaded value. | 410 // scratch - used to hold elements of the receiver and the loaded value. |
| 466 // result - holds the result on exit if the load succeeds and | 411 // result - holds the result on exit if the load succeeds and |
| 467 // we fall through. | 412 // we fall through. |
| 468 | 413 |
| 469 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset)); | 414 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset)); |
| 470 if (not_fast_array != NULL) { | 415 if (not_fast_array != NULL) { |
| 471 // Check that the object is in fast mode and writable. | 416 // Check that the object is in fast mode and writable. |
| 472 __ CheckMap(scratch, FACTORY->fixed_array_map(), not_fast_array, true); | 417 __ CheckMap(scratch, |
| 418 FACTORY->fixed_array_map(), |
| 419 not_fast_array, |
| 420 DONT_DO_SMI_CHECK); |
| 473 } else { | 421 } else { |
| 474 __ AssertFastElements(scratch); | 422 __ AssertFastElements(scratch); |
| 475 } | 423 } |
| 476 // Check that the key (index) is within bounds. | 424 // Check that the key (index) is within bounds. |
| 477 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset)); | 425 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset)); |
| 478 __ j(above_equal, out_of_range); | 426 __ j(above_equal, out_of_range); |
| 479 // Fast case: Do the load. | 427 // Fast case: Do the load. |
| 480 ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); | 428 ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); |
| 481 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); | 429 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); |
| 482 __ cmp(Operand(scratch), Immediate(FACTORY->the_hole_value())); | 430 __ cmp(Operand(scratch), Immediate(FACTORY->the_hole_value())); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 501 // key - holds the key and is unchanged. Assumed to be non-smi. | 449 // key - holds the key and is unchanged. Assumed to be non-smi. |
| 502 // Scratch registers: | 450 // Scratch registers: |
| 503 // map - used to hold the map of the key. | 451 // map - used to hold the map of the key. |
| 504 // hash - used to hold the hash of the key. | 452 // hash - used to hold the hash of the key. |
| 505 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); | 453 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); |
| 506 __ j(above_equal, not_symbol); | 454 __ j(above_equal, not_symbol); |
| 507 | 455 |
| 508 // Is the string an array index, with cached numeric value? | 456 // Is the string an array index, with cached numeric value? |
| 509 __ mov(hash, FieldOperand(key, String::kHashFieldOffset)); | 457 __ mov(hash, FieldOperand(key, String::kHashFieldOffset)); |
| 510 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask)); | 458 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask)); |
| 511 __ j(zero, index_string, not_taken); | 459 __ j(zero, index_string); |
| 512 | 460 |
| 513 // Is the string a symbol? | 461 // Is the string a symbol? |
| 514 ASSERT(kSymbolTag != 0); | 462 ASSERT(kSymbolTag != 0); |
| 515 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); | 463 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); |
| 516 __ j(zero, not_symbol, not_taken); | 464 __ j(zero, not_symbol); |
| 517 } | 465 } |
| 518 | 466 |
| 519 | 467 |
| 520 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 468 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
| 521 // ----------- S t a t e ------------- | 469 // ----------- S t a t e ------------- |
| 522 // -- eax : key | 470 // -- eax : key |
| 523 // -- edx : receiver | 471 // -- edx : receiver |
| 524 // -- esp[0] : return address | 472 // -- esp[0] : return address |
| 525 // ----------------------------------- | 473 // ----------------------------------- |
| 526 Label slow, check_string, index_smi, index_string, property_array_property; | 474 Label slow, check_string, index_smi, index_string, property_array_property; |
| 527 Label probe_dictionary, check_number_dictionary; | 475 Label probe_dictionary, check_number_dictionary; |
| 528 | 476 |
| 529 // Check that the key is a smi. | 477 // Check that the key is a smi. |
| 530 __ test(eax, Immediate(kSmiTagMask)); | 478 __ test(eax, Immediate(kSmiTagMask)); |
| 531 __ j(not_zero, &check_string, not_taken); | 479 __ j(not_zero, &check_string); |
| 532 __ bind(&index_smi); | 480 __ bind(&index_smi); |
| 533 // Now the key is known to be a smi. This place is also jumped to from | 481 // Now the key is known to be a smi. This place is also jumped to from |
| 534 // where a numeric string is converted to a smi. | 482 // where a numeric string is converted to a smi. |
| 535 | 483 |
| 536 GenerateKeyedLoadReceiverCheck( | 484 GenerateKeyedLoadReceiverCheck( |
| 537 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); | 485 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); |
| 538 | 486 |
| 539 // Check the "has fast elements" bit in the receiver's map which is | 487 // Check the "has fast elements" bit in the receiver's map which is |
| 540 // now in ecx. | 488 // now in ecx. |
| 541 __ test_b(FieldOperand(ecx, Map::kBitField2Offset), | 489 __ test_b(FieldOperand(ecx, Map::kBitField2Offset), |
| 542 1 << Map::kHasFastElements); | 490 1 << Map::kHasFastElements); |
| 543 __ j(zero, &check_number_dictionary, not_taken); | 491 __ j(zero, &check_number_dictionary); |
| 544 | 492 |
| 545 GenerateFastArrayLoad(masm, | 493 GenerateFastArrayLoad(masm, |
| 546 edx, | 494 edx, |
| 547 eax, | 495 eax, |
| 548 ecx, | 496 ecx, |
| 549 eax, | 497 eax, |
| 550 NULL, | 498 NULL, |
| 551 &slow); | 499 &slow); |
| 552 Isolate* isolate = masm->isolate(); | 500 Isolate* isolate = masm->isolate(); |
| 553 Counters* counters = isolate->counters(); | 501 Counters* counters = isolate->counters(); |
| 554 __ IncrementCounter(counters->keyed_load_generic_smi(), 1); | 502 __ IncrementCounter(counters->keyed_load_generic_smi(), 1); |
| 555 __ ret(0); | 503 __ ret(0); |
| 556 | 504 |
| 557 __ bind(&check_number_dictionary); | 505 __ bind(&check_number_dictionary); |
| 558 __ mov(ebx, eax); | 506 __ mov(ebx, eax); |
| 559 __ SmiUntag(ebx); | 507 __ SmiUntag(ebx); |
| 560 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); | 508 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); |
| 561 | 509 |
| 562 // Check whether the elements is a number dictionary. | 510 // Check whether the elements is a number dictionary. |
| 563 // edx: receiver | 511 // edx: receiver |
| 564 // ebx: untagged index | 512 // ebx: untagged index |
| 565 // eax: key | 513 // eax: key |
| 566 // ecx: elements | 514 // ecx: elements |
| 567 __ CheckMap(ecx, isolate->factory()->hash_table_map(), &slow, true); | 515 __ CheckMap(ecx, |
| 516 isolate->factory()->hash_table_map(), |
| 517 &slow, |
| 518 DONT_DO_SMI_CHECK); |
| 568 Label slow_pop_receiver; | 519 Label slow_pop_receiver; |
| 569 // Push receiver on the stack to free up a register for the dictionary | 520 // Push receiver on the stack to free up a register for the dictionary |
| 570 // probing. | 521 // probing. |
| 571 __ push(edx); | 522 __ push(edx); |
| 572 GenerateNumberDictionaryLoad(masm, | 523 GenerateNumberDictionaryLoad(masm, |
| 573 &slow_pop_receiver, | 524 &slow_pop_receiver, |
| 574 ecx, | 525 ecx, |
| 575 eax, | 526 eax, |
| 576 ebx, | 527 ebx, |
| 577 edx, | 528 edx, |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 697 &miss, // When not a number. | 648 &miss, // When not a number. |
| 698 &miss, // When index out of range. | 649 &miss, // When index out of range. |
| 699 STRING_INDEX_IS_ARRAY_INDEX); | 650 STRING_INDEX_IS_ARRAY_INDEX); |
| 700 char_at_generator.GenerateFast(masm); | 651 char_at_generator.GenerateFast(masm); |
| 701 __ ret(0); | 652 __ ret(0); |
| 702 | 653 |
| 703 StubRuntimeCallHelper call_helper; | 654 StubRuntimeCallHelper call_helper; |
| 704 char_at_generator.GenerateSlow(masm, call_helper); | 655 char_at_generator.GenerateSlow(masm, call_helper); |
| 705 | 656 |
| 706 __ bind(&miss); | 657 __ bind(&miss); |
| 707 GenerateMiss(masm); | 658 GenerateMiss(masm, false); |
| 708 } | 659 } |
| 709 | 660 |
| 710 | 661 |
| 711 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { | 662 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { |
| 712 // ----------- S t a t e ------------- | 663 // ----------- S t a t e ------------- |
| 713 // -- eax : key | 664 // -- eax : key |
| 714 // -- edx : receiver | 665 // -- edx : receiver |
| 715 // -- esp[0] : return address | 666 // -- esp[0] : return address |
| 716 // ----------------------------------- | 667 // ----------------------------------- |
| 717 Label slow; | 668 Label slow; |
| 718 | 669 |
| 719 // Check that the receiver isn't a smi. | 670 // Check that the receiver isn't a smi. |
| 720 __ test(edx, Immediate(kSmiTagMask)); | 671 __ test(edx, Immediate(kSmiTagMask)); |
| 721 __ j(zero, &slow, not_taken); | 672 __ j(zero, &slow); |
| 722 | 673 |
| 723 // Check that the key is an array index, that is Uint32. | 674 // Check that the key is an array index, that is Uint32. |
| 724 __ test(eax, Immediate(kSmiTagMask | kSmiSignMask)); | 675 __ test(eax, Immediate(kSmiTagMask | kSmiSignMask)); |
| 725 __ j(not_zero, &slow, not_taken); | 676 __ j(not_zero, &slow); |
| 726 | 677 |
| 727 // Get the map of the receiver. | 678 // Get the map of the receiver. |
| 728 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 679 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 729 | 680 |
| 730 // Check that it has indexed interceptor and access checks | 681 // Check that it has indexed interceptor and access checks |
| 731 // are not enabled for this object. | 682 // are not enabled for this object. |
| 732 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); | 683 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); |
| 733 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask)); | 684 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask)); |
| 734 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor)); | 685 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor)); |
| 735 __ j(not_zero, &slow, not_taken); | 686 __ j(not_zero, &slow); |
| 736 | 687 |
| 737 // Everything is fine, call runtime. | 688 // Everything is fine, call runtime. |
| 738 __ pop(ecx); | 689 __ pop(ecx); |
| 739 __ push(edx); // receiver | 690 __ push(edx); // receiver |
| 740 __ push(eax); // key | 691 __ push(eax); // key |
| 741 __ push(ecx); // return address | 692 __ push(ecx); // return address |
| 742 | 693 |
| 743 // Perform tail call to the entry. | 694 // Perform tail call to the entry. |
| 744 ExternalReference ref = | 695 ExternalReference ref = |
| 745 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), | 696 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), |
| 746 masm->isolate()); | 697 masm->isolate()); |
| 747 __ TailCallExternalReference(ref, 2, 1); | 698 __ TailCallExternalReference(ref, 2, 1); |
| 748 | 699 |
| 749 __ bind(&slow); | 700 __ bind(&slow); |
| 750 GenerateMiss(masm); | 701 GenerateMiss(masm, false); |
| 751 } | 702 } |
| 752 | 703 |
| 753 | 704 |
| 754 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, | 705 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, |
| 755 StrictModeFlag strict_mode) { | 706 StrictModeFlag strict_mode) { |
| 756 // ----------- S t a t e ------------- | 707 // ----------- S t a t e ------------- |
| 757 // -- eax : value | 708 // -- eax : value |
| 758 // -- ecx : key | 709 // -- ecx : key |
| 759 // -- edx : receiver | 710 // -- edx : receiver |
| 760 // -- esp[0] : return address | 711 // -- esp[0] : return address |
| 761 // ----------------------------------- | 712 // ----------------------------------- |
| 762 Label slow, fast, array, extra; | 713 Label slow, fast, array, extra; |
| 763 | 714 |
| 764 // Check that the object isn't a smi. | 715 // Check that the object isn't a smi. |
| 765 __ test(edx, Immediate(kSmiTagMask)); | 716 __ test(edx, Immediate(kSmiTagMask)); |
| 766 __ j(zero, &slow, not_taken); | 717 __ j(zero, &slow); |
| 767 // Get the map from the receiver. | 718 // Get the map from the receiver. |
| 768 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | 719 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
| 769 // Check that the receiver does not require access checks. We need | 720 // Check that the receiver does not require access checks. We need |
| 770 // to do this because this generic stub does not perform map checks. | 721 // to do this because this generic stub does not perform map checks. |
| 771 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), | 722 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), |
| 772 1 << Map::kIsAccessCheckNeeded); | 723 1 << Map::kIsAccessCheckNeeded); |
| 773 __ j(not_zero, &slow, not_taken); | 724 __ j(not_zero, &slow); |
| 774 // Check that the key is a smi. | 725 // Check that the key is a smi. |
| 775 __ test(ecx, Immediate(kSmiTagMask)); | 726 __ test(ecx, Immediate(kSmiTagMask)); |
| 776 __ j(not_zero, &slow, not_taken); | 727 __ j(not_zero, &slow); |
| 777 __ CmpInstanceType(edi, JS_ARRAY_TYPE); | 728 __ CmpInstanceType(edi, JS_ARRAY_TYPE); |
| 778 __ j(equal, &array); | 729 __ j(equal, &array); |
| 779 // Check that the object is some kind of JS object. | 730 // Check that the object is some kind of JS object. |
| 780 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); | 731 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); |
| 781 __ j(below, &slow, not_taken); | 732 __ j(below, &slow); |
| 782 | 733 |
| 783 // Object case: Check key against length in the elements array. | 734 // Object case: Check key against length in the elements array. |
| 784 // eax: value | 735 // eax: value |
| 785 // edx: JSObject | 736 // edx: JSObject |
| 786 // ecx: key (a smi) | 737 // ecx: key (a smi) |
| 787 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 738 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 788 // Check that the object is in fast mode and writable. | 739 // Check that the object is in fast mode and writable. |
| 789 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, true); | 740 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, DONT_DO_SMI_CHECK); |
| 790 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); | 741 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); |
| 791 __ j(below, &fast, taken); | 742 __ j(below, &fast); |
| 792 | 743 |
| 793 // Slow case: call runtime. | 744 // Slow case: call runtime. |
| 794 __ bind(&slow); | 745 __ bind(&slow); |
| 795 GenerateRuntimeSetProperty(masm, strict_mode); | 746 GenerateRuntimeSetProperty(masm, strict_mode); |
| 796 | 747 |
| 797 // Extra capacity case: Check if there is extra capacity to | 748 // Extra capacity case: Check if there is extra capacity to |
| 798 // perform the store and update the length. Used for adding one | 749 // perform the store and update the length. Used for adding one |
| 799 // element to the array by writing to array[array.length]. | 750 // element to the array by writing to array[array.length]. |
| 800 __ bind(&extra); | 751 __ bind(&extra); |
| 801 // eax: value | 752 // eax: value |
| 802 // edx: receiver, a JSArray | 753 // edx: receiver, a JSArray |
| 803 // ecx: key, a smi. | 754 // ecx: key, a smi. |
| 804 // edi: receiver->elements, a FixedArray | 755 // edi: receiver->elements, a FixedArray |
| 805 // flags: compare (ecx, edx.length()) | 756 // flags: compare (ecx, edx.length()) |
| 806 __ j(not_equal, &slow, not_taken); // do not leave holes in the array | 757 // do not leave holes in the array: |
| 758 __ j(not_equal, &slow); |
| 807 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); | 759 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); |
| 808 __ j(above_equal, &slow, not_taken); | 760 __ j(above_equal, &slow); |
| 809 // Add 1 to receiver->length, and go to fast array write. | 761 // Add 1 to receiver->length, and go to fast array write. |
| 810 __ add(FieldOperand(edx, JSArray::kLengthOffset), | 762 __ add(FieldOperand(edx, JSArray::kLengthOffset), |
| 811 Immediate(Smi::FromInt(1))); | 763 Immediate(Smi::FromInt(1))); |
| 812 __ jmp(&fast); | 764 __ jmp(&fast); |
| 813 | 765 |
| 814 // Array case: Get the length and the elements array from the JS | 766 // Array case: Get the length and the elements array from the JS |
| 815 // array. Check that the array is in fast mode (and writable); if it | 767 // array. Check that the array is in fast mode (and writable); if it |
| 816 // is the length is always a smi. | 768 // is the length is always a smi. |
| 817 __ bind(&array); | 769 __ bind(&array); |
| 818 // eax: value | 770 // eax: value |
| 819 // edx: receiver, a JSArray | 771 // edx: receiver, a JSArray |
| 820 // ecx: key, a smi. | 772 // ecx: key, a smi. |
| 821 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 773 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 822 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, true); | 774 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, DONT_DO_SMI_CHECK); |
| 823 | 775 |
| 824 // Check the key against the length in the array, compute the | 776 // Check the key against the length in the array, compute the |
| 825 // address to store into and fall through to fast case. | 777 // address to store into and fall through to fast case. |
| 826 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. | 778 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. |
| 827 __ j(above_equal, &extra, not_taken); | 779 __ j(above_equal, &extra); |
| 828 | 780 |
| 829 // Fast case: Do the store. | 781 // Fast case: Do the store. |
| 830 __ bind(&fast); | 782 __ bind(&fast); |
| 831 // eax: value | 783 // eax: value |
| 832 // ecx: key (a smi) | 784 // ecx: key (a smi) |
| 833 // edx: receiver | 785 // edx: receiver |
| 834 // edi: FixedArray receiver->elements | 786 // edi: FixedArray receiver->elements |
| 835 __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax); | 787 __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax); |
| 836 | 788 |
| 837 // Update write barrier for the elements array address. | 789 // Update write barrier for the elements array address. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 862 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, | 814 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, |
| 863 eax); | 815 eax); |
| 864 | 816 |
| 865 // If the stub cache probing failed, the receiver might be a value. | 817 // If the stub cache probing failed, the receiver might be a value. |
| 866 // For value objects, we use the map of the prototype objects for | 818 // For value objects, we use the map of the prototype objects for |
| 867 // the corresponding JSValue for the cache and that is what we need | 819 // the corresponding JSValue for the cache and that is what we need |
| 868 // to probe. | 820 // to probe. |
| 869 // | 821 // |
| 870 // Check for number. | 822 // Check for number. |
| 871 __ test(edx, Immediate(kSmiTagMask)); | 823 __ test(edx, Immediate(kSmiTagMask)); |
| 872 __ j(zero, &number, not_taken); | 824 __ j(zero, &number); |
| 873 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx); | 825 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx); |
| 874 __ j(not_equal, &non_number, taken); | 826 __ j(not_equal, &non_number); |
| 875 __ bind(&number); | 827 __ bind(&number); |
| 876 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 828 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
| 877 masm, Context::NUMBER_FUNCTION_INDEX, edx); | 829 masm, Context::NUMBER_FUNCTION_INDEX, edx); |
| 878 __ jmp(&probe); | 830 __ jmp(&probe); |
| 879 | 831 |
| 880 // Check for string. | 832 // Check for string. |
| 881 __ bind(&non_number); | 833 __ bind(&non_number); |
| 882 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE); | 834 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE); |
| 883 __ j(above_equal, &non_string, taken); | 835 __ j(above_equal, &non_string); |
| 884 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 836 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
| 885 masm, Context::STRING_FUNCTION_INDEX, edx); | 837 masm, Context::STRING_FUNCTION_INDEX, edx); |
| 886 __ jmp(&probe); | 838 __ jmp(&probe); |
| 887 | 839 |
| 888 // Check for boolean. | 840 // Check for boolean. |
| 889 __ bind(&non_string); | 841 __ bind(&non_string); |
| 890 __ cmp(edx, FACTORY->true_value()); | 842 __ cmp(edx, FACTORY->true_value()); |
| 891 __ j(equal, &boolean, not_taken); | 843 __ j(equal, &boolean); |
| 892 __ cmp(edx, FACTORY->false_value()); | 844 __ cmp(edx, FACTORY->false_value()); |
| 893 __ j(not_equal, &miss, taken); | 845 __ j(not_equal, &miss); |
| 894 __ bind(&boolean); | 846 __ bind(&boolean); |
| 895 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 847 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
| 896 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); | 848 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); |
| 897 | 849 |
| 898 // Probe the stub cache for the value object. | 850 // Probe the stub cache for the value object. |
| 899 __ bind(&probe); | 851 __ bind(&probe); |
| 900 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, | 852 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, |
| 901 no_reg); | 853 no_reg); |
| 902 __ bind(&miss); | 854 __ bind(&miss); |
| 903 } | 855 } |
| 904 | 856 |
| 905 | 857 |
| 906 static void GenerateFunctionTailCall(MacroAssembler* masm, | 858 static void GenerateFunctionTailCall(MacroAssembler* masm, |
| 907 int argc, | 859 int argc, |
| 908 Label* miss) { | 860 Label* miss) { |
| 909 // ----------- S t a t e ------------- | 861 // ----------- S t a t e ------------- |
| 910 // -- ecx : name | 862 // -- ecx : name |
| 911 // -- edi : function | 863 // -- edi : function |
| 912 // -- esp[0] : return address | 864 // -- esp[0] : return address |
| 913 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 865 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 914 // -- ... | 866 // -- ... |
| 915 // -- esp[(argc + 1) * 4] : receiver | 867 // -- esp[(argc + 1) * 4] : receiver |
| 916 // ----------------------------------- | 868 // ----------------------------------- |
| 917 | 869 |
| 918 // Check that the result is not a smi. | 870 // Check that the result is not a smi. |
| 919 __ test(edi, Immediate(kSmiTagMask)); | 871 __ test(edi, Immediate(kSmiTagMask)); |
| 920 __ j(zero, miss, not_taken); | 872 __ j(zero, miss); |
| 921 | 873 |
| 922 // Check that the value is a JavaScript function, fetching its map into eax. | 874 // Check that the value is a JavaScript function, fetching its map into eax. |
| 923 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); | 875 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); |
| 924 __ j(not_equal, miss, not_taken); | 876 __ j(not_equal, miss); |
| 925 | 877 |
| 926 // Invoke the function. | 878 // Invoke the function. |
| 927 ParameterCount actual(argc); | 879 ParameterCount actual(argc); |
| 928 __ InvokeFunction(edi, actual, JUMP_FUNCTION); | 880 __ InvokeFunction(edi, actual, JUMP_FUNCTION); |
| 929 } | 881 } |
| 930 | 882 |
| 931 // The generated code falls through if the call should be handled by runtime. | 883 // The generated code falls through if the call should be handled by runtime. |
| 932 static void GenerateCallNormal(MacroAssembler* masm, int argc) { | 884 static void GenerateCallNormal(MacroAssembler* masm, int argc) { |
| 933 // ----------- S t a t e ------------- | 885 // ----------- S t a t e ------------- |
| 934 // -- ecx : name | 886 // -- ecx : name |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 990 // Move result to edi and exit the internal frame. | 942 // Move result to edi and exit the internal frame. |
| 991 __ mov(edi, eax); | 943 __ mov(edi, eax); |
| 992 __ LeaveInternalFrame(); | 944 __ LeaveInternalFrame(); |
| 993 | 945 |
| 994 // Check if the receiver is a global object of some sort. | 946 // Check if the receiver is a global object of some sort. |
| 995 // This can happen only for regular CallIC but not KeyedCallIC. | 947 // This can happen only for regular CallIC but not KeyedCallIC. |
| 996 if (id == IC::kCallIC_Miss) { | 948 if (id == IC::kCallIC_Miss) { |
| 997 Label invoke, global; | 949 Label invoke, global; |
| 998 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver | 950 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver |
| 999 __ test(edx, Immediate(kSmiTagMask)); | 951 __ test(edx, Immediate(kSmiTagMask)); |
| 1000 __ j(zero, &invoke, not_taken); | 952 __ j(zero, &invoke, Label::kNear); |
| 1001 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 953 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 1002 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 954 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 1003 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); | 955 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); |
| 1004 __ j(equal, &global); | 956 __ j(equal, &global, Label::kNear); |
| 1005 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); | 957 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); |
| 1006 __ j(not_equal, &invoke); | 958 __ j(not_equal, &invoke, Label::kNear); |
| 1007 | 959 |
| 1008 // Patch the receiver on the stack. | 960 // Patch the receiver on the stack. |
| 1009 __ bind(&global); | 961 __ bind(&global); |
| 1010 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 962 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 1011 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 963 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 1012 __ bind(&invoke); | 964 __ bind(&invoke); |
| 1013 } | 965 } |
| 1014 | 966 |
| 1015 // Invoke the function. | 967 // Invoke the function. |
| 1016 ParameterCount actual(argc); | 968 ParameterCount actual(argc); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1072 | 1024 |
| 1073 // Get the receiver of the function from the stack; 1 ~ return address. | 1025 // Get the receiver of the function from the stack; 1 ~ return address. |
| 1074 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1026 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1075 | 1027 |
| 1076 Label do_call, slow_call, slow_load, slow_reload_receiver; | 1028 Label do_call, slow_call, slow_load, slow_reload_receiver; |
| 1077 Label check_number_dictionary, check_string, lookup_monomorphic_cache; | 1029 Label check_number_dictionary, check_string, lookup_monomorphic_cache; |
| 1078 Label index_smi, index_string; | 1030 Label index_smi, index_string; |
| 1079 | 1031 |
| 1080 // Check that the key is a smi. | 1032 // Check that the key is a smi. |
| 1081 __ test(ecx, Immediate(kSmiTagMask)); | 1033 __ test(ecx, Immediate(kSmiTagMask)); |
| 1082 __ j(not_zero, &check_string, not_taken); | 1034 __ j(not_zero, &check_string); |
| 1083 | 1035 |
| 1084 __ bind(&index_smi); | 1036 __ bind(&index_smi); |
| 1085 // Now the key is known to be a smi. This place is also jumped to from | 1037 // Now the key is known to be a smi. This place is also jumped to from |
| 1086 // where a numeric string is converted to a smi. | 1038 // where a numeric string is converted to a smi. |
| 1087 | 1039 |
| 1088 GenerateKeyedLoadReceiverCheck( | 1040 GenerateKeyedLoadReceiverCheck( |
| 1089 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call); | 1041 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call); |
| 1090 | 1042 |
| 1091 GenerateFastArrayLoad( | 1043 GenerateFastArrayLoad( |
| 1092 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); | 1044 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); |
| 1093 Isolate* isolate = masm->isolate(); | 1045 Isolate* isolate = masm->isolate(); |
| 1094 Counters* counters = isolate->counters(); | 1046 Counters* counters = isolate->counters(); |
| 1095 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1); | 1047 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1); |
| 1096 | 1048 |
| 1097 __ bind(&do_call); | 1049 __ bind(&do_call); |
| 1098 // receiver in edx is not used after this point. | 1050 // receiver in edx is not used after this point. |
| 1099 // ecx: key | 1051 // ecx: key |
| 1100 // edi: function | 1052 // edi: function |
| 1101 GenerateFunctionTailCall(masm, argc, &slow_call); | 1053 GenerateFunctionTailCall(masm, argc, &slow_call); |
| 1102 | 1054 |
| 1103 __ bind(&check_number_dictionary); | 1055 __ bind(&check_number_dictionary); |
| 1104 // eax: elements | 1056 // eax: elements |
| 1105 // ecx: smi key | 1057 // ecx: smi key |
| 1106 // Check whether the elements is a number dictionary. | 1058 // Check whether the elements is a number dictionary. |
| 1107 __ CheckMap(eax, isolate->factory()->hash_table_map(), &slow_load, true); | 1059 __ CheckMap(eax, |
| 1060 isolate->factory()->hash_table_map(), |
| 1061 &slow_load, |
| 1062 DONT_DO_SMI_CHECK); |
| 1108 __ mov(ebx, ecx); | 1063 __ mov(ebx, ecx); |
| 1109 __ SmiUntag(ebx); | 1064 __ SmiUntag(ebx); |
| 1110 // ebx: untagged index | 1065 // ebx: untagged index |
| 1111 // Receiver in edx will be clobbered, need to reload it on miss. | 1066 // Receiver in edx will be clobbered, need to reload it on miss. |
| 1112 GenerateNumberDictionaryLoad( | 1067 GenerateNumberDictionaryLoad( |
| 1113 masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi); | 1068 masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi); |
| 1114 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); | 1069 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); |
| 1115 __ jmp(&do_call); | 1070 __ jmp(&do_call); |
| 1116 | 1071 |
| 1117 __ bind(&slow_reload_receiver); | 1072 __ bind(&slow_reload_receiver); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1138 // If the receiver is a regular JS object with slow properties then do | 1093 // If the receiver is a regular JS object with slow properties then do |
| 1139 // a quick inline probe of the receiver's dictionary. | 1094 // a quick inline probe of the receiver's dictionary. |
| 1140 // Otherwise do the monomorphic cache probe. | 1095 // Otherwise do the monomorphic cache probe. |
| 1141 GenerateKeyedLoadReceiverCheck( | 1096 GenerateKeyedLoadReceiverCheck( |
| 1142 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); | 1097 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); |
| 1143 | 1098 |
| 1144 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); | 1099 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); |
| 1145 __ CheckMap(ebx, | 1100 __ CheckMap(ebx, |
| 1146 isolate->factory()->hash_table_map(), | 1101 isolate->factory()->hash_table_map(), |
| 1147 &lookup_monomorphic_cache, | 1102 &lookup_monomorphic_cache, |
| 1148 true); | 1103 DONT_DO_SMI_CHECK); |
| 1149 | 1104 |
| 1150 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi); | 1105 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi); |
| 1151 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1); | 1106 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1); |
| 1152 __ jmp(&do_call); | 1107 __ jmp(&do_call); |
| 1153 | 1108 |
| 1154 __ bind(&lookup_monomorphic_cache); | 1109 __ bind(&lookup_monomorphic_cache); |
| 1155 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1); | 1110 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1); |
| 1156 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); | 1111 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); |
| 1157 // Fall through on miss. | 1112 // Fall through on miss. |
| 1158 | 1113 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1261 __ push(ecx); // name | 1216 __ push(ecx); // name |
| 1262 __ push(ebx); // return address | 1217 __ push(ebx); // return address |
| 1263 | 1218 |
| 1264 // Perform tail call to the entry. | 1219 // Perform tail call to the entry. |
| 1265 ExternalReference ref = | 1220 ExternalReference ref = |
| 1266 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate()); | 1221 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate()); |
| 1267 __ TailCallExternalReference(ref, 2, 1); | 1222 __ TailCallExternalReference(ref, 2, 1); |
| 1268 } | 1223 } |
| 1269 | 1224 |
| 1270 | 1225 |
| 1271 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 1226 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) { |
| 1272 // ----------- S t a t e ------------- | 1227 // ----------- S t a t e ------------- |
| 1273 // -- eax : key | 1228 // -- eax : key |
| 1274 // -- edx : receiver | 1229 // -- edx : receiver |
| 1275 // -- esp[0] : return address | 1230 // -- esp[0] : return address |
| 1276 // ----------------------------------- | 1231 // ----------------------------------- |
| 1277 | 1232 |
| 1278 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1); | 1233 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1); |
| 1279 | 1234 |
| 1280 __ pop(ebx); | 1235 __ pop(ebx); |
| 1281 __ push(edx); // receiver | 1236 __ push(edx); // receiver |
| 1282 __ push(eax); // name | 1237 __ push(eax); // name |
| 1283 __ push(ebx); // return address | 1238 __ push(ebx); // return address |
| 1284 | 1239 |
| 1285 // Perform tail call to the entry. | 1240 // Perform tail call to the entry. |
| 1286 ExternalReference ref = | 1241 ExternalReference ref = force_generic |
| 1287 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); | 1242 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), |
| 1243 masm->isolate()) |
| 1244 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); |
| 1288 __ TailCallExternalReference(ref, 2, 1); | 1245 __ TailCallExternalReference(ref, 2, 1); |
| 1289 } | 1246 } |
| 1290 | 1247 |
| 1291 | 1248 |
| 1292 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 1249 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
| 1293 // ----------- S t a t e ------------- | 1250 // ----------- S t a t e ------------- |
| 1294 // -- eax : key | 1251 // -- eax : key |
| 1295 // -- edx : receiver | 1252 // -- edx : receiver |
| 1296 // -- esp[0] : return address | 1253 // -- esp[0] : return address |
| 1297 // ----------------------------------- | 1254 // ----------------------------------- |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1362 // Value must be a number, but only smis are accepted as the most common case. | 1319 // Value must be a number, but only smis are accepted as the most common case. |
| 1363 | 1320 |
| 1364 Label miss; | 1321 Label miss; |
| 1365 | 1322 |
| 1366 Register receiver = edx; | 1323 Register receiver = edx; |
| 1367 Register value = eax; | 1324 Register value = eax; |
| 1368 Register scratch = ebx; | 1325 Register scratch = ebx; |
| 1369 | 1326 |
| 1370 // Check that the receiver isn't a smi. | 1327 // Check that the receiver isn't a smi. |
| 1371 __ test(receiver, Immediate(kSmiTagMask)); | 1328 __ test(receiver, Immediate(kSmiTagMask)); |
| 1372 __ j(zero, &miss, not_taken); | 1329 __ j(zero, &miss); |
| 1373 | 1330 |
| 1374 // Check that the object is a JS array. | 1331 // Check that the object is a JS array. |
| 1375 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); | 1332 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); |
| 1376 __ j(not_equal, &miss, not_taken); | 1333 __ j(not_equal, &miss); |
| 1377 | 1334 |
| 1378 // Check that elements are FixedArray. | 1335 // Check that elements are FixedArray. |
| 1379 // We rely on StoreIC_ArrayLength below to deal with all types of | 1336 // We rely on StoreIC_ArrayLength below to deal with all types of |
| 1380 // fast elements (including COW). | 1337 // fast elements (including COW). |
| 1381 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset)); | 1338 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset)); |
| 1382 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch); | 1339 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch); |
| 1383 __ j(not_equal, &miss, not_taken); | 1340 __ j(not_equal, &miss); |
| 1384 | 1341 |
| 1385 // Check that value is a smi. | 1342 // Check that value is a smi. |
| 1386 __ test(value, Immediate(kSmiTagMask)); | 1343 __ test(value, Immediate(kSmiTagMask)); |
| 1387 __ j(not_zero, &miss, not_taken); | 1344 __ j(not_zero, &miss); |
| 1388 | 1345 |
| 1389 // Prepare tail call to StoreIC_ArrayLength. | 1346 // Prepare tail call to StoreIC_ArrayLength. |
| 1390 __ pop(scratch); | 1347 __ pop(scratch); |
| 1391 __ push(receiver); | 1348 __ push(receiver); |
| 1392 __ push(value); | 1349 __ push(value); |
| 1393 __ push(scratch); // return address | 1350 __ push(scratch); // return address |
| 1394 | 1351 |
| 1395 ExternalReference ref = | 1352 ExternalReference ref = |
| 1396 ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate()); | 1353 ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate()); |
| 1397 __ TailCallExternalReference(ref, 2, 1); | 1354 __ TailCallExternalReference(ref, 2, 1); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1469 __ push(eax); | 1426 __ push(eax); |
| 1470 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes | 1427 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes |
| 1471 __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode. | 1428 __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode. |
| 1472 __ push(ebx); // return address | 1429 __ push(ebx); // return address |
| 1473 | 1430 |
| 1474 // Do tail-call to runtime routine. | 1431 // Do tail-call to runtime routine. |
| 1475 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); | 1432 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); |
| 1476 } | 1433 } |
| 1477 | 1434 |
| 1478 | 1435 |
| 1479 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { | 1436 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) { |
| 1480 // ----------- S t a t e ------------- | 1437 // ----------- S t a t e ------------- |
| 1481 // -- eax : value | 1438 // -- eax : value |
| 1482 // -- ecx : key | 1439 // -- ecx : key |
| 1483 // -- edx : receiver | 1440 // -- edx : receiver |
| 1484 // -- esp[0] : return address | 1441 // -- esp[0] : return address |
| 1485 // ----------------------------------- | 1442 // ----------------------------------- |
| 1486 | 1443 |
| 1487 __ pop(ebx); | 1444 __ pop(ebx); |
| 1488 __ push(edx); | 1445 __ push(edx); |
| 1489 __ push(ecx); | 1446 __ push(ecx); |
| 1490 __ push(eax); | 1447 __ push(eax); |
| 1491 __ push(ebx); | 1448 __ push(ebx); |
| 1492 | 1449 |
| 1493 // Do tail-call to runtime routine. | 1450 // Do tail-call to runtime routine. |
| 1494 ExternalReference ref = | 1451 ExternalReference ref = force_generic |
| 1495 ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate()); | 1452 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric), |
| 1453 masm->isolate()) |
| 1454 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate()); |
| 1455 __ TailCallExternalReference(ref, 3, 1); |
| 1456 } |
| 1457 |
| 1458 |
| 1459 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { |
| 1460 // ----------- S t a t e ------------- |
| 1461 // -- eax : value |
| 1462 // -- ecx : key |
| 1463 // -- edx : receiver |
| 1464 // -- esp[0] : return address |
| 1465 // ----------------------------------- |
| 1466 |
| 1467 __ pop(ebx); |
| 1468 __ push(edx); |
| 1469 __ push(ecx); |
| 1470 __ push(eax); |
| 1471 __ push(ebx); // return address |
| 1472 |
| 1473 // Do tail-call to runtime routine. |
| 1474 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate()); |
| 1496 __ TailCallExternalReference(ref, 3, 1); | 1475 __ TailCallExternalReference(ref, 3, 1); |
| 1497 } | 1476 } |
| 1498 | 1477 |
| 1499 | 1478 |
| 1500 #undef __ | 1479 #undef __ |
| 1501 | 1480 |
| 1502 | 1481 |
| 1503 Condition CompareIC::ComputeCondition(Token::Value op) { | 1482 Condition CompareIC::ComputeCondition(Token::Value op) { |
| 1504 switch (op) { | 1483 switch (op) { |
| 1505 case Token::EQ_STRICT: | 1484 case Token::EQ_STRICT: |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1593 Condition cc = *jmp_address == Assembler::kJncShortOpcode | 1572 Condition cc = *jmp_address == Assembler::kJncShortOpcode |
| 1594 ? not_zero | 1573 ? not_zero |
| 1595 : zero; | 1574 : zero; |
| 1596 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1575 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
| 1597 } | 1576 } |
| 1598 | 1577 |
| 1599 | 1578 |
| 1600 } } // namespace v8::internal | 1579 } } // namespace v8::internal |
| 1601 | 1580 |
| 1602 #endif // V8_TARGET_ARCH_IA32 | 1581 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |