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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 // This function may return false negatives, so miss_label | 49 // This function may return false negatives, so miss_label |
50 // must always call a backup property load that is complete. | 50 // must always call a backup property load that is complete. |
51 // This function is safe to call if the receiver has fast properties, | 51 // This function is safe to call if the receiver has fast properties, |
52 // or if name is not a symbol, and will jump to the miss_label in that case. | 52 // or if name is not a symbol, and will jump to the miss_label in that case. |
53 static void GenerateDictionaryLoad(MacroAssembler* masm, | 53 static void GenerateDictionaryLoad(MacroAssembler* masm, |
54 Label* miss_label, | 54 Label* miss_label, |
55 Register r0, | 55 Register r0, |
56 Register r1, | 56 Register r1, |
57 Register r2, | 57 Register r2, |
58 Register name, | 58 Register name, |
| 59 Register r4, |
59 DictionaryCheck check_dictionary) { | 60 DictionaryCheck check_dictionary) { |
60 // Register use: | 61 // Register use: |
61 // | 62 // |
62 // r0 - used to hold the property dictionary. | 63 // r0 - used to hold the property dictionary. |
63 // | 64 // |
64 // r1 - initially the receiver | 65 // r1 - initially the receiver. |
65 // - used for the index into the property dictionary | 66 // - unchanged on any jump to miss_label. |
66 // - holds the result on exit. | 67 // - holds the result on exit. |
67 // | 68 // |
68 // r2 - used to hold the capacity of the property dictionary. | 69 // r2 - used to hold the capacity of the property dictionary. |
69 // | 70 // |
70 // name - holds the name of the property and is unchanged. | 71 // name - holds the name of the property and is unchanged. |
| 72 // r4 - used to hold the index into the property dictionary. |
71 | 73 |
72 Label done; | 74 Label done; |
73 | 75 |
74 // Check for the absence of an interceptor. | 76 // Check for the absence of an interceptor. |
75 // Load the map into r0. | 77 // Load the map into r0. |
76 __ movq(r0, FieldOperand(r1, JSObject::kMapOffset)); | 78 __ movq(r0, FieldOperand(r1, JSObject::kMapOffset)); |
77 | 79 |
78 // Bail out if the receiver has a named interceptor. | 80 // Bail out if the receiver has a named interceptor. |
79 __ testl(FieldOperand(r0, Map::kBitFieldOffset), | 81 __ testl(FieldOperand(r0, Map::kBitFieldOffset), |
80 Immediate(1 << Map::kHasNamedInterceptor)); | 82 Immediate(1 << Map::kHasNamedInterceptor)); |
(...skipping 28 matching lines...) Expand all Loading... |
109 | 111 |
110 // Generate an unrolled loop that performs a few probes before | 112 // Generate an unrolled loop that performs a few probes before |
111 // giving up. Measurements done on Gmail indicate that 2 probes | 113 // giving up. Measurements done on Gmail indicate that 2 probes |
112 // cover ~93% of loads from dictionaries. | 114 // cover ~93% of loads from dictionaries. |
113 static const int kProbes = 4; | 115 static const int kProbes = 4; |
114 const int kElementsStartOffset = | 116 const int kElementsStartOffset = |
115 StringDictionary::kHeaderSize + | 117 StringDictionary::kHeaderSize + |
116 StringDictionary::kElementsStartIndex * kPointerSize; | 118 StringDictionary::kElementsStartIndex * kPointerSize; |
117 for (int i = 0; i < kProbes; i++) { | 119 for (int i = 0; i < kProbes; i++) { |
118 // Compute the masked index: (hash + i + i * i) & mask. | 120 // Compute the masked index: (hash + i + i * i) & mask. |
119 __ movl(r1, FieldOperand(name, String::kHashFieldOffset)); | 121 __ movl(r4, FieldOperand(name, String::kHashFieldOffset)); |
120 __ shrl(r1, Immediate(String::kHashShift)); | 122 __ shrl(r4, Immediate(String::kHashShift)); |
121 if (i > 0) { | 123 if (i > 0) { |
122 __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i))); | 124 __ addl(r4, Immediate(StringDictionary::GetProbeOffset(i))); |
123 } | 125 } |
124 __ and_(r1, r2); | 126 __ and_(r4, r2); |
125 | 127 |
126 // Scale the index by multiplying by the entry size. | 128 // Scale the index by multiplying by the entry size. |
127 ASSERT(StringDictionary::kEntrySize == 3); | 129 ASSERT(StringDictionary::kEntrySize == 3); |
128 __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 | 130 __ lea(r4, Operand(r4, r4, times_2, 0)); // r4 = r4 * 3 |
129 | 131 |
130 // Check if the key is identical to the name. | 132 // Check if the key is identical to the name. |
131 __ cmpq(name, Operand(r0, r1, times_pointer_size, | 133 __ cmpq(name, Operand(r0, r4, times_pointer_size, |
132 kElementsStartOffset - kHeapObjectTag)); | 134 kElementsStartOffset - kHeapObjectTag)); |
133 if (i != kProbes - 1) { | 135 if (i != kProbes - 1) { |
134 __ j(equal, &done); | 136 __ j(equal, &done); |
135 } else { | 137 } else { |
136 __ j(not_equal, miss_label); | 138 __ j(not_equal, miss_label); |
137 } | 139 } |
138 } | 140 } |
139 | 141 |
140 // Check that the value is a normal property. | 142 // Check that the value is a normal property. |
141 __ bind(&done); | 143 __ bind(&done); |
142 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 144 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
143 __ Test(Operand(r0, r1, times_pointer_size, kDetailsOffset - kHeapObjectTag), | 145 __ Test(Operand(r0, r4, times_pointer_size, kDetailsOffset - kHeapObjectTag), |
144 Smi::FromInt(PropertyDetails::TypeField::mask())); | 146 Smi::FromInt(PropertyDetails::TypeField::mask())); |
145 __ j(not_zero, miss_label); | 147 __ j(not_zero, miss_label); |
146 | 148 |
147 // Get the value at the masked, scaled index. | 149 // Get the value at the masked, scaled index. |
148 const int kValueOffset = kElementsStartOffset + kPointerSize; | 150 const int kValueOffset = kElementsStartOffset + kPointerSize; |
149 __ movq(r1, | 151 __ movq(r1, |
150 Operand(r0, r1, times_pointer_size, kValueOffset - kHeapObjectTag)); | 152 Operand(r0, r4, times_pointer_size, kValueOffset - kHeapObjectTag)); |
151 } | 153 } |
152 | 154 |
153 | 155 |
154 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | 156 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
155 Label* miss, | 157 Label* miss, |
156 Register elements, | 158 Register elements, |
157 Register key, | 159 Register key, |
158 Register r0, | 160 Register r0, |
159 Register r1, | 161 Register r1, |
160 Register r2) { | 162 Register r2) { |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
494 | 496 |
495 // Do a quick inline probe of the receiver's dictionary, if it | 497 // Do a quick inline probe of the receiver's dictionary, if it |
496 // exists. | 498 // exists. |
497 __ bind(&probe_dictionary); | 499 __ bind(&probe_dictionary); |
498 GenerateDictionaryLoad(masm, | 500 GenerateDictionaryLoad(masm, |
499 &slow, | 501 &slow, |
500 rbx, | 502 rbx, |
501 rcx, | 503 rcx, |
502 rdx, | 504 rdx, |
503 rax, | 505 rax, |
| 506 rdi, |
504 DICTIONARY_CHECK_DONE); | 507 DICTIONARY_CHECK_DONE); |
505 __ movq(rax, rcx); | 508 __ movq(rax, rcx); |
506 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); | 509 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); |
507 __ ret(0); | 510 __ ret(0); |
508 // If the hash field contains an array index pick it out. The assert checks | 511 // If the hash field contains an array index pick it out. The assert checks |
509 // that the constants for the maximum number of digits for an array index | 512 // that the constants for the maximum number of digits for an array index |
510 // cached in the hash field and the number of bits reserved for it does not | 513 // cached in the hash field and the number of bits reserved for it does not |
511 // conflict. | 514 // conflict. |
512 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < | 515 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < |
513 (1 << String::kArrayIndexValueBits)); | 516 (1 << String::kArrayIndexValueBits)); |
(...skipping 707 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1221 // rcx : function name | 1224 // rcx : function name |
1222 // rdx : receiver | 1225 // rdx : receiver |
1223 // rsp[0] : return address | 1226 // rsp[0] : return address |
1224 // rsp[8] : argument argc | 1227 // rsp[8] : argument argc |
1225 // rsp[16] : argument argc - 1 | 1228 // rsp[16] : argument argc - 1 |
1226 // ... | 1229 // ... |
1227 // rsp[argc * 8] : argument 1 | 1230 // rsp[argc * 8] : argument 1 |
1228 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1231 // rsp[(argc + 1) * 8] : argument 0 = receiver |
1229 // ----------------------------------- | 1232 // ----------------------------------- |
1230 // Search dictionary - put result in register rdx. | 1233 // Search dictionary - put result in register rdx. |
1231 GenerateDictionaryLoad(masm, miss, rax, rdx, rbx, rcx, CHECK_DICTIONARY); | 1234 GenerateDictionaryLoad(masm, miss, rax, rdx, rbx, rcx, rdi, CHECK_DICTIONARY); |
1232 | 1235 |
1233 // Move the result to register rdi and check that it isn't a smi. | 1236 // Move the result to register rdi and check that it isn't a smi. |
1234 __ movq(rdi, rdx); | 1237 __ movq(rdi, rdx); |
1235 __ JumpIfSmi(rdx, miss); | 1238 __ JumpIfSmi(rdx, miss); |
1236 | 1239 |
1237 // Check that the value is a JavaScript function. | 1240 // Check that the value is a JavaScript function. |
1238 __ CmpObjectType(rdx, JS_FUNCTION_TYPE, rdx); | 1241 __ CmpObjectType(rdx, JS_FUNCTION_TYPE, rdx); |
1239 __ j(not_equal, miss); | 1242 __ j(not_equal, miss); |
1240 | 1243 |
1241 // Patch the receiver with the global proxy if necessary. | 1244 // Patch the receiver with the global proxy if necessary. |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1326 void LoadIC::ClearInlinedVersion(Address address) { | 1329 void LoadIC::ClearInlinedVersion(Address address) { |
1327 // Reset the map check of the inlined inobject property load (if | 1330 // Reset the map check of the inlined inobject property load (if |
1328 // present) to guarantee failure by holding an invalid map (the null | 1331 // present) to guarantee failure by holding an invalid map (the null |
1329 // value). The offset can be patched to anything. | 1332 // value). The offset can be patched to anything. |
1330 PatchInlinedLoad(address, Heap::null_value(), kMaxInt); | 1333 PatchInlinedLoad(address, Heap::null_value(), kMaxInt); |
1331 } | 1334 } |
1332 | 1335 |
1333 | 1336 |
1334 void LoadIC::GenerateMiss(MacroAssembler* masm) { | 1337 void LoadIC::GenerateMiss(MacroAssembler* masm) { |
1335 // ----------- S t a t e ------------- | 1338 // ----------- S t a t e ------------- |
| 1339 // -- rax : receiver |
1336 // -- rcx : name | 1340 // -- rcx : name |
1337 // -- rsp[0] : return address | 1341 // -- rsp[0] : return address |
1338 // -- rsp[8] : receiver | |
1339 // ----------------------------------- | 1342 // ----------------------------------- |
1340 | 1343 |
1341 __ pop(rbx); | 1344 __ pop(rbx); |
1342 __ push(Operand(rsp, 0)); // receiver | 1345 __ push(rax); // receiver |
1343 __ push(rcx); // name | 1346 __ push(rcx); // name |
1344 __ push(rbx); // return address | 1347 __ push(rbx); // return address |
1345 | 1348 |
1346 // Perform tail call to the entry. | 1349 // Perform tail call to the entry. |
1347 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); | 1350 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); |
1348 __ TailCallExternalReference(ref, 2, 1); | 1351 __ TailCallExternalReference(ref, 2, 1); |
1349 } | 1352 } |
1350 | 1353 |
1351 | 1354 |
1352 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 1355 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
1353 // ----------- S t a t e ------------- | 1356 // ----------- S t a t e ------------- |
| 1357 // -- rax : receiver |
1354 // -- rcx : name | 1358 // -- rcx : name |
1355 // -- rsp[0] : return address | 1359 // -- rsp[0] : return address |
1356 // -- rsp[8] : receiver | |
1357 // ----------------------------------- | 1360 // ----------------------------------- |
1358 Label miss; | 1361 Label miss; |
1359 | 1362 |
1360 __ movq(rax, Operand(rsp, kPointerSize)); | |
1361 | |
1362 StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss); | 1363 StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss); |
1363 __ bind(&miss); | 1364 __ bind(&miss); |
1364 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 1365 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
1365 } | 1366 } |
1366 | 1367 |
1367 | 1368 |
1368 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { | 1369 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { |
1369 // ----------- S t a t e ------------- | 1370 // ----------- S t a t e ------------- |
| 1371 // -- rax : receiver |
1370 // -- rcx : name | 1372 // -- rcx : name |
1371 // -- rsp[0] : return address | 1373 // -- rsp[0] : return address |
1372 // -- rsp[8] : receiver | |
1373 // ----------------------------------- | 1374 // ----------------------------------- |
1374 Label miss; | 1375 Label miss; |
1375 | 1376 |
1376 __ movq(rax, Operand(rsp, kPointerSize)); | |
1377 | |
1378 StubCompiler::GenerateLoadFunctionPrototype(masm, rax, rdx, rbx, &miss); | 1377 StubCompiler::GenerateLoadFunctionPrototype(masm, rax, rdx, rbx, &miss); |
1379 __ bind(&miss); | 1378 __ bind(&miss); |
1380 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 1379 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
1381 } | 1380 } |
1382 | 1381 |
1383 | 1382 |
1384 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { | 1383 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { |
1385 // ----------- S t a t e ------------- | 1384 // ----------- S t a t e ------------- |
| 1385 // -- rax : receiver |
1386 // -- rcx : name | 1386 // -- rcx : name |
1387 // -- rsp[0] : return address | 1387 // -- rsp[0] : return address |
1388 // -- rsp[8] : receiver | |
1389 // ----------------------------------- | 1388 // ----------------------------------- |
1390 | 1389 |
1391 __ movq(rax, Operand(rsp, kPointerSize)); | |
1392 | |
1393 // Probe the stub cache. | 1390 // Probe the stub cache. |
1394 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, | 1391 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, |
1395 NOT_IN_LOOP, | 1392 NOT_IN_LOOP, |
1396 MONOMORPHIC); | 1393 MONOMORPHIC); |
1397 StubCache::GenerateProbe(masm, flags, rax, rcx, rbx, rdx); | 1394 StubCache::GenerateProbe(masm, flags, rax, rcx, rbx, rdx); |
1398 | 1395 |
1399 // Cache miss: Jump to runtime. | 1396 // Cache miss: Jump to runtime. |
1400 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 1397 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
1401 } | 1398 } |
1402 | 1399 |
1403 | 1400 |
1404 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 1401 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
1405 // ----------- S t a t e ------------- | 1402 // ----------- S t a t e ------------- |
| 1403 // -- rax : receiver |
1406 // -- rcx : name | 1404 // -- rcx : name |
1407 // -- rsp[0] : return address | 1405 // -- rsp[0] : return address |
1408 // -- rsp[8] : receiver | |
1409 // ----------------------------------- | 1406 // ----------------------------------- |
1410 Label miss, probe, global; | 1407 Label miss, probe, global; |
1411 | 1408 |
1412 __ movq(rax, Operand(rsp, kPointerSize)); | |
1413 | |
1414 // Check that the receiver isn't a smi. | 1409 // Check that the receiver isn't a smi. |
1415 __ JumpIfSmi(rax, &miss); | 1410 __ JumpIfSmi(rax, &miss); |
1416 | 1411 |
1417 // Check that the receiver is a valid JS object. | 1412 // Check that the receiver is a valid JS object. |
1418 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 1413 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); |
1419 __ j(below, &miss); | 1414 __ j(below, &miss); |
1420 | 1415 |
1421 // If this assert fails, we have to check upper bound too. | 1416 // If this assert fails, we have to check upper bound too. |
1422 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 1417 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
1423 | 1418 |
1424 // Check for access to global object (unlikely). | 1419 // Check for access to global object (unlikely). |
1425 __ CmpInstanceType(rbx, JS_GLOBAL_PROXY_TYPE); | 1420 __ CmpInstanceType(rbx, JS_GLOBAL_PROXY_TYPE); |
1426 __ j(equal, &global); | 1421 __ j(equal, &global); |
1427 | 1422 |
1428 // Check for non-global object that requires access check. | 1423 // Check for non-global object that requires access check. |
1429 __ testl(FieldOperand(rbx, Map::kBitFieldOffset), | 1424 __ testl(FieldOperand(rbx, Map::kBitFieldOffset), |
1430 Immediate(1 << Map::kIsAccessCheckNeeded)); | 1425 Immediate(1 << Map::kIsAccessCheckNeeded)); |
1431 __ j(not_zero, &miss); | 1426 __ j(not_zero, &miss); |
1432 | 1427 |
1433 // Search the dictionary placing the result in rax. | 1428 // Search the dictionary placing the result in rax. |
1434 __ bind(&probe); | 1429 __ bind(&probe); |
1435 GenerateDictionaryLoad(masm, &miss, rdx, rax, rbx, rcx, CHECK_DICTIONARY); | 1430 GenerateDictionaryLoad(masm, &miss, rdx, rax, rbx, |
| 1431 rcx, rdi, CHECK_DICTIONARY); |
1436 __ ret(0); | 1432 __ ret(0); |
1437 | 1433 |
1438 // Global object access: Check access rights. | 1434 // Global object access: Check access rights. |
1439 __ bind(&global); | 1435 __ bind(&global); |
1440 __ CheckAccessGlobalProxy(rax, rdx, &miss); | 1436 __ CheckAccessGlobalProxy(rax, rdx, &miss); |
1441 __ jmp(&probe); | 1437 __ jmp(&probe); |
1442 | 1438 |
1443 // Cache miss: Restore receiver from stack and jump to runtime. | 1439 // Cache miss: Jump to runtime. |
1444 __ bind(&miss); | 1440 __ bind(&miss); |
1445 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | |
1446 GenerateMiss(masm); | 1441 GenerateMiss(masm); |
1447 } | 1442 } |
1448 | 1443 |
1449 | 1444 |
1450 void LoadIC::GenerateStringLength(MacroAssembler* masm) { | 1445 void LoadIC::GenerateStringLength(MacroAssembler* masm) { |
1451 // ----------- S t a t e ------------- | 1446 // ----------- S t a t e ------------- |
| 1447 // -- rax : receiver |
1452 // -- rcx : name | 1448 // -- rcx : name |
1453 // -- rsp[0] : return address | 1449 // -- rsp[0] : return address |
1454 // -- rsp[8] : receiver | |
1455 // ----------------------------------- | 1450 // ----------------------------------- |
1456 Label miss; | 1451 Label miss; |
1457 | 1452 |
1458 __ movq(rax, Operand(rsp, kPointerSize)); | |
1459 | |
1460 StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss); | 1453 StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss); |
1461 __ bind(&miss); | 1454 __ bind(&miss); |
1462 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 1455 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
1463 } | 1456 } |
1464 | 1457 |
1465 | 1458 |
1466 bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { | 1459 bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { |
1467 // The address of the instruction following the call. | 1460 // The address of the instruction following the call. |
1468 Address test_instruction_address = | 1461 Address test_instruction_address = |
1469 address + Assembler::kCallTargetAddressOffset; | 1462 address + Assembler::kCallTargetAddressOffset; |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1579 GenerateMiss(masm); | 1572 GenerateMiss(masm); |
1580 } | 1573 } |
1581 | 1574 |
1582 | 1575 |
1583 #undef __ | 1576 #undef __ |
1584 | 1577 |
1585 | 1578 |
1586 } } // namespace v8::internal | 1579 } } // namespace v8::internal |
1587 | 1580 |
1588 #endif // V8_TARGET_ARCH_X64 | 1581 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |