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, true); |
97 } | 97 } |
98 | 98 |
99 | 99 |
100 // Helper function used to load a property from a dictionary backing | 100 // Helper function used to load a property from a dictionary backing |
101 // 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 |
102 // 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 |
103 // 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 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 // If probing finds an entry in the dictionary, r0 contains the | 139 // If probing finds an entry in the dictionary, r0 contains the |
140 // index into the dictionary. Check that the value is a normal | 140 // index into the dictionary. Check that the value is a normal |
141 // property. | 141 // property. |
142 __ bind(&done); | 142 __ bind(&done); |
143 const int kElementsStartOffset = | 143 const int kElementsStartOffset = |
144 StringDictionary::kHeaderSize + | 144 StringDictionary::kHeaderSize + |
145 StringDictionary::kElementsStartIndex * kPointerSize; | 145 StringDictionary::kElementsStartIndex * kPointerSize; |
146 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 146 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
147 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), | 147 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), |
148 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 148 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
149 __ j(not_zero, miss_label, not_taken); | 149 __ j(not_zero, miss_label); |
150 | 150 |
151 // Get the value at the masked, scaled index. | 151 // Get the value at the masked, scaled index. |
152 const int kValueOffset = kElementsStartOffset + kPointerSize; | 152 const int kValueOffset = kElementsStartOffset + kPointerSize; |
153 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); | 153 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); |
154 } | 154 } |
155 | 155 |
156 | 156 |
157 // Helper function used to store a property to a dictionary backing | 157 // Helper function used to store a property to a dictionary backing |
158 // storage. This function may fail to store a property eventhough it | 158 // storage. This function may fail to store a property eventhough it |
159 // 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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 __ bind(&done); | 197 __ bind(&done); |
198 const int kElementsStartOffset = | 198 const int kElementsStartOffset = |
199 StringDictionary::kHeaderSize + | 199 StringDictionary::kHeaderSize + |
200 StringDictionary::kElementsStartIndex * kPointerSize; | 200 StringDictionary::kElementsStartIndex * kPointerSize; |
201 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 201 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
202 const int kTypeAndReadOnlyMask | 202 const int kTypeAndReadOnlyMask |
203 = (PropertyDetails::TypeField::mask() | | 203 = (PropertyDetails::TypeField::mask() | |
204 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; | 204 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; |
205 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), | 205 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), |
206 Immediate(kTypeAndReadOnlyMask)); | 206 Immediate(kTypeAndReadOnlyMask)); |
207 __ j(not_zero, miss_label, not_taken); | 207 __ j(not_zero, miss_label); |
208 | 208 |
209 // Store the value at the masked, scaled index. | 209 // Store the value at the masked, scaled index. |
210 const int kValueOffset = kElementsStartOffset + kPointerSize; | 210 const int kValueOffset = kElementsStartOffset + kPointerSize; |
211 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); | 211 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); |
212 __ mov(Operand(r0, 0), value); | 212 __ mov(Operand(r0, 0), value); |
213 | 213 |
214 // Update write barrier. Make sure not to clobber the value. | 214 // Update write barrier. Make sure not to clobber the value. |
215 __ mov(r1, value); | 215 __ mov(r1, value); |
216 __ RecordWrite(elements, r0, r1); | 216 __ RecordWrite(elements, r0, r1); |
217 } | 217 } |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 // Scale the index by multiplying by the entry size. | 287 // Scale the index by multiplying by the entry size. |
288 ASSERT(NumberDictionary::kEntrySize == 3); | 288 ASSERT(NumberDictionary::kEntrySize == 3); |
289 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 | 289 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 |
290 | 290 |
291 // Check if the key matches. | 291 // Check if the key matches. |
292 __ cmp(key, FieldOperand(elements, | 292 __ cmp(key, FieldOperand(elements, |
293 r2, | 293 r2, |
294 times_pointer_size, | 294 times_pointer_size, |
295 NumberDictionary::kElementsStartOffset)); | 295 NumberDictionary::kElementsStartOffset)); |
296 if (i != (kProbes - 1)) { | 296 if (i != (kProbes - 1)) { |
297 __ j(equal, &done, taken); | 297 __ j(equal, &done); |
298 } else { | 298 } else { |
299 __ j(not_equal, miss, not_taken); | 299 __ j(not_equal, miss); |
300 } | 300 } |
301 } | 301 } |
302 | 302 |
303 __ bind(&done); | 303 __ bind(&done); |
304 // Check that the value is a normal propety. | 304 // Check that the value is a normal propety. |
305 const int kDetailsOffset = | 305 const int kDetailsOffset = |
306 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | 306 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
307 ASSERT_EQ(NORMAL, 0); | 307 ASSERT_EQ(NORMAL, 0); |
308 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), | 308 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), |
309 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 309 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 Register map, | 367 Register map, |
368 int interceptor_bit, | 368 int interceptor_bit, |
369 Label* slow) { | 369 Label* slow) { |
370 // Register use: | 370 // Register use: |
371 // receiver - holds the receiver and is unchanged. | 371 // receiver - holds the receiver and is unchanged. |
372 // Scratch registers: | 372 // Scratch registers: |
373 // map - used to hold the map of the receiver. | 373 // map - used to hold the map of the receiver. |
374 | 374 |
375 // Check that the object isn't a smi. | 375 // Check that the object isn't a smi. |
376 __ test(receiver, Immediate(kSmiTagMask)); | 376 __ test(receiver, Immediate(kSmiTagMask)); |
377 __ j(zero, slow, not_taken); | 377 __ j(zero, slow); |
378 | 378 |
379 // Get the map of the receiver. | 379 // Get the map of the receiver. |
380 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset)); | 380 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset)); |
381 | 381 |
382 // Check bit field. | 382 // Check bit field. |
383 __ test_b(FieldOperand(map, Map::kBitFieldOffset), | 383 __ test_b(FieldOperand(map, Map::kBitFieldOffset), |
384 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)); | 384 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)); |
385 __ j(not_zero, slow, not_taken); | 385 __ j(not_zero, slow); |
386 // 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. |
387 // In the case that the object is a value-wrapper object, | 387 // In the case that the object is a value-wrapper object, |
388 // we enter the runtime system to make sure that indexing | 388 // we enter the runtime system to make sure that indexing |
389 // into string objects works as intended. | 389 // into string objects works as intended. |
390 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 390 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
391 | 391 |
392 __ CmpInstanceType(map, JS_OBJECT_TYPE); | 392 __ CmpInstanceType(map, JS_OBJECT_TYPE); |
393 __ j(below, slow, not_taken); | 393 __ j(below, slow); |
394 } | 394 } |
395 | 395 |
396 | 396 |
397 // Loads an indexed element from a fast case array. | 397 // Loads an indexed element from a fast case array. |
398 // 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. |
399 static void GenerateFastArrayLoad(MacroAssembler* masm, | 399 static void GenerateFastArrayLoad(MacroAssembler* masm, |
400 Register receiver, | 400 Register receiver, |
401 Register key, | 401 Register key, |
402 Register scratch, | 402 Register scratch, |
403 Register result, | 403 Register result, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
446 // key - holds the key and is unchanged. Assumed to be non-smi. | 446 // key - holds the key and is unchanged. Assumed to be non-smi. |
447 // Scratch registers: | 447 // Scratch registers: |
448 // map - used to hold the map of the key. | 448 // map - used to hold the map of the key. |
449 // hash - used to hold the hash of the key. | 449 // hash - used to hold the hash of the key. |
450 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); | 450 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); |
451 __ j(above_equal, not_symbol); | 451 __ j(above_equal, not_symbol); |
452 | 452 |
453 // Is the string an array index, with cached numeric value? | 453 // Is the string an array index, with cached numeric value? |
454 __ mov(hash, FieldOperand(key, String::kHashFieldOffset)); | 454 __ mov(hash, FieldOperand(key, String::kHashFieldOffset)); |
455 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask)); | 455 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask)); |
456 __ j(zero, index_string, not_taken); | 456 __ j(zero, index_string); |
457 | 457 |
458 // Is the string a symbol? | 458 // Is the string a symbol? |
459 ASSERT(kSymbolTag != 0); | 459 ASSERT(kSymbolTag != 0); |
460 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); | 460 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); |
461 __ j(zero, not_symbol, not_taken); | 461 __ j(zero, not_symbol); |
462 } | 462 } |
463 | 463 |
464 | 464 |
465 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 465 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
466 // ----------- S t a t e ------------- | 466 // ----------- S t a t e ------------- |
467 // -- eax : key | 467 // -- eax : key |
468 // -- edx : receiver | 468 // -- edx : receiver |
469 // -- esp[0] : return address | 469 // -- esp[0] : return address |
470 // ----------------------------------- | 470 // ----------------------------------- |
471 Label slow, check_string, index_smi, index_string, property_array_property; | 471 Label slow, check_string, index_smi, index_string, property_array_property; |
472 Label probe_dictionary, check_number_dictionary; | 472 Label probe_dictionary, check_number_dictionary; |
473 | 473 |
474 // Check that the key is a smi. | 474 // Check that the key is a smi. |
475 __ test(eax, Immediate(kSmiTagMask)); | 475 __ test(eax, Immediate(kSmiTagMask)); |
476 __ j(not_zero, &check_string, not_taken); | 476 __ j(not_zero, &check_string); |
477 __ bind(&index_smi); | 477 __ bind(&index_smi); |
478 // Now the key is known to be a smi. This place is also jumped to from | 478 // Now the key is known to be a smi. This place is also jumped to from |
479 // where a numeric string is converted to a smi. | 479 // where a numeric string is converted to a smi. |
480 | 480 |
481 GenerateKeyedLoadReceiverCheck( | 481 GenerateKeyedLoadReceiverCheck( |
482 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); | 482 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); |
483 | 483 |
484 // Check the "has fast elements" bit in the receiver's map which is | 484 // Check the "has fast elements" bit in the receiver's map which is |
485 // now in ecx. | 485 // now in ecx. |
486 __ test_b(FieldOperand(ecx, Map::kBitField2Offset), | 486 __ test_b(FieldOperand(ecx, Map::kBitField2Offset), |
487 1 << Map::kHasFastElements); | 487 1 << Map::kHasFastElements); |
488 __ j(zero, &check_number_dictionary, not_taken); | 488 __ j(zero, &check_number_dictionary); |
489 | 489 |
490 GenerateFastArrayLoad(masm, | 490 GenerateFastArrayLoad(masm, |
491 edx, | 491 edx, |
492 eax, | 492 eax, |
493 ecx, | 493 ecx, |
494 eax, | 494 eax, |
495 NULL, | 495 NULL, |
496 &slow); | 496 &slow); |
497 Isolate* isolate = masm->isolate(); | 497 Isolate* isolate = masm->isolate(); |
498 Counters* counters = isolate->counters(); | 498 Counters* counters = isolate->counters(); |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
656 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { | 656 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { |
657 // ----------- S t a t e ------------- | 657 // ----------- S t a t e ------------- |
658 // -- eax : key | 658 // -- eax : key |
659 // -- edx : receiver | 659 // -- edx : receiver |
660 // -- esp[0] : return address | 660 // -- esp[0] : return address |
661 // ----------------------------------- | 661 // ----------------------------------- |
662 Label slow; | 662 Label slow; |
663 | 663 |
664 // Check that the receiver isn't a smi. | 664 // Check that the receiver isn't a smi. |
665 __ test(edx, Immediate(kSmiTagMask)); | 665 __ test(edx, Immediate(kSmiTagMask)); |
666 __ j(zero, &slow, not_taken); | 666 __ j(zero, &slow); |
667 | 667 |
668 // Check that the key is an array index, that is Uint32. | 668 // Check that the key is an array index, that is Uint32. |
669 __ test(eax, Immediate(kSmiTagMask | kSmiSignMask)); | 669 __ test(eax, Immediate(kSmiTagMask | kSmiSignMask)); |
670 __ j(not_zero, &slow, not_taken); | 670 __ j(not_zero, &slow); |
671 | 671 |
672 // Get the map of the receiver. | 672 // Get the map of the receiver. |
673 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 673 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
674 | 674 |
675 // Check that it has indexed interceptor and access checks | 675 // Check that it has indexed interceptor and access checks |
676 // are not enabled for this object. | 676 // are not enabled for this object. |
677 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); | 677 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); |
678 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask)); | 678 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask)); |
679 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor)); | 679 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor)); |
680 __ j(not_zero, &slow, not_taken); | 680 __ j(not_zero, &slow); |
681 | 681 |
682 // Everything is fine, call runtime. | 682 // Everything is fine, call runtime. |
683 __ pop(ecx); | 683 __ pop(ecx); |
684 __ push(edx); // receiver | 684 __ push(edx); // receiver |
685 __ push(eax); // key | 685 __ push(eax); // key |
686 __ push(ecx); // return address | 686 __ push(ecx); // return address |
687 | 687 |
688 // Perform tail call to the entry. | 688 // Perform tail call to the entry. |
689 ExternalReference ref = | 689 ExternalReference ref = |
690 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), | 690 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), |
(...skipping 10 matching lines...) Expand all Loading... |
701 // ----------- S t a t e ------------- | 701 // ----------- S t a t e ------------- |
702 // -- eax : value | 702 // -- eax : value |
703 // -- ecx : key | 703 // -- ecx : key |
704 // -- edx : receiver | 704 // -- edx : receiver |
705 // -- esp[0] : return address | 705 // -- esp[0] : return address |
706 // ----------------------------------- | 706 // ----------------------------------- |
707 Label slow, fast, array, extra; | 707 Label slow, fast, array, extra; |
708 | 708 |
709 // Check that the object isn't a smi. | 709 // Check that the object isn't a smi. |
710 __ test(edx, Immediate(kSmiTagMask)); | 710 __ test(edx, Immediate(kSmiTagMask)); |
711 __ j(zero, &slow, not_taken); | 711 __ j(zero, &slow); |
712 // Get the map from the receiver. | 712 // Get the map from the receiver. |
713 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | 713 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
714 // Check that the receiver does not require access checks. We need | 714 // Check that the receiver does not require access checks. We need |
715 // to do this because this generic stub does not perform map checks. | 715 // to do this because this generic stub does not perform map checks. |
716 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), | 716 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), |
717 1 << Map::kIsAccessCheckNeeded); | 717 1 << Map::kIsAccessCheckNeeded); |
718 __ j(not_zero, &slow, not_taken); | 718 __ j(not_zero, &slow); |
719 // Check that the key is a smi. | 719 // Check that the key is a smi. |
720 __ test(ecx, Immediate(kSmiTagMask)); | 720 __ test(ecx, Immediate(kSmiTagMask)); |
721 __ j(not_zero, &slow, not_taken); | 721 __ j(not_zero, &slow); |
722 __ CmpInstanceType(edi, JS_ARRAY_TYPE); | 722 __ CmpInstanceType(edi, JS_ARRAY_TYPE); |
723 __ j(equal, &array); | 723 __ j(equal, &array); |
724 // Check that the object is some kind of JS object. | 724 // Check that the object is some kind of JS object. |
725 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); | 725 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); |
726 __ j(below, &slow, not_taken); | 726 __ j(below, &slow); |
727 | 727 |
728 // Object case: Check key against length in the elements array. | 728 // Object case: Check key against length in the elements array. |
729 // eax: value | 729 // eax: value |
730 // edx: JSObject | 730 // edx: JSObject |
731 // ecx: key (a smi) | 731 // ecx: key (a smi) |
732 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 732 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
733 // Check that the object is in fast mode and writable. | 733 // Check that the object is in fast mode and writable. |
734 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, true); | 734 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, true); |
735 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); | 735 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); |
736 __ j(below, &fast, taken); | 736 __ j(below, &fast); |
737 | 737 |
738 // Slow case: call runtime. | 738 // Slow case: call runtime. |
739 __ bind(&slow); | 739 __ bind(&slow); |
740 GenerateRuntimeSetProperty(masm, strict_mode); | 740 GenerateRuntimeSetProperty(masm, strict_mode); |
741 | 741 |
742 // Extra capacity case: Check if there is extra capacity to | 742 // Extra capacity case: Check if there is extra capacity to |
743 // perform the store and update the length. Used for adding one | 743 // perform the store and update the length. Used for adding one |
744 // element to the array by writing to array[array.length]. | 744 // element to the array by writing to array[array.length]. |
745 __ bind(&extra); | 745 __ bind(&extra); |
746 // eax: value | 746 // eax: value |
747 // edx: receiver, a JSArray | 747 // edx: receiver, a JSArray |
748 // ecx: key, a smi. | 748 // ecx: key, a smi. |
749 // edi: receiver->elements, a FixedArray | 749 // edi: receiver->elements, a FixedArray |
750 // flags: compare (ecx, edx.length()) | 750 // flags: compare (ecx, edx.length()) |
751 // do not leave holes in the array: | 751 // do not leave holes in the array: |
752 __ j(not_equal, &slow, not_taken); | 752 __ j(not_equal, &slow); |
753 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); | 753 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); |
754 __ j(above_equal, &slow, not_taken); | 754 __ j(above_equal, &slow); |
755 // Add 1 to receiver->length, and go to fast array write. | 755 // Add 1 to receiver->length, and go to fast array write. |
756 __ add(FieldOperand(edx, JSArray::kLengthOffset), | 756 __ add(FieldOperand(edx, JSArray::kLengthOffset), |
757 Immediate(Smi::FromInt(1))); | 757 Immediate(Smi::FromInt(1))); |
758 __ jmp(&fast); | 758 __ jmp(&fast); |
759 | 759 |
760 // Array case: Get the length and the elements array from the JS | 760 // Array case: Get the length and the elements array from the JS |
761 // array. Check that the array is in fast mode (and writable); if it | 761 // array. Check that the array is in fast mode (and writable); if it |
762 // is the length is always a smi. | 762 // is the length is always a smi. |
763 __ bind(&array); | 763 __ bind(&array); |
764 // eax: value | 764 // eax: value |
765 // edx: receiver, a JSArray | 765 // edx: receiver, a JSArray |
766 // ecx: key, a smi. | 766 // ecx: key, a smi. |
767 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 767 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
768 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, true); | 768 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, true); |
769 | 769 |
770 // Check the key against the length in the array, compute the | 770 // Check the key against the length in the array, compute the |
771 // address to store into and fall through to fast case. | 771 // address to store into and fall through to fast case. |
772 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. | 772 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. |
773 __ j(above_equal, &extra, not_taken); | 773 __ j(above_equal, &extra); |
774 | 774 |
775 // Fast case: Do the store. | 775 // Fast case: Do the store. |
776 __ bind(&fast); | 776 __ bind(&fast); |
777 // eax: value | 777 // eax: value |
778 // ecx: key (a smi) | 778 // ecx: key (a smi) |
779 // edx: receiver | 779 // edx: receiver |
780 // edi: FixedArray receiver->elements | 780 // edi: FixedArray receiver->elements |
781 __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax); | 781 __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax); |
782 // Update write barrier for the elements array address. | 782 // Update write barrier for the elements array address. |
783 __ mov(edx, Operand(eax)); | 783 __ mov(edx, Operand(eax)); |
(...skipping 23 matching lines...) Expand all Loading... |
807 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, | 807 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, |
808 eax); | 808 eax); |
809 | 809 |
810 // If the stub cache probing failed, the receiver might be a value. | 810 // If the stub cache probing failed, the receiver might be a value. |
811 // For value objects, we use the map of the prototype objects for | 811 // For value objects, we use the map of the prototype objects for |
812 // the corresponding JSValue for the cache and that is what we need | 812 // the corresponding JSValue for the cache and that is what we need |
813 // to probe. | 813 // to probe. |
814 // | 814 // |
815 // Check for number. | 815 // Check for number. |
816 __ test(edx, Immediate(kSmiTagMask)); | 816 __ test(edx, Immediate(kSmiTagMask)); |
817 __ j(zero, &number, not_taken); | 817 __ j(zero, &number); |
818 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx); | 818 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx); |
819 __ j(not_equal, &non_number, taken); | 819 __ j(not_equal, &non_number); |
820 __ bind(&number); | 820 __ bind(&number); |
821 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 821 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
822 masm, Context::NUMBER_FUNCTION_INDEX, edx); | 822 masm, Context::NUMBER_FUNCTION_INDEX, edx); |
823 __ jmp(&probe); | 823 __ jmp(&probe); |
824 | 824 |
825 // Check for string. | 825 // Check for string. |
826 __ bind(&non_number); | 826 __ bind(&non_number); |
827 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE); | 827 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE); |
828 __ j(above_equal, &non_string, taken); | 828 __ j(above_equal, &non_string); |
829 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 829 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
830 masm, Context::STRING_FUNCTION_INDEX, edx); | 830 masm, Context::STRING_FUNCTION_INDEX, edx); |
831 __ jmp(&probe); | 831 __ jmp(&probe); |
832 | 832 |
833 // Check for boolean. | 833 // Check for boolean. |
834 __ bind(&non_string); | 834 __ bind(&non_string); |
835 __ cmp(edx, FACTORY->true_value()); | 835 __ cmp(edx, FACTORY->true_value()); |
836 __ j(equal, &boolean, not_taken); | 836 __ j(equal, &boolean); |
837 __ cmp(edx, FACTORY->false_value()); | 837 __ cmp(edx, FACTORY->false_value()); |
838 __ j(not_equal, &miss, taken); | 838 __ j(not_equal, &miss); |
839 __ bind(&boolean); | 839 __ bind(&boolean); |
840 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 840 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
841 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); | 841 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); |
842 | 842 |
843 // Probe the stub cache for the value object. | 843 // Probe the stub cache for the value object. |
844 __ bind(&probe); | 844 __ bind(&probe); |
845 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, | 845 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, |
846 no_reg); | 846 no_reg); |
847 __ bind(&miss); | 847 __ bind(&miss); |
848 } | 848 } |
849 | 849 |
850 | 850 |
851 static void GenerateFunctionTailCall(MacroAssembler* masm, | 851 static void GenerateFunctionTailCall(MacroAssembler* masm, |
852 int argc, | 852 int argc, |
853 Label* miss) { | 853 Label* miss) { |
854 // ----------- S t a t e ------------- | 854 // ----------- S t a t e ------------- |
855 // -- ecx : name | 855 // -- ecx : name |
856 // -- edi : function | 856 // -- edi : function |
857 // -- esp[0] : return address | 857 // -- esp[0] : return address |
858 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 858 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
859 // -- ... | 859 // -- ... |
860 // -- esp[(argc + 1) * 4] : receiver | 860 // -- esp[(argc + 1) * 4] : receiver |
861 // ----------------------------------- | 861 // ----------------------------------- |
862 | 862 |
863 // Check that the result is not a smi. | 863 // Check that the result is not a smi. |
864 __ test(edi, Immediate(kSmiTagMask)); | 864 __ test(edi, Immediate(kSmiTagMask)); |
865 __ j(zero, miss, not_taken); | 865 __ j(zero, miss); |
866 | 866 |
867 // Check that the value is a JavaScript function, fetching its map into eax. | 867 // Check that the value is a JavaScript function, fetching its map into eax. |
868 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); | 868 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); |
869 __ j(not_equal, miss, not_taken); | 869 __ j(not_equal, miss); |
870 | 870 |
871 // Invoke the function. | 871 // Invoke the function. |
872 ParameterCount actual(argc); | 872 ParameterCount actual(argc); |
873 __ InvokeFunction(edi, actual, JUMP_FUNCTION); | 873 __ InvokeFunction(edi, actual, JUMP_FUNCTION); |
874 } | 874 } |
875 | 875 |
876 // The generated code falls through if the call should be handled by runtime. | 876 // The generated code falls through if the call should be handled by runtime. |
877 static void GenerateCallNormal(MacroAssembler* masm, int argc) { | 877 static void GenerateCallNormal(MacroAssembler* masm, int argc) { |
878 // ----------- S t a t e ------------- | 878 // ----------- S t a t e ------------- |
879 // -- ecx : name | 879 // -- ecx : name |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
935 // Move result to edi and exit the internal frame. | 935 // Move result to edi and exit the internal frame. |
936 __ mov(edi, eax); | 936 __ mov(edi, eax); |
937 __ LeaveInternalFrame(); | 937 __ LeaveInternalFrame(); |
938 | 938 |
939 // Check if the receiver is a global object of some sort. | 939 // Check if the receiver is a global object of some sort. |
940 // This can happen only for regular CallIC but not KeyedCallIC. | 940 // This can happen only for regular CallIC but not KeyedCallIC. |
941 if (id == IC::kCallIC_Miss) { | 941 if (id == IC::kCallIC_Miss) { |
942 Label invoke, global; | 942 Label invoke, global; |
943 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver | 943 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver |
944 __ test(edx, Immediate(kSmiTagMask)); | 944 __ test(edx, Immediate(kSmiTagMask)); |
945 __ j(zero, &invoke, not_taken, Label::kNear); | 945 __ j(zero, &invoke, Label::kNear); |
946 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 946 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); |
947 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 947 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
948 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); | 948 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); |
949 __ j(equal, &global, Label::kNear); | 949 __ j(equal, &global, Label::kNear); |
950 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); | 950 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); |
951 __ j(not_equal, &invoke, Label::kNear); | 951 __ j(not_equal, &invoke, Label::kNear); |
952 | 952 |
953 // Patch the receiver on the stack. | 953 // Patch the receiver on the stack. |
954 __ bind(&global); | 954 __ bind(&global); |
955 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 955 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1017 | 1017 |
1018 // Get the receiver of the function from the stack; 1 ~ return address. | 1018 // Get the receiver of the function from the stack; 1 ~ return address. |
1019 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1019 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
1020 | 1020 |
1021 Label do_call, slow_call, slow_load, slow_reload_receiver; | 1021 Label do_call, slow_call, slow_load, slow_reload_receiver; |
1022 Label check_number_dictionary, check_string, lookup_monomorphic_cache; | 1022 Label check_number_dictionary, check_string, lookup_monomorphic_cache; |
1023 Label index_smi, index_string; | 1023 Label index_smi, index_string; |
1024 | 1024 |
1025 // Check that the key is a smi. | 1025 // Check that the key is a smi. |
1026 __ test(ecx, Immediate(kSmiTagMask)); | 1026 __ test(ecx, Immediate(kSmiTagMask)); |
1027 __ j(not_zero, &check_string, not_taken); | 1027 __ j(not_zero, &check_string); |
1028 | 1028 |
1029 __ bind(&index_smi); | 1029 __ bind(&index_smi); |
1030 // Now the key is known to be a smi. This place is also jumped to from | 1030 // Now the key is known to be a smi. This place is also jumped to from |
1031 // where a numeric string is converted to a smi. | 1031 // where a numeric string is converted to a smi. |
1032 | 1032 |
1033 GenerateKeyedLoadReceiverCheck( | 1033 GenerateKeyedLoadReceiverCheck( |
1034 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call); | 1034 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call); |
1035 | 1035 |
1036 GenerateFastArrayLoad( | 1036 GenerateFastArrayLoad( |
1037 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); | 1037 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1307 // Value must be a number, but only smis are accepted as the most common case. | 1307 // Value must be a number, but only smis are accepted as the most common case. |
1308 | 1308 |
1309 Label miss; | 1309 Label miss; |
1310 | 1310 |
1311 Register receiver = edx; | 1311 Register receiver = edx; |
1312 Register value = eax; | 1312 Register value = eax; |
1313 Register scratch = ebx; | 1313 Register scratch = ebx; |
1314 | 1314 |
1315 // Check that the receiver isn't a smi. | 1315 // Check that the receiver isn't a smi. |
1316 __ test(receiver, Immediate(kSmiTagMask)); | 1316 __ test(receiver, Immediate(kSmiTagMask)); |
1317 __ j(zero, &miss, not_taken); | 1317 __ j(zero, &miss); |
1318 | 1318 |
1319 // Check that the object is a JS array. | 1319 // Check that the object is a JS array. |
1320 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); | 1320 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); |
1321 __ j(not_equal, &miss, not_taken); | 1321 __ j(not_equal, &miss); |
1322 | 1322 |
1323 // Check that elements are FixedArray. | 1323 // Check that elements are FixedArray. |
1324 // We rely on StoreIC_ArrayLength below to deal with all types of | 1324 // We rely on StoreIC_ArrayLength below to deal with all types of |
1325 // fast elements (including COW). | 1325 // fast elements (including COW). |
1326 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset)); | 1326 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset)); |
1327 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch); | 1327 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch); |
1328 __ j(not_equal, &miss, not_taken); | 1328 __ j(not_equal, &miss); |
1329 | 1329 |
1330 // Check that value is a smi. | 1330 // Check that value is a smi. |
1331 __ test(value, Immediate(kSmiTagMask)); | 1331 __ test(value, Immediate(kSmiTagMask)); |
1332 __ j(not_zero, &miss, not_taken); | 1332 __ j(not_zero, &miss); |
1333 | 1333 |
1334 // Prepare tail call to StoreIC_ArrayLength. | 1334 // Prepare tail call to StoreIC_ArrayLength. |
1335 __ pop(scratch); | 1335 __ pop(scratch); |
1336 __ push(receiver); | 1336 __ push(receiver); |
1337 __ push(value); | 1337 __ push(value); |
1338 __ push(scratch); // return address | 1338 __ push(scratch); // return address |
1339 | 1339 |
1340 ExternalReference ref = | 1340 ExternalReference ref = |
1341 ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate()); | 1341 ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate()); |
1342 __ TailCallExternalReference(ref, 2, 1); | 1342 __ TailCallExternalReference(ref, 2, 1); |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1538 Condition cc = *jmp_address == Assembler::kJncShortOpcode | 1538 Condition cc = *jmp_address == Assembler::kJncShortOpcode |
1539 ? not_zero | 1539 ? not_zero |
1540 : zero; | 1540 : zero; |
1541 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1541 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
1542 } | 1542 } |
1543 | 1543 |
1544 | 1544 |
1545 } } // namespace v8::internal | 1545 } } // namespace v8::internal |
1546 | 1546 |
1547 #endif // V8_TARGET_ARCH_IA32 | 1547 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |