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
This commit is contained in:
serya@chromium.org 2010-11-15 17:12:34 +00:00
parent af7b6fecfe
commit 3b248841da
14 changed files with 233 additions and 239 deletions

View File

@ -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<Code> CodeStub::GetCode() {
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;
}
@ -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));
}
}

View File

@ -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<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() { }

View File

@ -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

View File

@ -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,

View File

@ -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<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.
@ -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> code_constant,

View File

@ -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

View File

@ -486,31 +486,43 @@ static bool GenerateFastApiCall(MacroAssembler* masm,
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;
}
@ -1063,44 +1075,55 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
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;
}

View File

@ -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() {

View File

@ -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)

View File

@ -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);

View File

@ -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,

View File

@ -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);
}

View File

@ -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],

View File

@ -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<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.
@ -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<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;
}