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 __ cmp(type, JS_GLOBAL_OBJECT_TYPE); |
| 54 __ j(equal, global_object, not_taken); |
| 55 __ cmp(type, JS_BUILTINS_OBJECT_TYPE); |
| 56 __ j(equal, global_object, not_taken); |
| 57 __ cmp(type, JS_GLOBAL_PROXY_TYPE); |
| 58 __ j(equal, global_object, not_taken); |
| 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 // Check that the receiver isn't a smi. |
| 76 __ test(receiver, Immediate(kSmiTagMask)); |
| 77 __ j(zero, miss, not_taken); |
| 78 |
| 79 // Check that the receiver is a valid JS object. |
| 80 __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 81 __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset)); |
| 82 __ cmp(r0, FIRST_JS_OBJECT_TYPE); |
| 83 __ j(below, miss, not_taken); |
| 84 |
| 85 // If this assert fails, we have to check upper bound too. |
| 86 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| 87 |
| 88 GenerateGlobalInstanceTypeCheck(masm, r0, miss); |
| 89 |
| 90 // Check for non-global object that requires access check. |
| 91 __ test_b(FieldOperand(r1, Map::kBitFieldOffset), |
| 92 (1 << Map::kIsAccessCheckNeeded) | |
| 93 (1 << Map::kHasNamedInterceptor)); |
| 94 __ j(not_zero, miss, not_taken); |
| 95 |
| 96 __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
| 97 __ CheckMap(r0, Factory::hash_table_map(), miss, true); |
| 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, |
55 Register receiver, | 110 Register elements, |
56 Register name, | 111 Register name, |
57 Register r0, | 112 Register r0, |
58 Register r1, | 113 Register r1, |
59 Register r2, | 114 Register result) { |
60 Register result, | |
61 DictionaryCheck check_dictionary) { | |
62 // Register use: | 115 // Register use: |
63 // | 116 // |
64 // name - holds the name of the property and is unchanged. | 117 // elements - holds the property dictionary on entry and is unchanged. |
65 // receiver - holds the receiver and is unchanged. | 118 // |
| 119 // name - holds the name of the property on entry and is unchanged. |
| 120 // |
66 // Scratch registers: | 121 // Scratch registers: |
67 // r0 - used to hold the property dictionary. | |
68 // | 122 // |
69 // r1 - used for the index into the property dictionary | 123 // r0 - used for the index into the property dictionary |
70 // | 124 // |
71 // r2 - used to hold the capacity of the property dictionary. | 125 // r1 - used to hold the capacity of the property dictionary. |
72 // | 126 // |
73 // result - holds the result on exit. | 127 // result - holds the result on exit. |
74 | 128 |
75 Label done; | 129 Label done; |
76 | 130 |
77 // Check for the absence of an interceptor. | |
78 // Load the map into r0. | |
79 __ mov(r0, FieldOperand(receiver, JSObject::kMapOffset)); | |
80 | |
81 // Bail out if the receiver has a named interceptor. | |
82 __ test(FieldOperand(r0, Map::kBitFieldOffset), | |
83 Immediate(1 << Map::kHasNamedInterceptor)); | |
84 __ j(not_zero, miss_label, not_taken); | |
85 | |
86 // Bail out if we have a JS global proxy object. | |
87 __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset)); | |
88 __ cmp(r0, JS_GLOBAL_PROXY_TYPE); | |
89 __ j(equal, miss_label, not_taken); | |
90 | |
91 // Possible work-around for http://crbug.com/16276. | |
92 __ cmp(r0, JS_GLOBAL_OBJECT_TYPE); | |
93 __ j(equal, miss_label, not_taken); | |
94 __ cmp(r0, JS_BUILTINS_OBJECT_TYPE); | |
95 __ j(equal, miss_label, not_taken); | |
96 | |
97 // Load properties array. | |
98 __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); | |
99 | |
100 // Check that the properties array is a dictionary. | |
101 if (check_dictionary == CHECK_DICTIONARY) { | |
102 __ cmp(FieldOperand(r0, HeapObject::kMapOffset), | |
103 Immediate(Factory::hash_table_map())); | |
104 __ j(not_equal, miss_label); | |
105 } | |
106 | |
107 // Compute the capacity mask. | 131 // Compute the capacity mask. |
108 const int kCapacityOffset = | 132 const int kCapacityOffset = |
109 StringDictionary::kHeaderSize + | 133 StringDictionary::kHeaderSize + |
110 StringDictionary::kCapacityIndex * kPointerSize; | 134 StringDictionary::kCapacityIndex * kPointerSize; |
111 __ mov(r2, FieldOperand(r0, kCapacityOffset)); | 135 __ mov(r1, FieldOperand(elements, kCapacityOffset)); |
112 __ shr(r2, kSmiTagSize); // convert smi to int | 136 __ shr(r1, kSmiTagSize); // convert smi to int |
113 __ dec(r2); | 137 __ dec(r1); |
114 | 138 |
115 // Generate an unrolled loop that performs a few probes before | 139 // Generate an unrolled loop that performs a few probes before |
116 // giving up. Measurements done on Gmail indicate that 2 probes | 140 // giving up. Measurements done on Gmail indicate that 2 probes |
117 // cover ~93% of loads from dictionaries. | 141 // cover ~93% of loads from dictionaries. |
118 static const int kProbes = 4; | 142 static const int kProbes = 4; |
119 const int kElementsStartOffset = | 143 const int kElementsStartOffset = |
120 StringDictionary::kHeaderSize + | 144 StringDictionary::kHeaderSize + |
121 StringDictionary::kElementsStartIndex * kPointerSize; | 145 StringDictionary::kElementsStartIndex * kPointerSize; |
122 for (int i = 0; i < kProbes; i++) { | 146 for (int i = 0; i < kProbes; i++) { |
123 // Compute the masked index: (hash + i + i * i) & mask. | 147 // Compute the masked index: (hash + i + i * i) & mask. |
124 __ mov(r1, FieldOperand(name, String::kHashFieldOffset)); | 148 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); |
125 __ shr(r1, String::kHashShift); | 149 __ shr(r0, String::kHashShift); |
126 if (i > 0) { | 150 if (i > 0) { |
127 __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i))); | 151 __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i))); |
128 } | 152 } |
129 __ and_(r1, Operand(r2)); | 153 __ and_(r0, Operand(r1)); |
130 | 154 |
131 // Scale the index by multiplying by the entry size. | 155 // Scale the index by multiplying by the entry size. |
132 ASSERT(StringDictionary::kEntrySize == 3); | 156 ASSERT(StringDictionary::kEntrySize == 3); |
133 __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 | 157 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 |
134 | 158 |
135 // Check if the key is identical to the name. | 159 // Check if the key is identical to the name. |
136 __ cmp(name, | 160 __ cmp(name, Operand(elements, r0, times_4, |
137 Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag)); | 161 kElementsStartOffset - kHeapObjectTag)); |
138 if (i != kProbes - 1) { | 162 if (i != kProbes - 1) { |
139 __ j(equal, &done, taken); | 163 __ j(equal, &done, taken); |
140 } else { | 164 } else { |
141 __ j(not_equal, miss_label, not_taken); | 165 __ j(not_equal, miss_label, not_taken); |
142 } | 166 } |
143 } | 167 } |
144 | 168 |
145 // Check that the value is a normal property. | 169 // Check that the value is a normal property. |
146 __ bind(&done); | 170 __ bind(&done); |
147 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 171 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
148 __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag), | 172 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), |
149 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 173 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
150 __ j(not_zero, miss_label, not_taken); | 174 __ j(not_zero, miss_label, not_taken); |
151 | 175 |
152 // Get the value at the masked, scaled index. | 176 // Get the value at the masked, scaled index. |
153 const int kValueOffset = kElementsStartOffset + kPointerSize; | 177 const int kValueOffset = kElementsStartOffset + kPointerSize; |
154 __ mov(result, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag)); | 178 __ mov(result, Operand(elements, r0, times_4, 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 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 __ bind(&miss); | 324 __ bind(&miss); |
301 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 325 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
302 } | 326 } |
303 | 327 |
304 | 328 |
305 // Checks the receiver for special cases (value type, slow case bits). | 329 // Checks the receiver for special cases (value type, slow case bits). |
306 // Falls through for regular JS object. | 330 // Falls through for regular JS object. |
307 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, | 331 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, |
308 Register receiver, | 332 Register receiver, |
309 Register map, | 333 Register map, |
| 334 int interceptor_bit, |
310 Label* slow) { | 335 Label* slow) { |
311 // Register use: | 336 // Register use: |
312 // receiver - holds the receiver and is unchanged. | 337 // receiver - holds the receiver and is unchanged. |
313 // Scratch registers: | 338 // Scratch registers: |
314 // map - used to hold the map of the receiver. | 339 // map - used to hold the map of the receiver. |
315 | 340 |
316 // Check that the object isn't a smi. | 341 // Check that the object isn't a smi. |
317 __ test(receiver, Immediate(kSmiTagMask)); | 342 __ test(receiver, Immediate(kSmiTagMask)); |
318 __ j(zero, slow, not_taken); | 343 __ j(zero, slow, not_taken); |
319 | 344 |
320 // Get the map of the receiver. | 345 // Get the map of the receiver. |
321 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset)); | 346 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset)); |
322 | 347 |
323 // Check bit field. | 348 // Check bit field. |
324 __ test_b(FieldOperand(map, Map::kBitFieldOffset), | 349 __ test_b(FieldOperand(map, Map::kBitFieldOffset), |
325 KeyedLoadIC::kSlowCaseBitFieldMask); | 350 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)); |
326 __ j(not_zero, slow, not_taken); | 351 __ j(not_zero, slow, not_taken); |
327 // Check that the object is some kind of JS object EXCEPT JS Value type. | 352 // Check that the object is some kind of JS object EXCEPT JS Value type. |
328 // In the case that the object is a value-wrapper object, | 353 // In the case that the object is a value-wrapper object, |
329 // we enter the runtime system to make sure that indexing | 354 // we enter the runtime system to make sure that indexing |
330 // into string objects works as intended. | 355 // into string objects works as intended. |
331 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 356 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
332 | 357 |
333 __ CmpInstanceType(map, JS_OBJECT_TYPE); | 358 __ CmpInstanceType(map, JS_OBJECT_TYPE); |
334 __ j(below, slow, not_taken); | 359 __ j(below, slow, not_taken); |
335 } | 360 } |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 | 450 |
426 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 451 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
427 // ----------- S t a t e ------------- | 452 // ----------- S t a t e ------------- |
428 // -- eax : key | 453 // -- eax : key |
429 // -- edx : receiver | 454 // -- edx : receiver |
430 // -- esp[0] : return address | 455 // -- esp[0] : return address |
431 // ----------------------------------- | 456 // ----------------------------------- |
432 Label slow, check_string, index_smi, index_string; | 457 Label slow, check_string, index_smi, index_string; |
433 Label check_pixel_array, probe_dictionary, check_number_dictionary; | 458 Label check_pixel_array, probe_dictionary, check_number_dictionary; |
434 | 459 |
435 GenerateKeyedLoadReceiverCheck(masm, edx, ecx, &slow); | |
436 | |
437 // Check that the key is a smi. | 460 // Check that the key is a smi. |
438 __ test(eax, Immediate(kSmiTagMask)); | 461 __ test(eax, Immediate(kSmiTagMask)); |
439 __ j(not_zero, &check_string, not_taken); | 462 __ j(not_zero, &check_string, not_taken); |
440 __ bind(&index_smi); | 463 __ bind(&index_smi); |
441 // Now the key is known to be a smi. This place is also jumped to from | 464 // Now the key is known to be a smi. This place is also jumped to from |
442 // where a numeric string is converted to a smi. | 465 // where a numeric string is converted to a smi. |
443 | 466 |
| 467 GenerateKeyedLoadReceiverCheck( |
| 468 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow); |
| 469 |
444 GenerateFastArrayLoad(masm, | 470 GenerateFastArrayLoad(masm, |
445 edx, | 471 edx, |
446 eax, | 472 eax, |
447 ecx, | 473 ecx, |
448 eax, | 474 eax, |
449 &check_pixel_array, | 475 &check_pixel_array, |
450 &slow); | 476 &slow); |
451 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); | 477 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); |
452 __ ret(0); | 478 __ ret(0); |
453 | 479 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 __ bind(&slow); | 522 __ bind(&slow); |
497 // Slow case: jump to runtime. | 523 // Slow case: jump to runtime. |
498 // edx: receiver | 524 // edx: receiver |
499 // eax: key | 525 // eax: key |
500 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); | 526 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); |
501 GenerateRuntimeGetProperty(masm); | 527 GenerateRuntimeGetProperty(masm); |
502 | 528 |
503 __ bind(&check_string); | 529 __ bind(&check_string); |
504 GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow); | 530 GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow); |
505 | 531 |
| 532 GenerateKeyedLoadReceiverCheck( |
| 533 masm, edx, ecx, Map::kHasNamedInterceptor, &slow); |
| 534 |
506 // If the receiver is a fast-case object, check the keyed lookup | 535 // If the receiver is a fast-case object, check the keyed lookup |
507 // cache. Otherwise probe the dictionary. | 536 // cache. Otherwise probe the dictionary. |
508 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); | 537 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); |
509 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 538 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
510 Immediate(Factory::hash_table_map())); | 539 Immediate(Factory::hash_table_map())); |
511 __ j(equal, &probe_dictionary); | 540 __ j(equal, &probe_dictionary); |
512 | 541 |
513 // Load the map of the receiver, compute the keyed lookup cache hash | 542 // Load the map of the receiver, compute the keyed lookup cache hash |
514 // based on 32 bits of the map pointer and the string hash. | 543 // based on 32 bits of the map pointer and the string hash. |
515 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 544 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 // Load in-object property. | 577 // Load in-object property. |
549 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset)); | 578 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset)); |
550 __ add(ecx, Operand(edi)); | 579 __ add(ecx, Operand(edi)); |
551 __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0)); | 580 __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0)); |
552 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1); | 581 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1); |
553 __ ret(0); | 582 __ ret(0); |
554 | 583 |
555 // Do a quick inline probe of the receiver's dictionary, if it | 584 // Do a quick inline probe of the receiver's dictionary, if it |
556 // exists. | 585 // exists. |
557 __ bind(&probe_dictionary); | 586 __ bind(&probe_dictionary); |
558 GenerateDictionaryLoad(masm, | 587 |
559 &slow, | 588 __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset)); |
560 edx, | 589 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
561 eax, | 590 GenerateGlobalInstanceTypeCheck(masm, ecx, &slow); |
562 ebx, | 591 |
563 ecx, | 592 GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax); |
564 edi, | |
565 eax, | |
566 DICTIONARY_CHECK_DONE); | |
567 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); | 593 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); |
568 __ ret(0); | 594 __ ret(0); |
569 | 595 |
570 __ bind(&index_string); | 596 __ bind(&index_string); |
571 GenerateIndexFromHash(masm, eax, ebx); | 597 GenerateIndexFromHash(masm, eax, ebx); |
572 // Now jump to the place where smi keys are handled. | 598 // Now jump to the place where smi keys are handled. |
573 __ jmp(&index_smi); | 599 __ jmp(&index_smi); |
574 } | 600 } |
575 | 601 |
576 | 602 |
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1166 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 1192 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
1167 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); | 1193 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); |
1168 | 1194 |
1169 // Probe the stub cache for the value object. | 1195 // Probe the stub cache for the value object. |
1170 __ bind(&probe); | 1196 __ bind(&probe); |
1171 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); | 1197 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); |
1172 __ bind(&miss); | 1198 __ bind(&miss); |
1173 } | 1199 } |
1174 | 1200 |
1175 | 1201 |
1176 static void GenerateNormalHelper(MacroAssembler* masm, | 1202 static void GenerateFunctionTailCall(MacroAssembler* masm, |
1177 int argc, | 1203 int argc, |
1178 bool is_global_object, | 1204 Label* miss) { |
1179 Label* miss) { | |
1180 // ----------- S t a t e ------------- | 1205 // ----------- S t a t e ------------- |
1181 // -- ecx : name | 1206 // -- ecx : name |
1182 // -- edx : receiver | 1207 // -- edi : function |
1183 // -- esp[0] : return address | 1208 // -- esp[0] : return address |
1184 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1209 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
1185 // -- ... | 1210 // -- ... |
1186 // -- esp[(argc + 1) * 4] : receiver | 1211 // -- esp[(argc + 1) * 4] : receiver |
1187 // ----------------------------------- | 1212 // ----------------------------------- |
1188 | 1213 |
1189 // Search dictionary - put result in register edi. | |
1190 __ mov(edi, edx); | |
1191 GenerateDictionaryLoad( | |
1192 masm, miss, edx, ecx, eax, edi, ebx, edi, CHECK_DICTIONARY); | |
1193 | |
1194 // Check that the result is not a smi. | 1214 // Check that the result is not a smi. |
1195 __ test(edi, Immediate(kSmiTagMask)); | 1215 __ test(edi, Immediate(kSmiTagMask)); |
1196 __ j(zero, miss, not_taken); | 1216 __ j(zero, miss, not_taken); |
1197 | 1217 |
1198 // Check that the value is a JavaScript function, fetching its map into eax. | 1218 // Check that the value is a JavaScript function, fetching its map into eax. |
1199 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); | 1219 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); |
1200 __ j(not_equal, miss, not_taken); | 1220 __ j(not_equal, miss, not_taken); |
1201 | 1221 |
1202 // Patch the receiver on stack with the global proxy if necessary. | |
1203 if (is_global_object) { | |
1204 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | |
1205 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | |
1206 } | |
1207 | |
1208 // Invoke the function. | 1222 // Invoke the function. |
1209 ParameterCount actual(argc); | 1223 ParameterCount actual(argc); |
1210 __ InvokeFunction(edi, actual, JUMP_FUNCTION); | 1224 __ InvokeFunction(edi, actual, JUMP_FUNCTION); |
1211 } | 1225 } |
1212 | 1226 |
1213 // The generated code falls through if the call should be handled by runtime. | 1227 // The generated code falls through if the call should be handled by runtime. |
1214 static void GenerateCallNormal(MacroAssembler* masm, int argc) { | 1228 static void GenerateCallNormal(MacroAssembler* masm, int argc) { |
1215 // ----------- S t a t e ------------- | 1229 // ----------- S t a t e ------------- |
1216 // -- ecx : name | 1230 // -- ecx : name |
1217 // -- esp[0] : return address | 1231 // -- esp[0] : return address |
1218 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1232 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
1219 // -- ... | 1233 // -- ... |
1220 // -- esp[(argc + 1) * 4] : receiver | 1234 // -- esp[(argc + 1) * 4] : receiver |
1221 // ----------------------------------- | 1235 // ----------------------------------- |
1222 Label miss, global_object, non_global_object; | 1236 Label miss; |
1223 | 1237 |
1224 // Get the receiver of the function from the stack; 1 ~ return address. | 1238 // Get the receiver of the function from the stack; 1 ~ return address. |
1225 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1239 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
1226 | 1240 |
1227 // Check that the receiver isn't a smi. | 1241 GenerateDictionaryLoadReceiverCheck(masm, edx, eax, ebx, &miss); |
1228 __ test(edx, Immediate(kSmiTagMask)); | |
1229 __ j(zero, &miss, not_taken); | |
1230 | 1242 |
1231 // Check that the receiver is a valid JS object. | 1243 // eax: elements |
1232 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 1244 // Search the dictionary placing the result in edi. |
1233 __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 1245 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi); |
1234 __ cmp(eax, FIRST_JS_OBJECT_TYPE); | 1246 GenerateFunctionTailCall(masm, argc, &miss); |
1235 __ j(below, &miss, not_taken); | |
1236 | |
1237 // If this assert fails, we have to check upper bound too. | |
1238 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | |
1239 | |
1240 // Check for access to global object. | |
1241 __ cmp(eax, JS_GLOBAL_OBJECT_TYPE); | |
1242 __ j(equal, &global_object); | |
1243 __ cmp(eax, JS_BUILTINS_OBJECT_TYPE); | |
1244 __ j(not_equal, &non_global_object); | |
1245 | |
1246 // Accessing global object: Load and invoke. | |
1247 __ bind(&global_object); | |
1248 // Check that the global object does not require access checks. | |
1249 __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), | |
1250 1 << Map::kIsAccessCheckNeeded); | |
1251 __ j(not_equal, &miss, not_taken); | |
1252 GenerateNormalHelper(masm, argc, true, &miss); | |
1253 | |
1254 // Accessing non-global object: Check for access to global proxy. | |
1255 Label global_proxy, invoke; | |
1256 __ bind(&non_global_object); | |
1257 __ cmp(eax, JS_GLOBAL_PROXY_TYPE); | |
1258 __ j(equal, &global_proxy, not_taken); | |
1259 // Check that the non-global, non-global-proxy object does not | |
1260 // require access checks. | |
1261 __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), | |
1262 1 << Map::kIsAccessCheckNeeded); | |
1263 __ j(not_equal, &miss, not_taken); | |
1264 __ bind(&invoke); | |
1265 GenerateNormalHelper(masm, argc, false, &miss); | |
1266 | |
1267 // Global object proxy access: Check access rights. | |
1268 __ bind(&global_proxy); | |
1269 __ CheckAccessGlobalProxy(edx, eax, &miss); | |
1270 __ jmp(&invoke); | |
1271 | 1247 |
1272 __ bind(&miss); | 1248 __ bind(&miss); |
1273 } | 1249 } |
1274 | 1250 |
1275 | 1251 |
1276 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { | 1252 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { |
1277 // ----------- S t a t e ------------- | 1253 // ----------- S t a t e ------------- |
1278 // -- ecx : name | 1254 // -- ecx : name |
1279 // -- esp[0] : return address | 1255 // -- esp[0] : return address |
1280 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1256 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
1281 // -- ... | 1257 // -- ... |
1282 // -- esp[(argc + 1) * 4] : receiver | 1258 // -- esp[(argc + 1) * 4] : receiver |
1283 // ----------------------------------- | 1259 // ----------------------------------- |
1284 | 1260 |
| 1261 if (id == IC::kCallIC_Miss) { |
| 1262 __ IncrementCounter(&Counters::call_miss, 1); |
| 1263 } else { |
| 1264 __ IncrementCounter(&Counters::keyed_call_miss, 1); |
| 1265 } |
| 1266 |
1285 // Get the receiver of the function from the stack; 1 ~ return address. | 1267 // Get the receiver of the function from the stack; 1 ~ return address. |
1286 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1268 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
1287 | 1269 |
1288 // Enter an internal frame. | 1270 // Enter an internal frame. |
1289 __ EnterInternalFrame(); | 1271 __ EnterInternalFrame(); |
1290 | 1272 |
1291 // Push the receiver and the name of the function. | 1273 // Push the receiver and the name of the function. |
1292 __ push(edx); | 1274 __ push(edx); |
1293 __ push(ecx); | 1275 __ push(ecx); |
1294 | 1276 |
1295 // Call the entry. | 1277 // Call the entry. |
1296 CEntryStub stub(1); | 1278 CEntryStub stub(1); |
1297 __ mov(eax, Immediate(2)); | 1279 __ mov(eax, Immediate(2)); |
1298 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id)))); | 1280 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id)))); |
1299 __ CallStub(&stub); | 1281 __ CallStub(&stub); |
1300 | 1282 |
1301 // Move result to edi and exit the internal frame. | 1283 // Move result to edi and exit the internal frame. |
1302 __ mov(edi, eax); | 1284 __ mov(edi, eax); |
1303 __ LeaveInternalFrame(); | 1285 __ LeaveInternalFrame(); |
1304 | 1286 |
1305 // Check if the receiver is a global object of some sort. | 1287 // Check if the receiver is a global object of some sort. |
1306 Label invoke, global; | 1288 // This can happen only for regular CallIC but not KeyedCallIC. |
1307 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver | 1289 if (id == IC::kCallIC_Miss) { |
1308 __ test(edx, Immediate(kSmiTagMask)); | 1290 Label invoke, global; |
1309 __ j(zero, &invoke, not_taken); | 1291 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver |
1310 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 1292 __ test(edx, Immediate(kSmiTagMask)); |
1311 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 1293 __ j(zero, &invoke, not_taken); |
1312 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); | 1294 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); |
1313 __ j(equal, &global); | 1295 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
1314 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); | 1296 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); |
1315 __ j(not_equal, &invoke); | 1297 __ j(equal, &global); |
| 1298 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); |
| 1299 __ j(not_equal, &invoke); |
1316 | 1300 |
1317 // Patch the receiver on the stack. | 1301 // Patch the receiver on the stack. |
1318 __ bind(&global); | 1302 __ bind(&global); |
1319 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 1303 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
1320 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 1304 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 1305 __ bind(&invoke); |
| 1306 } |
1321 | 1307 |
1322 // Invoke the function. | 1308 // Invoke the function. |
1323 ParameterCount actual(argc); | 1309 ParameterCount actual(argc); |
1324 __ bind(&invoke); | |
1325 __ InvokeFunction(edi, actual, JUMP_FUNCTION); | 1310 __ InvokeFunction(edi, actual, JUMP_FUNCTION); |
1326 } | 1311 } |
1327 | 1312 |
1328 | 1313 |
1329 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { | 1314 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { |
1330 // ----------- S t a t e ------------- | 1315 // ----------- S t a t e ------------- |
1331 // -- ecx : name | 1316 // -- ecx : name |
1332 // -- esp[0] : return address | 1317 // -- esp[0] : return address |
1333 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1318 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
1334 // -- ... | 1319 // -- ... |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1386 Label index_smi, index_string; | 1371 Label index_smi, index_string; |
1387 | 1372 |
1388 // Check that the key is a smi. | 1373 // Check that the key is a smi. |
1389 __ test(ecx, Immediate(kSmiTagMask)); | 1374 __ test(ecx, Immediate(kSmiTagMask)); |
1390 __ j(not_zero, &check_string, not_taken); | 1375 __ j(not_zero, &check_string, not_taken); |
1391 | 1376 |
1392 __ bind(&index_smi); | 1377 __ bind(&index_smi); |
1393 // Now the key is known to be a smi. This place is also jumped to from | 1378 // Now the key is known to be a smi. This place is also jumped to from |
1394 // where a numeric string is converted to a smi. | 1379 // where a numeric string is converted to a smi. |
1395 | 1380 |
1396 GenerateKeyedLoadReceiverCheck(masm, edx, eax, &slow_call); | 1381 GenerateKeyedLoadReceiverCheck( |
| 1382 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call); |
1397 | 1383 |
1398 GenerateFastArrayLoad( | 1384 GenerateFastArrayLoad( |
1399 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); | 1385 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); |
1400 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1); | 1386 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1); |
1401 | 1387 |
1402 __ bind(&do_call); | 1388 __ bind(&do_call); |
1403 // receiver in edx is not used after this point. | 1389 // receiver in edx is not used after this point. |
1404 // ecx: key | 1390 // ecx: key |
1405 // edi: function | 1391 // edi: function |
1406 | 1392 GenerateFunctionTailCall(masm, argc, &slow_call); |
1407 // Check that the value in edi is a JavaScript function. | |
1408 __ test(edi, Immediate(kSmiTagMask)); | |
1409 __ j(zero, &slow_call, not_taken); | |
1410 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); | |
1411 __ j(not_equal, &slow_call, not_taken); | |
1412 // Invoke the function. | |
1413 ParameterCount actual(argc); | |
1414 __ InvokeFunction(edi, actual, JUMP_FUNCTION); | |
1415 | 1393 |
1416 __ bind(&check_number_dictionary); | 1394 __ bind(&check_number_dictionary); |
1417 // eax: elements | 1395 // eax: elements |
1418 // ecx: smi key | 1396 // ecx: smi key |
1419 // Check whether the elements is a number dictionary. | 1397 // Check whether the elements is a number dictionary. |
1420 __ CheckMap(eax, Factory::hash_table_map(), &slow_load, true); | 1398 __ CheckMap(eax, Factory::hash_table_map(), &slow_load, true); |
1421 __ mov(ebx, ecx); | 1399 __ mov(ebx, ecx); |
1422 __ SmiUntag(ebx); | 1400 __ SmiUntag(ebx); |
1423 // ebx: untagged index | 1401 // ebx: untagged index |
1424 // Receiver in edx will be clobbered, need to reload it on miss. | 1402 // Receiver in edx will be clobbered, need to reload it on miss. |
(...skipping 19 matching lines...) Expand all Loading... |
1444 __ mov(edi, eax); | 1422 __ mov(edi, eax); |
1445 __ jmp(&do_call); | 1423 __ jmp(&do_call); |
1446 | 1424 |
1447 __ bind(&check_string); | 1425 __ bind(&check_string); |
1448 GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call); | 1426 GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call); |
1449 | 1427 |
1450 // The key is known to be a symbol. | 1428 // The key is known to be a symbol. |
1451 // If the receiver is a regular JS object with slow properties then do | 1429 // If the receiver is a regular JS object with slow properties then do |
1452 // a quick inline probe of the receiver's dictionary. | 1430 // a quick inline probe of the receiver's dictionary. |
1453 // Otherwise do the monomorphic cache probe. | 1431 // Otherwise do the monomorphic cache probe. |
1454 GenerateKeyedLoadReceiverCheck(masm, edx, eax, &lookup_monomorphic_cache); | 1432 GenerateKeyedLoadReceiverCheck( |
| 1433 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); |
1455 | 1434 |
1456 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); | 1435 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); |
1457 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1436 __ CheckMap(ebx, Factory::hash_table_map(), &lookup_monomorphic_cache, true); |
1458 Immediate(Factory::hash_table_map())); | |
1459 __ j(not_equal, &lookup_monomorphic_cache, not_taken); | |
1460 | 1437 |
1461 GenerateDictionaryLoad( | 1438 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi); |
1462 masm, &slow_load, edx, ecx, ebx, eax, edi, edi, DICTIONARY_CHECK_DONE); | |
1463 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1); | 1439 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1); |
1464 __ jmp(&do_call); | 1440 __ jmp(&do_call); |
1465 | 1441 |
1466 __ bind(&lookup_monomorphic_cache); | 1442 __ bind(&lookup_monomorphic_cache); |
1467 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1); | 1443 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1); |
1468 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); | 1444 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); |
1469 // Fall through on miss. | 1445 // Fall through on miss. |
1470 | 1446 |
1471 __ bind(&slow_call); | 1447 __ bind(&slow_call); |
1472 // This branch is taken if: | 1448 // This branch is taken if: |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1532 GenerateMiss(masm); | 1508 GenerateMiss(masm); |
1533 } | 1509 } |
1534 | 1510 |
1535 | 1511 |
1536 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 1512 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
1537 // ----------- S t a t e ------------- | 1513 // ----------- S t a t e ------------- |
1538 // -- eax : receiver | 1514 // -- eax : receiver |
1539 // -- ecx : name | 1515 // -- ecx : name |
1540 // -- esp[0] : return address | 1516 // -- esp[0] : return address |
1541 // ----------------------------------- | 1517 // ----------------------------------- |
1542 Label miss, probe, global; | 1518 Label miss; |
1543 | 1519 |
1544 // Check that the receiver isn't a smi. | 1520 GenerateDictionaryLoadReceiverCheck(masm, eax, edx, ebx, &miss); |
1545 __ test(eax, Immediate(kSmiTagMask)); | |
1546 __ j(zero, &miss, not_taken); | |
1547 | 1521 |
1548 // Check that the receiver is a valid JS object. | 1522 // edx: elements |
1549 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | |
1550 __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | |
1551 __ cmp(edx, FIRST_JS_OBJECT_TYPE); | |
1552 __ j(less, &miss, not_taken); | |
1553 | |
1554 // If this assert fails, we have to check upper bound too. | |
1555 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | |
1556 | |
1557 // Check for access to global object (unlikely). | |
1558 __ cmp(edx, JS_GLOBAL_PROXY_TYPE); | |
1559 __ j(equal, &global, not_taken); | |
1560 | |
1561 // Check for non-global object that requires access check. | |
1562 __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), | |
1563 1 << Map::kIsAccessCheckNeeded); | |
1564 __ j(not_zero, &miss, not_taken); | |
1565 | |
1566 // Search the dictionary placing the result in eax. | 1523 // Search the dictionary placing the result in eax. |
1567 __ bind(&probe); | 1524 GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax); |
1568 GenerateDictionaryLoad(masm, | |
1569 &miss, | |
1570 eax, | |
1571 ecx, | |
1572 edx, | |
1573 edi, | |
1574 ebx, | |
1575 edi, | |
1576 CHECK_DICTIONARY); | |
1577 __ mov(eax, edi); | |
1578 __ ret(0); | 1525 __ ret(0); |
1579 | 1526 |
1580 // Global object access: Check access rights. | |
1581 __ bind(&global); | |
1582 __ CheckAccessGlobalProxy(eax, edx, &miss); | |
1583 __ jmp(&probe); | |
1584 | |
1585 // Cache miss: Jump to runtime. | 1527 // Cache miss: Jump to runtime. |
1586 __ bind(&miss); | 1528 __ bind(&miss); |
1587 GenerateMiss(masm); | 1529 GenerateMiss(masm); |
1588 } | 1530 } |
1589 | 1531 |
1590 | 1532 |
1591 void LoadIC::GenerateMiss(MacroAssembler* masm) { | 1533 void LoadIC::GenerateMiss(MacroAssembler* masm) { |
1592 // ----------- S t a t e ------------- | 1534 // ----------- S t a t e ------------- |
1593 // -- eax : receiver | 1535 // -- eax : receiver |
1594 // -- ecx : name | 1536 // -- ecx : name |
1595 // -- esp[0] : return address | 1537 // -- esp[0] : return address |
1596 // ----------------------------------- | 1538 // ----------------------------------- |
1597 | 1539 |
| 1540 __ IncrementCounter(&Counters::load_miss, 1); |
| 1541 |
1598 __ pop(ebx); | 1542 __ pop(ebx); |
1599 __ push(eax); // receiver | 1543 __ push(eax); // receiver |
1600 __ push(ecx); // name | 1544 __ push(ecx); // name |
1601 __ push(ebx); // return address | 1545 __ push(ebx); // return address |
1602 | 1546 |
1603 // Perform tail call to the entry. | 1547 // Perform tail call to the entry. |
1604 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); | 1548 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); |
1605 __ TailCallExternalReference(ref, 2, 1); | 1549 __ TailCallExternalReference(ref, 2, 1); |
1606 } | 1550 } |
1607 | 1551 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1704 Object* KeyedLoadIC_Miss(Arguments args); | 1648 Object* KeyedLoadIC_Miss(Arguments args); |
1705 | 1649 |
1706 | 1650 |
1707 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 1651 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
1708 // ----------- S t a t e ------------- | 1652 // ----------- S t a t e ------------- |
1709 // -- eax : key | 1653 // -- eax : key |
1710 // -- edx : receiver | 1654 // -- edx : receiver |
1711 // -- esp[0] : return address | 1655 // -- esp[0] : return address |
1712 // ----------------------------------- | 1656 // ----------------------------------- |
1713 | 1657 |
| 1658 __ IncrementCounter(&Counters::keyed_load_miss, 1); |
| 1659 |
1714 __ pop(ebx); | 1660 __ pop(ebx); |
1715 __ push(edx); // receiver | 1661 __ push(edx); // receiver |
1716 __ push(eax); // name | 1662 __ push(eax); // name |
1717 __ push(ebx); // return address | 1663 __ push(ebx); // return address |
1718 | 1664 |
1719 // Perform tail call to the entry. | 1665 // Perform tail call to the entry. |
1720 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss)); | 1666 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss)); |
1721 __ TailCallExternalReference(ref, 2, 1); | 1667 __ TailCallExternalReference(ref, 2, 1); |
1722 } | 1668 } |
1723 | 1669 |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1869 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss)); | 1815 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss)); |
1870 __ TailCallExternalReference(ref, 3, 1); | 1816 __ TailCallExternalReference(ref, 3, 1); |
1871 } | 1817 } |
1872 | 1818 |
1873 #undef __ | 1819 #undef __ |
1874 | 1820 |
1875 | 1821 |
1876 } } // namespace v8::internal | 1822 } } // namespace v8::internal |
1877 | 1823 |
1878 #endif // V8_TARGET_ARCH_IA32 | 1824 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |