OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 27 matching lines...) Expand all Loading... |
38 namespace v8 { | 38 namespace v8 { |
39 namespace internal { | 39 namespace internal { |
40 | 40 |
41 // ---------------------------------------------------------------------------- | 41 // ---------------------------------------------------------------------------- |
42 // Static IC stub generators. | 42 // Static IC stub generators. |
43 // | 43 // |
44 | 44 |
45 #define __ ACCESS_MASM(masm) | 45 #define __ ACCESS_MASM(masm) |
46 | 46 |
47 | 47 |
| 48 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, |
| 49 Register type, |
| 50 Label* global_object) { |
| 51 // Register usage: |
| 52 // type: holds the receiver instance type on entry. |
| 53 __ cmpb(type, Immediate(JS_GLOBAL_OBJECT_TYPE)); |
| 54 __ j(equal, global_object); |
| 55 __ cmpb(type, Immediate(JS_BUILTINS_OBJECT_TYPE)); |
| 56 __ j(equal, global_object); |
| 57 __ cmpb(type, Immediate(JS_GLOBAL_PROXY_TYPE)); |
| 58 __ j(equal, global_object); |
| 59 } |
| 60 |
| 61 |
| 62 // Generated code falls through if the receiver is a regular non-global |
| 63 // JS object with slow properties and no interceptors. |
| 64 static void GenerateDictionaryLoadReceiverCheck(MacroAssembler* masm, |
| 65 Register receiver, |
| 66 Register r0, |
| 67 Register r1, |
| 68 Label* miss) { |
| 69 // Register usage: |
| 70 // receiver: holds the receiver on entry and is unchanged. |
| 71 // r0: used to hold receiver instance type. |
| 72 // Holds the property dictionary on fall through. |
| 73 // r1: used to hold receivers map. |
| 74 |
| 75 __ JumpIfSmi(receiver, miss); |
| 76 |
| 77 // Check that the receiver is a valid JS object. |
| 78 __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 79 __ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset)); |
| 80 __ cmpb(r0, Immediate(FIRST_JS_OBJECT_TYPE)); |
| 81 __ j(below, miss); |
| 82 |
| 83 // If this assert fails, we have to check upper bound too. |
| 84 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| 85 |
| 86 GenerateGlobalInstanceTypeCheck(masm, r0, miss); |
| 87 |
| 88 // Check for non-global object that requires access check. |
| 89 __ testb(FieldOperand(r1, Map::kBitFieldOffset), |
| 90 Immediate((1 << Map::kIsAccessCheckNeeded) | |
| 91 (1 << Map::kHasNamedInterceptor))); |
| 92 __ j(not_zero, miss); |
| 93 |
| 94 __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
| 95 __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset), |
| 96 Heap::kHashTableMapRootIndex); |
| 97 __ j(not_equal, miss); |
| 98 } |
| 99 |
| 100 |
48 // Helper function used to load a property from a dictionary backing storage. | 101 // Helper function used to load a property from a dictionary backing storage. |
49 // This function may return false negatives, so miss_label | 102 // This function may return false negatives, so miss_label |
50 // must always call a backup property load that is complete. | 103 // must always call a backup property load that is complete. |
51 // This function is safe to call if the receiver has fast properties, | 104 // This function is safe to call if name is not a symbol, and will jump to |
52 // or if name is not a symbol, and will jump to the miss_label in that case. | 105 // the miss_label in that case. |
| 106 // The generated code assumes that the receiver has slow properties, |
| 107 // is not a global object and does not have interceptors. |
53 static void GenerateDictionaryLoad(MacroAssembler* masm, | 108 static void GenerateDictionaryLoad(MacroAssembler* masm, |
54 Label* miss_label, | 109 Label* miss_label, |
| 110 Register elements, |
| 111 Register name, |
55 Register r0, | 112 Register r0, |
56 Register r1, | 113 Register r1, |
57 Register r2, | 114 Register result) { |
58 Register name, | |
59 Register r4, | |
60 Register result, | |
61 DictionaryCheck check_dictionary) { | |
62 // Register use: | 115 // Register use: |
63 // | 116 // |
64 // r0 - used to hold the property dictionary and is unchanged. | 117 // elements - holds the property dictionary on entry and is unchanged. |
65 // | 118 // |
66 // r1 - used to hold the receiver and is unchanged. | 119 // name - holds the name of the property on entry and is unchanged. |
67 // | 120 // |
68 // r2 - used to hold the capacity of the property dictionary. | 121 // r0 - used to hold the capacity of the property dictionary. |
69 // | 122 // |
70 // name - holds the name of the property and is unchanged. | 123 // r1 - used to hold the index into the property dictionary. |
71 // | |
72 // r4 - used to hold the index into the property dictionary. | |
73 // | 124 // |
74 // result - holds the result on exit if the load succeeded. | 125 // result - holds the result on exit if the load succeeded. |
75 | 126 |
76 Label done; | 127 Label done; |
77 | 128 |
78 // Check for the absence of an interceptor. | |
79 // Load the map into r0. | |
80 __ movq(r0, FieldOperand(r1, JSObject::kMapOffset)); | |
81 | |
82 // Bail out if the receiver has a named interceptor. | |
83 __ testl(FieldOperand(r0, Map::kBitFieldOffset), | |
84 Immediate(1 << Map::kHasNamedInterceptor)); | |
85 __ j(not_zero, miss_label); | |
86 | |
87 // Bail out if we have a JS global proxy object. | |
88 __ movzxbq(r0, FieldOperand(r0, Map::kInstanceTypeOffset)); | |
89 __ cmpb(r0, Immediate(JS_GLOBAL_PROXY_TYPE)); | |
90 __ j(equal, miss_label); | |
91 | |
92 // Possible work-around for http://crbug.com/16276. | |
93 __ cmpb(r0, Immediate(JS_GLOBAL_OBJECT_TYPE)); | |
94 __ j(equal, miss_label); | |
95 __ cmpb(r0, Immediate(JS_BUILTINS_OBJECT_TYPE)); | |
96 __ j(equal, miss_label); | |
97 | |
98 // Load properties array. | |
99 __ movq(r0, FieldOperand(r1, JSObject::kPropertiesOffset)); | |
100 | |
101 if (check_dictionary == CHECK_DICTIONARY) { | |
102 // Check that the properties array is a dictionary. | |
103 __ Cmp(FieldOperand(r0, HeapObject::kMapOffset), Factory::hash_table_map()); | |
104 __ j(not_equal, miss_label); | |
105 } | |
106 | |
107 // Compute the capacity mask. | 129 // Compute the capacity mask. |
108 const int kCapacityOffset = | 130 const int kCapacityOffset = |
109 StringDictionary::kHeaderSize + | 131 StringDictionary::kHeaderSize + |
110 StringDictionary::kCapacityIndex * kPointerSize; | 132 StringDictionary::kCapacityIndex * kPointerSize; |
111 __ SmiToInteger32(r2, FieldOperand(r0, kCapacityOffset)); | 133 __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset)); |
112 __ decl(r2); | 134 __ decl(r0); |
113 | 135 |
114 // Generate an unrolled loop that performs a few probes before | 136 // Generate an unrolled loop that performs a few probes before |
115 // giving up. Measurements done on Gmail indicate that 2 probes | 137 // giving up. Measurements done on Gmail indicate that 2 probes |
116 // cover ~93% of loads from dictionaries. | 138 // cover ~93% of loads from dictionaries. |
117 static const int kProbes = 4; | 139 static const int kProbes = 4; |
118 const int kElementsStartOffset = | 140 const int kElementsStartOffset = |
119 StringDictionary::kHeaderSize + | 141 StringDictionary::kHeaderSize + |
120 StringDictionary::kElementsStartIndex * kPointerSize; | 142 StringDictionary::kElementsStartIndex * kPointerSize; |
121 for (int i = 0; i < kProbes; i++) { | 143 for (int i = 0; i < kProbes; i++) { |
122 // Compute the masked index: (hash + i + i * i) & mask. | 144 // Compute the masked index: (hash + i + i * i) & mask. |
123 __ movl(r4, FieldOperand(name, String::kHashFieldOffset)); | 145 __ movl(r1, FieldOperand(name, String::kHashFieldOffset)); |
124 __ shrl(r4, Immediate(String::kHashShift)); | 146 __ shrl(r1, Immediate(String::kHashShift)); |
125 if (i > 0) { | 147 if (i > 0) { |
126 __ addl(r4, Immediate(StringDictionary::GetProbeOffset(i))); | 148 __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i))); |
127 } | 149 } |
128 __ and_(r4, r2); | 150 __ and_(r1, r0); |
129 | 151 |
130 // Scale the index by multiplying by the entry size. | 152 // Scale the index by multiplying by the entry size. |
131 ASSERT(StringDictionary::kEntrySize == 3); | 153 ASSERT(StringDictionary::kEntrySize == 3); |
132 __ lea(r4, Operand(r4, r4, times_2, 0)); // r4 = r4 * 3 | 154 __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 |
133 | 155 |
134 // Check if the key is identical to the name. | 156 // Check if the key is identical to the name. |
135 __ cmpq(name, Operand(r0, r4, times_pointer_size, | 157 __ cmpq(name, Operand(elements, r1, times_pointer_size, |
136 kElementsStartOffset - kHeapObjectTag)); | 158 kElementsStartOffset - kHeapObjectTag)); |
137 if (i != kProbes - 1) { | 159 if (i != kProbes - 1) { |
138 __ j(equal, &done); | 160 __ j(equal, &done); |
139 } else { | 161 } else { |
140 __ j(not_equal, miss_label); | 162 __ j(not_equal, miss_label); |
141 } | 163 } |
142 } | 164 } |
143 | 165 |
144 // Check that the value is a normal property. | 166 // Check that the value is a normal property. |
145 __ bind(&done); | 167 __ bind(&done); |
146 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 168 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
147 __ Test(Operand(r0, r4, times_pointer_size, kDetailsOffset - kHeapObjectTag), | 169 __ Test(Operand(elements, r1, times_pointer_size, |
| 170 kDetailsOffset - kHeapObjectTag), |
148 Smi::FromInt(PropertyDetails::TypeField::mask())); | 171 Smi::FromInt(PropertyDetails::TypeField::mask())); |
149 __ j(not_zero, miss_label); | 172 __ j(not_zero, miss_label); |
150 | 173 |
151 // Get the value at the masked, scaled index. | 174 // Get the value at the masked, scaled index. |
152 const int kValueOffset = kElementsStartOffset + kPointerSize; | 175 const int kValueOffset = kElementsStartOffset + kPointerSize; |
153 __ movq(result, | 176 __ movq(result, |
154 Operand(r0, r4, times_pointer_size, kValueOffset - kHeapObjectTag)); | 177 Operand(elements, r1, times_pointer_size, |
| 178 kValueOffset - kHeapObjectTag)); |
155 } | 179 } |
156 | 180 |
157 | 181 |
158 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | 182 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
159 Label* miss, | 183 Label* miss, |
160 Register elements, | 184 Register elements, |
161 Register key, | 185 Register key, |
162 Register r0, | 186 Register r0, |
163 Register r1, | 187 Register r1, |
164 Register r2, | 188 Register r2, |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 } | 344 } |
321 | 345 |
322 | 346 |
323 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 347 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
324 // ----------- S t a t e ------------- | 348 // ----------- S t a t e ------------- |
325 // -- rax : key | 349 // -- rax : key |
326 // -- rdx : receiver | 350 // -- rdx : receiver |
327 // -- rsp[0] : return address | 351 // -- rsp[0] : return address |
328 // ----------------------------------- | 352 // ----------------------------------- |
329 | 353 |
| 354 __ IncrementCounter(&Counters::keyed_load_miss, 1); |
| 355 |
330 __ pop(rbx); | 356 __ pop(rbx); |
331 __ push(rdx); // receiver | 357 __ push(rdx); // receiver |
332 __ push(rax); // name | 358 __ push(rax); // name |
333 __ push(rbx); // return address | 359 __ push(rbx); // return address |
334 | 360 |
335 // Perform tail call to the entry. | 361 // Perform tail call to the entry. |
336 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss)); | 362 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss)); |
337 __ TailCallExternalReference(ref, 2, 1); | 363 __ TailCallExternalReference(ref, 2, 1); |
338 } | 364 } |
339 | 365 |
(...skipping 13 matching lines...) Expand all Loading... |
353 // Perform tail call to the entry. | 379 // Perform tail call to the entry. |
354 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 380 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
355 } | 381 } |
356 | 382 |
357 | 383 |
358 // Checks the receiver for special cases (value type, slow case bits). | 384 // Checks the receiver for special cases (value type, slow case bits). |
359 // Falls through for regular JS object. | 385 // Falls through for regular JS object. |
360 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, | 386 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, |
361 Register receiver, | 387 Register receiver, |
362 Register map, | 388 Register map, |
| 389 int interceptor_bit, |
363 Label* slow) { | 390 Label* slow) { |
364 // Register use: | 391 // Register use: |
365 // receiver - holds the receiver and is unchanged. | 392 // receiver - holds the receiver and is unchanged. |
366 // Scratch registers: | 393 // Scratch registers: |
367 // map - used to hold the map of the receiver. | 394 // map - used to hold the map of the receiver. |
368 | 395 |
369 // Check that the object isn't a smi. | 396 // Check that the object isn't a smi. |
370 __ JumpIfSmi(receiver, slow); | 397 __ JumpIfSmi(receiver, slow); |
371 | 398 |
372 // Check that the object is some kind of JS object EXCEPT JS Value type. | 399 // Check that the object is some kind of JS object EXCEPT JS Value type. |
373 // In the case that the object is a value-wrapper object, | 400 // In the case that the object is a value-wrapper object, |
374 // we enter the runtime system to make sure that indexing | 401 // we enter the runtime system to make sure that indexing |
375 // into string objects work as intended. | 402 // into string objects work as intended. |
376 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 403 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
377 __ CmpObjectType(receiver, JS_OBJECT_TYPE, map); | 404 __ CmpObjectType(receiver, JS_OBJECT_TYPE, map); |
378 __ j(below, slow); | 405 __ j(below, slow); |
379 | 406 |
380 // Check bit field. | 407 // Check bit field. |
381 __ testb(FieldOperand(map, Map::kBitFieldOffset), | 408 __ testb(FieldOperand(map, Map::kBitFieldOffset), |
382 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask)); | 409 Immediate((1 << Map::kIsAccessCheckNeeded) | |
| 410 (1 << interceptor_bit))); |
383 __ j(not_zero, slow); | 411 __ j(not_zero, slow); |
384 } | 412 } |
385 | 413 |
386 | 414 |
387 // Loads an indexed element from a fast case array. | 415 // Loads an indexed element from a fast case array. |
388 static void GenerateFastArrayLoad(MacroAssembler* masm, | 416 static void GenerateFastArrayLoad(MacroAssembler* masm, |
389 Register receiver, | 417 Register receiver, |
390 Register key, | 418 Register key, |
391 Register elements, | 419 Register elements, |
392 Register scratch, | 420 Register scratch, |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 | 521 |
494 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 522 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
495 // ----------- S t a t e ------------- | 523 // ----------- S t a t e ------------- |
496 // -- rax : key | 524 // -- rax : key |
497 // -- rdx : receiver | 525 // -- rdx : receiver |
498 // -- rsp[0] : return address | 526 // -- rsp[0] : return address |
499 // ----------------------------------- | 527 // ----------------------------------- |
500 Label slow, check_string, index_smi, index_string; | 528 Label slow, check_string, index_smi, index_string; |
501 Label check_pixel_array, probe_dictionary, check_number_dictionary; | 529 Label check_pixel_array, probe_dictionary, check_number_dictionary; |
502 | 530 |
503 GenerateKeyedLoadReceiverCheck(masm, rdx, rcx, &slow); | |
504 | |
505 // Check that the key is a smi. | 531 // Check that the key is a smi. |
506 __ JumpIfNotSmi(rax, &check_string); | 532 __ JumpIfNotSmi(rax, &check_string); |
507 __ bind(&index_smi); | 533 __ bind(&index_smi); |
508 // Now the key is known to be a smi. This place is also jumped to from below | 534 // Now the key is known to be a smi. This place is also jumped to from below |
509 // where a numeric string is converted to a smi. | 535 // where a numeric string is converted to a smi. |
510 | 536 |
| 537 GenerateKeyedLoadReceiverCheck( |
| 538 masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow); |
| 539 |
511 GenerateFastArrayLoad(masm, | 540 GenerateFastArrayLoad(masm, |
512 rdx, | 541 rdx, |
513 rax, | 542 rax, |
514 rcx, | 543 rcx, |
515 rbx, | 544 rbx, |
516 rax, | 545 rax, |
517 &check_pixel_array, | 546 &check_pixel_array, |
518 &slow); | 547 &slow); |
519 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); | 548 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); |
520 __ ret(0); | 549 __ ret(0); |
(...skipping 29 matching lines...) Expand all Loading... |
550 __ bind(&slow); | 579 __ bind(&slow); |
551 // Slow case: Jump to runtime. | 580 // Slow case: Jump to runtime. |
552 // rdx: receiver | 581 // rdx: receiver |
553 // rax: key | 582 // rax: key |
554 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); | 583 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); |
555 GenerateRuntimeGetProperty(masm); | 584 GenerateRuntimeGetProperty(masm); |
556 | 585 |
557 __ bind(&check_string); | 586 __ bind(&check_string); |
558 GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow); | 587 GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow); |
559 | 588 |
| 589 GenerateKeyedLoadReceiverCheck( |
| 590 masm, rdx, rcx, Map::kHasNamedInterceptor, &slow); |
| 591 |
560 // If the receiver is a fast-case object, check the keyed lookup | 592 // If the receiver is a fast-case object, check the keyed lookup |
561 // cache. Otherwise probe the dictionary leaving result in rcx. | 593 // cache. Otherwise probe the dictionary leaving result in rcx. |
562 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); | 594 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); |
563 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | 595 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
564 Heap::kHashTableMapRootIndex); | 596 Heap::kHashTableMapRootIndex); |
565 __ j(equal, &probe_dictionary); | 597 __ j(equal, &probe_dictionary); |
566 | 598 |
567 // Load the map of the receiver, compute the keyed lookup cache hash | 599 // Load the map of the receiver, compute the keyed lookup cache hash |
568 // based on 32 bits of the map pointer and the string hash. | 600 // based on 32 bits of the map pointer and the string hash. |
569 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | 601 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
601 __ addq(rcx, rdi); | 633 __ addq(rcx, rdi); |
602 __ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0)); | 634 __ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0)); |
603 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1); | 635 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1); |
604 __ ret(0); | 636 __ ret(0); |
605 | 637 |
606 // Do a quick inline probe of the receiver's dictionary, if it | 638 // Do a quick inline probe of the receiver's dictionary, if it |
607 // exists. | 639 // exists. |
608 __ bind(&probe_dictionary); | 640 __ bind(&probe_dictionary); |
609 // rdx: receiver | 641 // rdx: receiver |
610 // rax: key | 642 // rax: key |
611 GenerateDictionaryLoad(masm, | 643 // rbx: elements |
612 &slow, | 644 |
613 rbx, | 645 __ movq(rcx, FieldOperand(rdx, JSObject::kMapOffset)); |
614 rdx, | 646 __ movb(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset)); |
615 rcx, | 647 GenerateGlobalInstanceTypeCheck(masm, rcx, &slow); |
616 rax, | 648 |
617 rdi, | 649 GenerateDictionaryLoad(masm, &slow, rbx, rax, rcx, rdi, rax); |
618 rax, | |
619 DICTIONARY_CHECK_DONE); | |
620 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); | 650 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); |
621 __ ret(0); | 651 __ ret(0); |
622 | 652 |
623 __ bind(&index_string); | 653 __ bind(&index_string); |
624 GenerateIndexFromHash(masm, rax, rbx); | 654 GenerateIndexFromHash(masm, rax, rbx); |
625 __ jmp(&index_smi); | 655 __ jmp(&index_smi); |
626 } | 656 } |
627 | 657 |
628 | 658 |
629 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { | 659 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { |
(...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1205 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { | 1235 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { |
1206 // ----------- S t a t e ------------- | 1236 // ----------- S t a t e ------------- |
1207 // rcx : function name | 1237 // rcx : function name |
1208 // rsp[0] : return address | 1238 // rsp[0] : return address |
1209 // rsp[8] : argument argc | 1239 // rsp[8] : argument argc |
1210 // rsp[16] : argument argc - 1 | 1240 // rsp[16] : argument argc - 1 |
1211 // ... | 1241 // ... |
1212 // rsp[argc * 8] : argument 1 | 1242 // rsp[argc * 8] : argument 1 |
1213 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1243 // rsp[(argc + 1) * 8] : argument 0 = receiver |
1214 // ----------------------------------- | 1244 // ----------------------------------- |
| 1245 |
| 1246 if (id == IC::kCallIC_Miss) { |
| 1247 __ IncrementCounter(&Counters::call_miss, 1); |
| 1248 } else { |
| 1249 __ IncrementCounter(&Counters::keyed_call_miss, 1); |
| 1250 } |
| 1251 |
1215 // Get the receiver of the function from the stack; 1 ~ return address. | 1252 // Get the receiver of the function from the stack; 1 ~ return address. |
1216 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | 1253 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
1217 | 1254 |
1218 // Enter an internal frame. | 1255 // Enter an internal frame. |
1219 __ EnterInternalFrame(); | 1256 __ EnterInternalFrame(); |
1220 | 1257 |
1221 // Push the receiver and the name of the function. | 1258 // Push the receiver and the name of the function. |
1222 __ push(rdx); | 1259 __ push(rdx); |
1223 __ push(rcx); | 1260 __ push(rcx); |
1224 | 1261 |
1225 // Call the entry. | 1262 // Call the entry. |
1226 CEntryStub stub(1); | 1263 CEntryStub stub(1); |
1227 __ movq(rax, Immediate(2)); | 1264 __ movq(rax, Immediate(2)); |
1228 __ movq(rbx, ExternalReference(IC_Utility(id))); | 1265 __ movq(rbx, ExternalReference(IC_Utility(id))); |
1229 __ CallStub(&stub); | 1266 __ CallStub(&stub); |
1230 | 1267 |
1231 // Move result to rdi and exit the internal frame. | 1268 // Move result to rdi and exit the internal frame. |
1232 __ movq(rdi, rax); | 1269 __ movq(rdi, rax); |
1233 __ LeaveInternalFrame(); | 1270 __ LeaveInternalFrame(); |
1234 | 1271 |
1235 // Check if the receiver is a global object of some sort. | 1272 // Check if the receiver is a global object of some sort. |
1236 Label invoke, global; | 1273 // This can happen only for regular CallIC but not KeyedCallIC. |
1237 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver | 1274 if (id == IC::kCallIC_Miss) { |
1238 __ JumpIfSmi(rdx, &invoke); | 1275 Label invoke, global; |
1239 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx); | 1276 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver |
1240 __ j(equal, &global); | 1277 __ JumpIfSmi(rdx, &invoke); |
1241 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE); | 1278 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx); |
1242 __ j(not_equal, &invoke); | 1279 __ j(equal, &global); |
| 1280 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE); |
| 1281 __ j(not_equal, &invoke); |
1243 | 1282 |
1244 // Patch the receiver on the stack. | 1283 // Patch the receiver on the stack. |
1245 __ bind(&global); | 1284 __ bind(&global); |
1246 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); | 1285 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); |
1247 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); | 1286 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); |
| 1287 __ bind(&invoke); |
| 1288 } |
1248 | 1289 |
1249 // Invoke the function. | 1290 // Invoke the function. |
1250 ParameterCount actual(argc); | 1291 ParameterCount actual(argc); |
1251 __ bind(&invoke); | |
1252 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | 1292 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
1253 } | 1293 } |
1254 | 1294 |
1255 | 1295 |
1256 // The generated code does not accept smi keys. | 1296 // The generated code does not accept smi keys. |
1257 // The generated code falls through if both probes miss. | 1297 // The generated code falls through if both probes miss. |
1258 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, | 1298 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, |
1259 int argc, | 1299 int argc, |
1260 Code::Kind kind) { | 1300 Code::Kind kind) { |
1261 // ----------- S t a t e ------------- | 1301 // ----------- S t a t e ------------- |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1302 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx); | 1342 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx); |
1303 | 1343 |
1304 // Probe the stub cache for the value object. | 1344 // Probe the stub cache for the value object. |
1305 __ bind(&probe); | 1345 __ bind(&probe); |
1306 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg); | 1346 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg); |
1307 | 1347 |
1308 __ bind(&miss); | 1348 __ bind(&miss); |
1309 } | 1349 } |
1310 | 1350 |
1311 | 1351 |
1312 static void GenerateNormalHelper(MacroAssembler* masm, | 1352 static void GenerateFunctionTailCall(MacroAssembler* masm, |
1313 int argc, | 1353 int argc, |
1314 bool is_global_object, | 1354 Label* miss) { |
1315 Label* miss) { | |
1316 // ----------- S t a t e ------------- | 1355 // ----------- S t a t e ------------- |
1317 // rcx : function name | 1356 // rcx : function name |
1318 // rdx : receiver | 1357 // rdi : function |
1319 // rsp[0] : return address | 1358 // rsp[0] : return address |
1320 // rsp[8] : argument argc | 1359 // rsp[8] : argument argc |
1321 // rsp[16] : argument argc - 1 | 1360 // rsp[16] : argument argc - 1 |
1322 // ... | 1361 // ... |
1323 // rsp[argc * 8] : argument 1 | 1362 // rsp[argc * 8] : argument 1 |
1324 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1363 // rsp[(argc + 1) * 8] : argument 0 = receiver |
1325 // ----------------------------------- | 1364 // ----------------------------------- |
1326 // Search dictionary - put result in register rdx. | |
1327 GenerateDictionaryLoad( | |
1328 masm, miss, rax, rdx, rbx, rcx, rdi, rdi, CHECK_DICTIONARY); | |
1329 | |
1330 __ JumpIfSmi(rdi, miss); | 1365 __ JumpIfSmi(rdi, miss); |
1331 // Check that the value is a JavaScript function. | 1366 // Check that the value is a JavaScript function. |
1332 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx); | 1367 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx); |
1333 __ j(not_equal, miss); | 1368 __ j(not_equal, miss); |
1334 | 1369 |
1335 // Patch the receiver with the global proxy if necessary. | |
1336 if (is_global_object) { | |
1337 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); | |
1338 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); | |
1339 } | |
1340 | |
1341 // Invoke the function. | 1370 // Invoke the function. |
1342 ParameterCount actual(argc); | 1371 ParameterCount actual(argc); |
1343 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | 1372 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
1344 } | 1373 } |
1345 | 1374 |
1346 | 1375 |
1347 // The generated code falls through if the call should be handled by runtime. | 1376 // The generated code falls through if the call should be handled by runtime. |
1348 static void GenerateCallNormal(MacroAssembler* masm, int argc) { | 1377 static void GenerateCallNormal(MacroAssembler* masm, int argc) { |
1349 // ----------- S t a t e ------------- | 1378 // ----------- S t a t e ------------- |
1350 // rcx : function name | 1379 // rcx : function name |
1351 // rsp[0] : return address | 1380 // rsp[0] : return address |
1352 // rsp[8] : argument argc | 1381 // rsp[8] : argument argc |
1353 // rsp[16] : argument argc - 1 | 1382 // rsp[16] : argument argc - 1 |
1354 // ... | 1383 // ... |
1355 // rsp[argc * 8] : argument 1 | 1384 // rsp[argc * 8] : argument 1 |
1356 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1385 // rsp[(argc + 1) * 8] : argument 0 = receiver |
1357 // ----------------------------------- | 1386 // ----------------------------------- |
1358 Label miss, global_object, non_global_object; | 1387 Label miss; |
1359 | 1388 |
1360 // Get the receiver of the function from the stack. | 1389 // Get the receiver of the function from the stack. |
1361 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | 1390 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
1362 | 1391 |
1363 // Check that the receiver isn't a smi. | 1392 GenerateDictionaryLoadReceiverCheck(masm, rdx, rax, rbx, &miss); |
1364 __ JumpIfSmi(rdx, &miss); | |
1365 | 1393 |
1366 // Check that the receiver is a valid JS object. | 1394 // rax: elements |
1367 // Because there are so many map checks and type checks, do not | 1395 // Search the dictionary placing the result in rdi. |
1368 // use CmpObjectType, but load map and type into registers. | 1396 GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi); |
1369 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | |
1370 __ movb(rax, FieldOperand(rbx, Map::kInstanceTypeOffset)); | |
1371 __ cmpb(rax, Immediate(FIRST_JS_OBJECT_TYPE)); | |
1372 __ j(below, &miss); | |
1373 | 1397 |
1374 // If this assert fails, we have to check upper bound too. | 1398 GenerateFunctionTailCall(masm, argc, &miss); |
1375 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | |
1376 | |
1377 // Check for access to global object. | |
1378 __ cmpb(rax, Immediate(JS_GLOBAL_OBJECT_TYPE)); | |
1379 __ j(equal, &global_object); | |
1380 __ cmpb(rax, Immediate(JS_BUILTINS_OBJECT_TYPE)); | |
1381 __ j(not_equal, &non_global_object); | |
1382 | |
1383 // Accessing global object: Load and invoke. | |
1384 __ bind(&global_object); | |
1385 // Check that the global object does not require access checks. | |
1386 __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset)); | |
1387 __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded)); | |
1388 __ j(not_equal, &miss); | |
1389 GenerateNormalHelper(masm, argc, true, &miss); | |
1390 | |
1391 // Accessing non-global object: Check for access to global proxy. | |
1392 Label global_proxy, invoke; | |
1393 __ bind(&non_global_object); | |
1394 __ cmpb(rax, Immediate(JS_GLOBAL_PROXY_TYPE)); | |
1395 __ j(equal, &global_proxy); | |
1396 // Check that the non-global, non-global-proxy object does not | |
1397 // require access checks. | |
1398 __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset)); | |
1399 __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded)); | |
1400 __ j(not_equal, &miss); | |
1401 __ bind(&invoke); | |
1402 GenerateNormalHelper(masm, argc, false, &miss); | |
1403 | |
1404 // Global object proxy access: Check access rights. | |
1405 __ bind(&global_proxy); | |
1406 __ CheckAccessGlobalProxy(rdx, rax, &miss); | |
1407 __ jmp(&invoke); | |
1408 | 1399 |
1409 __ bind(&miss); | 1400 __ bind(&miss); |
1410 } | 1401 } |
1411 | 1402 |
1412 | 1403 |
1413 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { | 1404 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { |
1414 // ----------- S t a t e ------------- | 1405 // ----------- S t a t e ------------- |
1415 // rcx : function name | 1406 // rcx : function name |
1416 // rsp[0] : return address | 1407 // rsp[0] : return address |
1417 // rsp[8] : argument argc | 1408 // rsp[8] : argument argc |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1491 Label check_number_dictionary, check_string, lookup_monomorphic_cache; | 1482 Label check_number_dictionary, check_string, lookup_monomorphic_cache; |
1492 Label index_smi, index_string; | 1483 Label index_smi, index_string; |
1493 | 1484 |
1494 // Check that the key is a smi. | 1485 // Check that the key is a smi. |
1495 __ JumpIfNotSmi(rcx, &check_string); | 1486 __ JumpIfNotSmi(rcx, &check_string); |
1496 | 1487 |
1497 __ bind(&index_smi); | 1488 __ bind(&index_smi); |
1498 // Now the key is known to be a smi. This place is also jumped to from below | 1489 // Now the key is known to be a smi. This place is also jumped to from below |
1499 // where a numeric string is converted to a smi. | 1490 // where a numeric string is converted to a smi. |
1500 | 1491 |
1501 GenerateKeyedLoadReceiverCheck(masm, rdx, rax, &slow_call); | 1492 GenerateKeyedLoadReceiverCheck( |
| 1493 masm, rdx, rax, Map::kHasIndexedInterceptor, &slow_call); |
1502 | 1494 |
1503 GenerateFastArrayLoad( | 1495 GenerateFastArrayLoad( |
1504 masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load); | 1496 masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load); |
1505 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1); | 1497 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1); |
1506 | 1498 |
1507 __ bind(&do_call); | 1499 __ bind(&do_call); |
1508 // receiver in rdx is not used after this point. | 1500 // receiver in rdx is not used after this point. |
1509 // rcx: key | 1501 // rcx: key |
1510 // rdi: function | 1502 // rdi: function |
1511 | 1503 GenerateFunctionTailCall(masm, argc, &slow_call); |
1512 // Check that the value in edi is a JavaScript function. | |
1513 __ JumpIfSmi(rdi, &slow_call); | |
1514 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax); | |
1515 __ j(not_equal, &slow_call); | |
1516 // Invoke the function. | |
1517 ParameterCount actual(argc); | |
1518 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | |
1519 | 1504 |
1520 __ bind(&check_number_dictionary); | 1505 __ bind(&check_number_dictionary); |
1521 // eax: elements | 1506 // eax: elements |
1522 // ecx: smi key | 1507 // ecx: smi key |
1523 // Check whether the elements is a number dictionary. | 1508 // Check whether the elements is a number dictionary. |
1524 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 1509 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
1525 Heap::kHashTableMapRootIndex); | 1510 Heap::kHashTableMapRootIndex); |
| 1511 __ j(not_equal, &slow_load); |
1526 __ SmiToInteger32(rbx, rcx); | 1512 __ SmiToInteger32(rbx, rcx); |
1527 // ebx: untagged index | 1513 // ebx: untagged index |
1528 GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi); | 1514 GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi); |
1529 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1); | 1515 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1); |
1530 __ jmp(&do_call); | 1516 __ jmp(&do_call); |
1531 | 1517 |
1532 __ bind(&slow_load); | 1518 __ bind(&slow_load); |
1533 // This branch is taken when calling KeyedCallIC_Miss is neither required | 1519 // This branch is taken when calling KeyedCallIC_Miss is neither required |
1534 // nor beneficial. | 1520 // nor beneficial. |
1535 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1); | 1521 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1); |
1536 __ EnterInternalFrame(); | 1522 __ EnterInternalFrame(); |
1537 __ push(rcx); // save the key | 1523 __ push(rcx); // save the key |
1538 __ push(rdx); // pass the receiver | 1524 __ push(rdx); // pass the receiver |
1539 __ push(rcx); // pass the key | 1525 __ push(rcx); // pass the key |
1540 __ CallRuntime(Runtime::kKeyedGetProperty, 2); | 1526 __ CallRuntime(Runtime::kKeyedGetProperty, 2); |
1541 __ pop(rcx); // restore the key | 1527 __ pop(rcx); // restore the key |
1542 __ LeaveInternalFrame(); | 1528 __ LeaveInternalFrame(); |
1543 __ movq(rdi, rax); | 1529 __ movq(rdi, rax); |
1544 __ jmp(&do_call); | 1530 __ jmp(&do_call); |
1545 | 1531 |
1546 __ bind(&check_string); | 1532 __ bind(&check_string); |
1547 GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call); | 1533 GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call); |
1548 | 1534 |
1549 // The key is known to be a symbol. | 1535 // The key is known to be a symbol. |
1550 // If the receiver is a regular JS object with slow properties then do | 1536 // If the receiver is a regular JS object with slow properties then do |
1551 // a quick inline probe of the receiver's dictionary. | 1537 // a quick inline probe of the receiver's dictionary. |
1552 // Otherwise do the monomorphic cache probe. | 1538 // Otherwise do the monomorphic cache probe. |
1553 GenerateKeyedLoadReceiverCheck(masm, rdx, rax, &lookup_monomorphic_cache); | 1539 GenerateKeyedLoadReceiverCheck( |
| 1540 masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); |
1554 | 1541 |
1555 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); | 1542 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); |
1556 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | 1543 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
1557 Heap::kHashTableMapRootIndex); | 1544 Heap::kHashTableMapRootIndex); |
1558 __ j(not_equal, &lookup_monomorphic_cache); | 1545 __ j(not_equal, &lookup_monomorphic_cache); |
1559 | 1546 |
1560 GenerateDictionaryLoad( | 1547 GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi); |
1561 masm, &slow_load, rbx, rdx, rax, rcx, rdi, rdi, DICTIONARY_CHECK_DONE); | |
1562 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1); | 1548 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1); |
1563 __ jmp(&do_call); | 1549 __ jmp(&do_call); |
1564 | 1550 |
1565 __ bind(&lookup_monomorphic_cache); | 1551 __ bind(&lookup_monomorphic_cache); |
1566 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1); | 1552 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1); |
1567 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); | 1553 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); |
1568 // Fall through on miss. | 1554 // Fall through on miss. |
1569 | 1555 |
1570 __ bind(&slow_call); | 1556 __ bind(&slow_call); |
1571 // This branch is taken if: | 1557 // This branch is taken if: |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1613 } | 1599 } |
1614 | 1600 |
1615 | 1601 |
1616 void LoadIC::GenerateMiss(MacroAssembler* masm) { | 1602 void LoadIC::GenerateMiss(MacroAssembler* masm) { |
1617 // ----------- S t a t e ------------- | 1603 // ----------- S t a t e ------------- |
1618 // -- rax : receiver | 1604 // -- rax : receiver |
1619 // -- rcx : name | 1605 // -- rcx : name |
1620 // -- rsp[0] : return address | 1606 // -- rsp[0] : return address |
1621 // ----------------------------------- | 1607 // ----------------------------------- |
1622 | 1608 |
| 1609 __ IncrementCounter(&Counters::load_miss, 1); |
| 1610 |
1623 __ pop(rbx); | 1611 __ pop(rbx); |
1624 __ push(rax); // receiver | 1612 __ push(rax); // receiver |
1625 __ push(rcx); // name | 1613 __ push(rcx); // name |
1626 __ push(rbx); // return address | 1614 __ push(rbx); // return address |
1627 | 1615 |
1628 // Perform tail call to the entry. | 1616 // Perform tail call to the entry. |
1629 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); | 1617 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); |
1630 __ TailCallExternalReference(ref, 2, 1); | 1618 __ TailCallExternalReference(ref, 2, 1); |
1631 } | 1619 } |
1632 | 1620 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1676 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 1664 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
1677 } | 1665 } |
1678 | 1666 |
1679 | 1667 |
1680 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 1668 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
1681 // ----------- S t a t e ------------- | 1669 // ----------- S t a t e ------------- |
1682 // -- rax : receiver | 1670 // -- rax : receiver |
1683 // -- rcx : name | 1671 // -- rcx : name |
1684 // -- rsp[0] : return address | 1672 // -- rsp[0] : return address |
1685 // ----------------------------------- | 1673 // ----------------------------------- |
1686 Label miss, probe, global; | 1674 Label miss; |
1687 | 1675 |
1688 // Check that the receiver isn't a smi. | 1676 GenerateDictionaryLoadReceiverCheck(masm, rax, rdx, rbx, &miss); |
1689 __ JumpIfSmi(rax, &miss); | |
1690 | 1677 |
1691 // Check that the receiver is a valid JS object. | 1678 // rdx: elements |
1692 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | |
1693 __ j(below, &miss); | |
1694 | |
1695 // If this assert fails, we have to check upper bound too. | |
1696 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | |
1697 | |
1698 // Check for access to global object (unlikely). | |
1699 __ CmpInstanceType(rbx, JS_GLOBAL_PROXY_TYPE); | |
1700 __ j(equal, &global); | |
1701 | |
1702 // Check for non-global object that requires access check. | |
1703 __ testl(FieldOperand(rbx, Map::kBitFieldOffset), | |
1704 Immediate(1 << Map::kIsAccessCheckNeeded)); | |
1705 __ j(not_zero, &miss); | |
1706 | |
1707 // Search the dictionary placing the result in rax. | 1679 // Search the dictionary placing the result in rax. |
1708 __ bind(&probe); | 1680 GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax); |
1709 GenerateDictionaryLoad(masm, &miss, rdx, rax, rbx, | |
1710 rcx, rdi, rax, CHECK_DICTIONARY); | |
1711 __ ret(0); | 1681 __ ret(0); |
1712 | 1682 |
1713 // Global object access: Check access rights. | |
1714 __ bind(&global); | |
1715 __ CheckAccessGlobalProxy(rax, rdx, &miss); | |
1716 __ jmp(&probe); | |
1717 | |
1718 // Cache miss: Jump to runtime. | 1683 // Cache miss: Jump to runtime. |
1719 __ bind(&miss); | 1684 __ bind(&miss); |
1720 GenerateMiss(masm); | 1685 GenerateMiss(masm); |
1721 } | 1686 } |
1722 | 1687 |
1723 | 1688 |
1724 void LoadIC::GenerateStringLength(MacroAssembler* masm) { | 1689 void LoadIC::GenerateStringLength(MacroAssembler* masm) { |
1725 // ----------- S t a t e ------------- | 1690 // ----------- S t a t e ------------- |
1726 // -- rax : receiver | 1691 // -- rax : receiver |
1727 // -- rcx : name | 1692 // -- rcx : name |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1851 GenerateMiss(masm); | 1816 GenerateMiss(masm); |
1852 } | 1817 } |
1853 | 1818 |
1854 | 1819 |
1855 #undef __ | 1820 #undef __ |
1856 | 1821 |
1857 | 1822 |
1858 } } // namespace v8::internal | 1823 } } // namespace v8::internal |
1859 | 1824 |
1860 #endif // V8_TARGET_ARCH_X64 | 1825 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |