From: dcarney@chromium.org Date: Tue, 21 May 2013 06:36:24 +0000 (+0000) Subject: new style of property/function callbacks X-Git-Tag: upstream/4.7.83~14193 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=881476a7afec14b5ef03f8ff6400849af3cfe632;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/include/v8.h b/include/v8.h index 96a1d8b..19a8ad8 100644 --- a/include/v8.h +++ b/include/v8.h @@ -144,6 +144,17 @@ class Value; template class Handle; template class Local; template class Persistent; +class FunctionTemplate; +class ObjectTemplate; +class Data; +class AccessorInfo; +template 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 +class CustomArguments; +class PropertyCallbackArguments; +class FunctionCallbackArguments; } @@ -1936,11 +1951,18 @@ enum ExternalArrayType { */ typedef Handle (*AccessorGetter)(Local property, const AccessorInfo& info); +typedef void (*AccessorGetterCallback)( + Local property, + const PropertyCallbackInfo& info); typedef void (*AccessorSetter)(Local property, Local value, const AccessorInfo& info); +typedef void (*AccessorSetterCallback)( + Local property, + Local value, + const PropertyCallbackInfo& info); /** @@ -2010,12 +2032,19 @@ class V8EXPORT Object : public Value { bool Delete(uint32_t index); + // TODO(dcarney): deprecate bool SetAccessor(Handle name, AccessorGetter getter, AccessorSetter setter = 0, Handle data = Handle(), AccessControl settings = DEFAULT, PropertyAttribute attribute = None); + bool SetAccessor(Handle name, + AccessorGetterCallback getter, + AccessorSetterCallback setter = 0, + Handle data = Handle(), + AccessControl settings = DEFAULT, + PropertyAttribute attribute = None); // This function is not yet stable and should not be used at this time. bool SetAccessor(Handle name, @@ -2704,13 +2733,36 @@ class V8EXPORT Template : public Data { }; +template +class V8EXPORT ReturnValue { + public: + V8_INLINE(explicit ReturnValue(internal::Object** slot)); + // Handle setters + V8_INLINE(void Set(const Persistent& handle)); + V8_INLINE(void Set(const Handle 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 +class V8EXPORT FunctionCallbackInfo { public: V8_INLINE(int Length() const); V8_INLINE(Local operator[](int i) const); @@ -2720,15 +2772,20 @@ class V8EXPORT Arguments { V8_INLINE(bool IsConstructCall() const); V8_INLINE(Local Data() const); V8_INLINE(Isolate* GetIsolate() const); + V8_INLINE(ReturnValue 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; - - friend class ImplementationUtilities; - V8_INLINE(Arguments(internal::Object** implicit_args, + protected: + friend class internal::FunctionCallbackArguments; + friend class internal::CustomArguments; + 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; + + 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 { + 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 +class V8EXPORT PropertyCallbackInfo { public: - V8_INLINE(AccessorInfo(internal::Object** args)) - : args_(args) { } V8_INLINE(Isolate* GetIsolate() const); V8_INLINE(Local Data() const); V8_INLINE(Local This() const); V8_INLINE(Local Holder() const); + V8_INLINE(ReturnValue 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; + 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 { + private: + friend class internal::PropertyCallbackArguments; + V8_INLINE(AccessorInfo(internal::Object** args)) + : PropertyCallbackInfo(args) { } +}; + + typedef Handle (*InvocationCallback)(const Arguments& args); +typedef void (*FunctionCallback)(const FunctionCallbackInfo& info); /** * NamedProperty[Getter|Setter] are used as interceptors on object. @@ -2765,6 +2853,9 @@ typedef Handle (*InvocationCallback)(const Arguments& args); */ typedef Handle (*NamedPropertyGetter)(Local property, const AccessorInfo& info); +typedef void (*NamedPropertyGetterCallback)( + Local property, + const PropertyCallbackInfo& info); /** @@ -2774,6 +2865,11 @@ typedef Handle (*NamedPropertyGetter)(Local property, typedef Handle (*NamedPropertySetter)(Local property, Local value, const AccessorInfo& info); +typedef void (*NamedPropertySetterCallback)( + Local property, + Local value, + const PropertyCallbackInfo& info); + /** * Returns a non-empty handle if the interceptor intercepts the request. @@ -2782,6 +2878,9 @@ typedef Handle (*NamedPropertySetter)(Local property, */ typedef Handle (*NamedPropertyQuery)(Local property, const AccessorInfo& info); +typedef void (*NamedPropertyQueryCallback)( + Local property, + const PropertyCallbackInfo& info); /** @@ -2791,12 +2890,18 @@ typedef Handle (*NamedPropertyQuery)(Local property, */ typedef Handle (*NamedPropertyDeleter)(Local property, const AccessorInfo& info); +typedef void (*NamedPropertyDeleterCallback)( + Local property, + const PropertyCallbackInfo& info); + /** * Returns an array containing the names of the properties the named * property getter intercepts. */ typedef Handle (*NamedPropertyEnumerator)(const AccessorInfo& info); +typedef void (*NamedPropertyEnumeratorCallback)( + const PropertyCallbackInfo& info); /** @@ -2805,6 +2910,9 @@ typedef Handle (*NamedPropertyEnumerator)(const AccessorInfo& info); */ typedef Handle (*IndexedPropertyGetter)(uint32_t index, const AccessorInfo& info); +typedef void (*IndexedPropertyGetterCallback)( + uint32_t index, + const PropertyCallbackInfo& info); /** @@ -2814,6 +2922,10 @@ typedef Handle (*IndexedPropertyGetter)(uint32_t index, typedef Handle (*IndexedPropertySetter)(uint32_t index, Local value, const AccessorInfo& info); +typedef void (*IndexedPropertySetterCallback)( + uint32_t index, + Local value, + const PropertyCallbackInfo& info); /** @@ -2822,6 +2934,10 @@ typedef Handle (*IndexedPropertySetter)(uint32_t index, */ typedef Handle (*IndexedPropertyQuery)(uint32_t index, const AccessorInfo& info); +typedef void (*IndexedPropertyQueryCallback)( + uint32_t index, + const PropertyCallbackInfo& info); + /** * Returns a non-empty handle if the deleter intercepts the request. @@ -2830,12 +2946,18 @@ typedef Handle (*IndexedPropertyQuery)(uint32_t index, */ typedef Handle (*IndexedPropertyDeleter)(uint32_t index, const AccessorInfo& info); +typedef void (*IndexedPropertyDeleterCallback)( + uint32_t index, + const PropertyCallbackInfo& info); + /** * Returns an array containing the indices of the properties the * indexed property getter intercepts. */ typedef Handle (*IndexedPropertyEnumerator)(const AccessorInfo& info); +typedef void (*IndexedPropertyEnumeratorCallback)( + const PropertyCallbackInfo& info); /** @@ -2965,11 +3087,18 @@ typedef bool (*IndexedSecurityCallback)(Local host, class V8EXPORT FunctionTemplate : public Template { public: /** Creates a function template.*/ + // TODO(dcarney): deprecate static Local New( InvocationCallback callback = 0, Handle data = Handle(), Handle signature = Handle(), int length = 0); + static Local New( + FunctionCallback callback, // TODO(dcarney): add back default param. + Handle data = Handle(), + Handle signature = Handle(), + int length = 0); + /** Returns the unique function instance in the current execution context.*/ Local 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 data = Handle()); + void SetCallHandler(FunctionCallback callback, + Handle data = Handle()); /** 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 data); - void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter, - IndexedPropertySetter setter, - IndexedPropertyQuery query, - IndexedPropertyDeleter remover, - IndexedPropertyEnumerator enumerator, - Handle data); - void SetInstanceCallAsFunctionHandler(InvocationCallback callback, - Handle 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 name, AccessorGetter getter, AccessorSetter setter = 0, @@ -3102,6 +3220,14 @@ class V8EXPORT ObjectTemplate : public Template { PropertyAttribute attribute = None, Handle signature = Handle()); + void SetAccessor(Handle name, + AccessorGetterCallback getter, + AccessorSetterCallback setter = 0, + Handle data = Handle(), + AccessControl settings = DEFAULT, + PropertyAttribute attribute = None, + Handle signature = + Handle()); // This function is not yet stable and should not be used at this time. bool SetAccessor(Handle 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 data = Handle()); + void SetNamedPropertyHandler( + NamedPropertyGetterCallback getter, + NamedPropertySetterCallback setter = 0, + NamedPropertyQueryCallback query = 0, + NamedPropertyDeleterCallback deleter = 0, + NamedPropertyEnumeratorCallback enumerator = 0, + Handle data = Handle()); /** * 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 data = Handle()); + void SetIndexedPropertyHandler( + IndexedPropertyGetterCallback getter, + IndexedPropertySetterCallback setter = 0, + IndexedPropertyQueryCallback query = 0, + IndexedPropertyDeleterCallback deleter = 0, + IndexedPropertyEnumeratorCallback enumerator = 0, + Handle data = Handle()); /** * 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 data = Handle()); + void SetCallAsFunctionHandler(FunctionCallback callback, + Handle data = Handle()); /** * Mark object instances of the template as undetectable. @@ -5455,54 +5600,90 @@ uint16_t Persistent::WrapperClassId(Isolate* isolate) const { return *reinterpret_cast(addr); } -Arguments::Arguments(internal::Object** implicit_args, - internal::Object** values, int length, - bool is_construct_call) +template +ReturnValue::ReturnValue(internal::Object** slot) : value_(slot) {} + +template +void ReturnValue::Set(const Persistent& handle) { + *value_ = *reinterpret_cast(*handle); +} + +template +void ReturnValue::Set(const Handle handle) { + *value_ = *reinterpret_cast(*handle); +} + +template +FunctionCallbackInfo::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 Arguments::operator[](int i) const { +Arguments::Arguments(internal::Object** args, + internal::Object** values, + int length, + bool is_construct_call) + : FunctionCallbackInfo(args, values, length, is_construct_call) { } + + +template +Local FunctionCallbackInfo::operator[](int i) const { if (i < 0 || length_ <= i) return Local(*Undefined()); return Local(reinterpret_cast(values_ - i)); } -Local Arguments::Callee() const { +template +Local FunctionCallbackInfo::Callee() const { return Local(reinterpret_cast( &implicit_args_[kCalleeIndex])); } -Local Arguments::This() const { +template +Local FunctionCallbackInfo::This() const { return Local(reinterpret_cast(values_ + 1)); } -Local Arguments::Holder() const { +template +Local FunctionCallbackInfo::Holder() const { return Local(reinterpret_cast( &implicit_args_[kHolderIndex])); } -Local Arguments::Data() const { +template +Local FunctionCallbackInfo::Data() const { return Local(reinterpret_cast(&implicit_args_[kDataIndex])); } -Isolate* Arguments::GetIsolate() const { +template +Isolate* FunctionCallbackInfo::GetIsolate() const { return *reinterpret_cast(&implicit_args_[kIsolateIndex]); } -bool Arguments::IsConstructCall() const { +template +ReturnValue FunctionCallbackInfo::GetReturnValue() const { + return ReturnValue(&implicit_args_[kReturnValueIndex]); +} + + +template +bool FunctionCallbackInfo::IsConstructCall() const { return is_construct_call_; } -int Arguments::Length() const { +template +int FunctionCallbackInfo::Length() const { return length_; } @@ -5891,23 +6072,33 @@ External* External::Cast(v8::Value* value) { } -Isolate* AccessorInfo::GetIsolate() const { - return *reinterpret_cast(&args_[-3]); +template +Isolate* PropertyCallbackInfo::GetIsolate() const { + return *reinterpret_cast(&args_[kIsolateIndex]); +} + + +template +Local PropertyCallbackInfo::Data() const { + return Local(reinterpret_cast(&args_[kDataIndex])); } -Local AccessorInfo::Data() const { - return Local(reinterpret_cast(&args_[-2])); +template +Local PropertyCallbackInfo::This() const { + return Local(reinterpret_cast(&args_[kThisIndex])); } -Local AccessorInfo::This() const { - return Local(reinterpret_cast(&args_[0])); +template +Local PropertyCallbackInfo::Holder() const { + return Local(reinterpret_cast(&args_[kHolderIndex])); } -Local AccessorInfo::Holder() const { - return Local(reinterpret_cast(&args_[-1])); +template +ReturnValue PropertyCallbackInfo::GetReturnValue() const { + return ReturnValue(&args_[kReturnValueIndex]); } diff --git a/src/api.cc b/src/api.cc index f0505cd..ccf3822 100644 --- a/src/api.cc +++ b/src/api.cc @@ -983,8 +983,12 @@ void FunctionTemplate::Inherit(v8::Handle value) { } -Local FunctionTemplate::New(InvocationCallback callback, - v8::Handle data, v8::Handle signature, int length) { +template +static Local FunctionTemplateNew( + Callback callback_in, + v8::Handle data, + v8::Handle 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::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::New(InvocationCallback callback, } +Local FunctionTemplate::New( + InvocationCallback callback, + v8::Handle data, + v8::Handle signature, + int length) { + return FunctionTemplateNew(callback, data, signature, length); +} + + +Local FunctionTemplate::New( + FunctionCallback callback, + v8::Handle data, + v8::Handle signature, + int length) { + return FunctionTemplateNew(callback, data, signature, length); +} + + Local Signature::New(Handle receiver, int argc, Handle argv[]) { i::Isolate* isolate = i::Isolate::Current(); @@ -1202,9 +1226,11 @@ int TypeSwitch::match(v8::Handle value) { } while (false) -void FunctionTemplate::SetCallHandler(InvocationCallback callback, - v8::Handle data) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); +template +static void FunctionTemplateSetCallHandler(FunctionTemplate* function_template, + Callback callback, + v8::Handle 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 data) { + FunctionTemplateSetCallHandler(this, callback, data); +} + +void FunctionTemplate::SetCallHandler(FunctionCallback callback, + v8::Handle data) { + FunctionTemplateSetCallHandler(this, callback, data); +} static i::Handle SetAccessorInfoProperties( i::Handle obj, @@ -1237,10 +1272,11 @@ static i::Handle SetAccessorInfoProperties( } +template static i::Handle MakeAccessorInfo( v8::Handle name, - AccessorGetter getter, - AccessorSetter setter, + Getter getter_in, + Setter setter_in, v8::Handle data, v8::AccessControl settings, v8::PropertyAttribute attributes, @@ -1248,7 +1284,9 @@ static i::Handle MakeAccessorInfo( i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate(); i::Handle 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 MakeAccessorInfo( static i::Handle MakeAccessorInfo( v8::Handle name, v8::Handle descriptor, + void* setter_ignored, + void* data_ignored, v8::AccessControl settings, v8::PropertyAttribute attributes, v8::Handle 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 function_template, + Getter getter_in, + Setter setter_in, + Query query_in, + Deleter remover_in, + Enumerator enumerator_in, Handle 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 obj = i::Handle::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); -} - - -void FunctionTemplate::SetIndexedInstancePropertyHandler( - IndexedPropertyGetter getter, - IndexedPropertySetter setter, - IndexedPropertyQuery query, - IndexedPropertyDeleter remover, - IndexedPropertyEnumerator enumerator, + function_template->set_named_property_handler(*obj); +} + + +template< + typename Getter, + typename Setter, + typename Query, + typename Deleter, + typename Enumerator> +static void SetIndexedInstancePropertyHandler( + i::Handle function_template, + Getter getter_in, + Setter setter_in, + Query query_in, + Deleter remover_in, + Enumerator enumerator_in, Handle 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 obj = i::Handle::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 +static void SetInstanceCallAsFunctionHandler( + i::Handle function_template, + Callback callback_in, Handle 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 obj = i::Handle::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 +static bool ObjectTemplateSetAccessor( + ObjectTemplate* object_template, + v8::Handle name, + Getter getter, + Setter setter, + Data data, + AccessControl settings, + PropertyAttribute attribute, + v8::Handle 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 cons(constructor); + i::Handle 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 name, AccessorGetter getter, AccessorSetter setter, @@ -1468,64 +1567,89 @@ void ObjectTemplate::SetAccessor(v8::Handle name, AccessControl settings, PropertyAttribute attribute, v8::Handle 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 cons(constructor); - i::Handle obj = MakeAccessorInfo(name, getter, setter, data, - settings, attribute, - signature); - AddPropertyToFunctionTemplate(cons, obj); + ObjectTemplateSetAccessor( + this, name, getter, setter, data, settings, attribute, signature); } -bool ObjectTemplate::SetAccessor(Handle name, - Handle descriptor, +void ObjectTemplate::SetAccessor(v8::Handle name, + AccessorGetterCallback getter, + AccessorSetterCallback setter, + v8::Handle data, AccessControl settings, PropertyAttribute attribute, - Handle 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 cons(constructor); - i::Handle obj = MakeAccessorInfo( - name, descriptor, settings, attribute, signature); - if (obj.is_null()) return false; - AddPropertyToFunctionTemplate(cons, obj); - return true; + v8::Handle signature) { + ObjectTemplateSetAccessor( + this, name, getter, setter, data, settings, attribute, signature); } -void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter, - NamedPropertySetter setter, - NamedPropertyQuery query, - NamedPropertyDeleter remover, - NamedPropertyEnumerator enumerator, - Handle data) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); +bool ObjectTemplate::SetAccessor(Handle name, + Handle descriptor, + AccessControl settings, + PropertyAttribute attribute, + Handle signature) { + void* null = NULL; + return ObjectTemplateSetAccessor( + this, name, descriptor, null, null, settings, attribute, signature); +} + + +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 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 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 data) { + ObjectTemplateSetNamedPropertyHandler( + this, getter, setter, query, remover, enumerator, data); +} + + +void ObjectTemplate::SetNamedPropertyHandler( + NamedPropertyGetterCallback getter, + NamedPropertySetterCallback setter, + NamedPropertyQueryCallback query, + NamedPropertyDeleterCallback remover, + NamedPropertyEnumeratorCallback enumerator, + Handle data) { + ObjectTemplateSetNamedPropertyHandler( + this, getter, setter, query, remover, enumerator, data); } @@ -1574,46 +1698,93 @@ void ObjectTemplate::SetAccessCheckCallbacks( } -void ObjectTemplate::SetIndexedPropertyHandler( - IndexedPropertyGetter getter, - IndexedPropertySetter setter, - IndexedPropertyQuery query, - IndexedPropertyDeleter remover, - IndexedPropertyEnumerator enumerator, +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 data) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + i::Isolate* isolate = Utils::OpenHandle(object_template)->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()); + EnsureConstructor(object_template); + i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast( + Utils::OpenHandle(object_template)->constructor()); i::Handle cons(constructor); - Utils::ToLocal(cons)->SetIndexedInstancePropertyHandler(getter, - setter, - query, - remover, - enumerator, - data); + SetIndexedInstancePropertyHandler(cons, + getter, + setter, + query, + remover, + enumerator, + data); } -void ObjectTemplate::SetCallAsFunctionHandler(InvocationCallback callback, - Handle data) { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); +void ObjectTemplate::SetIndexedPropertyHandler( + IndexedPropertyGetter getter, + IndexedPropertySetter setter, + IndexedPropertyQuery query, + IndexedPropertyDeleter remover, + IndexedPropertyEnumerator enumerator, + Handle data) { + ObjectTemplateSetIndexedPropertyHandler( + this, getter, setter, query, remover, enumerator, data); +} + + +void ObjectTemplate::SetIndexedPropertyHandler( + IndexedPropertyGetterCallback getter, + IndexedPropertySetterCallback setter, + IndexedPropertyQueryCallback query, + IndexedPropertyDeleterCallback remover, + IndexedPropertyEnumeratorCallback enumerator, + Handle data) { + ObjectTemplateSetIndexedPropertyHandler( + this, getter, setter, query, remover, enumerator, data); +} + + +template +static void ObjectTemplateSetCallAsFunctionHandler( + ObjectTemplate* object_template, + Callback callback, + Handle 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 cons(constructor); - Utils::ToLocal(cons)->SetInstanceCallAsFunctionHandler(callback, data); + SetInstanceCallAsFunctionHandler(cons, callback, data); +} + + +void ObjectTemplate::SetCallAsFunctionHandler(InvocationCallback callback, + Handle data) { + return ObjectTemplateSetCallAsFunctionHandler(this, callback, data); +} + + +void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback, + Handle 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 info) { +template +static inline bool ObjectSetAccessor(Object* obj, + Handle 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 signature; + i::Handle info = MakeAccessorInfo( + name, getter, setter, data, settings, attributes, signature); if (info.is_null()) return false; bool fast = Utils::OpenHandle(obj)->HasFastProperties(); i::Handle result = i::SetAccessor(Utils::OpenHandle(obj), info); @@ -3462,15 +3647,19 @@ bool Object::SetAccessor(Handle name, v8::Handle 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 signature; - i::Handle 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 name, + AccessorGetterCallback getter, + AccessorSetterCallback setter, + v8::Handle data, + AccessControl settings, + PropertyAttribute attributes) { + return ObjectSetAccessor( + this, name, getter, setter, data, settings, attributes); } @@ -3478,14 +3667,9 @@ bool Object::SetAccessor(Handle name, Handle 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 signature; - i::Handle info = MakeAccessorInfo( - name, descriptor, settings, attributes, signature); - return v8::SetAccessor(this, info); + void* null = NULL; + return ObjectSetAccessor( + this, name, descriptor, null, null, settings, attributes); } diff --git a/src/apiutils.h b/src/apiutils.h index 9831f08..0765585 100644 --- a/src/apiutils.h +++ b/src/apiutils.h @@ -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(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; diff --git a/src/arguments.cc b/src/arguments.cc new file mode 100644 index 0000000..091d0b9 --- /dev/null +++ b/src/arguments.cc @@ -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(function); + if (sizeof(function) == 4) return static_cast(as_int); + uint64_t as_64 = static_cast(as_int); + return + static_cast(as_64 >> 32) ^ + static_cast(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 +template +v8::Handle CustomArguments::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(); + return v8::Handle(reinterpret_cast(handle)); +} + + +v8::Handle 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(f); + FunctionCallbackInfo info(end(), + argv_, + argc_, + is_construct_call_); + c(info); + } else { + v8::Arguments args(end(), + argv_, + argc_, + is_construct_call_); + v8::Handle return_value = f(args); + if (!return_value.IsEmpty()) return return_value; + } + return GetReturnValue(isolate); +} + + +#define WRITE_CALL_0(OldFunction, NewFunction, ReturnValue) \ +v8::Handle 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(f); \ + PropertyCallbackInfo info(end()); \ + c(info); \ + } else { \ + v8::AccessorInfo info(end()); \ + v8::Handle return_value = f(info); \ + if (!return_value.IsEmpty()) return return_value; \ + } \ + return GetReturnValue(isolate); \ +} + +#define WRITE_CALL_1(OldFunction, NewFunction, ReturnValue, Arg1) \ +v8::Handle 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(f); \ + PropertyCallbackInfo info(end()); \ + c(arg1, info); \ + } else { \ + v8::AccessorInfo info(end()); \ + v8::Handle return_value = f(arg1, info); \ + if (!return_value.IsEmpty()) return return_value; \ + } \ + return GetReturnValue(isolate); \ +} + +#define WRITE_CALL_2(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \ +v8::Handle 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(f); \ + PropertyCallbackInfo info(end()); \ + c(arg1, arg2, info); \ + } else { \ + v8::AccessorInfo info(end()); \ + v8::Handle return_value = f(arg1, arg2, info); \ + if (!return_value.IsEmpty()) return return_value; \ + } \ + return GetReturnValue(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(f); \ + PropertyCallbackInfo 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 + diff --git a/src/arguments.h b/src/arguments.h index 1423d56..a80b613 100644 --- a/src/arguments.h +++ b/src/arguments.h @@ -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) \ + F(NamedPropertyQuery, \ + NamedPropertyQueryCallback, \ + v8::Integer, \ + v8::Local) \ + F(NamedPropertyDeleter, \ + NamedPropertyDeleterCallback, \ + v8::Boolean, \ + v8::Local) \ + 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::Local) \ + F(IndexedPropertySetter, \ + IndexedPropertySetterCallback, \ + v8::Value, \ + uint32_t, \ + v8::Local) \ + +#define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \ + F(AccessorSetter, \ + AccessorSetterCallback, \ + void, \ + v8::Local, \ + v8::Local) \ + +// 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 + static inline void* FunctionToVoidPtr(F function) { + return reinterpret_cast(reinterpret_cast(function)); + } + +#define WRITE_REGISTER(OldFunction, NewFunction) \ + static OldFunction Register(Isolate* isolate, NewFunction f) { \ + InsertCallback(isolate, FunctionToVoidPtr(f), true); \ + return reinterpret_cast(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 +class CustomArgumentsBase : public Relocatable { + public: + virtual inline void IterateInstance(ObjectVisitor* v) { + v->VisitPointers(values_, values_ + kArrayLength); + } + protected: + inline Object** end() { return values_ + kArrayLength - 1; } + explicit inline CustomArgumentsBase(Isolate* isolate) + : Relocatable(isolate) {} + Object* values_[kArrayLength]; +}; + + +template +class CustomArguments : public CustomArgumentsBase { public: - inline CustomArguments(Isolate* isolate, - Object* data, - Object* self, - JSObject* holder) : Relocatable(isolate) { - ASSERT(reinterpret_cast(isolate)->IsSmi()); - values_[3] = self; - values_[2] = holder; - values_[1] = data; - values_[0] = reinterpret_cast(isolate); + static const int kReturnValueOffset = T::kReturnValueIndex; + + typedef CustomArgumentsBase Super; + ~CustomArguments() { + // TODO(dcarney): create a new zap value for this. + this->end()[kReturnValueOffset] = + reinterpret_cast(kHandleZapValue); + } + + protected: + explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {} + + template + v8::Handle GetReturnValue(Isolate* isolate); + + inline Isolate* isolate() { + return reinterpret_cast(this->end()[T::kIsolateIndex]); } +}; + + +class PropertyCallbackArguments + : public CustomArguments > { + public: + typedef PropertyCallbackInfo T; + typedef CustomArguments 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(isolate); + values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); + ASSERT(values[T::kHolderIndex]->IsHeapObject()); + ASSERT(values[T::kIsolateIndex]->IsSmi()); + } + + /* + * The following Call functions wrap the calling of all callbacks to handle + * calling either the old or the new style callbacks depending on which one + * has been registered. + * For old callbacks which return an empty handle, the ReturnValue is checked + * and used if it's been set to anything inside the callback. + * New style callbacks always use the return value. + */ +#define WRITE_CALL_0(OldFunction, NewFunction, ReturnValue) \ + v8::Handle Call(OldFunction f); \ + +#define WRITE_CALL_1(OldFunction, NewFunction, ReturnValue, Arg1) \ + v8::Handle Call(OldFunction f, Arg1 arg1); \ + +#define WRITE_CALL_2(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \ + v8::Handle 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 > { + public: + typedef FunctionCallbackInfo T; + typedef CustomArguments Super; + static const int kArgsLength = T::kArgsLength; - inline explicit CustomArguments(Isolate* isolate) : Relocatable(isolate) { -#ifdef DEBUG - for (size_t i = 0; i < ARRAY_SIZE(values_); i++) { - values_[i] = reinterpret_cast(kZapValue); - } -#endif + FunctionCallbackArguments(internal::Isolate* isolate, + internal::Object* data, + internal::JSFunction* callee, + internal::Object* holder, + internal::Object** argv, + int argc, + bool is_construct_call) + : Super(isolate), + argv_(argv), + argc_(argc), + is_construct_call_(is_construct_call) { + Object** values = end(); + values[T::kDataIndex] = data; + values[T::kCalleeIndex] = callee; + values[T::kHolderIndex] = holder; + values[T::kIsolateIndex] = reinterpret_cast(isolate); + values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); + ASSERT(values[T::kCalleeIndex]->IsJSFunction()); + ASSERT(values[T::kHolderIndex]->IsHeapObject()); + ASSERT(values[T::kIsolateIndex]->IsSmi()); } - void IterateInstance(ObjectVisitor* v); - Object** end() { return values_ + ARRAY_SIZE(values_) - 1; } + /* + * The following Call function wraps the calling of all callbacks to handle + * calling either the old or the new style callbacks depending on which one + * has been registered. + * For old callbacks which return an empty handle, the ReturnValue is checked + * and used if it's been set to anything inside the callback. + * New style callbacks always use the return value. + */ + v8::Handle Call(InvocationCallback f); private: - Object* values_[4]; + internal::Object** argv_; + int argc_; + bool is_construct_call_; }; diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index ae5978a..a3b21a2 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -2262,7 +2262,9 @@ static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, - int stack_space) { + int stack_space, + bool returns_handle, + int return_value_offset) { ExternalReference next_address = ExternalReference::handle_scope_next_address(isolate()); const int kNextOffset = 0; @@ -2308,13 +2310,20 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, Label promote_scheduled_exception; Label delete_allocated_handles; Label leave_exit_frame; - - // If result is non-zero, dereference to get the result value - // otherwise set it to undefined. - cmp(r0, Operand::Zero()); - LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); - ldr(r0, MemOperand(r0), ne); - + Label return_value_loaded; + + if (returns_handle) { + Label load_return_value; + cmp(r0, Operand::Zero()); + b(eq, &load_return_value); + // derefernce returned value + ldr(r0, MemOperand(r0)); + b(&return_value_loaded); + bind(&load_return_value); + } + // load value from ReturnValue + ldr(r0, MemOperand(fp, return_value_offset*kPointerSize)); + bind(&return_value_loaded); // No more valid handles (the result handle was the last one). Restore // previous handle scope. str(r4, MemOperand(r7, kNextOffset)); diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 9a6d930..50f53b3 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -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); diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 40b3313..86eb0db 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -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 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
(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 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
(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); } diff --git a/src/builtins.cc b/src/builtins.cc index add59eb..81b6005 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -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 value; { @@ -1333,7 +1331,7 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper( VMState state(isolate); ExternalCallbackScope call_scope(isolate, v8::ToCData
(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 value; { // Leaving JavaScript. VMState state(isolate); ExternalCallbackScope call_scope(isolate, v8::ToCData
(callback_obj)); - value = callback(new_args); + value = custom.Call(callback); } if (value.IsEmpty()) { result = heap->undefined_value(); diff --git a/src/handles.cc b/src/handles.cc index 5a5773e..7a8d5c9 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -545,19 +545,14 @@ int GetScriptLineNumberSafe(Handle