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
This commit is contained in:
dcarney@chromium.org 2013-05-21 06:36:24 +00:00
parent 45ec481659
commit 881476a7af
22 changed files with 1483 additions and 444 deletions

View File

@ -144,6 +144,17 @@ class Value;
template <class T> class Handle;
template <class T> class Local;
template <class T> class Persistent;
class FunctionTemplate;
class ObjectTemplate;
class Data;
class AccessorInfo;
template<typename T> class PropertyCallbackInfo;
class StackTrace;
class StackFrame;
class Isolate;
class DeclaredAccessorDescriptor;
class ObjectOperationDescriptor;
class RawOperationDescriptor;
namespace internal {
class Arguments;
@ -151,6 +162,10 @@ class Heap;
class HeapObject;
class Isolate;
class Object;
template<typename T>
class CustomArguments;
class PropertyCallbackArguments;
class FunctionCallbackArguments;
}
@ -1936,11 +1951,18 @@ enum ExternalArrayType {
*/
typedef Handle<Value> (*AccessorGetter)(Local<String> property,
const AccessorInfo& info);
typedef void (*AccessorGetterCallback)(
Local<String> property,
const PropertyCallbackInfo<Value>& info);
typedef void (*AccessorSetter)(Local<String> property,
Local<Value> value,
const AccessorInfo& info);
typedef void (*AccessorSetterCallback)(
Local<String> property,
Local<Value> value,
const PropertyCallbackInfo<void>& info);
/**
@ -2010,12 +2032,19 @@ class V8EXPORT Object : public Value {
bool Delete(uint32_t index);
// TODO(dcarney): deprecate
bool SetAccessor(Handle<String> name,
AccessorGetter getter,
AccessorSetter setter = 0,
Handle<Value> data = Handle<Value>(),
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None);
bool SetAccessor(Handle<String> name,
AccessorGetterCallback getter,
AccessorSetterCallback setter = 0,
Handle<Value> data = Handle<Value>(),
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None);
// This function is not yet stable and should not be used at this time.
bool SetAccessor(Handle<String> name,
@ -2704,13 +2733,36 @@ class V8EXPORT Template : public Data {
};
template<typename T>
class V8EXPORT ReturnValue {
public:
V8_INLINE(explicit ReturnValue(internal::Object** slot));
// Handle setters
V8_INLINE(void Set(const Persistent<T>& handle));
V8_INLINE(void Set(const Handle<T> handle));
// TODO(dcarney): implement
// Fast primitive setters
// V8_INLINE(void Set(Isolate* isolate, bool));
// V8_INLINE(void Set(Isolate* isolate, float i));
// V8_INLINE(void Set(Isolate* isolate, double i));
// V8_INLINE(void Set(Isolate* isolate, int32_t i));
// V8_INLINE(void Set(Isolate* isolate, uint32_t i));
// Fast JS primitive setters
// V8_INLINE(void SetNull(Isolate* isolate));
// V8_INLINE(void SetUndefined(Isolate* isolate));
private:
internal::Object** value_;
};
/**
* The argument information given to function call callbacks. This
* class provides access to information about the context of the call,
* including the receiver, the number and values of arguments, and
* the holder of the function.
*/
class V8EXPORT Arguments {
template<typename T>
class V8EXPORT FunctionCallbackInfo {
public:
V8_INLINE(int Length() const);
V8_INLINE(Local<Value> operator[](int i) const);
@ -2720,15 +2772,20 @@ class V8EXPORT Arguments {
V8_INLINE(bool IsConstructCall() const);
V8_INLINE(Local<Value> Data() const);
V8_INLINE(Isolate* GetIsolate() const);
V8_INLINE(ReturnValue<T> GetReturnValue() const);
// This shouldn't be public, but the arm compiler needs it.
static const int kArgsLength = 5;
private:
static const int kIsolateIndex = 0;
static const int kDataIndex = -1;
static const int kCalleeIndex = -2;
static const int kHolderIndex = -3;
protected:
friend class internal::FunctionCallbackArguments;
friend class internal::CustomArguments<FunctionCallbackInfo>;
static const int kReturnValueIndex = 0;
static const int kIsolateIndex = -1;
static const int kDataIndex = -2;
static const int kCalleeIndex = -3;
static const int kHolderIndex = -4;
friend class ImplementationUtilities;
V8_INLINE(Arguments(internal::Object** implicit_args,
V8_INLINE(FunctionCallbackInfo(internal::Object** implicit_args,
internal::Object** values,
int length,
bool is_construct_call));
@ -2739,25 +2796,56 @@ class V8EXPORT Arguments {
};
class V8EXPORT Arguments : public FunctionCallbackInfo<Value> {
private:
friend class internal::FunctionCallbackArguments;
V8_INLINE(Arguments(internal::Object** implicit_args,
internal::Object** values,
int length,
bool is_construct_call));
};
/**
* The information passed to an accessor callback about the context
* The information passed to a property callback about the context
* of the property access.
*/
class V8EXPORT AccessorInfo {
template<typename T>
class V8EXPORT PropertyCallbackInfo {
public:
V8_INLINE(AccessorInfo(internal::Object** args))
: args_(args) { }
V8_INLINE(Isolate* GetIsolate() const);
V8_INLINE(Local<Value> Data() const);
V8_INLINE(Local<Object> This() const);
V8_INLINE(Local<Object> Holder() const);
V8_INLINE(ReturnValue<T> GetReturnValue() const);
// This shouldn't be public, but the arm compiler needs it.
static const int kArgsLength = 5;
private:
protected:
friend class MacroAssembler;
friend class internal::PropertyCallbackArguments;
friend class internal::CustomArguments<PropertyCallbackInfo>;
static const int kThisIndex = 0;
static const int kHolderIndex = -1;
static const int kDataIndex = -2;
static const int kIsolateIndex = -3;
static const int kReturnValueIndex = -4;
V8_INLINE(PropertyCallbackInfo(internal::Object** args))
: args_(args) { }
internal::Object** args_;
};
class V8EXPORT AccessorInfo : public PropertyCallbackInfo<Value> {
private:
friend class internal::PropertyCallbackArguments;
V8_INLINE(AccessorInfo(internal::Object** args))
: PropertyCallbackInfo<Value>(args) { }
};
typedef Handle<Value> (*InvocationCallback)(const Arguments& args);
typedef void (*FunctionCallback)(const FunctionCallbackInfo<Value>& info);
/**
* NamedProperty[Getter|Setter] are used as interceptors on object.
@ -2765,6 +2853,9 @@ typedef Handle<Value> (*InvocationCallback)(const Arguments& args);
*/
typedef Handle<Value> (*NamedPropertyGetter)(Local<String> property,
const AccessorInfo& info);
typedef void (*NamedPropertyGetterCallback)(
Local<String> property,
const PropertyCallbackInfo<Value>& info);
/**
@ -2774,6 +2865,11 @@ typedef Handle<Value> (*NamedPropertyGetter)(Local<String> property,
typedef Handle<Value> (*NamedPropertySetter)(Local<String> property,
Local<Value> value,
const AccessorInfo& info);
typedef void (*NamedPropertySetterCallback)(
Local<String> property,
Local<Value> value,
const PropertyCallbackInfo<Value>& info);
/**
* Returns a non-empty handle if the interceptor intercepts the request.
@ -2782,6 +2878,9 @@ typedef Handle<Value> (*NamedPropertySetter)(Local<String> property,
*/
typedef Handle<Integer> (*NamedPropertyQuery)(Local<String> property,
const AccessorInfo& info);
typedef void (*NamedPropertyQueryCallback)(
Local<String> property,
const PropertyCallbackInfo<Integer>& info);
/**
@ -2791,12 +2890,18 @@ typedef Handle<Integer> (*NamedPropertyQuery)(Local<String> property,
*/
typedef Handle<Boolean> (*NamedPropertyDeleter)(Local<String> property,
const AccessorInfo& info);
typedef void (*NamedPropertyDeleterCallback)(
Local<String> property,
const PropertyCallbackInfo<Boolean>& info);
/**
* Returns an array containing the names of the properties the named
* property getter intercepts.
*/
typedef Handle<Array> (*NamedPropertyEnumerator)(const AccessorInfo& info);
typedef void (*NamedPropertyEnumeratorCallback)(
const PropertyCallbackInfo<Array>& info);
/**
@ -2805,6 +2910,9 @@ typedef Handle<Array> (*NamedPropertyEnumerator)(const AccessorInfo& info);
*/
typedef Handle<Value> (*IndexedPropertyGetter)(uint32_t index,
const AccessorInfo& info);
typedef void (*IndexedPropertyGetterCallback)(
uint32_t index,
const PropertyCallbackInfo<Value>& info);
/**
@ -2814,6 +2922,10 @@ typedef Handle<Value> (*IndexedPropertyGetter)(uint32_t index,
typedef Handle<Value> (*IndexedPropertySetter)(uint32_t index,
Local<Value> value,
const AccessorInfo& info);
typedef void (*IndexedPropertySetterCallback)(
uint32_t index,
Local<Value> value,
const PropertyCallbackInfo<Value>& info);
/**
@ -2822,6 +2934,10 @@ typedef Handle<Value> (*IndexedPropertySetter)(uint32_t index,
*/
typedef Handle<Integer> (*IndexedPropertyQuery)(uint32_t index,
const AccessorInfo& info);
typedef void (*IndexedPropertyQueryCallback)(
uint32_t index,
const PropertyCallbackInfo<Integer>& info);
/**
* Returns a non-empty handle if the deleter intercepts the request.
@ -2830,12 +2946,18 @@ typedef Handle<Integer> (*IndexedPropertyQuery)(uint32_t index,
*/
typedef Handle<Boolean> (*IndexedPropertyDeleter)(uint32_t index,
const AccessorInfo& info);
typedef void (*IndexedPropertyDeleterCallback)(
uint32_t index,
const PropertyCallbackInfo<Boolean>& info);
/**
* Returns an array containing the indices of the properties the
* indexed property getter intercepts.
*/
typedef Handle<Array> (*IndexedPropertyEnumerator)(const AccessorInfo& info);
typedef void (*IndexedPropertyEnumeratorCallback)(
const PropertyCallbackInfo<Array>& info);
/**
@ -2965,11 +3087,18 @@ typedef bool (*IndexedSecurityCallback)(Local<Object> host,
class V8EXPORT FunctionTemplate : public Template {
public:
/** Creates a function template.*/
// TODO(dcarney): deprecate
static Local<FunctionTemplate> New(
InvocationCallback callback = 0,
Handle<Value> data = Handle<Value>(),
Handle<Signature> signature = Handle<Signature>(),
int length = 0);
static Local<FunctionTemplate> New(
FunctionCallback callback, // TODO(dcarney): add back default param.
Handle<Value> data = Handle<Value>(),
Handle<Signature> signature = Handle<Signature>(),
int length = 0);
/** Returns the unique function instance in the current execution context.*/
Local<Function> GetFunction();
@ -2978,8 +3107,11 @@ class V8EXPORT FunctionTemplate : public Template {
* callback is called whenever the function created from this
* FunctionTemplate is called.
*/
// TODO(dcarney): deprecate
void SetCallHandler(InvocationCallback callback,
Handle<Value> data = Handle<Value>());
void SetCallHandler(FunctionCallback callback,
Handle<Value> data = Handle<Value>());
/** Set the predefined length property for the FunctionTemplate. */
void SetLength(int length);
@ -3031,21 +3163,6 @@ class V8EXPORT FunctionTemplate : public Template {
private:
FunctionTemplate();
void SetNamedInstancePropertyHandler(NamedPropertyGetter getter,
NamedPropertySetter setter,
NamedPropertyQuery query,
NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator,
Handle<Value> data);
void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter,
IndexedPropertySetter setter,
IndexedPropertyQuery query,
IndexedPropertyDeleter remover,
IndexedPropertyEnumerator enumerator,
Handle<Value> data);
void SetInstanceCallAsFunctionHandler(InvocationCallback callback,
Handle<Value> data);
friend class Context;
friend class ObjectTemplate;
};
@ -3094,6 +3211,7 @@ class V8EXPORT ObjectTemplate : public Template {
* defined by FunctionTemplate::HasInstance()), an implicit TypeError is
* thrown and no callback is invoked.
*/
// TODO(dcarney): deprecate
void SetAccessor(Handle<String> name,
AccessorGetter getter,
AccessorSetter setter = 0,
@ -3102,6 +3220,14 @@ class V8EXPORT ObjectTemplate : public Template {
PropertyAttribute attribute = None,
Handle<AccessorSignature> signature =
Handle<AccessorSignature>());
void SetAccessor(Handle<String> name,
AccessorGetterCallback getter,
AccessorSetterCallback setter = 0,
Handle<Value> data = Handle<Value>(),
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None,
Handle<AccessorSignature> signature =
Handle<AccessorSignature>());
// This function is not yet stable and should not be used at this time.
bool SetAccessor(Handle<String> name,
@ -3128,12 +3254,20 @@ class V8EXPORT ObjectTemplate : public Template {
* \param data A piece of data that will be passed to the callbacks
* whenever they are invoked.
*/
// TODO(dcarney): deprecate
void SetNamedPropertyHandler(NamedPropertyGetter getter,
NamedPropertySetter setter = 0,
NamedPropertyQuery query = 0,
NamedPropertyDeleter deleter = 0,
NamedPropertyEnumerator enumerator = 0,
Handle<Value> data = Handle<Value>());
void SetNamedPropertyHandler(
NamedPropertyGetterCallback getter,
NamedPropertySetterCallback setter = 0,
NamedPropertyQueryCallback query = 0,
NamedPropertyDeleterCallback deleter = 0,
NamedPropertyEnumeratorCallback enumerator = 0,
Handle<Value> data = Handle<Value>());
/**
* Sets an indexed property handler on the object template.
@ -3151,12 +3285,20 @@ class V8EXPORT ObjectTemplate : public Template {
* \param data A piece of data that will be passed to the callbacks
* whenever they are invoked.
*/
// TODO(dcarney): deprecate
void SetIndexedPropertyHandler(IndexedPropertyGetter getter,
IndexedPropertySetter setter = 0,
IndexedPropertyQuery query = 0,
IndexedPropertyDeleter deleter = 0,
IndexedPropertyEnumerator enumerator = 0,
Handle<Value> data = Handle<Value>());
void SetIndexedPropertyHandler(
IndexedPropertyGetterCallback getter,
IndexedPropertySetterCallback setter = 0,
IndexedPropertyQueryCallback query = 0,
IndexedPropertyDeleterCallback deleter = 0,
IndexedPropertyEnumeratorCallback enumerator = 0,
Handle<Value> data = Handle<Value>());
/**
* Sets the callback to be used when calling instances created from
@ -3164,8 +3306,11 @@ class V8EXPORT ObjectTemplate : public Template {
* behave like normal JavaScript objects that cannot be called as a
* function.
*/
// TODO(dcarney): deprecate
void SetCallAsFunctionHandler(InvocationCallback callback,
Handle<Value> data = Handle<Value>());
void SetCallAsFunctionHandler(FunctionCallback callback,
Handle<Value> data = Handle<Value>());
/**
* Mark object instances of the template as undetectable.
@ -5455,54 +5600,90 @@ uint16_t Persistent<T>::WrapperClassId(Isolate* isolate) const {
return *reinterpret_cast<uint16_t*>(addr);
}
Arguments::Arguments(internal::Object** implicit_args,
internal::Object** values, int length,
bool is_construct_call)
template<typename T>
ReturnValue<T>::ReturnValue(internal::Object** slot) : value_(slot) {}
template<typename T>
void ReturnValue<T>::Set(const Persistent<T>& handle) {
*value_ = *reinterpret_cast<internal::Object**>(*handle);
}
template<typename T>
void ReturnValue<T>::Set(const Handle<T> handle) {
*value_ = *reinterpret_cast<internal::Object**>(*handle);
}
template<typename T>
FunctionCallbackInfo<T>::FunctionCallbackInfo(internal::Object** implicit_args,
internal::Object** values,
int length,
bool is_construct_call)
: implicit_args_(implicit_args),
values_(values),
length_(length),
is_construct_call_(is_construct_call) { }
Local<Value> Arguments::operator[](int i) const {
Arguments::Arguments(internal::Object** args,
internal::Object** values,
int length,
bool is_construct_call)
: FunctionCallbackInfo<Value>(args, values, length, is_construct_call) { }
template<typename T>
Local<Value> FunctionCallbackInfo<T>::operator[](int i) const {
if (i < 0 || length_ <= i) return Local<Value>(*Undefined());
return Local<Value>(reinterpret_cast<Value*>(values_ - i));
}
Local<Function> Arguments::Callee() const {
template<typename T>
Local<Function> FunctionCallbackInfo<T>::Callee() const {
return Local<Function>(reinterpret_cast<Function*>(
&implicit_args_[kCalleeIndex]));
}
Local<Object> Arguments::This() const {
template<typename T>
Local<Object> FunctionCallbackInfo<T>::This() const {
return Local<Object>(reinterpret_cast<Object*>(values_ + 1));
}
Local<Object> Arguments::Holder() const {
template<typename T>
Local<Object> FunctionCallbackInfo<T>::Holder() const {
return Local<Object>(reinterpret_cast<Object*>(
&implicit_args_[kHolderIndex]));
}
Local<Value> Arguments::Data() const {
template<typename T>
Local<Value> FunctionCallbackInfo<T>::Data() const {
return Local<Value>(reinterpret_cast<Value*>(&implicit_args_[kDataIndex]));
}
Isolate* Arguments::GetIsolate() const {
template<typename T>
Isolate* FunctionCallbackInfo<T>::GetIsolate() const {
return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]);
}
bool Arguments::IsConstructCall() const {
template<typename T>
ReturnValue<T> FunctionCallbackInfo<T>::GetReturnValue() const {
return ReturnValue<T>(&implicit_args_[kReturnValueIndex]);
}
template<typename T>
bool FunctionCallbackInfo<T>::IsConstructCall() const {
return is_construct_call_;
}
int Arguments::Length() const {
template<typename T>
int FunctionCallbackInfo<T>::Length() const {
return length_;
}
@ -5891,23 +6072,33 @@ External* External::Cast(v8::Value* value) {
}
Isolate* AccessorInfo::GetIsolate() const {
return *reinterpret_cast<Isolate**>(&args_[-3]);
template<typename T>
Isolate* PropertyCallbackInfo<T>::GetIsolate() const {
return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
}
Local<Value> AccessorInfo::Data() const {
return Local<Value>(reinterpret_cast<Value*>(&args_[-2]));
template<typename T>
Local<Value> PropertyCallbackInfo<T>::Data() const {
return Local<Value>(reinterpret_cast<Value*>(&args_[kDataIndex]));
}
Local<Object> AccessorInfo::This() const {
return Local<Object>(reinterpret_cast<Object*>(&args_[0]));
template<typename T>
Local<Object> PropertyCallbackInfo<T>::This() const {
return Local<Object>(reinterpret_cast<Object*>(&args_[kThisIndex]));
}
Local<Object> AccessorInfo::Holder() const {
return Local<Object>(reinterpret_cast<Object*>(&args_[-1]));
template<typename T>
Local<Object> PropertyCallbackInfo<T>::Holder() const {
return Local<Object>(reinterpret_cast<Object*>(&args_[kHolderIndex]));
}
template<typename T>
ReturnValue<T> PropertyCallbackInfo<T>::GetReturnValue() const {
return ReturnValue<T>(&args_[kReturnValueIndex]);
}

View File

@ -983,8 +983,12 @@ void FunctionTemplate::Inherit(v8::Handle<FunctionTemplate> value) {
}
Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
v8::Handle<Value> data, v8::Handle<Signature> signature, int length) {
template<typename Callback>
static Local<FunctionTemplate> FunctionTemplateNew(
Callback callback_in,
v8::Handle<Value> data,
v8::Handle<Signature> signature,
int length) {
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::FunctionTemplate::New()");
LOG_API(isolate, "FunctionTemplate::New");
@ -997,8 +1001,10 @@ Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
int next_serial_number = isolate->next_serial_number();
isolate->set_next_serial_number(next_serial_number + 1);
obj->set_serial_number(i::Smi::FromInt(next_serial_number));
if (callback != 0) {
if (callback_in != 0) {
if (data.IsEmpty()) data = v8::Undefined();
InvocationCallback callback =
i::CallbackTable::Register(isolate, callback_in);
Utils::ToLocal(obj)->SetCallHandler(callback, data);
}
obj->set_length(length);
@ -1011,6 +1017,24 @@ Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
}
Local<FunctionTemplate> FunctionTemplate::New(
InvocationCallback callback,
v8::Handle<Value> data,
v8::Handle<Signature> signature,
int length) {
return FunctionTemplateNew(callback, data, signature, length);
}
Local<FunctionTemplate> FunctionTemplate::New(
FunctionCallback callback,
v8::Handle<Value> data,
v8::Handle<Signature> signature,
int length) {
return FunctionTemplateNew(callback, data, signature, length);
}
Local<Signature> Signature::New(Handle<FunctionTemplate> receiver,
int argc, Handle<FunctionTemplate> argv[]) {
i::Isolate* isolate = i::Isolate::Current();
@ -1202,9 +1226,11 @@ int TypeSwitch::match(v8::Handle<Value> value) {
} while (false)
void FunctionTemplate::SetCallHandler(InvocationCallback callback,
v8::Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
template<typename Callback>
static void FunctionTemplateSetCallHandler(FunctionTemplate* function_template,
Callback callback,
v8::Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(function_template)->GetIsolate();
if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetCallHandler()")) return;
ENTER_V8(isolate);
i::HandleScope scope(isolate);
@ -1215,9 +1241,18 @@ void FunctionTemplate::SetCallHandler(InvocationCallback callback,
SET_FIELD_WRAPPED(obj, set_callback, callback);
if (data.IsEmpty()) data = v8::Undefined();
obj->set_data(*Utils::OpenHandle(*data));
Utils::OpenHandle(this)->set_call_code(*obj);
Utils::OpenHandle(function_template)->set_call_code(*obj);
}
void FunctionTemplate::SetCallHandler(InvocationCallback callback,
v8::Handle<Value> data) {
FunctionTemplateSetCallHandler(this, callback, data);
}
void FunctionTemplate::SetCallHandler(FunctionCallback callback,
v8::Handle<Value> data) {
FunctionTemplateSetCallHandler(this, callback, data);
}
static i::Handle<i::AccessorInfo> SetAccessorInfoProperties(
i::Handle<i::AccessorInfo> obj,
@ -1237,10 +1272,11 @@ static i::Handle<i::AccessorInfo> SetAccessorInfoProperties(
}
template<typename Getter, typename Setter>
static i::Handle<i::AccessorInfo> MakeAccessorInfo(
v8::Handle<String> name,
AccessorGetter getter,
AccessorSetter setter,
Getter getter_in,
Setter setter_in,
v8::Handle<Value> data,
v8::AccessControl settings,
v8::PropertyAttribute attributes,
@ -1248,7 +1284,9 @@ static i::Handle<i::AccessorInfo> MakeAccessorInfo(
i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate();
i::Handle<i::ExecutableAccessorInfo> obj =
isolate->factory()->NewExecutableAccessorInfo();
AccessorGetter getter = i::CallbackTable::Register(isolate, getter_in);
SET_FIELD_WRAPPED(obj, set_getter, getter);
AccessorSetter setter = i::CallbackTable::Register(isolate, setter_in);
SET_FIELD_WRAPPED(obj, set_setter, setter);
if (data.IsEmpty()) data = v8::Undefined();
obj->set_data(*Utils::OpenHandle(*data));
@ -1259,6 +1297,8 @@ static i::Handle<i::AccessorInfo> MakeAccessorInfo(
static i::Handle<i::AccessorInfo> MakeAccessorInfo(
v8::Handle<String> name,
v8::Handle<v8::DeclaredAccessorDescriptor> descriptor,
void* setter_ignored,
void* data_ignored,
v8::AccessControl settings,
v8::PropertyAttribute attributes,
v8::Handle<AccessorSignature> signature) {
@ -1323,15 +1363,21 @@ void FunctionTemplate::ReadOnlyPrototype() {
Utils::OpenHandle(this)->set_read_only_prototype(true);
}
void FunctionTemplate::SetNamedInstancePropertyHandler(
NamedPropertyGetter getter,
NamedPropertySetter setter,
NamedPropertyQuery query,
NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator,
template<
typename Getter,
typename Setter,
typename Query,
typename Deleter,
typename Enumerator>
static void SetNamedInstancePropertyHandler(
i::Handle<i::FunctionTemplateInfo> function_template,
Getter getter_in,
Setter setter_in,
Query query_in,
Deleter remover_in,
Enumerator enumerator_in,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
i::Isolate* isolate = function_template->GetIsolate();
if (IsDeadCheck(isolate,
"v8::FunctionTemplate::SetNamedInstancePropertyHandler()")) {
return;
@ -1343,26 +1389,40 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
i::Handle<i::InterceptorInfo> obj =
i::Handle<i::InterceptorInfo>::cast(struct_obj);
NamedPropertyGetter getter = i::CallbackTable::Register(isolate, getter_in);
if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter);
NamedPropertySetter setter = i::CallbackTable::Register(isolate, setter_in);
if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter);
NamedPropertyQuery query = i::CallbackTable::Register(isolate, query_in);
if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
NamedPropertyDeleter remover =
i::CallbackTable::Register(isolate, remover_in);
if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
NamedPropertyEnumerator enumerator =
i::CallbackTable::Register(isolate, enumerator_in);
if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
if (data.IsEmpty()) data = v8::Undefined();
obj->set_data(*Utils::OpenHandle(*data));
Utils::OpenHandle(this)->set_named_property_handler(*obj);
function_template->set_named_property_handler(*obj);
}
void FunctionTemplate::SetIndexedInstancePropertyHandler(
IndexedPropertyGetter getter,
IndexedPropertySetter setter,
IndexedPropertyQuery query,
IndexedPropertyDeleter remover,
IndexedPropertyEnumerator enumerator,
template<
typename Getter,
typename Setter,
typename Query,
typename Deleter,
typename Enumerator>
static void SetIndexedInstancePropertyHandler(
i::Handle<i::FunctionTemplateInfo> function_template,
Getter getter_in,
Setter setter_in,
Query query_in,
Deleter remover_in,
Enumerator enumerator_in,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
i::Isolate* isolate = function_template->GetIsolate();
if (IsDeadCheck(isolate,
"v8::FunctionTemplate::SetIndexedInstancePropertyHandler()")) {
return;
@ -1374,22 +1434,33 @@ void FunctionTemplate::SetIndexedInstancePropertyHandler(
i::Handle<i::InterceptorInfo> obj =
i::Handle<i::InterceptorInfo>::cast(struct_obj);
IndexedPropertyGetter getter =
i::CallbackTable::Register(isolate, getter_in);
if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter);
IndexedPropertySetter setter =
i::CallbackTable::Register(isolate, setter_in);
if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter);
IndexedPropertyQuery query = i::CallbackTable::Register(isolate, query_in);
if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
IndexedPropertyDeleter remover =
i::CallbackTable::Register(isolate, remover_in);
if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
IndexedPropertyEnumerator enumerator =
i::CallbackTable::Register(isolate, enumerator_in);
if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
if (data.IsEmpty()) data = v8::Undefined();
obj->set_data(*Utils::OpenHandle(*data));
Utils::OpenHandle(this)->set_indexed_property_handler(*obj);
function_template->set_indexed_property_handler(*obj);
}
void FunctionTemplate::SetInstanceCallAsFunctionHandler(
InvocationCallback callback,
template<typename Callback>
static void SetInstanceCallAsFunctionHandler(
i::Handle<i::FunctionTemplateInfo> function_template,
Callback callback_in,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
i::Isolate* isolate = function_template->GetIsolate();
if (IsDeadCheck(isolate,
"v8::FunctionTemplate::SetInstanceCallAsFunctionHandler()")) {
return;
@ -1400,10 +1471,12 @@ void FunctionTemplate::SetInstanceCallAsFunctionHandler(
isolate->factory()->NewStruct(i::CALL_HANDLER_INFO_TYPE);
i::Handle<i::CallHandlerInfo> obj =
i::Handle<i::CallHandlerInfo>::cast(struct_obj);
InvocationCallback callback =
i::CallbackTable::Register(isolate, callback_in);
SET_FIELD_WRAPPED(obj, set_callback, callback);
if (data.IsEmpty()) data = v8::Undefined();
obj->set_data(*Utils::OpenHandle(*data));
Utils::OpenHandle(this)->set_instance_call_handler(*obj);
function_template->set_instance_call_handler(*obj);
}
@ -1461,6 +1534,32 @@ static inline void AddPropertyToFunctionTemplate(
}
template<typename Setter, typename Getter, typename Data>
static bool ObjectTemplateSetAccessor(
ObjectTemplate* object_template,
v8::Handle<String> name,
Getter getter,
Setter setter,
Data data,
AccessControl settings,
PropertyAttribute attribute,
v8::Handle<AccessorSignature> signature) {
i::Isolate* isolate = Utils::OpenHandle(object_template)->GetIsolate();
if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessor()")) return false;
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(object_template);
i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
Utils::OpenHandle(object_template)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(
name, getter, setter, data, settings, attribute, signature);
if (obj.is_null()) return false;
AddPropertyToFunctionTemplate(cons, obj);
return true;
}
void ObjectTemplate::SetAccessor(v8::Handle<String> name,
AccessorGetter getter,
AccessorSetter setter,
@ -1468,18 +1567,20 @@ void ObjectTemplate::SetAccessor(v8::Handle<String> name,
AccessControl settings,
PropertyAttribute attribute,
v8::Handle<AccessorSignature> signature) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessor()")) return;
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(name, getter, setter, data,
settings, attribute,
signature);
AddPropertyToFunctionTemplate(cons, obj);
ObjectTemplateSetAccessor(
this, name, getter, setter, data, settings, attribute, signature);
}
void ObjectTemplate::SetAccessor(v8::Handle<String> name,
AccessorGetterCallback getter,
AccessorSetterCallback setter,
v8::Handle<Value> data,
AccessControl settings,
PropertyAttribute attribute,
v8::Handle<AccessorSignature> signature) {
ObjectTemplateSetAccessor(
this, name, getter, setter, data, settings, attribute, signature);
}
@ -1488,44 +1589,67 @@ bool ObjectTemplate::SetAccessor(Handle<String> name,
AccessControl settings,
PropertyAttribute attribute,
Handle<AccessorSignature> signature) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessor()")) return false;
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(
name, descriptor, settings, attribute, signature);
if (obj.is_null()) return false;
AddPropertyToFunctionTemplate(cons, obj);
return true;
void* null = NULL;
return ObjectTemplateSetAccessor(
this, name, descriptor, null, null, settings, attribute, signature);
}
void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter,
NamedPropertySetter setter,
NamedPropertyQuery query,
NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
template<
typename Getter,
typename Setter,
typename Query,
typename Deleter,
typename Enumerator>
static void ObjectTemplateSetNamedPropertyHandler(
ObjectTemplate* object_template,
Getter getter,
Setter setter,
Query query,
Deleter remover,
Enumerator enumerator,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(object_template)->GetIsolate();
if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetNamedPropertyHandler()")) {
return;
}
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
EnsureConstructor(object_template);
i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
Utils::OpenHandle(object_template)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
Utils::ToLocal(cons)->SetNamedInstancePropertyHandler(getter,
setter,
query,
remover,
enumerator,
data);
SetNamedInstancePropertyHandler(cons,
getter,
setter,
query,
remover,
enumerator,
data);
}
void ObjectTemplate::SetNamedPropertyHandler(
NamedPropertyGetter getter,
NamedPropertySetter setter,
NamedPropertyQuery query,
NamedPropertyDeleter remover,
NamedPropertyEnumerator enumerator,
Handle<Value> data) {
ObjectTemplateSetNamedPropertyHandler(
this, getter, setter, query, remover, enumerator, data);
}
void ObjectTemplate::SetNamedPropertyHandler(
NamedPropertyGetterCallback getter,
NamedPropertySetterCallback setter,
NamedPropertyQueryCallback query,
NamedPropertyDeleterCallback remover,
NamedPropertyEnumeratorCallback enumerator,
Handle<Value> data) {
ObjectTemplateSetNamedPropertyHandler(
this, getter, setter, query, remover, enumerator, data);
}
@ -1574,6 +1698,40 @@ void ObjectTemplate::SetAccessCheckCallbacks(
}
template<
typename Getter,
typename Setter,
typename Query,
typename Deleter,
typename Enumerator>
void ObjectTemplateSetIndexedPropertyHandler(
ObjectTemplate* object_template,
Getter getter,
Setter setter,
Query query,
Deleter remover,
Enumerator enumerator,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(object_template)->GetIsolate();
if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetIndexedPropertyHandler()")) {
return;
}
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(object_template);
i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
Utils::OpenHandle(object_template)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
SetIndexedInstancePropertyHandler(cons,
getter,
setter,
query,
remover,
enumerator,
data);
}
void ObjectTemplate::SetIndexedPropertyHandler(
IndexedPropertyGetter getter,
IndexedPropertySetter setter,
@ -1581,39 +1739,52 @@ void ObjectTemplate::SetIndexedPropertyHandler(
IndexedPropertyDeleter remover,
IndexedPropertyEnumerator enumerator,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetIndexedPropertyHandler()")) {
return;
}
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
Utils::ToLocal(cons)->SetIndexedInstancePropertyHandler(getter,
setter,
query,
remover,
enumerator,
data);
ObjectTemplateSetIndexedPropertyHandler(
this, getter, setter, query, remover, enumerator, data);
}
void ObjectTemplate::SetCallAsFunctionHandler(InvocationCallback callback,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
void ObjectTemplate::SetIndexedPropertyHandler(
IndexedPropertyGetterCallback getter,
IndexedPropertySetterCallback setter,
IndexedPropertyQueryCallback query,
IndexedPropertyDeleterCallback remover,
IndexedPropertyEnumeratorCallback enumerator,
Handle<Value> data) {
ObjectTemplateSetIndexedPropertyHandler(
this, getter, setter, query, remover, enumerator, data);
}
template<typename Callback>
static void ObjectTemplateSetCallAsFunctionHandler(
ObjectTemplate* object_template,
Callback callback,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(object_template)->GetIsolate();
if (IsDeadCheck(isolate,
"v8::ObjectTemplate::SetCallAsFunctionHandler()")) {
return;
}
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
EnsureConstructor(object_template);
i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
Utils::OpenHandle(object_template)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
Utils::ToLocal(cons)->SetInstanceCallAsFunctionHandler(callback, data);
SetInstanceCallAsFunctionHandler(cons, callback, data);
}
void ObjectTemplate::SetCallAsFunctionHandler(InvocationCallback callback,
Handle<Value> data) {
return ObjectTemplateSetCallAsFunctionHandler(this, callback, data);
}
void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback,
Handle<Value> data) {
return ObjectTemplateSetCallAsFunctionHandler(this, callback, data);
}
@ -3446,7 +3617,21 @@ bool v8::Object::Has(uint32_t index) {
}
static inline bool SetAccessor(Object* obj, i::Handle<i::AccessorInfo> info) {
template<typename Setter, typename Getter, typename Data>
static inline bool ObjectSetAccessor(Object* obj,
Handle<String> name,
Setter getter,
Getter setter,
Data data,
AccessControl settings,
PropertyAttribute attributes) {
i::Isolate* isolate = Utils::OpenHandle(obj)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::SetAccessor()", return false);
ENTER_V8(isolate);
i::HandleScope scope(isolate);
v8::Handle<AccessorSignature> signature;
i::Handle<i::AccessorInfo> info = MakeAccessorInfo(
name, getter, setter, data, settings, attributes, signature);
if (info.is_null()) return false;
bool fast = Utils::OpenHandle(obj)->HasFastProperties();
i::Handle<i::Object> result = i::SetAccessor(Utils::OpenHandle(obj), info);
@ -3462,15 +3647,19 @@ bool Object::SetAccessor(Handle<String> name,
v8::Handle<Value> data,
AccessControl settings,
PropertyAttribute attributes) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::SetAccessor()", return false);
ENTER_V8(isolate);
i::HandleScope scope(isolate);
v8::Handle<AccessorSignature> signature;
i::Handle<i::AccessorInfo> info = MakeAccessorInfo(name, getter, setter, data,
settings, attributes,
signature);
return v8::SetAccessor(this, info);
return ObjectSetAccessor(
this, name, getter, setter, data, settings, attributes);
}
bool Object::SetAccessor(Handle<String> name,
AccessorGetterCallback getter,
AccessorSetterCallback setter,
v8::Handle<Value> data,
AccessControl settings,
PropertyAttribute attributes) {
return ObjectSetAccessor(
this, name, getter, setter, data, settings, attributes);
}
@ -3478,14 +3667,9 @@ bool Object::SetAccessor(Handle<String> name,
Handle<DeclaredAccessorDescriptor> descriptor,
AccessControl settings,
PropertyAttribute attributes) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::SetAccessor()", return false);
ENTER_V8(isolate);
i::HandleScope scope(isolate);
v8::Handle<AccessorSignature> signature;
i::Handle<i::AccessorInfo> info = MakeAccessorInfo(
name, descriptor, settings, attributes, signature);
return v8::SetAccessor(this, info);
void* null = NULL;
return ObjectSetAccessor(
this, name, descriptor, null, null, settings, attributes);
}

View File

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

195
src/arguments.cc Normal file
View File

@ -0,0 +1,195 @@
// 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

View File

@ -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:
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);
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:
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);
}
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
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());
}
void IterateInstance(ObjectVisitor* v);
Object** end() { return values_ + ARRAY_SIZE(values_) - 1; }
/*
* 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;
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());
}
/*
* 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_;
};

View File

@ -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;
Label return_value_loaded;
// 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);
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));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
__ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_.
__ add(eax, Immediate(argc * kPointerSize));
__ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_.
__ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_.
// v8::Arguments::is_construct_call_.
__ Set(ApiParameterOperand(4), Immediate(0));
// v8::InvocationCallback's argument.
__ lea(eax, ApiParameterOperand(1));
__ mov(ApiParameterOperand(0), eax);
// 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);
// v8::Arguments::implicit_args_.
__ mov(ApiParameterOperand(1, returns_handle), eax);
__ add(eax, Immediate(argc * kPointerSize));
// 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, returns_handle), Immediate(0));
// v8::InvocationCallback's argument.
__ lea(eax, ApiParameterOperand(1, returns_handle));
__ mov(ApiParameterOperand(0, returns_handle), eax);
__ 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

View File

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

View File

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

View File

@ -339,13 +339,12 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
JSObject* self = JSObject::cast(receiver);
Handle<String> key(String::cast(name));
LOG(isolate, ApiNamedPropertyAccess("load", self, name));
CustomArguments args(isolate, data->data(), self, this);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments args(isolate, data->data(), self, this);
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = call_fun(v8::Utils::ToLocal(key), info);
result = args.Call(call_fun, v8::Utils::ToLocal(key));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (result.IsEmpty()) {
@ -2640,8 +2639,7 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
if (!interceptor->setter()->IsUndefined()) {
LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
CustomArguments args(isolate, interceptor->data(), this, this);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
v8::NamedPropertySetter setter =
v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
v8::Handle<v8::Value> result;
@ -2652,9 +2650,9 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
isolate->heap()->undefined_value() :
value,
isolate);
result = setter(v8::Utils::ToLocal(name_handle),
v8::Utils::ToLocal(value_unhole),
info);
result = args.Call(setter,
v8::Utils::ToLocal(name_handle),
v8::Utils::ToLocal(value_unhole));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) return *value_handle;
@ -2754,14 +2752,14 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
if (call_fun == NULL) return value;
Handle<String> key(String::cast(name));
LOG(isolate, ApiNamedPropertyAccess("store", this, name));
CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
v8::AccessorInfo info(args.end());
PropertyCallbackArguments
args(isolate, data->data(), this, JSObject::cast(holder));
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
call_fun(v8::Utils::ToLocal(key),
v8::Utils::ToLocal(value_handle),
info);
args.Call(call_fun,
v8::Utils::ToLocal(key),
v8::Utils::ToLocal(value_handle));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return *value_handle;
@ -4063,8 +4061,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
Handle<JSObject> receiver_handle(receiver);
Handle<JSObject> holder_handle(this);
Handle<String> name_handle(String::cast(name));
CustomArguments args(isolate, interceptor->data(), receiver, this);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this);
if (!interceptor->query()->IsUndefined()) {
v8::NamedPropertyQuery query =
v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
@ -4074,7 +4071,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = query(v8::Utils::ToLocal(name_handle), info);
result = args.Call(query, v8::Utils::ToLocal(name_handle));
}
if (!result.IsEmpty()) {
ASSERT(result->IsInt32());
@ -4089,7 +4086,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = getter(v8::Utils::ToLocal(name_handle), info);
result = args.Call(getter, v8::Utils::ToLocal(name_handle));
}
if (!result.IsEmpty()) return DONT_ENUM;
}
@ -4204,8 +4201,7 @@ PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Handle<JSReceiver> hreceiver(receiver);
Handle<JSObject> holder(this);
CustomArguments args(isolate, interceptor->data(), receiver, this);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this);
if (!interceptor->query()->IsUndefined()) {
v8::IndexedPropertyQuery query =
v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
@ -4215,7 +4211,7 @@ PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = query(index, info);
result = args.Call(query, index);
}
if (!result.IsEmpty())
return static_cast<PropertyAttributes>(result->Int32Value());
@ -4228,7 +4224,7 @@ PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = getter(index, info);
result = args.Call(getter, index);
}
if (!result.IsEmpty()) return NONE;
}
@ -4892,13 +4888,12 @@ MaybeObject* JSObject::DeletePropertyWithInterceptor(Name* name) {
v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
LOG(isolate,
ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
CustomArguments args(isolate, interceptor->data(), this, this);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
v8::Handle<v8::Boolean> result;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = deleter(v8::Utils::ToLocal(name_handle), info);
result = args.Call(deleter, v8::Utils::ToLocal(name_handle));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) {
@ -4929,13 +4924,12 @@ MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Handle<JSObject> this_handle(this);
LOG(isolate,
ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
CustomArguments args(isolate, interceptor->data(), this, this);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
v8::Handle<v8::Boolean> result;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = deleter(index, info);
result = args.Call(deleter, index);
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) {
@ -11132,13 +11126,12 @@ MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
LOG(isolate,
ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
CustomArguments args(isolate, interceptor->data(), this, this);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = setter(index, v8::Utils::ToLocal(value_handle), info);
result = args.Call(setter, index, v8::Utils::ToLocal(value_handle));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) return *value_handle;
@ -11175,13 +11168,13 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Handle<String> key = isolate->factory()->NumberToString(number);
LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
CustomArguments args(isolate, data->data(), *self, *holder_handle);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments
args(isolate, data->data(), *self, *holder_handle);
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = call_fun(v8::Utils::ToLocal(key), info);
result = args.Call(call_fun, v8::Utils::ToLocal(key));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (result.IsEmpty()) return isolate->heap()->undefined_value();
@ -11242,14 +11235,14 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure,
Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Handle<String> key(isolate->factory()->NumberToString(number));
LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
CustomArguments args(isolate, data->data(), *self, *holder_handle);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments
args(isolate, data->data(), *self, *holder_handle);
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
call_fun(v8::Utils::ToLocal(key),
v8::Utils::ToLocal(value_handle),
info);
args.Call(call_fun,
v8::Utils::ToLocal(key),
v8::Utils::ToLocal(value_handle));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return *value_handle;
@ -12133,13 +12126,13 @@ MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
LOG(isolate,
ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
CustomArguments args(isolate, interceptor->data(), receiver, this);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments
args(isolate, interceptor->data(), receiver, this);
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = getter(index, info);
result = args.Call(getter, index);
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) {
@ -12443,13 +12436,13 @@ MaybeObject* JSObject::GetPropertyWithInterceptor(
v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
LOG(isolate,
ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
CustomArguments args(isolate, interceptor->data(), receiver, this);
v8::AccessorInfo info(args.end());
PropertyCallbackArguments
args(isolate, interceptor->data(), receiver, this);
v8::Handle<v8::Value> result;
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
result = getter(v8::Utils::ToLocal(name_handle), info);
result = args.Call(getter, v8::Utils::ToLocal(name_handle));
}
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (!result.IsEmpty()) {

View File

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

View File

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

View File

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

View File

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

View File

@ -805,63 +805,208 @@ THREADED_TEST(GlobalProperties) {
}
template<typename T>
static void CheckReturnValue(const T& t) {
v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
i::Object** o = *reinterpret_cast<i::Object***>(&rv);
CHECK_EQ(t.GetIsolate(), v8::Isolate::GetCurrent());
CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
}
static v8::Handle<Value> handle_call(const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(args);
args.GetReturnValue().Set(v8_str("bad value"));
return v8_num(102);
}
static v8::Handle<Value> handle_call_indirect(const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(args);
args.GetReturnValue().Set(v8_str("bad value"));
args.GetReturnValue().Set(v8_num(102));
return v8::Handle<Value>();
}
static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(info);
info.GetReturnValue().Set(v8_str("bad value"));
info.GetReturnValue().Set(v8_num(102));
}
static v8::Handle<Value> construct_call(const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(args);
args.This()->Set(v8_str("x"), v8_num(1));
args.This()->Set(v8_str("y"), v8_num(2));
args.GetReturnValue().Set(v8_str("bad value"));
return args.This();
}
static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
static v8::Handle<Value> construct_call_indirect(const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
return v8_num(239);
CheckReturnValue(args);
args.This()->Set(v8_str("x"), v8_num(1));
args.This()->Set(v8_str("y"), v8_num(2));
args.GetReturnValue().Set(v8_str("bad value"));
args.GetReturnValue().Set(args.This());
return v8::Handle<Value>();
}
static void construct_callback(
const v8::FunctionCallbackInfo<Value>& info) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(info);
info.This()->Set(v8_str("x"), v8_num(1));
info.This()->Set(v8_str("y"), v8_num(2));
info.GetReturnValue().Set(v8_str("bad value"));
info.GetReturnValue().Set(info.This());
}
THREADED_TEST(FunctionTemplate) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
static v8::Handle<Value> Return239(
Local<String> name, const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(info);
info.GetReturnValue().Set(v8_str("bad value"));
return v8_num(239);
}
static v8::Handle<Value> Return239Indirect(
Local<String> name, const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(info);
Handle<Value> value = v8_num(239);
info.GetReturnValue().Set(v8_str("bad value"));
info.GetReturnValue().Set(value);
return v8::Handle<Value>();
}
static void Return239Callback(
Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(info);
info.GetReturnValue().Set(v8_str("bad value"));
info.GetReturnValue().Set(v8_num(239));
}
template<typename Handler>
static void TestFunctionTemplateInitializer(Handler handler) {
// Test constructor calls.
{
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
Local<v8::FunctionTemplate> fun_templ =
v8::FunctionTemplate::New(handle_call);
v8::FunctionTemplate::New(handler);
Local<Function> fun = fun_templ->GetFunction();
env->Global()->Set(v8_str("obj"), fun);
Local<Script> script = v8_compile("obj()");
CHECK_EQ(102, script->Run()->Int32Value());
for (int i = 0; i < 30; i++) {
CHECK_EQ(102, script->Run()->Int32Value());
}
}
// Use SetCallHandler to initialize a function template, should work like the
// previous one.
{
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
fun_templ->SetCallHandler(handle_call);
fun_templ->SetCallHandler(handler);
Local<Function> fun = fun_templ->GetFunction();
env->Global()->Set(v8_str("obj"), fun);
Local<Script> script = v8_compile("obj()");
CHECK_EQ(102, script->Run()->Int32Value());
for (int i = 0; i < 30; i++) {
CHECK_EQ(102, script->Run()->Int32Value());
}
}
// Test constructor calls.
{
Local<v8::FunctionTemplate> fun_templ =
v8::FunctionTemplate::New(construct_call);
fun_templ->SetClassName(v8_str("funky"));
fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
Local<Function> fun = fun_templ->GetFunction();
env->Global()->Set(v8_str("obj"), fun);
Local<Script> script = v8_compile("var s = new obj(); s.x");
}
template<typename Constructor, typename Accessor>
static void TestFunctionTemplateAccessor(Constructor constructor,
Accessor accessor) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
Local<v8::FunctionTemplate> fun_templ =
v8::FunctionTemplate::New(constructor);
fun_templ->SetClassName(v8_str("funky"));
fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
Local<Function> fun = fun_templ->GetFunction();
env->Global()->Set(v8_str("obj"), fun);
Local<Value> result = v8_compile("(new obj()).toString()")->Run();
CHECK_EQ(v8_str("[object funky]"), result);
CompileRun("var obj_instance = new obj();");
Local<Script> script;
script = v8_compile("obj_instance.x");
for (int i = 0; i < 30; i++) {
CHECK_EQ(1, script->Run()->Int32Value());
Local<Value> result = v8_compile("(new obj()).toString()")->Run();
CHECK_EQ(v8_str("[object funky]"), result);
result = v8_compile("(new obj()).m")->Run();
CHECK_EQ(239, result->Int32Value());
}
script = v8_compile("obj_instance.m");
for (int i = 0; i < 30; i++) {
CHECK_EQ(239, script->Run()->Int32Value());
}
}
THREADED_TEST(FunctionTemplate) {
TestFunctionTemplateInitializer(handle_call);
TestFunctionTemplateInitializer(handle_call_indirect);
TestFunctionTemplateInitializer(handle_callback);
TestFunctionTemplateAccessor(construct_call, Return239);
TestFunctionTemplateAccessor(construct_call_indirect, Return239Indirect);
TestFunctionTemplateAccessor(construct_callback, Return239Callback);
}
static v8::Handle<v8::Value> SimpleDirectCallback(const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(args);
args.GetReturnValue().Set(v8_str("bad value"));
return v8_num(51423 + args.Length());
}
static v8::Handle<v8::Value> SimpleIndirectCallback(const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(args);
args.GetReturnValue().Set(v8_num(51423 + args.Length()));
return v8::Handle<v8::Value>();
}
static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(info);
info.GetReturnValue().Set(v8_num(51423 + info.Length()));
}
template<typename Callback>
static void TestSimpleCallback(Callback callback) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
object_template->Set("callback", v8::FunctionTemplate::New(callback));
v8::Local<v8::Object> object = object_template->NewInstance();
(*env)->Global()->Set(v8_str("callback_object"), object);
v8::Handle<v8::Script> script;
script = v8_compile("callback_object.callback(17)");
for (int i = 0; i < 30; i++) {
CHECK_EQ(51424, script->Run()->Int32Value());
}
script = v8_compile("callback_object.callback(17, 24)");
for (int i = 0; i < 30; i++) {
CHECK_EQ(51425, script->Run()->Int32Value());
}
}
THREADED_TEST(SimpleCallback) {
TestSimpleCallback(SimpleDirectCallback);
TestSimpleCallback(SimpleIndirectCallback);
TestSimpleCallback(SimpleCallback);
}
@ -4649,7 +4794,10 @@ THREADED_TEST(SetterOnly) {
THREADED_TEST(NoAccessors) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->SetAccessor(v8_str("x"), NULL, NULL, v8_str("donut"));
templ->SetAccessor(v8_str("x"),
static_cast<v8::AccessorGetter>(NULL),
NULL,
v8_str("donut"));
LocalContext context;
context->Global()->Set(v8_str("obj"), templ->NewInstance());
Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
@ -5308,8 +5456,7 @@ THREADED_TEST(UndetectableObject) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
Local<v8::FunctionTemplate> desc =
v8::FunctionTemplate::New(0, v8::Handle<Value>());
Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
Local<v8::Object> obj = desc->GetFunction()->NewInstance();
@ -5352,8 +5499,7 @@ THREADED_TEST(VoidLiteral) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
Local<v8::FunctionTemplate> desc =
v8::FunctionTemplate::New(0, v8::Handle<Value>());
Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
Local<v8::Object> obj = desc->GetFunction()->NewInstance();
@ -5396,8 +5542,7 @@ THREADED_TEST(ExtensibleOnUndetectable) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
Local<v8::FunctionTemplate> desc =
v8::FunctionTemplate::New(0, v8::Handle<Value>());
Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
Local<v8::Object> obj = desc->GetFunction()->NewInstance();
@ -10398,6 +10543,7 @@ THREADED_TEST(InterceptorCallICCachedFromGlobal) {
static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(info);
int* call_count =
reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
++(*call_count);
@ -10410,6 +10556,7 @@ static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
static v8::Handle<Value> FastApiCallback_TrivialSignature(
const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(args);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
CHECK_EQ(isolate, args.GetIsolate());
CHECK_EQ(args.This(), args.Holder());
@ -10420,6 +10567,7 @@ static v8::Handle<Value> FastApiCallback_TrivialSignature(
static v8::Handle<Value> FastApiCallback_SimpleSignature(
const v8::Arguments& args) {
ApiTestFuzzer::Fuzz();
CheckReturnValue(args);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
CHECK_EQ(isolate, args.GetIsolate());
CHECK_EQ(args.This()->GetPrototype(), args.Holder());
@ -10497,29 +10645,59 @@ THREADED_TEST(CallICFastApi_DirectCall_Throw) {
}
v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
const v8::AccessorInfo& info) {
static Handle<Value> DoDirectGetter() {
if (++p_getter_count % 3 == 0) {
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
GenerateSomeGarbage();
}
return v8_str("Direct Getter Result");
}
static v8::Handle<v8::Value> DirectGetter(Local<String> name,
const v8::AccessorInfo& info) {
CheckReturnValue(info);
info.GetReturnValue().Set(v8_str("Garbage"));
return DoDirectGetter();
}
static v8::Handle<v8::Value> DirectGetterIndirect(
Local<String> name,
const v8::AccessorInfo& info) {
CheckReturnValue(info);
info.GetReturnValue().Set(DoDirectGetter());
return v8::Handle<v8::Value>();
}
static void DirectGetterCallback(
Local<String> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
CheckReturnValue(info);
info.GetReturnValue().Set(DoDirectGetter());
}
THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
template<typename Accessor>
static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
obj->SetAccessor(v8_str("p1"), accessor);
context->Global()->Set(v8_str("o1"), obj->NewInstance());
p_getter_count = 0;
CompileRun(
v8::Handle<v8::Value> result = CompileRun(
"function f() {"
" for (var i = 0; i < 30; i++) o1.p1;"
" return o1.p1"
"}"
"f();");
CHECK_EQ(30, p_getter_count);
CHECK_EQ(v8_str("Direct Getter Result"), result);
CHECK_EQ(31, p_getter_count);
}
THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
LoadICFastApi_DirectCall_GCMoveStub(DirectGetterIndirect);
LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
LoadICFastApi_DirectCall_GCMoveStub(DirectGetter);
}
@ -11198,7 +11376,7 @@ THREADED_TEST(InterceptorICSetterExceptions) {
THREADED_TEST(NullNamedInterceptor) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
templ->SetNamedPropertyHandler(0);
templ->SetNamedPropertyHandler(static_cast<v8::NamedPropertyGetter>(0));
LocalContext context;
templ->Set("x", v8_num(42));
v8::Handle<v8::Object> obj = templ->NewInstance();
@ -11213,7 +11391,7 @@ THREADED_TEST(NullNamedInterceptor) {
THREADED_TEST(NullIndexedInterceptor) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
templ->SetIndexedPropertyHandler(0);
templ->SetIndexedPropertyHandler(static_cast<v8::IndexedPropertyGetter>(0));
LocalContext context;
templ->Set("42", v8_num(42));
v8::Handle<v8::Object> obj = templ->NewInstance();

View File

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