Direct call API functions (ia32 implementation).
Review URL: http://codereview.chromium.org/4456002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5791 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
8ebe8e4756
commit
82fc8fe39a
@ -542,7 +542,7 @@ class ApiGetterEntryStub : public CodeStub {
|
||||
ApiFunction* fun() { return fun_; }
|
||||
Major MajorKey() { return NoCache; }
|
||||
int MinorKey() { return 0; }
|
||||
const char* GetName() { return "ApiEntryStub"; }
|
||||
const char* GetName() { return "ApiGetterEntryStub"; }
|
||||
// The accessor info associated with the function.
|
||||
Handle<AccessorInfo> info_;
|
||||
// The function to be called.
|
||||
@ -550,6 +550,32 @@ class ApiGetterEntryStub : public CodeStub {
|
||||
};
|
||||
|
||||
|
||||
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() { }
|
||||
|
@ -482,8 +482,8 @@ int CEntryStub::MinorKey() {
|
||||
}
|
||||
|
||||
|
||||
bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
|
||||
Object* cache = info()->load_stub_cache();
|
||||
// Implementation of CodeStub::GetCustomCache.
|
||||
static bool GetCustomCacheHelper(Object* cache, Code** code_out) {
|
||||
if (cache->IsUndefined()) {
|
||||
return false;
|
||||
} else {
|
||||
@ -493,9 +493,24 @@ bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
@ -521,7 +521,6 @@ class Assembler : public Malloced {
|
||||
void push(const Immediate& x);
|
||||
void push(Register src);
|
||||
void push(const Operand& src);
|
||||
void push(Label* label, RelocInfo::Mode relocation_mode);
|
||||
|
||||
void pop(Register dst);
|
||||
void pop(const Operand& dst);
|
||||
|
@ -3067,6 +3067,26 @@ void ApiGetterEntryStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
|
@ -488,7 +488,7 @@ class MacroAssembler: public Assembler {
|
||||
// stored in ApiParameterOperand(0), ApiParameterOperand(1) etc.
|
||||
void PrepareCallApiFunction(int stack_space, int argc);
|
||||
|
||||
// Tail call an API function (jump). Allocates HandleScope, extracts
|
||||
// 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);
|
||||
|
@ -413,6 +413,10 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Number of pointers to be reserved on stack for fast API call.
|
||||
static const int kFastApiCallArguments = 3;
|
||||
|
||||
|
||||
// Reserves space for the extra arguments to FastHandleApiCall in the
|
||||
// caller's frame.
|
||||
//
|
||||
@ -423,10 +427,9 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
|
||||
// -- esp[4] : last argument in the internal frame of the caller
|
||||
// -----------------------------------
|
||||
__ pop(scratch);
|
||||
__ push(Immediate(Smi::FromInt(0)));
|
||||
__ push(Immediate(Smi::FromInt(0)));
|
||||
__ push(Immediate(Smi::FromInt(0)));
|
||||
__ push(Immediate(Smi::FromInt(0)));
|
||||
for (int i = 0; i < kFastApiCallArguments; i++) {
|
||||
__ push(Immediate(Smi::FromInt(0)));
|
||||
}
|
||||
__ push(scratch);
|
||||
}
|
||||
|
||||
@ -434,75 +437,81 @@ static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
|
||||
// Undoes the effects of ReserveSpaceForFastApiCall.
|
||||
static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : last fast api call extra argument
|
||||
// -- esp[0] : return address.
|
||||
// -- esp[4] : last fast api call extra argument.
|
||||
// -- ...
|
||||
// -- esp[16] : first fast api call extra argument
|
||||
// -- esp[20] : last argument in the internal frame
|
||||
// -- esp[kFastApiCallArguments * 4] : first fast api call extra argument.
|
||||
// -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
|
||||
// frame.
|
||||
// -----------------------------------
|
||||
__ pop(scratch);
|
||||
__ add(Operand(esp), Immediate(kPointerSize * 4));
|
||||
__ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments));
|
||||
__ push(scratch);
|
||||
}
|
||||
|
||||
|
||||
// Generates call to FastHandleApiCall builtin.
|
||||
static void GenerateFastApiCall(MacroAssembler* masm,
|
||||
static bool GenerateFastApiCall(MacroAssembler* masm,
|
||||
const CallOptimization& optimization,
|
||||
int argc) {
|
||||
int argc,
|
||||
Failure** failure) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- esp[0] : return address
|
||||
// -- esp[4] : object passing the type check
|
||||
// (last fast api call extra argument,
|
||||
// set by CheckPrototypes)
|
||||
// -- esp[8] : api call data
|
||||
// -- esp[12] : api callback
|
||||
// -- esp[16] : api function
|
||||
// -- esp[8] : api function
|
||||
// (first fast api call extra argument)
|
||||
// -- esp[20] : last argument
|
||||
// -- esp[12] : api call data
|
||||
// -- esp[16] : last argument
|
||||
// -- ...
|
||||
// -- esp[(argc + 5) * 4] : first argument
|
||||
// -- esp[(argc + 6) * 4] : receiver
|
||||
// -- esp[(argc + 3) * 4] : first argument
|
||||
// -- esp[(argc + 4) * 4] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// Get the function and setup the context.
|
||||
JSFunction* function = optimization.constant_function();
|
||||
__ mov(edi, Immediate(Handle<JSFunction>(function)));
|
||||
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
|
||||
|
||||
// Pass the additional arguments FastHandleApiCall expects.
|
||||
__ mov(Operand(esp, 4 * kPointerSize), edi);
|
||||
bool info_loaded = false;
|
||||
Object* callback = optimization.api_call_info()->callback();
|
||||
if (Heap::InNewSpace(callback)) {
|
||||
info_loaded = true;
|
||||
__ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
|
||||
__ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kCallbackOffset));
|
||||
__ mov(Operand(esp, 2 * kPointerSize), edi);
|
||||
Object* call_data = optimization.api_call_info()->data();
|
||||
Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
|
||||
if (Heap::InNewSpace(call_data)) {
|
||||
__ mov(ecx, api_call_info_handle);
|
||||
__ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
|
||||
__ mov(Operand(esp, 3 * kPointerSize), ebx);
|
||||
} else {
|
||||
__ mov(Operand(esp, 3 * kPointerSize), Immediate(Handle<Object>(callback)));
|
||||
}
|
||||
Object* call_data = optimization.api_call_info()->data();
|
||||
if (Heap::InNewSpace(call_data)) {
|
||||
if (!info_loaded) {
|
||||
__ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
|
||||
}
|
||||
__ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
|
||||
__ mov(Operand(esp, 2 * kPointerSize), ebx);
|
||||
} else {
|
||||
__ mov(Operand(esp, 2 * kPointerSize),
|
||||
__ mov(Operand(esp, 3 * kPointerSize),
|
||||
Immediate(Handle<Object>(call_data)));
|
||||
}
|
||||
|
||||
// Set the number of arguments.
|
||||
__ mov(eax, Immediate(argc + 4));
|
||||
// Prepare arguments for ApiCallEntryStub.
|
||||
__ lea(eax, Operand(esp, 3 * kPointerSize));
|
||||
__ lea(ebx, Operand(esp, (argc + 3) * kPointerSize));
|
||||
__ Set(edx, Immediate(argc));
|
||||
|
||||
// Jump to the fast api call builtin (tail call).
|
||||
Handle<Code> code = Handle<Code>(
|
||||
Builtins::builtin(Builtins::FastHandleApiCall));
|
||||
ParameterCount expected(0);
|
||||
__ InvokeCode(code, expected, expected,
|
||||
RelocInfo::CODE_TARGET, JUMP_FUNCTION);
|
||||
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);
|
||||
|
||||
__ EnterInternalFrame();
|
||||
|
||||
// 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);
|
||||
if (result->IsFailure()) {
|
||||
*failure = Failure::cast(result);
|
||||
return false;
|
||||
}
|
||||
|
||||
__ LeaveInternalFrame();
|
||||
__ ret((argc + 4) * kPointerSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -515,7 +524,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
arguments_(arguments),
|
||||
name_(name) {}
|
||||
|
||||
void Compile(MacroAssembler* masm,
|
||||
bool Compile(MacroAssembler* masm,
|
||||
JSObject* object,
|
||||
JSObject* holder,
|
||||
String* name,
|
||||
@ -524,7 +533,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
Register scratch1,
|
||||
Register scratch2,
|
||||
Register scratch3,
|
||||
Label* miss) {
|
||||
Label* miss,
|
||||
Failure** failure) {
|
||||
ASSERT(holder->HasNamedInterceptor());
|
||||
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
|
||||
|
||||
@ -535,17 +545,18 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
CallOptimization optimization(lookup);
|
||||
|
||||
if (optimization.is_constant_call()) {
|
||||
CompileCacheable(masm,
|
||||
object,
|
||||
receiver,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch3,
|
||||
holder,
|
||||
lookup,
|
||||
name,
|
||||
optimization,
|
||||
miss);
|
||||
return CompileCacheable(masm,
|
||||
object,
|
||||
receiver,
|
||||
scratch1,
|
||||
scratch2,
|
||||
scratch3,
|
||||
holder,
|
||||
lookup,
|
||||
name,
|
||||
optimization,
|
||||
miss,
|
||||
failure);
|
||||
} else {
|
||||
CompileRegular(masm,
|
||||
object,
|
||||
@ -556,11 +567,12 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
name,
|
||||
holder,
|
||||
miss);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void CompileCacheable(MacroAssembler* masm,
|
||||
bool CompileCacheable(MacroAssembler* masm,
|
||||
JSObject* object,
|
||||
Register receiver,
|
||||
Register scratch1,
|
||||
@ -570,7 +582,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
LookupResult* lookup,
|
||||
String* name,
|
||||
const CallOptimization& optimization,
|
||||
Label* miss_label) {
|
||||
Label* miss_label,
|
||||
Failure** failure) {
|
||||
ASSERT(optimization.is_constant_call());
|
||||
ASSERT(!lookup->holder()->IsGlobalObject());
|
||||
|
||||
@ -632,7 +645,11 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
|
||||
// Invoke function.
|
||||
if (can_do_fast_api_call) {
|
||||
GenerateFastApiCall(masm, optimization, arguments_.immediate());
|
||||
bool success = GenerateFastApiCall(masm, optimization,
|
||||
arguments_.immediate(), failure);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
__ InvokeFunction(optimization.constant_function(), arguments_,
|
||||
JUMP_FUNCTION);
|
||||
@ -650,6 +667,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
||||
if (can_do_fast_api_call) {
|
||||
FreeSpaceForFastApiCall(masm, scratch1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CompileRegular(MacroAssembler* masm,
|
||||
@ -1046,8 +1065,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
|
||||
|
||||
__ EnterInternalFrame();
|
||||
// Push the stack address where the list of arguments ends.
|
||||
__ mov(scratch2, esp);
|
||||
__ sub(Operand(scratch2), Immediate(2 * kPointerSize));
|
||||
__ lea(scratch2, Operand(esp, -2 * kPointerSize));
|
||||
__ push(scratch2);
|
||||
__ push(receiver); // receiver
|
||||
__ push(reg); // holder
|
||||
@ -1061,12 +1079,11 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object,
|
||||
__ 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.
|
||||
__ mov(eax, esp);
|
||||
__ add(Operand(eax), Immediate(4 * kPointerSize));
|
||||
STATIC_ASSERT(ApiGetterEntryStub::kStackSpace == 5);
|
||||
__ lea(eax, Operand(esp, 4 * kPointerSize));
|
||||
__ mov(ebx, esp);
|
||||
|
||||
// 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);
|
||||
@ -2208,7 +2225,11 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
}
|
||||
|
||||
if (depth != kInvalidProtoDepth) {
|
||||
GenerateFastApiCall(masm(), optimization, argc);
|
||||
Failure* failure;
|
||||
bool success = GenerateFastApiCall(masm(), optimization, argc, &failure);
|
||||
if (!success) {
|
||||
return failure;
|
||||
}
|
||||
} else {
|
||||
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
||||
}
|
||||
@ -2253,16 +2274,21 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
|
||||
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
|
||||
|
||||
CallInterceptorCompiler compiler(this, arguments(), ecx);
|
||||
compiler.Compile(masm(),
|
||||
object,
|
||||
holder,
|
||||
name,
|
||||
&lookup,
|
||||
edx,
|
||||
ebx,
|
||||
edi,
|
||||
eax,
|
||||
&miss);
|
||||
Failure* failure;
|
||||
bool success = compiler.Compile(masm(),
|
||||
object,
|
||||
holder,
|
||||
name,
|
||||
&lookup,
|
||||
edx,
|
||||
ebx,
|
||||
edi,
|
||||
eax,
|
||||
&miss,
|
||||
&failure);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restore receiver.
|
||||
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
|
||||
|
@ -997,6 +997,8 @@ void AccessorInfo::AccessorInfoPrint() {
|
||||
data()->ShortPrint();
|
||||
PrintF("\n - flag: ");
|
||||
flag()->ShortPrint();
|
||||
PrintF("\n - load_stub_cache: ");
|
||||
load_stub_cache()->ShortPrint();
|
||||
}
|
||||
|
||||
void AccessCheckInfo::AccessCheckInfoVerify() {
|
||||
@ -1046,6 +1048,7 @@ void CallHandlerInfo::CallHandlerInfoVerify() {
|
||||
CHECK(IsCallHandlerInfo());
|
||||
VerifyPointer(callback());
|
||||
VerifyPointer(data());
|
||||
VerifyPointer(call_stub_cache());
|
||||
}
|
||||
|
||||
void CallHandlerInfo::CallHandlerInfoPrint() {
|
||||
@ -1054,6 +1057,8 @@ void CallHandlerInfo::CallHandlerInfoPrint() {
|
||||
callback()->ShortPrint();
|
||||
PrintF("\n - data: ");
|
||||
data()->ShortPrint();
|
||||
PrintF("\n - call_stub_cache: ");
|
||||
call_stub_cache()->ShortPrint();
|
||||
}
|
||||
|
||||
void TemplateInfo::TemplateInfoVerify() {
|
||||
|
@ -2557,6 +2557,7 @@ 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)
|
||||
|
@ -5423,6 +5423,7 @@ 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);
|
||||
|
||||
@ -5433,7 +5434,8 @@ class CallHandlerInfo: public Struct {
|
||||
|
||||
static const int kCallbackOffset = HeapObject::kHeaderSize;
|
||||
static const int kDataOffset = kCallbackOffset + kPointerSize;
|
||||
static const int kSize = kDataOffset + kPointerSize;
|
||||
static const int kCallStubCacheOffset = kDataOffset + kPointerSize;
|
||||
static const int kSize = kCallStubCacheOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(CallHandlerInfo);
|
||||
|
Loading…
Reference in New Issue
Block a user