Bug 1320388 - Move JSFunction::HAS_REST to JSScript and LazyScript. r=evilpie
authorTooru Fujisawa <arai_a@mac.com>
Mon, 28 Nov 2016 12:29:19 +0900
changeset 352401 71e72406179d7eade596031badf3aa679da75cfc
parent 352400 b509be16fc198e36e326f7fead273c273e3cd207
child 352402 b4a687eff8e5886dad0e27eadd575091e3905180
push id10621
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 16:02:43 +0000
treeherdermozilla-aurora@dca7b42e6c67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersevilpie
bugs1320388
milestone53.0a1
Bug 1320388 - Move JSFunction::HAS_REST to JSScript and LazyScript. r=evilpie
js/src/builtin/ReflectParse.cpp
js/src/builtin/TypedObject.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/Parser.cpp
js/src/frontend/SharedContext.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/vm/Interpreter.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/Stack.cpp
js/src/wasm/AsmJS.cpp
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -3418,17 +3418,17 @@ ASTSerializer::function(ParseNode* pn, A
     RootedAtom funcAtom(cx, func->name());
     if (!optIdentifier(funcAtom, nullptr, &id))
         return false;
 
     NodeVector args(cx);
     NodeVector defaults(cx);
 
     RootedValue body(cx), rest(cx);
-    if (func->hasRest())
+    if (pn->pn_funbox->hasRest())
         rest.setUndefined();
     else
         rest.setNull();
     return functionArgsAndBody(pn->pn_body, args, defaults, isAsync, isExpression, &body, &rest) &&
            builder.function(type, &pn->pn_pos, id, args, defaults, body,
                             rest, generatorStyle, isAsync, isExpression, dst);
 }
 
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -225,17 +225,17 @@ static const ClassOps ScalarTypeDescrCla
 const Class js::ScalarTypeDescr::class_ = {
     "Scalar",
     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE,
     &ScalarTypeDescrClassOps
 };
 
 const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
-    JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, JSFUN_HAS_REST),
+    JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
     JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
     JS_FS_END
 };
 
 uint32_t
 ScalarTypeDescr::size(Type t)
 {
     return AssertedCast<uint32_t>(Scalar::byteSize(t));
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1048,17 +1048,17 @@ BytecodeEmitter::EmitterScope::enterFunc
             NameLocationMap::AddPtr p = cache.lookupForAdd(bi.name());
 
             // The only duplicate bindings that occur are simple formal
             // parameters, in which case the last position counts, so update the
             // location.
             if (p) {
                 MOZ_ASSERT(bi.kind() == BindingKind::FormalParameter);
                 MOZ_ASSERT(!funbox->hasDestructuringArgs);
-                MOZ_ASSERT(!funbox->function()->hasRest());
+                MOZ_ASSERT(!funbox->hasRest());
                 p->value() = loc;
                 continue;
             }
 
             if (!cache.add(p, bi.name(), loc)) {
                 ReportOutOfMemory(bce->cx);
                 return false;
             }
@@ -8014,17 +8014,17 @@ BytecodeEmitter::isRestParameter(ParseNo
 {
     if (!sc->isFunctionBox()) {
         *result = false;
         return true;
     }
 
     FunctionBox* funbox = sc->asFunctionBox();
     RootedFunction fun(cx, funbox->function());
-    if (!fun->hasRest()) {
+    if (!funbox->hasRest()) {
         *result = false;
         return true;
     }
 
     if (!pn->isKind(PNK_NAME)) {
         if (emitterMode == BytecodeEmitter::SelfHosting && pn->isKind(PNK_CALL)) {
             ParseNode* pn2 = pn->pn_head;
             if (pn2->getKind() == PNK_NAME && pn2->name() == cx->names().allowContentSpread)
@@ -8957,17 +8957,17 @@ BytecodeEmitter::emitFunctionFormalParam
 bool
 BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn)
 {
     ParseNode* funBody = pn->last();
     FunctionBox* funbox = sc->asFunctionBox();
     EmitterScope* funScope = innermostEmitterScope;
 
     bool hasParameterExprs = funbox->hasParameterExprs;
-    bool hasRest = funbox->function()->hasRest();
+    bool hasRest = funbox->hasRest();
 
     uint16_t argSlot = 0;
     for (ParseNode* arg = pn->pn_head; arg != funBody; arg = arg->pn_next, argSlot++) {
         ParseNode* bindingElement = arg;
         ParseNode* initializer = nullptr;
         if (arg->isKind(PNK_ASSIGN)) {
             bindingElement = arg->pn_left;
             initializer = arg->pn_right;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -460,45 +460,43 @@ FunctionBox::FunctionBox(ExclusiveContex
     insideUseAsm(false),
     isAnnexB(false),
     wasEmitted(false),
     declaredArguments(false),
     usesArguments(false),
     usesApply(false),
     usesThis(false),
     usesReturn(false),
+    hasRest_(false),
     funCxFlags()
 {
     // Functions created at parse time may be set singleton after parsing and
     // baked into JIT code, so they must be allocated tenured. They are held by
     // the JSScript so cannot be collected during a minor GC anyway.
     MOZ_ASSERT(fun->isTenured());
 }
 
 void
 FunctionBox::initFromLazyFunction()
 {
     JSFunction* fun = function();
-    length = fun->nargs() - fun->hasRest();
     if (fun->lazyScript()->isDerivedClassConstructor())
         setDerivedClassConstructor();
     if (fun->lazyScript()->needsHomeObject())
         setNeedsHomeObject();
     enclosingScope_ = fun->lazyScript()->enclosingScope();
     initWithEnclosingScope(enclosingScope_);
 }
 
 void
 FunctionBox::initStandaloneFunction(Scope* enclosingScope)
 {
     // Standalone functions are Function or Generator constructors and are
     // always scoped to the global.
     MOZ_ASSERT(enclosingScope->is<GlobalScope>());
-    JSFunction* fun = function();
-    length = fun->nargs() - fun->hasRest();
     enclosingScope_ = enclosingScope;
     allowNewTarget_ = true;
     thisBinding_ = ThisBinding::Function;
 }
 
 void
 FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind)
 {
@@ -2243,16 +2241,18 @@ Parser<SyntaxParseHandler>::finishFuncti
         return false;
 
     // Flags that need to be copied into the JSScript when we do the full
     // parse.
     if (pc->sc()->strict())
         lazy->setStrict();
     lazy->setGeneratorKind(funbox->generatorKind());
     lazy->setAsyncKind(funbox->asyncKind());
+    if (funbox->hasRest())
+        lazy->setHasRest();
     if (funbox->isLikelyConstructorWrapper())
         lazy->setLikelyConstructorWrapper();
     if (funbox->isDerivedClassConstructor())
         lazy->setIsDerivedClassConstructor();
     if (funbox->needsHomeObject())
         lazy->setNeedsHomeObject();
     if (funbox->declaredArguments)
         lazy->setShouldDeclareArguments();
@@ -2806,17 +2806,17 @@ Parser<ParseHandler>::functionArguments(
                 disallowDuplicateParams = true;
                 if (duplicatedParam) {
                     // Has duplicated args before the rest parameter.
                     error(JSMSG_BAD_DUP_ARGS);
                     return false;
                 }
 
                 hasRest = true;
-                funbox->function()->setHasRest();
+                funbox->setHasRest();
 
                 if (!tokenStream.getToken(&tt))
                     return false;
 
                 if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) {
                     error(JSMSG_NO_REST_NAME);
                     return false;
                 }
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -466,16 +466,17 @@ class FunctionBox : public ObjectBox, pu
     bool            wasEmitted:1;           /* Bytecode has been emitted for this function. */
 
     // Fields for use in heuristics.
     bool            declaredArguments:1;    /* the Parser declared 'arguments' */
     bool            usesArguments:1;        /* contains a free use of 'arguments' */
     bool            usesApply:1;            /* contains an f.apply() call */
     bool            usesThis:1;             /* contains 'this' */
     bool            usesReturn:1;           /* contains a 'return' statement */
+    bool            hasRest_:1;             /* has rest parameter */
 
     FunctionContextFlags funCxFlags;
 
     FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
                 Directives directives, bool extraWarnings, GeneratorKind generatorKind,
                 FunctionAsyncKind asyncKind);
 
     MutableHandle<LexicalScope::Data*> namedLambdaBindings() {
@@ -534,16 +535,21 @@ class FunctionBox : public ObjectBox, pu
     GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
     bool isGenerator() const { return generatorKind() != NotGenerator; }
     bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
     bool isStarGenerator() const { return generatorKind() == StarGenerator; }
     FunctionAsyncKind asyncKind() const { return AsyncKindFromBits(asyncKindBits_); }
     bool isAsync() const { return asyncKind() == AsyncFunction; }
     bool isArrow() const { return function()->isArrow(); }
 
+    bool hasRest() const { return hasRest_; }
+    void setHasRest() {
+        hasRest_ = true;
+    }
+
     void setGeneratorKind(GeneratorKind kind) {
         // A generator kind can be set at initialization, or when "yield" is
         // first seen.  In both cases the transition can only happen from
         // NotGenerator.
         MOZ_ASSERT(!isGenerator());
         generatorKindBits_ = GeneratorKindAsBits(kind);
     }
 
@@ -562,17 +568,17 @@ class FunctionBox : public ObjectBox, pu
                                              funCxFlags.definitelyNeedsArgsObj   = true; }
     void setNeedsHomeObject()              { MOZ_ASSERT(function()->allowSuperProperty());
                                              funCxFlags.needsHomeObject          = true; }
     void setDerivedClassConstructor()      { MOZ_ASSERT(function()->isClassConstructor());
                                              funCxFlags.isDerivedClassConstructor = true; }
     void setHasInnerFunctions()            { funCxFlags.hasInnerFunctions         = true; }
 
     bool hasSimpleParameterList() const {
-        return !function()->hasRest() && !hasParameterExprs && !hasDestructuringArgs;
+        return !hasRest() && !hasParameterExprs && !hasDestructuringArgs;
     }
 
     bool hasMappedArgsObj() const {
         return !strict() && hasSimpleParameterList();
     }
 
     // Return whether this or an enclosing function is being parsed and
     // validated as asm.js. Note: if asm.js validation fails, this will be false
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3419,20 +3419,17 @@ JS::NewFunctionFromSpec(JSContext* cx, c
         if (!name)
             return nullptr;
         RootedValue funVal(cx);
         if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, fs->nargs,
                                                  &funVal))
         {
             return nullptr;
         }
-        JSFunction* fun = &funVal.toObject().as<JSFunction>();
-        if (fs->flags & JSFUN_HAS_REST)
-            fun->setHasRest();
-        return fun;
+        return &funVal.toObject().as<JSFunction>();
     }
 
     RootedAtom atom(cx, IdToFunctionName(cx, id));
     if (!atom)
         return nullptr;
 
     JSFunction* fun;
     if (!fs->call.op)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -870,21 +870,17 @@ class MOZ_STACK_CLASS SourceBufferHolder
                                            containing this property */
 #define JSPROP_INTERNAL_USE_BIT 0x80    /* internal JS engine use only */
 #define JSFUN_STUB_GSOPS       0x200    /* use JS_PropertyStub getter/setter
                                            instead of defaulting to class gsops
                                            for property holding function */
 
 #define JSFUN_CONSTRUCTOR      0x400    /* native that can be called as a ctor */
 
-//                             0x800    /* Unused */
-
-#define JSFUN_HAS_REST        0x1000    /* function has ...rest parameter. */
-
-#define JSFUN_FLAGS_MASK      0x1e00    /* | of all the JSFUN_* flags */
+#define JSFUN_FLAGS_MASK       0x600    /* | of all the JSFUN_* flags */
 
 /*
  * If set, will allow redefining a non-configurable property, but only on a
  * non-DOM global.  This is a temporary hack that will need to go away in bug
  * 1105518.
  */
 #define JSPROP_REDEFINE_NONCONFIGURABLE 0x1000
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1271,18 +1271,17 @@ JSFunction::isDerivedClassConstructor()
 
 /* static */ bool
 JSFunction::getLength(JSContext* cx, HandleFunction fun, uint16_t* length)
 {
     MOZ_ASSERT(!fun->isBoundFunction());
     if (fun->isInterpretedLazy() && !getOrCreateScript(cx, fun))
         return false;
 
-    *length = fun->hasScript() ? fun->nonLazyScript()->funLength()
-                               : (fun->nargs() - fun->hasRest());
+    *length = fun->isNative() ? fun->nargs() : fun->nonLazyScript()->funLength();
     return true;
 }
 
 /* static */ bool
 JSFunction::getUnresolvedLength(JSContext* cx, HandleFunction fun, MutableHandleValue v)
 {
     MOZ_ASSERT(!IsInternalFunctionObject(*fun));
     MOZ_ASSERT(!fun->hasResolvedLength());
@@ -1559,17 +1558,17 @@ fun_isGenerator(JSContext* cx, unsigned 
 const JSFunctionSpec js::function_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,   fun_toSource,   0,0),
 #endif
     JS_FN(js_toString_str,   fun_toString,   0,0),
     JS_FN(js_apply_str,      fun_apply,      2,0),
     JS_FN(js_call_str,       fun_call,       1,0),
     JS_FN("isGenerator",     fun_isGenerator,0,0),
-    JS_SELF_HOSTED_FN("bind", "FunctionBind", 2, JSFUN_HAS_REST),
+    JS_SELF_HOSTED_FN("bind", "FunctionBind", 2, 0),
     JS_SYM_FN(hasInstance, fun_symbolHasInstance, 1, JSPROP_READONLY | JSPROP_PERMANENT),
     JS_FS_END
 };
 
 // ES 2017 draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077 19.2.1.1.1.
 static bool
 FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
                     FunctionAsyncKind asyncKind)
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -56,17 +56,16 @@ class JSFunction : public js::NativeObje
                                      * expression closure: function(x) x*x */
         HAS_GUESSED_ATOM = 0x0020,  /* function had no explicit name, but a
                                        name was guessed for it anyway */
         LAMBDA           = 0x0040,  /* function comes from a FunctionExpression, ArrowFunction, or
                                        Function() call (not a FunctionDeclaration or nonstandard
                                        function-statement) */
         SELF_HOSTED      = 0x0080,  /* function is self-hosted builtin and must not be
                                        decompilable nor constructible. */
-        HAS_REST         = 0x0100,  /* function has a rest (...) parameter */
         INTERPRETED_LAZY = 0x0200,  /* function is interpreted but doesn't have a script yet */
         RESOLVED_LENGTH  = 0x0400,  /* f.length has been resolved (see fun_resolve). */
         RESOLVED_NAME    = 0x0800,  /* f.name has been resolved (see fun_resolve). */
 
         FUNCTION_KIND_SHIFT = 13,
         FUNCTION_KIND_MASK  = 0x7 << FUNCTION_KIND_SHIFT,
 
         ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
@@ -90,17 +89,17 @@ class JSFunction : public js::NativeObje
         INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
         INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
         INTERPRETED_LAMBDA_GENERATOR = INTERPRETED | LAMBDA,
         INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR,
         INTERPRETED_GENERATOR = INTERPRETED,
         NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
 
         STABLE_ACROSS_CLONES = CONSTRUCTOR | EXPR_BODY | HAS_GUESSED_ATOM | LAMBDA |
-                               SELF_HOSTED |  HAS_REST | FUNCTION_KIND_MASK
+                               SELF_HOSTED | FUNCTION_KIND_MASK
     };
 
     static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS,
                   "jsfriendapi.h's JSFunction::INTERPRETED-alike is wrong");
     static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= FUNCTION_KIND_MASK,
                   "FunctionKind doesn't fit into flags_");
 
   private:
@@ -178,17 +177,16 @@ class JSFunction : public js::NativeObje
     /* Possible attributes of a native function: */
     bool isAsmJSNative()            const { return kind() == AsmJS; }
 
     /* Possible attributes of an interpreted function: */
     bool isExprBody()               const { return flags() & EXPR_BODY; }
     bool hasGuessedAtom()           const { return flags() & HAS_GUESSED_ATOM; }
     bool isLambda()                 const { return flags() & LAMBDA; }
     bool isBoundFunction()          const { return flags() & BOUND_FUN; }
-    bool hasRest()                  const { return flags() & HAS_REST; }
     bool isInterpretedLazy()        const { return flags() & INTERPRETED_LAZY; }
     bool hasScript()                const { return flags() & INTERPRETED; }
 
     bool infallibleIsDefaultClassConstructor(JSContext* cx) const;
 
     // Arrow functions store their lexical new.target in the first extended slot.
     bool isArrow()                  const { return kind() == Arrow; }
     // Every class-constructor is also a method.
@@ -259,21 +257,16 @@ class JSFunction : public js::NativeObje
         setKind(ClassConstructor);
     }
 
     // Can be called multiple times by the parser.
     void setArgCount(uint16_t nargs) {
         this->nargs_ = nargs;
     }
 
-    // Can be called multiple times by the parser.
-    void setHasRest() {
-        flags_ |= HAS_REST;
-    }
-
     void setIsBoundFunction() {
         MOZ_ASSERT(!isBoundFunction());
         flags_ |= BOUND_FUN;
     }
 
     void setIsSelfHostedBuiltin() {
         MOZ_ASSERT(isInterpreted());
         MOZ_ASSERT(!isSelfHostedBuiltin());
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -312,16 +312,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl
         NeedsArgsObj,
         HasMappedArgsObj,
         FunctionHasThisBinding,
         FunctionHasExtraBodyVarScope,
         IsGeneratorExp,
         IsLegacyGenerator,
         IsStarGenerator,
         IsAsync,
+        HasRest,
         OwnSource,
         ExplicitUseStrict,
         SelfHosted,
         HasSingleton,
         TreatAsRunOnce,
         HasLazyScript,
         HasNonSyntacticScope,
         HasInnerFunctions,
@@ -427,16 +428,18 @@ js::XDRScript(XDRState<mode>* xdr, Handl
         if (script->isGeneratorExp())
             scriptBits |= (1 << IsGeneratorExp);
         if (script->isLegacyGenerator())
             scriptBits |= (1 << IsLegacyGenerator);
         if (script->isStarGenerator())
             scriptBits |= (1 << IsStarGenerator);
         if (script->asyncKind() == AsyncFunction)
             scriptBits |= (1 << IsAsync);
+        if (script->hasRest())
+            scriptBits |= (1 << HasRest);
         if (script->hasSingletons())
             scriptBits |= (1 << HasSingleton);
         if (script->treatAsRunOnce())
             scriptBits |= (1 << TreatAsRunOnce);
         if (script->isRelazifiable())
             scriptBits |= (1 << HasLazyScript);
         if (script->hasNonSyntacticScope())
             scriptBits |= (1 << HasNonSyntacticScope);
@@ -578,16 +581,18 @@ js::XDRScript(XDRState<mode>* xdr, Handl
         if (scriptBits & (1 << IsLegacyGenerator)) {
             MOZ_ASSERT(!(scriptBits & (1 << IsStarGenerator)));
             script->setGeneratorKind(LegacyGenerator);
         } else if (scriptBits & (1 << IsStarGenerator))
             script->setGeneratorKind(StarGenerator);
 
         if (scriptBits & (1 << IsAsync))
             script->setAsyncKind(AsyncFunction);
+        if (scriptBits & (1 << HasRest))
+            script->setHasRest();
     }
 
     JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
     JS_STATIC_ASSERT(sizeof(jssrcnote) == 1);
 
     if (scriptBits & (1 << OwnSource)) {
         if (!script->scriptSource()->performXDR<mode>(xdr))
             return false;
@@ -2618,16 +2623,18 @@ JSScript::initFromFunctionBox(ExclusiveC
     script->functionHasThisBinding_ = funbox->hasThisBinding();
     script->functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
 
     script->funLength_ = funbox->length;
 
     script->isGeneratorExp_ = funbox->isGenexpLambda;
     script->setGeneratorKind(funbox->generatorKind());
     script->setAsyncKind(funbox->asyncKind());
+    if (funbox->hasRest())
+        script->setHasRest();
 
     PositionalFormalParameterIter fi(script);
     while (fi && !fi.closedOver())
         fi++;
     script->funHasAnyAliasedFormal_ = !!fi;
 
     script->setHasInnerFunctions(funbox->hasInnerFunctions());
 }
@@ -3278,16 +3285,17 @@ js::detail::CopyScript(JSContext* cx, Ha
     dst->treatAsRunOnce_ = src->treatAsRunOnce();
     dst->hasInnerFunctions_ = src->hasInnerFunctions();
     dst->isGeneratorExp_ = src->isGeneratorExp();
     dst->setGeneratorKind(src->generatorKind());
     dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
     dst->needsHomeObject_ = src->needsHomeObject();
     dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
     dst->isAsync_ = src->asyncKind() == AsyncFunction;
+    dst->hasRest_ = src->hasRest_;
 
     if (nconsts != 0) {
         GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
         dst->consts()->vector = vector;
         for (unsigned i = 0; i < nconsts; ++i)
             MOZ_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom());
     }
     if (nobjects != 0) {
@@ -4011,16 +4019,17 @@ LazyScript::Create(ExclusiveContext* cx,
         PackedView p;
         uint64_t packedFields;
     };
 
     p.version = version;
     p.shouldDeclareArguments = false;
     p.hasThisBinding = false;
     p.isAsync = false;
+    p.hasRest = false;
     p.numClosedOverBindings = closedOverBindings.length();
     p.numInnerFunctions = innerFunctions.length();
     p.generatorKindBits = GeneratorKindAsBits(NotGenerator);
     p.strict = false;
     p.bindingsAccessedDynamically = false;
     p.hasDebuggerStatement = false;
     p.hasDirectEval = false;
     p.isLikelyConstructorWrapper = false;
@@ -4152,17 +4161,17 @@ JSScript::hasLoops()
             return true;
     }
     return false;
 }
 
 bool
 JSScript::mayReadFrameArgsDirectly()
 {
-    return argumentsHasVarBinding() || (function() && function()->hasRest());
+    return argumentsHasVarBinding() || hasRest();
 }
 
 static inline void
 LazyScriptHash(uint32_t lineno, uint32_t column, uint32_t begin, uint32_t end,
                HashNumber hashes[3])
 {
     HashNumber hash = lineno;
     hash = RotateLeft(hash, 4) ^ column;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1007,16 +1007,18 @@ class JSScript : public js::gc::TenuredC
 
     bool needsHomeObject_:1;
 
     bool isDerivedClassConstructor_:1;
     bool isDefaultClassConstructor_:1;
 
     bool isAsync_:1;
 
+    bool hasRest_:1;
+
     // Add padding so JSScript is gc::Cell aligned. Make padding protected
     // instead of private to suppress -Wunused-private-field compiler warnings.
   protected:
 #if JS_BITS_PER_WORD == 32
     // Currently no padding is needed.
 #endif
 
     //
@@ -1303,16 +1305,23 @@ class JSScript : public js::gc::TenuredC
     js::FunctionAsyncKind asyncKind() const {
         return isAsync_ ? js::AsyncFunction : js::SyncFunction;
     }
 
     void setAsyncKind(js::FunctionAsyncKind kind) {
         isAsync_ = kind == js::AsyncFunction;
     }
 
+    bool hasRest() const {
+        return hasRest_;
+    }
+    void setHasRest() {
+        hasRest_ = true;
+    }
+
     void setNeedsHomeObject() {
         needsHomeObject_ = true;
     }
     bool needsHomeObject() const {
         return needsHomeObject_;
     }
 
     bool isDerivedClassConstructor() const {
@@ -1935,16 +1944,17 @@ class LazyScript : public gc::TenuredCel
         uint32_t bindingsAccessedDynamically : 1;
         uint32_t hasDebuggerStatement : 1;
         uint32_t hasDirectEval : 1;
         uint32_t isLikelyConstructorWrapper : 1;
         uint32_t hasBeenCloned : 1;
         uint32_t treatAsRunOnce : 1;
         uint32_t isDerivedClassConstructor : 1;
         uint32_t needsHomeObject : 1;
+        uint32_t hasRest : 1;
     };
 
     union {
         PackedView p_;
         uint64_t packedFields_;
     };
 
     // Source location for the script.
@@ -2063,16 +2073,23 @@ class LazyScript : public gc::TenuredCel
     FunctionAsyncKind asyncKind() const {
         return p_.isAsync ? AsyncFunction : SyncFunction;
     }
 
     void setAsyncKind(FunctionAsyncKind kind) {
         p_.isAsync = kind == AsyncFunction;
     }
 
+    bool hasRest() const {
+        return p_.hasRest;
+    }
+    void setHasRest() {
+        p_.hasRest = true;
+    }
+
     bool strict() const {
         return p_.strict;
     }
     void setStrict() {
         p_.strict = true;
     }
 
     bool bindingsAccessedDynamically() const {
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2951,17 +2951,17 @@ js::str_fromCodePoint(JSContext* cx, uns
     args.rval().setString(str);
     return true;
 }
 
 static const JSFunctionSpec string_static_methods[] = {
     JS_INLINABLE_FN("fromCharCode", js::str_fromCharCode, 1, 0, StringFromCharCode),
     JS_INLINABLE_FN("fromCodePoint", js::str_fromCodePoint, 1, 0, StringFromCodePoint),
 
-    JS_SELF_HOSTED_FN("raw",             "String_static_raw",           2,JSFUN_HAS_REST),
+    JS_SELF_HOSTED_FN("raw",             "String_static_raw",           2,0),
     JS_SELF_HOSTED_FN("substring",       "String_static_substring",     3,0),
     JS_SELF_HOSTED_FN("substr",          "String_static_substr",        3,0),
     JS_SELF_HOSTED_FN("slice",           "String_static_slice",         3,0),
 
     JS_SELF_HOSTED_FN("match",           "String_generic_match",        2,0),
     JS_SELF_HOSTED_FN("replace",         "String_generic_replace",      3,0),
     JS_SELF_HOSTED_FN("search",          "String_generic_search",       2,0),
     JS_SELF_HOSTED_FN("split",           "String_generic_split",        3,0),
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -277,18 +277,16 @@ MakeDefaultConstructor(JSContext* cx, JS
                                                           /* nargs = */ !!derived,
                                                           proto, TenuredObject, &ctor))
     {
         return nullptr;
     }
 
     ctor->setIsConstructor();
     ctor->setIsClassConstructor();
-    if (derived)
-        ctor->setHasRest();
 
     MOZ_ASSERT(ctor->infallibleIsDefaultClassConstructor(cx));
 
     return ctor;
 }
 
 bool
 js::ReportIsNotFunction(JSContext* cx, HandleValue v, int numToSkip, MaybeConstruct construct)
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -3017,17 +3017,17 @@ JSRuntime::cloneSelfHostedFunctionScript
     // invariants.
     MOZ_ASSERT(sourceScript->outermostScope()->enclosing()->kind() == ScopeKind::Global);
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
     if (!CloneScriptIntoFunction(cx, emptyGlobalScope, targetFun, sourceScript))
         return false;
     MOZ_ASSERT(!targetFun->isInterpretedLazy());
 
     MOZ_ASSERT(sourceFun->nargs() == targetFun->nargs());
-    MOZ_ASSERT(sourceFun->hasRest() == targetFun->hasRest());
+    MOZ_ASSERT(sourceScript->hasRest() == targetFun->nonLazyScript()->hasRest());
 
     // The target function might have been relazified after its flags changed.
     targetFun->setFlags(targetFun->flags() | sourceFun->flags());
     return true;
 }
 
 bool
 JSRuntime::getUnclonedSelfHostedValue(JSContext* cx, HandlePropertyName name,
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -80,17 +80,17 @@ bool
 InterpreterFrame::isNonGlobalEvalFrame() const
 {
     return isEvalFrame() && script()->bodyScope()->as<EvalScope>().isNonGlobal();
 }
 
 JSObject*
 InterpreterFrame::createRestParameter(JSContext* cx)
 {
-    MOZ_ASSERT(callee().hasRest());
+    MOZ_ASSERT(script()->hasRest());
     unsigned nformal = callee().nargs() - 1, nactual = numActualArgs();
     unsigned nrest = (nactual > nformal) ? nactual - nformal : 0;
     Value* restvp = argv() + nformal;
     return ObjectGroup::newArrayObject(cx, restvp, nrest, GenericObject,
                                        ObjectGroup::NewArrayKind::UnknownIndex);
 }
 
 static inline void
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -3246,17 +3246,17 @@ CheckModuleLevelName(ModuleValidator& m,
 
     return true;
 }
 
 static bool
 CheckFunctionHead(ModuleValidator& m, ParseNode* fn)
 {
     JSFunction* fun = FunctionObject(fn);
-    if (fun->hasRest())
+    if (fn->pn_funbox->hasRest())
         return m.fail(fn, "rest args not allowed");
     if (fun->isExprBody())
         return m.fail(fn, "expression closures not allowed");
     if (fn->pn_funbox->hasDestructuringArgs)
         return m.fail(fn, "destructuring args not allowed");
     return true;
 }