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;
class HeapObject;
class Isolate;
class Object;
+template<typename T>
+class CustomArguments;
+class PropertyCallbackArguments;
+class FunctionCallbackArguments;
}
*/
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);
/**
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,
};
+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);
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;
-
- friend class ImplementationUtilities;
- V8_INLINE(Arguments(internal::Object** implicit_args,
+ 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;
+
+ V8_INLINE(FunctionCallbackInfo(internal::Object** implicit_args,
internal::Object** values,
int length,
bool is_construct_call));
};
+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.
*/
typedef Handle<Value> (*NamedPropertyGetter)(Local<String> property,
const AccessorInfo& info);
+typedef void (*NamedPropertyGetterCallback)(
+ Local<String> property,
+ const PropertyCallbackInfo<Value>& info);
/**
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.
*/
typedef Handle<Integer> (*NamedPropertyQuery)(Local<String> property,
const AccessorInfo& info);
+typedef void (*NamedPropertyQueryCallback)(
+ Local<String> property,
+ const PropertyCallbackInfo<Integer>& info);
/**
*/
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);
/**
*/
typedef Handle<Value> (*IndexedPropertyGetter)(uint32_t index,
const AccessorInfo& info);
+typedef void (*IndexedPropertyGetterCallback)(
+ uint32_t index,
+ const PropertyCallbackInfo<Value>& info);
/**
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);
/**
*/
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.
*/
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);
/**
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();
* 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);
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;
};
* 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,
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,
* \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.
* \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
* 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.
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_;
}
}
-Isolate* AccessorInfo::GetIsolate() const {
- return *reinterpret_cast<Isolate**>(&args_[-3]);
+template<typename T>
+Isolate* PropertyCallbackInfo<T>::GetIsolate() const {
+ return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
+}
+
+
+template<typename T>
+Local<Value> PropertyCallbackInfo<T>::Data() const {
+ return Local<Value>(reinterpret_cast<Value*>(&args_[kDataIndex]));
}
-Local<Value> AccessorInfo::Data() const {
- return Local<Value>(reinterpret_cast<Value*>(&args_[-2]));
+template<typename T>
+Local<Object> PropertyCallbackInfo<T>::This() const {
+ return Local<Object>(reinterpret_cast<Object*>(&args_[kThisIndex]));
}
-Local<Object> AccessorInfo::This() const {
- return Local<Object>(reinterpret_cast<Object*>(&args_[0]));
+template<typename T>
+Local<Object> PropertyCallbackInfo<T>::Holder() const {
+ return Local<Object>(reinterpret_cast<Object*>(&args_[kHolderIndex]));
}
-Local<Object> AccessorInfo::Holder() const {
- return Local<Object>(reinterpret_cast<Object*>(&args_[-1]));
+template<typename T>
+ReturnValue<T> PropertyCallbackInfo<T>::GetReturnValue() const {
+ return ReturnValue<T>(&args_[kReturnValueIndex]);
}
}
-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");
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);
}
+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();
} 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);
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,
}
+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,
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));
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) {
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;
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);
-}
-
-
-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<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;
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;
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);
}
}
+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,
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);
}
-bool ObjectTemplate::SetAccessor(Handle<String> name,
- Handle<DeclaredAccessorDescriptor> descriptor,
+void ObjectTemplate::SetAccessor(v8::Handle<String> name,
+ AccessorGetterCallback getter,
+ AccessorSetterCallback setter,
+ v8::Handle<Value> data,
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;
+ v8::Handle<AccessorSignature> signature) {
+ ObjectTemplateSetAccessor(
+ this, name, getter, setter, data, 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();
+bool ObjectTemplate::SetAccessor(Handle<String> name,
+ Handle<DeclaredAccessorDescriptor> descriptor,
+ AccessControl settings,
+ PropertyAttribute attribute,
+ Handle<AccessorSignature> 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<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);
}
}
-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<Value> 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<i::FunctionTemplateInfo> 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<Value> data) {
- i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+void ObjectTemplate::SetIndexedPropertyHandler(
+ IndexedPropertyGetter getter,
+ IndexedPropertySetter setter,
+ IndexedPropertyQuery query,
+ IndexedPropertyDeleter remover,
+ IndexedPropertyEnumerator enumerator,
+ Handle<Value> data) {
+ ObjectTemplateSetIndexedPropertyHandler(
+ this, getter, setter, query, remover, enumerator, data);
+}
+
+
+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);
}
}
-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);
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);
}
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);
}
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;
--- /dev/null
+// 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
+
};
+// mappings from old property callbacks to new ones
+// F(old name, new name, return value, parameters...)
+//
+// These aren't included in the list as they have duplicate signatures
+// F(NamedPropertyEnumerator, NamedPropertyEnumeratorCallback, ...)
+// F(NamedPropertyGetter, NamedPropertyGetterCallback, ...)
+
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \
+ F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback, v8::Array) \
+
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \
+ F(AccessorGetter, AccessorGetterCallback, v8::Value, v8::Local<v8::String>) \
+ F(NamedPropertyQuery, \
+ NamedPropertyQueryCallback, \
+ v8::Integer, \
+ v8::Local<v8::String>) \
+ F(NamedPropertyDeleter, \
+ NamedPropertyDeleterCallback, \
+ v8::Boolean, \
+ v8::Local<v8::String>) \
+ F(IndexedPropertyGetter, \
+ IndexedPropertyGetterCallback, \
+ v8::Value, \
+ uint32_t) \
+ F(IndexedPropertyQuery, \
+ IndexedPropertyQueryCallback, \
+ v8::Integer, \
+ uint32_t) \
+ F(IndexedPropertyDeleter, \
+ IndexedPropertyDeleterCallback, \
+ v8::Boolean, \
+ uint32_t) \
+
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \
+ F(NamedPropertySetter, \
+ NamedPropertySetterCallback, \
+ v8::Value, \
+ v8::Local<v8::String>, \
+ v8::Local<v8::Value>) \
+ F(IndexedPropertySetter, \
+ IndexedPropertySetterCallback, \
+ v8::Value, \
+ uint32_t, \
+ v8::Local<v8::Value>) \
+
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \
+ F(AccessorSetter, \
+ AccessorSetterCallback, \
+ void, \
+ v8::Local<v8::String>, \
+ v8::Local<v8::Value>) \
+
+// All property callbacks as well as invocation callbacks
+#define FOR_EACH_CALLBACK_TABLE_MAPPING(F) \
+ F(InvocationCallback, FunctionCallback) \
+ F(AccessorGetter, AccessorGetterCallback) \
+ F(AccessorSetter, AccessorSetterCallback) \
+ F(NamedPropertySetter, NamedPropertySetterCallback) \
+ F(NamedPropertyQuery, NamedPropertyQueryCallback) \
+ F(NamedPropertyDeleter, NamedPropertyDeleterCallback) \
+ F(IndexedPropertyGetter, IndexedPropertyGetterCallback) \
+ F(IndexedPropertySetter, IndexedPropertySetterCallback) \
+ F(IndexedPropertyQuery, IndexedPropertyQueryCallback) \
+ F(IndexedPropertyDeleter, IndexedPropertyDeleterCallback) \
+ F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback) \
+
+
+// TODO(dcarney): Remove this class when old callbacks are gone.
+class CallbackTable {
+ public:
+ // TODO(dcarney): Flip this when it makes sense for performance.
+ static const bool kStoreVoidFunctions = true;
+ static inline bool ReturnsVoid(Isolate* isolate, void* function) {
+ CallbackTable* table = isolate->callback_table();
+ bool contains =
+ table != NULL &&
+ table->map_.occupancy() != 0 &&
+ table->Contains(function);
+ return contains == kStoreVoidFunctions;
+ }
+
+ STATIC_ASSERT(sizeof(intptr_t) == sizeof(AccessorGetterCallback));
+
+ template<typename F>
+ static inline void* FunctionToVoidPtr(F function) {
+ return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(function));
+ }
+
+#define WRITE_REGISTER(OldFunction, NewFunction) \
+ static OldFunction Register(Isolate* isolate, NewFunction f) { \
+ InsertCallback(isolate, FunctionToVoidPtr(f), true); \
+ return reinterpret_cast<OldFunction>(f); \
+ } \
+ \
+ static OldFunction Register(Isolate* isolate, OldFunction f) { \
+ InsertCallback(isolate, FunctionToVoidPtr(f), false); \
+ return f; \
+ }
+ FOR_EACH_CALLBACK_TABLE_MAPPING(WRITE_REGISTER)
+#undef WRITE_REGISTER
+
+ private:
+ CallbackTable();
+ bool Contains(void* function);
+ static void InsertCallback(Isolate* isolate,
+ void* function,
+ bool returns_void);
+ HashMap map_;
+ DISALLOW_COPY_AND_ASSIGN(CallbackTable);
+};
+
+
// Custom arguments replicate a small segment of stack that can be
// accessed through an Arguments object the same way the actual stack
// can.
-class CustomArguments : public Relocatable {
+template<int kArrayLength>
+class CustomArgumentsBase : public Relocatable {
+ public:
+ virtual inline void IterateInstance(ObjectVisitor* v) {
+ v->VisitPointers(values_, values_ + kArrayLength);
+ }
+ protected:
+ inline Object** end() { return values_ + kArrayLength - 1; }
+ explicit inline CustomArgumentsBase(Isolate* isolate)
+ : Relocatable(isolate) {}
+ Object* values_[kArrayLength];
+};
+
+
+template<typename T>
+class CustomArguments : public CustomArgumentsBase<T::kArgsLength> {
public:
- inline CustomArguments(Isolate* isolate,
- Object* data,
- Object* self,
- JSObject* holder) : Relocatable(isolate) {
- ASSERT(reinterpret_cast<Object*>(isolate)->IsSmi());
- values_[3] = self;
- values_[2] = holder;
- values_[1] = data;
- values_[0] = reinterpret_cast<Object*>(isolate);
+ static const int kReturnValueOffset = T::kReturnValueIndex;
+
+ typedef CustomArgumentsBase<T::kArgsLength> Super;
+ ~CustomArguments() {
+ // TODO(dcarney): create a new zap value for this.
+ this->end()[kReturnValueOffset] =
+ reinterpret_cast<Object*>(kHandleZapValue);
+ }
+
+ protected:
+ explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {}
+
+ template<typename V>
+ v8::Handle<V> GetReturnValue(Isolate* isolate);
+
+ inline Isolate* isolate() {
+ return reinterpret_cast<Isolate*>(this->end()[T::kIsolateIndex]);
}
+};
+
+
+class PropertyCallbackArguments
+ : public CustomArguments<PropertyCallbackInfo<Value> > {
+ public:
+ typedef PropertyCallbackInfo<Value> T;
+ typedef CustomArguments<T> Super;
+ static const int kArgsLength = T::kArgsLength;
+ static const int kThisIndex = T::kThisIndex;
+ static const int kHolderIndex = T::kHolderIndex;
+
+ PropertyCallbackArguments(Isolate* isolate,
+ Object* data,
+ Object* self,
+ JSObject* holder)
+ : Super(isolate) {
+ Object** values = this->end();
+ values[T::kThisIndex] = self;
+ values[T::kHolderIndex] = holder;
+ values[T::kDataIndex] = data;
+ values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate);
+ values[T::kReturnValueIndex] = isolate->heap()->the_hole_value();
+ ASSERT(values[T::kHolderIndex]->IsHeapObject());
+ ASSERT(values[T::kIsolateIndex]->IsSmi());
+ }
+
+ /*
+ * The following Call functions wrap the calling of all callbacks to handle
+ * calling either the old or the new style callbacks depending on which one
+ * has been registered.
+ * For old callbacks which return an empty handle, the ReturnValue is checked
+ * and used if it's been set to anything inside the callback.
+ * New style callbacks always use the return value.
+ */
+#define WRITE_CALL_0(OldFunction, NewFunction, ReturnValue) \
+ v8::Handle<ReturnValue> Call(OldFunction f); \
+
+#define WRITE_CALL_1(OldFunction, NewFunction, ReturnValue, Arg1) \
+ v8::Handle<ReturnValue> Call(OldFunction f, Arg1 arg1); \
+
+#define WRITE_CALL_2(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \
+ v8::Handle<ReturnValue> Call(OldFunction f, Arg1 arg1, Arg2 arg2); \
+
+#define WRITE_CALL_2_VOID(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \
+ void Call(OldFunction f, Arg1 arg1, Arg2 arg2); \
+
+FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0)
+FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1)
+FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2)
+FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID)
+
+#undef WRITE_CALL_0
+#undef WRITE_CALL_1
+#undef WRITE_CALL_2
+#undef WRITE_CALL_2_VOID
+};
+
+
+class FunctionCallbackArguments
+ : public CustomArguments<FunctionCallbackInfo<Value> > {
+ public:
+ typedef FunctionCallbackInfo<Value> T;
+ typedef CustomArguments<T> Super;
+ static const int kArgsLength = T::kArgsLength;
- inline explicit CustomArguments(Isolate* isolate) : Relocatable(isolate) {
-#ifdef DEBUG
- for (size_t i = 0; i < ARRAY_SIZE(values_); i++) {
- values_[i] = reinterpret_cast<Object*>(kZapValue);
- }
-#endif
+ FunctionCallbackArguments(internal::Isolate* isolate,
+ internal::Object* data,
+ internal::JSFunction* callee,
+ internal::Object* holder,
+ internal::Object** argv,
+ int argc,
+ bool is_construct_call)
+ : Super(isolate),
+ argv_(argv),
+ argc_(argc),
+ is_construct_call_(is_construct_call) {
+ Object** values = end();
+ values[T::kDataIndex] = data;
+ values[T::kCalleeIndex] = callee;
+ values[T::kHolderIndex] = holder;
+ values[T::kIsolateIndex] = reinterpret_cast<internal::Object*>(isolate);
+ values[T::kReturnValueIndex] = isolate->heap()->the_hole_value();
+ ASSERT(values[T::kCalleeIndex]->IsJSFunction());
+ ASSERT(values[T::kHolderIndex]->IsHeapObject());
+ ASSERT(values[T::kIsolateIndex]->IsSmi());
}
- void IterateInstance(ObjectVisitor* v);
- Object** end() { return values_ + ARRAY_SIZE(values_) - 1; }
+ /*
+ * The following Call function wraps the calling of all callbacks to handle
+ * calling either the old or the new style callbacks depending on which one
+ * has been registered.
+ * For old callbacks which return an empty handle, the ReturnValue is checked
+ * and used if it's been set to anything inside the callback.
+ * New style callbacks always use the return value.
+ */
+ v8::Handle<v8::Value> Call(InvocationCallback f);
private:
- Object* values_[4];
+ internal::Object** argv_;
+ int argc_;
+ bool is_construct_call_;
};
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;
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));
// 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);
}
-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.
// -- 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();
__ 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.
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);
}
__ 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;
__ 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);
}
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;
{
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();
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();
}
-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 =
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
- result = enum_fun(info);
+ result = args.Call(enum_fun);
}
}
#if ENABLE_EXTRA_CHECKS
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 =
{
// 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
#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.
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 =
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.
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);
// 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);
// Generates an Operand for saving parameters after PrepareCallApiFunction.
-Operand ApiParameterOperand(int index);
+Operand ApiParameterOperand(int index, bool returns_handle);
#ifdef GENERATED_CODE_COVERAGE
// 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
// (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();
}
__ 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.
// it's not controlled by GC.
const int kApiStackSpace = 4;
- __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
+ // Function address is a foreign pointer outside V8's heap.
+ Address function_address = v8::ToCData<Address>(api_call_info->callback());
+ bool returns_handle =
+ !CallbackTable::ReturnsVoid(masm->isolate(),
+ reinterpret_cast<void*>(function_address));
+ __ PrepareCallApiFunction(kApiArgc + kApiStackSpace, returns_handle);
- __ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_.
+ // v8::Arguments::implicit_args_.
+ __ mov(ApiParameterOperand(1, returns_handle), eax);
__ add(eax, Immediate(argc * kPointerSize));
- __ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_.
- __ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_.
+ // v8::Arguments::values_.
+ __ mov(ApiParameterOperand(2, returns_handle), eax);
+ // v8::Arguments::length_.
+ __ Set(ApiParameterOperand(3, returns_handle), Immediate(argc));
// v8::Arguments::is_construct_call_.
- __ Set(ApiParameterOperand(4), Immediate(0));
+ __ Set(ApiParameterOperand(4, returns_handle), Immediate(0));
// v8::InvocationCallback's argument.
- __ lea(eax, ApiParameterOperand(1));
- __ mov(ApiParameterOperand(0), eax);
+ __ lea(eax, ApiParameterOperand(1, returns_handle));
+ __ mov(ApiParameterOperand(0, returns_handle), eax);
- // Function address is a foreign pointer outside V8's heap.
- Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ CallApiFunctionAndReturn(function_address,
- argc + kFastApiCallArguments + 1);
+ argc + kFastApiCallArguments + 1,
+ returns_handle,
+ kFastApiCallArguments + 1);
}
__ 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.
__ 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);
}
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
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);
namespace internal {
class Bootstrapper;
+class CallbackTable;
class CodeGenerator;
class CodeRange;
struct CodeStubInterfaceDescriptor;
return sweeper_thread_;
}
+ CallbackTable* callback_table() {
+ return callback_table_;
+ }
+ void set_callback_table(CallbackTable* callback_table) {
+ callback_table_ = callback_table;
+ }
+
HStatistics* GetHStatistics();
HTracer* GetHTracer();
OptimizingCompilerThread optimizing_compiler_thread_;
MarkingThread** marking_thread_;
SweeperThread** sweeper_thread_;
+ CallbackTable* callback_table_;
friend class ExecutionAccess;
friend class HandleScopeImplementer;
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()) {
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;
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;
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;
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());
{
// 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());
{
// 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;
}
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());
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
- result = query(index, info);
+ result = args.Call(query, index);
}
if (!result.IsEmpty())
return static_cast<PropertyAttributes>(result->Int32Value());
{
// Leaving JavaScript.
VMState<EXTERNAL> state(isolate);
- result = getter(index, info);
+ result = args.Call(getter, index);
}
if (!result.IsEmpty()) return NONE;
}
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()) {
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()) {
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;
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();
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;
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()) {
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()) {
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;
* 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())
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()) {
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();
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()) {
}
-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);
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;
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
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);
// 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],
// 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
// (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();
__ 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
// 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));
// 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);
}
} 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;
__ 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);
// 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);
}
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);
}
+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();
+ 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());
+}
+
+
+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>();
+}
-THREADED_TEST(FunctionTemplate) {
- LocalContext env;
- v8::HandleScope scope(env->GetIsolate());
+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());
+ }
+ 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()));
+}
- 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());
+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);
+}
+
+
THREADED_TEST(FunctionTemplateSetLength) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
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"));
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();
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();
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();
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);
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());
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());
}
-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);
}
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();
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();
'../../src/api.cc',
'../../src/api.h',
'../../src/apiutils.h',
+ '../../src/arguments.cc',
'../../src/arguments.h',
'../../src/assembler.cc',
'../../src/assembler.h',