new style of property/function callbacks
authordcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 21 May 2013 06:36:24 +0000 (06:36 +0000)
committerdcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 21 May 2013 06:36:24 +0000 (06:36 +0000)
R=svenpanne@chromium.org
BUG=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14725 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

22 files changed:
include/v8.h
src/api.cc
src/apiutils.h
src/arguments.cc [new file with mode: 0644]
src/arguments.h
src/arm/macro-assembler-arm.cc
src/arm/macro-assembler-arm.h
src/arm/stub-cache-arm.cc
src/builtins.cc
src/handles.cc
src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/ia32/stub-cache-ia32.cc
src/isolate.cc
src/isolate.h
src/objects.cc
src/stub-cache.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h
src/x64/stub-cache-x64.cc
test/cctest/test-api.cc
tools/gyp/v8.gyp

index 96a1d8b..19a8ad8 100644 (file)
@@ -144,6 +144,17 @@ class Value;
 template <class T> class Handle;
 template <class T> class Local;
 template <class T> class Persistent;
+class FunctionTemplate;
+class ObjectTemplate;
+class Data;
+class AccessorInfo;
+template<typename T> class PropertyCallbackInfo;
+class StackTrace;
+class StackFrame;
+class Isolate;
+class DeclaredAccessorDescriptor;
+class ObjectOperationDescriptor;
+class RawOperationDescriptor;
 
 namespace internal {
 class Arguments;
@@ -151,6 +162,10 @@ class Heap;
 class HeapObject;
 class Isolate;
 class Object;
+template<typename T>
+class CustomArguments;
+class PropertyCallbackArguments;
+class FunctionCallbackArguments;
 }
 
 
