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));
Handle<Code> 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<NumberDictionary> dict =
- Factory::DictionaryAtNumberPut(
- Handle<NumberDictionary>(Heap::code_stubs()),
- GetKey(),
- new_object);
- Heap::public_set_code_stubs(*dict);
- }
+ // Update the dictionary and the root in Heap.
+ Handle<NumberDictionary> dict =
+ Factory::DictionaryAtNumberPut(
+ Handle<NumberDictionary>(Heap::code_stubs()),
+ GetKey(),
+ new_object);
+ Heap::public_set_code_stubs(*dict);
+
code = *new_object;
}
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));
}
}
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;
};
-class ApiGetterEntryStub : public CodeStub {
- public:
- ApiGetterEntryStub(Handle<AccessorInfo> 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<AccessorInfo> 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<AccessorInfo> info_;
- // The function to be called.
- ApiFunction* fun_;
-};
-
-
-class ApiCallEntryStub : public CodeStub {
- public:
- ApiCallEntryStub(Handle<CallHandlerInfo> 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<CallHandlerInfo> 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<CallHandlerInfo> info_;
- // The function to be called.
- ApiFunction* fun_;
-};
-
-
class JSEntryStub : public CodeStub {
public:
JSEntryStub() { }
}
-// 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
}
-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,
}
+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) {
}
+MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid,
+ int num_arguments,
+ int result_size) {
+ return TryTailCallExternalReference(
+ ExternalReference(fid), num_arguments, result_size);
+}
+
+
// If true, a Handle<T> 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.
}
-void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function, int argc) {
+MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function,
+ int argc) {
if (!kPassHandlesDirectly) {
// The argument slots are filled as follows:
//
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());
call(Operand(eax));
mov(eax, edi);
jmp(&leave_exit_frame);
+
+ return result;
}
}
+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> code_constant,
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.
// 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
Immediate(Handle<Object>(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<Address>(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;
}
Handle<AccessorInfo> 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<Object>(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<Address>(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;
}
VerifyPointer(name());
VerifyPointer(data());
VerifyPointer(flag());
- VerifyPointer(load_stub_cache());
}
void AccessorInfo::AccessorInfoPrint() {
data()->ShortPrint();
PrintF("\n - flag: ");
flag()->ShortPrint();
- PrintF("\n - load_stub_cache: ");
- load_stub_cache()->ShortPrint();
}
void AccessCheckInfo::AccessCheckInfoVerify() {
CHECK(IsCallHandlerInfo());
VerifyPointer(callback());
VerifyPointer(data());
- VerifyPointer(call_stub_cache());
}
void CallHandlerInfo::CallHandlerInfoPrint() {
PrintF("\n - data: ");
data()->ShortPrint();
PrintF("\n - call_stub_cache: ");
- call_stub_cache()->ShortPrint();
}
void TemplateInfo::TemplateInfoVerify() {
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)
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)
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);
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.
public:
DECL_ACCESSORS(callback, Object)
DECL_ACCESSORS(data, Object)
- DECL_ACCESSORS(call_stub_cache, Object)
static inline CallHandlerInfo* cast(Object* obj);
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);
}
-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,
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);
}
}
+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) {
}
+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.
}
-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;
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.
call(rax);
movq(rax, prev_limit_reg);
jmp(&leave_exit_frame);
+
+ return result;
}
}
+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());
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);
}
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],
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();
Handle<AccessorInfo> 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<Object>(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.
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<Address>(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;
}