From: serya@chromium.org Date: Mon, 15 Nov 2010 17:12:34 +0000 (+0000) Subject: Removing redundant stubs for API functions. X-Git-Tag: upstream/4.7.83~20957 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3b248841da4f26f77831151b88b1c38d24721df1;p=platform%2Fupstream%2Fv8.git Removing redundant stubs for API functions. Review URL: http://codereview.chromium.org/4695003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5827 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/code-stubs.cc b/src/code-stubs.cc index 787ec2a..8b9198f 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -37,7 +37,6 @@ namespace v8 { namespace internal { bool CodeStub::FindCodeInCache(Code** code_out) { - if (has_custom_cache()) return GetCustomCache(code_out); int index = Heap::code_stubs()->FindEntry(GetKey()); if (index != NumberDictionary::kNotFound) { *code_out = Code::cast(Heap::code_stubs()->ValueAt(index)); @@ -105,17 +104,14 @@ Handle CodeStub::GetCode() { Handle new_object = Factory::NewCode(desc, flags, masm.CodeObject()); RecordCodeGeneration(*new_object, &masm); - if (has_custom_cache()) { - SetCustomCache(*new_object); - } else { - // Update the dictionary and the root in Heap. - Handle dict = - Factory::DictionaryAtNumberPut( - Handle(Heap::code_stubs()), - GetKey(), - new_object); - Heap::public_set_code_stubs(*dict); - } + // Update the dictionary and the root in Heap. + Handle dict = + Factory::DictionaryAtNumberPut( + Handle(Heap::code_stubs()), + GetKey(), + new_object); + Heap::public_set_code_stubs(*dict); + code = *new_object; } @@ -147,15 +143,11 @@ MaybeObject* CodeStub::TryGetCode() { code = Code::cast(new_object); RecordCodeGeneration(code, &masm); - if (has_custom_cache()) { - SetCustomCache(code); - } else { - // Try to update the code cache but do not fail if unable. - MaybeObject* maybe_new_object = - Heap::code_stubs()->AtNumberPut(GetKey(), code); - if (maybe_new_object->ToObject(&new_object)) { - Heap::public_set_code_stubs(NumberDictionary::cast(new_object)); - } + // Try to update the code cache but do not fail if unable. + MaybeObject* maybe_new_object = + Heap::code_stubs()->AtNumberPut(GetKey(), code); + if (maybe_new_object->ToObject(&new_object)) { + Heap::public_set_code_stubs(NumberDictionary::cast(new_object)); } } diff --git a/src/code-stubs.h b/src/code-stubs.h index ec64353..b156647 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -124,12 +124,6 @@ class CodeStub BASE_EMBEDDED { virtual ~CodeStub() {} - // Override these methods to provide a custom caching mechanism for - // an individual type of code stub. - virtual bool GetCustomCache(Code** code_out) { return false; } - virtual void SetCustomCache(Code* value) { } - virtual bool has_custom_cache() { return false; } - protected: static const int kMajorBits = 5; static const int kMinorBits = kBitsPerInt - kSmiTagSize - kMajorBits; @@ -524,58 +518,6 @@ class CEntryStub : public CodeStub { }; -class ApiGetterEntryStub : public CodeStub { - public: - ApiGetterEntryStub(Handle info, - ApiFunction* fun) - : info_(info), - fun_(fun) { } - void Generate(MacroAssembler* masm); - virtual bool has_custom_cache() { return true; } - virtual bool GetCustomCache(Code** code_out); - virtual void SetCustomCache(Code* value); - - static const int kStackSpace = 5; - static const int kArgc = 2; - private: - Handle info() { return info_; } - ApiFunction* fun() { return fun_; } - Major MajorKey() { return NoCache; } - int MinorKey() { return 0; } - const char* GetName() { return "ApiGetterEntryStub"; } - // The accessor info associated with the function. - Handle info_; - // The function to be called. - ApiFunction* fun_; -}; - - -class ApiCallEntryStub : public CodeStub { - public: - ApiCallEntryStub(Handle info, - ApiFunction* fun) - : info_(info), - fun_(fun) { } - void Generate(MacroAssembler* masm); - virtual bool has_custom_cache() { return true; } - virtual bool GetCustomCache(Code** code_out); - virtual void SetCustomCache(Code* value); - - static const int kStackSpace = 0; - static const int kArgc = 5; - private: - Handle info() { return info_; } - ApiFunction* fun() { return fun_; } - Major MajorKey() { return NoCache; } - int MinorKey() { return 0; } - const char* GetName() { return "ApiCallEntryStub"; } - // The call handler info associated with the function. - Handle info_; - // The function to be called. - ApiFunction* fun_; -}; - - class JSEntryStub : public CodeStub { public: JSEntryStub() { } diff --git a/src/codegen.cc b/src/codegen.cc index 6db3d1c..fb8c5cd 100644 --- a/src/codegen.cc +++ b/src/codegen.cc @@ -449,35 +449,4 @@ int CEntryStub::MinorKey() { } -// Implementation of CodeStub::GetCustomCache. -static bool GetCustomCacheHelper(Object* cache, Code** code_out) { - if (cache->IsUndefined()) { - return false; - } else { - *code_out = Code::cast(cache); - return true; - } -} - - -bool ApiGetterEntryStub::GetCustomCache(Code** code_out) { - return GetCustomCacheHelper(info()->load_stub_cache(), code_out); -} - - -void ApiGetterEntryStub::SetCustomCache(Code* value) { - info()->set_load_stub_cache(value); -} - - -bool ApiCallEntryStub::GetCustomCache(Code** code_out) { - return GetCustomCacheHelper(info()->call_stub_cache(), code_out); -} - - -void ApiCallEntryStub::SetCustomCache(Code* value) { - info()->set_call_stub_cache(value); -} - - } } // namespace v8::internal diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index a7d658b..6ac89bf 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -3058,35 +3058,6 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { } -void ApiGetterEntryStub::Generate(MacroAssembler* masm) { - __ PrepareCallApiFunction(kStackSpace, kArgc); - STATIC_ASSERT(kArgc == 2); - __ mov(ApiParameterOperand(0), ebx); // name. - __ mov(ApiParameterOperand(1), eax); // arguments pointer. - __ CallApiFunctionAndReturn(fun(), kArgc); -} - - -void ApiCallEntryStub::Generate(MacroAssembler* masm) { - __ PrepareCallApiFunction(kStackSpace, kArgc); - STATIC_ASSERT(kArgc == 5); - - // Allocate the v8::Arguments structure in the arguments' space since - // it's not controlled by GC. - __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. - __ mov(ApiParameterOperand(2), ebx); // v8::Arguments::values_. - __ mov(ApiParameterOperand(3), edx); // v8::Arguments::length_. - // v8::Arguments::is_construct_call_. - __ mov(ApiParameterOperand(4), Immediate(0)); - - // v8::InvocationCallback's argument. - __ lea(eax, ApiParameterOperand(1)); - __ mov(ApiParameterOperand(0), eax); - - __ CallApiFunctionAndReturn(fun(), kArgc); -} - - void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_normal_exception, Label* throw_termination_exception, diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index b72f4df..c53e273 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -1110,6 +1110,17 @@ void MacroAssembler::TailCallExternalReference(const ExternalReference& ext, } +MaybeObject* MacroAssembler::TryTailCallExternalReference( + const ExternalReference& ext, int num_arguments, int result_size) { + // TODO(1236192): Most runtime routines don't need the number of + // arguments passed in because it is constant. At some point we + // should remove this need and make the runtime routine entry code + // smarter. + Set(eax, Immediate(num_arguments)); + return TryJumpToExternalReference(ext); +} + + void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, int num_arguments, int result_size) { @@ -1117,6 +1128,14 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, } +MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid, + int num_arguments, + int result_size) { + return TryTailCallExternalReference( + ExternalReference(fid), num_arguments, result_size); +} + + // If true, a Handle passed by value is passed and returned by // using the location_ field directly. If false, it is passed and // returned as a pointer to a handle. @@ -1144,7 +1163,8 @@ void MacroAssembler::PrepareCallApiFunction(int stack_space, int argc) { } -void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) { +MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, + int argc) { if (!kPassHandlesDirectly) { // The argument slots are filled as follows: // @@ -1213,7 +1233,11 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) { LeaveExitFrame(); ret(0); bind(&promote_scheduled_exception); - TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); + MaybeObject* result = + TryTailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); + if (result->IsFailure()) { + return result; + } bind(&empty_handle); // It was zero; the result is undefined. mov(eax, Factory::undefined_value()); @@ -1227,6 +1251,8 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) { call(Operand(eax)); mov(eax, edi); jmp(&leave_exit_frame); + + return result; } @@ -1238,6 +1264,15 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) { } +MaybeObject* MacroAssembler::TryJumpToExternalReference( + const ExternalReference& ext) { + // Set the entry point and jump to the C entry runtime stub. + mov(ebx, Immediate(ext)); + CEntryStub ces(1); + return TryTailCallStub(&ces); +} + + void MacroAssembler::InvokePrologue(const ParameterCount& expected, const ParameterCount& actual, Handle code_constant, diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index fc6161a..b205f84 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -460,11 +460,23 @@ class MacroAssembler: public Assembler { int num_arguments, int result_size); + // Tail call of a runtime routine (jump). Try to generate the code if + // necessary. Do not perform a GC but instead return a retry after GC failure. + MUST_USE_RESULT MaybeObject* TryTailCallExternalReference( + const ExternalReference& ext, int num_arguments, int result_size); + // Convenience function: tail call a runtime routine (jump). void TailCallRuntime(Runtime::FunctionId fid, int num_arguments, int result_size); + // Convenience function: tail call a runtime routine (jump). Try to generate + // the code if necessary. Do not perform a GC but instead return a retry after + // GC failure. + MUST_USE_RESULT MaybeObject* TryTailCallRuntime(Runtime::FunctionId fid, + int num_arguments, + int result_size); + // Before calling a C-function from generated code, align arguments on stack. // After aligning the frame, arguments must be stored in esp[0], esp[4], // etc., not pushed. The argument count assumes all arguments are word sized. @@ -485,17 +497,20 @@ class MacroAssembler: public Assembler { // Prepares stack to put arguments (aligns and so on). Reserves // space for return value if needed (assumes the return value is a handle). // Uses callee-saved esi to restore stack state after call. Arguments must be - // stored in ApiParameterOperand(0), ApiParameterOperand(1) etc. + // stored in ApiParameterOperand(0), ApiParameterOperand(1) etc. Saves + // context (esi). void PrepareCallApiFunction(int stack_space, int argc); // Calls an API function. Allocates HandleScope, extracts // returned value from handle and propagates exceptions. - // Clobbers ebx, esi, edi and caller-save registers. - void CallApiFunctionAndReturn(ApiFunction* function, int argc); + // Clobbers ebx, edi and caller-save registers. Restores context. + MaybeObject* TryCallApiFunctionAndReturn(ApiFunction* function, int argc); // Jump to a runtime routine. void JumpToExternalReference(const ExternalReference& ext); + MaybeObject* TryJumpToExternalReference(const ExternalReference& ext); + // --------------------------------------------------------------------------- // Utilities diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index f59928f..48e04c8 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -486,31 +486,43 @@ static bool GenerateFastApiCall(MacroAssembler* masm, Immediate(Handle(call_data))); } - // Prepare arguments for ApiCallEntryStub. + // Prepare arguments. __ lea(eax, Operand(esp, 3 * kPointerSize)); - __ lea(ebx, Operand(esp, (argc + 3) * kPointerSize)); - __ Set(edx, Immediate(argc)); Object* callback = optimization.api_call_info()->callback(); Address api_function_address = v8::ToCData
(callback); ApiFunction fun(api_function_address); - ApiCallEntryStub stub(api_call_info_handle, &fun); + const int kApiArgc = 1; // API function gets reference to the v8::Arguments. - __ EnterInternalFrame(); + // Allocate the v8::Arguments structure in the arguments' space since + // it's not controlled by GC. + const int kApiStackSpace = 4; + + __ PrepareCallApiFunction(argc + kFastApiCallArguments + 1, + kApiArgc + kApiStackSpace); + + __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. + __ add(Operand(eax), Immediate(argc * kPointerSize)); + __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_. + __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_. + // v8::Arguments::is_construct_call_. + __ mov(ApiParameterOperand(4), Immediate(0)); + + // v8::InvocationCallback's argument. + __ lea(eax, ApiParameterOperand(1)); + __ mov(ApiParameterOperand(0), eax); // Emitting a stub call may try to allocate (if the code is not // already generated). Do not allow the assembler to perform a // garbage collection but instead return the allocation failure // object. - MaybeObject* result = masm->TryCallStub(&stub); + MaybeObject* result = + masm->TryCallApiFunctionAndReturn(&fun, kApiArgc + kApiStackSpace); if (result->IsFailure()) { *failure = Failure::cast(result); return false; } - - __ LeaveInternalFrame(); - __ ret((argc + 4) * kPointerSize); return true; } @@ -1063,44 +1075,55 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, Handle callback_handle(callback); - __ EnterInternalFrame(); - // Push the stack address where the list of arguments ends. - __ lea(scratch2, Operand(esp, -2 * kPointerSize)); - __ push(scratch2); + // Insert additional parameters into the stack frame above return address. + ASSERT(!scratch3.is(reg)); + __ pop(scratch3); // Get return address to place it below. + __ push(receiver); // receiver + __ mov(scratch2, Operand(esp)); + ASSERT(!scratch2.is(reg)); __ push(reg); // holder // Push data from AccessorInfo. if (Heap::InNewSpace(callback_handle->data())) { - __ mov(scratch2, Immediate(callback_handle)); - __ push(FieldOperand(scratch2, AccessorInfo::kDataOffset)); + __ mov(scratch1, Immediate(callback_handle)); + __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); } else { __ push(Immediate(Handle(callback_handle->data()))); } - __ push(name_reg); // name + // Save a pointer to where we pushed the arguments pointer. // This will be passed as the const AccessorInfo& to the C++ callback. - STATIC_ASSERT(ApiGetterEntryStub::kStackSpace == 5); - __ lea(eax, Operand(esp, 4 * kPointerSize)); - __ mov(ebx, esp); + __ push(scratch2); + + __ push(name_reg); // name + __ mov(ebx, esp); // esp points to reference to name (handler). + + __ push(scratch3); // Restore return address. // Do call through the api. Address getter_address = v8::ToCData
(callback->getter()); ApiFunction fun(getter_address); - ApiGetterEntryStub stub(callback_handle, &fun); + + // 3 elements array for v8::Agruments::values_, handler for name and pointer + // to the values (it considered as smi in GC). + const int kStackSpace = 5; + const int kApiArgc = 2; + + __ PrepareCallApiFunction(kStackSpace, kApiArgc); + __ mov(ApiParameterOperand(0), ebx); // name. + __ add(Operand(ebx), Immediate(kPointerSize)); + __ mov(ApiParameterOperand(1), ebx); // arguments pointer. + // Emitting a stub call may try to allocate (if the code is not // already generated). Do not allow the assembler to perform a // garbage collection but instead return the allocation failure // object. - Object* result = NULL; // Initialization to please compiler. - { MaybeObject* try_call_result = masm()->TryCallStub(&stub); - if (!try_call_result->ToObject(&result)) { - *failure = Failure::cast(try_call_result); - return false; - } + MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kApiArgc); + if (result->IsFailure()) { + *failure = Failure::cast(result); + return false; } - __ LeaveInternalFrame(); - __ ret(0); return true; } diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 2b79016..69219ee 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -982,7 +982,6 @@ void AccessorInfo::AccessorInfoVerify() { VerifyPointer(name()); VerifyPointer(data()); VerifyPointer(flag()); - VerifyPointer(load_stub_cache()); } void AccessorInfo::AccessorInfoPrint() { @@ -997,8 +996,6 @@ void AccessorInfo::AccessorInfoPrint() { data()->ShortPrint(); PrintF("\n - flag: "); flag()->ShortPrint(); - PrintF("\n - load_stub_cache: "); - load_stub_cache()->ShortPrint(); } void AccessCheckInfo::AccessCheckInfoVerify() { @@ -1048,7 +1045,6 @@ void CallHandlerInfo::CallHandlerInfoVerify() { CHECK(IsCallHandlerInfo()); VerifyPointer(callback()); VerifyPointer(data()); - VerifyPointer(call_stub_cache()); } void CallHandlerInfo::CallHandlerInfoPrint() { @@ -1058,7 +1054,6 @@ void CallHandlerInfo::CallHandlerInfoPrint() { PrintF("\n - data: "); data()->ShortPrint(); PrintF("\n - call_stub_cache: "); - call_stub_cache()->ShortPrint(); } void TemplateInfo::TemplateInfoVerify() { diff --git a/src/objects-inl.h b/src/objects-inl.h index 79d70e1..499cb91 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2542,7 +2542,6 @@ ACCESSORS(AccessorInfo, setter, Object, kSetterOffset) ACCESSORS(AccessorInfo, data, Object, kDataOffset) ACCESSORS(AccessorInfo, name, Object, kNameOffset) ACCESSORS(AccessorInfo, flag, Smi, kFlagOffset) -ACCESSORS(AccessorInfo, load_stub_cache, Object, kLoadStubCacheOffset) ACCESSORS(AccessCheckInfo, named_callback, Object, kNamedCallbackOffset) ACCESSORS(AccessCheckInfo, indexed_callback, Object, kIndexedCallbackOffset) @@ -2557,7 +2556,6 @@ ACCESSORS(InterceptorInfo, data, Object, kDataOffset) ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) -ACCESSORS(CallHandlerInfo, call_stub_cache, Object, kCallStubCacheOffset) ACCESSORS(TemplateInfo, tag, Object, kTagOffset) ACCESSORS(TemplateInfo, property_list, Object, kPropertyListOffset) diff --git a/src/objects.h b/src/objects.h index 9d975ec..b52bac2 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5327,7 +5327,6 @@ class AccessorInfo: public Struct { DECL_ACCESSORS(data, Object) DECL_ACCESSORS(name, Object) DECL_ACCESSORS(flag, Smi) - DECL_ACCESSORS(load_stub_cache, Object) inline bool all_can_read(); inline void set_all_can_read(bool value); @@ -5353,8 +5352,7 @@ class AccessorInfo: public Struct { static const int kDataOffset = kSetterOffset + kPointerSize; static const int kNameOffset = kDataOffset + kPointerSize; static const int kFlagOffset = kNameOffset + kPointerSize; - static const int kLoadStubCacheOffset = kFlagOffset + kPointerSize; - static const int kSize = kLoadStubCacheOffset + kPointerSize; + static const int kSize = kFlagOffset + kPointerSize; private: // Bit positions in flag. @@ -5423,7 +5421,6 @@ class CallHandlerInfo: public Struct { public: DECL_ACCESSORS(callback, Object) DECL_ACCESSORS(data, Object) - DECL_ACCESSORS(call_stub_cache, Object) static inline CallHandlerInfo* cast(Object* obj); @@ -5434,8 +5431,7 @@ class CallHandlerInfo: public Struct { static const int kCallbackOffset = HeapObject::kHeaderSize; static const int kDataOffset = kCallbackOffset + kPointerSize; - static const int kCallStubCacheOffset = kDataOffset + kPointerSize; - static const int kSize = kCallStubCacheOffset + kPointerSize; + static const int kSize = kDataOffset + kPointerSize; private: DISALLOW_IMPLICIT_CONSTRUCTORS(CallHandlerInfo); diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index c179769..291375c 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -2483,20 +2483,6 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { } -void ApiGetterEntryStub::Generate(MacroAssembler* masm) { - __ PrepareCallApiFunction(kStackSpace); -#ifdef _WIN64 - // All the parameters should be set up by a caller. -#else - // Set 1st parameter register with property name. - __ movq(rsi, rdx); - // Second parameter register rdi should be set with pointer to AccessorInfo - // by a caller. -#endif - __ CallApiFunctionAndReturn(fun()); -} - - void CEntryStub::GenerateCore(MacroAssembler* masm, Label* throw_normal_exception, Label* throw_termination_exception, diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 293d8a5..a7dc1e9 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -327,7 +327,7 @@ MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub) { void MacroAssembler::TailCallStub(CodeStub* stub) { - ASSERT(allow_stub_calls()); // calls are not allowed in some stubs + ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. Jump(stub->GetCode(), RelocInfo::CODE_TARGET); } @@ -456,6 +456,24 @@ void MacroAssembler::TailCallExternalReference(const ExternalReference& ext, } +MaybeObject* MacroAssembler::TryTailCallExternalReference( + const ExternalReference& ext, int num_arguments, int result_size) { + // ----------- S t a t e ------------- + // -- rsp[0] : return address + // -- rsp[8] : argument num_arguments - 1 + // ... + // -- rsp[8 * num_arguments] : argument 0 (receiver) + // ----------------------------------- + + // TODO(1236192): Most runtime routines don't need the number of + // arguments passed in because it is constant. At some point we + // should remove this need and make the runtime routine entry code + // smarter. + Set(rax, num_arguments); + return TryJumpToExternalReference(ext, result_size); +} + + void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, int num_arguments, int result_size) { @@ -463,6 +481,15 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, } +MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid, + int num_arguments, + int result_size) { + return TryTailCallExternalReference(ExternalReference(fid), + num_arguments, + result_size); +} + + static int Offset(ExternalReference ref0, ExternalReference ref1) { int64_t offset = (ref0.address() - ref1.address()); // Check that fits into int. @@ -471,12 +498,24 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) { } -void MacroAssembler::PrepareCallApiFunction(int stack_space) { - EnterApiExitFrame(stack_space, 0); +void MacroAssembler::PrepareCallApiFunction(int stack_space, int argc) { +#ifdef _WIN64 + // We need to prepare a slot for result handle on stack and put + // a pointer to it into 1st arg register. + int register_based_args = argc > 3 ? 3 : argc; + EnterApiExitFrame(stack_space, argc - register_based_args + 1); + + int return_value_slot = (argc > 3 ? argc - 3 + 1 : 4); + // rcx must be used to pass the pointer to the return value slot. + lea(rcx, Operand(rsp, return_value_slot * kPointerSize)); +#else + EnterApiExitFrame(stack_space, argc); +#endif } -void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function) { +MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( + ApiFunction* function) { Label empty_result; Label prologue; Label promote_scheduled_exception; @@ -539,7 +578,11 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function) { ret(0); bind(&promote_scheduled_exception); - TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); + MaybeObject* result = TryTailCallRuntime(Runtime::kPromoteScheduledException, + 0, 1); + if (result->IsFailure()) { + return result; + } bind(&empty_result); // It was zero; the result is undefined. @@ -554,6 +597,8 @@ void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function) { call(rax); movq(rax, prev_limit_reg); jmp(&leave_exit_frame); + + return result; } @@ -566,6 +611,15 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext, } +MaybeObject* MacroAssembler::TryJumpToExternalReference( + const ExternalReference& ext, int result_size) { + // Set the entry point and jump to the C entry runtime stub. + movq(rbx, ext); + CEntryStub ces(result_size); + return TryTailCallStub(&ces); +} + + void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) { // Calls are not allowed in some stubs. ASSERT(flag == JUMP_FUNCTION || allow_stub_calls()); @@ -1742,6 +1796,10 @@ void MacroAssembler::EnterApiExitFrame(int stack_space, int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; lea(r12, Operand(rbp, (stack_space * kPointerSize) + offset)); +#ifndef _WIN64 + ASSERT(argc <= 6); // EnterApiExitFrame supports only register based args. +#endif + EnterExitFrameEpilogue(result_size, argc); } diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index 7007374..2554868 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -813,22 +813,38 @@ class MacroAssembler: public Assembler { int num_arguments, int result_size); + MUST_USE_RESULT MaybeObject* TryTailCallExternalReference( + const ExternalReference& ext, int num_arguments, int result_size); + // Convenience function: tail call a runtime routine (jump). void TailCallRuntime(Runtime::FunctionId fid, int num_arguments, int result_size); + MUST_USE_RESULT MaybeObject* TryTailCallRuntime(Runtime::FunctionId fid, + int num_arguments, + int result_size); + // Jump to a runtime routine. void JumpToExternalReference(const ExternalReference& ext, int result_size); - // Prepares stack to put arguments (aligns and so on). - // Uses calle-saved esi to restore stack state after call. - void PrepareCallApiFunction(int stack_space); + // Jump to a runtime routine. + MaybeObject* TryJumpToExternalReference(const ExternalReference& ext, + int result_size); - // Tail call an API function (jump). Allocates HandleScope, extracts - // returned value from handle and propogates exceptions. - // Clobbers ebx, edi and caller-save registers. - void CallApiFunctionAndReturn(ApiFunction* function); + // Prepares stack to put arguments (aligns and so on). + // Uses callee-saved rsi to restore stack state after call. WIN64 calling + // convention requires to put the pointer to the return value slot into rcx + // (rcx must be preserverd until TryCallApiFunctionAndReturn). argc is number + // of arguments to be passed in C-function. stack_space * kPointerSize bytes + // will be removed from stack after the call. Saves context (rsi). + void PrepareCallApiFunction(int stack_space, int argc); + + // Calls an API function. Allocates HandleScope, extracts + // returned value from handle and propagates exceptions. + // Clobbers r12, r14, rbx and caller-save registers. Restores context. + MUST_USE_RESULT MaybeObject* TryCallApiFunctionAndReturn( + ApiFunction* function); // Before calling a C-function from generated code, align arguments on stack. // After aligning the frame, arguments must be stored in esp[0], esp[4], diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 24609bf..13a543f 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -1844,7 +1844,7 @@ MaybeObject* LoadStubCompiler::CompileLoadCallback(String* name, Label miss; Failure* failure = Failure::InternalError(); - bool success = GenerateLoadCallback(object, holder, rax, rcx, rbx, rdx, rdi, + bool success = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi, callback, name, &miss, &failure); if (!success) { miss.Unuse(); @@ -2585,19 +2585,21 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, Handle callback_handle(callback); - __ EnterInternalFrame(); - // Push the stack address where the list of arguments ends. - __ movq(scratch2, rsp); - __ subq(scratch2, Immediate(2 * kPointerSize)); - __ push(scratch2); + // Insert additional parameters into the stack frame above return address. + ASSERT(!scratch2.is(reg)); + __ pop(scratch2); // Get return address to place it below. + __ push(receiver); // receiver + ASSERT(!scratch3.is(reg)); + __ movq(scratch3, rsp); __ push(reg); // holder if (Heap::InNewSpace(callback_handle->data())) { - __ Move(scratch2, callback_handle); - __ push(FieldOperand(scratch2, AccessorInfo::kDataOffset)); // data + __ Move(scratch1, callback_handle); + __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data } else { __ Push(Handle(callback_handle->data())); } + __ push(scratch3); __ push(name_reg); // name // Save a pointer to where we pushed the arguments pointer. // This will be passed as the const AccessorInfo& to the C++ callback. @@ -2607,42 +2609,38 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, Register accessor_info_arg = r8; Register name_arg = rdx; #else - Register accessor_info_arg = rdx; // temporary, copied to rsi by the stub. + Register accessor_info_arg = rsi; Register name_arg = rdi; #endif - __ movq(accessor_info_arg, rsp); - __ addq(accessor_info_arg, Immediate(4 * kPointerSize)); + ASSERT(!name_arg.is(scratch2)); __ movq(name_arg, rsp); + __ push(scratch2); // Restore return address. // Do call through the api. - ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace); Address getter_address = v8::ToCData
(callback->getter()); ApiFunction fun(getter_address); - ApiGetterEntryStub stub(callback_handle, &fun); -#ifdef _WIN64 - // We need to prepare a slot for result handle on stack and put - // a pointer to it into 1st arg register. - __ push(Immediate(0)); - __ movq(rcx, rsp); -#endif + + // 3 elements array for v8::Agruments::values_, handler for name and pointer + // to the values (it considered as smi in GC). + const int kStackSpace = 5; + const int kApiArgc = 2; + + __ PrepareCallApiFunction(kStackSpace, kApiArgc); + + // The context register (rsi) has been saved in PrepareCallApiFunction and + // could be used to pass arguments. + __ lea(accessor_info_arg, Operand(name_arg, 1 * kPointerSize)); + // Emitting a stub call may try to allocate (if the code is not // already generated). Do not allow the assembler to perform a // garbage collection but instead return the allocation failure // object. - MaybeObject* result = masm()->TryCallStub(&stub); + MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun); if (result->IsFailure()) { *failure = Failure::cast(result); return false; } -#ifdef _WIN64 - // Discard allocated slot. - __ addq(rsp, Immediate(kPointerSize)); -#endif - __ LeaveInternalFrame(); - - __ ret(0); - return true; }