OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 4555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4566 __ cmp(scratch, kSymbolTag | kStringTag); | 4566 __ cmp(scratch, kSymbolTag | kStringTag); |
4567 __ j(not_equal, label); | 4567 __ j(not_equal, label); |
4568 } | 4568 } |
4569 | 4569 |
4570 | 4570 |
4571 void StackCheckStub::Generate(MacroAssembler* masm) { | 4571 void StackCheckStub::Generate(MacroAssembler* masm) { |
4572 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); | 4572 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); |
4573 } | 4573 } |
4574 | 4574 |
4575 | 4575 |
4576 void CallFunctionStub::FinishCode(Handle<Code> code) { | 4576 void CallStub::Clear(Heap* heap, Address address) { |
Vyacheslav Egorov (Chromium)
2012/01/23 10:39:52
Did it disappear? I can't find it.
Michael Starzinger
2012/01/25 11:42:29
Done. It was still there on line 4633. No longer n
| |
4577 code->set_has_function_cache(RecordCallTarget()); | |
4578 } | |
4579 | |
4580 | |
4581 void CallFunctionStub::Clear(Heap* heap, Address address) { | |
4582 ASSERT(Memory::uint8_at(address + kPointerSize) == Assembler::kTestEaxByte); | 4577 ASSERT(Memory::uint8_at(address + kPointerSize) == Assembler::kTestEaxByte); |
4583 // 1 ~ size of the test eax opcode. | 4578 // 1 ~ size of the test eax opcode. |
4584 Object* cell = Memory::Object_at(address + kPointerSize + 1); | 4579 Object* cell = Memory::Object_at(address + kPointerSize + 1); |
4585 // Low-level because clearing happens during GC. | 4580 // Low-level because clearing happens during GC. |
4586 reinterpret_cast<JSGlobalPropertyCell*>(cell)->set_value( | 4581 reinterpret_cast<JSGlobalPropertyCell*>(cell)->set_value( |
4587 RawUninitializedSentinel(heap)); | 4582 RawUninitializedSentinel(heap)); |
4588 } | 4583 } |
4589 | 4584 |
4590 | 4585 |
4591 Object* CallFunctionStub::GetCachedValue(Address address) { | 4586 Object* CallStub::GetCachedValue(Address address) { |
4592 ASSERT(Memory::uint8_at(address + kPointerSize) == Assembler::kTestEaxByte); | 4587 ASSERT(Memory::uint8_at(address + kPointerSize) == Assembler::kTestEaxByte); |
4593 // 1 ~ size of the test eax opcode. | 4588 // 1 ~ size of the test eax opcode. |
4594 Object* cell = Memory::Object_at(address + kPointerSize + 1); | 4589 Object* cell = Memory::Object_at(address + kPointerSize + 1); |
4595 return JSGlobalPropertyCell::cast(cell)->value(); | 4590 return JSGlobalPropertyCell::cast(cell)->value(); |
4596 } | 4591 } |
4597 | 4592 |
4598 | 4593 |
4594 void CallStub::GenerateRecordCallTarget(MacroAssembler* masm) { | |
4595 // Cache the called function in a global property cell in the | |
4596 // instruction stream after the call. Cache states are uninitialized, | |
4597 // monomorphic (indicated by a JSFunction), and megamorphic. | |
4598 // edi : the function to call | |
4599 Isolate* isolate = masm->isolate(); | |
4600 Label initialize, call; | |
Vyacheslav Egorov (Chromium)
2012/01/23 10:39:52
I would rename call to done.
Michael Starzinger
2012/01/25 11:42:29
Done.
| |
4601 | |
4602 // Load the cache cell address into ebx and the cache state into ecx. | |
4603 __ mov(ebx, Operand(esp, 0)); // Return address. | |
4604 __ mov(ebx, Operand(ebx, 1)); // 1 ~ sizeof 'test eax' opcode in bytes. | |
Vyacheslav Egorov (Chromium)
2012/01/23 10:39:52
you can generate assertion into instruction stream
Michael Starzinger
2012/01/25 11:42:29
Done. No longer needed with new approach.
| |
4605 __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); | |
4606 | |
4607 // A monomorphic cache hit or an already megamorphic state: invoke the | |
4608 // function without changing the state. | |
4609 __ cmp(ecx, edi); | |
4610 __ j(equal, &call, Label::kNear); | |
4611 __ cmp(ecx, Immediate(MegamorphicSentinel(isolate))); | |
4612 __ j(equal, &call, Label::kNear); | |
4613 | |
4614 // A monomorphic miss (i.e, here the cache is not uninitialized) goes | |
4615 // megamorphic. | |
4616 __ cmp(ecx, Immediate(UninitializedSentinel(isolate))); | |
4617 __ j(equal, &initialize, Label::kNear); | |
4618 // MegamorphicSentinel is an immortal immovable object (undefined) so no | |
4619 // write-barrier is needed. | |
4620 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), | |
4621 Immediate(MegamorphicSentinel(isolate))); | |
4622 __ jmp(&call, Label::kNear); | |
4623 | |
4624 // An uninitialized cache is patched with the function. | |
4625 __ bind(&initialize); | |
4626 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi); | |
4627 // No need for a write barrier here - cells are rescanned. | |
4628 | |
4629 __ bind(&call); | |
4630 } | |
4631 | |
4632 | |
4633 void CallFunctionStub::FinishCode(Handle<Code> code) { | |
4634 code->set_has_function_cache(RecordCallTarget()); | |
4635 } | |
4636 | |
4637 | |
4599 void CallFunctionStub::Generate(MacroAssembler* masm) { | 4638 void CallFunctionStub::Generate(MacroAssembler* masm) { |
4600 // edi : the function to call | 4639 // edi : the function to call |
4601 Isolate* isolate = masm->isolate(); | 4640 Isolate* isolate = masm->isolate(); |
4602 Label slow, non_function; | 4641 Label slow, non_function; |
4603 | 4642 |
4604 // The receiver might implicitly be the global object. This is | 4643 // The receiver might implicitly be the global object. This is |
4605 // indicated by passing the hole as the receiver to the call | 4644 // indicated by passing the hole as the receiver to the call |
4606 // function stub. | 4645 // function stub. |
4607 if (ReceiverMightBeImplicit()) { | 4646 if (ReceiverMightBeImplicit()) { |
4608 Label receiver_ok; | 4647 Label receiver_ok; |
(...skipping 10 matching lines...) Expand all Loading... | |
4619 __ bind(&receiver_ok); | 4658 __ bind(&receiver_ok); |
4620 } | 4659 } |
4621 | 4660 |
4622 // Check that the function really is a JavaScript function. | 4661 // Check that the function really is a JavaScript function. |
4623 __ JumpIfSmi(edi, &non_function); | 4662 __ JumpIfSmi(edi, &non_function); |
4624 // Goto slow case if we do not have a function. | 4663 // Goto slow case if we do not have a function. |
4625 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 4664 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
4626 __ j(not_equal, &slow); | 4665 __ j(not_equal, &slow); |
4627 | 4666 |
4628 if (RecordCallTarget()) { | 4667 if (RecordCallTarget()) { |
4629 // Cache the called function in a global property cell in the | 4668 GenerateRecordCallTarget(masm); |
4630 // instruction stream after the call. Cache states are uninitialized, | |
4631 // monomorphic (indicated by a JSFunction), and megamorphic. | |
4632 Label initialize, call; | |
4633 // Load the cache cell address into ebx and the cache state into ecx. | |
4634 __ mov(ebx, Operand(esp, 0)); // Return address. | |
4635 __ mov(ebx, Operand(ebx, 1)); // 1 ~ sizeof 'test eax' opcode in bytes. | |
4636 __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); | |
4637 | |
4638 // A monomorphic cache hit or an already megamorphic state: invoke the | |
4639 // function without changing the state. | |
4640 __ cmp(ecx, edi); | |
4641 __ j(equal, &call, Label::kNear); | |
4642 __ cmp(ecx, Immediate(MegamorphicSentinel(isolate))); | |
4643 __ j(equal, &call, Label::kNear); | |
4644 | |
4645 // A monomorphic miss (i.e, here the cache is not uninitialized) goes | |
4646 // megamorphic. | |
4647 __ cmp(ecx, Immediate(UninitializedSentinel(isolate))); | |
4648 __ j(equal, &initialize, Label::kNear); | |
4649 // MegamorphicSentinel is an immortal immovable object (undefined) so no | |
4650 // write-barrier is needed. | |
4651 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), | |
4652 Immediate(MegamorphicSentinel(isolate))); | |
4653 __ jmp(&call, Label::kNear); | |
4654 | |
4655 // An uninitialized cache is patched with the function. | |
4656 __ bind(&initialize); | |
4657 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi); | |
4658 // No need for a write barrier here - cells are rescanned. | |
4659 | |
4660 __ bind(&call); | |
4661 } | 4669 } |
4662 | 4670 |
4663 // Fast-case: Just invoke the function. | 4671 // Fast-case: Just invoke the function. |
4664 ParameterCount actual(argc_); | 4672 ParameterCount actual(argc_); |
4665 | 4673 |
4666 if (ReceiverMightBeImplicit()) { | 4674 if (ReceiverMightBeImplicit()) { |
4667 Label call_as_function; | 4675 Label call_as_function; |
4668 __ cmp(eax, isolate->factory()->the_hole_value()); | 4676 __ cmp(eax, isolate->factory()->the_hole_value()); |
4669 __ j(equal, &call_as_function); | 4677 __ j(equal, &call_as_function); |
4670 __ InvokeFunction(edi, | 4678 __ InvokeFunction(edi, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4713 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi); | 4721 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi); |
4714 __ Set(eax, Immediate(argc_)); | 4722 __ Set(eax, Immediate(argc_)); |
4715 __ Set(ebx, Immediate(0)); | 4723 __ Set(ebx, Immediate(0)); |
4716 __ SetCallKind(ecx, CALL_AS_METHOD); | 4724 __ SetCallKind(ecx, CALL_AS_METHOD); |
4717 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | 4725 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
4718 Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline(); | 4726 Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline(); |
4719 __ jmp(adaptor, RelocInfo::CODE_TARGET); | 4727 __ jmp(adaptor, RelocInfo::CODE_TARGET); |
4720 } | 4728 } |
4721 | 4729 |
4722 | 4730 |
4731 void CallConstructStub::FinishCode(Handle<Code> code) { | |
4732 code->set_has_function_cache(RecordCallTarget()); | |
4733 } | |
4734 | |
4735 | |
4736 void CallConstructStub::Generate(MacroAssembler* masm) { | |
4737 // ----------- S t a t e ------------- | |
4738 // -- eax: number of arguments | |
4739 // -- edi: constructor function | |
4740 // ----------------------------------- | |
4741 | |
4742 Label slow, non_function_call; | |
4743 // Check that function is not a smi. | |
4744 __ JumpIfSmi(edi, &non_function_call); | |
4745 // Check that function is a JSFunction. | |
4746 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | |
4747 __ j(not_equal, &slow); | |
4748 | |
4749 if (RecordCallTarget()) { | |
4750 GenerateRecordCallTarget(masm); | |
4751 } | |
4752 | |
4753 // Jump to the function-specific construct stub. | |
4754 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | |
4755 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset)); | |
4756 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); | |
4757 __ jmp(ebx); | |
4758 | |
4759 // edi: called object | |
4760 // eax: number of arguments | |
4761 // ecx: object map | |
4762 Label do_call; | |
4763 __ bind(&slow); | |
4764 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); | |
4765 __ j(not_equal, &non_function_call); | |
4766 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR); | |
4767 __ jmp(&do_call); | |
4768 | |
4769 __ bind(&non_function_call); | |
4770 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); | |
4771 __ bind(&do_call); | |
4772 // Set expected number of arguments to zero (not changing eax). | |
4773 __ Set(ebx, Immediate(0)); | |
4774 Handle<Code> arguments_adaptor = | |
4775 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); | |
4776 __ SetCallKind(ecx, CALL_AS_METHOD); | |
4777 __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET); | |
4778 } | |
4779 | |
4780 | |
4723 bool CEntryStub::NeedsImmovableCode() { | 4781 bool CEntryStub::NeedsImmovableCode() { |
4724 return false; | 4782 return false; |
4725 } | 4783 } |
4726 | 4784 |
4727 | 4785 |
4728 bool CEntryStub::IsPregenerated() { | 4786 bool CEntryStub::IsPregenerated() { |
4729 return (!save_doubles_ || ISOLATE->fp_stubs_generated()) && | 4787 return (!save_doubles_ || ISOLATE->fp_stubs_generated()) && |
4730 result_size_ == 1; | 4788 result_size_ == 1; |
4731 } | 4789 } |
4732 | 4790 |
(...skipping 2577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7310 false); | 7368 false); |
7311 __ pop(edx); | 7369 __ pop(edx); |
7312 __ ret(0); | 7370 __ ret(0); |
7313 } | 7371 } |
7314 | 7372 |
7315 #undef __ | 7373 #undef __ |
7316 | 7374 |
7317 } } // namespace v8::internal | 7375 } } // namespace v8::internal |
7318 | 7376 |
7319 #endif // V8_TARGET_ARCH_IA32 | 7377 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |