Bug 1131855 - Store bound function target in a slot. r=terrence
authorTom Schuster <evilpies@gmail.com>
Wed, 11 Feb 2015 22:39:02 +0100
changeset 228773 cae2905182387f3424e7092a4893a03dad263899
parent 228772 4cea294700c1efb42f2e5a93644839b0e81c1052
child 228774 ee592ac6cc90b1248f7d1a84bee4b64d85c8ba94
push idunknown
push userunknown
push dateunknown
reviewersterrence
bugs1131855
milestone38.0a1
Bug 1131855 - Store bound function target in a slot. r=terrence
js/src/jsfun.cpp
js/src/jsfun.h
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1322,23 +1322,24 @@ js_fun_apply(JSContext *cx, unsigned arg
     // Step 9.
     if (!Invoke(cx, args2))
         return false;
 
     args.rval().set(args2.rval());
     return true;
 }
 
-static const uint32_t JSSLOT_BOUND_FUNCTION_THIS       = 0;
-static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1;
+static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET     = 0;
+static const uint32_t JSSLOT_BOUND_FUNCTION_THIS       = 1;
+static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 2;
 
-static const uint32_t BOUND_FUNCTION_RESERVED_SLOTS = 2;
+static const uint32_t BOUND_FUNCTION_RESERVED_SLOTS = 3;
 
 inline bool
-JSFunction::initBoundFunction(JSContext *cx, HandleValue thisArg,
+JSFunction::initBoundFunction(JSContext *cx, HandleObject target, HandleValue thisArg,
                               const Value *args, unsigned argslen)
 {
     RootedFunction self(cx, this);
 
     /*
      * Convert to a dictionary to set the BOUND_FUNCTION flag and increase
      * the slot span to cover the arguments and additional slots for the 'this'
      * value and arguments count.
@@ -1347,24 +1348,33 @@ JSFunction::initBoundFunction(JSContext 
         return false;
 
     if (!self->setFlag(cx, BaseShape::BOUND_FUNCTION))
         return false;
 
     if (!NativeObject::setSlotSpan(cx, self, BOUND_FUNCTION_RESERVED_SLOTS + argslen))
         return false;
 
+    self->setSlot(JSSLOT_BOUND_FUNCTION_TARGET, ObjectValue(*target));
     self->setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
     self->setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
 
     self->initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen);
 
     return true;
 }
 
+JSObject*
+JSFunction::getBoundFunctionTarget() const
+{
+    MOZ_ASSERT(isBoundFunction());
+
+    return &getSlot(JSSLOT_BOUND_FUNCTION_TARGET).toObject();
+}
+
 const js::Value &
 JSFunction::getBoundFunctionThis() const
 {
     MOZ_ASSERT(isBoundFunction());
 
     return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
 }
 
@@ -1655,31 +1665,27 @@ js_fun_bind(JSContext *cx, HandleObject 
             length = nargs - argslen;
     }
 
     /* Step 4-6, 10-11. */
     RootedAtom name(cx, target->is<JSFunction>() ? target->as<JSFunction>().atom() : nullptr);
 
     JSFunction::Flags flags = target->isConstructor() ? JSFunction::NATIVE_CTOR
                                                       : JSFunction::NATIVE_FUN;
-    RootedObject funobj(cx, NewFunction(cx, js::NullPtr(), CallOrConstructBoundFunction, length,
-                                        flags, target, name));
-    if (!funobj)
+    RootedFunction fun(cx, NewFunction(cx, js::NullPtr(), CallOrConstructBoundFunction, length,
+                                       flags, cx->global(), name));
+    if (!fun)
         return nullptr;
 
-    /* NB: Bound functions abuse |parent| to store their target. */
-    if (!JSObject::setParent(cx, funobj, target))
-        return nullptr;
-
-    if (!funobj->as<JSFunction>().initBoundFunction(cx, thisArg, boundArgs, argslen))
+    if (!fun->initBoundFunction(cx, target, thisArg, boundArgs, argslen))
         return nullptr;
 
     /* Steps 17, 19-21 are handled by fun_resolve. */
     /* Step 18 is the default for new functions. */
-    return funobj;
+    return fun;
 }
 
 /*
  * Report "malformed formal parameter" iff no illegal char or similar scanner
  * error was already reported.
  */
 static bool
 OnBadFormal(JSContext *cx)
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -427,26 +427,20 @@ class JSFunction : public js::NativeObje
     static const js::gc::AllocKind FinalizeKind = js::gc::FINALIZE_OBJECT4_BACKGROUND;
     static const js::gc::AllocKind ExtendedFinalizeKind = js::gc::FINALIZE_OBJECT8_BACKGROUND;
 #endif
 
     inline void trace(JSTracer *trc);
 
     /* Bound function accessors. */
 
-    inline bool initBoundFunction(JSContext *cx, js::HandleValue thisArg,
+    inline bool initBoundFunction(JSContext *cx, js::HandleObject target, js::HandleValue thisArg,
                                   const js::Value *args, unsigned argslen);
 
-    JSObject *getBoundFunctionTarget() const {
-        MOZ_ASSERT(isBoundFunction());
-
-        /* Bound functions abuse |parent| to store their target function. */
-        return getParent();
-    }
-
+    JSObject *getBoundFunctionTarget() const;
     const js::Value &getBoundFunctionThis() const;
     const js::Value &getBoundFunctionArgument(unsigned which) const;
     size_t getBoundFunctionArgumentCount() const;
 
   private:
     inline js::FunctionExtended *toExtended();
     inline const js::FunctionExtended *toExtended() const;