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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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 | |
101 // Helper function used to load a property from a dictionary backing | 100 // Helper function used to load a property from a dictionary backing |
102 // 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 |
103 // 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 |
104 // 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 |
105 // 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 |
106 // case. The generated code assumes that the receiver has slow | 105 // case. The generated code assumes that the receiver has slow |
107 // properties, is not a global object and does not have interceptors. | 106 // properties, is not a global object and does not have interceptors. |
108 static void GenerateDictionaryLoad(MacroAssembler* masm, | 107 static void GenerateDictionaryLoad(MacroAssembler* masm, |
109 Label* miss_label, | 108 Label* miss_label, |
110 Register elements, | 109 Register elements, |
(...skipping 29 matching lines...) Expand all Loading... |
140 // If probing finds an entry in the dictionary, r0 contains the | 139 // If probing finds an entry in the dictionary, r0 contains the |
141 // index into the dictionary. Check that the value is a normal | 140 // index into the dictionary. Check that the value is a normal |
142 // property. | 141 // property. |
143 __ bind(&done); | 142 __ bind(&done); |
144 const int kElementsStartOffset = | 143 const int kElementsStartOffset = |
145 StringDictionary::kHeaderSize + | 144 StringDictionary::kHeaderSize + |
146 StringDictionary::kElementsStartIndex * kPointerSize; | 145 StringDictionary::kElementsStartIndex * kPointerSize; |
147 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 146 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
148 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), | 147 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), |
149 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 148 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
150 __ j(not_zero, miss_label, not_taken); | 149 __ j(not_zero, miss_label, Label::kFar, not_taken); |
151 | 150 |
152 // Get the value at the masked, scaled index. | 151 // Get the value at the masked, scaled index. |
153 const int kValueOffset = kElementsStartOffset + kPointerSize; | 152 const int kValueOffset = kElementsStartOffset + kPointerSize; |
154 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); | 153 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); |
155 } | 154 } |
156 | 155 |
157 | 156 |
158 // Helper function used to store a property to a dictionary backing | 157 // Helper function used to store a property to a dictionary backing |
159 // storage. This function may fail to store a property eventhough it | 158 // storage. This function may fail to store a property eventhough it |
160 // 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... |
198 __ bind(&done); | 197 __ bind(&done); |
199 const int kElementsStartOffset = | 198 const int kElementsStartOffset = |
200 StringDictionary::kHeaderSize + | 199 StringDictionary::kHeaderSize + |
201 StringDictionary::kElementsStartIndex * kPointerSize; | 200 StringDictionary::kElementsStartIndex * kPointerSize; |
202 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 201 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
203 const int kTypeAndReadOnlyMask | 202 const int kTypeAndReadOnlyMask |
204 = (PropertyDetails::TypeField::mask() | | 203 = (PropertyDetails::TypeField::mask() | |
205 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; | 204 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; |
206 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), | 205 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), |
207 Immediate(kTypeAndReadOnlyMask)); | 206 Immediate(kTypeAndReadOnlyMask)); |
208 __ j(not_zero, miss_label, not_taken); | 207 __ j(not_zero, miss_label, Label::kFar, not_taken); |
209 | 208 |
210 // Store the value at the masked, scaled index. | 209 // Store the value at the masked, scaled index. |
211 const int kValueOffset = kElementsStartOffset + kPointerSize; | 210 const int kValueOffset = kElementsStartOffset + kPointerSize; |
212 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); | 211 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); |
213 __ mov(Operand(r0, 0), value); | 212 __ mov(Operand(r0, 0), value); |
214 | 213 |
215 // Update write barrier. Make sure not to clobber the value. | 214 // Update write barrier. Make sure not to clobber the value. |
216 __ mov(r1, value); | 215 __ mov(r1, value); |
217 __ RecordWrite(elements, r0, r1); | 216 __ RecordWrite(elements, r0, r1); |
218 } | 217 } |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 // Scale the index by multiplying by the entry size. | 287 // Scale the index by multiplying by the entry size. |
289 ASSERT(NumberDictionary::kEntrySize == 3); | 288 ASSERT(NumberDictionary::kEntrySize == 3); |
290 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 | 289 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3 |
291 | 290 |
292 // Check if the key matches. | 291 // Check if the key matches. |
293 __ cmp(key, FieldOperand(elements, | 292 __ cmp(key, FieldOperand(elements, |
294 r2, | 293 r2, |
295 times_pointer_size, | 294 times_pointer_size, |
296 NumberDictionary::kElementsStartOffset)); | 295 NumberDictionary::kElementsStartOffset)); |
297 if (i != (kProbes - 1)) { | 296 if (i != (kProbes - 1)) { |
298 __ j(equal, &done, taken); | 297 __ j(equal, &done, Label::kFar, taken); |
299 } else { | 298 } else { |
300 __ j(not_equal, miss, not_taken); | 299 __ j(not_equal, miss, Label::kFar, not_taken); |
301 } | 300 } |
302 } | 301 } |
303 | 302 |
304 __ bind(&done); | 303 __ bind(&done); |
305 // Check that the value is a normal propety. | 304 // Check that the value is a normal propety. |
306 const int kDetailsOffset = | 305 const int kDetailsOffset = |
307 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | 306 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
308 ASSERT_EQ(NORMAL, 0); | 307 ASSERT_EQ(NORMAL, 0); |
309 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), | 308 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), |
310 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 309 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 Register map, | 367 Register map, |
369 int interceptor_bit, | 368 int interceptor_bit, |
370 Label* slow) { | 369 Label* slow) { |
371 // Register use: | 370 // Register use: |
372 // receiver - holds the receiver and is unchanged. | 371 // receiver - holds the receiver and is unchanged. |
373 // Scratch registers: | 372 // Scratch registers: |
374 // map - used to hold the map of the receiver. | 373 // map - used to hold the map of the receiver. |
375 | 374 |
376 // Check that the object isn't a smi. | 375 // Check that the object isn't a smi. |
377 __ test(receiver, Immediate(kSmiTagMask)); | 376 __ test(receiver, Immediate(kSmiTagMask)); |
378 __ j(zero, slow, not_taken); | 377 __ j(zero, slow, Label::kFar, not_taken); |
379 | 378 |
380 // Get the map of the receiver. | 379 // Get the map of the receiver. |
381 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset)); | 380 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset)); |
382 | 381 |
383 // Check bit field. | 382 // Check bit field. |
384 __ test_b(FieldOperand(map, Map::kBitFieldOffset), | 383 __ test_b(FieldOperand(map, Map::kBitFieldOffset), |
385 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)); | 384 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)); |
386 __ j(not_zero, slow, not_taken); | 385 __ j(not_zero, slow, Label::kFar, not_taken); |
387 // 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. |
388 // In the case that the object is a value-wrapper object, | 387 // In the case that the object is a value-wrapper object, |
389 // we enter the runtime system to make sure that indexing | 388 // we enter the runtime system to make sure that indexing |
390 // into string objects works as intended. | 389 // into string objects works as intended. |
391 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 390 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
392 | 391 |
393 __ CmpInstanceType(map, JS_OBJECT_TYPE); | 392 __ CmpInstanceType(map, JS_OBJECT_TYPE); |
394 __ j(below, slow, not_taken); | 393 __ j(below, slow, Label::kFar, not_taken); |
395 } | 394 } |
396 | 395 |
397 | 396 |
398 // Loads an indexed element from a fast case array. | 397 // Loads an indexed element from a fast case array. |
399 // 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. |
400 static void GenerateFastArrayLoad(MacroAssembler* masm, | 399 static void GenerateFastArrayLoad(MacroAssembler* masm, |
401 Register receiver, | 400 Register receiver, |
402 Register key, | 401 Register key, |
403 Register scratch, | 402 Register scratch, |
404 Register result, | 403 Register result, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 // 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. |
448 // Scratch registers: | 447 // Scratch registers: |
449 // map - used to hold the map of the key. | 448 // map - used to hold the map of the key. |
450 // hash - used to hold the hash of the key. | 449 // hash - used to hold the hash of the key. |
451 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); | 450 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); |
452 __ j(above_equal, not_symbol); | 451 __ j(above_equal, not_symbol); |
453 | 452 |
454 // Is the string an array index, with cached numeric value? | 453 // Is the string an array index, with cached numeric value? |
455 __ mov(hash, FieldOperand(key, String::kHashFieldOffset)); | 454 __ mov(hash, FieldOperand(key, String::kHashFieldOffset)); |
456 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask)); | 455 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask)); |
457 __ j(zero, index_string, not_taken); | 456 __ j(zero, index_string, Label::kFar, not_taken); |
458 | 457 |
459 // Is the string a symbol? | 458 // Is the string a symbol? |
460 ASSERT(kSymbolTag != 0); | 459 ASSERT(kSymbolTag != 0); |
461 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); | 460 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask); |
462 __ j(zero, not_symbol, not_taken); | 461 __ j(zero, not_symbol, Label::kFar, not_taken); |
463 } | 462 } |
464 | 463 |
465 | 464 |
466 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 465 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
467 // ----------- S t a t e ------------- | 466 // ----------- S t a t e ------------- |
468 // -- eax : key | 467 // -- eax : key |
469 // -- edx : receiver | 468 // -- edx : receiver |
470 // -- esp[0] : return address | 469 // -- esp[0] : return address |
471 // ----------------------------------- | 470 // ----------------------------------- |
472 Label slow, check_string, index_smi, index_string, property_array_property; | 471 Label slow, check_string, index_smi, index_string, property_array_property; |
473 Label probe_dictionary, check_number_dictionary; | 472 Label probe_dictionary, check_number_dictionary; |
474 | 473 |
475 // Check that the key is a smi. | 474 // Check that the key is a smi. |
476 __ test(eax, Immediate(kSmiTagMask)); | 475 __ test(eax, Immediate(kSmiTagMask)); |
477 __ j(not_zero, &check_string, not_taken); | 476 __ j(not_zero, &check_string, Label::kFar, not_taken); |
478 __ bind(&index_smi); | 477 __ bind(&index_smi); |
479 // 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 |
480 // where a numeric string is converted to a smi. | 479 // where a numeric string is converted to a smi. |
481 | 480 |
482 GenerateKeyedLoadReceiverCheck( | 481 GenerateKeyedLoadReceiverCheck( |
483 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); | 482 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); |
484 | 483 |
485 // 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 |
486 // now in ecx. | 485 // now in ecx. |
487 __ test_b(FieldOperand(ecx, Map::kBitField2Offset), | 486 __ test_b(FieldOperand(ecx, Map::kBitField2Offset), |
488 1 << Map::kHasFastElements); | 487 1 << Map::kHasFastElements); |
489 __ j(zero, &check_number_dictionary, not_taken); | 488 __ j(zero, &check_number_dictionary, Label::kFar, not_taken); |
490 | 489 |
491 GenerateFastArrayLoad(masm, | 490 GenerateFastArrayLoad(masm, |
492 edx, | 491 edx, |
493 eax, | 492 eax, |
494 ecx, | 493 ecx, |
495 eax, | 494 eax, |
496 NULL, | 495 NULL, |
497 &slow); | 496 &slow); |
498 Isolate* isolate = masm->isolate(); | 497 Isolate* isolate = masm->isolate(); |
499 Counters* counters = isolate->counters(); | 498 Counters* counters = isolate->counters(); |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { | 656 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { |
658 // ----------- S t a t e ------------- | 657 // ----------- S t a t e ------------- |
659 // -- eax : key | 658 // -- eax : key |
660 // -- edx : receiver | 659 // -- edx : receiver |
661 // -- esp[0] : return address | 660 // -- esp[0] : return address |
662 // ----------------------------------- | 661 // ----------------------------------- |
663 Label slow; | 662 Label slow; |
664 | 663 |
665 // Check that the receiver isn't a smi. | 664 // Check that the receiver isn't a smi. |
666 __ test(edx, Immediate(kSmiTagMask)); | 665 __ test(edx, Immediate(kSmiTagMask)); |
667 __ j(zero, &slow, not_taken); | 666 __ j(zero, &slow, Label::kFar, not_taken); |
668 | 667 |
669 // Check that the key is an array index, that is Uint32. | 668 // Check that the key is an array index, that is Uint32. |
670 __ test(eax, Immediate(kSmiTagMask | kSmiSignMask)); | 669 __ test(eax, Immediate(kSmiTagMask | kSmiSignMask)); |
671 __ j(not_zero, &slow, not_taken); | 670 __ j(not_zero, &slow, Label::kFar, not_taken); |
672 | 671 |
673 // Get the map of the receiver. | 672 // Get the map of the receiver. |
674 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 673 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
675 | 674 |
676 // Check that it has indexed interceptor and access checks | 675 // Check that it has indexed interceptor and access checks |
677 // are not enabled for this object. | 676 // are not enabled for this object. |
678 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); | 677 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset)); |
679 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask)); | 678 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask)); |
680 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor)); | 679 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor)); |
681 __ j(not_zero, &slow, not_taken); | 680 __ j(not_zero, &slow, Label::kFar, not_taken); |
682 | 681 |
683 // Everything is fine, call runtime. | 682 // Everything is fine, call runtime. |
684 __ pop(ecx); | 683 __ pop(ecx); |
685 __ push(edx); // receiver | 684 __ push(edx); // receiver |
686 __ push(eax); // key | 685 __ push(eax); // key |
687 __ push(ecx); // return address | 686 __ push(ecx); // return address |
688 | 687 |
689 // Perform tail call to the entry. | 688 // Perform tail call to the entry. |
690 ExternalReference ref = | 689 ExternalReference ref = |
691 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), | 690 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor), |
(...skipping 10 matching lines...) Expand all Loading... |
702 // ----------- S t a t e ------------- | 701 // ----------- S t a t e ------------- |
703 // -- eax : value | 702 // -- eax : value |
704 // -- ecx : key | 703 // -- ecx : key |
705 // -- edx : receiver | 704 // -- edx : receiver |
706 // -- esp[0] : return address | 705 // -- esp[0] : return address |
707 // ----------------------------------- | 706 // ----------------------------------- |
708 Label slow, fast, array, extra; | 707 Label slow, fast, array, extra; |
709 | 708 |
710 // Check that the object isn't a smi. | 709 // Check that the object isn't a smi. |
711 __ test(edx, Immediate(kSmiTagMask)); | 710 __ test(edx, Immediate(kSmiTagMask)); |
712 __ j(zero, &slow, not_taken); | 711 __ j(zero, &slow, Label::kFar, not_taken); |
713 // Get the map from the receiver. | 712 // Get the map from the receiver. |
714 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | 713 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
715 // Check that the receiver does not require access checks. We need | 714 // Check that the receiver does not require access checks. We need |
716 // 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. |
717 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), | 716 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), |
718 1 << Map::kIsAccessCheckNeeded); | 717 1 << Map::kIsAccessCheckNeeded); |
719 __ j(not_zero, &slow, not_taken); | 718 __ j(not_zero, &slow, Label::kFar, not_taken); |
720 // Check that the key is a smi. | 719 // Check that the key is a smi. |
721 __ test(ecx, Immediate(kSmiTagMask)); | 720 __ test(ecx, Immediate(kSmiTagMask)); |
722 __ j(not_zero, &slow, not_taken); | 721 __ j(not_zero, &slow, Label::kFar, not_taken); |
723 __ CmpInstanceType(edi, JS_ARRAY_TYPE); | 722 __ CmpInstanceType(edi, JS_ARRAY_TYPE); |
724 __ j(equal, &array); | 723 __ j(equal, &array); |
725 // Check that the object is some kind of JS object. | 724 // Check that the object is some kind of JS object. |
726 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); | 725 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE); |
727 __ j(below, &slow, not_taken); | 726 __ j(below, &slow, Label::kFar, not_taken); |
728 | 727 |
729 // Object case: Check key against length in the elements array. | 728 // Object case: Check key against length in the elements array. |
730 // eax: value | 729 // eax: value |
731 // edx: JSObject | 730 // edx: JSObject |
732 // ecx: key (a smi) | 731 // ecx: key (a smi) |
733 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 732 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
734 // Check that the object is in fast mode and writable. | 733 // Check that the object is in fast mode and writable. |
735 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, true); | 734 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, true); |
736 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); | 735 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); |
737 __ j(below, &fast, taken); | 736 __ j(below, &fast, Label::kFar, taken); |
738 | 737 |
739 // Slow case: call runtime. | 738 // Slow case: call runtime. |
740 __ bind(&slow); | 739 __ bind(&slow); |
741 GenerateRuntimeSetProperty(masm, strict_mode); | 740 GenerateRuntimeSetProperty(masm, strict_mode); |
742 | 741 |
743 // Extra capacity case: Check if there is extra capacity to | 742 // Extra capacity case: Check if there is extra capacity to |
744 // perform the store and update the length. Used for adding one | 743 // perform the store and update the length. Used for adding one |
745 // element to the array by writing to array[array.length]. | 744 // element to the array by writing to array[array.length]. |
746 __ bind(&extra); | 745 __ bind(&extra); |
747 // eax: value | 746 // eax: value |
748 // edx: receiver, a JSArray | 747 // edx: receiver, a JSArray |
749 // ecx: key, a smi. | 748 // ecx: key, a smi. |
750 // edi: receiver->elements, a FixedArray | 749 // edi: receiver->elements, a FixedArray |
751 // flags: compare (ecx, edx.length()) | 750 // flags: compare (ecx, edx.length()) |
752 __ j(not_equal, &slow, not_taken); // do not leave holes in the array | 751 // do not leave holes in the array: |
| 752 __ j(not_equal, &slow, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, taken); |
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, Label::kFar, taken); |
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, Label::kFar, not_taken); |
837 __ cmp(edx, FACTORY->false_value()); | 837 __ cmp(edx, FACTORY->false_value()); |
838 __ j(not_equal, &miss, taken); | 838 __ j(not_equal, &miss, Label::kFar, taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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); | 945 __ j(zero, &invoke, Label::kNear, not_taken); |
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); | 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); | 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)); |
956 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 956 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
957 __ bind(&invoke); | 957 __ bind(&invoke); |
958 } | 958 } |
959 | 959 |
960 // Invoke the function. | 960 // Invoke the function. |
961 ParameterCount actual(argc); | 961 ParameterCount actual(argc); |
(...skipping 55 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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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, Label::kFar, not_taken); |
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 |