OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 int length, | 312 int length, |
313 FastCloneShallowArrayStub::Mode mode, | 313 FastCloneShallowArrayStub::Mode mode, |
314 Label* fail) { | 314 Label* fail) { |
315 // Registers on entry: | 315 // Registers on entry: |
316 // | 316 // |
317 // ecx: boilerplate literal array. | 317 // ecx: boilerplate literal array. |
318 ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS); | 318 ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS); |
319 | 319 |
320 // All sizes here are multiples of kPointerSize. | 320 // All sizes here are multiples of kPointerSize. |
321 int elements_size = 0; | 321 int elements_size = 0; |
| 322 int allocation_site_info_size = 0; |
322 if (length > 0) { | 323 if (length > 0) { |
323 elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS | 324 elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS |
324 ? FixedDoubleArray::SizeFor(length) | 325 ? FixedDoubleArray::SizeFor(length) |
325 : FixedArray::SizeFor(length); | 326 : FixedArray::SizeFor(length); |
| 327 } else { |
| 328 // Empty or COW arrays need to track type information to adjust the |
| 329 // boilerplate ElementsKind on subsequent stores. |
| 330 allocation_site_info_size = AllocationSiteInfo::kSize; |
326 } | 331 } |
327 int size = JSArray::kSize + elements_size; | 332 int allocation_offset = JSArray::kSize + elements_size; |
| 333 int size = allocation_offset + allocation_site_info_size; |
328 | 334 |
329 // Allocate both the JS array and the elements array in one big | 335 // Allocate both the JS array and the elements array in one big |
330 // allocation. This avoids multiple limit checks. | 336 // allocation. This avoids multiple limit checks. |
331 __ AllocateInNewSpace(size, eax, ebx, edx, fail, TAG_OBJECT); | 337 __ AllocateInNewSpace(size, eax, ebx, edx, fail, TAG_OBJECT); |
332 | 338 |
333 // Copy the JS array part. | 339 // Copy the JS array part. |
334 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { | 340 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { |
335 if ((i != JSArray::kElementsOffset) || (length == 0)) { | 341 if ((i != JSArray::kElementsOffset) || (length == 0)) { |
336 __ mov(ebx, FieldOperand(ecx, i)); | 342 __ mov(ebx, FieldOperand(ecx, i)); |
337 __ mov(FieldOperand(eax, i), ebx); | 343 __ mov(FieldOperand(eax, i), ebx); |
(...skipping 20 matching lines...) Expand all Loading... |
358 __ mov(ebx, FieldOperand(ecx, i)); | 364 __ mov(ebx, FieldOperand(ecx, i)); |
359 __ mov(FieldOperand(edx, i), ebx); | 365 __ mov(FieldOperand(edx, i), ebx); |
360 } | 366 } |
361 while (i < elements_size) { | 367 while (i < elements_size) { |
362 __ fld_d(FieldOperand(ecx, i)); | 368 __ fld_d(FieldOperand(ecx, i)); |
363 __ fstp_d(FieldOperand(edx, i)); | 369 __ fstp_d(FieldOperand(edx, i)); |
364 i += kDoubleSize; | 370 i += kDoubleSize; |
365 } | 371 } |
366 ASSERT(i == elements_size); | 372 ASSERT(i == elements_size); |
367 } | 373 } |
| 374 } else { |
| 375 // Track information about the allocation site |
| 376 __ mov(FieldOperand(eax, allocation_offset), |
| 377 Immediate(Handle<Map>(masm->isolate()->heap()-> |
| 378 allocation_site_info_map()))); |
| 379 __ mov(FieldOperand(eax, allocation_offset + kPointerSize), ecx); |
368 } | 380 } |
369 } | 381 } |
370 | 382 |
371 | 383 |
372 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 384 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
373 // Stack layout on entry: | 385 // Stack layout on entry: |
374 // | 386 // |
375 // [esp + kPointerSize]: constant elements. | 387 // [esp + kPointerSize]: constant elements. |
376 // [esp + (2 * kPointerSize)]: literal index. | 388 // [esp + (2 * kPointerSize)]: literal index. |
377 // [esp + (3 * kPointerSize)]: literals array. | 389 // [esp + (3 * kPointerSize)]: literals array. |
(...skipping 4298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4676 } | 4688 } |
4677 | 4689 |
4678 | 4690 |
4679 static void GenerateRecordCallTarget(MacroAssembler* masm) { | 4691 static void GenerateRecordCallTarget(MacroAssembler* masm) { |
4680 // Cache the called function in a global property cell. Cache states | 4692 // Cache the called function in a global property cell. Cache states |
4681 // are uninitialized, monomorphic (indicated by a JSFunction), and | 4693 // are uninitialized, monomorphic (indicated by a JSFunction), and |
4682 // megamorphic. | 4694 // megamorphic. |
4683 // ebx : cache cell for call target | 4695 // ebx : cache cell for call target |
4684 // edi : the function to call | 4696 // edi : the function to call |
4685 Isolate* isolate = masm->isolate(); | 4697 Isolate* isolate = masm->isolate(); |
4686 Label initialize, done; | 4698 Label initialize, done, miss, megamorphic, not_array_function; |
4687 | 4699 |
4688 // Load the cache state into ecx. | 4700 // Load the cache state into ecx. |
4689 __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); | 4701 __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); |
4690 | 4702 |
4691 // A monomorphic cache hit or an already megamorphic state: invoke the | 4703 // A monomorphic cache hit or an already megamorphic state: invoke the |
4692 // function without changing the state. | 4704 // function without changing the state. |
4693 __ cmp(ecx, edi); | 4705 __ cmp(ecx, edi); |
4694 __ j(equal, &done, Label::kNear); | 4706 __ j(equal, &done, Label::kFar); |
4695 __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); | 4707 __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); |
4696 __ j(equal, &done, Label::kNear); | 4708 __ j(equal, &done, Label::kFar); |
4697 | 4709 |
| 4710 // Special handling of the Array() function, which caches not only the |
| 4711 // monomorphic Array function but the initial ElementsKind with special |
| 4712 // sentinels. |
| 4713 Handle<Object> terminal_kind_sentinel = |
| 4714 TypeFeedbackCells::MonomorphicArraySentinel( |
| 4715 LAST_FAST_ELEMENTS_KIND); |
| 4716 __ cmp(ecx, Immediate(terminal_kind_sentinel)); |
| 4717 __ j(above, &miss, Label::kFar); |
| 4718 // Load the global or builtins object from the current context. |
| 4719 __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
| 4720 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); |
| 4721 // Make sure the function is the Array() function. |
| 4722 __ cmp(edi, Operand(ecx, |
| 4723 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); |
| 4724 Label megamorphic_pre; |
| 4725 __ j(not_equal, &megamorphic_pre, Label::kFar); |
| 4726 __ jmp(&done); |
| 4727 |
| 4728 __ bind(&megamorphic_pre); |
| 4729 __ jmp(&megamorphic, Label::kFar); |
| 4730 |
| 4731 __ bind(&miss); |
4698 // A monomorphic miss (i.e, here the cache is not uninitialized) goes | 4732 // A monomorphic miss (i.e, here the cache is not uninitialized) goes |
4699 // megamorphic. | 4733 // megamorphic. |
4700 __ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate))); | 4734 __ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate))); |
4701 __ j(equal, &initialize, Label::kNear); | 4735 __ j(equal, &initialize, Label::kFar); |
4702 // MegamorphicSentinel is an immortal immovable object (undefined) so no | 4736 // MegamorphicSentinel is an immortal immovable object (undefined) so no |
4703 // write-barrier is needed. | 4737 // write-barrier is needed. |
| 4738 __ bind(&megamorphic); |
| 4739 |
| 4740 __ push(eax); |
| 4741 __ push(ebx); |
| 4742 __ push(ecx); |
| 4743 __ push(edx); |
| 4744 __ push(edi); |
| 4745 __ push(esi); |
| 4746 |
| 4747 __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); |
| 4748 Label aligned, done_aligned; |
| 4749 __ mov(esi, esp); |
| 4750 __ test(esi, Immediate(kPointerSize)); |
| 4751 __ j(not_equal, &aligned, Label::kFar); |
| 4752 __ push(Immediate(0)); |
| 4753 __ push(Immediate(4)); |
| 4754 __ mov(esi, Operand(esp, 8)); |
| 4755 __ jmp(&done_aligned, Label::kFar); |
| 4756 __ bind(&aligned); |
| 4757 __ push(Immediate(0)); |
| 4758 __ mov(esi, Operand(esp, 4)); |
| 4759 __ bind(&done_aligned); |
| 4760 |
4704 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), | 4761 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), |
4705 Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); | 4762 Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); |
4706 __ jmp(&done, Label::kNear); | 4763 __ jmp(&done, Label::kNear); |
4707 | 4764 |
4708 // An uninitialized cache is patched with the function. | 4765 // An uninitialized cache is patched with the function or sentinel to |
| 4766 // indicate the ElementsKind if function is the Array constructor. |
4709 __ bind(&initialize); | 4767 __ bind(&initialize); |
| 4768 __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
| 4769 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); |
| 4770 // Make sure the function is the Array() function. |
| 4771 __ cmp(edi, Operand(ecx, |
| 4772 Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); |
| 4773 __ j(not_equal, ¬_array_function); |
| 4774 |
| 4775 // The target function is the Array constructor, install a sentinel value in |
| 4776 // the constructor's type info cell that will track the initial ElementsKind |
| 4777 // that should be used for the array when its constructed. |
| 4778 Handle<Object> initial_kind_sentinel = |
| 4779 TypeFeedbackCells::MonomorphicArraySentinel( |
| 4780 GetInitialFastElementsKind()); |
| 4781 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), |
| 4782 Immediate(initial_kind_sentinel)); |
| 4783 __ jmp(&done); |
| 4784 |
| 4785 __ bind(¬_array_function); |
4710 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi); | 4786 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi); |
4711 // No need for a write barrier here - cells are rescanned. | 4787 // No need for a write barrier here - cells are rescanned. |
4712 | 4788 |
4713 __ bind(&done); | 4789 __ bind(&done); |
4714 } | 4790 } |
4715 | 4791 |
4716 | 4792 |
4717 void CallFunctionStub::Generate(MacroAssembler* masm) { | 4793 void CallFunctionStub::Generate(MacroAssembler* masm) { |
4718 // ebx : cache cell for call target | 4794 // ebx : cache cell for call target |
4719 // edi : the function to call | 4795 // edi : the function to call |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4815 __ JumpIfSmi(edi, &non_function_call); | 4891 __ JumpIfSmi(edi, &non_function_call); |
4816 // Check that function is a JSFunction. | 4892 // Check that function is a JSFunction. |
4817 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 4893 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
4818 __ j(not_equal, &slow); | 4894 __ j(not_equal, &slow); |
4819 | 4895 |
4820 if (RecordCallTarget()) { | 4896 if (RecordCallTarget()) { |
4821 GenerateRecordCallTarget(masm); | 4897 GenerateRecordCallTarget(masm); |
4822 } | 4898 } |
4823 | 4899 |
4824 // Jump to the function-specific construct stub. | 4900 // Jump to the function-specific construct stub. |
4825 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 4901 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
4826 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset)); | 4902 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); |
4827 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); | 4903 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); |
4828 __ jmp(ebx); | 4904 __ jmp(ecx); |
4829 | 4905 |
4830 // edi: called object | 4906 // edi: called object |
4831 // eax: number of arguments | 4907 // eax: number of arguments |
4832 // ecx: object map | 4908 // ecx: object map |
4833 Label do_call; | 4909 Label do_call; |
4834 __ bind(&slow); | 4910 __ bind(&slow); |
4835 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); | 4911 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); |
4836 __ j(not_equal, &non_function_call); | 4912 __ j(not_equal, &non_function_call); |
4837 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR); | 4913 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR); |
4838 __ jmp(&do_call); | 4914 __ jmp(&do_call); |
(...skipping 2688 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7527 // Restore ecx. | 7603 // Restore ecx. |
7528 __ pop(ecx); | 7604 __ pop(ecx); |
7529 __ ret(0); | 7605 __ ret(0); |
7530 } | 7606 } |
7531 | 7607 |
7532 #undef __ | 7608 #undef __ |
7533 | 7609 |
7534 } } // namespace v8::internal | 7610 } } // namespace v8::internal |
7535 | 7611 |
7536 #endif // V8_TARGET_ARCH_IA32 | 7612 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |