| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_X87 | 7 #if V8_TARGET_ARCH_X87 |
| 8 | 8 |
| 9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
| 10 #include "src/ic/ic.h" | 10 #include "src/ic/ic.h" |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 | 165 |
| 166 __ CmpInstanceType(map, JS_OBJECT_TYPE); | 166 __ CmpInstanceType(map, JS_OBJECT_TYPE); |
| 167 __ j(below, slow); | 167 __ j(below, slow); |
| 168 } | 168 } |
| 169 | 169 |
| 170 | 170 |
| 171 // Loads an indexed element from a fast case array. | 171 // Loads an indexed element from a fast case array. |
| 172 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, | 172 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, |
| 173 Register key, Register scratch, | 173 Register key, Register scratch, |
| 174 Register scratch2, Register result, | 174 Register scratch2, Register result, |
| 175 Label* slow, LanguageMode language_mode) { | 175 Label* slow) { |
| 176 // Register use: | 176 // Register use: |
| 177 // receiver - holds the receiver and is unchanged. | 177 // receiver - holds the receiver and is unchanged. |
| 178 // key - holds the key and is unchanged (must be a smi). | 178 // key - holds the key and is unchanged (must be a smi). |
| 179 // Scratch registers: | 179 // Scratch registers: |
| 180 // scratch - used to hold elements of the receiver and the loaded value. | 180 // scratch - used to hold elements of the receiver and the loaded value. |
| 181 // scratch2 - holds maps and prototypes during prototype chain check. | 181 // scratch2 - holds maps and prototypes during prototype chain check. |
| 182 // result - holds the result on exit if the load succeeds and | 182 // result - holds the result on exit if the load succeeds and |
| 183 // we fall through. | 183 // we fall through. |
| 184 Label check_prototypes, check_next_prototype; | 184 Label check_prototypes, check_next_prototype; |
| 185 Label done, in_bounds, absent; | 185 Label done, in_bounds, return_undefined; |
| 186 | 186 |
| 187 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset)); | 187 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset)); |
| 188 __ AssertFastElements(scratch); | 188 __ AssertFastElements(scratch); |
| 189 | 189 |
| 190 // Check that the key (index) is within bounds. | 190 // Check that the key (index) is within bounds. |
| 191 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset)); | 191 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset)); |
| 192 __ j(below, &in_bounds); | 192 __ j(below, &in_bounds); |
| 193 // Out-of-bounds. Check the prototype chain to see if we can just return | 193 // Out-of-bounds. Check the prototype chain to see if we can just return |
| 194 // 'undefined'. | 194 // 'undefined'. |
| 195 __ cmp(key, 0); | 195 __ cmp(key, 0); |
| 196 __ j(less, slow); // Negative keys can't take the fast OOB path. | 196 __ j(less, slow); // Negative keys can't take the fast OOB path. |
| 197 __ bind(&check_prototypes); | 197 __ bind(&check_prototypes); |
| 198 __ mov(scratch2, FieldOperand(receiver, HeapObject::kMapOffset)); | 198 __ mov(scratch2, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 199 __ bind(&check_next_prototype); | 199 __ bind(&check_next_prototype); |
| 200 __ mov(scratch2, FieldOperand(scratch2, Map::kPrototypeOffset)); | 200 __ mov(scratch2, FieldOperand(scratch2, Map::kPrototypeOffset)); |
| 201 // scratch2: current prototype | 201 // scratch2: current prototype |
| 202 __ cmp(scratch2, masm->isolate()->factory()->null_value()); | 202 __ cmp(scratch2, masm->isolate()->factory()->null_value()); |
| 203 __ j(equal, &absent); | 203 __ j(equal, &return_undefined); |
| 204 __ mov(scratch, FieldOperand(scratch2, JSObject::kElementsOffset)); | 204 __ mov(scratch, FieldOperand(scratch2, JSObject::kElementsOffset)); |
| 205 __ mov(scratch2, FieldOperand(scratch2, HeapObject::kMapOffset)); | 205 __ mov(scratch2, FieldOperand(scratch2, HeapObject::kMapOffset)); |
| 206 // scratch: elements of current prototype | 206 // scratch: elements of current prototype |
| 207 // scratch2: map of current prototype | 207 // scratch2: map of current prototype |
| 208 __ CmpInstanceType(scratch2, JS_OBJECT_TYPE); | 208 __ CmpInstanceType(scratch2, JS_OBJECT_TYPE); |
| 209 __ j(below, slow); | 209 __ j(below, slow); |
| 210 __ test_b( | 210 __ test_b( |
| 211 FieldOperand(scratch2, Map::kBitFieldOffset), | 211 FieldOperand(scratch2, Map::kBitFieldOffset), |
| 212 (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor)); | 212 (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor)); |
| 213 __ j(not_zero, slow); | 213 __ j(not_zero, slow); |
| 214 __ cmp(scratch, masm->isolate()->factory()->empty_fixed_array()); | 214 __ cmp(scratch, masm->isolate()->factory()->empty_fixed_array()); |
| 215 __ j(not_equal, slow); | 215 __ j(not_equal, slow); |
| 216 __ jmp(&check_next_prototype); | 216 __ jmp(&check_next_prototype); |
| 217 | 217 |
| 218 __ bind(&absent); | 218 __ bind(&return_undefined); |
| 219 if (is_strong(language_mode)) { | 219 __ mov(result, masm->isolate()->factory()->undefined_value()); |
| 220 // Strong mode accesses must throw in this case, so call the runtime. | 220 __ jmp(&done); |
| 221 __ jmp(slow); | |
| 222 } else { | |
| 223 __ mov(result, masm->isolate()->factory()->undefined_value()); | |
| 224 __ jmp(&done); | |
| 225 } | |
| 226 | 221 |
| 227 __ bind(&in_bounds); | 222 __ bind(&in_bounds); |
| 228 // Fast case: Do the load. | 223 // Fast case: Do the load. |
| 229 STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); | 224 STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); |
| 230 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); | 225 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); |
| 231 __ cmp(scratch, Immediate(masm->isolate()->factory()->the_hole_value())); | 226 __ cmp(scratch, Immediate(masm->isolate()->factory()->the_hole_value())); |
| 232 // In case the loaded value is the_hole we have to check the prototype chain. | 227 // In case the loaded value is the_hole we have to check the prototype chain. |
| 233 __ j(equal, &check_prototypes); | 228 __ j(equal, &check_prototypes); |
| 234 __ Move(result, scratch); | 229 __ Move(result, scratch); |
| 235 __ bind(&done); | 230 __ bind(&done); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 261 // bit test is enough. | 256 // bit test is enough. |
| 262 STATIC_ASSERT(kNotInternalizedTag != 0); | 257 STATIC_ASSERT(kNotInternalizedTag != 0); |
| 263 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), | 258 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), |
| 264 kIsNotInternalizedMask); | 259 kIsNotInternalizedMask); |
| 265 __ j(not_zero, not_unique); | 260 __ j(not_zero, not_unique); |
| 266 | 261 |
| 267 __ bind(&unique); | 262 __ bind(&unique); |
| 268 } | 263 } |
| 269 | 264 |
| 270 | 265 |
| 271 void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm, | 266 void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { |
| 272 LanguageMode language_mode) { | |
| 273 // The return address is on the stack. | 267 // The return address is on the stack. |
| 274 Label slow, check_name, index_smi, index_name, property_array_property; | 268 Label slow, check_name, index_smi, index_name, property_array_property; |
| 275 Label probe_dictionary, check_number_dictionary; | 269 Label probe_dictionary, check_number_dictionary; |
| 276 | 270 |
| 277 Register receiver = LoadDescriptor::ReceiverRegister(); | 271 Register receiver = LoadDescriptor::ReceiverRegister(); |
| 278 Register key = LoadDescriptor::NameRegister(); | 272 Register key = LoadDescriptor::NameRegister(); |
| 279 DCHECK(receiver.is(edx)); | 273 DCHECK(receiver.is(edx)); |
| 280 DCHECK(key.is(ecx)); | 274 DCHECK(key.is(ecx)); |
| 281 | 275 |
| 282 // Check that the key is a smi. | 276 // Check that the key is a smi. |
| 283 __ JumpIfNotSmi(key, &check_name); | 277 __ JumpIfNotSmi(key, &check_name); |
| 284 __ bind(&index_smi); | 278 __ bind(&index_smi); |
| 285 // Now the key is known to be a smi. This place is also jumped to from | 279 // Now the key is known to be a smi. This place is also jumped to from |
| 286 // where a numeric string is converted to a smi. | 280 // where a numeric string is converted to a smi. |
| 287 | 281 |
| 288 GenerateKeyedLoadReceiverCheck(masm, receiver, eax, | 282 GenerateKeyedLoadReceiverCheck(masm, receiver, eax, |
| 289 Map::kHasIndexedInterceptor, &slow); | 283 Map::kHasIndexedInterceptor, &slow); |
| 290 | 284 |
| 291 // Check the receiver's map to see if it has fast elements. | 285 // Check the receiver's map to see if it has fast elements. |
| 292 __ CheckFastElements(eax, &check_number_dictionary); | 286 __ CheckFastElements(eax, &check_number_dictionary); |
| 293 | 287 |
| 294 GenerateFastArrayLoad(masm, receiver, key, eax, ebx, eax, &slow, | 288 GenerateFastArrayLoad(masm, receiver, key, eax, ebx, eax, &slow); |
| 295 language_mode); | |
| 296 Isolate* isolate = masm->isolate(); | 289 Isolate* isolate = masm->isolate(); |
| 297 Counters* counters = isolate->counters(); | 290 Counters* counters = isolate->counters(); |
| 298 __ IncrementCounter(counters->keyed_load_generic_smi(), 1); | 291 __ IncrementCounter(counters->keyed_load_generic_smi(), 1); |
| 299 __ ret(0); | 292 __ ret(0); |
| 300 | 293 |
| 301 __ bind(&check_number_dictionary); | 294 __ bind(&check_number_dictionary); |
| 302 __ mov(ebx, key); | 295 __ mov(ebx, key); |
| 303 __ SmiUntag(ebx); | 296 __ SmiUntag(ebx); |
| 304 __ mov(eax, FieldOperand(receiver, JSObject::kElementsOffset)); | 297 __ mov(eax, FieldOperand(receiver, JSObject::kElementsOffset)); |
| 305 | 298 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 317 __ pop(receiver); | 310 __ pop(receiver); |
| 318 __ ret(0); | 311 __ ret(0); |
| 319 | 312 |
| 320 __ bind(&slow_pop_receiver); | 313 __ bind(&slow_pop_receiver); |
| 321 // Pop the receiver from the stack and jump to runtime. | 314 // Pop the receiver from the stack and jump to runtime. |
| 322 __ pop(receiver); | 315 __ pop(receiver); |
| 323 | 316 |
| 324 __ bind(&slow); | 317 __ bind(&slow); |
| 325 // Slow case: jump to runtime. | 318 // Slow case: jump to runtime. |
| 326 __ IncrementCounter(counters->keyed_load_generic_slow(), 1); | 319 __ IncrementCounter(counters->keyed_load_generic_slow(), 1); |
| 327 GenerateSlow(masm); | 320 GenerateRuntimeGetProperty(masm); |
| 328 | 321 |
| 329 __ bind(&check_name); | 322 __ bind(&check_name); |
| 330 GenerateKeyNameCheck(masm, key, eax, ebx, &index_name, &slow); | 323 GenerateKeyNameCheck(masm, key, eax, ebx, &index_name, &slow); |
| 331 | 324 |
| 332 GenerateKeyedLoadReceiverCheck(masm, receiver, eax, Map::kHasNamedInterceptor, | 325 GenerateKeyedLoadReceiverCheck(masm, receiver, eax, Map::kHasNamedInterceptor, |
| 333 &slow); | 326 &slow); |
| 334 | 327 |
| 335 // If the receiver is a fast-case object, check the stub cache. Otherwise | 328 // If the receiver is a fast-case object, check the stub cache. Otherwise |
| 336 // probe the dictionary. | 329 // probe the dictionary. |
| 337 __ mov(ebx, FieldOperand(receiver, JSObject::kPropertiesOffset)); | 330 __ mov(ebx, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 Label slow; | 616 Label slow; |
| 624 | 617 |
| 625 __ mov(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(), | 618 __ mov(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(), |
| 626 JSObject::kPropertiesOffset)); | 619 JSObject::kPropertiesOffset)); |
| 627 GenerateDictionaryLoad(masm, &slow, dictionary, | 620 GenerateDictionaryLoad(masm, &slow, dictionary, |
| 628 LoadDescriptor::NameRegister(), edi, ebx, eax); | 621 LoadDescriptor::NameRegister(), edi, ebx, eax); |
| 629 __ ret(0); | 622 __ ret(0); |
| 630 | 623 |
| 631 // Dictionary load failed, go slow (but don't miss). | 624 // Dictionary load failed, go slow (but don't miss). |
| 632 __ bind(&slow); | 625 __ bind(&slow); |
| 633 GenerateSlow(masm); | 626 GenerateRuntimeGetProperty(masm); |
| 634 } | 627 } |
| 635 | 628 |
| 636 | 629 |
| 637 static void LoadIC_PushArgs(MacroAssembler* masm) { | 630 static void LoadIC_PushArgs(MacroAssembler* masm) { |
| 638 Register receiver = LoadDescriptor::ReceiverRegister(); | 631 Register receiver = LoadDescriptor::ReceiverRegister(); |
| 639 Register name = LoadDescriptor::NameRegister(); | 632 Register name = LoadDescriptor::NameRegister(); |
| 640 | 633 |
| 641 Register slot = LoadDescriptor::SlotRegister(); | 634 Register slot = LoadDescriptor::SlotRegister(); |
| 642 Register vector = LoadWithVectorDescriptor::VectorRegister(); | 635 Register vector = LoadWithVectorDescriptor::VectorRegister(); |
| 643 DCHECK(!edi.is(receiver) && !edi.is(name) && !edi.is(slot) && | 636 DCHECK(!edi.is(receiver) && !edi.is(name) && !edi.is(slot) && |
| (...skipping 14 matching lines...) Expand all Loading... |
| 658 LoadIC_PushArgs(masm); | 651 LoadIC_PushArgs(masm); |
| 659 | 652 |
| 660 // Perform tail call to the entry. | 653 // Perform tail call to the entry. |
| 661 ExternalReference ref = | 654 ExternalReference ref = |
| 662 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate()); | 655 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate()); |
| 663 int arg_count = 4; | 656 int arg_count = 4; |
| 664 __ TailCallExternalReference(ref, arg_count, 1); | 657 __ TailCallExternalReference(ref, arg_count, 1); |
| 665 } | 658 } |
| 666 | 659 |
| 667 | 660 |
| 668 void LoadIC::GenerateSlow(MacroAssembler* masm) { | 661 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
| 669 // Return address is on the stack. | 662 // Return address is on the stack. |
| 670 Register receiver = LoadDescriptor::ReceiverRegister(); | 663 Register receiver = LoadDescriptor::ReceiverRegister(); |
| 671 Register name = LoadDescriptor::NameRegister(); | 664 Register name = LoadDescriptor::NameRegister(); |
| 672 DCHECK(!ebx.is(receiver) && !ebx.is(name)); | 665 DCHECK(!ebx.is(receiver) && !ebx.is(name)); |
| 673 | 666 |
| 674 __ pop(ebx); | 667 __ pop(ebx); |
| 675 __ push(receiver); | 668 __ push(receiver); |
| 676 __ push(name); | 669 __ push(name); |
| 677 __ push(ebx); | 670 __ push(ebx); |
| 678 | 671 |
| 679 // Perform tail call to the entry. | 672 // Perform tail call to the entry. |
| 680 ExternalReference ref = | 673 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); |
| 681 ExternalReference(IC_Utility(kLoadIC_Slow), masm->isolate()); | |
| 682 int arg_count = 2; | |
| 683 __ TailCallExternalReference(ref, arg_count, 1); | |
| 684 } | 674 } |
| 685 | 675 |
| 686 | 676 |
| 687 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 677 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
| 688 // Return address is on the stack. | 678 // Return address is on the stack. |
| 689 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1); | 679 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1); |
| 690 | 680 |
| 691 LoadIC_PushArgs(masm); | 681 LoadIC_PushArgs(masm); |
| 692 | 682 |
| 693 // Perform tail call to the entry. | 683 // Perform tail call to the entry. |
| 694 ExternalReference ref = | 684 ExternalReference ref = |
| 695 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); | 685 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); |
| 696 int arg_count = 4; | 686 int arg_count = 4; |
| 697 __ TailCallExternalReference(ref, arg_count, 1); | 687 __ TailCallExternalReference(ref, arg_count, 1); |
| 698 } | 688 } |
| 699 | 689 |
| 700 | 690 |
| 701 void KeyedLoadIC::GenerateSlow(MacroAssembler* masm) { | 691 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
| 702 // Return address is on the stack. | 692 // Return address is on the stack. |
| 703 Register receiver = LoadDescriptor::ReceiverRegister(); | 693 Register receiver = LoadDescriptor::ReceiverRegister(); |
| 704 Register name = LoadDescriptor::NameRegister(); | 694 Register name = LoadDescriptor::NameRegister(); |
| 705 DCHECK(!ebx.is(receiver) && !ebx.is(name)); | 695 DCHECK(!ebx.is(receiver) && !ebx.is(name)); |
| 706 | 696 |
| 707 __ pop(ebx); | 697 __ pop(ebx); |
| 708 __ push(receiver); | 698 __ push(receiver); |
| 709 __ push(name); | 699 __ push(name); |
| 710 __ push(ebx); | 700 __ push(ebx); |
| 711 | 701 |
| 712 // Perform tail call to the entry. | 702 // Perform tail call to the entry. |
| 713 ExternalReference ref = | 703 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 714 ExternalReference(IC_Utility(kKeyedLoadIC_Slow), masm->isolate()); | |
| 715 int arg_count = 2; | |
| 716 __ TailCallExternalReference(ref, arg_count, 1); | |
| 717 } | 704 } |
| 718 | 705 |
| 719 | 706 |
| 720 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { | 707 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { |
| 721 // Return address is on the stack. | 708 // Return address is on the stack. |
| 722 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( | 709 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( |
| 723 Code::ComputeHandlerFlags(Code::STORE_IC)); | 710 Code::ComputeHandlerFlags(Code::STORE_IC)); |
| 724 masm->isolate()->stub_cache()->GenerateProbe( | 711 masm->isolate()->stub_cache()->GenerateProbe( |
| 725 masm, Code::STORE_IC, flags, false, StoreDescriptor::ReceiverRegister(), | 712 masm, Code::STORE_IC, flags, false, StoreDescriptor::ReceiverRegister(), |
| 726 StoreDescriptor::NameRegister(), ebx, no_reg); | 713 StoreDescriptor::NameRegister(), ebx, no_reg); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 861 Condition cc = | 848 Condition cc = |
| 862 (check == ENABLE_INLINED_SMI_CHECK) | 849 (check == ENABLE_INLINED_SMI_CHECK) |
| 863 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) | 850 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) |
| 864 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); | 851 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); |
| 865 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 852 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
| 866 } | 853 } |
| 867 } // namespace internal | 854 } // namespace internal |
| 868 } // namespace v8 | 855 } // namespace v8 |
| 869 | 856 |
| 870 #endif // V8_TARGET_ARCH_X87 | 857 #endif // V8_TARGET_ARCH_X87 |
| OLD | NEW |