Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 43 #define __ ACCESS_MASM(masm) | 43 #define __ ACCESS_MASM(masm) |
| 44 | 44 |
| 45 | 45 |
| 46 // Helper function used to load a property from a dictionary backing storage. | 46 // Helper function used to load a property from a dictionary backing storage. |
| 47 // This function may return false negatives, so miss_label | 47 // This function may return false negatives, so miss_label |
| 48 // must always call a backup property load that is complete. | 48 // must always call a backup property load that is complete. |
| 49 // This function is safe to call if the receiver has fast properties, | 49 // This function is safe to call if the receiver has fast properties, |
| 50 // or if name is not a symbol, and will jump to the miss_label in that case. | 50 // or if name is not a symbol, and will jump to the miss_label in that case. |
| 51 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label, | 51 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label, |
| 52 Register r0, Register r1, Register r2, | 52 Register r0, Register r1, Register r2, |
| 53 Register name) { | 53 Register name, bool check_dictionary) { |
|
Erik Corry
2009/12/09 10:43:40
This should be an enum with CHECK_DICTIONARY and D
Mads Ager (chromium)
2009/12/10 09:18:18
Done.
| |
| 54 // Register use: | 54 // Register use: |
| 55 // | 55 // |
| 56 // r0 - used to hold the property dictionary. | 56 // r0 - used to hold the property dictionary. |
| 57 // | 57 // |
| 58 // r1 - initially the receiver | 58 // r1 - initially the receiver |
| 59 // - used for the index into the property dictionary | 59 // - used for the index into the property dictionary |
| 60 // - holds the result on exit. | 60 // - holds the result on exit. |
| 61 // | 61 // |
| 62 // r2 - used to hold the capacity of the property dictionary. | 62 // r2 - used to hold the capacity of the property dictionary. |
| 63 // | 63 // |
| 64 // name - holds the name of the property and is unchanged. | 64 // name - holds the name of the property and is unchanged. |
| 65 | 65 |
| 66 Label done; | 66 Label done; |
| 67 | 67 |
| 68 // Check for the absence of an interceptor. | 68 // Check for the absence of an interceptor. |
| 69 // Load the map into r0. | 69 // Load the map into r0. |
| 70 __ mov(r0, FieldOperand(r1, JSObject::kMapOffset)); | 70 __ mov(r0, FieldOperand(r1, JSObject::kMapOffset)); |
| 71 // Test the has_named_interceptor bit in the map. | 71 // Test the has_named_interceptor bit in the map. |
| 72 __ test(FieldOperand(r0, Map::kInstanceAttributesOffset), | 72 __ test(FieldOperand(r0, Map::kInstanceAttributesOffset), |
| 73 Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8)))); | 73 Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8)))); |
| 74 | 74 |
| 75 // Jump to miss if the interceptor bit is set. | 75 // Jump to miss if the interceptor bit is set. |
| 76 __ j(not_zero, miss_label, not_taken); | 76 __ j(not_zero, miss_label, not_taken); |
| 77 | 77 |
| 78 // Bail out if we have a JS global proxy object. | 78 // Bail out if we have a JS global proxy object. |
| 79 __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset)); | 79 __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset)); |
| 80 __ cmp(r0, JS_GLOBAL_PROXY_TYPE); | 80 __ cmp(r0, JS_GLOBAL_PROXY_TYPE); |
| 81 __ j(equal, miss_label, not_taken); | 81 __ j(equal, miss_label, not_taken); |
| 82 | 82 |
| 83 // Possible work-around for http://crbug.com/16276. | 83 // Possible work-around for http://crbug.com/16276. |
|
Erik Corry
2009/12/09 10:43:40
Hmmm. Did this work?
Mads Ager (chromium)
2009/12/10 09:18:18
I don't know, but you are right that we should che
| |
| 84 __ cmp(r0, JS_GLOBAL_OBJECT_TYPE); | 84 __ cmp(r0, JS_GLOBAL_OBJECT_TYPE); |
| 85 __ j(equal, miss_label, not_taken); | 85 __ j(equal, miss_label, not_taken); |
| 86 __ cmp(r0, JS_BUILTINS_OBJECT_TYPE); | 86 __ cmp(r0, JS_BUILTINS_OBJECT_TYPE); |
| 87 __ j(equal, miss_label, not_taken); | 87 __ j(equal, miss_label, not_taken); |
| 88 | 88 |
| 89 // Load properties array. | |
| 90 __ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset)); | |
| 91 | |
| 89 // Check that the properties array is a dictionary. | 92 // Check that the properties array is a dictionary. |
| 90 __ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset)); | 93 if (check_dictionary) { |
| 91 __ cmp(FieldOperand(r0, HeapObject::kMapOffset), | 94 __ cmp(FieldOperand(r0, HeapObject::kMapOffset), |
| 92 Immediate(Factory::hash_table_map())); | 95 Immediate(Factory::hash_table_map())); |
| 93 __ j(not_equal, miss_label); | 96 __ j(not_equal, miss_label); |
| 97 } | |
| 94 | 98 |
| 95 // Compute the capacity mask. | 99 // Compute the capacity mask. |
| 96 const int kCapacityOffset = | 100 const int kCapacityOffset = |
| 97 StringDictionary::kHeaderSize + | 101 StringDictionary::kHeaderSize + |
| 98 StringDictionary::kCapacityIndex * kPointerSize; | 102 StringDictionary::kCapacityIndex * kPointerSize; |
| 99 __ mov(r2, FieldOperand(r0, kCapacityOffset)); | 103 __ mov(r2, FieldOperand(r0, kCapacityOffset)); |
| 100 __ shr(r2, kSmiTagSize); // convert smi to int | 104 __ shr(r2, kSmiTagSize); // convert smi to int |
| 101 __ dec(r2); | 105 __ dec(r2); |
| 102 | 106 |
| 103 // Generate an unrolled loop that performs a few probes before | 107 // Generate an unrolled loop that performs a few probes before |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 216 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 220 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
| 217 } | 221 } |
| 218 | 222 |
| 219 | 223 |
| 220 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 224 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
| 221 // ----------- S t a t e ------------- | 225 // ----------- S t a t e ------------- |
| 222 // -- esp[0] : return address | 226 // -- esp[0] : return address |
| 223 // -- esp[4] : name | 227 // -- esp[4] : name |
| 224 // -- esp[8] : receiver | 228 // -- esp[8] : receiver |
| 225 // ----------------------------------- | 229 // ----------------------------------- |
| 226 Label slow, check_string, index_int, index_string, check_pixel_array; | 230 Label slow, check_string, index_int, index_string; |
| 231 Label check_pixel_array, probe_dictionary; | |
| 227 | 232 |
| 228 // Load name and receiver. | 233 // Load name and receiver. |
| 229 __ mov(eax, Operand(esp, kPointerSize)); | 234 __ mov(eax, Operand(esp, kPointerSize)); |
| 230 __ mov(ecx, Operand(esp, 2 * kPointerSize)); | 235 __ mov(ecx, Operand(esp, 2 * kPointerSize)); |
| 231 | 236 |
| 232 // Check that the object isn't a smi. | 237 // Check that the object isn't a smi. |
| 233 __ test(ecx, Immediate(kSmiTagMask)); | 238 __ test(ecx, Immediate(kSmiTagMask)); |
| 234 __ j(zero, &slow, not_taken); | 239 __ j(zero, &slow, not_taken); |
| 235 | 240 |
| 236 // Get the map of the receiver. | 241 // Get the map of the receiver. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 292 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); | 297 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); |
| 293 Generate(masm, ExternalReference(Runtime::kKeyedGetProperty)); | 298 Generate(masm, ExternalReference(Runtime::kKeyedGetProperty)); |
| 294 | 299 |
| 295 __ bind(&check_string); | 300 __ bind(&check_string); |
| 296 // The key is not a smi. | 301 // The key is not a smi. |
| 297 // Is it a string? | 302 // Is it a string? |
| 298 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); | 303 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); |
| 299 __ j(above_equal, &slow); | 304 __ j(above_equal, &slow); |
| 300 // Is the string an array index, with cached numeric value? | 305 // Is the string an array index, with cached numeric value? |
| 301 __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset)); | 306 __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset)); |
| 302 __ test(ebx, Immediate(String::kIsArrayIndexMask)); | 307 __ test(ebx, Immediate(String::kIsArrayIndexMask)); |
|
Erik Corry
2009/12/09 10:43:40
Can't we do this with a single test instruction in
Mads Ager (chromium)
2009/12/10 09:18:18
No. If we jump, we use the fact that the hash fiel
| |
| 303 __ j(not_zero, &index_string, not_taken); | 308 __ j(not_zero, &index_string, not_taken); |
| 304 | 309 |
| 305 // If the string is a symbol, do a quick inline probe of the receiver's | 310 // Is the string a symbol? |
| 306 // dictionary, if it exists. | |
| 307 __ movzx_b(ebx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 311 __ movzx_b(ebx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 308 __ test(ebx, Immediate(kIsSymbolMask)); | 312 __ test(ebx, Immediate(kIsSymbolMask)); |
|
Erik Corry
2009/12/09 10:43:40
And here?
Mads Ager (chromium)
2009/12/10 09:18:18
No, because we are not looking at a word, but only
| |
| 309 __ j(zero, &slow, not_taken); | 313 __ j(zero, &slow, not_taken); |
| 310 // Probe the dictionary leaving result in ecx. | 314 |
| 311 GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax); | 315 // If the receiver is a fast-case object, check the keyed lookup |
| 316 // cache. Otherwise probe the dictionary leaving result in ecx. | |
| 317 __ mov(ebx, FieldOperand(ecx, JSObject::kPropertiesOffset)); | |
| 318 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | |
| 319 Immediate(Factory::hash_table_map())); | |
| 320 __ j(equal, &probe_dictionary); | |
| 321 | |
| 322 // Load the map of the receiver, compute the keyed lookup cache hash | |
|
Erik Corry
2009/12/09 10:43:40
Don't we need to check the interceptor bit here or
Mads Ager (chromium)
2009/12/10 09:18:18
No. I those cases we will never put the map-name p
| |
| 323 // based on 32 bits of the map pointer and the string hash. | |
| 324 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); | |
| 325 __ mov(edx, ebx); | |
| 326 __ shr(edx, KeyedLookupCache::kMapHashShift); | |
| 327 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); | |
| 328 __ shr(eax, String::kHashShift); | |
| 329 __ xor_(edx, Operand(eax)); | |
| 330 __ and_(edx, KeyedLookupCache::kCapacityMask); | |
| 331 | |
| 332 // Load the key (consisting of map and symbol) from the cache and | |
| 333 // check for match. | |
| 334 ExternalReference cache_keys | |
| 335 = ExternalReference::keyed_lookup_cache_keys(); | |
| 336 __ mov(edi, edx); | |
| 337 __ shl(edi, kPointerSizeLog2 + 1); | |
|
Erik Corry
2009/12/09 10:43:40
You can combine this mov-shl-mov-cmp combination i
Mads Ager (chromium)
2009/12/10 09:18:18
Done in the ia32 version. Can't do a times_16 sca
| |
| 338 __ mov(eax, Operand::StaticArray(edi, times_1, cache_keys)); | |
| 339 __ cmp(ebx, Operand(eax)); | |
| 340 __ j(not_equal, &slow); | |
| 341 __ mov(eax, Operand(esp, kPointerSize)); | |
| 342 __ add(Operand(edi), Immediate(kPointerSize)); | |
| 343 __ mov(edi, Operand::StaticArray(edi, times_1, cache_keys)); | |
| 344 __ cmp(eax, Operand(edi)); | |
|
Erik Corry
2009/12/09 10:43:40
And this cmp could just take the operand instead o
Mads Ager (chromium)
2009/12/10 09:18:18
Done.
| |
| 345 __ j(not_equal, &slow); | |
| 346 | |
| 347 // Get field offset and check that it is an in-object property. | |
|
Erik Corry
2009/12/09 10:43:40
In a later change we could handle out-of-object fa
Mads Ager (chromium)
2009/12/10 09:18:18
Yes, we can and we probably should.
| |
| 348 ExternalReference cache_field_offsets | |
| 349 = ExternalReference::keyed_lookup_cache_field_offsets(); | |
| 350 __ mov(eax, | |
| 351 Operand::StaticArray(edx, times_pointer_size, cache_field_offsets)); | |
| 352 __ movzx_b(edx, FieldOperand(ebx, Map::kInObjectPropertiesOffset)); | |
| 353 __ cmp(eax, Operand(edx)); | |
| 354 __ j(above_equal, &slow); | |
| 355 | |
| 356 // Load in-object property. | |
| 357 __ sub(eax, Operand(edx)); | |
| 358 __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceSizeOffset)); | |
| 359 __ add(eax, Operand(edx)); | |
| 360 __ mov(eax, FieldOperand(ecx, eax, times_pointer_size, 0)); | |
| 361 __ ret(0); | |
| 362 | |
| 363 // Do a quick inline probe of the receiver's dictionary, if it | |
| 364 // exists. | |
| 365 __ bind(&probe_dictionary); | |
| 366 GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax, false); | |
| 312 GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, edx); | 367 GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, edx); |
| 313 __ mov(eax, Operand(ecx)); | 368 __ mov(eax, Operand(ecx)); |
| 314 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); | 369 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); |
| 315 __ ret(0); | 370 __ ret(0); |
| 371 | |
| 316 // If the hash field contains an array index pick it out. The assert checks | 372 // If the hash field contains an array index pick it out. The assert checks |
| 317 // that the constants for the maximum number of digits for an array index | 373 // that the constants for the maximum number of digits for an array index |
| 318 // cached in the hash field and the number of bits reserved for it does not | 374 // cached in the hash field and the number of bits reserved for it does not |
| 319 // conflict. | 375 // conflict. |
| 320 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < | 376 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < |
| 321 (1 << String::kArrayIndexValueBits)); | 377 (1 << String::kArrayIndexValueBits)); |
| 322 __ bind(&index_string); | 378 __ bind(&index_string); |
| 323 __ mov(eax, Operand(ebx)); | 379 __ mov(eax, Operand(ebx)); |
| 324 __ and_(eax, String::kArrayIndexHashMask); | 380 __ and_(eax, String::kArrayIndexHashMask); |
| 325 __ shr(eax, String::kHashShift); | 381 __ shr(eax, String::kHashShift); |
| (...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 878 __ bind(&miss); | 934 __ bind(&miss); |
| 879 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); | 935 Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); |
| 880 } | 936 } |
| 881 | 937 |
| 882 | 938 |
| 883 static void GenerateNormalHelper(MacroAssembler* masm, | 939 static void GenerateNormalHelper(MacroAssembler* masm, |
| 884 int argc, | 940 int argc, |
| 885 bool is_global_object, | 941 bool is_global_object, |
| 886 Label* miss) { | 942 Label* miss) { |
| 887 // Search dictionary - put result in register edx. | 943 // Search dictionary - put result in register edx. |
| 888 GenerateDictionaryLoad(masm, miss, eax, edx, ebx, ecx); | 944 GenerateDictionaryLoad(masm, miss, eax, edx, ebx, ecx, true); |
| 889 | 945 |
| 890 // Move the result to register edi and check that it isn't a smi. | 946 // Move the result to register edi and check that it isn't a smi. |
| 891 __ mov(edi, Operand(edx)); | 947 __ mov(edi, Operand(edx)); |
| 892 __ test(edx, Immediate(kSmiTagMask)); | 948 __ test(edx, Immediate(kSmiTagMask)); |
| 893 __ j(zero, miss, not_taken); | 949 __ j(zero, miss, not_taken); |
| 894 | 950 |
| 895 // Check that the value is a JavaScript function. | 951 // Check that the value is a JavaScript function. |
| 896 __ CmpObjectType(edx, JS_FUNCTION_TYPE, edx); | 952 __ CmpObjectType(edx, JS_FUNCTION_TYPE, edx); |
| 897 __ j(not_equal, miss, not_taken); | 953 __ j(not_equal, miss, not_taken); |
| 898 | 954 |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1081 __ cmp(edx, JS_GLOBAL_PROXY_TYPE); | 1137 __ cmp(edx, JS_GLOBAL_PROXY_TYPE); |
| 1082 __ j(equal, &global, not_taken); | 1138 __ j(equal, &global, not_taken); |
| 1083 | 1139 |
| 1084 // Check for non-global object that requires access check. | 1140 // Check for non-global object that requires access check. |
| 1085 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset)); | 1141 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset)); |
| 1086 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded)); | 1142 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded)); |
| 1087 __ j(not_zero, &miss, not_taken); | 1143 __ j(not_zero, &miss, not_taken); |
| 1088 | 1144 |
| 1089 // Search the dictionary placing the result in eax. | 1145 // Search the dictionary placing the result in eax. |
| 1090 __ bind(&probe); | 1146 __ bind(&probe); |
| 1091 GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx); | 1147 GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx, true); |
| 1092 GenerateCheckNonObjectOrLoaded(masm, &miss, eax, edx); | 1148 GenerateCheckNonObjectOrLoaded(masm, &miss, eax, edx); |
| 1093 __ ret(0); | 1149 __ ret(0); |
| 1094 | 1150 |
| 1095 // Global object access: Check access rights. | 1151 // Global object access: Check access rights. |
| 1096 __ bind(&global); | 1152 __ bind(&global); |
| 1097 __ CheckAccessGlobalProxy(eax, edx, &miss); | 1153 __ CheckAccessGlobalProxy(eax, edx, &miss); |
| 1098 __ jmp(&probe); | 1154 __ jmp(&probe); |
| 1099 | 1155 |
| 1100 // Cache miss: Restore receiver from stack and jump to runtime. | 1156 // Cache miss: Restore receiver from stack and jump to runtime. |
| 1101 __ bind(&miss); | 1157 __ bind(&miss); |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1362 | 1418 |
| 1363 // Do tail-call to runtime routine. | 1419 // Do tail-call to runtime routine. |
| 1364 __ TailCallRuntime( | 1420 __ TailCallRuntime( |
| 1365 ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3, 1); | 1421 ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3, 1); |
| 1366 } | 1422 } |
| 1367 | 1423 |
| 1368 #undef __ | 1424 #undef __ |
| 1369 | 1425 |
| 1370 | 1426 |
| 1371 } } // namespace v8::internal | 1427 } } // namespace v8::internal |
| OLD | NEW |