@@ -1936,11 +1951,18 @@ enum ExternalArrayType {
  */
 typedef Handle<Value> (*AccessorGetter)(Local<String> property,
                                         const AccessorInfo& info);
+typedef void (*AccessorGetterCallback)(
+    Local<String> property,
+    const PropertyCallbackInfo<Value>& info);
 
 
 typedef void (*AccessorSetter)(Local<String> property,
                                Local<Value> value,
                                const AccessorInfo& info);
+typedef void (*AccessorSetterCallback)(
+    Local<String> property,
+    Local<Value> value,
+    const PropertyCallbackInfo<void>& info);
 
 
 /**
@@ -2010,12 +2032,19 @@ class V8EXPORT Object : public Value {
 
   bool Delete(uint32_t index);
 
+  // TODO(dcarney): deprecate
   bool SetAccessor(Handle<String> name,
                    AccessorGetter getter,
                    AccessorSetter setter = 0,
                    Handle<Value> data = Handle<Value>(),
                    AccessControl settings = DEFAULT,
                    PropertyAttribute attribute = None);
+  bool SetAccessor(Handle<String> name,
+                   AccessorGetterCallback getter,
+                   AccessorSetterCallback setter = 0,
+                   Handle<Value> data = Handle<Value>(),
+                   AccessControl settings = DEFAULT,
+                   PropertyAttribute attribute = None);
 
   // This function is not yet stable and should not be used at this time.
   bool SetAccessor(Handle<String> name,
@@ -2704,13 +2733,36 @@ class V8EXPORT Template : public Data {
 };
 
 
+template<typename T>
+class V8EXPORT ReturnValue {
+ public:
+  V8_INLINE(explicit ReturnValue(internal::Object** slot));
+  // Handle setters
+  V8_INLINE(void Set(const Persistent<T>& handle));
+  V8_INLINE(void Set(const Handle<T> handle));
+  // TODO(dcarney): implement
+  // Fast primitive setters
+//  V8_INLINE(void Set(Isolate* isolate, bool));
+//  V8_INLINE(void Set(Isolate* isolate, float i));
+//  V8_INLINE(void Set(Isolate* isolate, double i));
+//  V8_INLINE(void Set(Isolate* isolate, int32_t i));
+//  V8_INLINE(void Set(Isolate* isolate, uint32_t i));
+  // Fast JS primitive setters
+//  V8_INLINE(void SetNull(Isolate* isolate));
+//  V8_INLINE(void SetUndefined(Isolate* isolate));
+ private:
+  internal::Object** value_;
+};
+
+
 /**
  * The argument information given to function call callbacks.  This
  * class provides access to information about the context of the call,
  * including the receiver, the number and values of arguments, and
  * the holder of the function.
  */
-class V8EXPORT Arguments {
+template<typename T>
+class V8EXPORT FunctionCallbackInfo {
  public:
   V8_INLINE(int Length() const);
   V8_INLINE(Local<Value> operator[](int i) const);
@@ -2720,15 +2772,20 @@ class V8EXPORT Arguments {
   V8_INLINE(bool IsConstructCall() const);
   V8_INLINE(Local<Value> Data() const);
   V8_INLINE(Isolate* GetIsolate() const);
+  V8_INLINE(ReturnValue<T> GetReturnValue() const);
+  // This shouldn't be public, but the arm compiler needs it.
+  static const int kArgsLength = 5;
 
- private:
-  static const int kIsolateIndex = 0;
-  static const int kDataIndex = -1;
-  static const int kCalleeIndex = -2;
-  static const int kHolderIndex = -3;
-
-  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));
@@ -2739,25 +2796,56 @@ class V8EXPORT Arguments {
 };
 
 
+class V8EXPORT Arguments : public FunctionCallbackInfo<Value> {
+ private:
+  friend class internal::FunctionCallbackArguments;
+  V8_INLINE(Arguments(internal::Object** implicit_args,
+                      internal::Object** values,
+                      int length,
+                      bool is_construct_call));
+};
+
 /**
- * The information passed to an accessor callback about the context
+ * The information passed to a property callback about the context
  * of the property access.
  */
-class V8EXPORT AccessorInfo {
+template<typename T>
+class V8EXPORT PropertyCallbackInfo {
  public:
-  V8_INLINE(AccessorInfo(internal::Object** args))
-      : args_(args) { }
   V8_INLINE(Isolate* GetIsolate() const);
   V8_INLINE(Local<Value> Data() const);
   V8_INLINE(Local<Object> This() const);
   V8_INLINE(Local<Object> Holder() const);
+  V8_INLINE(ReturnValue<T> GetReturnValue() const);
+  // This shouldn't be public, but the arm compiler needs it.
+  static const int kArgsLength = 5;
 
- private:
+ protected:
+  friend class MacroAssembler;
+  friend class internal::PropertyCallbackArguments;
+  friend class internal::CustomArguments<PropertyCallbackInfo>;
+  static const int kThisIndex = 0;
+  static const int kHolderIndex = -1;
+  static const int kDataIndex = -2;
+  static const int kIsolateIndex = -3;
+  static const int kReturnValueIndex = -4;
+
+  V8_INLINE(PropertyCallbackInfo(internal::Object** args))
+      : args_(args) { }
   internal::Object** args_;
 };
 
 
+class V8EXPORT AccessorInfo : public PropertyCallbackInfo<Value> {
+ private:
+  friend class internal::PropertyCallbackArguments;
+  V8_INLINE(AccessorInfo(internal::Object** args))
+      : PropertyCallbackInfo<Value>(args) { }
+};
+
+
 typedef Handle<Value> (*InvocationCallback)(const Arguments& args);
+typedef void (*FunctionCallback)(const FunctionCallbackInfo<Value>& info);
 
 /**
  * NamedProperty[Getter|Setter] are used as interceptors on object.
@@ -2765,6 +2853,9 @@ typedef Handle<Value> (*InvocationCallback)(const Arguments& args);
  */
 typedef Handle<Value> (*NamedPropertyGetter)(Local<String> property,
                                              const AccessorInfo& info);
+typedef void (*NamedPropertyGetterCallback)(
+    Local<String> property,
+    const PropertyCallbackInfo<Value>& info);
 
 
 /**
@@ -2774,6 +2865,11 @@ typedef Handle<Value> (*NamedPropertyGetter)(Local<String> property,
 typedef Handle<Value> (*NamedPropertySetter)(Local<String> property,
                                              Local<Value> value,
                                              const AccessorInfo& info);
+typedef void (*NamedPropertySetterCallback)(
+    Local<String> property,
+    Local<Value> value,
+    const PropertyCallbackInfo<Value>& info);
+
 
 /**
  * Returns a non-empty handle if the interceptor intercepts the request.
@@ -2782,6 +2878,9 @@ typedef Handle<Value> (*NamedPropertySetter)(Local<String> property,
  */
 typedef Handle<Integer> (*NamedPropertyQuery)(Local<String> property,
                                               const AccessorInfo& info);
+typedef void (*NamedPropertyQueryCallback)(
+    Local<String> property,
+    const PropertyCallbackInfo<Integer>& info);
 
 
 /**
@@ -2791,12 +2890,18 @@ typedef Handle<Integer> (*NamedPropertyQuery)(Local<String> property,
  */
 typedef Handle<Boolean> (*NamedPropertyDeleter)(Local<String> property,
                                                 const AccessorInfo& info);
+typedef void (*NamedPropertyDeleterCallback)(
+    Local<String> property,
+    const PropertyCallbackInfo<Boolean>& info);
+
 
 /**
  * Returns an array containing the names of the properties the named
  * property getter intercepts.
  */
 typedef Handle<Array> (*NamedPropertyEnumerator)(const AccessorInfo& info);
+typedef void (*NamedPropertyEnumeratorCallback)(
+    const PropertyCallbackInfo<Array>& info);
 
 
 /**
@@ -2805,6 +2910,9 @@ typedef Handle<Array> (*NamedPropertyEnumerator)(const AccessorInfo& info);
  */
 typedef Handle<Value> (*IndexedPropertyGetter)(uint32_t index,
                                                const AccessorInfo& info);
+typedef void (*IndexedPropertyGetterCallback)(
+    uint32_t index,
+    const PropertyCallbackInfo<Value>& info);
 
 
 /**
@@ -2814,6 +2922,10 @@ typedef Handle<Value> (*IndexedPropertyGetter)(uint32_t index,
 typedef Handle<Value> (*IndexedPropertySetter)(uint32_t index,
                                                Local<Value> value,
                                                const AccessorInfo& info);
+typedef void (*IndexedPropertySetterCallback)(
+    uint32_t index,
+    Local<Value> value,
+    const PropertyCallbackInfo<Value>& info);
 
 
 /**
@@ -2822,6 +2934,10 @@ typedef Handle<Value> (*IndexedPropertySetter)(uint32_t index,
  */
 typedef Handle<Integer> (*IndexedPropertyQuery)(uint32_t index,
                                                 const AccessorInfo& info);
+typedef void (*IndexedPropertyQueryCallback)(
+    uint32_t index,
+    const PropertyCallbackInfo<Integer>& info);
+
 
 /**
  * Returns a non-empty handle if the deleter intercepts the request.
@@ -2830,12 +2946,18 @@ typedef Handle<Integer> (*IndexedPropertyQuery)(uint32_t index,
  */
 typedef Handle<Boolean> (*IndexedPropertyDeleter)(uint32_t index,
                                                   const AccessorInfo& info);
+typedef void (*IndexedPropertyDeleterCallback)(
+    uint32_t index,
+    const PropertyCallbackInfo<Boolean>& info);
+
 
 /**
  * Returns an array containing the indices of the properties the
  * indexed property getter intercepts.
  */
 typedef Handle<Array> (*IndexedPropertyEnumerator)(const AccessorInfo& info);
+typedef void (*IndexedPropertyEnumeratorCallback)(
+    const PropertyCallbackInfo<Array>& info);
 
 
 /**
@@ -2965,11 +3087,18 @@ typedef bool (*IndexedSecurityCallback)(Local<Object> host,
 class V8EXPORT FunctionTemplate : public Template {
  public:
   /** Creates a function template.*/
+  // TODO(dcarney): deprecate
   static Local<FunctionTemplate> New(
       InvocationCallback callback = 0,
       Handle<Value> data = Handle<Value>(),
       Handle<Signature> signature = Handle<Signature>(),
       int length = 0);
+  static Local<FunctionTemplate> New(
+      FunctionCallback callback,  // TODO(dcarney): add back default param.
+      Handle<Value> data = Handle<Value>(),
+      Handle<Signature> signature = Handle<Signature>(),
+      int length = 0);
+
   /** Returns the unique function instance in the current execution context.*/
   Local<Function> GetFunction();
 
@@ -2978,8 +3107,11 @@ class V8EXPORT FunctionTemplate : public Template {
    * callback is called whenever the function created from this
    * FunctionTemplate is called.
    */
+  // TODO(dcarney): deprecate
   void SetCallHandler(InvocationCallback callback,
                       Handle<Value> data = Handle<Value>());
+  void SetCallHandler(FunctionCallback callback,
+                      Handle<Value> data = Handle<Value>());
 
   /** Set the predefined length property for the FunctionTemplate. */
   void SetLength(int length);
@@ -3031,21 +3163,6 @@ class V8EXPORT FunctionTemplate : public Template {
 
  private:
   FunctionTemplate();
-  void SetNamedInstancePropertyHandler(NamedPropertyGetter getter,
-                                       NamedPropertySetter setter,
-                                       NamedPropertyQuery query,
-                                       NamedPropertyDeleter remover,
-                                       NamedPropertyEnumerator enumerator,
-                                       Handle<Value> data);
-  void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter,
-                                         IndexedPropertySetter setter,
-                                         IndexedPropertyQuery query,
-                                         IndexedPropertyDeleter remover,
-                                         IndexedPropertyEnumerator enumerator,
-                                         Handle<Value> data);
-  void SetInstanceCallAsFunctionHandler(InvocationCallback callback,
-                                        Handle<Value> data);
-
   friend class Context;
   friend class ObjectTemplate;
 };
@@ -3094,6 +3211,7 @@ class V8EXPORT ObjectTemplate : public Template {
    *   defined by FunctionTemplate::HasInstance()), an implicit TypeError is
    *   thrown and no callback is invoked.
    */
+  // TODO(dcarney): deprecate
   void SetAccessor(Handle<String> name,
                    AccessorGetter getter,
                    AccessorSetter setter = 0,
@@ -3102,6 +3220,14 @@ class V8EXPORT ObjectTemplate : public Template {
                    PropertyAttribute attribute = None,
                    Handle<AccessorSignature> signature =
                        Handle<AccessorSignature>());
+  void SetAccessor(Handle<String> name,
+                   AccessorGetterCallback getter,
+                   AccessorSetterCallback setter = 0,
+                   Handle<Value> data = Handle<Value>(),
+                   AccessControl settings = DEFAULT,
+                   PropertyAttribute attribute = None,
+                   Handle<AccessorSignature> signature =
+                       Handle<AccessorSignature>());
 
   // This function is not yet stable and should not be used at this time.
   bool SetAccessor(Handle<String> name,
@@ -3128,12 +3254,20 @@ class V8EXPORT ObjectTemplate : public Template {
    * \param data A piece of data that will be passed to the callbacks
    *   whenever they are invoked.
    */
+  // TODO(dcarney): deprecate
   void SetNamedPropertyHandler(NamedPropertyGetter getter,
                                NamedPropertySetter setter = 0,
                                NamedPropertyQuery query = 0,
                                NamedPropertyDeleter deleter = 0,
                                NamedPropertyEnumerator enumerator = 0,
                                Handle<Value> data = Handle<Value>());
+  void SetNamedPropertyHandler(
+      NamedPropertyGetterCallback getter,
+      NamedPropertySetterCallback setter = 0,
+      NamedPropertyQueryCallback query = 0,
+      NamedPropertyDeleterCallback deleter = 0,
+      NamedPropertyEnumeratorCallback enumerator = 0,
+      Handle<Value> data = Handle<Value>());
 
   /**
    * Sets an indexed property handler on the object template.
@@ -3151,12 +3285,20 @@ class V8EXPORT ObjectTemplate : public Template {
    * \param data A piece of data that will be passed to the callbacks
    *   whenever they are invoked.
    */
+  // TODO(dcarney): deprecate
   void SetIndexedPropertyHandler(IndexedPropertyGetter getter,
                                  IndexedPropertySetter setter = 0,
                                  IndexedPropertyQuery query = 0,
                                  IndexedPropertyDeleter deleter = 0,
                                  IndexedPropertyEnumerator enumerator = 0,
                                  Handle<Value> data = Handle<Value>());
+  void SetIndexedPropertyHandler(
+      IndexedPropertyGetterCallback getter,
+      IndexedPropertySetterCallback setter = 0,
+      IndexedPropertyQueryCallback query = 0,
+      IndexedPropertyDeleterCallback deleter = 0,
+      IndexedPropertyEnumeratorCallback enumerator = 0,
+      Handle<Value> data = Handle<Value>());
 
   /**
    * Sets the callback to be used when calling instances created from
@@ -3164,8 +3306,11 @@ class V8EXPORT ObjectTemplate : public Template {
    * behave like normal JavaScript objects that cannot be called as a
    * function.
    */
+  // TODO(dcarney): deprecate
   void SetCallAsFunctionHandler(InvocationCallback callback,
                                 Handle<Value> data = Handle<Value>());
+  void SetCallAsFunctionHandler(FunctionCallback callback,
+                                Handle<Value> data = Handle<Value>());
 
   /**
    * Mark object instances of the template as undetectable.
@@ -5455,54 +5600,90 @@ uint16_t Persistent<T>::WrapperClassId(Isolate* isolate) const {
   return *reinterpret_cast<uint16_t*>(addr);
 }
 
-Arguments::Arguments(internal::Object** implicit_args,
-                     internal::Object** values, int length,
-                     bool is_construct_call)
+template<typename T>
+ReturnValue<T>::ReturnValue(internal::Object** slot) : value_(slot) {}
+
+template<typename T>
+void ReturnValue<T>::Set(const Persistent<T>& handle) {
+  *value_ = *reinterpret_cast<internal::Object**>(*handle);
+}
+
+template<typename T>
+void ReturnValue<T>::Set(const Handle<T> handle) {
+  *value_ = *reinterpret_cast<internal::Object**>(*handle);
+}
+
+template<typename T>
+FunctionCallbackInfo<T>::FunctionCallbackInfo(internal::Object** implicit_args,
+                                              internal::Object** values,
+                                              int length,
+                                              bool is_construct_call)
     : implicit_args_(implicit_args),
       values_(values),
       length_(length),
       is_construct_call_(is_construct_call) { }
 
 
-Local<Value> Arguments::operator[](int i) const {
+Arguments::Arguments(internal::Object** args,
+                     internal::Object** values,
+                     int length,
+                     bool is_construct_call)
+    : FunctionCallbackInfo<Value>(args, values, length, is_construct_call) { }
+
+
+template<typename T>
+Local<Value> FunctionCallbackInfo<T>::operator[](int i) const {
   if (i < 0 || length_ <= i) return Local<Value>(*Undefined());
   return Local<Value>(reinterpret_cast<Value*>(values_ - i));
 }
 
 
-Local<Function> Arguments::Callee() const {
+template<typename T>
+Local<Function> FunctionCallbackInfo<T>::Callee() const {
   return Local<Function>(reinterpret_cast<Function*>(
       &implicit_args_[kCalleeIndex]));
 }
 
 
-Local<Object> Arguments::This() const {
+template<typename T>
+Local<Object> FunctionCallbackInfo<T>::This() const {
   return Local<Object>(reinterpret_cast<Object*>(values_ + 1));
 }
 
 
-Local<Object> Arguments::Holder() const {
+template<typename T>
+Local<Object> FunctionCallbackInfo<T>::Holder() const {
   return Local<Object>(reinterpret_cast<Object*>(
       &implicit_args_[kHolderIndex]));
 }
 
 
-Local<Value> Arguments::Data() const {
+template<typename T>
+Local<Value> FunctionCallbackInfo<T>::Data() const {
   return Local<Value>(reinterpret_cast<Value*>(&implicit_args_[kDataIndex]));
 }
 
 
-Isolate* Arguments::GetIsolate() const {
+template<typename T>
+Isolate* FunctionCallbackInfo<T>::GetIsolate() const {
   return *reinterpret_cast<Isolate**>(&implicit_args_[kIsolateIndex]);
 }
 
 
-bool Arguments::IsConstructCall() const {
+template<typename T>
+ReturnValue<T> FunctionCallbackInfo<T>::GetReturnValue() const {
+  return ReturnValue<T>(&implicit_args_[kReturnValueIndex]);
+}
+
+
+template<typename T>
+bool FunctionCallbackInfo<T>::IsConstructCall() const {
   return is_construct_call_;
 }
 
 
-int Arguments::Length() const {
+template<typename T>
+int FunctionCallbackInfo<T>::Length() const {
   return length_;
 }
 
@@ -5891,23 +6072,33 @@ External* External::Cast(v8::Value* value) {
 }
 
 
-Isolate* AccessorInfo::GetIsolate() const {
-  return *reinterpret_cast<Isolate**>(&args_[-3]);
+template<typename T>
+Isolate* PropertyCallbackInfo<T>::GetIsolate() const {
+  return *reinterpret_cast<Isolate**>(&args_[kIsolateIndex]);
+}
+
+
+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]);
 }
 
 
index f0505cd..ccf3822 100644 (file)
@@ -983,8 +983,12 @@ void FunctionTemplate::Inherit(v8::Handle<FunctionTemplate> value) {
 }
 
 
-Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
-    v8::Handle<Value> data, v8::Handle<Signature> signature, int length) {
+template<typename Callback>
+static Local<FunctionTemplate> FunctionTemplateNew(
+    Callback callback_in,
+    v8::Handle<Value> data,
+    v8::Handle<Signature> signature,
+    int length) {
   i::Isolate* isolate = i::Isolate::Current();
   EnsureInitializedForIsolate(isolate, "v8::FunctionTemplate::New()");
   LOG_API(isolate, "FunctionTemplate::New");
@@ -997,8 +1001,10 @@ Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
   int next_serial_number = isolate->next_serial_number();
   isolate->set_next_serial_number(next_serial_number + 1);
   obj->set_serial_number(i::Smi::FromInt(next_serial_number));
-  if (callback != 0) {
+  if (callback_in != 0) {
     if (data.IsEmpty()) data = v8::Undefined();
+    InvocationCallback callback =
+        i::CallbackTable::Register(isolate, callback_in);
     Utils::ToLocal(obj)->SetCallHandler(callback, data);
   }
   obj->set_length(length);
@@ -1011,6 +1017,24 @@ Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
 }
 
 
+Local<FunctionTemplate> FunctionTemplate::New(
+    InvocationCallback callback,
+    v8::Handle<Value> data,
+    v8::Handle<Signature> signature,
+    int length) {
+  return FunctionTemplateNew(callback, data, signature, length);
+}
+
+
+Local<FunctionTemplate> FunctionTemplate::New(
+    FunctionCallback callback,
+    v8::Handle<Value> data,
+    v8::Handle<Signature> signature,
+    int length) {
+  return FunctionTemplateNew(callback, data, signature, length);
+}
+
+
 Local<Signature> Signature::New(Handle<FunctionTemplate> receiver,
       int argc, Handle<FunctionTemplate> argv[]) {
   i::Isolate* isolate = i::Isolate::Current();
@@ -1202,9 +1226,11 @@ int TypeSwitch::match(v8::Handle<Value> value) {
   } while (false)
 
 
-void FunctionTemplate::SetCallHandler(InvocationCallback callback,
-                                      v8::Handle<Value> data) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+template<typename Callback>
+static void FunctionTemplateSetCallHandler(FunctionTemplate* function_template,
+                                           Callback callback,
+                                           v8::Handle<Value> data) {
+  i::Isolate* isolate = Utils::OpenHandle(function_template)->GetIsolate();
   if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetCallHandler()")) return;
   ENTER_V8(isolate);
   i::HandleScope scope(isolate);
@@ -1215,9 +1241,18 @@ void FunctionTemplate::SetCallHandler(InvocationCallback callback,
   SET_FIELD_WRAPPED(obj, set_callback, callback);
   if (data.IsEmpty()) data = v8::Undefined();
   obj->set_data(*Utils::OpenHandle(*data));
-  Utils::OpenHandle(this)->set_call_code(*obj);
+  Utils::OpenHandle(function_template)->set_call_code(*obj);
 }
 
+void FunctionTemplate::SetCallHandler(InvocationCallback callback,
+                                      v8::Handle<Value> data) {
+  FunctionTemplateSetCallHandler(this, callback, data);
+}
+
+void FunctionTemplate::SetCallHandler(FunctionCallback callback,
+                                      v8::Handle<Value> data) {
+  FunctionTemplateSetCallHandler(this, callback, data);
+}
 
 static i::Handle<i::AccessorInfo> SetAccessorInfoProperties(
     i::Handle<i::AccessorInfo> obj,
@@ -1237,10 +1272,11 @@ static i::Handle<i::AccessorInfo> SetAccessorInfoProperties(
 }
 
 
+template<typename Getter, typename Setter>
 static i::Handle<i::AccessorInfo> MakeAccessorInfo(
       v8::Handle<String> name,
-      AccessorGetter getter,
-      AccessorSetter setter,
+      Getter getter_in,
+      Setter setter_in,
       v8::Handle<Value> data,
       v8::AccessControl settings,
       v8::PropertyAttribute attributes,
@@ -1248,7 +1284,9 @@ static i::Handle<i::AccessorInfo> MakeAccessorInfo(
   i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate();
   i::Handle<i::ExecutableAccessorInfo> obj =
       isolate->factory()->NewExecutableAccessorInfo();
+  AccessorGetter getter = i::CallbackTable::Register(isolate, getter_in);
   SET_FIELD_WRAPPED(obj, set_getter, getter);
+  AccessorSetter setter = i::CallbackTable::Register(isolate, setter_in);
   SET_FIELD_WRAPPED(obj, set_setter, setter);
   if (data.IsEmpty()) data = v8::Undefined();
   obj->set_data(*Utils::OpenHandle(*data));
@@ -1259,6 +1297,8 @@ static i::Handle<i::AccessorInfo> MakeAccessorInfo(
 static i::Handle<i::AccessorInfo> MakeAccessorInfo(
       v8::Handle<String> name,
       v8::Handle<v8::DeclaredAccessorDescriptor> descriptor,
+      void* setter_ignored,
+      void* data_ignored,
       v8::AccessControl settings,
       v8::PropertyAttribute attributes,
       v8::Handle<AccessorSignature> signature) {
@@ -1323,15 +1363,21 @@ void FunctionTemplate::ReadOnlyPrototype() {
   Utils::OpenHandle(this)->set_read_only_prototype(true);
 }
 
-
-void FunctionTemplate::SetNamedInstancePropertyHandler(
-      NamedPropertyGetter getter,
-      NamedPropertySetter setter,
-      NamedPropertyQuery query,
-      NamedPropertyDeleter remover,
-      NamedPropertyEnumerator enumerator,
+template<
+    typename Getter,
+    typename Setter,
+    typename Query,
+    typename Deleter,
+    typename Enumerator>
+static void SetNamedInstancePropertyHandler(
+      i::Handle<i::FunctionTemplateInfo> function_template,
+      Getter getter_in,
+      Setter setter_in,
+      Query query_in,
+      Deleter remover_in,
+      Enumerator enumerator_in,
       Handle<Value> data) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+  i::Isolate* isolate = function_template->GetIsolate();
   if (IsDeadCheck(isolate,
                   "v8::FunctionTemplate::SetNamedInstancePropertyHandler()")) {
     return;
@@ -1343,26 +1389,40 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
   i::Handle<i::InterceptorInfo> obj =
       i::Handle<i::InterceptorInfo>::cast(struct_obj);
 
+  NamedPropertyGetter getter = i::CallbackTable::Register(isolate, getter_in);
   if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter);
+  NamedPropertySetter setter = i::CallbackTable::Register(isolate, setter_in);
   if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter);
+  NamedPropertyQuery query = i::CallbackTable::Register(isolate, query_in);
   if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
+  NamedPropertyDeleter remover =
+      i::CallbackTable::Register(isolate, remover_in);
   if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
+  NamedPropertyEnumerator enumerator =
+      i::CallbackTable::Register(isolate, enumerator_in);
   if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
 
   if (data.IsEmpty()) data = v8::Undefined();
   obj->set_data(*Utils::OpenHandle(*data));
-  Utils::OpenHandle(this)->set_named_property_handler(*obj);
-}
-
-
-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;
@@ -1374,22 +1434,33 @@ void FunctionTemplate::SetIndexedInstancePropertyHandler(
   i::Handle<i::InterceptorInfo> obj =
       i::Handle<i::InterceptorInfo>::cast(struct_obj);
 
+  IndexedPropertyGetter getter =
+      i::CallbackTable::Register(isolate, getter_in);
   if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter);
+  IndexedPropertySetter setter =
+      i::CallbackTable::Register(isolate, setter_in);
   if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter);
+  IndexedPropertyQuery query = i::CallbackTable::Register(isolate, query_in);
   if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
+  IndexedPropertyDeleter remover =
+      i::CallbackTable::Register(isolate, remover_in);
   if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
+  IndexedPropertyEnumerator enumerator =
+      i::CallbackTable::Register(isolate, enumerator_in);
   if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
 
   if (data.IsEmpty()) data = v8::Undefined();
   obj->set_data(*Utils::OpenHandle(*data));
-  Utils::OpenHandle(this)->set_indexed_property_handler(*obj);
+  function_template->set_indexed_property_handler(*obj);
 }
 
 
-void FunctionTemplate::SetInstanceCallAsFunctionHandler(
-      InvocationCallback callback,
+template<typename Callback>
+static void SetInstanceCallAsFunctionHandler(
+      i::Handle<i::FunctionTemplateInfo> function_template,
+      Callback callback_in,
       Handle<Value> data) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+  i::Isolate* isolate = function_template->GetIsolate();
   if (IsDeadCheck(isolate,
                   "v8::FunctionTemplate::SetInstanceCallAsFunctionHandler()")) {
     return;
@@ -1400,10 +1471,12 @@ void FunctionTemplate::SetInstanceCallAsFunctionHandler(
       isolate->factory()->NewStruct(i::CALL_HANDLER_INFO_TYPE);
   i::Handle<i::CallHandlerInfo> obj =
       i::Handle<i::CallHandlerInfo>::cast(struct_obj);
+  InvocationCallback callback =
+      i::CallbackTable::Register(isolate, callback_in);
   SET_FIELD_WRAPPED(obj, set_callback, callback);
   if (data.IsEmpty()) data = v8::Undefined();
   obj->set_data(*Utils::OpenHandle(*data));
-  Utils::OpenHandle(this)->set_instance_call_handler(*obj);
+  function_template->set_instance_call_handler(*obj);
 }
 
 
@@ -1461,6 +1534,32 @@ static inline void AddPropertyToFunctionTemplate(
 }
 
 
+template<typename Setter, typename Getter, typename Data>
+static bool ObjectTemplateSetAccessor(
+    ObjectTemplate* object_template,
+    v8::Handle<String> name,
+    Getter getter,
+    Setter setter,
+    Data data,
+    AccessControl settings,
+    PropertyAttribute attribute,
+    v8::Handle<AccessorSignature> signature) {
+  i::Isolate* isolate = Utils::OpenHandle(object_template)->GetIsolate();
+  if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessor()")) return false;
+  ENTER_V8(isolate);
+  i::HandleScope scope(isolate);
+  EnsureConstructor(object_template);
+  i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
+      Utils::OpenHandle(object_template)->constructor());
+  i::Handle<i::FunctionTemplateInfo> cons(constructor);
+  i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(
+      name, getter, setter, data, settings, attribute, signature);
+  if (obj.is_null()) return false;
+  AddPropertyToFunctionTemplate(cons, obj);
+  return true;
+}
+
+
 void ObjectTemplate::SetAccessor(v8::Handle<String> name,
                                  AccessorGetter getter,
                                  AccessorSetter setter,
@@ -1468,64 +1567,89 @@ void ObjectTemplate::SetAccessor(v8::Handle<String> name,
                                  AccessControl settings,
                                  PropertyAttribute attribute,
                                  v8::Handle<AccessorSignature> signature) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessor()")) return;
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  EnsureConstructor(this);
-  i::FunctionTemplateInfo* constructor =
-      i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
-  i::Handle<i::FunctionTemplateInfo> cons(constructor);
-  i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(name, getter, setter, data,
-                                                      settings, attribute,
-                                                      signature);
-  AddPropertyToFunctionTemplate(cons, obj);
+  ObjectTemplateSetAccessor(
+      this, name, getter, setter, data, settings, attribute, signature);
 }
 
 
-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);
 }
 
 
@@ -1574,46 +1698,93 @@ void ObjectTemplate::SetAccessCheckCallbacks(
 }
 
 
-void ObjectTemplate::SetIndexedPropertyHandler(
-      IndexedPropertyGetter getter,
-      IndexedPropertySetter setter,
-      IndexedPropertyQuery query,
-      IndexedPropertyDeleter remover,
-      IndexedPropertyEnumerator enumerator,
+template<
+    typename Getter,
+    typename Setter,
+    typename Query,
+    typename Deleter,
+    typename Enumerator>
+void ObjectTemplateSetIndexedPropertyHandler(
+      ObjectTemplate* object_template,
+      Getter getter,
+      Setter setter,
+      Query query,
+      Deleter remover,
+      Enumerator enumerator,
       Handle<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);
 }
 
 
@@ -3446,7 +3617,21 @@ bool v8::Object::Has(uint32_t index) {
 }
 
 
-static inline bool SetAccessor(Object* obj, i::Handle<i::AccessorInfo> info) {
+template<typename Setter, typename Getter, typename Data>
+static inline bool ObjectSetAccessor(Object* obj,
+                                     Handle<String> name,
+                                     Setter getter,
+                                     Getter setter,
+                                     Data data,
+                                     AccessControl settings,
+                                     PropertyAttribute attributes) {
+  i::Isolate* isolate = Utils::OpenHandle(obj)->GetIsolate();
+  ON_BAILOUT(isolate, "v8::Object::SetAccessor()", return false);
+  ENTER_V8(isolate);
+  i::HandleScope scope(isolate);
+  v8::Handle<AccessorSignature> signature;
+  i::Handle<i::AccessorInfo> info = MakeAccessorInfo(
+      name, getter, setter, data, settings, attributes, signature);
   if (info.is_null()) return false;
   bool fast = Utils::OpenHandle(obj)->HasFastProperties();
   i::Handle<i::Object> result = i::SetAccessor(Utils::OpenHandle(obj), info);
@@ -3462,15 +3647,19 @@ bool Object::SetAccessor(Handle<String> name,
                          v8::Handle<Value> data,
                          AccessControl settings,
                          PropertyAttribute attributes) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::SetAccessor()", return false);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  v8::Handle<AccessorSignature> signature;
-  i::Handle<i::AccessorInfo> info = MakeAccessorInfo(name, getter, setter, data,
-                                                     settings, attributes,
-                                                     signature);
-  return v8::SetAccessor(this, info);
+  return ObjectSetAccessor(
+      this, name, getter, setter, data, settings, attributes);
+}
+
+
+bool Object::SetAccessor(Handle<String> name,
+                         AccessorGetterCallback getter,
+                         AccessorSetterCallback setter,
+                         v8::Handle<Value> data,
+                         AccessControl settings,
+                         PropertyAttribute attributes) {
+  return ObjectSetAccessor(
+      this, name, getter, setter, data, settings, attributes);
 }
 
 
@@ -3478,14 +3667,9 @@ bool Object::SetAccessor(Handle<String> name,
                          Handle<DeclaredAccessorDescriptor> descriptor,
                          AccessControl settings,
                          PropertyAttribute attributes) {
-  i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  ON_BAILOUT(isolate, "v8::Object::SetAccessor()", return false);
-  ENTER_V8(isolate);
-  i::HandleScope scope(isolate);
-  v8::Handle<AccessorSignature> signature;
-  i::Handle<i::AccessorInfo> info = MakeAccessorInfo(
-      name, descriptor, settings, attributes, signature);
-  return v8::SetAccessor(this, info);
+  void* null = NULL;
+  return ObjectSetAccessor(
+      this, name, descriptor, null, null, settings, attributes);
 }
 
 
index 9831f08..0765585 100644 (file)
@@ -39,31 +39,6 @@ class ImplementationUtilities {
     return that->names_;
   }
 
-  // Packs additional parameters for the NewArguments function. |implicit_args|
-  // is a pointer to the last element of 4-elements array controlled by GC.
-  static void PrepareArgumentsData(internal::Object** implicit_args,
-                                   internal::Isolate* isolate,
-                                   internal::Object* data,
-                                   internal::JSFunction* callee,
-                                   internal::Object* holder) {
-    implicit_args[v8::Arguments::kDataIndex] = data;
-    implicit_args[v8::Arguments::kCalleeIndex] = callee;
-    implicit_args[v8::Arguments::kHolderIndex] = holder;
-    implicit_args[v8::Arguments::kIsolateIndex] =
-        reinterpret_cast<internal::Object*>(isolate);
-  }
-
-  static v8::Arguments NewArguments(internal::Object** implicit_args,
-                                    internal::Object** argv, int argc,
-                                    bool is_construct_call) {
-    ASSERT(implicit_args[v8::Arguments::kCalleeIndex]->IsJSFunction());
-    ASSERT(implicit_args[v8::Arguments::kHolderIndex]->IsHeapObject());
-    // The implicit isolate argument is not tagged and looks like a SMI.
-    ASSERT(implicit_args[v8::Arguments::kIsolateIndex]->IsSmi());
-
-    return v8::Arguments(implicit_args, argv, argc, is_construct_call);
-  }
-
   // Introduce an alias for the handle scope data to allow non-friends
   // to access the HandleScope data.
   typedef v8::HandleScope::Data HandleScopeData;
diff --git a/src/arguments.cc b/src/arguments.cc
new file mode 100644 (file)
index 0000000..091d0b9
--- /dev/null
@@ -0,0 +1,195 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+#include "arguments.h"
+
+namespace v8 {
+namespace internal {
+
+
+static bool Match(void* a, void* b) {
+  return a == b;
+}
+
+
+static uint32_t Hash(void* function) {
+  uintptr_t as_int = reinterpret_cast<uintptr_t>(function);
+  if (sizeof(function) == 4) return static_cast<uint32_t>(as_int);
+  uint64_t as_64 = static_cast<uint64_t>(as_int);
+  return
+      static_cast<uint32_t>(as_64 >> 32) ^
+      static_cast<uint32_t>(as_64);
+}
+
+
+CallbackTable::CallbackTable(): map_(Match, 64) {}
+
+
+bool CallbackTable::Contains(void* function) {
+  ASSERT(function != NULL);
+  return map_.Lookup(function, Hash(function), false) != NULL;
+}
+
+
+void CallbackTable::InsertCallback(Isolate* isolate,
+                           void* function,
+                           bool returns_void) {
+  if (function == NULL) return;
+  // Don't store for performance.
+  if (kStoreVoidFunctions != returns_void) return;
+  CallbackTable* table = isolate->callback_table();
+  if (table == NULL) {
+    table = new CallbackTable();
+    isolate->set_callback_table(table);
+  }
+  typedef HashMap::Entry Entry;
+  Entry* entry = table->map_.Lookup(function, Hash(function), true);
+  ASSERT(entry != NULL);
+  ASSERT(entry->value == NULL || entry->value == function);
+  entry->value = function;
+}
+
+
+template<typename T>
+template<typename V>
+v8::Handle<V> CustomArguments<T>::GetReturnValue(Isolate* isolate) {
+  // Check the ReturnValue.
+  Object** handle = &this->end()[kReturnValueOffset];
+  // Nothing was set, return empty handle as per previous behaviour.
+  if ((*handle)->IsTheHole()) return v8::Handle<V>();
+  return v8::Handle<V>(reinterpret_cast<V*>(handle));
+}
+
+
+v8::Handle<v8::Value> FunctionCallbackArguments::Call(InvocationCallback f) {
+  Isolate* isolate = this->isolate();
+  void* f_as_void = CallbackTable::FunctionToVoidPtr(f);
+  bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void);
+  if (new_style) {
+    FunctionCallback c = reinterpret_cast<FunctionCallback>(f);
+    FunctionCallbackInfo<v8::Value> info(end(),
+                                         argv_,
+                                         argc_,
+                                         is_construct_call_);
+    c(info);
+  } else {
+    v8::Arguments args(end(),
+                       argv_,
+                       argc_,
+                       is_construct_call_);
+    v8::Handle<v8::Value> return_value = f(args);
+    if (!return_value.IsEmpty()) return return_value;
+  }
+  return GetReturnValue<v8::Value>(isolate);
+}
+
+
+#define WRITE_CALL_0(OldFunction, NewFunction, ReturnValue)                    \
+v8::Handle<ReturnValue> PropertyCallbackArguments::Call(OldFunction f) {       \
+  Isolate* isolate = this->isolate();                                          \
+  void* f_as_void = CallbackTable::FunctionToVoidPtr(f);                       \
+  bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void);             \
+  if (new_style) {                                                             \
+    NewFunction c = reinterpret_cast<NewFunction>(f);                          \
+    PropertyCallbackInfo<ReturnValue> info(end());                             \
+    c(info);                                                                   \
+  } else {                                                                     \
+    v8::AccessorInfo info(end());                                              \
+    v8::Handle<ReturnValue> return_value = f(info);                            \
+    if (!return_value.IsEmpty()) return return_value;                          \
+  }                                                                            \
+  return GetReturnValue<ReturnValue>(isolate);                                 \
+}
+
+#define WRITE_CALL_1(OldFunction, NewFunction, ReturnValue, Arg1)              \
+v8::Handle<ReturnValue> PropertyCallbackArguments::Call(OldFunction f,         \
+                                                        Arg1 arg1) {           \
+  Isolate* isolate = this->isolate();                                          \
+  void* f_as_void = CallbackTable::FunctionToVoidPtr(f);                       \
+  bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void);             \
+  if (new_style) {                                                             \
+    NewFunction c = reinterpret_cast<NewFunction>(f);                          \
+    PropertyCallbackInfo<ReturnValue> info(end());                             \
+    c(arg1, info);                                                             \
+  } else {                                                                     \
+    v8::AccessorInfo info(end());                                              \
+    v8::Handle<ReturnValue> return_value = f(arg1, info);                      \
+    if (!return_value.IsEmpty()) return return_value;                          \
+  }                                                                            \
+  return GetReturnValue<ReturnValue>(isolate);                                 \
+}
+
+#define WRITE_CALL_2(OldFunction, NewFunction, ReturnValue, Arg1, Arg2)        \
+v8::Handle<ReturnValue> PropertyCallbackArguments::Call(OldFunction f,         \
+                                                        Arg1 arg1,             \
+                                                        Arg2 arg2) {           \
+  Isolate* isolate = this->isolate();                                          \
+  void* f_as_void = CallbackTable::FunctionToVoidPtr(f);                       \
+  bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void);             \
+  if (new_style) {                                                             \
+    NewFunction c = reinterpret_cast<NewFunction>(f);                          \
+    PropertyCallbackInfo<ReturnValue> info(end());                             \
+    c(arg1, arg2, info);                                                       \
+  } else {                                                                     \
+    v8::AccessorInfo info(end());                                              \
+    v8::Handle<ReturnValue> return_value = f(arg1, arg2, info);                \
+    if (!return_value.IsEmpty()) return return_value;                          \
+  }                                                                            \
+  return GetReturnValue<ReturnValue>(isolate);                                 \
+}
+
+#define WRITE_CALL_2_VOID(OldFunction, NewFunction, ReturnValue, Arg1, Arg2)   \
+void PropertyCallbackArguments::Call(OldFunction f,                            \
+                                     Arg1 arg1,                                \
+                                     Arg2 arg2) {                              \
+  Isolate* isolate = this->isolate();                                          \
+  void* f_as_void = CallbackTable::FunctionToVoidPtr(f);                       \
+  bool new_style = CallbackTable::ReturnsVoid(isolate, f_as_void);             \
+  if (new_style) {                                                             \
+    NewFunction c = reinterpret_cast<NewFunction>(f);                          \
+    PropertyCallbackInfo<ReturnValue> info(end());                             \
+    c(arg1, arg2, info);                                                       \
+  } else {                                                                     \
+    v8::AccessorInfo info(end());                                              \
+    f(arg1, arg2, info);                                                       \
+  }                                                                            \
+}
+
+FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0)
+FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1)
+FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2)
+FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID)
+
+#undef WRITE_CALL_0
+#undef WRITE_CALL_1
+#undef WRITE_CALL_2
+#undef WRITE_CALL_2_VOID
+
+
+} }  // namespace v8::internal
+
index 1423d56..a80b613 100644 (file)
@@ -82,35 +82,258 @@ class Arguments BASE_EMBEDDED {
 };
 
 
+// mappings from old property callbacks to new ones
+// F(old name, new name, return value, parameters...)
+//
+// These aren't included in the list as they have duplicate signatures
+// F(NamedPropertyEnumerator, NamedPropertyEnumeratorCallback, ...)
+// F(NamedPropertyGetter, NamedPropertyGetterCallback, ...)
+
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \
+  F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback, v8::Array) \
+
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \
+  F(AccessorGetter, AccessorGetterCallback, v8::Value, v8::Local<v8::String>) \
+  F(NamedPropertyQuery, \
+    NamedPropertyQueryCallback, \
+    v8::Integer, \
+    v8::Local<v8::String>) \
+  F(NamedPropertyDeleter, \
+    NamedPropertyDeleterCallback, \
+    v8::Boolean, \
+    v8::Local<v8::String>) \
+  F(IndexedPropertyGetter, \
+    IndexedPropertyGetterCallback, \
+    v8::Value, \
+    uint32_t) \
+  F(IndexedPropertyQuery, \
+    IndexedPropertyQueryCallback, \
+    v8::Integer, \
+    uint32_t) \
+  F(IndexedPropertyDeleter, \
+    IndexedPropertyDeleterCallback, \
+    v8::Boolean, \
+    uint32_t) \
+
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \
+  F(NamedPropertySetter, \
+    NamedPropertySetterCallback, \
+    v8::Value, \
+    v8::Local<v8::String>, \
+    v8::Local<v8::Value>) \
+  F(IndexedPropertySetter, \
+    IndexedPropertySetterCallback, \
+    v8::Value, \
+    uint32_t, \
+    v8::Local<v8::Value>) \
+
+#define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \
+  F(AccessorSetter, \
+    AccessorSetterCallback, \
+    void, \
+    v8::Local<v8::String>, \
+    v8::Local<v8::Value>) \
+
+// All property callbacks as well as invocation callbacks
+#define FOR_EACH_CALLBACK_TABLE_MAPPING(F) \
+  F(InvocationCallback, FunctionCallback) \
+  F(AccessorGetter, AccessorGetterCallback) \
+  F(AccessorSetter, AccessorSetterCallback) \
+  F(NamedPropertySetter, NamedPropertySetterCallback) \
+  F(NamedPropertyQuery, NamedPropertyQueryCallback) \
+  F(NamedPropertyDeleter, NamedPropertyDeleterCallback) \
+  F(IndexedPropertyGetter, IndexedPropertyGetterCallback) \
+  F(IndexedPropertySetter, IndexedPropertySetterCallback) \
+  F(IndexedPropertyQuery, IndexedPropertyQueryCallback) \
+  F(IndexedPropertyDeleter, IndexedPropertyDeleterCallback) \
+  F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback) \
+
+
+// TODO(dcarney): Remove this class when old callbacks are gone.
+class CallbackTable {
+ public:
+  // TODO(dcarney): Flip this when it makes sense for performance.
+  static const bool kStoreVoidFunctions = true;
+  static inline bool ReturnsVoid(Isolate* isolate, void* function) {
+    CallbackTable* table = isolate->callback_table();
+    bool contains =
+        table != NULL &&
+        table->map_.occupancy() != 0 &&
+        table->Contains(function);
+    return contains == kStoreVoidFunctions;
+  }
+
+  STATIC_ASSERT(sizeof(intptr_t) == sizeof(AccessorGetterCallback));
+
+  template<typename F>
+  static inline void* FunctionToVoidPtr(F function) {
+    return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(function));
+  }
+
+#define WRITE_REGISTER(OldFunction, NewFunction)                    \
+  static OldFunction Register(Isolate* isolate, NewFunction f) {    \
+    InsertCallback(isolate, FunctionToVoidPtr(f), true);            \
+    return reinterpret_cast<OldFunction>(f);                        \
+  }                                                                 \
+                                                                    \
+  static OldFunction Register(Isolate* isolate, OldFunction f) {    \
+    InsertCallback(isolate, FunctionToVoidPtr(f), false);           \
+    return f;                                                       \
+  }
+  FOR_EACH_CALLBACK_TABLE_MAPPING(WRITE_REGISTER)
+#undef WRITE_REGISTER
+
+ private:
+  CallbackTable();
+  bool Contains(void* function);
+  static void InsertCallback(Isolate* isolate,
+                             void* function,
+                             bool returns_void);
+  HashMap map_;
+  DISALLOW_COPY_AND_ASSIGN(CallbackTable);
+};
+
+
 // Custom arguments replicate a small segment of stack that can be
 // accessed through an Arguments object the same way the actual stack
 // can.
-class CustomArguments : public Relocatable {
+template<int kArrayLength>
+class CustomArgumentsBase : public Relocatable {
+ public:
+  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_;
 };
 
 
index ae5978a..a3b21a2 100644 (file)
@@ -2262,7 +2262,9 @@ static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
 
 
 void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
-                                              int stack_space) {
+                                              int stack_space,
+                                              bool returns_handle,
+                                              int return_value_offset) {
   ExternalReference next_address =
       ExternalReference::handle_scope_next_address(isolate());
   const int kNextOffset = 0;
@@ -2308,13 +2310,20 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
   Label promote_scheduled_exception;
   Label delete_allocated_handles;
   Label leave_exit_frame;
-
-  // 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));
index 9a6d930..50f53b3 100644 (file)
@@ -1087,7 +1087,10 @@ class MacroAssembler: public Assembler {
   // from handle and propagates exceptions.  Restores context.  stack_space
   // - space to be unwound on exit (includes the call JS arguments space and
   // the additional space allocated for the fast call).
-  void CallApiFunctionAndReturn(ExternalReference function, int stack_space);
+  void CallApiFunctionAndReturn(ExternalReference function,
+                                int stack_space,
+                                bool returns_handle,
+                                int return_value_offset_from_fp);
 
   // Jump to a runtime routine.
   void JumpToExternalReference(const ExternalReference& builtin);
index 40b3313..86eb0db 100644 (file)
@@ -852,7 +852,7 @@ static void CompileCallLoadPropertyWithInterceptor(
 }
 
 
-static const int kFastApiCallArguments = 4;
+static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
 
 // Reserves space for the extra arguments to API function in the
 // caller's frame.
@@ -881,10 +881,11 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
   //  -- sp[4]              : callee JS function
   //  -- sp[8]              : call data
   //  -- sp[12]             : isolate
-  //  -- sp[16]             : last JS argument
+  //  -- sp[16]             : ReturnValue
+  //  -- sp[20]             : last JS argument
   //  -- ...
-  //  -- sp[(argc + 3) * 4] : first JS argument
-  //  -- sp[(argc + 4) * 4] : receiver
+  //  -- sp[(argc + 4) * 4] : first JS argument
+  //  -- sp[(argc + 5) * 4] : receiver
   // -----------------------------------
   // Get the function and setup the context.
   Handle<JSFunction> function = optimization.constant_function();
@@ -901,11 +902,13 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
     __ Move(r6, call_data);
   }
   __ mov(r7, Operand(ExternalReference::isolate_address(masm->isolate())));
-  // Store JS function, call data and isolate.
+  // Store JS function, call data, isolate and ReturnValue.
   __ stm(ib, sp, r5.bit() | r6.bit() | r7.bit());
+  __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
+  __ str(r5, MemOperand(sp, 4 * kPointerSize));
 
   // Prepare arguments.
-  __ add(r2, sp, Operand(3 * kPointerSize));
+  __ add(r2, sp, Operand(4 * kPointerSize));
 
   // Allocate the v8::Arguments structure in the arguments' space since
   // it's not controlled by GC.
@@ -931,13 +934,17 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
 
   const int kStackUnwindSpace = argc + kFastApiCallArguments + 1;
   Address function_address = v8::ToCData<Address>(api_call_info->callback());
+  bool returns_handle =
+      !CallbackTable::ReturnsVoid(masm->isolate(), function_address);
   ApiFunction fun(function_address);
   ExternalReference ref = ExternalReference(&fun,
                                             ExternalReference::DIRECT_API_CALL,
                                             masm->isolate());
   AllowExternalCallThatCantCauseGC scope(masm);
-
-  __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
+  __ CallApiFunctionAndReturn(ref,
+                              kStackUnwindSpace,
+                              returns_handle,
+                              kFastApiCallArguments + 1);
 }
 
 
@@ -1413,7 +1420,8 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   __ Push(reg, scratch3());
   __ mov(scratch3(),
          Operand(ExternalReference::isolate_address(isolate())));
-  __ Push(scratch3(), name());
+  __ LoadRoot(scratch4(), Heap::kUndefinedValueRootIndex);
+  __ Push(scratch3(), scratch4(), name());
   __ mov(r0, sp);  // r0 = Handle<Name>
 
   const int kApiStackSpace = 1;
@@ -1425,12 +1433,17 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   __ str(scratch2(), MemOperand(sp, 1 * kPointerSize));
   __ add(r1, sp, Operand(1 * kPointerSize));  // r1 = AccessorInfo&
 
-  const int kStackUnwindSpace = 5;
+  const int kStackUnwindSpace = kFastApiCallArguments + 1;
   Address getter_address = v8::ToCData<Address>(callback->getter());
+  bool returns_handle =
+      !CallbackTable::ReturnsVoid(isolate(), getter_address);
   ApiFunction fun(getter_address);
   ExternalReference ref = ExternalReference(
       &fun, ExternalReference::DIRECT_GETTER_CALL, isolate());
-  __ CallApiFunctionAndReturn(ref, kStackUnwindSpace);
+  __ CallApiFunctionAndReturn(ref,
+                              kStackUnwindSpace,
+                              returns_handle,
+                              3);
 }
 
 
index add59eb..81b6005 100644 (file)
@@ -1317,15 +1317,13 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
     LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
     ASSERT(raw_holder->IsJSObject());
 
-    CustomArguments custom(isolate);
-    v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
-        isolate, data_obj, *function, raw_holder);
-
-    v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
-        custom.end(),
-        &args[0] - 1,
-        args.length() - 1,
-        is_construct);
+    FunctionCallbackArguments custom(isolate,
+                                     data_obj,
+                                     *function,
+                                     raw_holder,
+                                     &args[0] - 1,
+                                     args.length() - 1,
+                                     is_construct);
 
     v8::Handle<v8::Value> value;
     {
@@ -1333,7 +1331,7 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
       VMState<EXTERNAL> state(isolate);
       ExternalCallbackScope call_scope(isolate,
                                        v8::ToCData<Address>(callback_obj));
-      value = callback(new_args);
+      value = custom.Call(callback);
     }
     if (value.IsEmpty()) {
       result = heap->undefined_value();
@@ -1396,21 +1394,20 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
     HandleScope scope(isolate);
     LOG(isolate, ApiObjectAccess("call non-function", obj));
 
-    CustomArguments custom(isolate);
-    v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
-        isolate, call_data->data(), constructor, obj);
-    v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
-        custom.end(),
-        &args[0] - 1,
-        args.length() - 1,
-        is_construct_call);
+    FunctionCallbackArguments custom(isolate,
+                                     call_data->data(),
+                                     constructor,
+                                     obj,
+                                     &args[0] - 1,
+                                     args.length() - 1,
+                                     is_construct_call);
     v8::Handle<v8::Value> value;
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
       ExternalCallbackScope call_scope(isolate,
                                        v8::ToCData<Address>(callback_obj));
-      value = callback(new_args);
+      value = custom.Call(callback);
     }
     if (value.IsEmpty()) {
       result = heap->undefined_value();
index 5a5773e..7a8d5c9 100644 (file)
@@ -545,19 +545,14 @@ int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
 }
 
 
-void CustomArguments::IterateInstance(ObjectVisitor* v) {
-  v->VisitPointers(values_, values_ + ARRAY_SIZE(values_));
-}
-
-
 // Compute the property keys from the interceptor.
 // TODO(rossberg): support symbols in API, and filter here if needed.
 v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSReceiver> receiver,
                                                  Handle<JSObject> object) {
   Isolate* isolate = receiver->GetIsolate();
   Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
-  CustomArguments args(isolate, interceptor->data(), *receiver, *object);
-  v8::AccessorInfo info(args.end());
+  PropertyCallbackArguments
+      args(isolate, interceptor->data(), *receiver, *object);
   v8::Handle<v8::Array> result;
   if (!interceptor->enumerator()->IsUndefined()) {
     v8::NamedPropertyEnumerator enum_fun =
@@ -566,7 +561,7 @@ v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSReceiver> receiver,
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = enum_fun(info);
+      result = args.Call(enum_fun);
     }
   }
 #if ENABLE_EXTRA_CHECKS
@@ -581,8 +576,8 @@ v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver,
                                                    Handle<JSObject> object) {
   Isolate* isolate = receiver->GetIsolate();
   Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
-  CustomArguments args(isolate, interceptor->data(), *receiver, *object);
-  v8::AccessorInfo info(args.end());
+  PropertyCallbackArguments
+      args(isolate, interceptor->data(), *receiver, *object);
   v8::Handle<v8::Array> result;
   if (!interceptor->enumerator()->IsUndefined()) {
     v8::IndexedPropertyEnumerator enum_fun =
@@ -591,7 +586,7 @@ v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver,
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = enum_fun(info);
+      result = args.Call(enum_fun);
 #if ENABLE_EXTRA_CHECKS
       CHECK(result.IsEmpty() || v8::Utils::OpenHandle(*result)->IsJSObject());
 #endif
index 175b1ca..5c18cae 100644 (file)
@@ -1954,14 +1954,14 @@ static const bool kReturnHandlesDirectly = false;
 #endif
 
 
-Operand ApiParameterOperand(int index) {
-  return Operand(
-      esp, (index + (kReturnHandlesDirectly ? 0 : 1)) * kPointerSize);
+Operand ApiParameterOperand(int index, bool returns_handle) {
+  int offset = (index +(kReturnHandlesDirectly || !returns_handle ? 0 : 1));
+  return Operand(esp, offset * kPointerSize);
 }
 
 
-void MacroAssembler::PrepareCallApiFunction(int argc) {
-  if (kReturnHandlesDirectly) {
+void MacroAssembler::PrepareCallApiFunction(int argc, bool returns_handle) {
+  if (kReturnHandlesDirectly || !returns_handle) {
     EnterApiExitFrame(argc);
     // When handles are returned directly we don't have to allocate extra
     // space for and pass an out parameter.
@@ -1990,7 +1990,9 @@ void MacroAssembler::PrepareCallApiFunction(int argc) {
 
 
 void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
-                                              int stack_space) {
+                                              int stack_space,
+                                              bool returns_handle,
+                                              int return_value_offset) {
   ExternalReference next_address =
       ExternalReference::handle_scope_next_address(isolate());
   ExternalReference limit_address =
@@ -2026,23 +2028,29 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
     PopSafepointRegisters();
   }
 
-  if (!kReturnHandlesDirectly) {
-    // PrepareCallApiFunction saved pointer to the output slot into
-    // callee-save register esi.
-    mov(eax, Operand(esi, 0));
-  }
-
-  Label empty_handle;
   Label prologue;
+  if (returns_handle) {
+    if (!kReturnHandlesDirectly) {
+      // PrepareCallApiFunction saved pointer to the output slot into
+      // callee-save register esi.
+      mov(eax, Operand(esi, 0));
+    }
+    Label empty_handle;
+    // Check if the result handle holds 0.
+    test(eax, eax);
+    j(zero, &empty_handle);
+    // It was non-zero.  Dereference to get the result value.
+    mov(eax, Operand(eax, 0));
+    jmp(&prologue);
+    bind(&empty_handle);
+  }
+  // Load the value from ReturnValue
+  mov(eax, Operand(ebp, return_value_offset * kPointerSize));
+
   Label promote_scheduled_exception;
   Label delete_allocated_handles;
   Label leave_exit_frame;
 
-  // Check if the result handle holds 0.
-  test(eax, eax);
-  j(zero, &empty_handle);
-  // It was non-zero.  Dereference to get the result value.
-  mov(eax, Operand(eax, 0));
   bind(&prologue);
   // No more valid handles (the result handle was the last one). Restore
   // previous handle scope.
@@ -2098,11 +2106,6 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
   LeaveApiExitFrame();
   ret(stack_space * kPointerSize);
 
-  bind(&empty_handle);
-  // It was zero; the result is undefined.
-  mov(eax, isolate()->factory()->undefined_value());
-  jmp(&prologue);
-
   bind(&promote_scheduled_exception);
   TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
index 519652a..e7a075d 100644 (file)
@@ -769,13 +769,16 @@ class MacroAssembler: public Assembler {
   // Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1)
   // etc. Saves context (esi). If space was reserved for return value then
   // stores the pointer to the reserved slot into esi.
-  void PrepareCallApiFunction(int argc);
+  void PrepareCallApiFunction(int argc, bool returns_handle);
 
   // Calls an API function.  Allocates HandleScope, extracts returned value
   // from handle and propagates exceptions.  Clobbers ebx, edi and
   // caller-save registers.  Restores context.  On return removes
   // stack_space * kPointerSize (GCed).
-  void CallApiFunctionAndReturn(Address function_address, int stack_space);
+  void CallApiFunctionAndReturn(Address function_address,
+                                int stack_space,
+                                bool returns_handle,
+                                int return_value_offset_from_ebp);
 
   // Jump to a runtime routine.
   void JumpToExternalReference(const ExternalReference& ext);
@@ -1010,7 +1013,7 @@ inline Operand GlobalObjectOperand() {
 
 
 // Generates an Operand for saving parameters after PrepareCallApiFunction.
-Operand ApiParameterOperand(int index);
+Operand ApiParameterOperand(int index, bool returns_handle);
 
 
 #ifdef GENERATED_CODE_COVERAGE
index 4805d52..88ea4b2 100644 (file)
@@ -420,7 +420,7 @@ static void CompileCallLoadPropertyWithInterceptor(
 
 
 // Number of pointers to be reserved on stack for fast API call.
-static const int kFastApiCallArguments = 4;
+static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
 
 
 // Reserves space for the extra arguments to API function in the
@@ -469,10 +469,11 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   //                           (first fast api call extra argument)
   //  -- esp[12]             : api call data
   //  -- esp[16]             : isolate
-  //  -- esp[20]             : last argument
+  //  -- esp[20]             : ReturnValue
+  //  -- esp[24]             : last argument
   //  -- ...
-  //  -- esp[(argc + 4) * 4] : first argument
-  //  -- esp[(argc + 5) * 4] : receiver
+  //  -- esp[(argc + 5) * 4] : first argument
+  //  -- esp[(argc + 6) * 4] : receiver
   // -----------------------------------
   // Get the function and setup the context.
   Handle<JSFunction> function = optimization.constant_function();
@@ -492,9 +493,12 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   }
   __ mov(Operand(esp, 4 * kPointerSize),
          Immediate(reinterpret_cast<int>(masm->isolate())));
+  __ mov(Operand(esp, 5 * kPointerSize),
+         masm->isolate()->factory()->undefined_value());
 
   // Prepare arguments.
-  __ lea(eax, Operand(esp, 4 * kPointerSize));
+  STATIC_ASSERT(kFastApiCallArguments == 5);
+  __ lea(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
 
   const int kApiArgc = 1;  // API function gets reference to the v8::Arguments.
 
@@ -502,23 +506,31 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   // it's not controlled by GC.
   const int kApiStackSpace = 4;
 
-  __ PrepareCallApiFunction(kApiArgc + kApiStackSpace);
+  // Function address is a foreign pointer outside V8's heap.
+  Address function_address = v8::ToCData<Address>(api_call_info->callback());
+  bool returns_handle =
+    !CallbackTable::ReturnsVoid(masm->isolate(),
+                                reinterpret_cast<void*>(function_address));
+  __ PrepareCallApiFunction(kApiArgc + kApiStackSpace, returns_handle);
 
-  __ mov(ApiParameterOperand(1), eax);  // v8::Arguments::implicit_args_.
+  // v8::Arguments::implicit_args_.
+  __ mov(ApiParameterOperand(1, returns_handle), eax);
   __ add(eax, Immediate(argc * kPointerSize));
-  __ mov(ApiParameterOperand(2), eax);  // v8::Arguments::values_.
-  __ Set(ApiParameterOperand(3), Immediate(argc));  // v8::Arguments::length_.
+  // v8::Arguments::values_.
+  __ mov(ApiParameterOperand(2, returns_handle), eax);
+  // v8::Arguments::length_.
+  __ Set(ApiParameterOperand(3, returns_handle), Immediate(argc));
   // v8::Arguments::is_construct_call_.
-  __ Set(ApiParameterOperand(4), Immediate(0));
+  __ Set(ApiParameterOperand(4, returns_handle), Immediate(0));
 
   // v8::InvocationCallback's argument.
-  __ lea(eax, ApiParameterOperand(1));
-  __ mov(ApiParameterOperand(0), eax);
+  __ lea(eax, ApiParameterOperand(1, returns_handle));
+  __ mov(ApiParameterOperand(0, returns_handle), eax);
 
-  // Function address is a foreign pointer outside V8's heap.
-  Address function_address = v8::ToCData<Address>(api_call_info->callback());
   __ CallApiFunctionAndReturn(function_address,
-                              argc + kFastApiCallArguments + 1);
+                              argc + kFastApiCallArguments + 1,
+                              returns_handle,
+                              kFastApiCallArguments + 1);
 }
 
 
@@ -1365,6 +1377,7 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
     __ push(Immediate(Handle<Object>(callback->data(), isolate())));
   }
   __ push(Immediate(reinterpret_cast<int>(isolate())));
+  __ push(Immediate(isolate()->factory()->undefined_value()));  // ReturnValue
 
   // Save a pointer to where we pushed the arguments pointer.  This will be
   // passed as the const ExecutableAccessorInfo& to the C++ callback.
@@ -1375,22 +1388,29 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
 
   __ push(scratch3());  // Restore return address.
 
-  // 4 elements array for v8::Arguments::values_, handler for name and pointer
+  // array for v8::Arguments::values_, handler for name and pointer
   // to the values (it considered as smi in GC).
-  const int kStackSpace = 6;
+  const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
   const int kApiArgc = 2;
 
-  __ PrepareCallApiFunction(kApiArgc);
-  __ mov(ApiParameterOperand(0), ebx);  // name.
+  Address getter_address = v8::ToCData<Address>(callback->getter());
+  bool returns_handle =
+    !CallbackTable::ReturnsVoid(isolate(),
+                                reinterpret_cast<void*>(getter_address));
+  __ PrepareCallApiFunction(kApiArgc, returns_handle);
+  __ mov(ApiParameterOperand(0, returns_handle), ebx);  // name.
   __ add(ebx, Immediate(kPointerSize));
-  __ mov(ApiParameterOperand(1), ebx);  // arguments pointer.
+  __ mov(ApiParameterOperand(1, returns_handle), ebx);  // arguments pointer.
 
   // Emitting a stub call may try to allocate (if the code is not
   // already generated).  Do not allow the assembler to perform a
   // garbage collection but instead return the allocation failure
   // object.
-  Address getter_address = v8::ToCData<Address>(callback->getter());
-  __ CallApiFunctionAndReturn(getter_address, kStackSpace);
+
+  __ CallApiFunctionAndReturn(getter_address,
+                              kStackSpace,
+                              returns_handle,
+                              4);
 }
 
 
@@ -2493,7 +2513,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
                   name, depth, &miss);
 
   // Move the return address on top of the stack.
-  __ mov(eax, Operand(esp, 4 * kPointerSize));
+  __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
   __ mov(Operand(esp, 0 * kPointerSize), eax);
 
   // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
index 2f36063..bb102cc 100644 (file)
@@ -1752,7 +1752,8 @@ Isolate::Isolate()
       deferred_handles_head_(NULL),
       optimizing_compiler_thread_(this),
       marking_thread_(NULL),
-      sweeper_thread_(NULL) {
+      sweeper_thread_(NULL),
+      callback_table_(NULL) {
   id_ = NoBarrier_AtomicIncrement(&isolate_counter_, 1);
   TRACE_ISOLATE(constructor);
 
index ab32987..84c3fb6 100644 (file)
@@ -51,6 +51,7 @@ namespace v8 {
 namespace internal {
 
 class Bootstrapper;
+class CallbackTable;
 class CodeGenerator;
 class CodeRange;
 struct CodeStubInterfaceDescriptor;
@@ -1102,6 +1103,13 @@ class Isolate {
     return sweeper_thread_;
   }
 
+  CallbackTable* callback_table() {
+    return callback_table_;
+  }
+  void set_callback_table(CallbackTable* callback_table) {
+    callback_table_ = callback_table;
+  }
+
   HStatistics* GetHStatistics();
   HTracer* GetHTracer();
 
@@ -1339,6 +1347,7 @@ class Isolate {
   OptimizingCompilerThread optimizing_compiler_thread_;
   MarkingThread** marking_thread_;
   SweeperThread** sweeper_thread_;
+  CallbackTable* callback_table_;
 
   friend class ExecutionAccess;
   friend class HandleScopeImplementer;
index ee0ff51..16d38a6 100644 (file)
@@ -339,13 +339,12 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
     JSObject* self = JSObject::cast(receiver);
     Handle<String> key(String::cast(name));
     LOG(isolate, ApiNamedPropertyAccess("load", self, name));
-    CustomArguments args(isolate, data->data(), self, this);
-    v8::AccessorInfo info(args.end());
+    PropertyCallbackArguments args(isolate, data->data(), self, this);
     v8::Handle<v8::Value> result;
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = call_fun(v8::Utils::ToLocal(key), info);
+      result = args.Call(call_fun, v8::Utils::ToLocal(key));
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     if (result.IsEmpty()) {
@@ -2640,8 +2639,7 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
   Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
   if (!interceptor->setter()->IsUndefined()) {
     LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
-    CustomArguments args(isolate, interceptor->data(), this, this);
-    v8::AccessorInfo info(args.end());
+    PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
     v8::NamedPropertySetter setter =
         v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
     v8::Handle<v8::Value> result;
@@ -2652,9 +2650,9 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
                                   isolate->heap()->undefined_value() :
                                   value,
                                   isolate);
-      result = setter(v8::Utils::ToLocal(name_handle),
-                      v8::Utils::ToLocal(value_unhole),
-                      info);
+      result = args.Call(setter,
+                         v8::Utils::ToLocal(name_handle),
+                         v8::Utils::ToLocal(value_unhole));
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     if (!result.IsEmpty()) return *value_handle;
@@ -2754,14 +2752,14 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
     if (call_fun == NULL) return value;
     Handle<String> key(String::cast(name));
     LOG(isolate, ApiNamedPropertyAccess("store", this, name));
-    CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
-    v8::AccessorInfo info(args.end());
+    PropertyCallbackArguments
+      args(isolate, data->data(), this, JSObject::cast(holder));
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      call_fun(v8::Utils::ToLocal(key),
-               v8::Utils::ToLocal(value_handle),
-               info);
+      args.Call(call_fun,
+                v8::Utils::ToLocal(key),
+                v8::Utils::ToLocal(value_handle));
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     return *value_handle;
@@ -4063,8 +4061,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
   Handle<JSObject> receiver_handle(receiver);
   Handle<JSObject> holder_handle(this);
   Handle<String> name_handle(String::cast(name));
-  CustomArguments args(isolate, interceptor->data(), receiver, this);
-  v8::AccessorInfo info(args.end());
+  PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this);
   if (!interceptor->query()->IsUndefined()) {
     v8::NamedPropertyQuery query =
         v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
@@ -4074,7 +4071,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = query(v8::Utils::ToLocal(name_handle), info);
+      result = args.Call(query, v8::Utils::ToLocal(name_handle));
     }
     if (!result.IsEmpty()) {
       ASSERT(result->IsInt32());
@@ -4089,7 +4086,7 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = getter(v8::Utils::ToLocal(name_handle), info);
+      result = args.Call(getter, v8::Utils::ToLocal(name_handle));
     }
     if (!result.IsEmpty()) return DONT_ENUM;
   }
@@ -4204,8 +4201,7 @@ PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
   Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
   Handle<JSReceiver> hreceiver(receiver);
   Handle<JSObject> holder(this);
-  CustomArguments args(isolate, interceptor->data(), receiver, this);
-  v8::AccessorInfo info(args.end());
+  PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this);
   if (!interceptor->query()->IsUndefined()) {
     v8::IndexedPropertyQuery query =
         v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
@@ -4215,7 +4211,7 @@ PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = query(index, info);
+      result = args.Call(query, index);
     }
     if (!result.IsEmpty())
       return static_cast<PropertyAttributes>(result->Int32Value());
@@ -4228,7 +4224,7 @@ PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = getter(index, info);
+      result = args.Call(getter, index);
     }
     if (!result.IsEmpty()) return NONE;
   }
@@ -4892,13 +4888,12 @@ MaybeObject* JSObject::DeletePropertyWithInterceptor(Name* name) {
         v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
     LOG(isolate,
         ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
-    CustomArguments args(isolate, interceptor->data(), this, this);
-    v8::AccessorInfo info(args.end());
+    PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
     v8::Handle<v8::Boolean> result;
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = deleter(v8::Utils::ToLocal(name_handle), info);
+      result = args.Call(deleter, v8::Utils::ToLocal(name_handle));
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     if (!result.IsEmpty()) {
@@ -4929,13 +4924,12 @@ MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
   Handle<JSObject> this_handle(this);
   LOG(isolate,
       ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
-  CustomArguments args(isolate, interceptor->data(), this, this);
-  v8::AccessorInfo info(args.end());
+  PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
   v8::Handle<v8::Boolean> result;
   {
     // Leaving JavaScript.
     VMState<EXTERNAL> state(isolate);
-    result = deleter(index, info);
+    result = args.Call(deleter, index);
   }
   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   if (!result.IsEmpty()) {
@@ -11132,13 +11126,12 @@ MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
         v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
     LOG(isolate,
         ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
-    CustomArguments args(isolate, interceptor->data(), this, this);
-    v8::AccessorInfo info(args.end());
+    PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
     v8::Handle<v8::Value> result;
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = setter(index, v8::Utils::ToLocal(value_handle), info);
+      result = args.Call(setter, index, v8::Utils::ToLocal(value_handle));
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     if (!result.IsEmpty()) return *value_handle;
@@ -11175,13 +11168,13 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
     Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
     Handle<String> key = isolate->factory()->NumberToString(number);
     LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
-    CustomArguments args(isolate, data->data(), *self, *holder_handle);
-    v8::AccessorInfo info(args.end());
+    PropertyCallbackArguments
+        args(isolate, data->data(), *self, *holder_handle);
     v8::Handle<v8::Value> result;
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = call_fun(v8::Utils::ToLocal(key), info);
+      result = args.Call(call_fun, v8::Utils::ToLocal(key));
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     if (result.IsEmpty()) return isolate->heap()->undefined_value();
@@ -11242,14 +11235,14 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure,
     Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
     Handle<String> key(isolate->factory()->NumberToString(number));
     LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
-    CustomArguments args(isolate, data->data(), *self, *holder_handle);
-    v8::AccessorInfo info(args.end());
+    PropertyCallbackArguments
+        args(isolate, data->data(), *self, *holder_handle);
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      call_fun(v8::Utils::ToLocal(key),
-               v8::Utils::ToLocal(value_handle),
-               info);
+      args.Call(call_fun,
+                v8::Utils::ToLocal(key),
+                v8::Utils::ToLocal(value_handle));
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     return *value_handle;
@@ -12133,13 +12126,13 @@ MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
         v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
     LOG(isolate,
         ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
-    CustomArguments args(isolate, interceptor->data(), receiver, this);
-    v8::AccessorInfo info(args.end());
+    PropertyCallbackArguments
+        args(isolate, interceptor->data(), receiver, this);
     v8::Handle<v8::Value> result;
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = getter(index, info);
+      result = args.Call(getter, index);
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     if (!result.IsEmpty()) {
@@ -12443,13 +12436,13 @@ MaybeObject* JSObject::GetPropertyWithInterceptor(
         v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
     LOG(isolate,
         ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
-    CustomArguments args(isolate, interceptor->data(), receiver, this);
-    v8::AccessorInfo info(args.end());
+    PropertyCallbackArguments
+        args(isolate, interceptor->data(), receiver, this);
     v8::Handle<v8::Value> result;
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      result = getter(v8::Utils::ToLocal(name_handle), info);
+      result = args.Call(getter, v8::Utils::ToLocal(name_handle));
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     if (!result.IsEmpty()) {
index 89dee10..a613ced 100644 (file)
@@ -1104,13 +1104,13 @@ RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
   Handle<String> str = Handle<String>::cast(name);
 
   LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
-  CustomArguments custom_args(isolate, callback->data(), recv, recv);
-  v8::AccessorInfo info(custom_args.end());
+  PropertyCallbackArguments
+      custom_args(isolate, callback->data(), recv, recv);
   {
     // Leaving JavaScript.
     VMState<EXTERNAL> state(isolate);
     ExternalCallbackScope call_scope(isolate, setter_address);
-    fun(v8::Utils::ToLocal(str), v8::Utils::ToLocal(value), info);
+    custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value));
   }
   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
   return *value;
@@ -1128,13 +1128,13 @@ static const int kAccessorInfoOffsetInInterceptorArgs = 2;
  * provide any value for the given name.
  */
 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
+  typedef PropertyCallbackArguments PCA;
+  static const int kArgsOffset = kAccessorInfoOffsetInInterceptorArgs;
   Handle<Name> name_handle = args.at<Name>(0);
   Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
-  ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
-  ASSERT(args[2]->IsJSObject());  // Receiver.
-  ASSERT(args[3]->IsJSObject());  // Holder.
-  ASSERT(args[5]->IsSmi());  // Isolate.
-  ASSERT(args.length() == 6);
+  ASSERT(kArgsOffset == 2);
+  // No ReturnValue in interceptors.
+  ASSERT(args.length() == kArgsOffset + PCA::kArgsLength - 1);
 
   // TODO(rossberg): Support symbols in the API.
   if (name_handle->IsSymbol())
@@ -1146,16 +1146,22 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
       FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
   ASSERT(getter != NULL);
 
+  Handle<JSObject> receiver =
+      args.at<JSObject>(kArgsOffset - PCA::kThisIndex);
+  Handle<JSObject> holder =
+      args.at<JSObject>(kArgsOffset - PCA::kHolderIndex);
+  PropertyCallbackArguments callback_args(isolate,
+                                          interceptor_info->data(),
+                                          *receiver,
+                                          *holder);
   {
     // Use the interceptor getter.
-    v8::AccessorInfo info(args.arguments() -
-                          kAccessorInfoOffsetInInterceptorArgs);
     HandleScope scope(isolate);
     v8::Handle<v8::Value> r;
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      r = getter(v8::Utils::ToLocal(name), info);
+      r = callback_args.Call(getter, v8::Utils::ToLocal(name));
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     if (!r.IsEmpty()) {
@@ -1189,12 +1195,17 @@ static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) {
 
 static MaybeObject* LoadWithInterceptor(Arguments* args,
                                         PropertyAttributes* attrs) {
+  typedef PropertyCallbackArguments PCA;
+  static const int kArgsOffset = kAccessorInfoOffsetInInterceptorArgs;
   Handle<Name> name_handle = args->at<Name>(0);
   Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
-  ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
-  Handle<JSObject> receiver_handle = args->at<JSObject>(2);
-  Handle<JSObject> holder_handle = args->at<JSObject>(3);
-  ASSERT(args->length() == 6);
+  ASSERT(kArgsOffset == 2);
+  // No ReturnValue in interceptors.
+  ASSERT(args->length() == kArgsOffset + PCA::kArgsLength - 1);
+  Handle<JSObject> receiver_handle =
+      args->at<JSObject>(kArgsOffset - PCA::kThisIndex);
+  Handle<JSObject> holder_handle =
+      args->at<JSObject>(kArgsOffset - PCA::kHolderIndex);
 
   Isolate* isolate = receiver_handle->GetIsolate();
 
@@ -1209,16 +1220,18 @@ static MaybeObject* LoadWithInterceptor(Arguments* args,
       FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
   ASSERT(getter != NULL);
 
+  PropertyCallbackArguments callback_args(isolate,
+                                          interceptor_info->data(),
+                                          *receiver_handle,
+                                          *holder_handle);
   {
     // Use the interceptor getter.
-    v8::AccessorInfo info(args->arguments() -
-                          kAccessorInfoOffsetInInterceptorArgs);
     HandleScope scope(isolate);
     v8::Handle<v8::Value> r;
     {
       // Leaving JavaScript.
       VMState<EXTERNAL> state(isolate);
-      r = getter(v8::Utils::ToLocal(name), info);
+      r = callback_args.Call(getter, v8::Utils::ToLocal(name));
     }
     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
     if (!r.IsEmpty()) {
index 691894c..31796b1 100644 (file)
@@ -677,8 +677,13 @@ static int Offset(ExternalReference ref0, ExternalReference ref1) {
 }
 
 
-void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) {
+void MacroAssembler::PrepareCallApiFunction(int arg_stack_space,
+                                            bool returns_handle) {
 #if defined(_WIN64) && !defined(__MINGW64__)
+  if (!returns_handle) {
+    EnterApiExitFrame(arg_stack_space);
+    return;
+  }
   // We need to prepare a slot for result handle on stack and put
   // a pointer to it into 1st arg register.
   EnterApiExitFrame(arg_stack_space + 1);
@@ -692,8 +697,9 @@ void MacroAssembler::PrepareCallApiFunction(int arg_stack_space) {
 
 
 void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
-                                              int stack_space) {
-  Label empty_result;
+                                              int stack_space,
+                                              bool returns_handle,
+                                              int return_value_offset) {
   Label prologue;
   Label promote_scheduled_exception;
   Label delete_allocated_handles;
@@ -745,15 +751,25 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
     PopSafepointRegisters();
   }
 
+  // Can skip the result check for new-style callbacks
+  // TODO(dcarney): may need to pass this information down
+  // as some function_addresses might not have been registered
+  if (returns_handle) {
+    Label empty_result;
 #if defined(_WIN64) && !defined(__MINGW64__)
-  // rax keeps a pointer to v8::Handle, unpack it.
-  movq(rax, Operand(rax, 0));
+    // rax keeps a pointer to v8::Handle, unpack it.
+    movq(rax, Operand(rax, 0));
 #endif
-  // Check if the result handle holds 0.
-  testq(rax, rax);
-  j(zero, &empty_result);
-  // It was non-zero.  Dereference to get the result value.
-  movq(rax, Operand(rax, 0));
+    // Check if the result handle holds 0.
+    testq(rax, rax);
+    j(zero, &empty_result);
+    // It was non-zero.  Dereference to get the result value.
+    movq(rax, Operand(rax, 0));
+    jmp(&prologue);
+    bind(&empty_result);
+  }
+  // Load the value from ReturnValue
+  movq(rax, Operand(rbp, return_value_offset * kPointerSize));
   bind(&prologue);
 
   // No more valid handles (the result handle was the last one). Restore
@@ -807,11 +823,6 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
   LeaveApiExitFrame();
   ret(stack_space * kPointerSize);
 
-  bind(&empty_result);
-  // It was zero; the result is undefined.
-  LoadRoot(rax, Heap::kUndefinedValueRootIndex);
-  jmp(&prologue);
-
   bind(&promote_scheduled_exception);
   TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
 
index 76941ff..6c8d5ff 100644 (file)
@@ -1224,13 +1224,16 @@ class MacroAssembler: public Assembler {
   // rcx (rcx must be preserverd until CallApiFunctionAndReturn).  Saves
   // context (rsi).  Clobbers rax.  Allocates arg_stack_space * kPointerSize
   // inside the exit frame (not GCed) accessible via StackSpaceOperand.
-  void PrepareCallApiFunction(int arg_stack_space);
+  void PrepareCallApiFunction(int arg_stack_space, bool returns_handle);
 
   // Calls an API function.  Allocates HandleScope, extracts returned value
   // from handle and propagates exceptions.  Clobbers r14, r15, rbx and
   // caller-save registers.  Restores context.  On return removes
   // stack_space * kPointerSize (GCed).
-  void CallApiFunctionAndReturn(Address function_address, int stack_space);
+  void CallApiFunctionAndReturn(Address function_address,
+                                int stack_space,
+                                bool returns_handle,
+                                int return_value_offset_from_rbp);
 
   // Before calling a C-function from generated code, align arguments on stack.
   // After aligning the frame, arguments must be stored in esp[0], esp[4],
index f0b362b..148f65e 100644 (file)
@@ -398,7 +398,7 @@ static void CompileCallLoadPropertyWithInterceptor(
 
 
 // Number of pointers to be reserved on stack for fast API call.
-static const int kFastApiCallArguments = 4;
+static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength;
 
 
 // Reserves space for the extra arguments to API function in the
@@ -449,10 +449,12 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   //                           (first fast api call extra argument)
   //  -- rsp[24]             : api call data
   //  -- rsp[32]             : isolate
-  //  -- rsp[40]             : last argument
+  //  -- rsp[40]             : ReturnValue
+  //
+  //  -- rsp[48]             : last argument
   //  -- ...
-  //  -- rsp[(argc + 4) * 8] : first argument
-  //  -- rsp[(argc + 5) * 8] : receiver
+  //  -- rsp[(argc + 5) * 8] : first argument
+  //  -- rsp[(argc + 6) * 8] : receiver
   // -----------------------------------
   // Get the function and setup the context.
   Handle<JSFunction> function = optimization.constant_function();
@@ -473,15 +475,23 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   __ movq(kScratchRegister,
           ExternalReference::isolate_address(masm->isolate()));
   __ movq(Operand(rsp, 4 * kPointerSize), kScratchRegister);
+  __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
+  __ movq(Operand(rsp, 5 * kPointerSize), kScratchRegister);
 
   // Prepare arguments.
-  __ lea(rbx, Operand(rsp, 4 * kPointerSize));
+  STATIC_ASSERT(kFastApiCallArguments == 5);
+  __ lea(rbx, Operand(rsp, kFastApiCallArguments * kPointerSize));
+
+  // Function address is a foreign pointer outside V8's heap.
+  Address function_address = v8::ToCData<Address>(api_call_info->callback());
+  bool returns_handle =
+      !CallbackTable::ReturnsVoid(masm->isolate(), function_address);
 
 #if defined(__MINGW64__)
   Register arguments_arg = rcx;
 #elif defined(_WIN64)
   // Win64 uses first register--rcx--for returned value.
-  Register arguments_arg = rdx;
+  Register arguments_arg = returns_handle ? rdx : rcx;
 #else
   Register arguments_arg = rdi;
 #endif
@@ -490,7 +500,7 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   // it's not controlled by GC.
   const int kApiStackSpace = 4;
 
-  __ PrepareCallApiFunction(kApiStackSpace);
+  __ PrepareCallApiFunction(kApiStackSpace, returns_handle);
 
   __ movq(StackSpaceOperand(0), rbx);  // v8::Arguments::implicit_args_.
   __ addq(rbx, Immediate(argc * kPointerSize));
@@ -502,10 +512,10 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   // v8::InvocationCallback's argument.
   __ lea(arguments_arg, StackSpaceOperand(0));
 
-  // Function address is a foreign pointer outside V8's heap.
-  Address function_address = v8::ToCData<Address>(api_call_info->callback());
   __ CallApiFunctionAndReturn(function_address,
-                              argc + kFastApiCallArguments + 1);
+                              argc + kFastApiCallArguments + 1,
+                              returns_handle,
+                              kFastApiCallArguments + 1);
 }
 
 
@@ -1288,18 +1298,24 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   } else {
     __ Push(Handle<Object>(callback->data(), isolate()));
   }
-  __ PushAddress(ExternalReference::isolate_address(isolate()));  // isolate
+  __ PushAddress(ExternalReference::isolate_address(isolate()));
+  __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
+  __ push(kScratchRegister);  // return value
   __ push(name());  // name
   // Save a pointer to where we pushed the arguments pointer.  This will be
   // passed as the const ExecutableAccessorInfo& to the C++ callback.
 
+  Address getter_address = v8::ToCData<Address>(callback->getter());
+  bool returns_handle =
+      !CallbackTable::ReturnsVoid(isolate(), getter_address);
+
 #if defined(__MINGW64__)
   Register accessor_info_arg = rdx;
   Register name_arg = rcx;
 #elif defined(_WIN64)
   // Win64 uses first register--rcx--for returned value.
-  Register accessor_info_arg = r8;
-  Register name_arg = rdx;
+  Register accessor_info_arg = returns_handle ? r8 : rdx;
+  Register name_arg = returns_handle ? rdx : rcx;
 #else
   Register accessor_info_arg = rsi;
   Register name_arg = rdi;
@@ -1309,14 +1325,15 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   __ movq(name_arg, rsp);
   __ push(scratch2());  // Restore return address.
 
-  // 4 elements array for v8::Arguments::values_ and handler for name.
-  const int kStackSpace = 5;
+  // v8::Arguments::values_ and handler for name.
+  const int kStackSpace = PropertyCallbackArguments::kArgsLength + 1;
 
   // Allocate v8::AccessorInfo in non-GCed stack space.
   const int kArgStackSpace = 1;
 
-  __ PrepareCallApiFunction(kArgStackSpace);
-  __ lea(rax, Operand(name_arg, 4 * kPointerSize));
+  __ PrepareCallApiFunction(kArgStackSpace, returns_handle);
+  STATIC_ASSERT(PropertyCallbackArguments::kArgsLength == 5);
+  __ lea(rax, Operand(name_arg, 5 * kPointerSize));
 
   // v8::AccessorInfo::args_.
   __ movq(StackSpaceOperand(0), rax);
@@ -1325,8 +1342,10 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   // could be used to pass arguments.
   __ lea(accessor_info_arg, StackSpaceOperand(0));
 
-  Address getter_address = v8::ToCData<Address>(callback->getter());
-  __ CallApiFunctionAndReturn(getter_address, kStackSpace);
+  __ CallApiFunctionAndReturn(getter_address,
+                              kStackSpace,
+                              returns_handle,
+                              3);
 }
 
 
@@ -2272,7 +2291,7 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
                   name, depth, &miss);
 
   // Move the return address on top of the stack.
-  __ movq(rax, Operand(rsp, 4 * kPointerSize));
+  __ movq(rax, Operand(rsp, kFastApiCallArguments * kPointerSize));
   __ movq(Operand(rsp, 0 * kPointerSize), rax);
 
   GenerateFastApiCall(masm(), optimization, argc);
index 2093dbb..b4f962c 100644 (file)
@@ -805,66 +805,211 @@ THREADED_TEST(GlobalProperties) {
 }
 
 
+template<typename T>
+static void CheckReturnValue(const T& t) {
+  v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
+  i::Object** o = *reinterpret_cast<i::Object***>(&rv);
+  CHECK_EQ(t.GetIsolate(), v8::Isolate::GetCurrent());
+  CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
+}
+
 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
+  CheckReturnValue(args);
+  args.GetReturnValue().Set(v8_str("bad value"));
   return v8_num(102);
 }
 
+static v8::Handle<Value> handle_call_indirect(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  CheckReturnValue(args);
+  args.GetReturnValue().Set(v8_str("bad value"));
+  args.GetReturnValue().Set(v8_num(102));
+  return v8::Handle<Value>();
+}
+
+static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
+  ApiTestFuzzer::Fuzz();
+  CheckReturnValue(info);
+  info.GetReturnValue().Set(v8_str("bad value"));
+  info.GetReturnValue().Set(v8_num(102));
+}
+
 
 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
+  CheckReturnValue(args);
   args.This()->Set(v8_str("x"), v8_num(1));
   args.This()->Set(v8_str("y"), v8_num(2));
+  args.GetReturnValue().Set(v8_str("bad value"));
   return args.This();
 }
 
-static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
+static v8::Handle<Value> construct_call_indirect(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  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());
@@ -4649,7 +4794,10 @@ THREADED_TEST(SetterOnly) {
 THREADED_TEST(NoAccessors) {
   v8::HandleScope scope(v8::Isolate::GetCurrent());
   Local<ObjectTemplate> templ = ObjectTemplate::New();
-  templ->SetAccessor(v8_str("x"), NULL, NULL, v8_str("donut"));
+  templ->SetAccessor(v8_str("x"),
+                     static_cast<v8::AccessorGetter>(NULL),
+                     NULL,
+                     v8_str("donut"));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
@@ -5308,8 +5456,7 @@ THREADED_TEST(UndetectableObject) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
-  Local<v8::FunctionTemplate> desc =
-      v8::FunctionTemplate::New(0, v8::Handle<Value>());
+  Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
 
   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
@@ -5352,8 +5499,7 @@ THREADED_TEST(VoidLiteral) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
-  Local<v8::FunctionTemplate> desc =
-      v8::FunctionTemplate::New(0, v8::Handle<Value>());
+  Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
 
   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
@@ -5396,8 +5542,7 @@ THREADED_TEST(ExtensibleOnUndetectable) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
 
-  Local<v8::FunctionTemplate> desc =
-      v8::FunctionTemplate::New(0, v8::Handle<Value>());
+  Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
 
   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
@@ -10398,6 +10543,7 @@ THREADED_TEST(InterceptorCallICCachedFromGlobal) {
 static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
                                                   const AccessorInfo& info) {
   ApiTestFuzzer::Fuzz();
+  CheckReturnValue(info);
   int* call_count =
       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
   ++(*call_count);
@@ -10410,6 +10556,7 @@ static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
 static v8::Handle<Value> FastApiCallback_TrivialSignature(
     const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
+  CheckReturnValue(args);
   v8::Isolate* isolate = v8::Isolate::GetCurrent();
   CHECK_EQ(isolate, args.GetIsolate());
   CHECK_EQ(args.This(), args.Holder());
@@ -10420,6 +10567,7 @@ static v8::Handle<Value> FastApiCallback_TrivialSignature(
 static v8::Handle<Value> FastApiCallback_SimpleSignature(
     const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
+  CheckReturnValue(args);
   v8::Isolate* isolate = v8::Isolate::GetCurrent();
   CHECK_EQ(isolate, args.GetIsolate());
   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
@@ -10497,29 +10645,59 @@ THREADED_TEST(CallICFastApi_DirectCall_Throw) {
 }
 
 
-v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
-                                           const v8::AccessorInfo& info) {
+static Handle<Value> DoDirectGetter() {
   if (++p_getter_count % 3 == 0) {
     HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
     GenerateSomeGarbage();
   }
+  return v8_str("Direct Getter Result");
+}
+
+static v8::Handle<v8::Value> DirectGetter(Local<String> name,
+                                  const v8::AccessorInfo& info) {
+  CheckReturnValue(info);
+  info.GetReturnValue().Set(v8_str("Garbage"));
+  return DoDirectGetter();
+}
+
+static v8::Handle<v8::Value> DirectGetterIndirect(
+    Local<String> name,
+    const v8::AccessorInfo& info) {
+  CheckReturnValue(info);
+  info.GetReturnValue().Set(DoDirectGetter());
   return v8::Handle<v8::Value>();
 }
 
+static void DirectGetterCallback(
+    Local<String> name,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {
+  CheckReturnValue(info);
+  info.GetReturnValue().Set(DoDirectGetter());
+}
 
-THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
+
+template<typename Accessor>
+static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
   LocalContext context;
   v8::HandleScope scope(context->GetIsolate());
   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
-  obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
+  obj->SetAccessor(v8_str("p1"), accessor);
   context->Global()->Set(v8_str("o1"), obj->NewInstance());
   p_getter_count = 0;
-  CompileRun(
+  v8::Handle<v8::Value> result = CompileRun(
       "function f() {"
       "  for (var i = 0; i < 30; i++) o1.p1;"
+      "  return o1.p1"
       "}"
       "f();");
-  CHECK_EQ(30, p_getter_count);
+  CHECK_EQ(v8_str("Direct Getter Result"), result);
+  CHECK_EQ(31, p_getter_count);
+}
+
+THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
+  LoadICFastApi_DirectCall_GCMoveStub(DirectGetterIndirect);
+  LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
+  LoadICFastApi_DirectCall_GCMoveStub(DirectGetter);
 }
 
 
@@ -11198,7 +11376,7 @@ THREADED_TEST(InterceptorICSetterExceptions) {
 THREADED_TEST(NullNamedInterceptor) {
   v8::HandleScope scope(v8::Isolate::GetCurrent());
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
-  templ->SetNamedPropertyHandler(0);
+  templ->SetNamedPropertyHandler(static_cast<v8::NamedPropertyGetter>(0));
   LocalContext context;
   templ->Set("x", v8_num(42));
   v8::Handle<v8::Object> obj = templ->NewInstance();
@@ -11213,7 +11391,7 @@ THREADED_TEST(NullNamedInterceptor) {
 THREADED_TEST(NullIndexedInterceptor) {
   v8::HandleScope scope(v8::Isolate::GetCurrent());
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
-  templ->SetIndexedPropertyHandler(0);
+  templ->SetIndexedPropertyHandler(static_cast<v8::IndexedPropertyGetter>(0));
   LocalContext context;
   templ->Set("42", v8_num(42));
   v8::Handle<v8::Object> obj = templ->NewInstance();
index ba8312b..f31fc4a 100644 (file)
         '../../src/api.cc',
         '../../src/api.h',
         '../../src/apiutils.h',
+        '../../src/arguments.cc',
         '../../src/arguments.h',
         '../../src/assembler.cc',
         '../../src/assembler.h',