Commit 881476a7 authored by dcarney@chromium.org's avatar dcarney@chromium.org

new style of property/function callbacks

R=svenpanne@chromium.org
BUG=

Review URL: https://codereview.chromium.org/12494012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14725 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 45ec4816
This diff is collapsed.
This diff is collapsed.
......@@ -39,31 +39,6 @@ class ImplementationUtilities {
return that->names_;
}
// Packs additional parameters for the NewArguments function. |implicit_args|
// is a pointer to the last element of 4-elements array controlled by GC.
static void PrepareArgumentsData(internal::Object** implicit_args,
internal::Isolate* isolate,
internal::Object* data,
internal::JSFunction* callee,
internal::Object* holder) {
implicit_args[v8::Arguments::kDataIndex] = data;
implicit_args[v8::Arguments::kCalleeIndex] = callee;
implicit_args[v8::Arguments::kHolderIndex] = holder;
implicit_args[v8::Arguments::kIsolateIndex] =
reinterpret_cast<internal::Object*>(isolate);
}
static v8::Arguments NewArguments(internal::Object** implicit_args,
internal::Object** argv, int argc,
bool is_construct_call) {
ASSERT(implicit_args[v8::Arguments::kCalleeIndex]->IsJSFunction());
ASSERT(implicit_args[v8::Arguments::kHolderIndex]->IsHeapObject());
// The implicit isolate argument is not tagged and looks like a SMI.
ASSERT(implicit_args[v8::Arguments::kIsolateIndex]->IsSmi());
return v8::Arguments(implicit_args, argv, argc, is_construct_call);
}
// Introduce an alias for the handle scope data to allow non-friends
// to access the HandleScope data.
typedef v8::HandleScope::Data HandleScopeData;
......
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "v8.h"
#include "arguments.h"
namespace v8 {
namespace internal {
static bool Match(void* a, void* b) {
return a == b;
}
static uint32_t Hash(void* function) {
uintptr_t as_int = reinterpret_cast<uintptr_t>(function);
if (sizeof(function) == 4) return static_cast<uint32_t>(as_int);
uint64_t as_64 = static_cast<uint64_t>(as_int);
return
static_cast<uint32_t>(as_64 >> 32) ^
static_cast<uint32_t>(as_64);
}
CallbackTable::CallbackTable(): map_(Match, 64) {}
bool CallbackTable::Contains(void* function) {
ASSERT(function != NULL);
return map_.Lookup(function, Hash(function), false) != NULL;
}
void CallbackTable::InsertCallback(Isolate* isolate,
void* function,
bool returns_void) {
if (function == NULL) return;
// Don't store for performance.
if (kStoreVoidFunctions != returns_void) return;
CallbackTable* table = isolate->callback_table();
if (table == NULL) {
table = new CallbackTable();
isolate->set_callback_table(table);
}
typedef HashMap::Entry Entry;
Entry* entry = table->map_.Lookup(function, Hash(function), true);
ASSERT(entry != NULL);
ASSERT(entry->value == NULL || entry->value == function);
entry->value = function;
}
template<typename T>
template<typename V>
v8::Handle<V> CustomArguments<T>::GetReturnValue(Isolate* isolate) {
// Check the ReturnValue.
Object** handle = &this->end()[kReturnValueOffset];
// Nothing was set, return empty handle as per previous behaviour.
if ((*handle)->IsTheHole()) return v8::Handle<V>();
return v8::Handle<V>(reinterpret_cast<V*>(handle));
}
v8::Handle<v8::Value> FunctionCallbackArguments::Call(InvocationCallback f) {
Isolate* isolate = this->isolate();
void* f_as_void = CallbackTable::FunctionToVoidPtr(f);
bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void);
if (new_style) {
FunctionCallback c = reinterpret_cast<FunctionCallback>(f);
FunctionCallbackInfo<v8::Value> info(end(),
argv_,
argc_,
is_construct_call_);
c(info);
} else {
v8::Arguments args(end(),
argv_,
argc_,
is_construct_call_);
v8::Handle<v8::Value> return_value = f(args);
if (!return_value.IsEmpty()) return return_value;
}
return GetReturnValue<v8::Value>(isolate);
}
#define WRITE_CALL_0(OldFunction, NewFunction, ReturnValue) \
v8::Handle<ReturnValue> PropertyCallbackArguments::Call(OldFunction f) { \
Isolate* isolate = this->isolate(); \
void* f_as_void = CallbackTable::FunctionToVoidPtr(f); \
bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void); \
if (new_style) { \
NewFunction c = reinterpret_cast<NewFunction>(f); \
PropertyCallbackInfo<ReturnValue> info(end()); \
c(info); \
} else { \
v8::AccessorInfo info(end()); \
v8::Handle<ReturnValue> return_value = f(info); \
if (!return_value.IsEmpty()) return return_value; \
} \
return GetReturnValue<ReturnValue>(isolate); \
}
#define WRITE_CALL_1(OldFunction, NewFunction, ReturnValue, Arg1) \
v8::Handle<ReturnValue> PropertyCallbackArguments::Call(OldFunction f, \
Arg1 arg1) { \
Isolate* isolate = this->isolate(); \
void* f_as_void = CallbackTable::FunctionToVoidPtr(f); \
bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void); \
if (new_style) { \
NewFunction c = reinterpret_cast<NewFunction>(f); \
PropertyCallbackInfo<ReturnValue> info(end()); \
c(arg1, info); \
} else { \
v8::AccessorInfo info(end()); \
v8::Handle<ReturnValue> return_value = f(arg1, info); \
if (!return_value.IsEmpty()) return return_value; \
} \
return GetReturnValue<ReturnValue>(isolate); \
}
#define WRITE_CALL_2(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \
v8::Handle<ReturnValue> PropertyCallbackArguments::Call(OldFunction f, \
Arg1 arg1, \
Arg2 arg2) { \
Isolate* isolate = this->isolate(); \
void* f_as_void = CallbackTable::FunctionToVoidPtr(f); \
bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void); \
if (new_style) { \
NewFunction c = reinterpret_cast<NewFunction>(f); \
PropertyCallbackInfo<ReturnValue> info(end()); \
c(arg1, arg2, info); \
} else { \
v8::AccessorInfo info(end()); \
v8::Handle<ReturnValue> return_value = f(arg1, arg2, info); \
if (!return_value.IsEmpty()) return return_value; \
} \
return GetReturnValue<ReturnValue>(isolate); \
}
#define WRITE_CALL_2_VOID(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \
void PropertyCallbackArguments::Call(OldFunction f, \
Arg1 arg1, \
Arg2 arg2) { \
Isolate* isolate = this->isolate(); \
void* f_as_void = CallbackTable::FunctionToVoidPtr(f); \
bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void); \
if (new_style) { \
NewFunction c = reinterpret_cast<NewFunction>(f); \
PropertyCallbackInfo<ReturnValue> info(end()); \
c(arg1, arg2, info); \
} else { \
v8::AccessorInfo info(end()); \
f(arg1, arg2, info); \
} \
}
FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0)
FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1)
FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2)
FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID)
#undef WRITE_CALL_0
#undef WRITE_CALL_1
#undef WRITE_CALL_2
#undef WRITE_CALL_2_VOID
} } // namespace v8::internal
......@@ -82,35 +82,258 @@ class Arguments BASE_EMBEDDED {
};
// mappings from old property callbacks to new ones
// F(old name, new name, return value, parameters...)
//
// These aren't included in the list as they have duplicate signatures
// F(NamedPropertyEnumerator, NamedPropertyEnumeratorCallback, ...)
// F(NamedPropertyGetter, NamedPropertyGetterCallback, ...)
#define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \
F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback, v8::Array) \
#define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \
F(AccessorGetter, AccessorGetterCallback, v8::Value, v8::Local<v8::String>) \
F(NamedPropertyQuery, \
NamedPropertyQueryCallback, \
v8::Integer, \
v8::Local<v8::String>) \
F(NamedPropertyDeleter, \
NamedPropertyDeleterCallback, \
v8::Boolean, \
v8::Local<v8::String>) \
F(IndexedPropertyGetter, \
IndexedPropertyGetterCallback, \
v8::Value, \
uint32_t) \
F(IndexedPropertyQuery, \
IndexedPropertyQueryCallback, \
v8::Integer, \
uint32_t) \
F(IndexedPropertyDeleter, \
IndexedPropertyDeleterCallback, \
v8::Boolean, \
uint32_t) \
#define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \
F(NamedPropertySetter, \
NamedPropertySetterCallback, \
v8::Value, \
v8::Local<v8::String>, \
v8::Local<v8::Value>) \
F(IndexedPropertySetter, \
IndexedPropertySetterCallback, \
v8::Value, \
uint32_t, \
v8::Local<v8::Value>) \
#define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \
F(AccessorSetter, \
AccessorSetterCallback, \
void, \
v8::Local<v8::String>, \
v8::Local<v8::Value>) \
// All property callbacks as well as invocation callbacks
#define FOR_EACH_CALLBACK_TABLE_MAPPING(F) \
F(InvocationCallback, FunctionCallback) \
F(AccessorGetter, AccessorGetterCallback) \
F(AccessorSetter, AccessorSetterCallback) \
F(NamedPropertySetter, NamedPropertySetterCallback) \
F(NamedPropertyQuery, NamedPropertyQueryCallback) \
F(NamedPropertyDeleter, NamedPropertyDeleterCallback) \
F(IndexedPropertyGetter, IndexedPropertyGetterCallback) \
F(IndexedPropertySetter, IndexedPropertySetterCallback) \
F(IndexedPropertyQuery, IndexedPropertyQueryCallback) \
F(IndexedPropertyDeleter, IndexedPropertyDeleterCallback) \
F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback) \
// TODO(dcarney): Remove this class when old callbacks are gone.
class CallbackTable {
public:
// TODO(dcarney): Flip this when it makes sense for performance.
static const bool kStoreVoidFunctions = true;
static inline bool ReturnsVoid(Isolate* isolate, void* function) {
CallbackTable* table = isolate->callback_table();
bool contains =
table != NULL &&
table->map_.occupancy() != 0 &&
table->Contains(function);
return contains == kStoreVoidFunctions;
}
STATIC_ASSERT(sizeof(intptr_t) == sizeof(AccessorGetterCallback));
template<typename F>
static inline void* FunctionToVoidPtr(F function) {
return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(function));
}
#define WRITE_REGISTER(OldFunction, NewFunction) \
static OldFunction Register(Isolate* isolate, NewFunction f) { \
InsertCallback(isolate, FunctionToVoidPtr(f), true); \
return reinterpret_cast<OldFunction>(f); \
} \
\
static OldFunction Register(Isolate* isolate, OldFunction f) { \
InsertCallback(isolate, FunctionToVoidPtr(f), false); \
return f; \
}
FOR_EACH_CALLBACK_TABLE_MAPPING(WRITE_REGISTER)
#undef WRITE_REGISTER
private:
CallbackTable();
bool Contains(void* function);
static void InsertCallback(Isolate* isolate,
void* function,
bool returns_void);
HashMap map_;
DISALLOW_COPY_AND_ASSIGN(CallbackTable);
};
// Custom arguments replicate a small segment of stack that can be
// accessed through an Arguments object the same way the actual stack
// can.
class CustomArguments : public Relocatable {
template<int kArrayLength>
class CustomArgumentsBase : public Relocatable {
public:
virtual inline void IterateInstance(ObjectVisitor* v) {
v->VisitPointers(values_, values_ + kArrayLength);
}
protected:
inline Object** end() { return values_ + kArrayLength - 1; }
explicit inline CustomArgumentsBase(Isolate* isolate)
: Relocatable(isolate) {}
Object* values_[kArrayLength];
};
template<typename T>
class CustomArguments : public CustomArgumentsBase<T::kArgsLength> {
public:
inline CustomArguments(Isolate* isolate,
Object* data,
Object* self,
JSObject* holder) : Relocatable(isolate) {
ASSERT(reinterpret_cast<Object*>(isolate)->IsSmi());
values_[3] = self;
values_[2] = holder;
values_[1] = data;
values_[0] = reinterpret_cast<Object*>(isolate);
static const int kReturnValueOffset = T::kReturnValueIndex;
typedef CustomArgumentsBase<T::kArgsLength> Super;
~CustomArguments() {
// TODO(dcarney): create a new zap value for this.
this->end()[kReturnValueOffset] =
reinterpret_cast<Object*>(kHandleZapValue);
}
protected:
explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {}
template<typename V>
v8::Handle<V> GetReturnValue(Isolate* isolate);
inline Isolate* isolate() {
return reinterpret_cast<Isolate*>(this->end()[T::kIsolateIndex]);
}
};
class PropertyCallbackArguments
: public CustomArguments<PropertyCallbackInfo<Value> > {
public:
typedef PropertyCallbackInfo<Value> T;
typedef CustomArguments<T> Super;
static const int kArgsLength = T::kArgsLength;
static const int kThisIndex = T::kThisIndex;
static const int kHolderIndex = T::kHolderIndex;
PropertyCallbackArguments(Isolate* isolate,
Object* data,
Object* self,
JSObject* holder)
: Super(isolate) {
Object** values = this->end();
values[T::kThisIndex] = self;
values[T::kHolderIndex] = holder;
values[T::kDataIndex] = data;
values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate);
values[T::kReturnValueIndex] = isolate->heap()->the_hole_value();
ASSERT(values[T::kHolderIndex]->IsHeapObject());
ASSERT(values[T::kIsolateIndex]->IsSmi());
}
/*
* The following Call functions wrap the calling of all callbacks to handle
* calling either the old or the new style callbacks depending on which one
* has been registered.
* For old callbacks which return an empty handle, the ReturnValue is checked
* and used if it's been set to anything inside the callback.
* New style callbacks always use the return value.
*/
#define WRITE_CALL_0(OldFunction, NewFunction, ReturnValue) \
v8::Handle<ReturnValue> Call(OldFunction f); \
#define WRITE_CALL_1(OldFunction, NewFunction, ReturnValue, Arg1) \
v8::Handle<ReturnValue> Call(OldFunction f, Arg1 arg1); \
#define WRITE_CALL_2(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \
v8::Handle<ReturnValue> Call(OldFunction f, Arg1 arg1, Arg2 arg2); \
#define WRITE_CALL_2_VOID(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \
void Call(OldFunction f, Arg1 arg1, Arg2 arg2); \
FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0)
FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1)
FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2)
FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID)
#undef WRITE_CALL_0
#undef WRITE_CALL_1
#undef WRITE_CALL_2
#undef WRITE_CALL_2_VOID
};
class FunctionCallbackArguments
: public CustomArguments<FunctionCallbackInfo<Value> > {
public:
typedef FunctionCallbackInfo<Value> T;
typedef CustomArguments<T> Super;
static const int kArgsLength = T::kArgsLength;
inline explicit CustomArguments(Isolate* isolate) : Relocatable(isolate) {
#ifdef DEBUG
for (size_t i = 0; i < ARRAY_SIZE(values_); i++) {
values_[i] = reinterpret_cast<Object*>(kZapValue);
}
#endif
FunctionCallbackArguments(internal::Isolate* isolate,
internal::Object* data,
internal::JSFunction* callee,
internal::Object* holder,
internal::Object** argv,
int argc,
bool is_construct_call)
: Super(isolate),
argv_(argv),
argc_(argc),
is_construct_call_(is_construct_call) {
Object** values = end();
values[T::kDataIndex] = data;
values[T::kCalleeIndex] = callee;
values[T::kHolderIndex] = holder;
values[T::kIsolateIndex] = reinterpret_cast<internal::Object*>(isolate);
values[T::kReturnValueIndex] = isolate->heap()->the_hole_value();
ASSERT(values[T::kCalleeIndex]->IsJSFunction());
ASSERT(values[T::kHolderIndex]->IsHeapObject());
ASSERT(values[T::kIsolateIndex]->IsSmi());
}
void IterateInstance(ObjectVisitor* v);
Object** end() { return values_ + ARRAY_SIZE(values_) - 1; }
/*
* The following Call function wraps the calling of all callbacks to handle
* calling either the old or the new style callbacks depending on which one
* has been registered.
* For old callbacks which return an empty handle, the ReturnValue is checked
* and used if it's been set to anything inside the callback.
* New style callbacks always use the return value.
*/
v8::Handle<v8::Value> Call(InvocationCallback f);
private:
Object* values_[4];
internal::Object** argv_;
int argc_;
bool is_construct_call_;
};
......
......@@ -2262,7 +2262,9 @@ static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
int stack_space) {
int stack_space,
bool returns_handle,
int return_value_offset) {
ExternalReference next_address =
ExternalReference::handle_scope_next_address(isolate());
const int kNextOffset = 0;
......@@ -2308,13 +2310,20 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
Label promote_scheduled_exception;
Label delete_allocated_handles;
Label leave_exit_frame;
// If result is non-zero, dereference to get the result value
// otherwise set it to undefined.
cmp(r0, Operand::Zero());
LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
ldr(r0, MemOperand(r0), ne);
Label return_value_loaded;
if (returns_handle) {
Label load_return_value;
cmp(r0, Operand::Zero());
b(eq, &load_return_value);
// derefernce returned value
ldr(r0, MemOperand(r0));
b(&return_value_loaded);
bind(&load_return_value);
}
// load value from ReturnValue
ldr(r0, MemOperand(fp, return_value_offset*kPointerSize));
bind(&return_value_loaded);
// No more valid handles (the result handle was the last one). Restore
// previous handle scope.
str(r4, MemOperand(r7, kNextOffset));
......
......@@ -1087,7 +1087,10 @@ class MacroAssembler: public Assembler {
// from handle and propagates exceptions. Restores context. stack_space
// - space to be unwound on exit (includes the call JS arguments space and
// the additional space allocated for the fast call).
void CallApiFunctionAndReturn(ExternalReference function, int stack_space);
void CallApiFunctionAndReturn(ExternalReference function,
int stack_space,
bool returns_handle,
int return_value_offset_from_fp);
// Jump to a runtime routine.
void JumpToExternalReference(const ExternalReference& builtin);
......
......@@ -852,7 +852,7 @@ static void CompileCallLoadPropertyWithInterceptor(
}
static const int kFastApiCallArguments = 4;
static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
// Reserves space for the extra arguments to API function in the
// caller's frame.
......@@ -881,10 +881,11 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
// -- sp[4] : callee JS function
// -- sp[8] : call data
// -- sp[12] : isolate
// -- sp[16] : last JS argument
// -- sp[16] : ReturnValue
// -- sp[20] : last JS argument
// -- ...
// -- sp[(argc + 3) * 4] : first JS argument
// -- sp[(argc + 4) * 4] : receiver
// -- sp[(argc + 4) * 4] : first JS argument
// -- sp[(argc + 5) * 4] : receiver
// -----------------------------------
// Get the function and setup the context.
Handle<JSFunction> function = optimization.constant_function();
......@@ -901,11 +902,13 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
__ Move(r6, call_data);
}
__ mov(r7, Operand(ExternalReference::isolate_address(masm->isolate())));
// Store JS function, call data and isolate.
// Store JS function, call data, isolate and ReturnValue.
__ stm(ib, sp, r5.bit() | r6.bit() | r7.bit());
__ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
__ str(r5, MemOperand(sp, 4 * kPointerSize));
// Prepare arguments.
__ add(r2, sp, Operand(3 * kPointerSize));
__ add(r2, sp, Operand(4 * kPointerSize));
// Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC.
......@@ -931,13 +934,17 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
Address function_address = v8::ToCData<Address>(api_call_info->callback());
bool returns_handle =
!CallbackTable::ReturnsVoid(masm->isolate(), function_address);
ApiFunction fun(function_address);
ExternalReference ref = ExternalReference(&fun,
ExternalReference::DIRECT_API_CALL,
masm->isolate());
AllowExternalCallThatCantCauseGC scope(masm);
__ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
__ CallApiFunctionAndReturn(ref,
kStackUnwindSpace,
returns_handle,
kFastApiCallArguments + 1);
}
......@@ -1413,7 +1420,8 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
__ Push(reg, scratch3());
__ mov(scratch3(),
Operand(ExternalReference::isolate_address(isolate())));
__ Push(scratch3(), name());
__ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex);
__ Push(scratch3(), scratch4(), name());
__ mov(r0, sp); // r0 = Handle<Name>
const int kApiStackSpace = 1;
......@@ -1425,12 +1433,17 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
__ str(scratch2(), MemOperand(sp, 1 * kPointerSize));
__ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo&
const int kStackUnwindSpace = 5;
const int kStackUnwindSpace = kFastApiCallArguments + 1;
Address getter_address = v8::ToCData<Address>(callback->getter());
bool returns_handle =
!CallbackTable::ReturnsVoid(isolate(), getter_address);
ApiFunction fun(getter_address);
ExternalReference ref = ExternalReference(
&fun, ExternalReference::DIRECT_GETTER_CALL, isolate());
__ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
__ CallApiFunctionAndReturn(ref,
kStackUnwindSpace,
returns_handle,
3);
}
......
......@@ -1317,15 +1317,13 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
ASSERT(raw_holder->IsJSObject());
CustomArguments custom(isolate);
v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
isolate, data_obj, *function, raw_holder);
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
custom.end(),
&args[0] - 1,
args.length() - 1,
is_construct);
FunctionCallbackArguments custom(isolate,
data_obj,
*function,
raw_holder,
&args[0] - 1,
args.length() - 1,
is_construct);
v8::Handle<v8::Value> value;
{
......@@ -1333,7 +1331,7 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
VMState<EXTERNAL> state(isolate);
ExternalCallbackScope call_scope(isolate,
v8::ToCData<Address>(callback_obj));
value = callback(new_args);
value = custom.Call(callback);
}
if (value.IsEmpty()) {
result = heap->undefined_value();
......@@ -1396,21 +1394,20 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
HandleScope scope(isolate);
LOG(isolate, ApiObjectAccess("call non-function", obj));
CustomArguments custom(isolate);
v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
isolate, call_data->data(), constructor, obj);
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
custom.end(),
&args[0] - 1,
args.length() - 1,
is_construct_call);
FunctionCallbackArguments custom(isolate,
call_data->data(),
constructor,
obj,
&args[0] - 1,
args.length() - 1,
is_construct_call);
v8::Handle<v8::Value> value;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
ExternalCallbackScope call_scope(isolate,
v8::ToCData<Address>(callback_obj));
value = callback(new_args);
value = custom.Call(callback);
}
if (value.IsEmpty()) {
result = heap->undefined_value();
......
......@@ -545,19 +545,14 @@ int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
}
void CustomArguments::IterateInstance(ObjectVisitor* v) {
v->VisitPointers(values_, values_ + ARRAY_SIZE(values_));
}
// Compute the property keys from the interceptor.
// TODO(rossberg): support symbols in API, and filter here if needed.
v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSReceiver> receiver,
Handle<JSObject> object) {
Isolate* isolate = receiver->GetIsolate();
Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
CustomArguments args(isolate, interceptor->data(), *receiver, *object);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments
args(isolate, interceptor->data(), *receiver, *object);
v8::Handle<v8::Array> result;
if (!interceptor->enumerator()->IsUndefined()) {
v8::NamedPropertyEnumerator enum_fun =
......@@ -566,7 +561,7 @@ v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSReceiver> receiver,
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = enum_fun(info);
result = args.Call(enum_fun);
}
}
#if ENABLE_EXTRA_CHECKS
......@@ -581,8 +576,8 @@ v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver,
Handle<JSObject> object) {
Isolate* isolate = receiver->GetIsolate();
Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
CustomArguments args(isolate, interceptor->data(), *receiver, *object);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments
args(isolate, interceptor->data(), *receiver, *object);
v8::Handle<v8::Array> result;
if (!interceptor->enumerator()->IsUndefined()) {
v8::IndexedPropertyEnumerator enum_fun =
......@@ -591,7 +586,7 @@ v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver,
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = enum_fun(info);
result = args.Call(enum_fun);
#if ENABLE_EXTRA_CHECKS
CHECK(result.IsEmpty() || v8::Utils::OpenHandle(*result)->IsJSObject());
#endif
......
......@@ -1954,14 +1954,14 @@ static const bool kReturnHandlesDirectly = false;
#endif
Operand ApiParameterOperand(int index) {
return Operand(
esp, (index + (kReturnHandlesDirectly ? 0 : 1)) * kPointerSize);
Operand ApiParameterOperand(int index, bool returns_handle) {
int offset = (index +(kReturnHandlesDirectly || !returns_handle ? 0 : 1));
return Operand(esp, offset * kPointerSize);
}
void MacroAssembler::PrepareCallApiFunction(int argc) {
if (kReturnHandlesDirectly) {
void MacroAssembler::PrepareCallApiFunction(int argc, bool returns_handle) {
if (kReturnHandlesDirectly || !returns_handle) {
EnterApiExitFrame(argc);
// When handles are returned directly we don't have to allocate extra
// space for and pass an out parameter.
......@@ -1990,7 +1990,9 @@ void MacroAssembler::PrepareCallApiFunction(int argc) {
void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
int stack_space) {
int stack_space,
bool returns_handle,
int return_value_offset) {
ExternalReference next_address =
ExternalReference::handle_scope_next_address(isolate());
ExternalReference limit_address =
......@@ -2026,23 +2028,29 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
PopSafepointRegisters();
}
if (!kReturnHandlesDirectly) {
// PrepareCallApiFunction saved pointer to the output slot into
// callee-save register esi.
mov(eax, Operand(esi, 0));
}
Label empty_handle;
Label prologue;
if (returns_handle) {
if (!kReturnHandlesDirectly) {
// PrepareCallApiFunction saved pointer to the output slot into
// callee-save register esi.
mov(eax, Operand(esi, 0));
}
Label empty_handle;
// Check if the result handle holds 0.
test(eax, eax);
j(zero, &empty_handle);
// It was non-zero. Dereference to get the result value.
mov(eax, Operand(eax, 0));
jmp(&prologue);
bind(&empty_handle);
}
// Load the value from ReturnValue
mov(eax, Operand(ebp, return_value_offset * kPointerSize));
Label promote_scheduled_exception;
Label delete_allocated_handles;
Label leave_exit_frame;
// Check if the result handle holds 0.
test(eax, eax);
j(zero, &empty_handle);
// It was non-zero. Dereference to get the result value.
mov(eax, Operand(eax, 0));
bind(&prologue);
// No more valid handles (the result handle was the last one). Restore
// previous handle scope.
......@@ -2098,11 +2106,6 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
LeaveApiExitFrame();
ret(stack_space * kPointerSize);
bind(&empty_handle);
// It was zero; the result is undefined.
mov(eax, isolate()->factory()->undefined_value());
jmp(&prologue);
bind(&promote_scheduled_exception);
TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
......
......@@ -769,13 +769,16 @@ class MacroAssembler: public Assembler {
// Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1)
// etc. Saves context (esi). If space was reserved for return value then
// stores the pointer to the reserved slot into esi.
void PrepareCallApiFunction(int argc);
void PrepareCallApiFunction(int argc, bool returns_handle);
// Calls an API function. Allocates HandleScope, extracts returned value
// from handle and propagates exceptions. Clobbers ebx, edi and
// caller-save registers. Restores context. On return removes
// stack_space * kPointerSize (GCed).
void CallApiFunctionAndReturn(Address function_address, int stack_space);
void CallApiFunctionAndReturn(Address function_address,
int stack_space,
bool returns_handle,
int return_value_offset_from_ebp);
// Jump to a runtime routine.
void JumpToExternalReference(const ExternalReference& ext);
......@@ -1010,7 +1013,7 @@ inline Operand GlobalObjectOperand() {
// Generates an Operand for saving parameters after PrepareCallApiFunction.
Operand ApiParameterOperand(int index);
Operand ApiParameterOperand(int index, bool returns_handle);
#ifdef GENERATED_CODE_COVERAGE
......
......@@ -420,7 +420,7 @@ static void CompileCallLoadPropertyWithInterceptor(
// Number of pointers to be reserved on stack for fast API call.
static const int kFastApiCallArguments = 4;
static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
// Reserves space for the extra arguments to API function in the
......@@ -469,10 +469,11 @@ static void GenerateFastApiCall(MacroAssembler* masm,
// (first fast api call extra argument)
// -- esp[12] : api call data
// -- esp[16] : isolate
// -- esp[20] : last argument
// -- esp[20] : ReturnValue
// -- esp[24] : last argument
// -- ...
// -- esp[(argc + 4) * 4] : first argument
// -- esp[(argc + 5) * 4] : receiver
// -- esp[(argc + 5) * 4] : first argument
// -- esp[(argc + 6) * 4] : receiver
// -----------------------------------
// Get the function and setup the context.
Handle<JSFunction> function = optimization.constant_function();
......@@ -492,9 +493,12 @@ static void GenerateFastApiCall(MacroAssembler* masm,
}
__ mov(Operand(esp, 4 * kPointerSize),
Immediate(reinterpret_cast<int>(masm->isolate())));
__ mov(Operand(esp, 5 * kPointerSize),
masm->isolate()->factory()->undefined_value());
// Prepare arguments.
__ lea(eax, Operand(esp, 4 * kPointerSize));
STATIC_ASSERT(kFastApiCallArguments == 5);
__ lea(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
const int kApiArgc = 1; // API function gets reference to the v8::Arguments.
......@@ -502,23 +506,31 @@ static void GenerateFastApiCall(MacroAssembler* masm,
// it's not controlled by GC.
const int kApiStackSpace = 4;
__ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
// Function address is a foreign pointer outside V8's heap.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
bool returns_handle =
!CallbackTable::ReturnsVoid(masm->isolate(),
reinterpret_cast<void*>(function_address));
__ PrepareCallApiFunction(kApiArgc + kApiStackSpace, returns_handle);
__ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_.
// v8::Arguments::implicit_args_.
__ mov(ApiParameterOperand(1, returns_handle), eax);
__ add(eax, Immediate(argc * kPointerSize));
__ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_.
__ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_.
// v8::Arguments::values_.
__ mov(ApiParameterOperand(2, returns_handle), eax);
// v8::Arguments::length_.
__ Set(ApiParameterOperand(3, returns_handle), Immediate(argc));
// v8::Arguments::is_construct_call_.
__ Set(ApiParameterOperand(4), Immediate(0));
__ Set(ApiParameterOperand(4, returns_handle), Immediate(0));
// v8::InvocationCallback's argument.
__ lea(eax, ApiParameterOperand(1));
__ mov(ApiParameterOperand(0), eax);
__ lea(eax, ApiParameterOperand(1, returns_handle));
__ mov(ApiParameterOperand(0, returns_handle), eax);
// Function address is a foreign pointer outside V8's heap.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ CallApiFunctionAndReturn(function_address,
argc + kFastApiCallArguments + 1);
argc + kFastApiCallArguments + 1,
returns_handle,
kFastApiCallArguments + 1);
}
......@@ -1365,6 +1377,7 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
__ push(Immediate(Handle<Object>(callback->data(), isolate())));
}
__ push(Immediate(reinterpret_cast<int>(isolate())));
__ push(Immediate(isolate()->factory()->undefined_value())); // ReturnValue
// Save a pointer to where we pushed the arguments pointer. This will be
// passed as the const ExecutableAccessorInfo& to the C++ callback.
......@@ -1375,22 +1388,29 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
__ push(scratch3()); // Restore return address.
// 4 elements array for v8::Arguments::values_, handler for name and pointer
// array for v8::Arguments::values_, handler for name and pointer
// to the values (it considered as smi in GC).
const int kStackSpace = 6;
const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
const int kApiArgc = 2;
__ PrepareCallApiFunction(kApiArgc);
__ mov(ApiParameterOperand(0), ebx); // name.
Address getter_address = v8::ToCData<Address>(callback->getter());
bool returns_handle =
!CallbackTable::ReturnsVoid(isolate(),
reinterpret_cast<void*>(getter_address));
__ PrepareCallApiFunction(kApiArgc, returns_handle);
__ mov(ApiParameterOperand(0, returns_handle), ebx); // name.
__ add(ebx, Immediate(kPointerSize));
__ mov(ApiParameterOperand(1), ebx); // arguments pointer.
__ mov(ApiParameterOperand(1, returns_handle), 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.
Address getter_address = v8::ToCData<Address>(callback->getter());
__ CallApiFunctionAndReturn(getter_address, kStackSpace);
__ CallApiFunctionAndReturn(getter_address,
kStackSpace,
returns_handle,
4);
}
......@@ -2493,7 +2513,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
name, depth, &miss);
// Move the return address on top of the stack.
__ mov(eax, Operand(esp, 4 * kPointerSize));
__ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
__ mov(Operand(esp, 0 * kPointerSize), eax);
// esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
......
......@@ -1752,7 +1752,8 @@ Isolate::Isolate()
deferred_handles_head_(NULL),
optimizing_compiler_thread_(this),
marking_thread_(NULL),
sweeper_thread_(NULL) {
sweeper_thread_(NULL),
callback_table_(NULL) {
id_ = NoBarrier_AtomicIncrement(&isolate_counter_, 1);
TRACE_ISOLATE(constructor);
......
......@@ -51,6 +51,7 @@ namespace v8 {
namespace internal {
class Bootstrapper;
class CallbackTable;
class CodeGenerator;
class CodeRange;
struct CodeStubInterfaceDescriptor;
......@@ -1102,6 +1103,13 @@ class Isolate {
return sweeper_thread_;
}
CallbackTable* callback_table() {
return callback_table_;
}
void set_callback_table(CallbackTable* callback_table) {
callback_table_ = callback_table;
}
HStatistics* GetHStatistics();
HTracer* GetHTracer();
......@@ -1339,6 +1347,7 @@ class Isolate {
OptimizingCompilerThread optimizing_compiler_thread_;
MarkingThread** marking_thread_;
SweeperThread** sweeper_thread_;
CallbackTable* callback_table_;
friend class ExecutionAccess;
friend class HandleScopeImplementer;
......
This diff is collapsed.
......@@ -1104,13 +1104,13 @@ RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
Handle<String> str = Handle<String>::cast(name);
LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
CustomArguments custom_args(isolate, callback->data(), recv, recv);
v8::AccessorInfo info(custom_args.end());
PropertyCallbackArguments
custom_args(isolate, callback->data(), recv, recv);
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
ExternalCallbackScope call_scope(isolate, setter_address);
fun(v8::Utils::ToLocal(str), v8::Utils::ToLocal(value), info);
custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return *value;
......@@ -1128,13 +1128,13 @@ static const int kAccessorInfoOffsetInInterceptorArgs = 2;
* provide any value for the given name.
*/
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
typedef PropertyCallbackArguments PCA;
static const int kArgsOffset = kAccessorInfoOffsetInInterceptorArgs;
Handle<Name> name_handle = args.at<Name>(0);
Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
ASSERT(args[2]->IsJSObject()); // Receiver.
ASSERT(args[3]->IsJSObject()); // Holder.
ASSERT(args[5]->IsSmi()); // Isolate.
ASSERT(args.length() == 6);
ASSERT(kArgsOffset == 2);
// No ReturnValue in interceptors.
ASSERT(args.length() == kArgsOffset + PCA::kArgsLength - 1);
// TODO(rossberg): Support symbols in the API.
if (name_handle->IsSymbol())
......@@ -1146,16 +1146,22 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
ASSERT(getter != NULL);
Handle<JSObject> receiver =
args.at<JSObject>(kArgsOffset - PCA::kThisIndex);
Handle<JSObject> holder =
args.at<JSObject>(kArgsOffset - PCA::kHolderIndex);
PropertyCallbackArguments callback_args(isolate,
interceptor_info->data(),
*receiver,
*holder);
{
// Use the interceptor getter.
v8::AccessorInfo info(args.arguments() -
kAccessorInfoOffsetInInterceptorArgs);
HandleScope scope(isolate);
v8::Handle<v8::Value> r;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
r = getter(v8::Utils::ToLocal(name), info);
r = callback_args.Call(getter, v8::Utils::ToLocal(name));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!r.IsEmpty()) {
......@@ -1189,12 +1195,17 @@ static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) {
static MaybeObject* LoadWithInterceptor(Arguments* args,
PropertyAttributes* attrs) {
typedef PropertyCallbackArguments PCA;
static const int kArgsOffset = kAccessorInfoOffsetInInterceptorArgs;
Handle<Name> name_handle = args->at<Name>(0);
Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
Handle<JSObject> receiver_handle = args->at<JSObject>(2);
Handle<JSObject> holder_handle = args->at<JSObject>(3);
ASSERT(args->length() == 6);
ASSERT(kArgsOffset == 2);
// No ReturnValue in interceptors.
ASSERT(args->length() == kArgsOffset + PCA::kArgsLength - 1);
Handle<JSObject> receiver_handle =
args->at<JSObject>(kArgsOffset - PCA::kThisIndex);
Handle<JSObject> holder_handle =
args->at<JSObject>(kArgsOffset - PCA::kHolderIndex);
Isolate* isolate = receiver_handle->GetIsolate();
......@@ -1209,16 +1220,18 @@ static MaybeObject* LoadWithInterceptor(Arguments* args,
FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
ASSERT(getter != NULL);
PropertyCallbackArguments callback_args(isolate,
interceptor_info->data(),
*receiver_handle,
*holder_handle);
{
// Use the interceptor getter.
v8::AccessorInfo info(args->arguments() -
kAccessorInfoOffsetInInterceptorArgs);
HandleScope scope(isolate);
v8::Handle<v8::Value> r;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
r = getter(v8::Utils::ToLocal(name), info);
r = callback_args.Call(getter, v8::Utils::ToLocal(name));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!r.IsEmpty()) {
......
......@@ -677,8 +677,13 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) {
}
void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) {
void MacroAssembler::PrepareCallApiFunction(int arg_stack_space,
bool returns_handle) {
#if defined(_WIN64) && !defined(__MINGW64__)
if (!returns_handle) {
EnterApiExitFrame(arg_stack_space);
return;
}
// We need to prepare a slot for result handle on stack and put
// a pointer to it into 1st arg register.
EnterApiExitFrame(arg_stack_space + 1);
......@@ -692,8 +697,9 @@ void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) {
void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
int stack_space) {
Label empty_result;
int stack_space,
bool returns_handle,
int return_value_offset) {
Label prologue;
Label promote_scheduled_exception;
Label delete_allocated_handles;
......@@ -745,15 +751,25 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
PopSafepointRegisters();
}
// Can skip the result check for new-style callbacks
// TODO(dcarney): may need to pass this information down
// as some function_addresses might not have been registered
if (returns_handle) {
Label empty_result;
#if defined(_WIN64) && !defined(__MINGW64__)
// rax keeps a pointer to v8::Handle, unpack it.
movq(rax, Operand(rax, 0));
// rax keeps a pointer to v8::Handle, unpack it.
movq(rax, Operand(rax, 0));
#endif
// Check if the result handle holds 0.
testq(rax, rax);
j(zero, &empty_result);
// It was non-zero. Dereference to get the result value.
movq(rax, Operand(rax, 0));
// Check if the result handle holds 0.
testq(rax, rax);
j(zero, &empty_result);
// It was non-zero. Dereference to get the result value.
movq(rax, Operand(rax, 0));
jmp(&prologue);
bind(&empty_result);
}
// Load the value from ReturnValue
movq(rax, Operand(rbp, return_value_offset * kPointerSize));
bind(&prologue);
// No more valid handles (the result handle was the last one). Restore
......@@ -807,11 +823,6 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
LeaveApiExitFrame();
ret(stack_space * kPointerSize);
bind(&empty_result);
// It was zero; the result is undefined.
LoadRoot(rax, Heap::kUndefinedValueRootIndex);
jmp(&prologue);
bind(&promote_scheduled_exception);
TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
......
......@@ -1224,13 +1224,16 @@ class MacroAssembler: public Assembler {
// rcx (rcx must be preserverd until CallApiFunctionAndReturn). Saves
// context (rsi). Clobbers rax. Allocates arg_stack_space * kPointerSize
// inside the exit frame (not GCed) accessible via StackSpaceOperand.
void PrepareCallApiFunction(int arg_stack_space);
void PrepareCallApiFunction(int arg_stack_space, bool returns_handle);
// Calls an API function. Allocates HandleScope, extracts returned value
// from handle and propagates exceptions. Clobbers r14, r15, rbx and
// caller-save registers. Restores context. On return removes
// stack_space * kPointerSize (GCed).
void CallApiFunctionAndReturn(Address function_address, int stack_space);
void CallApiFunctionAndReturn(Address function_address,
int stack_space,
bool returns_handle,
int return_value_offset_from_rbp);
// 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],
......
......@@ -398,7 +398,7 @@ static void CompileCallLoadPropertyWithInterceptor(
// Number of pointers to be reserved on stack for fast API call.
static const int kFastApiCallArguments = 4;
static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
// Reserves space for the extra arguments to API function in the
......@@ -449,10 +449,12 @@ static void GenerateFastApiCall(MacroAssembler* masm,
// (first fast api call extra argument)
// -- rsp[24] : api call data
// -- rsp[32] : isolate
// -- rsp[40] : last argument
// -- rsp[40] : ReturnValue
//
// -- rsp[48] : last argument
// -- ...
// -- rsp[(argc + 4) * 8] : first argument
// -- rsp[(argc + 5) * 8] : receiver
// -- rsp[(argc + 5) * 8] : first argument
// -- rsp[(argc + 6) * 8] : receiver
// -----------------------------------
// Get the function and setup the context.
Handle<JSFunction> function = optimization.constant_function();
......@@ -473,15 +475,23 @@ static void GenerateFastApiCall(MacroAssembler* masm,
__ movq(kScratchRegister,
ExternalReference::isolate_address(masm->isolate()));
__ movq(Operand(rsp, 4 * kPointerSize), kScratchRegister);
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
__ movq(Operand(rsp, 5 * kPointerSize), kScratchRegister);
// Prepare arguments.
__ lea(rbx, Operand(rsp, 4 * kPointerSize));
STATIC_ASSERT(kFastApiCallArguments == 5);
__ lea(rbx, Operand(rsp, kFastApiCallArguments * kPointerSize));
// Function address is a foreign pointer outside V8's heap.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
bool returns_handle =
!CallbackTable::ReturnsVoid(masm->isolate(), function_address);
#if defined(__MINGW64__)
Register arguments_arg = rcx;
#elif defined(_WIN64)
// Win64 uses first register--rcx--for returned value.
Register arguments_arg = rdx;
Register arguments_arg = returns_handle ? rdx : rcx;
#else
Register arguments_arg = rdi;
#endif
......@@ -490,7 +500,7 @@ static void GenerateFastApiCall(MacroAssembler* masm,
// it's not controlled by GC.
const int kApiStackSpace = 4;
__ PrepareCallApiFunction(kApiStackSpace);
__ PrepareCallApiFunction(kApiStackSpace, returns_handle);
__ movq(StackSpaceOperand(0), rbx); // v8::Arguments::implicit_args_.
__ addq(rbx, Immediate(argc * kPointerSize));
......@@ -502,10 +512,10 @@ static void GenerateFastApiCall(MacroAssembler* masm,
// v8::InvocationCallback's argument.
__ lea(arguments_arg, StackSpaceOperand(0));
// Function address is a foreign pointer outside V8's heap.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ CallApiFunctionAndReturn(function_address,
argc + kFastApiCallArguments + 1);
argc + kFastApiCallArguments + 1,
returns_handle,
kFastApiCallArguments + 1);
}
......@@ -1288,18 +1298,24 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
} else {
__ Push(Handle<Object>(callback->data(), isolate()));
}
__ PushAddress(ExternalReference::isolate_address(isolate())); // isolate
__ PushAddress(ExternalReference::isolate_address(isolate()));
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
__ push(kScratchRegister); // return value
__ push(name()); // name
// Save a pointer to where we pushed the arguments pointer. This will be
// passed as the const ExecutableAccessorInfo& to the C++ callback.
Address getter_address = v8::ToCData<Address>(callback->getter());
bool returns_handle =
!CallbackTable::ReturnsVoid(isolate(), getter_address);
#if defined(__MINGW64__)
Register accessor_info_arg = rdx;
Register name_arg = rcx;
#elif defined(_WIN64)
// Win64 uses first register--rcx--for returned value.
Register accessor_info_arg = r8;
Register name_arg = rdx;
Register accessor_info_arg = returns_handle ? r8 : rdx;
Register name_arg = returns_handle ? rdx : rcx;
#else
Register accessor_info_arg = rsi;
Register name_arg = rdi;
......@@ -1309,14 +1325,15 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
__ movq(name_arg, rsp);
__ push(scratch2()); // Restore return address.
// 4 elements array for v8::Arguments::values_ and handler for name.
const int kStackSpace = 5;
// v8::Arguments::values_ and handler for name.
const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1;
// Allocate v8::AccessorInfo in non-GCed stack space.
const int kArgStackSpace = 1;
__ PrepareCallApiFunction(kArgStackSpace);
__ lea(rax, Operand(name_arg, 4 * kPointerSize));
__ PrepareCallApiFunction(kArgStackSpace, returns_handle);
STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 5);
__ lea(rax, Operand(name_arg, 5 * kPointerSize));
// v8::AccessorInfo::args_.
__ movq(StackSpaceOperand(0), rax);
......@@ -1325,8 +1342,10 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
// could be used to pass arguments.
__ lea(accessor_info_arg, StackSpaceOperand(0));
Address getter_address = v8::ToCData<Address>(callback->getter());
__ CallApiFunctionAndReturn(getter_address, kStackSpace);
__ CallApiFunctionAndReturn(getter_address,
kStackSpace,
returns_handle,
3);
}
......@@ -2272,7 +2291,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
name, depth, &miss);
// Move the return address on top of the stack.
__ movq(rax, Operand(rsp, 4 * kPointerSize));
__ movq(rax, Operand(rsp, kFastApiCallArguments * kPointerSize));
__ movq(Operand(rsp, 0 * kPointerSize), rax);
GenerateFastApiCall(masm(), optimization, argc);
......
This diff is collapsed.
......@@ -208,6 +208,7 @@
'../../src/api.cc',
'../../src/api.h',
'../../src/apiutils.h',
'../../src/arguments.cc',
'../../src/arguments.h',
'../../src/assembler.cc',
'../../src/assembler.h',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment