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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Register r4, |
| 60 Register result, |
60 DictionaryCheck check_dictionary) { | 61 DictionaryCheck check_dictionary) { |
61 // Register use: | 62 // Register use: |
62 // | 63 // |
63 // r0 - used to hold the property dictionary. | 64 // r0 - used to hold the property dictionary and is unchanged. |
64 // | 65 // |
65 // r1 - initially the receiver. | 66 // r1 - used to hold the receiver and is unchanged. |
66 // - unchanged on any jump to miss_label. | |
67 // - holds the result on exit. | |
68 // | 67 // |
69 // r2 - used to hold the capacity of the property dictionary. | 68 // r2 - used to hold the capacity of the property dictionary. |
70 // | 69 // |
71 // name - holds the name of the property and is unchanged. | 70 // name - holds the name of the property and is unchanged. |
| 71 // |
72 // r4 - used to hold the index into the property dictionary. | 72 // r4 - used to hold the index into the property dictionary. |
| 73 // |
| 74 // result - holds the result on exit if the load succeeded. |
73 | 75 |
74 Label done; | 76 Label done; |
75 | 77 |
76 // Check for the absence of an interceptor. | 78 // Check for the absence of an interceptor. |
77 // Load the map into r0. | 79 // Load the map into r0. |
78 __ movq(r0, FieldOperand(r1, JSObject::kMapOffset)); | 80 __ movq(r0, FieldOperand(r1, JSObject::kMapOffset)); |
79 | 81 |
80 // Bail out if the receiver has a named interceptor. | 82 // Bail out if the receiver has a named interceptor. |
81 __ testl(FieldOperand(r0, Map::kBitFieldOffset), | 83 __ testl(FieldOperand(r0, Map::kBitFieldOffset), |
82 Immediate(1 << Map::kHasNamedInterceptor)); | 84 Immediate(1 << Map::kHasNamedInterceptor)); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 | 143 |
142 // Check that the value is a normal property. | 144 // Check that the value is a normal property. |
143 __ bind(&done); | 145 __ bind(&done); |
144 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 146 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
145 __ Test(Operand(r0, r4, times_pointer_size, kDetailsOffset - kHeapObjectTag), | 147 __ Test(Operand(r0, r4, times_pointer_size, kDetailsOffset - kHeapObjectTag), |
146 Smi::FromInt(PropertyDetails::TypeField::mask())); | 148 Smi::FromInt(PropertyDetails::TypeField::mask())); |
147 __ j(not_zero, miss_label); | 149 __ j(not_zero, miss_label); |
148 | 150 |
149 // Get the value at the masked, scaled index. | 151 // Get the value at the masked, scaled index. |
150 const int kValueOffset = kElementsStartOffset + kPointerSize; | 152 const int kValueOffset = kElementsStartOffset + kPointerSize; |
151 __ movq(r1, | 153 __ movq(result, |
152 Operand(r0, r4, times_pointer_size, kValueOffset - kHeapObjectTag)); | 154 Operand(r0, r4, times_pointer_size, kValueOffset - kHeapObjectTag)); |
153 } | 155 } |
154 | 156 |
155 | 157 |
156 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | 158 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
157 Label* miss, | 159 Label* miss, |
158 Register elements, | 160 Register elements, |
159 Register key, | 161 Register key, |
160 Register r0, | 162 Register r0, |
161 Register r1, | 163 Register r1, |
162 Register r2) { | 164 Register r2, |
| 165 Register result) { |
163 // Register use: | 166 // Register use: |
164 // | 167 // |
165 // elements - holds the slow-case elements of the receiver and is unchanged. | 168 // elements - holds the slow-case elements of the receiver on entry. |
| 169 // Unchanged unless 'result' is the same register. |
166 // | 170 // |
167 // key - holds the smi key on entry and is unchanged if a branch is | 171 // key - holds the smi key on entry. |
168 // performed to the miss label. | 172 // Unchanged unless 'result' is the same register. |
169 // Holds the result on exit if the load succeeded. | |
170 // | 173 // |
171 // Scratch registers: | 174 // Scratch registers: |
172 // | 175 // |
173 // r0 - holds the untagged key on entry and holds the hash once computed. | 176 // r0 - holds the untagged key on entry and holds the hash once computed. |
174 // | 177 // |
175 // r1 - used to hold the capacity mask of the dictionary | 178 // r1 - used to hold the capacity mask of the dictionary |
176 // | 179 // |
177 // r2 - used for the index into the dictionary. | 180 // r2 - used for the index into the dictionary. |
| 181 // |
| 182 // result - holds the result on exit if the load succeeded. |
| 183 // Allowed to be the same as 'key' or 'result'. |
| 184 // Unchanged on bailout so 'key' or 'result' can be used |
| 185 // in further computation. |
| 186 |
178 Label done; | 187 Label done; |
179 | 188 |
180 // Compute the hash code from the untagged key. This must be kept in sync | 189 // Compute the hash code from the untagged key. This must be kept in sync |
181 // with ComputeIntegerHash in utils.h. | 190 // with ComputeIntegerHash in utils.h. |
182 // | 191 // |
183 // hash = ~hash + (hash << 15); | 192 // hash = ~hash + (hash << 15); |
184 __ movl(r1, r0); | 193 __ movl(r1, r0); |
185 __ notl(r0); | 194 __ notl(r0); |
186 __ shll(r1, Immediate(15)); | 195 __ shll(r1, Immediate(15)); |
187 __ addl(r0, r1); | 196 __ addl(r0, r1); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 const int kDetailsOffset = | 248 const int kDetailsOffset = |
240 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | 249 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
241 ASSERT_EQ(NORMAL, 0); | 250 ASSERT_EQ(NORMAL, 0); |
242 __ Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), | 251 __ Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset), |
243 Smi::FromInt(PropertyDetails::TypeField::mask())); | 252 Smi::FromInt(PropertyDetails::TypeField::mask())); |
244 __ j(not_zero, miss); | 253 __ j(not_zero, miss); |
245 | 254 |
246 // Get the value at the masked, scaled index. | 255 // Get the value at the masked, scaled index. |
247 const int kValueOffset = | 256 const int kValueOffset = |
248 NumberDictionary::kElementsStartOffset + kPointerSize; | 257 NumberDictionary::kElementsStartOffset + kPointerSize; |
249 __ movq(key, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); | 258 __ movq(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset)); |
250 } | 259 } |
251 | 260 |
252 | 261 |
253 // One byte opcode for test eax,0xXXXXXXXX. | 262 // One byte opcode for test eax,0xXXXXXXXX. |
254 static const byte kTestEaxByte = 0xA9; | 263 static const byte kTestEaxByte = 0xA9; |
255 | 264 |
256 | 265 |
257 static bool PatchInlinedMapCheck(Address address, Object* map) { | 266 static bool PatchInlinedMapCheck(Address address, Object* map) { |
258 // Arguments are address of start of call sequence that called | 267 // Arguments are address of start of call sequence that called |
259 // the IC, | 268 // the IC, |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 __ pop(rbx); | 348 __ pop(rbx); |
340 __ push(rdx); // receiver | 349 __ push(rdx); // receiver |
341 __ push(rax); // name | 350 __ push(rax); // name |
342 __ push(rbx); // return address | 351 __ push(rbx); // return address |
343 | 352 |
344 // Perform tail call to the entry. | 353 // Perform tail call to the entry. |
345 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 354 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
346 } | 355 } |
347 | 356 |
348 | 357 |
| 358 // Checks the receiver for special cases (value type, slow case bits). |
| 359 // Falls through for regular JS object. |
| 360 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, |
| 361 Register receiver, |
| 362 Register map, |
| 363 Label* slow) { |
| 364 // Register use: |
| 365 // receiver - holds the receiver and is unchanged. |
| 366 // Scratch registers: |
| 367 // map - used to hold the map of the receiver. |
| 368 |
| 369 // Check that the object isn't a smi. |
| 370 __ JumpIfSmi(receiver, slow); |
| 371 |
| 372 // Check that the object is some kind of JS object EXCEPT JS Value type. |
| 373 // In the case that the object is a value-wrapper object, |
| 374 // we enter the runtime system to make sure that indexing |
| 375 // into string objects work as intended. |
| 376 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
| 377 __ CmpObjectType(receiver, JS_OBJECT_TYPE, map); |
| 378 __ j(below, slow); |
| 379 |
| 380 // Check bit field. |
| 381 __ testb(FieldOperand(map, Map::kBitFieldOffset), |
| 382 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask)); |
| 383 __ j(not_zero, slow); |
| 384 } |
| 385 |
| 386 |
| 387 // Loads an indexed element from a fast case array. |
| 388 static void GenerateFastArrayLoad(MacroAssembler* masm, |
| 389 Register receiver, |
| 390 Register key, |
| 391 Register elements, |
| 392 Register scratch, |
| 393 Register result, |
| 394 Label* not_fast_array, |
| 395 Label* out_of_range) { |
| 396 // Register use: |
| 397 // |
| 398 // receiver - holds the receiver on entry. |
| 399 // Unchanged unless 'result' is the same register. |
| 400 // |
| 401 // key - holds the smi key on entry. |
| 402 // Unchanged unless 'result' is the same register. |
| 403 // |
| 404 // elements - holds the elements of the receiver on exit. |
| 405 // |
| 406 // result - holds the result on exit if the load succeeded. |
| 407 // Allowed to be the the same as 'receiver' or 'key'. |
| 408 // Unchanged on bailout so 'receiver' and 'key' can be safely |
| 409 // used by further computation. |
| 410 // |
| 411 // Scratch registers: |
| 412 // |
| 413 // scratch - used to hold elements of the receiver and the loaded value. |
| 414 |
| 415 __ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset)); |
| 416 // Check that the object is in fast mode (not dictionary). |
| 417 __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), |
| 418 Heap::kFixedArrayMapRootIndex); |
| 419 __ j(not_equal, not_fast_array); |
| 420 // Check that the key (index) is within bounds. |
| 421 __ SmiCompare(key, FieldOperand(elements, FixedArray::kLengthOffset)); |
| 422 // Unsigned comparison rejects negative indices. |
| 423 __ j(above_equal, out_of_range); |
| 424 // Fast case: Do the load. |
| 425 SmiIndex index = masm->SmiToIndex(scratch, key, kPointerSizeLog2); |
| 426 __ movq(scratch, FieldOperand(elements, |
| 427 index.reg, |
| 428 index.scale, |
| 429 FixedArray::kHeaderSize)); |
| 430 __ CompareRoot(scratch, Heap::kTheHoleValueRootIndex); |
| 431 // In case the loaded value is the_hole we have to consult GetProperty |
| 432 // to ensure the prototype chain is searched. |
| 433 __ j(equal, out_of_range); |
| 434 if (!result.is(scratch)) { |
| 435 __ movq(result, scratch); |
| 436 } |
| 437 } |
| 438 |
| 439 |
| 440 // Checks whether a key is an array index string or a symbol string. |
| 441 // Falls through if the key is a symbol. |
| 442 static void GenerateKeyStringCheck(MacroAssembler* masm, |
| 443 Register key, |
| 444 Register map, |
| 445 Register hash, |
| 446 Label* index_string, |
| 447 Label* not_symbol) { |
| 448 // Register use: |
| 449 // key - holds the key and is unchanged. Assumed to be non-smi. |
| 450 // Scratch registers: |
| 451 // map - used to hold the map of the key. |
| 452 // hash - used to hold the hash of the key. |
| 453 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map); |
| 454 __ j(above_equal, not_symbol); |
| 455 // Is the string an array index, with cached numeric value? |
| 456 __ movl(hash, FieldOperand(key, String::kHashFieldOffset)); |
| 457 __ testl(hash, Immediate(String::kContainsCachedArrayIndexMask)); |
| 458 __ j(zero, index_string); // The value in hash is used at jump target. |
| 459 |
| 460 // Is the string a symbol? |
| 461 ASSERT(kSymbolTag != 0); |
| 462 __ testb(FieldOperand(map, Map::kInstanceTypeOffset), |
| 463 Immediate(kIsSymbolMask)); |
| 464 __ j(zero, not_symbol); |
| 465 } |
| 466 |
| 467 |
| 468 // Picks out an array index from the hash field. |
| 469 static void GenerateIndexFromHash(MacroAssembler* masm, |
| 470 Register key, |
| 471 Register hash) { |
| 472 // Register use: |
| 473 // key - holds the overwritten key on exit. |
| 474 // hash - holds the key's hash. Clobbered. |
| 475 |
| 476 // The assert checks that the constants for the maximum number of digits |
| 477 // for an array index cached in the hash field and the number of bits |
| 478 // reserved for it does not conflict. |
| 479 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < |
| 480 (1 << String::kArrayIndexValueBits)); |
| 481 // We want the smi-tagged index in key. Even if we subsequently go to |
| 482 // the slow case, converting the key to a smi is always valid. |
| 483 // key: string key |
| 484 // hash: key's hash field, including its array index value. |
| 485 __ and_(hash, Immediate(String::kArrayIndexValueMask)); |
| 486 __ shr(hash, Immediate(String::kHashShift)); |
| 487 // Here we actually clobber the key which will be used if calling into |
| 488 // runtime later. However as the new key is the numeric value of a string key |
| 489 // there is no difference in using either key. |
| 490 __ Integer32ToSmi(key, hash); |
| 491 } |
| 492 |
| 493 |
349 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 494 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
350 // ----------- S t a t e ------------- | 495 // ----------- S t a t e ------------- |
351 // -- rax : key | 496 // -- rax : key |
352 // -- rdx : receiver | 497 // -- rdx : receiver |
353 // -- rsp[0] : return address | 498 // -- rsp[0] : return address |
354 // ----------------------------------- | 499 // ----------------------------------- |
355 Label slow, check_string, index_smi, index_string; | 500 Label slow, check_string, index_smi, index_string; |
356 Label check_pixel_array, probe_dictionary, check_number_dictionary; | 501 Label check_pixel_array, probe_dictionary, check_number_dictionary; |
357 | 502 |
358 // Check that the object isn't a smi. | 503 GenerateKeyedLoadReceiverCheck(masm, rdx, rcx, &slow); |
359 __ JumpIfSmi(rdx, &slow); | |
360 | |
361 // Check that the object is some kind of JS object EXCEPT JS Value type. | |
362 // In the case that the object is a value-wrapper object, | |
363 // we enter the runtime system to make sure that indexing | |
364 // into string objects work as intended. | |
365 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | |
366 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); | |
367 __ j(below, &slow); | |
368 | |
369 // Check bit field. | |
370 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), | |
371 Immediate(kSlowCaseBitFieldMask)); | |
372 __ j(not_zero, &slow); | |
373 | 504 |
374 // Check that the key is a smi. | 505 // Check that the key is a smi. |
375 __ JumpIfNotSmi(rax, &check_string); | 506 __ JumpIfNotSmi(rax, &check_string); |
376 __ bind(&index_smi); | 507 __ bind(&index_smi); |
377 // Now the key is known to be a smi. This place is also jumped to from below | 508 // Now the key is known to be a smi. This place is also jumped to from below |
378 // where a numeric string is converted to a smi. | 509 // where a numeric string is converted to a smi. |
379 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset)); | 510 |
380 // Check that the object is in fast mode (not dictionary). | 511 GenerateFastArrayLoad(masm, |
381 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | 512 rdx, |
382 Heap::kFixedArrayMapRootIndex); | 513 rax, |
383 __ j(not_equal, &check_pixel_array); | 514 rcx, |
384 // Check that the key (index) is within bounds. | 515 rbx, |
385 __ SmiCompare(rax, FieldOperand(rcx, FixedArray::kLengthOffset)); | 516 rax, |
386 __ j(above_equal, &slow); // Unsigned comparison rejects negative indices. | 517 &check_pixel_array, |
387 // Fast case: Do the load. | 518 &slow); |
388 SmiIndex index = masm->SmiToIndex(rbx, rax, kPointerSizeLog2); | |
389 __ movq(rbx, FieldOperand(rcx, | |
390 index.reg, | |
391 index.scale, | |
392 FixedArray::kHeaderSize)); | |
393 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); | |
394 // In case the loaded value is the_hole we have to consult GetProperty | |
395 // to ensure the prototype chain is searched. | |
396 __ j(equal, &slow); | |
397 __ movq(rax, rbx); | |
398 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); | 519 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); |
399 __ ret(0); | 520 __ ret(0); |
400 | 521 |
401 __ bind(&check_pixel_array); | 522 __ bind(&check_pixel_array); |
402 // Check whether the elements object is a pixel array. | 523 // Check whether the elements object is a pixel array. |
403 // rdx: receiver | 524 // rdx: receiver |
404 // rax: key | 525 // rax: key |
405 // rcx: elements array | 526 // rcx: elements array |
406 __ SmiToInteger32(rbx, rax); // Used on both directions of next branch. | 527 __ SmiToInteger32(rbx, rax); // Used on both directions of next branch. |
407 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | 528 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), |
408 Heap::kPixelArrayMapRootIndex); | 529 Heap::kPixelArrayMapRootIndex); |
409 __ j(not_equal, &check_number_dictionary); | 530 __ j(not_equal, &check_number_dictionary); |
410 __ cmpl(rbx, FieldOperand(rcx, PixelArray::kLengthOffset)); | 531 __ cmpl(rbx, FieldOperand(rcx, PixelArray::kLengthOffset)); |
411 __ j(above_equal, &slow); | 532 __ j(above_equal, &slow); |
412 __ movq(rax, FieldOperand(rcx, PixelArray::kExternalPointerOffset)); | 533 __ movq(rax, FieldOperand(rcx, PixelArray::kExternalPointerOffset)); |
413 __ movzxbq(rax, Operand(rax, rbx, times_1, 0)); | 534 __ movzxbq(rax, Operand(rax, rbx, times_1, 0)); |
414 __ Integer32ToSmi(rax, rax); | 535 __ Integer32ToSmi(rax, rax); |
415 __ ret(0); | 536 __ ret(0); |
416 | 537 |
417 __ bind(&check_number_dictionary); | 538 __ bind(&check_number_dictionary); |
418 // Check whether the elements is a number dictionary. | 539 // Check whether the elements is a number dictionary. |
419 // rdx: receiver | 540 // rdx: receiver |
420 // rax: key | 541 // rax: key |
421 // rbx: key as untagged int32 | 542 // rbx: key as untagged int32 |
422 // rcx: elements | 543 // rcx: elements |
423 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), | 544 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset), |
424 Heap::kHashTableMapRootIndex); | 545 Heap::kHashTableMapRootIndex); |
425 __ j(not_equal, &slow); | 546 __ j(not_equal, &slow); |
426 GenerateNumberDictionaryLoad(masm, &slow, rcx, rax, rbx, r9, rdi); | 547 GenerateNumberDictionaryLoad(masm, &slow, rcx, rax, rbx, r9, rdi, rax); |
427 __ ret(0); | 548 __ ret(0); |
428 | 549 |
429 __ bind(&slow); | 550 __ bind(&slow); |
430 // Slow case: Jump to runtime. | 551 // Slow case: Jump to runtime. |
431 // rdx: receiver | 552 // rdx: receiver |
432 // rax: key | 553 // rax: key |
433 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); | 554 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); |
434 GenerateRuntimeGetProperty(masm); | 555 GenerateRuntimeGetProperty(masm); |
435 | 556 |
436 __ bind(&check_string); | 557 __ bind(&check_string); |
437 // The key is not a smi. | 558 GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow); |
438 // Is it a string? | |
439 // rdx: receiver | |
440 // rax: key | |
441 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rcx); | |
442 __ j(above_equal, &slow); | |
443 // Is the string an array index, with cached numeric value? | |
444 __ movl(rbx, FieldOperand(rax, String::kHashFieldOffset)); | |
445 __ testl(rbx, Immediate(String::kContainsCachedArrayIndexMask)); | |
446 __ j(zero, &index_string); // The value in rbx is used at jump target. | |
447 | |
448 // Is the string a symbol? | |
449 ASSERT(kSymbolTag != 0); | |
450 __ testb(FieldOperand(rcx, Map::kInstanceTypeOffset), | |
451 Immediate(kIsSymbolMask)); | |
452 __ j(zero, &slow); | |
453 | 559 |
454 // If the receiver is a fast-case object, check the keyed lookup | 560 // If the receiver is a fast-case object, check the keyed lookup |
455 // cache. Otherwise probe the dictionary leaving result in rcx. | 561 // cache. Otherwise probe the dictionary leaving result in rcx. |
456 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); | 562 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); |
457 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | 563 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
458 Heap::kHashTableMapRootIndex); | 564 Heap::kHashTableMapRootIndex); |
459 __ j(equal, &probe_dictionary); | 565 __ j(equal, &probe_dictionary); |
460 | 566 |
461 // Load the map of the receiver, compute the keyed lookup cache hash | 567 // Load the map of the receiver, compute the keyed lookup cache hash |
462 // based on 32 bits of the map pointer and the string hash. | 568 // based on 32 bits of the map pointer and the string hash. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
502 __ bind(&probe_dictionary); | 608 __ bind(&probe_dictionary); |
503 // rdx: receiver | 609 // rdx: receiver |
504 // rax: key | 610 // rax: key |
505 GenerateDictionaryLoad(masm, | 611 GenerateDictionaryLoad(masm, |
506 &slow, | 612 &slow, |
507 rbx, | 613 rbx, |
508 rdx, | 614 rdx, |
509 rcx, | 615 rcx, |
510 rax, | 616 rax, |
511 rdi, | 617 rdi, |
| 618 rax, |
512 DICTIONARY_CHECK_DONE); | 619 DICTIONARY_CHECK_DONE); |
513 __ movq(rax, rdx); | |
514 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); | 620 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); |
515 __ ret(0); | 621 __ ret(0); |
516 // If the hash field contains an array index pick it out. The assert checks | 622 |
517 // that the constants for the maximum number of digits for an array index | |
518 // cached in the hash field and the number of bits reserved for it does not | |
519 // conflict. | |
520 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < | |
521 (1 << String::kArrayIndexValueBits)); | |
522 __ bind(&index_string); | 623 __ bind(&index_string); |
523 // We want the smi-tagged index in rax. Even if we subsequently go to | 624 GenerateIndexFromHash(masm, rax, rbx); |
524 // the slow case, converting the key to a smi is always valid. | |
525 // rdx: receiver | |
526 // rax: key (a string) | |
527 // rbx: key's hash field, including its array index value. | |
528 __ and_(rbx, Immediate(String::kArrayIndexValueMask)); | |
529 __ shr(rbx, Immediate(String::kHashShift)); | |
530 // Here we actually clobber the key (rax) which will be used if calling into | |
531 // runtime later. However as the new key is the numeric value of a string key | |
532 // there is no difference in using either key. | |
533 __ Integer32ToSmi(rax, rbx); | |
534 // Now jump to the place where smi keys are handled. | |
535 __ jmp(&index_smi); | 625 __ jmp(&index_smi); |
536 } | 626 } |
537 | 627 |
538 | 628 |
539 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { | 629 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { |
540 // ----------- S t a t e ------------- | 630 // ----------- S t a t e ------------- |
541 // -- rax : key | 631 // -- rax : key |
542 // -- rdx : receiver | 632 // -- rdx : receiver |
543 // -- rsp[0] : return address | 633 // -- rsp[0] : return address |
544 // ----------------------------------- | 634 // ----------------------------------- |
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1102 } | 1192 } |
1103 __ ret(0); | 1193 __ ret(0); |
1104 } | 1194 } |
1105 | 1195 |
1106 // Slow case: call runtime. | 1196 // Slow case: call runtime. |
1107 __ bind(&slow); | 1197 __ bind(&slow); |
1108 GenerateRuntimeSetProperty(masm); | 1198 GenerateRuntimeSetProperty(masm); |
1109 } | 1199 } |
1110 | 1200 |
1111 | 1201 |
1112 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { | 1202 // Defined in ic.cc. |
| 1203 Object* CallIC_Miss(Arguments args); |
| 1204 |
| 1205 |
| 1206 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { |
1113 // ----------- S t a t e ------------- | 1207 // ----------- S t a t e ------------- |
1114 // rcx : function name | 1208 // rcx : function name |
1115 // rsp[0] : return address | 1209 // rsp[0] : return address |
1116 // rsp[8] : argument argc | 1210 // rsp[8] : argument argc |
1117 // rsp[16] : argument argc - 1 | 1211 // rsp[16] : argument argc - 1 |
1118 // ... | 1212 // ... |
1119 // rsp[argc * 8] : argument 1 | 1213 // rsp[argc * 8] : argument 1 |
1120 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1214 // rsp[(argc + 1) * 8] : argument 0 = receiver |
1121 // ----------------------------------- | 1215 // ----------------------------------- |
1122 // Get the receiver of the function from the stack; 1 ~ return address. | 1216 // Get the receiver of the function from the stack; 1 ~ return address. |
1123 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | 1217 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
1124 | 1218 |
1125 // Enter an internal frame. | 1219 // Enter an internal frame. |
1126 __ EnterInternalFrame(); | 1220 __ EnterInternalFrame(); |
1127 | 1221 |
1128 // Push the receiver and the name of the function. | 1222 // Push the receiver and the name of the function. |
1129 __ push(rdx); | 1223 __ push(rdx); |
1130 __ push(rcx); | 1224 __ push(rcx); |
1131 | 1225 |
1132 // Call the entry. | 1226 // Call the entry. |
1133 CEntryStub stub(1); | 1227 CEntryStub stub(1); |
1134 __ movq(rax, Immediate(2)); | 1228 __ movq(rax, Immediate(2)); |
1135 __ movq(rbx, ExternalReference(IC_Utility(kCallIC_Miss))); | 1229 __ movq(rbx, ExternalReference(IC_Utility(id))); |
1136 __ CallStub(&stub); | 1230 __ CallStub(&stub); |
1137 | 1231 |
1138 // Move result to rdi and exit the internal frame. | 1232 // Move result to rdi and exit the internal frame. |
1139 __ movq(rdi, rax); | 1233 __ movq(rdi, rax); |
1140 __ LeaveInternalFrame(); | 1234 __ LeaveInternalFrame(); |
1141 | 1235 |
1142 // Check if the receiver is a global object of some sort. | 1236 // Check if the receiver is a global object of some sort. |
1143 Label invoke, global; | 1237 Label invoke, global; |
1144 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver | 1238 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver |
1145 __ JumpIfSmi(rdx, &invoke); | 1239 __ JumpIfSmi(rdx, &invoke); |
1146 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx); | 1240 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx); |
1147 __ j(equal, &global); | 1241 __ j(equal, &global); |
1148 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE); | 1242 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE); |
1149 __ j(not_equal, &invoke); | 1243 __ j(not_equal, &invoke); |
1150 | 1244 |
1151 // Patch the receiver on the stack. | 1245 // Patch the receiver on the stack. |
1152 __ bind(&global); | 1246 __ bind(&global); |
1153 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); | 1247 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); |
1154 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); | 1248 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); |
1155 | 1249 |
1156 // Invoke the function. | 1250 // Invoke the function. |
1157 ParameterCount actual(argc); | 1251 ParameterCount actual(argc); |
1158 __ bind(&invoke); | 1252 __ bind(&invoke); |
1159 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | 1253 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
1160 } | 1254 } |
1161 | 1255 |
1162 | 1256 |
1163 // Defined in ic.cc. | 1257 // The generated code does not accept smi keys. |
1164 Object* CallIC_Miss(Arguments args); | 1258 // The generated code falls through if both probes miss. |
1165 | 1259 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, |
1166 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { | 1260 int argc, |
| 1261 Code::Kind kind) { |
1167 // ----------- S t a t e ------------- | 1262 // ----------- S t a t e ------------- |
1168 // rcx : function name | 1263 // rcx : function name |
1169 // rsp[0] : return address | 1264 // rdx : receiver |
1170 // rsp[8] : argument argc | |
1171 // rsp[16] : argument argc - 1 | |
1172 // ... | |
1173 // rsp[argc * 8] : argument 1 | |
1174 // rsp[(argc + 1) * 8] : argument 0 = receiver | |
1175 // ----------------------------------- | 1265 // ----------------------------------- |
1176 Label number, non_number, non_string, boolean, probe, miss; | 1266 Label number, non_number, non_string, boolean, probe, miss; |
1177 | 1267 |
1178 // Get the receiver of the function from the stack; 1 ~ return address. | |
1179 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | |
1180 | |
1181 // Probe the stub cache. | 1268 // Probe the stub cache. |
1182 Code::Flags flags = | 1269 Code::Flags flags = |
1183 Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); | 1270 Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); |
1184 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, rax); | 1271 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, rax); |
1185 | 1272 |
1186 // If the stub cache probing failed, the receiver might be a value. | 1273 // If the stub cache probing failed, the receiver might be a value. |
1187 // For value objects, we use the map of the prototype objects for | 1274 // For value objects, we use the map of the prototype objects for |
1188 // the corresponding JSValue for the cache and that is what we need | 1275 // the corresponding JSValue for the cache and that is what we need |
1189 // to probe. | 1276 // to probe. |
1190 // | 1277 // |
1191 // Check for number. | 1278 // Check for number. |
1192 __ JumpIfSmi(rdx, &number); | 1279 __ JumpIfSmi(rdx, &number); |
1193 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rbx); | 1280 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rbx); |
(...skipping 18 matching lines...) Expand all Loading... |
1212 __ CompareRoot(rdx, Heap::kFalseValueRootIndex); | 1299 __ CompareRoot(rdx, Heap::kFalseValueRootIndex); |
1213 __ j(not_equal, &miss); | 1300 __ j(not_equal, &miss); |
1214 __ bind(&boolean); | 1301 __ bind(&boolean); |
1215 StubCompiler::GenerateLoadGlobalFunctionPrototype( | 1302 StubCompiler::GenerateLoadGlobalFunctionPrototype( |
1216 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx); | 1303 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx); |
1217 | 1304 |
1218 // Probe the stub cache for the value object. | 1305 // Probe the stub cache for the value object. |
1219 __ bind(&probe); | 1306 __ bind(&probe); |
1220 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg); | 1307 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg); |
1221 | 1308 |
1222 // Cache miss: Jump to runtime. | |
1223 __ bind(&miss); | 1309 __ bind(&miss); |
1224 GenerateMiss(masm, argc); | |
1225 } | 1310 } |
1226 | 1311 |
1227 | 1312 |
1228 static void GenerateNormalHelper(MacroAssembler* masm, | 1313 static void GenerateNormalHelper(MacroAssembler* masm, |
1229 int argc, | 1314 int argc, |
1230 bool is_global_object, | 1315 bool is_global_object, |
1231 Label* miss) { | 1316 Label* miss) { |
1232 // ----------- S t a t e ------------- | 1317 // ----------- S t a t e ------------- |
1233 // rcx : function name | 1318 // rcx : function name |
1234 // rdx : receiver | 1319 // rdx : receiver |
1235 // rsp[0] : return address | 1320 // rsp[0] : return address |
1236 // rsp[8] : argument argc | 1321 // rsp[8] : argument argc |
1237 // rsp[16] : argument argc - 1 | 1322 // rsp[16] : argument argc - 1 |
1238 // ... | 1323 // ... |
1239 // rsp[argc * 8] : argument 1 | 1324 // rsp[argc * 8] : argument 1 |
1240 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1325 // rsp[(argc + 1) * 8] : argument 0 = receiver |
1241 // ----------------------------------- | 1326 // ----------------------------------- |
1242 // Search dictionary - put result in register rdx. | 1327 // Search dictionary - put result in register rdx. |
1243 GenerateDictionaryLoad(masm, miss, rax, rdx, rbx, rcx, rdi, CHECK_DICTIONARY); | 1328 GenerateDictionaryLoad( |
| 1329 masm, miss, rax, rdx, rbx, rcx, rdi, rdi, CHECK_DICTIONARY); |
1244 | 1330 |
1245 // Move the result to register rdi and check that it isn't a smi. | 1331 __ JumpIfSmi(rdi, miss); |
1246 __ movq(rdi, rdx); | |
1247 __ JumpIfSmi(rdx, miss); | |
1248 | |
1249 // Check that the value is a JavaScript function. | 1332 // Check that the value is a JavaScript function. |
1250 __ CmpObjectType(rdx, JS_FUNCTION_TYPE, rdx); | 1333 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx); |
1251 __ j(not_equal, miss); | 1334 __ j(not_equal, miss); |
1252 | 1335 |
1253 // Patch the receiver with the global proxy if necessary. | 1336 // Patch the receiver with the global proxy if necessary. |
1254 if (is_global_object) { | 1337 if (is_global_object) { |
1255 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | |
1256 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); | 1338 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); |
1257 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); | 1339 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); |
1258 } | 1340 } |
1259 | 1341 |
1260 // Invoke the function. | 1342 // Invoke the function. |
1261 ParameterCount actual(argc); | 1343 ParameterCount actual(argc); |
1262 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | 1344 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
1263 } | 1345 } |
1264 | 1346 |
1265 | 1347 |
1266 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { | 1348 // The generated code falls through if the call should be handled by runtime. |
| 1349 static void GenerateCallNormal(MacroAssembler* masm, int argc) { |
1267 // ----------- S t a t e ------------- | 1350 // ----------- S t a t e ------------- |
1268 // rcx : function name | 1351 // rcx : function name |
1269 // rsp[0] : return address | 1352 // rsp[0] : return address |
1270 // rsp[8] : argument argc | 1353 // rsp[8] : argument argc |
1271 // rsp[16] : argument argc - 1 | 1354 // rsp[16] : argument argc - 1 |
1272 // ... | 1355 // ... |
1273 // rsp[argc * 8] : argument 1 | 1356 // rsp[argc * 8] : argument 1 |
1274 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1357 // rsp[(argc + 1) * 8] : argument 0 = receiver |
1275 // ----------------------------------- | 1358 // ----------------------------------- |
1276 Label miss, global_object, non_global_object; | 1359 Label miss, global_object, non_global_object; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1317 __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded)); | 1400 __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded)); |
1318 __ j(not_equal, &miss); | 1401 __ j(not_equal, &miss); |
1319 __ bind(&invoke); | 1402 __ bind(&invoke); |
1320 GenerateNormalHelper(masm, argc, false, &miss); | 1403 GenerateNormalHelper(masm, argc, false, &miss); |
1321 | 1404 |
1322 // Global object proxy access: Check access rights. | 1405 // Global object proxy access: Check access rights. |
1323 __ bind(&global_proxy); | 1406 __ bind(&global_proxy); |
1324 __ CheckAccessGlobalProxy(rdx, rax, &miss); | 1407 __ CheckAccessGlobalProxy(rdx, rax, &miss); |
1325 __ jmp(&invoke); | 1408 __ jmp(&invoke); |
1326 | 1409 |
1327 // Cache miss: Jump to runtime. | |
1328 __ bind(&miss); | 1410 __ bind(&miss); |
| 1411 } |
| 1412 |
| 1413 |
| 1414 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { |
| 1415 // ----------- S t a t e ------------- |
| 1416 // rcx : function name |
| 1417 // rsp[0] : return address |
| 1418 // rsp[8] : argument argc |
| 1419 // rsp[16] : argument argc - 1 |
| 1420 // ... |
| 1421 // rsp[argc * 8] : argument 1 |
| 1422 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1423 // ----------------------------------- |
| 1424 GenerateCallMiss(masm, argc, IC::kCallIC_Miss); |
| 1425 } |
| 1426 |
| 1427 |
| 1428 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { |
| 1429 // ----------- S t a t e ------------- |
| 1430 // rcx : function name |
| 1431 // rsp[0] : return address |
| 1432 // rsp[8] : argument argc |
| 1433 // rsp[16] : argument argc - 1 |
| 1434 // ... |
| 1435 // rsp[argc * 8] : argument 1 |
| 1436 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1437 // ----------------------------------- |
| 1438 |
| 1439 // Get the receiver of the function from the stack; 1 ~ return address. |
| 1440 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
| 1441 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC); |
| 1442 GenerateMiss(masm, argc); |
| 1443 } |
| 1444 |
| 1445 |
| 1446 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { |
| 1447 // ----------- S t a t e ------------- |
| 1448 // rcx : function name |
| 1449 // rsp[0] : return address |
| 1450 // rsp[8] : argument argc |
| 1451 // rsp[16] : argument argc - 1 |
| 1452 // ... |
| 1453 // rsp[argc * 8] : argument 1 |
| 1454 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1455 // ----------------------------------- |
| 1456 |
| 1457 GenerateCallNormal(masm, argc); |
1329 GenerateMiss(masm, argc); | 1458 GenerateMiss(masm, argc); |
1330 } | 1459 } |
1331 | 1460 |
1332 | 1461 |
1333 void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { | 1462 void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { |
1334 UNREACHABLE(); | 1463 // ----------- S t a t e ------------- |
| 1464 // rcx : function name |
| 1465 // rsp[0] : return address |
| 1466 // rsp[8] : argument argc |
| 1467 // rsp[16] : argument argc - 1 |
| 1468 // ... |
| 1469 // rsp[argc * 8] : argument 1 |
| 1470 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1471 // ----------------------------------- |
| 1472 |
| 1473 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss); |
1335 } | 1474 } |
1336 | 1475 |
1337 | 1476 |
1338 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { | 1477 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { |
1339 UNREACHABLE(); | 1478 // ----------- S t a t e ------------- |
| 1479 // rcx : function name |
| 1480 // rsp[0] : return address |
| 1481 // rsp[8] : argument argc |
| 1482 // rsp[16] : argument argc - 1 |
| 1483 // ... |
| 1484 // rsp[argc * 8] : argument 1 |
| 1485 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1486 // ----------------------------------- |
| 1487 |
| 1488 // Get the receiver of the function from the stack; 1 ~ return address. |
| 1489 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
| 1490 |
| 1491 Label do_call, slow_call, slow_load, slow_reload_receiver; |
| 1492 Label check_number_dictionary, check_string, lookup_monomorphic_cache; |
| 1493 Label index_smi, index_string; |
| 1494 |
| 1495 // Check that the key is a smi. |
| 1496 __ JumpIfNotSmi(rcx, &check_string); |
| 1497 |
| 1498 __ bind(&index_smi); |
| 1499 // Now the key is known to be a smi. This place is also jumped to from below |
| 1500 // where a numeric string is converted to a smi. |
| 1501 |
| 1502 GenerateKeyedLoadReceiverCheck(masm, rdx, rax, &slow_call); |
| 1503 |
| 1504 GenerateFastArrayLoad( |
| 1505 masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load); |
| 1506 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1); |
| 1507 |
| 1508 __ bind(&do_call); |
| 1509 // receiver in rdx is not used after this point. |
| 1510 // rcx: key |
| 1511 // rdi: function |
| 1512 |
| 1513 // Check that the value in edi is a JavaScript function. |
| 1514 __ JumpIfSmi(rdi, &slow_call); |
| 1515 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax); |
| 1516 __ j(not_equal, &slow_call); |
| 1517 // Invoke the function. |
| 1518 ParameterCount actual(argc); |
| 1519 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
| 1520 |
| 1521 __ bind(&check_number_dictionary); |
| 1522 // eax: elements |
| 1523 // ecx: smi key |
| 1524 // Check whether the elements is a number dictionary. |
| 1525 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
| 1526 Heap::kHashTableMapRootIndex); |
| 1527 __ SmiToInteger32(rbx, rcx); |
| 1528 // ebx: untagged index |
| 1529 GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi); |
| 1530 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1); |
| 1531 __ jmp(&do_call); |
| 1532 |
| 1533 __ bind(&slow_load); |
| 1534 // This branch is taken when calling KeyedCallIC_Miss is neither required |
| 1535 // nor beneficial. |
| 1536 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1); |
| 1537 __ EnterInternalFrame(); |
| 1538 __ push(rcx); // save the key |
| 1539 __ push(rdx); // pass the receiver |
| 1540 __ push(rcx); // pass the key |
| 1541 __ CallRuntime(Runtime::kKeyedGetProperty, 2); |
| 1542 __ pop(rcx); // restore the key |
| 1543 __ LeaveInternalFrame(); |
| 1544 __ movq(rdi, rax); |
| 1545 __ jmp(&do_call); |
| 1546 |
| 1547 __ bind(&check_string); |
| 1548 GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call); |
| 1549 |
| 1550 // The key is known to be a symbol. |
| 1551 // If the receiver is a regular JS object with slow properties then do |
| 1552 // a quick inline probe of the receiver's dictionary. |
| 1553 // Otherwise do the monomorphic cache probe. |
| 1554 GenerateKeyedLoadReceiverCheck(masm, rdx, rax, &lookup_monomorphic_cache); |
| 1555 |
| 1556 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); |
| 1557 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
| 1558 Heap::kHashTableMapRootIndex); |
| 1559 __ j(not_equal, &lookup_monomorphic_cache); |
| 1560 |
| 1561 GenerateDictionaryLoad( |
| 1562 masm, &slow_load, rbx, rdx, rax, rcx, rdi, rdi, DICTIONARY_CHECK_DONE); |
| 1563 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1); |
| 1564 __ jmp(&do_call); |
| 1565 |
| 1566 __ bind(&lookup_monomorphic_cache); |
| 1567 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1); |
| 1568 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); |
| 1569 // Fall through on miss. |
| 1570 |
| 1571 __ bind(&slow_call); |
| 1572 // This branch is taken if: |
| 1573 // - the receiver requires boxing or access check, |
| 1574 // - the key is neither smi nor symbol, |
| 1575 // - the value loaded is not a function, |
| 1576 // - there is hope that the runtime will create a monomorphic call stub |
| 1577 // that will get fetched next time. |
| 1578 __ IncrementCounter(&Counters::keyed_call_generic_slow, 1); |
| 1579 GenerateMiss(masm, argc); |
| 1580 |
| 1581 __ bind(&index_string); |
| 1582 GenerateIndexFromHash(masm, rcx, rbx); |
| 1583 // Now jump to the place where smi keys are handled. |
| 1584 __ jmp(&index_smi); |
1340 } | 1585 } |
1341 | 1586 |
1342 | 1587 |
1343 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { | 1588 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { |
1344 UNREACHABLE(); | 1589 // ----------- S t a t e ------------- |
| 1590 // rcx : function name |
| 1591 // rsp[0] : return address |
| 1592 // rsp[8] : argument argc |
| 1593 // rsp[16] : argument argc - 1 |
| 1594 // ... |
| 1595 // rsp[argc * 8] : argument 1 |
| 1596 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1597 // ----------------------------------- |
| 1598 |
| 1599 GenerateCallNormal(masm, argc); |
| 1600 GenerateMiss(masm, argc); |
1345 } | 1601 } |
1346 | 1602 |
1347 | 1603 |
1348 // The offset from the inlined patch site to the start of the | 1604 // The offset from the inlined patch site to the start of the |
1349 // inlined load instruction. | 1605 // inlined load instruction. |
1350 const int LoadIC::kOffsetToLoadInstruction = 20; | 1606 const int LoadIC::kOffsetToLoadInstruction = 20; |
1351 | 1607 |
1352 | 1608 |
1353 void LoadIC::ClearInlinedVersion(Address address) { | 1609 void LoadIC::ClearInlinedVersion(Address address) { |
1354 // Reset the map check of the inlined inobject property load (if | 1610 // Reset the map check of the inlined inobject property load (if |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1445 __ j(equal, &global); | 1701 __ j(equal, &global); |
1446 | 1702 |
1447 // Check for non-global object that requires access check. | 1703 // Check for non-global object that requires access check. |
1448 __ testl(FieldOperand(rbx, Map::kBitFieldOffset), | 1704 __ testl(FieldOperand(rbx, Map::kBitFieldOffset), |
1449 Immediate(1 << Map::kIsAccessCheckNeeded)); | 1705 Immediate(1 << Map::kIsAccessCheckNeeded)); |
1450 __ j(not_zero, &miss); | 1706 __ j(not_zero, &miss); |
1451 | 1707 |
1452 // Search the dictionary placing the result in rax. | 1708 // Search the dictionary placing the result in rax. |
1453 __ bind(&probe); | 1709 __ bind(&probe); |
1454 GenerateDictionaryLoad(masm, &miss, rdx, rax, rbx, | 1710 GenerateDictionaryLoad(masm, &miss, rdx, rax, rbx, |
1455 rcx, rdi, CHECK_DICTIONARY); | 1711 rcx, rdi, rax, CHECK_DICTIONARY); |
1456 __ ret(0); | 1712 __ ret(0); |
1457 | 1713 |
1458 // Global object access: Check access rights. | 1714 // Global object access: Check access rights. |
1459 __ bind(&global); | 1715 __ bind(&global); |
1460 __ CheckAccessGlobalProxy(rax, rdx, &miss); | 1716 __ CheckAccessGlobalProxy(rax, rdx, &miss); |
1461 __ jmp(&probe); | 1717 __ jmp(&probe); |
1462 | 1718 |
1463 // Cache miss: Jump to runtime. | 1719 // Cache miss: Jump to runtime. |
1464 __ bind(&miss); | 1720 __ bind(&miss); |
1465 GenerateMiss(masm); | 1721 GenerateMiss(masm); |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1596 GenerateMiss(masm); | 1852 GenerateMiss(masm); |
1597 } | 1853 } |
1598 | 1854 |
1599 | 1855 |
1600 #undef __ | 1856 #undef __ |
1601 | 1857 |
1602 | 1858 |
1603 } } // namespace v8::internal | 1859 } } // namespace v8::internal |
1604 | 1860 |
1605 #endif // V8_TARGET_ARCH_X64 | 1861 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |