Bug 1131855 - Store bound function target in a slot. r=terrence
--- 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;