Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: src/ia32/ic-ia32.cc

Issue 2801007: Remove redundant checks in and around GenerateDictionaryLoad.... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/arm/ic-arm.cc ('k') | src/ic.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/arm/ic-arm.cc ('k') | src/ic.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698