| 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 27 matching lines...) Expand all Loading... |
| 38 namespace v8 { | 38 namespace v8 { |
| 39 namespace internal { | 39 namespace internal { |
| 40 | 40 |
| 41 // ---------------------------------------------------------------------------- | 41 // ---------------------------------------------------------------------------- |
| 42 // Static IC stub generators. | 42 // Static IC stub generators. |
| 43 // | 43 // |
| 44 | 44 |
| 45 #define __ ACCESS_MASM(masm) | 45 #define __ ACCESS_MASM(masm) |
| 46 | 46 |
| 47 | 47 |
| 48 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, |
| 49 Register type, |
| 50 Label* global_object) { |
| 51 // Register usage: |
| 52 // type: holds the receiver instance type on entry. |
| 53 __ cmpb(type, Immediate(JS_GLOBAL_OBJECT_TYPE)); |
| 54 __ j(equal, global_object); |
| 55 __ cmpb(type, Immediate(JS_BUILTINS_OBJECT_TYPE)); |
| 56 __ j(equal, global_object); |
| 57 __ cmpb(type, Immediate(JS_GLOBAL_PROXY_TYPE)); |
| 58 __ j(equal, global_object); |
| 59 } |
| 60 |
| 61 |
| 62 // Generated code falls through if the receiver is a regular non-global |
| 63 // JS object with slow properties and no interceptors. |
| 64 static void GenerateDictionaryLoadReceiverCheck(MacroAssembler* masm, |
| 65 Register receiver, |
| 66 Register r0, |
| 67 Register r1, |
| 68 Label* miss) { |
| 69 // Register usage: |
| 70 // receiver: holds the receiver on entry and is unchanged. |
| 71 // r0: used to hold receiver instance type. |
| 72 // Holds the property dictionary on fall through. |
| 73 // r1: used to hold receivers map. |
| 74 |
| 75 __ JumpIfSmi(receiver, miss); |
| 76 |
| 77 // Check that the receiver is a valid JS object. |
| 78 __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 79 __ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset)); |
| 80 __ cmpb(r0, Immediate(FIRST_JS_OBJECT_TYPE)); |
| 81 __ j(below, miss); |
| 82 |
| 83 // If this assert fails, we have to check upper bound too. |
| 84 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| 85 |
| 86 GenerateGlobalInstanceTypeCheck(masm, r0, miss); |
| 87 |
| 88 // Check for non-global object that requires access check. |
| 89 __ testb(FieldOperand(r1, Map::kBitFieldOffset), |
| 90 Immediate((1 << Map::kIsAccessCheckNeeded) | |
| 91 (1 << Map::kHasNamedInterceptor))); |
| 92 __ j(not_zero, miss); |
| 93 |
| 94 __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
| 95 __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset), |
| 96 Heap::kHashTableMapRootIndex); |
| 97 __ j(not_equal, miss); |
| 98 } |
| 99 |
| 100 |
| 48 // Helper function used to load a property from a dictionary backing storage. | 101 // Helper function used to load a property from a dictionary backing storage. |
| 49 // This function may return false negatives, so miss_label | 102 // This function may return false negatives, so miss_label |
| 50 // must always call a backup property load that is complete. | 103 // must always call a backup property load that is complete. |
| 51 // This function is safe to call if the receiver has fast properties, | 104 // This function is safe to call if name is not a symbol, and will jump to |
| 52 // or if name is not a symbol, and will jump to the miss_label in that case. | 105 // the miss_label in that case. |
| 106 // The generated code assumes that the receiver has slow properties, |
| 107 // is not a global object and does not have interceptors. |
| 53 static void GenerateDictionaryLoad(MacroAssembler* masm, | 108 static void GenerateDictionaryLoad(MacroAssembler* masm, |
| 54 Label* miss_label, | 109 Label* miss_label, |
| 110 Register elements, |
| 111 Register name, |
| 55 Register r0, | 112 Register r0, |
| 56 Register r1, | 113 Register r1, |
| 57 Register r2, | 114 Register result) { |
| 58 Register name, | |
| 59 Register r4, | |
| 60 Register result, | |
| 61 DictionaryCheck check_dictionary) { | |
| 62 // Register use: | 115 // Register use: |
| 63 // | 116 // |
| 64 // r0 - used to hold the property dictionary and is unchanged. | 117 // elements - holds the property dictionary on entry and is unchanged. |
| 65 // | 118 // |
| 66 // r1 - used to hold the receiver and is unchanged. | 119 // name - holds the name of the property on entry and is unchanged. |
| 67 // | 120 // |
| 68 // r2 - used to hold the capacity of the property dictionary. | 121 // r0 - used to hold the capacity of the property dictionary. |
| 69 // | 122 // |
| 70 // name - holds the name of the property and is unchanged. | 123 // r1 - used to hold the index into the property dictionary. |
| 71 // | |
| 72 // r4 - used to hold the index into the property dictionary. | |
| 73 // | 124 // |
| 74 // result - holds the result on exit if the load succeeded. | 125 // result - holds the result on exit if the load succeeded. |
| 75 | 126 |
| 76 Label done; | 127 Label done; |
| 77 | 128 |
| 78 // Check for the absence of an interceptor. | |
| 79 // Load the map into r0. | |
| 80 __ movq(r0, FieldOperand(r1, JSObject::kMapOffset)); | |
| 81 | |
| 82 // Bail out if the receiver has a named interceptor. | |
| 83 __ testl(FieldOperand(r0, Map::kBitFieldOffset), | |
| 84 Immediate(1 << Map::kHasNamedInterceptor)); | |
| 85 __ j(not_zero, miss_label); | |
| 86 | |
| 87 // Bail out if we have a JS global proxy object. | |
| 88 __ movzxbq(r0, FieldOperand(r0, Map::kInstanceTypeOffset)); | |
| 89 __ cmpb(r0, Immediate(JS_GLOBAL_PROXY_TYPE)); | |
| 90 __ j(equal, miss_label); | |
| 91 | |
| 92 // Possible work-around for http://crbug.com/16276. | |
| 93 __ cmpb(r0, Immediate(JS_GLOBAL_OBJECT_TYPE)); | |
| 94 __ j(equal, miss_label); | |
| 95 __ cmpb(r0, Immediate(JS_BUILTINS_OBJECT_TYPE)); | |
| 96 __ j(equal, miss_label); | |
| 97 | |
| 98 // Load properties array. | |
| 99 __ movq(r0, FieldOperand(r1, JSObject::kPropertiesOffset)); | |
| 100 | |
| 101 if (check_dictionary == CHECK_DICTIONARY) { | |
| 102 // Check that the properties array is a dictionary. | |
| 103 __ Cmp(FieldOperand(r0, HeapObject::kMapOffset), Factory::hash_table_map()); | |
| 104 __ j(not_equal, miss_label); | |
| 105 } | |
| 106 | |
| 107 // Compute the capacity mask. | 129 // Compute the capacity mask. |
| 108 const int kCapacityOffset = | 130 const int kCapacityOffset = |
| 109 StringDictionary::kHeaderSize + | 131 StringDictionary::kHeaderSize + |
| 110 StringDictionary::kCapacityIndex * kPointerSize; | 132 StringDictionary::kCapacityIndex * kPointerSize; |
| 111 __ SmiToInteger32(r2, FieldOperand(r0, kCapacityOffset)); | 133 __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset)); |
| 112 __ decl(r2); | 134 __ decl(r0); |
| 113 | 135 |
| 114 // Generate an unrolled loop that performs a few probes before | 136 // Generate an unrolled loop that performs a few probes before |
| 115 // giving up. Measurements done on Gmail indicate that 2 probes | 137 // giving up. Measurements done on Gmail indicate that 2 probes |
| 116 // cover ~93% of loads from dictionaries. | 138 // cover ~93% of loads from dictionaries. |
| 117 static const int kProbes = 4; | 139 static const int kProbes = 4; |
| 118 const int kElementsStartOffset = | 140 const int kElementsStartOffset = |
| 119 StringDictionary::kHeaderSize + | 141 StringDictionary::kHeaderSize + |
| 120 StringDictionary::kElementsStartIndex * kPointerSize; | 142 StringDictionary::kElementsStartIndex * kPointerSize; |
| 121 for (int i = 0; i < kProbes; i++) { | 143 for (int i = 0; i < kProbes; i++) { |
| 122 // Compute the masked index: (hash + i + i * i) & mask. | 144 // Compute the masked index: (hash + i + i * i) & mask. |
| 123 __ movl(r4, FieldOperand(name, String::kHashFieldOffset)); | 145 __ movl(r1, FieldOperand(name, String::kHashFieldOffset)); |
| 124 __ shrl(r4, Immediate(String::kHashShift)); | 146 __ shrl(r1, Immediate(String::kHashShift)); |
| 125 if (i > 0) { | 147 if (i > 0) { |
| 126 __ addl(r4, Immediate(StringDictionary::GetProbeOffset(i))); | 148 __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i))); |
| 127 } | 149 } |
| 128 __ and_(r4, r2); | 150 __ and_(r1, r0); |
| 129 | 151 |
| 130 // Scale the index by multiplying by the entry size. | 152 // Scale the index by multiplying by the entry size. |
| 131 ASSERT(StringDictionary::kEntrySize == 3); | 153 ASSERT(StringDictionary::kEntrySize == 3); |
| 132 __ lea(r4, Operand(r4, r4, times_2, 0)); // r4 = r4 * 3 | 154 __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 |
| 133 | 155 |
| 134 // Check if the key is identical to the name. | 156 // Check if the key is identical to the name. |
| 135 __ cmpq(name, Operand(r0, r4, times_pointer_size, | 157 __ cmpq(name, Operand(elements, r1, times_pointer_size, |
| 136 kElementsStartOffset - kHeapObjectTag)); | 158 kElementsStartOffset - kHeapObjectTag)); |
| 137 if (i != kProbes - 1) { | 159 if (i != kProbes - 1) { |
| 138 __ j(equal, &done); | 160 __ j(equal, &done); |
| 139 } else { | 161 } else { |
| 140 __ j(not_equal, miss_label); | 162 __ j(not_equal, miss_label); |
| 141 } | 163 } |
| 142 } | 164 } |
| 143 | 165 |
| 144 // Check that the value is a normal property. | 166 // Check that the value is a normal property. |
| 145 __ bind(&done); | 167 __ bind(&done); |
| 146 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 168 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
| 147 __ Test(Operand(r0, r4, times_pointer_size, kDetailsOffset - kHeapObjectTag), | 169 __ Test(Operand(elements, r1, times_pointer_size, |
| 170 kDetailsOffset - kHeapObjectTag), |
| 148 Smi::FromInt(PropertyDetails::TypeField::mask())); | 171 Smi::FromInt(PropertyDetails::TypeField::mask())); |
| 149 __ j(not_zero, miss_label); | 172 __ j(not_zero, miss_label); |
| 150 | 173 |
| 151 // Get the value at the masked, scaled index. | 174 // Get the value at the masked, scaled index. |
| 152 const int kValueOffset = kElementsStartOffset + kPointerSize; | 175 const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 153 __ movq(result, | 176 __ movq(result, |
| 154 Operand(r0, r4, times_pointer_size, kValueOffset - kHeapObjectTag)); | 177 Operand(elements, r1, times_pointer_size, |
| 178 kValueOffset - kHeapObjectTag)); |
| 155 } | 179 } |
| 156 | 180 |
| 157 | 181 |
| 158 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | 182 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
| 159 Label* miss, | 183 Label* miss, |
| 160 Register elements, | 184 Register elements, |
| 161 Register key, | 185 Register key, |
| 162 Register r0, | 186 Register r0, |
| 163 Register r1, | 187 Register r1, |
| 164 Register r2, | 188 Register r2, |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 } | 344 } |
| 321 | 345 |
| 322 | 346 |
| 323 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 347 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
| 324 // ----------- S t a t e ------------- | 348 // ----------- S t a t e ------------- |
| 325 // -- rax : key | 349 // -- rax : key |
| 326 // -- rdx : receiver | 350 // -- rdx : receiver |
| 327 // -- rsp[0] : return address | 351 // -- rsp[0] : return address |
| 328 // ----------------------------------- | 352 // ----------------------------------- |
| 329 | 353 |
| 354 __ IncrementCounter(&Counters::keyed_load_miss, 1); |
| 355 |
| 330 __ pop(rbx); | 356 __ pop(rbx); |
| 331 __ push(rdx); // receiver | 357 __ push(rdx); // receiver |
| 332 __ push(rax); // name | 358 __ push(rax); // name |
| 333 __ push(rbx); // return address | 359 __ push(rbx); // return address |
| 334 | 360 |
| 335 // Perform tail call to the entry. | 361 // Perform tail call to the entry. |
| 336 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss)); | 362 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss)); |
| 337 __ TailCallExternalReference(ref, 2, 1); | 363 __ TailCallExternalReference(ref, 2, 1); |
| 338 } | 364 } |
| 339 | 365 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 353 // Perform tail call to the entry. | 379 // Perform tail call to the entry. |
| 354 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 380 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 355 } | 381 } |
| 356 | 382 |
| 357 | 383 |
| 358 // Checks the receiver for special cases (value type, slow case bits). | 384 // Checks the receiver for special cases (value type, slow case bits). |
| 359 // Falls through for regular JS object. | 385 // Falls through for regular JS object. |
| 360 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, | 386 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, |
| 361 Register receiver, | 387 Register receiver, |
| 362 Register map, | 388 Register map, |
| 389 int interceptor_bit, |
| 363 Label* slow) { | 390 Label* slow) { |
| 364 // Register use: | 391 // Register use: |
| 365 // receiver - holds the receiver and is unchanged. | 392 // receiver - holds the receiver and is unchanged. |
| 366 // Scratch registers: | 393 // Scratch registers: |
| 367 // map - used to hold the map of the receiver. | 394 // map - used to hold the map of the receiver. |
| 368 | 395 |
| 369 // Check that the object isn't a smi. | 396 // Check that the object isn't a smi. |
| 370 __ JumpIfSmi(receiver, slow); | 397 __ JumpIfSmi(receiver, slow); |
| 371 | 398 |
| 372 // Check that the object is some kind of JS object EXCEPT JS Value type. | 399 // 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, | 400 // In the case that the object is a value-wrapper object, |
| 374 // we enter the runtime system to make sure that indexing | 401 // we enter the runtime system to make sure that indexing |
| 375 // into string objects work as intended. | 402 // into string objects work as intended. |
| 376 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 403 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
| 377 __ CmpObjectType(receiver, JS_OBJECT_TYPE, map); | 404 __ CmpObjectType(receiver, JS_OBJECT_TYPE, map); |
| 378 __ j(below, slow); | 405 __ j(below, slow); |
| 379 | 406 |
| 380 // Check bit field. | 407 // Check bit field. |
| 381 __ testb(FieldOperand(map, Map::kBitFieldOffset), | 408 __ testb(FieldOperand(map, Map::kBitFieldOffset), |
| 382 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask)); | 409 Immediate((1 << Map::kIsAccessCheckNeeded) | |
| 410 (1 << interceptor_bit))); |
| 383 __ j(not_zero, slow); | 411 __ j(not_zero, slow); |
| 384 } | 412 } |
| 385 | 413 |
| 386 | 414 |
| 387 // Loads an indexed element from a fast case array. | 415 // Loads an indexed element from a fast case array. |
| 388 static void GenerateFastArrayLoad(MacroAssembler* masm, | 416 static void GenerateFastArrayLoad(MacroAssembler* masm, |
| 389 Register receiver, | 417 Register receiver, |
| 390 Register key, | 418 Register key, |
| 391 Register elements, | 419 Register elements, |
| 392 Register scratch, | 420 Register scratch, |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 | 521 |
| 494 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 522 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
| 495 // ----------- S t a t e ------------- | 523 // ----------- S t a t e ------------- |
| 496 // -- rax : key | 524 // -- rax : key |
| 497 // -- rdx : receiver | 525 // -- rdx : receiver |
| 498 // -- rsp[0] : return address | 526 // -- rsp[0] : return address |
| 499 // ----------------------------------- | 527 // ----------------------------------- |
| 500 Label slow, check_string, index_smi, index_string; | 528 Label slow, check_string, index_smi, index_string; |
| 501 Label check_pixel_array, probe_dictionary, check_number_dictionary; | 529 Label check_pixel_array, probe_dictionary, check_number_dictionary; |
| 502 | 530 |
| 503 GenerateKeyedLoadReceiverCheck(masm, rdx, rcx, &slow); | |
| 504 | |
| 505 // Check that the key is a smi. | 531 // Check that the key is a smi. |
| 506 __ JumpIfNotSmi(rax, &check_string); | 532 __ JumpIfNotSmi(rax, &check_string); |
| 507 __ bind(&index_smi); | 533 __ bind(&index_smi); |
| 508 // Now the key is known to be a smi. This place is also jumped to from below | 534 // Now the key is known to be a smi. This place is also jumped to from below |
| 509 // where a numeric string is converted to a smi. | 535 // where a numeric string is converted to a smi. |
| 510 | 536 |
| 537 GenerateKeyedLoadReceiverCheck( |
| 538 masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow); |
| 539 |
| 511 GenerateFastArrayLoad(masm, | 540 GenerateFastArrayLoad(masm, |
| 512 rdx, | 541 rdx, |
| 513 rax, | 542 rax, |
| 514 rcx, | 543 rcx, |
| 515 rbx, | 544 rbx, |
| 516 rax, | 545 rax, |
| 517 &check_pixel_array, | 546 &check_pixel_array, |
| 518 &slow); | 547 &slow); |
| 519 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); | 548 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); |
| 520 __ ret(0); | 549 __ ret(0); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 550 __ bind(&slow); | 579 __ bind(&slow); |
| 551 // Slow case: Jump to runtime. | 580 // Slow case: Jump to runtime. |
| 552 // rdx: receiver | 581 // rdx: receiver |
| 553 // rax: key | 582 // rax: key |
| 554 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); | 583 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1); |
| 555 GenerateRuntimeGetProperty(masm); | 584 GenerateRuntimeGetProperty(masm); |
| 556 | 585 |
| 557 __ bind(&check_string); | 586 __ bind(&check_string); |
| 558 GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow); | 587 GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow); |
| 559 | 588 |
| 589 GenerateKeyedLoadReceiverCheck( |
| 590 masm, rdx, rcx, Map::kHasNamedInterceptor, &slow); |
| 591 |
| 560 // If the receiver is a fast-case object, check the keyed lookup | 592 // If the receiver is a fast-case object, check the keyed lookup |
| 561 // cache. Otherwise probe the dictionary leaving result in rcx. | 593 // cache. Otherwise probe the dictionary leaving result in rcx. |
| 562 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); | 594 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); |
| 563 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | 595 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
| 564 Heap::kHashTableMapRootIndex); | 596 Heap::kHashTableMapRootIndex); |
| 565 __ j(equal, &probe_dictionary); | 597 __ j(equal, &probe_dictionary); |
| 566 | 598 |
| 567 // Load the map of the receiver, compute the keyed lookup cache hash | 599 // Load the map of the receiver, compute the keyed lookup cache hash |
| 568 // based on 32 bits of the map pointer and the string hash. | 600 // based on 32 bits of the map pointer and the string hash. |
| 569 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | 601 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 __ addq(rcx, rdi); | 633 __ addq(rcx, rdi); |
| 602 __ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0)); | 634 __ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0)); |
| 603 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1); | 635 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1); |
| 604 __ ret(0); | 636 __ ret(0); |
| 605 | 637 |
| 606 // Do a quick inline probe of the receiver's dictionary, if it | 638 // Do a quick inline probe of the receiver's dictionary, if it |
| 607 // exists. | 639 // exists. |
| 608 __ bind(&probe_dictionary); | 640 __ bind(&probe_dictionary); |
| 609 // rdx: receiver | 641 // rdx: receiver |
| 610 // rax: key | 642 // rax: key |
| 611 GenerateDictionaryLoad(masm, | 643 // rbx: elements |
| 612 &slow, | 644 |
| 613 rbx, | 645 __ movq(rcx, FieldOperand(rdx, JSObject::kMapOffset)); |
| 614 rdx, | 646 __ movb(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset)); |
| 615 rcx, | 647 GenerateGlobalInstanceTypeCheck(masm, rcx, &slow); |
| 616 rax, | 648 |
| 617 rdi, | 649 GenerateDictionaryLoad(masm, &slow, rbx, rax, rcx, rdi, rax); |
| 618 rax, | |
| 619 DICTIONARY_CHECK_DONE); | |
| 620 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); | 650 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1); |
| 621 __ ret(0); | 651 __ ret(0); |
| 622 | 652 |
| 623 __ bind(&index_string); | 653 __ bind(&index_string); |
| 624 GenerateIndexFromHash(masm, rax, rbx); | 654 GenerateIndexFromHash(masm, rax, rbx); |
| 625 __ jmp(&index_smi); | 655 __ jmp(&index_smi); |
| 626 } | 656 } |
| 627 | 657 |
| 628 | 658 |
| 629 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { | 659 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { |
| (...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1205 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { | 1235 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { |
| 1206 // ----------- S t a t e ------------- | 1236 // ----------- S t a t e ------------- |
| 1207 // rcx : function name | 1237 // rcx : function name |
| 1208 // rsp[0] : return address | 1238 // rsp[0] : return address |
| 1209 // rsp[8] : argument argc | 1239 // rsp[8] : argument argc |
| 1210 // rsp[16] : argument argc - 1 | 1240 // rsp[16] : argument argc - 1 |
| 1211 // ... | 1241 // ... |
| 1212 // rsp[argc * 8] : argument 1 | 1242 // rsp[argc * 8] : argument 1 |
| 1213 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1243 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1214 // ----------------------------------- | 1244 // ----------------------------------- |
| 1245 |
| 1246 if (id == IC::kCallIC_Miss) { |
| 1247 __ IncrementCounter(&Counters::call_miss, 1); |
| 1248 } else { |
| 1249 __ IncrementCounter(&Counters::keyed_call_miss, 1); |
| 1250 } |
| 1251 |
| 1215 // Get the receiver of the function from the stack; 1 ~ return address. | 1252 // Get the receiver of the function from the stack; 1 ~ return address. |
| 1216 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | 1253 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
| 1217 | 1254 |
| 1218 // Enter an internal frame. | 1255 // Enter an internal frame. |
| 1219 __ EnterInternalFrame(); | 1256 __ EnterInternalFrame(); |
| 1220 | 1257 |
| 1221 // Push the receiver and the name of the function. | 1258 // Push the receiver and the name of the function. |
| 1222 __ push(rdx); | 1259 __ push(rdx); |
| 1223 __ push(rcx); | 1260 __ push(rcx); |
| 1224 | 1261 |
| 1225 // Call the entry. | 1262 // Call the entry. |
| 1226 CEntryStub stub(1); | 1263 CEntryStub stub(1); |
| 1227 __ movq(rax, Immediate(2)); | 1264 __ movq(rax, Immediate(2)); |
| 1228 __ movq(rbx, ExternalReference(IC_Utility(id))); | 1265 __ movq(rbx, ExternalReference(IC_Utility(id))); |
| 1229 __ CallStub(&stub); | 1266 __ CallStub(&stub); |
| 1230 | 1267 |
| 1231 // Move result to rdi and exit the internal frame. | 1268 // Move result to rdi and exit the internal frame. |
| 1232 __ movq(rdi, rax); | 1269 __ movq(rdi, rax); |
| 1233 __ LeaveInternalFrame(); | 1270 __ LeaveInternalFrame(); |
| 1234 | 1271 |
| 1235 // Check if the receiver is a global object of some sort. | 1272 // Check if the receiver is a global object of some sort. |
| 1236 Label invoke, global; | 1273 // This can happen only for regular CallIC but not KeyedCallIC. |
| 1237 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver | 1274 if (id == IC::kCallIC_Miss) { |
| 1238 __ JumpIfSmi(rdx, &invoke); | 1275 Label invoke, global; |
| 1239 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx); | 1276 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver |
| 1240 __ j(equal, &global); | 1277 __ JumpIfSmi(rdx, &invoke); |
| 1241 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE); | 1278 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx); |
| 1242 __ j(not_equal, &invoke); | 1279 __ j(equal, &global); |
| 1280 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE); |
| 1281 __ j(not_equal, &invoke); |
| 1243 | 1282 |
| 1244 // Patch the receiver on the stack. | 1283 // Patch the receiver on the stack. |
| 1245 __ bind(&global); | 1284 __ bind(&global); |
| 1246 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); | 1285 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); |
| 1247 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); | 1286 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); |
| 1287 __ bind(&invoke); |
| 1288 } |
| 1248 | 1289 |
| 1249 // Invoke the function. | 1290 // Invoke the function. |
| 1250 ParameterCount actual(argc); | 1291 ParameterCount actual(argc); |
| 1251 __ bind(&invoke); | |
| 1252 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | 1292 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
| 1253 } | 1293 } |
| 1254 | 1294 |
| 1255 | 1295 |
| 1256 // The generated code does not accept smi keys. | 1296 // The generated code does not accept smi keys. |
| 1257 // The generated code falls through if both probes miss. | 1297 // The generated code falls through if both probes miss. |
| 1258 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, | 1298 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, |
| 1259 int argc, | 1299 int argc, |
| 1260 Code::Kind kind) { | 1300 Code::Kind kind) { |
| 1261 // ----------- S t a t e ------------- | 1301 // ----------- S t a t e ------------- |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1302 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx); | 1342 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx); |
| 1303 | 1343 |
| 1304 // Probe the stub cache for the value object. | 1344 // Probe the stub cache for the value object. |
| 1305 __ bind(&probe); | 1345 __ bind(&probe); |
| 1306 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg); | 1346 StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg); |
| 1307 | 1347 |
| 1308 __ bind(&miss); | 1348 __ bind(&miss); |
| 1309 } | 1349 } |
| 1310 | 1350 |
| 1311 | 1351 |
| 1312 static void GenerateNormalHelper(MacroAssembler* masm, | 1352 static void GenerateFunctionTailCall(MacroAssembler* masm, |
| 1313 int argc, | 1353 int argc, |
| 1314 bool is_global_object, | 1354 Label* miss) { |
| 1315 Label* miss) { | |
| 1316 // ----------- S t a t e ------------- | 1355 // ----------- S t a t e ------------- |
| 1317 // rcx : function name | 1356 // rcx : function name |
| 1318 // rdx : receiver | 1357 // rdi : function |
| 1319 // rsp[0] : return address | 1358 // rsp[0] : return address |
| 1320 // rsp[8] : argument argc | 1359 // rsp[8] : argument argc |
| 1321 // rsp[16] : argument argc - 1 | 1360 // rsp[16] : argument argc - 1 |
| 1322 // ... | 1361 // ... |
| 1323 // rsp[argc * 8] : argument 1 | 1362 // rsp[argc * 8] : argument 1 |
| 1324 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1363 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1325 // ----------------------------------- | 1364 // ----------------------------------- |
| 1326 // Search dictionary - put result in register rdx. | |
| 1327 GenerateDictionaryLoad( | |
| 1328 masm, miss, rax, rdx, rbx, rcx, rdi, rdi, CHECK_DICTIONARY); | |
| 1329 | |
| 1330 __ JumpIfSmi(rdi, miss); | 1365 __ JumpIfSmi(rdi, miss); |
| 1331 // Check that the value is a JavaScript function. | 1366 // Check that the value is a JavaScript function. |
| 1332 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx); | 1367 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx); |
| 1333 __ j(not_equal, miss); | 1368 __ j(not_equal, miss); |
| 1334 | 1369 |
| 1335 // Patch the receiver with the global proxy if necessary. | |
| 1336 if (is_global_object) { | |
| 1337 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); | |
| 1338 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); | |
| 1339 } | |
| 1340 | |
| 1341 // Invoke the function. | 1370 // Invoke the function. |
| 1342 ParameterCount actual(argc); | 1371 ParameterCount actual(argc); |
| 1343 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | 1372 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
| 1344 } | 1373 } |
| 1345 | 1374 |
| 1346 | 1375 |
| 1347 // The generated code falls through if the call should be handled by runtime. | 1376 // The generated code falls through if the call should be handled by runtime. |
| 1348 static void GenerateCallNormal(MacroAssembler* masm, int argc) { | 1377 static void GenerateCallNormal(MacroAssembler* masm, int argc) { |
| 1349 // ----------- S t a t e ------------- | 1378 // ----------- S t a t e ------------- |
| 1350 // rcx : function name | 1379 // rcx : function name |
| 1351 // rsp[0] : return address | 1380 // rsp[0] : return address |
| 1352 // rsp[8] : argument argc | 1381 // rsp[8] : argument argc |
| 1353 // rsp[16] : argument argc - 1 | 1382 // rsp[16] : argument argc - 1 |
| 1354 // ... | 1383 // ... |
| 1355 // rsp[argc * 8] : argument 1 | 1384 // rsp[argc * 8] : argument 1 |
| 1356 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1385 // rsp[(argc + 1) * 8] : argument 0 = receiver |
| 1357 // ----------------------------------- | 1386 // ----------------------------------- |
| 1358 Label miss, global_object, non_global_object; | 1387 Label miss; |
| 1359 | 1388 |
| 1360 // Get the receiver of the function from the stack. | 1389 // Get the receiver of the function from the stack. |
| 1361 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | 1390 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
| 1362 | 1391 |
| 1363 // Check that the receiver isn't a smi. | 1392 GenerateDictionaryLoadReceiverCheck(masm, rdx, rax, rbx, &miss); |
| 1364 __ JumpIfSmi(rdx, &miss); | |
| 1365 | 1393 |
| 1366 // Check that the receiver is a valid JS object. | 1394 // rax: elements |
| 1367 // Because there are so many map checks and type checks, do not | 1395 // Search the dictionary placing the result in rdi. |
| 1368 // use CmpObjectType, but load map and type into registers. | 1396 GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi); |
| 1369 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); | |
| 1370 __ movb(rax, FieldOperand(rbx, Map::kInstanceTypeOffset)); | |
| 1371 __ cmpb(rax, Immediate(FIRST_JS_OBJECT_TYPE)); | |
| 1372 __ j(below, &miss); | |
| 1373 | 1397 |
| 1374 // If this assert fails, we have to check upper bound too. | 1398 GenerateFunctionTailCall(masm, argc, &miss); |
| 1375 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | |
| 1376 | |
| 1377 // Check for access to global object. | |
| 1378 __ cmpb(rax, Immediate(JS_GLOBAL_OBJECT_TYPE)); | |
| 1379 __ j(equal, &global_object); | |
| 1380 __ cmpb(rax, Immediate(JS_BUILTINS_OBJECT_TYPE)); | |
| 1381 __ j(not_equal, &non_global_object); | |
| 1382 | |
| 1383 // Accessing global object: Load and invoke. | |
| 1384 __ bind(&global_object); | |
| 1385 // Check that the global object does not require access checks. | |
| 1386 __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset)); | |
| 1387 __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded)); | |
| 1388 __ j(not_equal, &miss); | |
| 1389 GenerateNormalHelper(masm, argc, true, &miss); | |
| 1390 | |
| 1391 // Accessing non-global object: Check for access to global proxy. | |
| 1392 Label global_proxy, invoke; | |
| 1393 __ bind(&non_global_object); | |
| 1394 __ cmpb(rax, Immediate(JS_GLOBAL_PROXY_TYPE)); | |
| 1395 __ j(equal, &global_proxy); | |
| 1396 // Check that the non-global, non-global-proxy object does not | |
| 1397 // require access checks. | |
| 1398 __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset)); | |
| 1399 __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded)); | |
| 1400 __ j(not_equal, &miss); | |
| 1401 __ bind(&invoke); | |
| 1402 GenerateNormalHelper(masm, argc, false, &miss); | |
| 1403 | |
| 1404 // Global object proxy access: Check access rights. | |
| 1405 __ bind(&global_proxy); | |
| 1406 __ CheckAccessGlobalProxy(rdx, rax, &miss); | |
| 1407 __ jmp(&invoke); | |
| 1408 | 1399 |
| 1409 __ bind(&miss); | 1400 __ bind(&miss); |
| 1410 } | 1401 } |
| 1411 | 1402 |
| 1412 | 1403 |
| 1413 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { | 1404 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { |
| 1414 // ----------- S t a t e ------------- | 1405 // ----------- S t a t e ------------- |
| 1415 // rcx : function name | 1406 // rcx : function name |
| 1416 // rsp[0] : return address | 1407 // rsp[0] : return address |
| 1417 // rsp[8] : argument argc | 1408 // rsp[8] : argument argc |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1491 Label check_number_dictionary, check_string, lookup_monomorphic_cache; | 1482 Label check_number_dictionary, check_string, lookup_monomorphic_cache; |
| 1492 Label index_smi, index_string; | 1483 Label index_smi, index_string; |
| 1493 | 1484 |
| 1494 // Check that the key is a smi. | 1485 // Check that the key is a smi. |
| 1495 __ JumpIfNotSmi(rcx, &check_string); | 1486 __ JumpIfNotSmi(rcx, &check_string); |
| 1496 | 1487 |
| 1497 __ bind(&index_smi); | 1488 __ bind(&index_smi); |
| 1498 // Now the key is known to be a smi. This place is also jumped to from below | 1489 // Now the key is known to be a smi. This place is also jumped to from below |
| 1499 // where a numeric string is converted to a smi. | 1490 // where a numeric string is converted to a smi. |
| 1500 | 1491 |
| 1501 GenerateKeyedLoadReceiverCheck(masm, rdx, rax, &slow_call); | 1492 GenerateKeyedLoadReceiverCheck( |
| 1493 masm, rdx, rax, Map::kHasIndexedInterceptor, &slow_call); |
| 1502 | 1494 |
| 1503 GenerateFastArrayLoad( | 1495 GenerateFastArrayLoad( |
| 1504 masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load); | 1496 masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load); |
| 1505 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1); | 1497 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1); |
| 1506 | 1498 |
| 1507 __ bind(&do_call); | 1499 __ bind(&do_call); |
| 1508 // receiver in rdx is not used after this point. | 1500 // receiver in rdx is not used after this point. |
| 1509 // rcx: key | 1501 // rcx: key |
| 1510 // rdi: function | 1502 // rdi: function |
| 1511 | 1503 GenerateFunctionTailCall(masm, argc, &slow_call); |
| 1512 // Check that the value in edi is a JavaScript function. | |
| 1513 __ JumpIfSmi(rdi, &slow_call); | |
| 1514 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax); | |
| 1515 __ j(not_equal, &slow_call); | |
| 1516 // Invoke the function. | |
| 1517 ParameterCount actual(argc); | |
| 1518 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | |
| 1519 | 1504 |
| 1520 __ bind(&check_number_dictionary); | 1505 __ bind(&check_number_dictionary); |
| 1521 // eax: elements | 1506 // eax: elements |
| 1522 // ecx: smi key | 1507 // ecx: smi key |
| 1523 // Check whether the elements is a number dictionary. | 1508 // Check whether the elements is a number dictionary. |
| 1524 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 1509 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
| 1525 Heap::kHashTableMapRootIndex); | 1510 Heap::kHashTableMapRootIndex); |
| 1511 __ j(not_equal, &slow_load); |
| 1526 __ SmiToInteger32(rbx, rcx); | 1512 __ SmiToInteger32(rbx, rcx); |
| 1527 // ebx: untagged index | 1513 // ebx: untagged index |
| 1528 GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi); | 1514 GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi); |
| 1529 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1); | 1515 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1); |
| 1530 __ jmp(&do_call); | 1516 __ jmp(&do_call); |
| 1531 | 1517 |
| 1532 __ bind(&slow_load); | 1518 __ bind(&slow_load); |
| 1533 // This branch is taken when calling KeyedCallIC_Miss is neither required | 1519 // This branch is taken when calling KeyedCallIC_Miss is neither required |
| 1534 // nor beneficial. | 1520 // nor beneficial. |
| 1535 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1); | 1521 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1); |
| 1536 __ EnterInternalFrame(); | 1522 __ EnterInternalFrame(); |
| 1537 __ push(rcx); // save the key | 1523 __ push(rcx); // save the key |
| 1538 __ push(rdx); // pass the receiver | 1524 __ push(rdx); // pass the receiver |
| 1539 __ push(rcx); // pass the key | 1525 __ push(rcx); // pass the key |
| 1540 __ CallRuntime(Runtime::kKeyedGetProperty, 2); | 1526 __ CallRuntime(Runtime::kKeyedGetProperty, 2); |
| 1541 __ pop(rcx); // restore the key | 1527 __ pop(rcx); // restore the key |
| 1542 __ LeaveInternalFrame(); | 1528 __ LeaveInternalFrame(); |
| 1543 __ movq(rdi, rax); | 1529 __ movq(rdi, rax); |
| 1544 __ jmp(&do_call); | 1530 __ jmp(&do_call); |
| 1545 | 1531 |
| 1546 __ bind(&check_string); | 1532 __ bind(&check_string); |
| 1547 GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call); | 1533 GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call); |
| 1548 | 1534 |
| 1549 // The key is known to be a symbol. | 1535 // The key is known to be a symbol. |
| 1550 // If the receiver is a regular JS object with slow properties then do | 1536 // If the receiver is a regular JS object with slow properties then do |
| 1551 // a quick inline probe of the receiver's dictionary. | 1537 // a quick inline probe of the receiver's dictionary. |
| 1552 // Otherwise do the monomorphic cache probe. | 1538 // Otherwise do the monomorphic cache probe. |
| 1553 GenerateKeyedLoadReceiverCheck(masm, rdx, rax, &lookup_monomorphic_cache); | 1539 GenerateKeyedLoadReceiverCheck( |
| 1540 masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); |
| 1554 | 1541 |
| 1555 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); | 1542 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); |
| 1556 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | 1543 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
| 1557 Heap::kHashTableMapRootIndex); | 1544 Heap::kHashTableMapRootIndex); |
| 1558 __ j(not_equal, &lookup_monomorphic_cache); | 1545 __ j(not_equal, &lookup_monomorphic_cache); |
| 1559 | 1546 |
| 1560 GenerateDictionaryLoad( | 1547 GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi); |
| 1561 masm, &slow_load, rbx, rdx, rax, rcx, rdi, rdi, DICTIONARY_CHECK_DONE); | |
| 1562 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1); | 1548 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1); |
| 1563 __ jmp(&do_call); | 1549 __ jmp(&do_call); |
| 1564 | 1550 |
| 1565 __ bind(&lookup_monomorphic_cache); | 1551 __ bind(&lookup_monomorphic_cache); |
| 1566 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1); | 1552 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1); |
| 1567 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); | 1553 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC); |
| 1568 // Fall through on miss. | 1554 // Fall through on miss. |
| 1569 | 1555 |
| 1570 __ bind(&slow_call); | 1556 __ bind(&slow_call); |
| 1571 // This branch is taken if: | 1557 // This branch is taken if: |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1613 } | 1599 } |
| 1614 | 1600 |
| 1615 | 1601 |
| 1616 void LoadIC::GenerateMiss(MacroAssembler* masm) { | 1602 void LoadIC::GenerateMiss(MacroAssembler* masm) { |
| 1617 // ----------- S t a t e ------------- | 1603 // ----------- S t a t e ------------- |
| 1618 // -- rax : receiver | 1604 // -- rax : receiver |
| 1619 // -- rcx : name | 1605 // -- rcx : name |
| 1620 // -- rsp[0] : return address | 1606 // -- rsp[0] : return address |
| 1621 // ----------------------------------- | 1607 // ----------------------------------- |
| 1622 | 1608 |
| 1609 __ IncrementCounter(&Counters::load_miss, 1); |
| 1610 |
| 1623 __ pop(rbx); | 1611 __ pop(rbx); |
| 1624 __ push(rax); // receiver | 1612 __ push(rax); // receiver |
| 1625 __ push(rcx); // name | 1613 __ push(rcx); // name |
| 1626 __ push(rbx); // return address | 1614 __ push(rbx); // return address |
| 1627 | 1615 |
| 1628 // Perform tail call to the entry. | 1616 // Perform tail call to the entry. |
| 1629 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); | 1617 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss)); |
| 1630 __ TailCallExternalReference(ref, 2, 1); | 1618 __ TailCallExternalReference(ref, 2, 1); |
| 1631 } | 1619 } |
| 1632 | 1620 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1676 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 1664 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
| 1677 } | 1665 } |
| 1678 | 1666 |
| 1679 | 1667 |
| 1680 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 1668 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
| 1681 // ----------- S t a t e ------------- | 1669 // ----------- S t a t e ------------- |
| 1682 // -- rax : receiver | 1670 // -- rax : receiver |
| 1683 // -- rcx : name | 1671 // -- rcx : name |
| 1684 // -- rsp[0] : return address | 1672 // -- rsp[0] : return address |
| 1685 // ----------------------------------- | 1673 // ----------------------------------- |
| 1686 Label miss, probe, global; | 1674 Label miss; |
| 1687 | 1675 |
| 1688 // Check that the receiver isn't a smi. | 1676 GenerateDictionaryLoadReceiverCheck(masm, rax, rdx, rbx, &miss); |
| 1689 __ JumpIfSmi(rax, &miss); | |
| 1690 | 1677 |
| 1691 // Check that the receiver is a valid JS object. | 1678 // rdx: elements |
| 1692 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | |
| 1693 __ j(below, &miss); | |
| 1694 | |
| 1695 // If this assert fails, we have to check upper bound too. | |
| 1696 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | |
| 1697 | |
| 1698 // Check for access to global object (unlikely). | |
| 1699 __ CmpInstanceType(rbx, JS_GLOBAL_PROXY_TYPE); | |
| 1700 __ j(equal, &global); | |
| 1701 | |
| 1702 // Check for non-global object that requires access check. | |
| 1703 __ testl(FieldOperand(rbx, Map::kBitFieldOffset), | |
| 1704 Immediate(1 << Map::kIsAccessCheckNeeded)); | |
| 1705 __ j(not_zero, &miss); | |
| 1706 | |
| 1707 // Search the dictionary placing the result in rax. | 1679 // Search the dictionary placing the result in rax. |
| 1708 __ bind(&probe); | 1680 GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax); |
| 1709 GenerateDictionaryLoad(masm, &miss, rdx, rax, rbx, | |
| 1710 rcx, rdi, rax, CHECK_DICTIONARY); | |
| 1711 __ ret(0); | 1681 __ ret(0); |
| 1712 | 1682 |
| 1713 // Global object access: Check access rights. | |
| 1714 __ bind(&global); | |
| 1715 __ CheckAccessGlobalProxy(rax, rdx, &miss); | |
| 1716 __ jmp(&probe); | |
| 1717 | |
| 1718 // Cache miss: Jump to runtime. | 1683 // Cache miss: Jump to runtime. |
| 1719 __ bind(&miss); | 1684 __ bind(&miss); |
| 1720 GenerateMiss(masm); | 1685 GenerateMiss(masm); |
| 1721 } | 1686 } |
| 1722 | 1687 |
| 1723 | 1688 |
| 1724 void LoadIC::GenerateStringLength(MacroAssembler* masm) { | 1689 void LoadIC::GenerateStringLength(MacroAssembler* masm) { |
| 1725 // ----------- S t a t e ------------- | 1690 // ----------- S t a t e ------------- |
| 1726 // -- rax : receiver | 1691 // -- rax : receiver |
| 1727 // -- rcx : name | 1692 // -- rcx : name |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1851 GenerateMiss(masm); | 1816 GenerateMiss(masm); |
| 1852 } | 1817 } |
| 1853 | 1818 |
| 1854 | 1819 |
| 1855 #undef __ | 1820 #undef __ |
| 1856 | 1821 |
| 1857 | 1822 |
| 1858 } } // namespace v8::internal | 1823 } } // namespace v8::internal |
| 1859 | 1824 |
| 1860 #endif // V8_TARGET_ARCH_X64 | 1825 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |