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:
parent
af7b6fecfe
commit
3b248841da
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() { }
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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],
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user