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_IA32 | 7 #if V8_TARGET_ARCH_IA32 |
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) { | 175 Label* slow, LanguageMode language_mode) { |
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, return_undefined; | 185 Label done, in_bounds, absent; |
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, &return_undefined); | 203 __ j(equal, &absent); |
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(&return_undefined); | 218 __ bind(&absent); |
219 __ mov(result, masm->isolate()->factory()->undefined_value()); | 219 if (is_strong(language_mode)) { |
220 __ jmp(&done); | 220 // Strong mode accesses must throw in this case, so call the runtime. |
| 221 __ jmp(slow); |
| 222 } else { |
| 223 __ mov(result, masm->isolate()->factory()->undefined_value()); |
| 224 __ jmp(&done); |
| 225 } |
221 | 226 |
222 __ bind(&in_bounds); | 227 __ bind(&in_bounds); |
223 // Fast case: Do the load. | 228 // Fast case: Do the load. |
224 STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); | 229 STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); |
225 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); | 230 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize)); |
226 __ cmp(scratch, Immediate(masm->isolate()->factory()->the_hole_value())); | 231 __ cmp(scratch, Immediate(masm->isolate()->factory()->the_hole_value())); |
227 // In case the loaded value is the_hole we have to check the prototype chain. | 232 // In case the loaded value is the_hole we have to check the prototype chain. |
228 __ j(equal, &check_prototypes); | 233 __ j(equal, &check_prototypes); |
229 __ Move(result, scratch); | 234 __ Move(result, scratch); |
230 __ bind(&done); | 235 __ bind(&done); |
(...skipping 25 matching lines...) Expand all Loading... |
256 // bit test is enough. | 261 // bit test is enough. |
257 STATIC_ASSERT(kNotInternalizedTag != 0); | 262 STATIC_ASSERT(kNotInternalizedTag != 0); |
258 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), | 263 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), |
259 kIsNotInternalizedMask); | 264 kIsNotInternalizedMask); |
260 __ j(not_zero, not_unique); | 265 __ j(not_zero, not_unique); |
261 | 266 |
262 __ bind(&unique); | 267 __ bind(&unique); |
263 } | 268 } |
264 | 269 |
265 | 270 |
266 void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { | 271 void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm, |
| 272 LanguageMode language_mode) { |
267 // The return address is on the stack. | 273 // The return address is on the stack. |
268 Label slow, check_name, index_smi, index_name, property_array_property; | 274 Label slow, check_name, index_smi, index_name, property_array_property; |
269 Label probe_dictionary, check_number_dictionary; | 275 Label probe_dictionary, check_number_dictionary; |
270 | 276 |
271 Register receiver = LoadDescriptor::ReceiverRegister(); | 277 Register receiver = LoadDescriptor::ReceiverRegister(); |
272 Register key = LoadDescriptor::NameRegister(); | 278 Register key = LoadDescriptor::NameRegister(); |
273 DCHECK(receiver.is(edx)); | 279 DCHECK(receiver.is(edx)); |
274 DCHECK(key.is(ecx)); | 280 DCHECK(key.is(ecx)); |
275 | 281 |
276 // Check that the key is a smi. | 282 // Check that the key is a smi. |
277 __ JumpIfNotSmi(key, &check_name); | 283 __ JumpIfNotSmi(key, &check_name); |
278 __ bind(&index_smi); | 284 __ bind(&index_smi); |
279 // Now the key is known to be a smi. This place is also jumped to from | 285 // Now the key is known to be a smi. This place is also jumped to from |
280 // where a numeric string is converted to a smi. | 286 // where a numeric string is converted to a smi. |
281 | 287 |
282 GenerateKeyedLoadReceiverCheck(masm, receiver, eax, | 288 GenerateKeyedLoadReceiverCheck(masm, receiver, eax, |
283 Map::kHasIndexedInterceptor, &slow); | 289 Map::kHasIndexedInterceptor, &slow); |
284 | 290 |
285 // Check the receiver's map to see if it has fast elements. | 291 // Check the receiver's map to see if it has fast elements. |
286 __ CheckFastElements(eax, &check_number_dictionary); | 292 __ CheckFastElements(eax, &check_number_dictionary); |
287 | 293 |
288 GenerateFastArrayLoad(masm, receiver, key, eax, ebx, eax, &slow); | 294 GenerateFastArrayLoad(masm, receiver, key, eax, ebx, eax, &slow, |
| 295 language_mode); |
289 Isolate* isolate = masm->isolate(); | 296 Isolate* isolate = masm->isolate(); |
290 Counters* counters = isolate->counters(); | 297 Counters* counters = isolate->counters(); |
291 __ IncrementCounter(counters->keyed_load_generic_smi(), 1); | 298 __ IncrementCounter(counters->keyed_load_generic_smi(), 1); |
292 __ ret(0); | 299 __ ret(0); |
293 | 300 |
294 __ bind(&check_number_dictionary); | 301 __ bind(&check_number_dictionary); |
295 __ mov(ebx, key); | 302 __ mov(ebx, key); |
296 __ SmiUntag(ebx); | 303 __ SmiUntag(ebx); |
297 __ mov(eax, FieldOperand(receiver, JSObject::kElementsOffset)); | 304 __ mov(eax, FieldOperand(receiver, JSObject::kElementsOffset)); |
298 | 305 |
(...skipping 11 matching lines...) Expand all Loading... |
310 __ pop(receiver); | 317 __ pop(receiver); |
311 __ ret(0); | 318 __ ret(0); |
312 | 319 |
313 __ bind(&slow_pop_receiver); | 320 __ bind(&slow_pop_receiver); |
314 // Pop the receiver from the stack and jump to runtime. | 321 // Pop the receiver from the stack and jump to runtime. |
315 __ pop(receiver); | 322 __ pop(receiver); |
316 | 323 |
317 __ bind(&slow); | 324 __ bind(&slow); |
318 // Slow case: jump to runtime. | 325 // Slow case: jump to runtime. |
319 __ IncrementCounter(counters->keyed_load_generic_slow(), 1); | 326 __ IncrementCounter(counters->keyed_load_generic_slow(), 1); |
320 GenerateRuntimeGetProperty(masm); | 327 GenerateRuntimeGetProperty(masm, language_mode); |
321 | 328 |
322 __ bind(&check_name); | 329 __ bind(&check_name); |
323 GenerateKeyNameCheck(masm, key, eax, ebx, &index_name, &slow); | 330 GenerateKeyNameCheck(masm, key, eax, ebx, &index_name, &slow); |
324 | 331 |
325 GenerateKeyedLoadReceiverCheck(masm, receiver, eax, Map::kHasNamedInterceptor, | 332 GenerateKeyedLoadReceiverCheck(masm, receiver, eax, Map::kHasNamedInterceptor, |
326 &slow); | 333 &slow); |
327 | 334 |
328 // If the receiver is a fast-case object, check the stub cache. Otherwise | 335 // If the receiver is a fast-case object, check the stub cache. Otherwise |
329 // probe the dictionary. | 336 // probe the dictionary. |
330 __ mov(ebx, FieldOperand(receiver, JSObject::kPropertiesOffset)); | 337 __ mov(ebx, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 kCheckMap, kDontIncrementLength); | 626 kCheckMap, kDontIncrementLength); |
620 KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow, | 627 KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow, |
621 &fast_double_grow, &slow, kDontCheckMap, | 628 &fast_double_grow, &slow, kDontCheckMap, |
622 kIncrementLength); | 629 kIncrementLength); |
623 | 630 |
624 __ bind(&miss); | 631 __ bind(&miss); |
625 GenerateMiss(masm); | 632 GenerateMiss(masm); |
626 } | 633 } |
627 | 634 |
628 | 635 |
629 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 636 void LoadIC::GenerateNormal(MacroAssembler* masm, LanguageMode language_mode) { |
630 Register dictionary = eax; | 637 Register dictionary = eax; |
631 DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister())); | 638 DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister())); |
632 DCHECK(!dictionary.is(LoadDescriptor::NameRegister())); | 639 DCHECK(!dictionary.is(LoadDescriptor::NameRegister())); |
633 | 640 |
634 Label slow; | 641 Label slow; |
635 | 642 |
636 __ mov(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(), | 643 __ mov(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(), |
637 JSObject::kPropertiesOffset)); | 644 JSObject::kPropertiesOffset)); |
638 GenerateDictionaryLoad(masm, &slow, dictionary, | 645 GenerateDictionaryLoad(masm, &slow, dictionary, |
639 LoadDescriptor::NameRegister(), edi, ebx, eax); | 646 LoadDescriptor::NameRegister(), edi, ebx, eax); |
640 __ ret(0); | 647 __ ret(0); |
641 | 648 |
642 // Dictionary load failed, go slow (but don't miss). | 649 // Dictionary load failed, go slow (but don't miss). |
643 __ bind(&slow); | 650 __ bind(&slow); |
644 GenerateRuntimeGetProperty(masm); | 651 GenerateRuntimeGetProperty(masm, language_mode); |
645 } | 652 } |
646 | 653 |
647 | 654 |
648 static void LoadIC_PushArgs(MacroAssembler* masm) { | 655 static void LoadIC_PushArgs(MacroAssembler* masm) { |
649 Register receiver = LoadDescriptor::ReceiverRegister(); | 656 Register receiver = LoadDescriptor::ReceiverRegister(); |
650 Register name = LoadDescriptor::NameRegister(); | 657 Register name = LoadDescriptor::NameRegister(); |
651 | 658 |
652 Register slot = LoadDescriptor::SlotRegister(); | 659 Register slot = LoadDescriptor::SlotRegister(); |
653 Register vector = LoadWithVectorDescriptor::VectorRegister(); | 660 Register vector = LoadWithVectorDescriptor::VectorRegister(); |
654 DCHECK(!edi.is(receiver) && !edi.is(name) && !edi.is(slot) && | 661 DCHECK(!edi.is(receiver) && !edi.is(name) && !edi.is(slot) && |
(...skipping 14 matching lines...) Expand all Loading... |
669 LoadIC_PushArgs(masm); | 676 LoadIC_PushArgs(masm); |
670 | 677 |
671 // Perform tail call to the entry. | 678 // Perform tail call to the entry. |
672 ExternalReference ref = | 679 ExternalReference ref = |
673 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate()); | 680 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate()); |
674 int arg_count = 4; | 681 int arg_count = 4; |
675 __ TailCallExternalReference(ref, arg_count, 1); | 682 __ TailCallExternalReference(ref, arg_count, 1); |
676 } | 683 } |
677 | 684 |
678 | 685 |
679 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 686 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm, |
| 687 LanguageMode language_mode) { |
680 // Return address is on the stack. | 688 // Return address is on the stack. |
681 Register receiver = LoadDescriptor::ReceiverRegister(); | 689 Register receiver = LoadDescriptor::ReceiverRegister(); |
682 Register name = LoadDescriptor::NameRegister(); | 690 Register name = LoadDescriptor::NameRegister(); |
683 DCHECK(!ebx.is(receiver) && !ebx.is(name)); | 691 DCHECK(!ebx.is(receiver) && !ebx.is(name)); |
684 | 692 |
685 __ pop(ebx); | 693 __ pop(ebx); |
686 __ push(receiver); | 694 __ push(receiver); |
687 __ push(name); | 695 __ push(name); |
688 __ push(ebx); | 696 __ push(ebx); |
689 | 697 |
690 // Perform tail call to the entry. | 698 // Do tail-call to runtime routine. |
691 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); | 699 __ TailCallRuntime(is_strong(language_mode) ? Runtime::kGetPropertyStrong |
| 700 : Runtime::kGetProperty, |
| 701 2, 1); |
692 } | 702 } |
693 | 703 |
694 | 704 |
695 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 705 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
696 // Return address is on the stack. | 706 // Return address is on the stack. |
697 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1); | 707 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1); |
698 | 708 |
699 LoadIC_PushArgs(masm); | 709 LoadIC_PushArgs(masm); |
700 | 710 |
701 // Perform tail call to the entry. | 711 // Perform tail call to the entry. |
702 ExternalReference ref = | 712 ExternalReference ref = |
703 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); | 713 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); |
704 int arg_count = 4; | 714 int arg_count = 4; |
705 __ TailCallExternalReference(ref, arg_count, 1); | 715 __ TailCallExternalReference(ref, arg_count, 1); |
706 } | 716 } |
707 | 717 |
708 | 718 |
709 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 719 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm, |
| 720 LanguageMode language_mode) { |
710 // Return address is on the stack. | 721 // Return address is on the stack. |
711 Register receiver = LoadDescriptor::ReceiverRegister(); | 722 Register receiver = LoadDescriptor::ReceiverRegister(); |
712 Register name = LoadDescriptor::NameRegister(); | 723 Register name = LoadDescriptor::NameRegister(); |
713 DCHECK(!ebx.is(receiver) && !ebx.is(name)); | 724 DCHECK(!ebx.is(receiver) && !ebx.is(name)); |
714 | 725 |
715 __ pop(ebx); | 726 __ pop(ebx); |
716 __ push(receiver); | 727 __ push(receiver); |
717 __ push(name); | 728 __ push(name); |
718 __ push(ebx); | 729 __ push(ebx); |
719 | 730 |
720 // Perform tail call to the entry. | 731 // Do tail-call to runtime routine. |
721 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 732 __ TailCallRuntime(is_strong(language_mode) ? Runtime::kKeyedGetPropertyStrong |
| 733 : Runtime::kKeyedGetProperty, |
| 734 2, 1); |
722 } | 735 } |
723 | 736 |
724 | 737 |
725 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { | 738 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { |
726 // Return address is on the stack. | 739 // Return address is on the stack. |
727 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( | 740 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( |
728 Code::ComputeHandlerFlags(Code::STORE_IC)); | 741 Code::ComputeHandlerFlags(Code::STORE_IC)); |
729 masm->isolate()->stub_cache()->GenerateProbe( | 742 masm->isolate()->stub_cache()->GenerateProbe( |
730 masm, Code::STORE_IC, flags, false, StoreDescriptor::ReceiverRegister(), | 743 masm, Code::STORE_IC, flags, false, StoreDescriptor::ReceiverRegister(), |
731 StoreDescriptor::NameRegister(), ebx, no_reg); | 744 StoreDescriptor::NameRegister(), ebx, no_reg); |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
866 Condition cc = | 879 Condition cc = |
867 (check == ENABLE_INLINED_SMI_CHECK) | 880 (check == ENABLE_INLINED_SMI_CHECK) |
868 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) | 881 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) |
869 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); | 882 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); |
870 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 883 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
871 } | 884 } |
872 } // namespace internal | 885 } // namespace internal |
873 } // namespace v8 | 886 } // namespace v8 |
874 | 887 |
875 #endif // V8_TARGET_ARCH_IA32 | 888 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |