diff --git a/js/src/vm/JSFunction-inl.h b/js/src/vm/JSFunction-inl.h index e4ee1fc19023..438eb287bef7 100644 --- a/js/src/vm/JSFunction-inl.h +++ b/js/src/vm/JSFunction-inl.h @@ -63,11 +63,27 @@ inline JSFunction* CloneFunctionObjectIfNotSingleton( * the function's script. */ if (CanReuseFunctionForClone(cx, fun)) { - ObjectOpResult succeeded; - if (proto && !SetPrototype(cx, fun, proto, succeeded)) { - return nullptr; + if (proto && proto != fun->staticPrototype()) { + // |CanReuseFunctionForClone| ensures |fun| is a singleton function. |fun| + // must also be extensible and have a mutable prototype for its prototype + // to be modifiable, so assert both conditions, too. + MOZ_ASSERT(fun->isSingleton()); + MOZ_ASSERT(!fun->staticPrototypeIsImmutable()); + MOZ_ASSERT(fun->isExtensible()); + + if (!JSObject::setDelegate(cx, proto)) { + return nullptr; + } + + // Directly splice the prototype instead of calling |js::SetPrototype| to + // ensure we don't mark the function as having "unknown properties". This + // is safe to do, because the singleton function hasn't yet been exposed + // to scripts. + Rooted tagged(cx, TaggedProto(proto)); + if (!JSObject::splicePrototype(cx, fun, tagged)) { + return nullptr; + } } - MOZ_ASSERT(!proto || succeeded); fun->setEnvironment(parent); return fun; }