OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset), | 94 __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset), |
95 Heap::kHashTableMapRootIndex); | 95 Heap::kHashTableMapRootIndex); |
96 __ j(not_equal, miss); | 96 __ j(not_equal, miss); |
97 } | 97 } |
98 | 98 |
99 | 99 |
100 | 100 |
101 // 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. |
102 // This function may return false negatives, so miss_label | 102 // This function may return false negatives, so miss_label |
103 // must always call a backup property load that is complete. | 103 // must always call a backup property load that is complete. |
104 // This function is safe to call if name is not a symbol, and will jump to | 104 // This function is safe to call if name is not an internalized string, |
105 // the miss_label in that case. | 105 // and will jump to the miss_label in that case. |
106 // The generated code assumes that the receiver has slow properties, | 106 // The generated code assumes that the receiver has slow properties, |
107 // is not a global object and does not have interceptors. | 107 // is not a global object and does not have interceptors. |
108 static void GenerateDictionaryLoad(MacroAssembler* masm, | 108 static void GenerateDictionaryLoad(MacroAssembler* masm, |
109 Label* miss_label, | 109 Label* miss_label, |
110 Register elements, | 110 Register elements, |
111 Register name, | 111 Register name, |
112 Register r0, | 112 Register r0, |
113 Register r1, | 113 Register r1, |
114 Register result) { | 114 Register result) { |
115 // Register use: | 115 // Register use: |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 __ movq(result, | 153 __ movq(result, |
154 Operand(elements, r1, times_pointer_size, | 154 Operand(elements, r1, times_pointer_size, |
155 kValueOffset - kHeapObjectTag)); | 155 kValueOffset - kHeapObjectTag)); |
156 } | 156 } |
157 | 157 |
158 | 158 |
159 // Helper function used to store a property to a dictionary backing | 159 // Helper function used to store a property to a dictionary backing |
160 // storage. This function may fail to store a property even though it | 160 // storage. This function may fail to store a property even though it |
161 // is in the dictionary, so code at miss_label must always call a | 161 // is in the dictionary, so code at miss_label must always call a |
162 // backup property store that is complete. This function is safe to | 162 // backup property store that is complete. This function is safe to |
163 // call if name is not a symbol, and will jump to the miss_label in | 163 // call if name is not an internalized string, and will jump to the miss_label |
164 // that case. The generated code assumes that the receiver has slow | 164 // in that case. The generated code assumes that the receiver has slow |
165 // properties, is not a global object and does not have interceptors. | 165 // properties, is not a global object and does not have interceptors. |
166 static void GenerateDictionaryStore(MacroAssembler* masm, | 166 static void GenerateDictionaryStore(MacroAssembler* masm, |
167 Label* miss_label, | 167 Label* miss_label, |
168 Register elements, | 168 Register elements, |
169 Register name, | 169 Register name, |
170 Register value, | 170 Register value, |
171 Register scratch0, | 171 Register scratch0, |
172 Register scratch1) { | 172 Register scratch1) { |
173 // Register use: | 173 // Register use: |
174 // | 174 // |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 __ CompareRoot(scratch, Heap::kTheHoleValueRootIndex); | 306 __ CompareRoot(scratch, Heap::kTheHoleValueRootIndex); |
307 // In case the loaded value is the_hole we have to consult GetProperty | 307 // In case the loaded value is the_hole we have to consult GetProperty |
308 // to ensure the prototype chain is searched. | 308 // to ensure the prototype chain is searched. |
309 __ j(equal, out_of_range); | 309 __ j(equal, out_of_range); |
310 if (!result.is(scratch)) { | 310 if (!result.is(scratch)) { |
311 __ movq(result, scratch); | 311 __ movq(result, scratch); |
312 } | 312 } |
313 } | 313 } |
314 | 314 |
315 | 315 |
316 // Checks whether a key is an array index string or a symbol string. | 316 // Checks whether a key is an array index string or an internalized string. |
317 // Falls through if the key is a symbol. | 317 // Falls through if the key is an internalized string. |
318 static void GenerateKeyStringCheck(MacroAssembler* masm, | 318 static void GenerateKeyStringCheck(MacroAssembler* masm, |
319 Register key, | 319 Register key, |
320 Register map, | 320 Register map, |
321 Register hash, | 321 Register hash, |
322 Label* index_string, | 322 Label* index_string, |
323 Label* not_symbol) { | 323 Label* not_internalized) { |
324 // Register use: | 324 // Register use: |
325 // key - holds the key and is unchanged. Assumed to be non-smi. | 325 // key - holds the key and is unchanged. Assumed to be non-smi. |
326 // Scratch registers: | 326 // Scratch registers: |
327 // map - used to hold the map of the key. | 327 // map - used to hold the map of the key. |
328 // hash - used to hold the hash of the key. | 328 // hash - used to hold the hash of the key. |
329 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); | 329 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); |
330 __ j(above_equal, not_symbol); | 330 __ j(above_equal, not_internalized); |
331 // Is the string an array index, with cached numeric value? | 331 // Is the string an array index, with cached numeric value? |
332 __ movl(hash, FieldOperand(key, String::kHashFieldOffset)); | 332 __ movl(hash, FieldOperand(key, String::kHashFieldOffset)); |
333 __ testl(hash, Immediate(String::kContainsCachedArrayIndexMask)); | 333 __ testl(hash, Immediate(String::kContainsCachedArrayIndexMask)); |
334 __ j(zero, index_string); // The value in hash is used at jump target. | 334 __ j(zero, index_string); // The value in hash is used at jump target. |
335 | 335 |
336 // Is the string a symbol? | 336 // Is the string internalized? |
337 STATIC_ASSERT(kSymbolTag != 0); | 337 STATIC_ASSERT(kInternalizedTag != 0); |
338 __ testb(FieldOperand(map, Map::kInstanceTypeOffset), | 338 __ testb(FieldOperand(map, Map::kInstanceTypeOffset), |
339 Immediate(kIsSymbolMask)); | 339 Immediate(kIsInternalizedMask)); |
340 __ j(zero, not_symbol); | 340 __ j(zero, not_internalized); |
341 } | 341 } |
342 | 342 |
343 | 343 |
344 | 344 |
345 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 345 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
346 // ----------- S t a t e ------------- | 346 // ----------- S t a t e ------------- |
347 // -- rax : key | 347 // -- rax : key |
348 // -- rdx : receiver | 348 // -- rdx : receiver |
349 // -- rsp[0] : return address | 349 // -- rsp[0] : return address |
350 // ----------------------------------- | 350 // ----------------------------------- |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 // based on 32 bits of the map pointer and the string hash. | 414 // based on 32 bits of the map pointer and the string hash. |
415 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | 415 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
416 __ movl(rcx, rbx); | 416 __ movl(rcx, rbx); |
417 __ shr(rcx, Immediate(KeyedLookupCache::kMapHashShift)); | 417 __ shr(rcx, Immediate(KeyedLookupCache::kMapHashShift)); |
418 __ movl(rdi, FieldOperand(rax, String::kHashFieldOffset)); | 418 __ movl(rdi, FieldOperand(rax, String::kHashFieldOffset)); |
419 __ shr(rdi, Immediate(String::kHashShift)); | 419 __ shr(rdi, Immediate(String::kHashShift)); |
420 __ xor_(rcx, rdi); | 420 __ xor_(rcx, rdi); |
421 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); | 421 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); |
422 __ and_(rcx, Immediate(mask)); | 422 __ and_(rcx, Immediate(mask)); |
423 | 423 |
424 // Load the key (consisting of map and symbol) from the cache and | 424 // Load the key (consisting of map and internalized string) from the cache and |
425 // check for match. | 425 // check for match. |
426 Label load_in_object_property; | 426 Label load_in_object_property; |
427 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket; | 427 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket; |
428 Label hit_on_nth_entry[kEntriesPerBucket]; | 428 Label hit_on_nth_entry[kEntriesPerBucket]; |
429 ExternalReference cache_keys | 429 ExternalReference cache_keys |
430 = ExternalReference::keyed_lookup_cache_keys(masm->isolate()); | 430 = ExternalReference::keyed_lookup_cache_keys(masm->isolate()); |
431 | 431 |
432 for (int i = 0; i < kEntriesPerBucket - 1; i++) { | 432 for (int i = 0; i < kEntriesPerBucket - 1; i++) { |
433 Label try_next_entry; | 433 Label try_next_entry; |
434 __ movq(rdi, rcx); | 434 __ movq(rdi, rcx); |
(...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1068 __ push(rcx); // pass the key | 1068 __ push(rcx); // pass the key |
1069 __ CallRuntime(Runtime::kKeyedGetProperty, 2); | 1069 __ CallRuntime(Runtime::kKeyedGetProperty, 2); |
1070 __ pop(rcx); // restore the key | 1070 __ pop(rcx); // restore the key |
1071 } | 1071 } |
1072 __ movq(rdi, rax); | 1072 __ movq(rdi, rax); |
1073 __ jmp(&do_call); | 1073 __ jmp(&do_call); |
1074 | 1074 |
1075 __ bind(&check_string); | 1075 __ bind(&check_string); |
1076 GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call); | 1076 GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call); |
1077 | 1077 |
1078 // The key is known to be a symbol. | 1078 // The key is known to be an internalized string. |
1079 // If the receiver is a regular JS object with slow properties then do | 1079 // If the receiver is a regular JS object with slow properties then do |
1080 // a quick inline probe of the receiver's dictionary. | 1080 // a quick inline probe of the receiver's dictionary. |
1081 // Otherwise do the monomorphic cache probe. | 1081 // Otherwise do the monomorphic cache probe. |
1082 GenerateKeyedLoadReceiverCheck( | 1082 GenerateKeyedLoadReceiverCheck( |
1083 masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); | 1083 masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); |
1084 | 1084 |
1085 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); | 1085 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); |
1086 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | 1086 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
1087 Heap::kHashTableMapRootIndex); | 1087 Heap::kHashTableMapRootIndex); |
1088 __ j(not_equal, &lookup_monomorphic_cache); | 1088 __ j(not_equal, &lookup_monomorphic_cache); |
1089 | 1089 |
1090 GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi); | 1090 GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi); |
1091 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1); | 1091 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1); |
1092 __ jmp(&do_call); | 1092 __ jmp(&do_call); |
1093 | 1093 |
1094 __ bind(&lookup_monomorphic_cache); | 1094 __ bind(&lookup_monomorphic_cache); |
1095 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1); | 1095 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1); |
1096 GenerateMonomorphicCacheProbe(masm, | 1096 GenerateMonomorphicCacheProbe(masm, |
1097 argc, | 1097 argc, |
1098 Code::KEYED_CALL_IC, | 1098 Code::KEYED_CALL_IC, |
1099 Code::kNoExtraICState); | 1099 Code::kNoExtraICState); |
1100 // Fall through on miss. | 1100 // Fall through on miss. |
1101 | 1101 |
1102 __ bind(&slow_call); | 1102 __ bind(&slow_call); |
1103 // This branch is taken if: | 1103 // This branch is taken if: |
1104 // - the receiver requires boxing or access check, | 1104 // - the receiver requires boxing or access check, |
1105 // - the key is neither smi nor symbol, | 1105 // - the key is neither smi nor internalized string, |
1106 // - the value loaded is not a function, | 1106 // - the value loaded is not a function, |
1107 // - there is hope that the runtime will create a monomorphic call stub | 1107 // - there is hope that the runtime will create a monomorphic call stub |
1108 // that will get fetched next time. | 1108 // that will get fetched next time. |
1109 __ IncrementCounter(counters->keyed_call_generic_slow(), 1); | 1109 __ IncrementCounter(counters->keyed_call_generic_slow(), 1); |
1110 GenerateMiss(masm, argc); | 1110 GenerateMiss(masm, argc); |
1111 | 1111 |
1112 __ bind(&index_string); | 1112 __ bind(&index_string); |
1113 __ IndexFromHash(rbx, rcx); | 1113 __ IndexFromHash(rbx, rcx); |
1114 // Now jump to the place where smi keys are handled. | 1114 // Now jump to the place where smi keys are handled. |
1115 __ jmp(&index_smi); | 1115 __ jmp(&index_smi); |
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1680 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) | 1680 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) |
1681 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) | 1681 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) |
1682 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); | 1682 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); |
1683 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1683 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
1684 } | 1684 } |
1685 | 1685 |
1686 | 1686 |
1687 } } // namespace v8::internal | 1687 } } // namespace v8::internal |
1688 | 1688 |
1689 #endif // V8_TARGET_ARCH_X64 | 1689 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |