LCOV - code coverage report
Current view: top level - js/src/vm - JSFunction.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 130 1035 12.6 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * JS function support.
       9             :  */
      10             : 
      11             : #include "vm/JSFunction-inl.h"
      12             : 
      13             : #include "mozilla/ArrayUtils.h"
      14             : #include "mozilla/CheckedInt.h"
      15             : #include "mozilla/Maybe.h"
      16             : #include "mozilla/Range.h"
      17             : 
      18             : #include <string.h>
      19             : 
      20             : #include "jsapi.h"
      21             : #include "jstypes.h"
      22             : 
      23             : #include "builtin/Array.h"
      24             : #include "builtin/Eval.h"
      25             : #include "builtin/Object.h"
      26             : #include "builtin/SelfHostingDefines.h"
      27             : #include "builtin/String.h"
      28             : #include "frontend/BytecodeCompiler.h"
      29             : #include "frontend/TokenStream.h"
      30             : #include "gc/Marking.h"
      31             : #include "gc/Policy.h"
      32             : #include "jit/InlinableNatives.h"
      33             : #include "jit/Ion.h"
      34             : #include "js/CallNonGenericMethod.h"
      35             : #include "js/Proxy.h"
      36             : #include "js/Wrapper.h"
      37             : #include "util/StringBuffer.h"
      38             : #include "vm/AsyncFunction.h"
      39             : #include "vm/AsyncIteration.h"
      40             : #include "vm/Debugger.h"
      41             : #include "vm/GlobalObject.h"
      42             : #include "vm/Interpreter.h"
      43             : #include "vm/JSAtom.h"
      44             : #include "vm/JSContext.h"
      45             : #include "vm/JSObject.h"
      46             : #include "vm/JSScript.h"
      47             : #include "vm/SelfHosting.h"
      48             : #include "vm/Shape.h"
      49             : #include "vm/SharedImmutableStringsCache.h"
      50             : #include "vm/WrapperObject.h"
      51             : #include "vm/Xdr.h"
      52             : #include "wasm/AsmJS.h"
      53             : 
      54             : #include "vm/Interpreter-inl.h"
      55             : #include "vm/JSScript-inl.h"
      56             : #include "vm/Stack-inl.h"
      57             : 
      58             : using namespace js;
      59             : using namespace js::gc;
      60             : using namespace js::frontend;
      61             : 
      62             : using mozilla::ArrayLength;
      63             : using mozilla::CheckedInt;
      64             : using mozilla::Maybe;
      65             : using mozilla::Some;
      66             : 
      67             : static bool
      68           0 : fun_enumerate(JSContext* cx, HandleObject obj)
      69             : {
      70           0 :     MOZ_ASSERT(obj->is<JSFunction>());
      71             : 
      72           0 :     RootedId id(cx);
      73             :     bool found;
      74             : 
      75           0 :     if (!obj->isBoundFunction() && !obj->as<JSFunction>().isArrow()) {
      76           0 :         id = NameToId(cx->names().prototype);
      77           0 :         if (!HasOwnProperty(cx, obj, id, &found))
      78             :             return false;
      79             :     }
      80             : 
      81           0 :     if (!obj->as<JSFunction>().hasResolvedLength()) {
      82           0 :         id = NameToId(cx->names().length);
      83           0 :         if (!HasOwnProperty(cx, obj, id, &found))
      84             :             return false;
      85             :     }
      86             : 
      87           0 :     if (!obj->as<JSFunction>().hasResolvedName()) {
      88           0 :         id = NameToId(cx->names().name);
      89           0 :         if (!HasOwnProperty(cx, obj, id, &found))
      90             :             return false;
      91             :     }
      92             : 
      93             :     return true;
      94             : }
      95             : 
      96             : bool
      97           0 : IsFunction(HandleValue v)
      98             : {
      99           0 :     return v.isObject() && v.toObject().is<JSFunction>();
     100             : }
     101             : 
     102             : static bool
     103           0 : AdvanceToActiveCallLinear(JSContext* cx, NonBuiltinScriptFrameIter& iter, HandleFunction fun)
     104             : {
     105           0 :     MOZ_ASSERT(!fun->isBuiltin());
     106             : 
     107           0 :     for (; !iter.done(); ++iter) {
     108           0 :         if (!iter.isFunctionFrame())
     109             :             continue;
     110           0 :         if (iter.matchCallee(cx, fun))
     111             :             return true;
     112             :     }
     113             :     return false;
     114             : }
     115             : 
     116             : void
     117           0 : js::ThrowTypeErrorBehavior(JSContext* cx)
     118             : {
     119             :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_THROW_TYPE_ERROR);
     120           0 : }
     121           0 : 
     122             : static bool
     123             : IsSloppyNormalFunction(JSFunction* fun)
     124           0 : {
     125             :     // FunctionDeclaration or FunctionExpression in sloppy mode.
     126             :     if (fun->kind() == JSFunction::NormalFunction) {
     127           0 :         if (fun->isBuiltin() || fun->isBoundFunction())
     128           0 :             return false;
     129             : 
     130             :         if (fun->isGenerator() || fun->isAsync())
     131           0 :             return false;
     132             : 
     133             :         MOZ_ASSERT(fun->isInterpreted());
     134           0 :         return !fun->strict();
     135           0 :     }
     136             : 
     137             :     // Or asm.js function in sloppy mode.
     138             :     if (fun->kind() == JSFunction::AsmJS)
     139           0 :         return !IsAsmJSStrictModeModuleOrFunction(fun);
     140           0 : 
     141             :     return false;
     142             : }
     143             : 
     144             : // Beware: this function can be invoked on *any* function! That includes
     145             : // natives, strict mode functions, bound functions, arrow functions,
     146             : // self-hosted functions and constructors, asm.js functions, functions with
     147             : // destructuring arguments and/or a rest argument, and probably a few more I
     148             : // forgot. Turn back and save yourself while you still can. It's too late for
     149             : // me.
     150             : static bool
     151             : ArgumentsRestrictions(JSContext* cx, HandleFunction fun)
     152           0 : {
     153             :     // Throw unless the function is a sloppy, normal function.
     154             :     // TODO (bug 1057208): ensure semantics are correct for all possible
     155             :     // pairings of callee/caller.
     156             :     if (!IsSloppyNormalFunction(fun)) {
     157           0 :         ThrowTypeErrorBehavior(cx);
     158           0 :         return false;
     159           0 :     }
     160             : 
     161             :     // Otherwise emit a strict warning about |f.arguments| to discourage use of
     162             :     // this non-standard, performance-harmful feature.
     163             :     if (!JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING | JSREPORT_STRICT, GetErrorMessage,
     164           0 :                                            nullptr, JSMSG_DEPRECATED_USAGE, js_arguments_str))
     165             :     {
     166             :         return false;
     167             :     }
     168             : 
     169             :     return true;
     170           0 : }
     171             : 
     172             : bool
     173             : ArgumentsGetterImpl(JSContext* cx, const CallArgs& args)
     174           0 : {
     175             :     MOZ_ASSERT(IsFunction(args.thisv()));
     176           0 : 
     177             :     RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>());
     178           0 :     if (!ArgumentsRestrictions(cx, fun))
     179           0 :         return false;
     180             : 
     181             :     // Return null if this function wasn't found on the stack.
     182             :     NonBuiltinScriptFrameIter iter(cx);
     183           0 :     if (!AdvanceToActiveCallLinear(cx, iter, fun)) {
     184           0 :         args.rval().setNull();
     185           0 :         return true;
     186           0 :     }
     187             : 
     188             :     Rooted<ArgumentsObject*> argsobj(cx, ArgumentsObject::createUnexpected(cx, iter));
     189           0 :     if (!argsobj)
     190           0 :         return false;
     191             : 
     192             : #ifndef JS_CODEGEN_NONE
     193             :     // Disabling compiling of this script in IonMonkey.  IonMonkey doesn't
     194             :     // guarantee |f.arguments| can be fully recovered, so we try to mitigate
     195             :     // observing this behavior by detecting its use early.
     196             :     JSScript* script = iter.script();
     197           0 :     jit::ForbidCompilation(cx, script);
     198           0 : #endif
     199             : 
     200             :     args.rval().setObject(*argsobj);
     201           0 :     return true;
     202           0 : }
     203             : 
     204             : static bool
     205             : ArgumentsGetter(JSContext* cx, unsigned argc, Value* vp)
     206           0 : {
     207             :     CallArgs args = CallArgsFromVp(argc, vp);
     208           0 :     return CallNonGenericMethod<IsFunction, ArgumentsGetterImpl>(cx, args);
     209           0 : }
     210             : 
     211             : bool
     212             : ArgumentsSetterImpl(JSContext* cx, const CallArgs& args)
     213           0 : {
     214             :     MOZ_ASSERT(IsFunction(args.thisv()));
     215           0 : 
     216             :     RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>());
     217           0 :     if (!ArgumentsRestrictions(cx, fun))
     218           0 :         return false;
     219             : 
     220             :     // If the function passes the gauntlet, return |undefined|.
     221             :     args.rval().setUndefined();
     222           0 :     return true;
     223           0 : }
     224             : 
     225             : static bool
     226             : ArgumentsSetter(JSContext* cx, unsigned argc, Value* vp)
     227           0 : {
     228             :     CallArgs args = CallArgsFromVp(argc, vp);
     229           0 :     return CallNonGenericMethod<IsFunction, ArgumentsSetterImpl>(cx, args);
     230           0 : }
     231             : 
     232             : // Beware: this function can be invoked on *any* function! That includes
     233             : // natives, strict mode functions, bound functions, arrow functions,
     234             : // self-hosted functions and constructors, asm.js functions, functions with
     235             : // destructuring arguments and/or a rest argument, and probably a few more I
     236             : // forgot. Turn back and save yourself while you still can. It's too late for
     237             : // me.
     238             : static bool
     239             : CallerRestrictions(JSContext* cx, HandleFunction fun)
     240           0 : {
     241             :     // Throw unless the function is a sloppy, normal function.
     242             :     // TODO (bug 1057208): ensure semantics are correct for all possible
     243             :     // pairings of callee/caller.
     244             :     if (!IsSloppyNormalFunction(fun)) {
     245           0 :         ThrowTypeErrorBehavior(cx);
     246           0 :         return false;
     247           0 :     }
     248             : 
     249             :     // Otherwise emit a strict warning about |f.caller| to discourage use of
     250             :     // this non-standard, performance-harmful feature.
     251             :     if (!JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING | JSREPORT_STRICT, GetErrorMessage,
     252           0 :                                            nullptr, JSMSG_DEPRECATED_USAGE, js_caller_str))
     253             :     {
     254             :         return false;
     255             :     }
     256             : 
     257             :     return true;
     258           0 : }
     259             : 
     260             : bool
     261             : CallerGetterImpl(JSContext* cx, const CallArgs& args)
     262           0 : {
     263             :     MOZ_ASSERT(IsFunction(args.thisv()));
     264           0 : 
     265             :     // Beware!  This function can be invoked on *any* function!  It can't
     266             :     // assume it'll never be invoked on natives, strict mode functions, bound
     267             :     // functions, or anything else that ordinarily has immutable .caller
     268             :     // defined with [[ThrowTypeError]].
     269             :     RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>());
     270           0 :     if (!CallerRestrictions(cx, fun))
     271           0 :         return false;
     272             : 
     273             :     // Also return null if this function wasn't found on the stack.
     274             :     NonBuiltinScriptFrameIter iter(cx);
     275           0 :     if (!AdvanceToActiveCallLinear(cx, iter, fun)) {
     276           0 :         args.rval().setNull();
     277           0 :         return true;
     278           0 :     }
     279             : 
     280             :     ++iter;
     281           0 :     while (!iter.done() && iter.isEvalFrame())
     282           0 :         ++iter;
     283           0 : 
     284             :     if (iter.done() || !iter.isFunctionFrame()) {
     285           0 :         args.rval().setNull();
     286           0 :         return true;
     287           0 :     }
     288             : 
     289             :     RootedObject caller(cx, iter.callee(cx));
     290           0 :     if (caller->is<JSFunction>() && caller->as<JSFunction>().isAsync())
     291           0 :         caller = GetWrappedAsyncFunction(&caller->as<JSFunction>());
     292           0 :     if (!cx->compartment()->wrap(cx, &caller))
     293           0 :         return false;
     294             : 
     295             :     // Censor the caller if we don't have full access to it.  If we do, but the
     296             :     // caller is a function with strict mode code, throw a TypeError per ES5.
     297             :     // If we pass these checks, we can return the computed caller.
     298             :     {
     299             :         JSObject* callerObj = CheckedUnwrap(caller);
     300           0 :         if (!callerObj) {
     301           0 :             args.rval().setNull();
     302           0 :             return true;
     303           0 :         }
     304             : 
     305             :         JSFunction* callerFun = &callerObj->as<JSFunction>();
     306           0 :         if (IsWrappedAsyncFunction(callerFun))
     307           0 :             callerFun = GetUnwrappedAsyncFunction(callerFun);
     308           0 :         else if (IsWrappedAsyncGenerator(callerFun))
     309           0 :             callerFun = GetUnwrappedAsyncGenerator(callerFun);
     310           0 :         MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?");
     311           0 : 
     312             :         if (callerFun->strict()) {
     313           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CALLER_IS_STRICT);
     314             :             return false;
     315           0 :         }
     316           0 :     }
     317             : 
     318             :     args.rval().setObject(*caller);
     319             :     return true;
     320           0 : }
     321           0 : 
     322             : static bool
     323             : CallerGetter(JSContext* cx, unsigned argc, Value* vp)
     324             : {
     325           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     326             :     return CallNonGenericMethod<IsFunction, CallerGetterImpl>(cx, args);
     327           0 : }
     328           0 : 
     329             : bool
     330             : CallerSetterImpl(JSContext* cx, const CallArgs& args)
     331             : {
     332           0 :     MOZ_ASSERT(IsFunction(args.thisv()));
     333             : 
     334           0 :     // Beware!  This function can be invoked on *any* function!  It can't
     335             :     // assume it'll never be invoked on natives, strict mode functions, bound
     336             :     // functions, or anything else that ordinarily has immutable .caller
     337             :     // defined with [[ThrowTypeError]].
     338             :     RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>());
     339             :     if (!CallerRestrictions(cx, fun))
     340           0 :         return false;
     341           0 : 
     342             :     // Return |undefined| unless an error must be thrown.
     343             :     args.rval().setUndefined();
     344             : 
     345           0 :     // We can almost just return |undefined| here -- but if the caller function
     346             :     // was strict mode code, we still have to throw a TypeError.  This requires
     347             :     // computing the caller, checking that no security boundaries are crossed,
     348             :     // and throwing a TypeError if the resulting caller is strict.
     349             : 
     350             :     NonBuiltinScriptFrameIter iter(cx);
     351             :     if (!AdvanceToActiveCallLinear(cx, iter, fun))
     352           0 :         return true;
     353           0 : 
     354             :     ++iter;
     355             :     while (!iter.done() && iter.isEvalFrame())
     356           0 :         ++iter;
     357           0 : 
     358           0 :     if (iter.done() || !iter.isFunctionFrame())
     359             :         return true;
     360           0 : 
     361             :     RootedObject caller(cx, iter.callee(cx));
     362             :     // |caller| is only used for security access-checking and for its
     363           0 :     // strictness.  An unwrapped async function has its wrapped async
     364             :     // function's security access and strictness, so don't bother calling
     365             :     // |GetUnwrappedAsyncFunction|.
     366             :     if (!cx->compartment()->wrap(cx, &caller)) {
     367             :         cx->clearPendingException();
     368           0 :         return true;
     369           0 :     }
     370           0 : 
     371             :     // If we don't have full access to the caller, or the caller is not strict,
     372             :     // return undefined.  Otherwise throw a TypeError.
     373             :     JSObject* callerObj = CheckedUnwrap(caller);
     374             :     if (!callerObj)
     375           0 :         return true;
     376           0 : 
     377             :     JSFunction* callerFun = &callerObj->as<JSFunction>();
     378             :     MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?");
     379           0 : 
     380           0 :     if (callerFun->strict()) {
     381             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CALLER_IS_STRICT);
     382           0 :         return false;
     383             :     }
     384           0 : 
     385           0 :     return true;
     386             : }
     387             : 
     388             : static bool
     389             : CallerSetter(JSContext* cx, unsigned argc, Value* vp)
     390             : {
     391             :     CallArgs args = CallArgsFromVp(argc, vp);
     392           0 :     return CallNonGenericMethod<IsFunction, CallerSetterImpl>(cx, args);
     393             : }
     394           0 : 
     395           0 : static const JSPropertySpec function_properties[] = {
     396             :     JS_PSGS("arguments", ArgumentsGetter, ArgumentsSetter, 0),
     397             :     JS_PSGS("caller", CallerGetter, CallerSetter, 0),
     398             :     JS_PS_END
     399             : };
     400             : 
     401             : static bool
     402             : ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId id)
     403             : {
     404             :     bool isAsyncGenerator = IsWrappedAsyncGenerator(fun);
     405           0 : 
     406             :     MOZ_ASSERT_IF(!isAsyncGenerator, fun->isInterpreted() || fun->isAsmJSNative());
     407           0 :     MOZ_ASSERT(id == NameToId(cx->names().prototype));
     408             : 
     409           0 :     // Assert that fun is not a compiler-created function object, which
     410           0 :     // must never leak to script or embedding code and then be mutated.
     411             :     // Also assert that fun is not bound, per the ES5 15.3.4.5 ref above.
     412             :     MOZ_ASSERT_IF(!isAsyncGenerator, !IsInternalFunctionObject(*fun));
     413             :     MOZ_ASSERT(!fun->isBoundFunction());
     414             : 
     415           0 :     // Make the prototype object an instance of Object with the same parent as
     416           0 :     // the function object itself, unless the function is an ES6 generator.  In
     417             :     // that case, per the 15 July 2013 ES6 draft, section 15.19.3, its parent is
     418             :     // the GeneratorObjectPrototype singleton.
     419             :     bool isGenerator = fun->isGenerator();
     420             :     Rooted<GlobalObject*> global(cx, &fun->global());
     421             :     RootedObject objProto(cx);
     422           0 :     if (isAsyncGenerator)
     423           0 :         objProto = GlobalObject::getOrCreateAsyncGeneratorPrototype(cx, global);
     424           0 :     else if (isGenerator)
     425           0 :         objProto = GlobalObject::getOrCreateGeneratorObjectPrototype(cx, global);
     426           0 :     else
     427           0 :         objProto = GlobalObject::getOrCreateObjectPrototype(cx, global);
     428           0 :     if (!objProto)
     429             :         return false;
     430           0 : 
     431           0 :     RootedPlainObject proto(cx, NewObjectWithGivenProto<PlainObject>(cx, objProto,
     432             :                                                                      SingletonObject));
     433             :     if (!proto)
     434           0 :         return false;
     435           0 : 
     436           0 :     // Per ES5 13.2 the prototype's .constructor property is configurable,
     437             :     // non-enumerable, and writable.  However, per the 15 July 2013 ES6 draft,
     438             :     // section 15.19.3, the .prototype of a generator function does not link
     439             :     // back with a .constructor.
     440             :     if (!isGenerator && !isAsyncGenerator) {
     441             :         RootedValue objVal(cx, ObjectValue(*fun));
     442             :         if (!DefineDataProperty(cx, proto, cx->names().constructor, objVal, 0))
     443           0 :             return false;
     444           0 :     }
     445           0 : 
     446           0 :     // Per ES5 15.3.5.2 a user-defined function's .prototype property is
     447             :     // initially non-configurable, non-enumerable, and writable.
     448             :     RootedValue protoVal(cx, ObjectValue(*proto));
     449             :     return DefineDataProperty(cx, fun, id, protoVal, JSPROP_PERMANENT | JSPROP_RESOLVING);
     450             : }
     451           0 : 
     452           0 : bool
     453             : JSFunction::needsPrototypeProperty()
     454             : {
     455             :     /*
     456           0 :      * Built-in functions do not have a .prototype property per ECMA-262,
     457             :      * or (Object.prototype, Function.prototype, etc.) have that property
     458             :      * created eagerly.
     459             :      *
     460             :      * ES5 15.3.4.5: bound functions don't have a prototype property. The
     461             :      * isBuiltin() test covers this case because bound functions are native
     462             :      * (and thus built-in) functions by definition/construction.
     463             :      *
     464             :      * ES6 9.2.8 MakeConstructor defines the .prototype property on constructors.
     465             :      * Generators are not constructors, but they have a .prototype property anyway,
     466             :      * according to errata to ES6. See bug 1191486.
     467             :      *
     468             :      * Thus all of the following don't get a .prototype property:
     469             :      * - Methods (that are not class-constructors or generators)
     470             :      * - Arrow functions
     471             :      * - Function.prototype
     472             :      */
     473             :     if (isBuiltin())
     474             :         return IsWrappedAsyncGenerator(this);
     475             : 
     476           0 :     return isConstructor() || isGenerator() || isAsync();
     477           0 : }
     478             : 
     479           0 : static bool
     480             : fun_mayResolve(const JSAtomState& names, jsid id, JSObject*)
     481             : {
     482             :     if (!JSID_IS_ATOM(id))
     483           0 :         return false;
     484             : 
     485           0 :     JSAtom* atom = JSID_TO_ATOM(id);
     486             :     return atom == names.prototype || atom == names.length || atom == names.name;
     487             : }
     488           0 : 
     489           0 : static bool
     490             : fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
     491             : {
     492             :     if (!JSID_IS_ATOM(id))
     493           0 :         return true;
     494             : 
     495           0 :     RootedFunction fun(cx, &obj->as<JSFunction>());
     496             : 
     497             :     if (JSID_IS_ATOM(id, cx->names().prototype)) {
     498           0 :         if (!fun->needsPrototypeProperty())
     499             :             return true;
     500           0 : 
     501           0 :         if (!ResolveInterpretedFunctionPrototype(cx, fun, id))
     502             :             return false;
     503             : 
     504           0 :         *resolvedp = true;
     505             :         return true;
     506             :     }
     507           0 : 
     508           0 :     bool isLength = JSID_IS_ATOM(id, cx->names().length);
     509             :     if (isLength || JSID_IS_ATOM(id, cx->names().name)) {
     510             :         MOZ_ASSERT(!IsInternalFunctionObject(*obj));
     511           0 : 
     512           0 :         RootedValue v(cx);
     513           0 : 
     514             :         // Since f.length and f.name are configurable, they could be resolved
     515           0 :         // and then deleted:
     516             :         //     function f(x) {}
     517             :         //     assertEq(f.length, 1);
     518             :         //     delete f.length;
     519             :         //     assertEq(f.name, "f");
     520             :         //     delete f.name;
     521             :         // Afterwards, asking for f.length or f.name again will cause this
     522             :         // resolve hook to run again. Defining the property again the second
     523             :         // time through would be a bug.
     524             :         //     assertEq(f.length, 0);  // gets Function.prototype.length!
     525             :         //     assertEq(f.name, "");  // gets Function.prototype.name!
     526             :         // We use the RESOLVED_LENGTH and RESOLVED_NAME flags as a hack to prevent this
     527             :         // bug.
     528             :         if (isLength) {
     529             :             if (fun->hasResolvedLength())
     530             :                 return true;
     531           0 : 
     532           0 :             if (!JSFunction::getUnresolvedLength(cx, fun, &v))
     533             :                 return false;
     534             :         } else {
     535           0 :             if (fun->hasResolvedName())
     536             :                 return true;
     537             : 
     538           0 :             RootedString name(cx);
     539           0 :             if (!JSFunction::getUnresolvedName(cx, fun, &name))
     540             :                 return false;
     541           0 : 
     542           0 :             // Don't define an own .name property for unnamed functions.
     543           0 :             if (!name)
     544             :                 return true;
     545             : 
     546           0 :             v.setString(name);
     547             :         }
     548             : 
     549           0 :         if (!NativeDefineDataProperty(cx, fun, id, v, JSPROP_READONLY | JSPROP_RESOLVING))
     550             :             return false;
     551             : 
     552           0 :         if (isLength)
     553             :             fun->setResolvedLength();
     554             :         else
     555           0 :             fun->setResolvedName();
     556           0 : 
     557             :         *resolvedp = true;
     558           0 :         return true;
     559             :     }
     560           0 : 
     561           0 :     return true;
     562             : }
     563             : 
     564             : template<XDRMode mode>
     565             : XDRResult
     566             : js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
     567             :                            HandleScriptSourceObject sourceObject, MutableHandleFunction objp)
     568             : {
     569           0 :     enum FirstWordFlag {
     570             :         HasAtom             = 0x1,
     571             :         HasGeneratorProto   = 0x2,
     572             :         IsLazy              = 0x4,
     573             :         HasSingletonType    = 0x8
     574             :     };
     575             : 
     576             :     /* NB: Keep this in sync with CloneInnerInterpretedFunction. */
     577             :     RootedAtom atom(xdr->cx());
     578             :     uint32_t firstword = 0;        /* bitmask of FirstWordFlag */
     579             :     uint32_t flagsword = 0;        /* word for argument count and fun->flags */
     580           0 : 
     581           0 :     JSContext* cx = xdr->cx();
     582           0 :     RootedFunction fun(cx);
     583             :     RootedScript script(cx);
     584           0 :     Rooted<LazyScript*> lazy(cx);
     585           0 : 
     586           0 :     if (mode == XDR_ENCODE) {
     587           0 :         fun = objp;
     588             :         if (!fun->isInterpreted())
     589             :             return xdr->fail(JS::TranscodeResult_Failure_NotInterpretedFun);
     590           0 : 
     591           0 :         if (fun->explicitName() || fun->hasInferredName() || fun->hasGuessedAtom())
     592           0 :             firstword |= HasAtom;
     593             : 
     594           0 :         if (fun->isGenerator() || fun->isAsync())
     595           0 :             firstword |= HasGeneratorProto;
     596             : 
     597           0 :         if (fun->isInterpretedLazy()) {
     598           0 :             // Encode a lazy script.
     599             :             firstword |= IsLazy;
     600           0 :             lazy = fun->lazyScript();
     601             :         } else {
     602           0 :             // Encode the script.
     603           0 :             script = fun->nonLazyScript();
     604             :         }
     605             : 
     606           0 :         if (fun->isSingleton())
     607             :             firstword |= HasSingletonType;
     608             : 
     609           0 :         atom = fun->displayAtom();
     610           0 :         flagsword = (fun->nargs() << 16) |
     611             :                     (fun->flags() & ~JSFunction::NO_XDR_FLAGS);
     612           0 : 
     613           0 :         // The environment of any function which is not reused will always be
     614           0 :         // null, it is later defined when a function is cloned or reused to
     615             :         // mirror the scope chain.
     616             :         MOZ_ASSERT_IF(fun->isSingleton() &&
     617             :                       !((lazy && lazy->hasBeenCloned()) || (script && script->hasBeenCloned())),
     618             :                       fun->environment() == nullptr);
     619           0 :     }
     620             : 
     621             :     // Everything added below can substituted by the non-lazy-script version of
     622             :     // this function later.
     623             :     MOZ_TRY(xdr->codeAlign(sizeof(js::XDRAlignment)));
     624             :     js::AutoXDRTree funTree(xdr, xdr->getTreeKey(fun));
     625             : 
     626           0 :     MOZ_TRY(xdr->codeUint32(&firstword));
     627           0 : 
     628             :     if (firstword & HasAtom)
     629           0 :         MOZ_TRY(XDRAtom(xdr, &atom));
     630             :     MOZ_TRY(xdr->codeUint32(&flagsword));
     631           0 : 
     632           0 :     if (mode == XDR_DECODE) {
     633           0 :         RootedObject proto(cx);
     634             :         if (firstword & HasGeneratorProto) {
     635             :             proto = GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
     636           0 :             if (!proto)
     637           0 :                 return xdr->fail(JS::TranscodeResult_Throw);
     638           0 :         }
     639           0 : 
     640           0 :         gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
     641             :         if (uint16_t(flagsword) & JSFunction::EXTENDED)
     642             :             allocKind = gc::AllocKind::FUNCTION_EXTENDED;
     643           0 :         fun = NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED,
     644           0 :                                    /* enclosingDynamicScope = */ nullptr, nullptr, proto,
     645           0 :                                    allocKind, TenuredObject);
     646           0 :         if (!fun)
     647             :             return xdr->fail(JS::TranscodeResult_Throw);
     648             :         script = nullptr;
     649           0 :     }
     650           0 : 
     651           0 :     if (firstword & IsLazy)
     652             :         MOZ_TRY(XDRLazyScript(xdr, enclosingScope, sourceObject, fun, &lazy));
     653             :     else
     654           0 :         MOZ_TRY(XDRScript(xdr, enclosingScope, sourceObject, fun, &script));
     655           0 : 
     656             :     if (mode == XDR_DECODE) {
     657           0 :         fun->setArgCount(flagsword >> 16);
     658             :         fun->setFlags(uint16_t(flagsword));
     659             :         fun->initAtom(atom);
     660           0 :         if (firstword & IsLazy) {
     661           0 :             MOZ_ASSERT(fun->lazyScript() == lazy);
     662           0 :         } else {
     663           0 :             MOZ_ASSERT(fun->nonLazyScript() == script);
     664           0 :             MOZ_ASSERT(fun->nargs() == script->numArgs());
     665             :         }
     666           0 : 
     667           0 :         bool singleton = firstword & HasSingletonType;
     668             :         if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
     669             :             return xdr->fail(JS::TranscodeResult_Throw);
     670           0 :         objp.set(fun);
     671           0 :     }
     672           0 : 
     673           0 :     // Verify marker at end of function to detect buffer trunction.
     674             :     MOZ_TRY(xdr->codeMarker(0x9E35CA1F));
     675             : 
     676             :     // Required by AutoXDRTree to copy & paste snipet of sub-trees while keeping
     677           0 :     // the alignment.
     678             :     MOZ_TRY(xdr->codeAlign(sizeof(js::XDRAlignment)));
     679             : 
     680             :     return Ok();
     681           0 : }
     682             : 
     683           0 : template XDRResult
     684             : js::XDRInterpretedFunction(XDRState<XDR_ENCODE>*, HandleScope, HandleScriptSourceObject,
     685             :                            MutableHandleFunction);
     686             : 
     687             : template XDRResult
     688             : js::XDRInterpretedFunction(XDRState<XDR_DECODE>*, HandleScope, HandleScriptSourceObject,
     689             :                            MutableHandleFunction);
     690             : 
     691             : /* ES6 (04-25-16) 19.2.3.6 Function.prototype [ @@hasInstance ] */
     692             : bool
     693             : js::fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp)
     694             : {
     695             :     CallArgs args = CallArgsFromVp(argc, vp);
     696           0 : 
     697             :     if (args.length() < 1) {
     698           0 :         args.rval().setBoolean(false);
     699             :         return true;
     700           0 :     }
     701           0 : 
     702           0 :     /* Step 1. */
     703             :     HandleValue func = args.thisv();
     704             : 
     705             :     // Primitives are non-callable and will always return false from
     706           0 :     // OrdinaryHasInstance.
     707             :     if (!func.isObject()) {
     708             :         args.rval().setBoolean(false);
     709             :         return true;
     710           0 :     }
     711           0 : 
     712           0 :     RootedObject obj(cx, &func.toObject());
     713             : 
     714             :     /* Step 2. */
     715           0 :     bool result;
     716             :     if (!OrdinaryHasInstance(cx, obj, args[0], &result))
     717             :         return false;
     718             : 
     719           0 :     args.rval().setBoolean(result);
     720             :     return true;
     721             : }
     722           0 : 
     723           0 : /*
     724             :  * ES6 (4-25-16) 7.3.19 OrdinaryHasInstance
     725             :  */
     726             : bool
     727             : JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, bool* bp)
     728             : {
     729             :     AssertHeapIsIdle();
     730           0 :     assertSameCompartment(cx, objArg, v);
     731             : 
     732           0 :     RootedObject obj(cx, objArg);
     733           0 : 
     734             :     /* Step 1. */
     735           0 :     if (!obj->isCallable()) {
     736             :         *bp = false;
     737             :         return true;
     738           0 :     }
     739           0 : 
     740           0 :     /* Step 2. */
     741             :     if (obj->is<JSFunction>() && obj->isBoundFunction()) {
     742             :         /* Steps 2a-b. */
     743             :         obj = obj->as<JSFunction>().getBoundFunctionTarget();
     744           0 :         return InstanceOfOperator(cx, obj, v, bp);
     745             :     }
     746           0 : 
     747           0 :     /* Step 3. */
     748             :     if (!v.isObject()) {
     749             :         *bp = false;
     750             :         return true;
     751           0 :     }
     752           0 : 
     753           0 :     /* Step 4. */
     754             :     RootedValue pval(cx);
     755             :     if (!GetProperty(cx, obj, obj, cx->names().prototype, &pval))
     756             :         return false;
     757           0 : 
     758           0 :     /* Step 5. */
     759             :     if (pval.isPrimitive()) {
     760             :         /*
     761             :          * Throw a runtime error if instanceof is called on a function that
     762           0 :          * has a non-object as its .prototype value.
     763             :          */
     764             :         RootedValue val(cx, ObjectValue(*obj));
     765             :         ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, nullptr);
     766             :         return false;
     767           0 :     }
     768           0 : 
     769             :     /* Step 6. */
     770             :     RootedObject pobj(cx, &pval.toObject());
     771             :     bool isDelegate;
     772             :     if (!IsDelegate(cx, pobj, v, &isDelegate))
     773           0 :         return false;
     774             :     *bp = isDelegate;
     775           0 :     return true;
     776             : }
     777           0 : 
     778           0 : inline void
     779             : JSFunction::trace(JSTracer* trc)
     780             : {
     781             :     if (isExtended()) {
     782           0 :         TraceRange(trc, ArrayLength(toExtended()->extendedSlots),
     783             :                    (GCPtrValue*)toExtended()->extendedSlots, "nativeReserved");
     784           0 :     }
     785           0 : 
     786           0 :     TraceNullableEdge(trc, &atom_, "atom");
     787             : 
     788             :     if (isInterpreted()) {
     789           0 :         // Functions can be be marked as interpreted despite having no script
     790             :         // yet at some points when parsing, and can be lazy with no lazy script
     791           0 :         // for self-hosted code.
     792             :         if (hasScript() && !hasUncompletedScript())
     793             :             TraceManuallyBarrieredEdge(trc, &u.scripted.s.script_, "script");
     794             :         else if (isInterpretedLazy() && u.scripted.s.lazy_)
     795           0 :             TraceManuallyBarrieredEdge(trc, &u.scripted.s.lazy_, "lazyScript");
     796           0 : 
     797           0 :         if (u.scripted.env_)
     798           0 :             TraceManuallyBarrieredEdge(trc, &u.scripted.env_, "fun_environment");
     799             :     }
     800           0 : }
     801           0 : 
     802             : static void
     803           0 : fun_trace(JSTracer* trc, JSObject* obj)
     804             : {
     805             :     obj->as<JSFunction>().trace(trc);
     806           0 : }
     807             : 
     808           0 : static JSObject*
     809           0 : CreateFunctionConstructor(JSContext* cx, JSProtoKey key)
     810             : {
     811             :     Rooted<GlobalObject*> global(cx, cx->global());
     812           0 :     RootedObject functionProto(cx, &global->getPrototype(JSProto_Function).toObject());
     813             : 
     814           0 :     RootedObject functionCtor(cx,
     815           0 :       NewFunctionWithProto(cx, Function, 1, JSFunction::NATIVE_CTOR,
     816             :                            nullptr, HandlePropertyName(cx->names().Function),
     817             :                            functionProto, AllocKind::FUNCTION, SingletonObject));
     818           0 :     if (!functionCtor)
     819           0 :         return nullptr;
     820           0 : 
     821           0 :     return functionCtor;
     822             : }
     823             : 
     824           0 : static JSObject*
     825             : CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
     826             : {
     827             :     Rooted<GlobalObject*> self(cx, cx->global());
     828           0 : 
     829             :     RootedObject objectProto(cx, &self->getPrototype(JSProto_Object).toObject());
     830           0 :     /*
     831             :      * Bizarrely, |Function.prototype| must be an interpreted function, so
     832           0 :      * give it the guts to be one.
     833             :      */
     834             :     RootedObject enclosingEnv(cx, &self->lexicalEnvironment());
     835             :     RootedFunction functionProto(cx, NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED,
     836             :                                                           enclosingEnv, nullptr, objectProto,
     837           0 :                                                           AllocKind::FUNCTION, SingletonObject));
     838           0 :     if (!functionProto)
     839             :         return nullptr;
     840           0 : 
     841           0 :     const char* rawSource = "function () {\n}";
     842             :     size_t sourceLen = strlen(rawSource);
     843             :     size_t begin = 9;
     844           0 :     MOZ_ASSERT(rawSource[begin] == '(');
     845           0 :     UniqueTwoByteChars source(InflateString(cx, rawSource, sourceLen));
     846           0 :     if (!source)
     847             :         return nullptr;
     848           0 : 
     849           0 :     ScriptSource* ss = cx->new_<ScriptSource>();
     850             :     if (!ss)
     851             :         return nullptr;
     852           0 :     ScriptSourceHolder ssHolder(ss);
     853           0 :     if (!ss->setSource(cx, std::move(source), sourceLen))
     854             :         return nullptr;
     855           0 : 
     856           0 :     CompileOptions options(cx);
     857             :     options.setIntroductionType("Function.prototype")
     858             :            .setNoScriptRval(true);
     859           0 :     if (!ss->initFromOptions(cx, options))
     860           0 :         return nullptr;
     861           0 :     RootedScriptSourceObject sourceObject(cx, ScriptSourceObject::create(cx, ss));
     862           0 :     if (!sourceObject || !ScriptSourceObject::initFromOptions(cx, sourceObject, options))
     863             :         return nullptr;
     864           0 : 
     865           0 :     RootedScript script(cx, JSScript::Create(cx,
     866             :                                              options,
     867             :                                              sourceObject,
     868           0 :                                              begin,
     869             :                                              ss->length(),
     870             :                                              0,
     871             :                                              ss->length()));
     872           0 :     if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto))
     873             :         return nullptr;
     874           0 : 
     875           0 :     functionProto->initScript(script);
     876             :     ObjectGroup* protoGroup = JSObject::getGroup(cx, functionProto);
     877             :     if (!protoGroup)
     878           0 :         return nullptr;
     879           0 : 
     880           0 :     protoGroup->setInterpretedFunction(functionProto);
     881             : 
     882             :     /*
     883           0 :      * The default 'new' group of Function.prototype is required by type
     884             :      * inference to have unknown properties, to simplify handling of e.g.
     885             :      * NewFunctionClone.
     886             :      */
     887             :     ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
     888             :     if (!JSObject::setNewGroupUnknown(cx, realm, &JSFunction::class_, functionProto))
     889             :         return nullptr;
     890           0 : 
     891           0 :     return functionProto;
     892             : }
     893             : 
     894           0 : static const ClassOps JSFunctionClassOps = {
     895             :     nullptr,                 /* addProperty */
     896             :     nullptr,                 /* delProperty */
     897             :     fun_enumerate,
     898             :     nullptr,                 /* newEnumerate */
     899             :     fun_resolve,
     900             :     fun_mayResolve,
     901             :     nullptr,                 /* finalize    */
     902             :     nullptr,                 /* call        */
     903             :     nullptr,
     904             :     nullptr,                 /* construct   */
     905             :     fun_trace,
     906             : };
     907             : 
     908             : static const ClassSpec JSFunctionClassSpec = {
     909             :     CreateFunctionConstructor,
     910             :     CreateFunctionPrototype,
     911             :     nullptr,
     912             :     nullptr,
     913             :     function_methods,
     914             :     function_properties
     915             : };
     916             : 
     917             : const Class JSFunction::class_ = {
     918             :     js_Function_str,
     919             :     JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
     920             :     &JSFunctionClassOps,
     921             :     &JSFunctionClassSpec
     922             : };
     923             : 
     924             : const Class* const js::FunctionClassPtr = &JSFunction::class_;
     925             : 
     926             : JSString*
     927             : js::FunctionToStringCache::lookup(JSScript* script) const
     928             : {
     929             :     for (size_t i = 0; i < NumEntries; i++) {
     930             :         if (entries_[i].script == script)
     931             :             return entries_[i].string;
     932           0 :     }
     933           0 :     return nullptr;
     934           0 : }
     935             : 
     936             : void
     937             : js::FunctionToStringCache::put(JSScript* script, JSString* string)
     938             : {
     939             :     for (size_t i = NumEntries - 1; i > 0; i--)
     940           0 :         entries_[i] = entries_[i - 1];
     941             : 
     942           0 :     entries_[0].set(script, string);
     943           0 : }
     944             : 
     945           0 : JSString*
     946           0 : js::FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource)
     947             : {
     948             :     if (fun->isInterpretedLazy() && !JSFunction::getOrCreateScript(cx, fun))
     949           0 :         return nullptr;
     950             : 
     951           0 :     if (IsAsmJSModule(fun))
     952             :         return AsmJSModuleToString(cx, fun, isToSource);
     953             :     if (IsAsmJSFunction(fun))
     954           0 :         return AsmJSFunctionToString(cx, fun);
     955           0 : 
     956           0 :     if (IsWrappedAsyncFunction(fun)) {
     957           0 :         RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
     958             :         return FunctionToString(cx, unwrapped, isToSource);
     959           0 :     }
     960           0 :     if (IsWrappedAsyncGenerator(fun)) {
     961           0 :         RootedFunction unwrapped(cx, GetUnwrappedAsyncGenerator(fun));
     962             :         return FunctionToString(cx, unwrapped, isToSource);
     963           0 :     }
     964           0 : 
     965           0 :     RootedScript script(cx);
     966             :     if (fun->hasScript())
     967             :         script = fun->nonLazyScript();
     968           0 : 
     969           0 :     // Default class constructors are self-hosted, but have their source
     970           0 :     // objects overridden to refer to the span of the class statement or
     971             :     // expression. Non-default class constructors are never self-hosted. So,
     972             :     // all class constructors always have source.
     973             :     bool haveSource = fun->isInterpreted() && (fun->isClassConstructor() ||
     974             :                                                !fun->isSelfHostedBuiltin());
     975             : 
     976           0 :     // If we're in toSource mode, put parentheses around lambda functions so
     977           0 :     // that eval returns lambda, not function statement.
     978             :     bool addParentheses = haveSource && isToSource && (fun->isLambda() && !fun->isArrow());
     979             : 
     980             :     if (haveSource && !script->scriptSource()->hasSourceData() &&
     981           0 :         !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
     982             :     {
     983           0 :         return nullptr;
     984           0 :     }
     985             : 
     986             :     // Fast path for the common case, to avoid StringBuffer overhead.
     987             :     if (!addParentheses && haveSource) {
     988             :         FunctionToStringCache& cache = cx->zone()->functionToStringCache();
     989             :         if (JSString* str = cache.lookup(script))
     990           0 :             return str;
     991           0 : 
     992           0 :         size_t start = script->toStringStart(), end = script->toStringEnd();
     993             :         JSString* str = (end - start <= ScriptSource::SourceDeflateLimit)
     994             :             ? script->scriptSource()->substring(cx, start, end)
     995           0 :             : script->scriptSource()->substringDontDeflate(cx, start, end);
     996           0 :         if (!str)
     997           0 :             return nullptr;
     998           0 : 
     999           0 :         cache.put(script, str);
    1000             :         return str;
    1001             :     }
    1002           0 : 
    1003           0 :     StringBuffer out(cx);
    1004             :     if (addParentheses) {
    1005             :         if (!out.append('('))
    1006           0 :             return nullptr;
    1007           0 :     }
    1008           0 : 
    1009             :     if (haveSource) {
    1010             :         if (!script->appendSourceDataForToString(cx, out))
    1011             :             return nullptr;
    1012           0 :     } else {
    1013           0 :         if (fun->isAsync()) {
    1014             :             if (!out.append("async "))
    1015             :                 return nullptr;
    1016           0 :         }
    1017           0 : 
    1018             :         if (!fun->isArrow()) {
    1019             :             if (!out.append("function"))
    1020             :                 return nullptr;
    1021           0 : 
    1022           0 :             if (fun->isGenerator()) {
    1023             :                 if (!out.append('*'))
    1024             :                     return nullptr;
    1025           0 :             }
    1026           0 :         }
    1027             : 
    1028             :         if (fun->explicitName()) {
    1029             :             if (!out.append(' '))
    1030             :                 return nullptr;
    1031           0 : 
    1032           0 :             if (fun->isBoundFunction()) {
    1033             :                 JSLinearString* boundName = JSFunction::getBoundFunctionName(cx, fun);
    1034             :                 if (!boundName || !out.append(boundName))
    1035           0 :                     return nullptr;
    1036           0 :             } else {
    1037           0 :                 if (!out.append(fun->explicitName()))
    1038             :                     return nullptr;
    1039             :             }
    1040           0 :         }
    1041             : 
    1042             :         if (fun->isInterpreted() &&
    1043             :             (!fun->isSelfHostedBuiltin() ||
    1044             :              fun->infallibleIsDefaultClassConstructor(cx)))
    1045           0 :         {
    1046           0 :             // Default class constructors should always haveSource except;
    1047           0 :             //
    1048             :             // 1. Source has been discarded for the whole compartment.
    1049             :             //
    1050             :             // 2. The source is marked as "lazy", i.e., retrieved on demand, and
    1051             :             // the embedding has not provided a hook to retrieve sources.
    1052             :             MOZ_ASSERT_IF(fun->infallibleIsDefaultClassConstructor(cx),
    1053             :                           !cx->runtime()->sourceHook.ref() ||
    1054             :                           !script->scriptSource()->sourceRetrievable() ||
    1055           0 :                           fun->realm()->behaviors().discardSource());
    1056             : 
    1057             :             if (!out.append("() {\n    [sourceless code]\n}"))
    1058             :                 return nullptr;
    1059             :         } else {
    1060           0 :             if (!out.append("() {\n    [native code]\n}"))
    1061             :                 return nullptr;
    1062             :         }
    1063           0 :     }
    1064             : 
    1065             :     if (addParentheses) {
    1066             :         if (!out.append(')'))
    1067             :             return nullptr;
    1068           0 :     }
    1069           0 : 
    1070             :     return out.finishString();
    1071             : }
    1072             : 
    1073           0 : JSString*
    1074             : fun_toStringHelper(JSContext* cx, HandleObject obj, bool isToSource)
    1075             : {
    1076             :     if (!obj->is<JSFunction>()) {
    1077           0 :         if (JSFunToStringOp op = obj->getOpsFunToString())
    1078             :             return op(cx, obj, isToSource);
    1079           0 : 
    1080           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1081           0 :                                   JSMSG_INCOMPATIBLE_PROTO,
    1082             :                                   js_Function_str, js_toString_str, "object");
    1083             :         return nullptr;
    1084             :     }
    1085           0 : 
    1086           0 :     RootedFunction fun(cx, &obj->as<JSFunction>());
    1087             :     return FunctionToString(cx, fun, isToSource);
    1088             : }
    1089           0 : 
    1090           0 : bool
    1091             : js::FunctionHasDefaultHasInstance(JSFunction* fun, const WellKnownSymbols& symbols)
    1092             : {
    1093             :     jsid id = SYMBOL_TO_JSID(symbols.hasInstance);
    1094           0 :     Shape* shape = fun->lookupPure(id);
    1095             :     if (shape) {
    1096           0 :         if (!shape->isDataProperty())
    1097           0 :             return false;
    1098           0 :         const Value hasInstance = fun->as<NativeObject>().getSlot(shape->slot());
    1099           0 :         return IsNativeFunction(hasInstance, js::fun_symbolHasInstance);
    1100             :     }
    1101           0 :     return true;
    1102           0 : }
    1103             : 
    1104             : bool
    1105             : js::fun_toString(JSContext* cx, unsigned argc, Value* vp)
    1106             : {
    1107             :     CallArgs args = CallArgsFromVp(argc, vp);
    1108           0 :     MOZ_ASSERT(IsFunctionObject(args.calleev()));
    1109             : 
    1110           0 :     RootedObject obj(cx, ToObject(cx, args.thisv()));
    1111           0 :     if (!obj)
    1112             :         return false;
    1113           0 : 
    1114           0 :     JSString* str = fun_toStringHelper(cx, obj, /* isToSource = */ false);
    1115             :     if (!str)
    1116             :         return false;
    1117           0 : 
    1118           0 :     args.rval().setString(str);
    1119             :     return true;
    1120             : }
    1121           0 : 
    1122           0 : static bool
    1123             : fun_toSource(JSContext* cx, unsigned argc, Value* vp)
    1124             : {
    1125             :     CallArgs args = CallArgsFromVp(argc, vp);
    1126           0 :     MOZ_ASSERT(IsFunctionObject(args.calleev()));
    1127             : 
    1128           0 :     RootedObject obj(cx, ToObject(cx, args.thisv()));
    1129           0 :     if (!obj)
    1130             :         return false;
    1131           0 : 
    1132           0 :     RootedString str(cx);
    1133             :     if (obj->isCallable())
    1134             :         str = fun_toStringHelper(cx, obj, /* isToSource = */ true);
    1135           0 :     else
    1136           0 :         str = ObjectToSource(cx, obj);
    1137           0 :     if (!str)
    1138             :         return false;
    1139           0 : 
    1140           0 :     args.rval().setString(str);
    1141             :     return true;
    1142             : }
    1143           0 : 
    1144           0 : bool
    1145             : js::fun_call(JSContext* cx, unsigned argc, Value* vp)
    1146             : {
    1147             :     CallArgs args = CallArgsFromVp(argc, vp);
    1148           0 : 
    1149             :     HandleValue func = args.thisv();
    1150           0 : 
    1151             :     // We don't need to do this -- Call would do it for us -- but the error
    1152           0 :     // message is *much* better if we do this here.  (Without this,
    1153             :     // JSDVG_SEARCH_STACK tries to decompile |func| as if it were |this| in
    1154             :     // the scripted caller's frame -- so for example
    1155             :     //
    1156             :     //   Function.prototype.call.call({});
    1157             :     //
    1158             :     // would identify |{}| as |this| as being the result of evaluating
    1159             :     // |Function.prototype.call| and would conclude, "Function.prototype.call
    1160             :     // is not a function".  Grotesque.)
    1161             :     if (!IsCallable(func)) {
    1162             :         ReportIncompatibleMethod(cx, args, &JSFunction::class_);
    1163             :         return false;
    1164           0 :     }
    1165           0 : 
    1166           0 :     size_t argCount = args.length();
    1167             :     if (argCount > 0)
    1168             :         argCount--; // strip off provided |this|
    1169           0 : 
    1170           0 :     InvokeArgs iargs(cx);
    1171           0 :     if (!iargs.init(cx, argCount))
    1172             :         return false;
    1173           0 : 
    1174           0 :     for (size_t i = 0; i < argCount; i++)
    1175             :         iargs[i].set(args[i + 1]);
    1176             : 
    1177           0 :     return Call(cx, func, args.get(0), iargs, args.rval());
    1178           0 : }
    1179             : 
    1180           0 : // ES5 15.3.4.3
    1181             : bool
    1182             : js::fun_apply(JSContext* cx, unsigned argc, Value* vp)
    1183             : {
    1184             :     CallArgs args = CallArgsFromVp(argc, vp);
    1185           0 : 
    1186             :     // Step 1.
    1187           0 :     //
    1188             :     // Note that we must check callability here, not at actual call time,
    1189             :     // because extracting argument values from the provided arraylike might
    1190             :     // have side effects or throw an exception.
    1191             :     HandleValue fval = args.thisv();
    1192             :     if (!IsCallable(fval)) {
    1193             :         ReportIncompatibleMethod(cx, args, &JSFunction::class_);
    1194           0 :         return false;
    1195           0 :     }
    1196           0 : 
    1197           0 :     // Step 2.
    1198             :     if (args.length() < 2 || args[1].isNullOrUndefined())
    1199             :         return fun_call(cx, (args.length() > 0) ? 1 : 0, vp);
    1200             : 
    1201           0 :     InvokeArgs args2(cx);
    1202           0 : 
    1203             :     // A JS_OPTIMIZED_ARGUMENTS magic value means that 'arguments' flows into
    1204           0 :     // this apply call from a scripted caller and, as an optimization, we've
    1205             :     // avoided creating it since apply can simply pull the argument values from
    1206             :     // the calling frame (which we must do now).
    1207             :     if (args[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
    1208             :         // Step 3-6.
    1209             :         ScriptFrameIter iter(cx);
    1210           0 :         MOZ_ASSERT(iter.numActualArgs() <= ARGS_LENGTH_MAX);
    1211             :         if (!args2.init(cx, iter.numActualArgs()))
    1212           0 :             return false;
    1213           0 : 
    1214           0 :         // Steps 7-8.
    1215           0 :         iter.unaliasedForEachActual(cx, CopyTo(args2.array()));
    1216             :     } else {
    1217             :         // Step 3.
    1218           0 :         if (!args[1].isObject()) {
    1219             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1220             :                                       JSMSG_BAD_APPLY_ARGS, js_apply_str);
    1221           0 :             return false;
    1222             :         }
    1223           0 : 
    1224           0 :         // Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
    1225             :         // original version of ES5).
    1226             :         RootedObject aobj(cx, &args[1].toObject());
    1227             :         uint32_t length;
    1228             :         if (!GetLengthProperty(cx, aobj, &length))
    1229           0 :             return false;
    1230             : 
    1231           0 :         // Step 6.
    1232           0 :         if (!args2.init(cx, length))
    1233             :             return false;
    1234             : 
    1235           0 :         MOZ_ASSERT(length <= ARGS_LENGTH_MAX);
    1236             : 
    1237             :         // Steps 7-8.
    1238           0 :         if (!GetElements(cx, aobj, length, args2.array()))
    1239             :             return false;
    1240             :     }
    1241           0 : 
    1242             :     // Step 9.
    1243             :     return Call(cx, fval, args[0], args2, args.rval());
    1244             : }
    1245             : 
    1246           0 : bool
    1247             : JSFunction::infallibleIsDefaultClassConstructor(JSContext* cx) const
    1248             : {
    1249             :     if (!isSelfHostedBuiltin())
    1250           0 :         return false;
    1251             : 
    1252           0 :     bool isDefault = false;
    1253             :     if (isInterpretedLazy()) {
    1254             :         JSAtom* name = &getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).toString()->asAtom();
    1255           0 :         isDefault = name == cx->names().DefaultDerivedClassConstructor ||
    1256           0 :                     name == cx->names().DefaultBaseClassConstructor;
    1257           0 :     } else {
    1258           0 :         isDefault = nonLazyScript()->isDefaultClassConstructor();
    1259           0 :     }
    1260             : 
    1261           0 :     MOZ_ASSERT_IF(isDefault, isConstructor());
    1262             :     MOZ_ASSERT_IF(isDefault, isClassConstructor());
    1263             :     return isDefault;
    1264           0 : }
    1265           0 : 
    1266             : bool
    1267             : JSFunction::isDerivedClassConstructor()
    1268             : {
    1269             :     bool derived;
    1270           0 :     if (isInterpretedLazy()) {
    1271             :         // There is only one plausible lazy self-hosted derived
    1272             :         // constructor.
    1273           0 :         if (isSelfHostedBuiltin()) {
    1274             :             JSAtom* name = &getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).toString()->asAtom();
    1275             : 
    1276           0 :             // This function is called from places without access to a
    1277           0 :             // JSContext. Trace some plumbing to get what we want.
    1278             :             derived = name == compartment()->runtimeFromAnyThread()->
    1279             :                               commonNames->DefaultDerivedClassConstructor;
    1280             :         } else {
    1281           0 :             derived = lazyScript()->isDerivedClassConstructor();
    1282           0 :         }
    1283             :     } else {
    1284           0 :         derived = nonLazyScript()->isDerivedClassConstructor();
    1285             :     }
    1286             :     MOZ_ASSERT_IF(derived, isClassConstructor());
    1287           0 :     return derived;
    1288             : }
    1289           0 : 
    1290           0 : /* static */ bool
    1291             : JSFunction::getLength(JSContext* cx, HandleFunction fun, uint16_t* length)
    1292             : {
    1293             :     MOZ_ASSERT(!fun->isBoundFunction());
    1294           0 :     if (fun->isInterpretedLazy() && !getOrCreateScript(cx, fun))
    1295             :         return false;
    1296           0 : 
    1297           0 :     *length = fun->isNative() ? fun->nargs() : fun->nonLazyScript()->funLength();
    1298             :     return true;
    1299             : }
    1300           0 : 
    1301           0 : /* static */ bool
    1302             : JSFunction::getUnresolvedLength(JSContext* cx, HandleFunction fun, MutableHandleValue v)
    1303             : {
    1304             :     MOZ_ASSERT(!IsInternalFunctionObject(*fun));
    1305           0 :     MOZ_ASSERT(!fun->hasResolvedLength());
    1306             : 
    1307           0 :     // Bound functions' length can have values up to MAX_SAFE_INTEGER, so
    1308           0 :     // they're handled differently from other functions.
    1309             :     if (fun->isBoundFunction()) {
    1310             :         MOZ_ASSERT(fun->getExtendedSlot(BOUND_FUN_LENGTH_SLOT).isNumber());
    1311             :         v.set(fun->getExtendedSlot(BOUND_FUN_LENGTH_SLOT));
    1312           0 :         return true;
    1313           0 :     }
    1314           0 : 
    1315           0 :     uint16_t length;
    1316             :     if (!JSFunction::getLength(cx, fun, &length))
    1317             :         return false;
    1318             : 
    1319           0 :     v.setInt32(length);
    1320             :     return true;
    1321             : }
    1322           0 : 
    1323           0 : JSAtom*
    1324             : JSFunction::infallibleGetUnresolvedName(JSContext* cx)
    1325             : {
    1326             :     MOZ_ASSERT(!IsInternalFunctionObject(*this));
    1327           0 :     MOZ_ASSERT(!hasResolvedName());
    1328             : 
    1329           0 :     if (JSAtom* name = explicitOrInferredName())
    1330           0 :         return name;
    1331             : 
    1332           0 :     // Unnamed class expressions should not get a .name property at all.
    1333             :     if (isClassConstructor())
    1334             :         return nullptr;
    1335             : 
    1336           0 :     return cx->names().empty;
    1337             : }
    1338             : 
    1339           0 : /* static */ bool
    1340             : JSFunction::getUnresolvedName(JSContext* cx, HandleFunction fun, MutableHandleString v)
    1341             : {
    1342             :     if (fun->isBoundFunction()) {
    1343           0 :         JSLinearString* name = JSFunction::getBoundFunctionName(cx, fun);
    1344             :         if (!name)
    1345           0 :             return false;
    1346           0 : 
    1347           0 :         v.set(name);
    1348             :         return true;
    1349             :     }
    1350           0 : 
    1351           0 :     v.set(fun->infallibleGetUnresolvedName(cx));
    1352             :     return true;
    1353             : }
    1354           0 : 
    1355           0 : /* static */ JSLinearString*
    1356             : JSFunction::getBoundFunctionName(JSContext* cx, HandleFunction fun)
    1357             : {
    1358             :     MOZ_ASSERT(fun->isBoundFunction());
    1359           0 :     JSAtom* name = fun->explicitName();
    1360             : 
    1361           0 :     // Bound functions are never unnamed.
    1362           0 :     MOZ_ASSERT(name);
    1363             : 
    1364             :     // If the bound function prefix is present, return the name as is.
    1365           0 :     if (fun->hasBoundFunctionNamePrefix())
    1366             :         return name;
    1367             : 
    1368           0 :     // Otherwise return "bound " * (number of bound function targets) + name.
    1369             :     size_t boundTargets = 0;
    1370             :     for (JSFunction* boundFn = fun; boundFn->isBoundFunction(); ) {
    1371             :         boundTargets++;
    1372           0 : 
    1373           0 :         JSObject* target = boundFn->getBoundFunctionTarget();
    1374           0 :         if (!target->is<JSFunction>())
    1375             :             break;
    1376           0 :         boundFn = &target->as<JSFunction>();
    1377           0 :     }
    1378             : 
    1379           0 :     // |function /*unnamed*/ (){...}.bind()| is a common case, handle it here.
    1380             :     if (name->empty() && boundTargets == 1)
    1381             :         return cx->names().boundWithSpace;
    1382             : 
    1383           0 :     static constexpr char boundWithSpaceChars[] = "bound ";
    1384           0 :     static constexpr size_t boundWithSpaceCharsLength =
    1385             :         ArrayLength(boundWithSpaceChars) - 1; // No trailing '\0'.
    1386             :     MOZ_ASSERT(StringEqualsAscii(cx->names().boundWithSpace, boundWithSpaceChars));
    1387             : 
    1388             :     StringBuffer sb(cx);
    1389           0 :     if (name->hasTwoByteChars() && !sb.ensureTwoByteChars())
    1390             :         return nullptr;
    1391           0 : 
    1392           0 :     CheckedInt<size_t> len(boundTargets);
    1393             :     len *= boundWithSpaceCharsLength;
    1394             :     len += name->length();
    1395           0 :     if (!len.isValid()) {
    1396           0 :         ReportAllocationOverflow(cx);
    1397           0 :         return nullptr;
    1398           0 :     }
    1399           0 :     if (!sb.reserve(len.value()))
    1400           0 :         return nullptr;
    1401             : 
    1402           0 :     while (boundTargets--)
    1403             :         sb.infallibleAppend(boundWithSpaceChars, boundWithSpaceCharsLength);
    1404             :     sb.infallibleAppendSubstring(name, 0, name->length());
    1405           0 : 
    1406             :     return sb.finishString();
    1407           0 : }
    1408             : 
    1409           0 : static const js::Value&
    1410             : BoundFunctionEnvironmentSlotValue(const JSFunction* fun, uint32_t slotIndex)
    1411             : {
    1412             :     MOZ_ASSERT(fun->isBoundFunction());
    1413           0 :     MOZ_ASSERT(fun->environment()->is<CallObject>());
    1414             :     CallObject* callObject = &fun->environment()->as<CallObject>();
    1415           0 :     return callObject->getSlot(slotIndex);
    1416           0 : }
    1417           0 : 
    1418           0 : JSObject*
    1419             : JSFunction::getBoundFunctionTarget() const
    1420             : {
    1421             :     js::Value targetVal = BoundFunctionEnvironmentSlotValue(this, JSSLOT_BOUND_FUNCTION_TARGET);
    1422           0 :     MOZ_ASSERT(IsCallable(targetVal));
    1423             :     return &targetVal.toObject();
    1424           0 : }
    1425           0 : 
    1426           0 : const js::Value&
    1427             : JSFunction::getBoundFunctionThis() const
    1428             : {
    1429             :     return BoundFunctionEnvironmentSlotValue(this, JSSLOT_BOUND_FUNCTION_THIS);
    1430           0 : }
    1431             : 
    1432           0 : static ArrayObject*
    1433             : GetBoundFunctionArguments(const JSFunction* boundFun)
    1434             : {
    1435             :     js::Value argsVal = BoundFunctionEnvironmentSlotValue(boundFun, JSSLOT_BOUND_FUNCTION_ARGS);
    1436           0 :     return &argsVal.toObject().as<ArrayObject>();
    1437             : }
    1438           0 : 
    1439           0 : const js::Value&
    1440             : JSFunction::getBoundFunctionArgument(unsigned which) const
    1441             : {
    1442             :     MOZ_ASSERT(which < getBoundFunctionArgumentCount());
    1443           0 :     return GetBoundFunctionArguments(this)->getDenseElement(which);
    1444             : }
    1445           0 : 
    1446           0 : size_t
    1447             : JSFunction::getBoundFunctionArgumentCount() const
    1448             : {
    1449             :     return GetBoundFunctionArguments(this)->length();
    1450           0 : }
    1451             : 
    1452           0 : static JSAtom*
    1453             : AppendBoundFunctionPrefix(JSContext* cx, JSString* str)
    1454             : {
    1455             :     static constexpr char boundWithSpaceChars[] = "bound ";
    1456           0 :     MOZ_ASSERT(StringEqualsAscii(cx->names().boundWithSpace, boundWithSpaceChars));
    1457             : 
    1458             :     StringBuffer sb(cx);
    1459           0 :     if (!sb.append(boundWithSpaceChars) || !sb.append(str))
    1460             :         return nullptr;
    1461           0 :     return sb.finishAtom();
    1462           0 : }
    1463             : 
    1464           0 : /* static */ bool
    1465             : JSFunction::finishBoundFunctionInit(JSContext* cx, HandleFunction bound, HandleObject targetObj,
    1466             :                                     int32_t argCount)
    1467             : {
    1468           0 :     bound->setIsBoundFunction();
    1469             :     MOZ_ASSERT(bound->getBoundFunctionTarget() == targetObj);
    1470             : 
    1471           0 :     // 9.4.1.3 BoundFunctionCreate, steps 1, 3-5, 8-12 (Already performed).
    1472           0 : 
    1473             :     // 9.4.1.3 BoundFunctionCreate, step 6.
    1474             :     if (targetObj->isConstructor())
    1475             :         bound->setIsConstructor();
    1476             : 
    1477           0 :     // 9.4.1.3 BoundFunctionCreate, step 2.
    1478           0 :     RootedObject proto(cx);
    1479             :     if (!GetPrototype(cx, targetObj, &proto))
    1480             :         return false;
    1481           0 : 
    1482           0 :     // 9.4.1.3 BoundFunctionCreate, step 7.
    1483             :     if (bound->staticPrototype() != proto) {
    1484             :         if (!SetPrototype(cx, bound, proto))
    1485             :             return false;
    1486           0 :     }
    1487           0 : 
    1488             :     double length = 0.0;
    1489             : 
    1490             :     // Try to avoid invoking the resolve hook.
    1491           0 :     if (targetObj->is<JSFunction>() && !targetObj->as<JSFunction>().hasResolvedLength()) {
    1492             :         RootedValue targetLength(cx);
    1493             :         if (!JSFunction::getUnresolvedLength(cx, targetObj.as<JSFunction>(), &targetLength))
    1494           0 :             return false;
    1495           0 : 
    1496           0 :         length = Max(0.0, targetLength.toNumber() - argCount);
    1497           0 :     } else {
    1498             :         // 19.2.3.2 Function.prototype.bind, step 5.
    1499           0 :         bool hasLength;
    1500             :         RootedId idRoot(cx, NameToId(cx->names().length));
    1501             :         if (!HasOwnProperty(cx, targetObj, idRoot, &hasLength))
    1502             :             return false;
    1503           0 : 
    1504           0 :         // 19.2.3.2 Function.prototype.bind, step 6.
    1505           0 :         if (hasLength) {
    1506             :             RootedValue targetLength(cx);
    1507             :             if (!GetProperty(cx, targetObj, targetObj, idRoot, &targetLength))
    1508           0 :                 return false;
    1509           0 : 
    1510           0 :             if (targetLength.isNumber())
    1511           0 :                 length = Max(0.0, JS::ToInteger(targetLength.toNumber()) - argCount);
    1512             :         }
    1513           0 : 
    1514           0 :         // 19.2.3.2 Function.prototype.bind, step 7 (implicit).
    1515             :     }
    1516             : 
    1517             :     // 19.2.3.2 Function.prototype.bind, step 8.
    1518             :     bound->setExtendedSlot(BOUND_FUN_LENGTH_SLOT, NumberValue(length));
    1519             : 
    1520             :     MOZ_ASSERT(!bound->hasGuessedAtom());
    1521           0 : 
    1522             :     // Try to avoid invoking the resolve hook.
    1523           0 :     JSAtom* name = nullptr;
    1524             :     if (targetObj->is<JSFunction>() && !targetObj->as<JSFunction>().hasResolvedName()) {
    1525             :         JSFunction* targetFn = &targetObj->as<JSFunction>();
    1526           0 : 
    1527           0 :         // If the target is a bound function with a prefixed name, we can't
    1528           0 :         // lazily compute the full name in getBoundFunctionName(), therefore
    1529             :         // we need to append the bound function name prefix here.
    1530             :         if (targetFn->isBoundFunction() && targetFn->hasBoundFunctionNamePrefix()) {
    1531             :             name = AppendBoundFunctionPrefix(cx, targetFn->explicitName());
    1532             :             if (!name)
    1533           0 :                 return false;
    1534           0 :             bound->setPrefixedBoundFunctionName(name);
    1535           0 :         } else {
    1536             :             name = targetFn->infallibleGetUnresolvedName(cx);
    1537           0 :             if (name)
    1538             :                 bound->setAtom(name);
    1539           0 :         }
    1540           0 :     }
    1541           0 : 
    1542             :     // 19.2.3.2 Function.prototype.bind, steps 9-11.
    1543             :     if (!name) {
    1544             :         // 19.2.3.2 Function.prototype.bind, step 9.
    1545             :         RootedValue targetName(cx);
    1546           0 :         if (!GetProperty(cx, targetObj, targetObj, cx->names().name, &targetName))
    1547             :             return false;
    1548           0 : 
    1549           0 :         // 19.2.3.2 Function.prototype.bind, step 10.
    1550           0 :         if (!targetName.isString())
    1551             :             targetName.setString(cx->names().empty);
    1552             : 
    1553           0 :         // If the target itself is a bound function (with a resolved name), we
    1554           0 :         // can't compute the full name in getBoundFunctionName() based only on
    1555             :         // the number of bound target functions, therefore we need to store
    1556             :         // the complete prefixed name here.
    1557             :         if (targetObj->is<JSFunction>() && targetObj->as<JSFunction>().isBoundFunction()) {
    1558             :             name = AppendBoundFunctionPrefix(cx, targetName.toString());
    1559             :             if (!name)
    1560           0 :                 return false;
    1561           0 :             bound->setPrefixedBoundFunctionName(name);
    1562           0 :         } else {
    1563             :             name = AtomizeString(cx, targetName.toString());
    1564           0 :             if (!name)
    1565             :                 return false;
    1566           0 :             bound->setAtom(name);
    1567           0 :         }
    1568             :     }
    1569           0 : 
    1570             :     return true;
    1571             : }
    1572             : 
    1573             : /* static */ bool
    1574             : JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFunction fun)
    1575             : {
    1576             :     MOZ_ASSERT(fun->isInterpretedLazy());
    1577           0 : 
    1578             :     Rooted<LazyScript*> lazy(cx, fun->lazyScriptOrNull());
    1579           0 :     if (lazy) {
    1580             :         RootedScript script(cx, lazy->maybeScript());
    1581           0 : 
    1582           0 :         // Only functions without inner functions or direct eval are
    1583           0 :         // re-lazified. Functions with either of those are on the static scope
    1584             :         // chain of their inner functions, or in the case of eval, possibly
    1585             :         // eval'd inner functions. This prohibits re-lazification as
    1586             :         // StaticScopeIter queries needsCallObject of those functions, which
    1587             :         // requires a non-lazy script.  Note that if this ever changes,
    1588             :         // XDRRelazificationInfo will have to be fixed.
    1589             :         bool canRelazify = !lazy->numInnerFunctions() && !lazy->hasDirectEval();
    1590             : 
    1591             :         if (script) {
    1592           0 :             fun->setUnlazifiedScript(script);
    1593             :             // Remember the lazy script on the compiled script, so it can be
    1594           0 :             // stored on the function again in case of re-lazification.
    1595           0 :             if (canRelazify)
    1596             :                 script->setLazyScript(lazy);
    1597             :             return true;
    1598           0 :         }
    1599           0 : 
    1600             :         if (fun != lazy->functionNonDelazifying()) {
    1601             :             if (!LazyScript::functionDelazifying(cx, lazy))
    1602             :                 return false;
    1603           0 :             script = lazy->functionNonDelazifying()->nonLazyScript();
    1604           0 :             if (!script)
    1605             :                 return false;
    1606           0 : 
    1607           0 :             fun->setUnlazifiedScript(script);
    1608             :             return true;
    1609             :         }
    1610           0 : 
    1611           0 :         MOZ_ASSERT(lazy->scriptSource()->hasSourceData());
    1612             : 
    1613             :         // Parse and compile the script from source.
    1614           0 :         size_t lazyLength = lazy->sourceEnd() - lazy->sourceStart();
    1615             :         UncompressedSourceCache::AutoHoldEntry holder;
    1616             :         ScriptSource::PinnedChars chars(cx, lazy->scriptSource(), holder,
    1617           0 :                                         lazy->sourceStart(), lazyLength);
    1618           0 :         if (!chars.get())
    1619           0 :             return false;
    1620           0 : 
    1621           0 :         if (!frontend::CompileLazyFunction(cx, lazy, chars.get(), lazyLength)) {
    1622             :             // The frontend may have linked the function and the non-lazy
    1623             :             // script together during bytecode compilation. Reset it now on
    1624           0 :             // error.
    1625             :             fun->initLazyScript(lazy);
    1626             :             if (lazy->hasScript())
    1627             :                 lazy->resetScript();
    1628           0 :             return false;
    1629           0 :         }
    1630           0 : 
    1631             :         script = fun->nonLazyScript();
    1632             : 
    1633             :         // Remember the compiled script on the lazy script itself, in case
    1634           0 :         // there are clones of the function still pointing to the lazy script.
    1635             :         if (!lazy->maybeScript())
    1636             :             lazy->initScript(script);
    1637             : 
    1638           0 :         // Try to insert the newly compiled script into the lazy script cache.
    1639           0 :         if (canRelazify) {
    1640             :             // A script's starting column isn't set by the bytecode emitter, so
    1641             :             // specify this from the lazy script so that if an identical lazy
    1642           0 :             // script is encountered later a match can be determined.
    1643             :             script->setColumn(lazy->column());
    1644             : 
    1645             :             // Remember the lazy script on the compiled script, so it can be
    1646           0 :             // stored on the function again in case of re-lazification.
    1647             :             // Only functions without inner functions are re-lazified.
    1648             :             script->setLazyScript(lazy);
    1649             :         }
    1650             : 
    1651           0 :         // XDR the newly delazified function.
    1652             :         if (script->scriptSource()->hasEncoder()) {
    1653             :             RootedScriptSourceObject sourceObject(cx, &lazy->sourceObject());
    1654             :             if (!script->scriptSource()->xdrEncodeFunction(cx, fun, sourceObject))
    1655           0 :                 return false;
    1656           0 :         }
    1657           0 : 
    1658           0 :         return true;
    1659             :     }
    1660             : 
    1661             :     /* Lazily cloned self-hosted script. */
    1662             :     MOZ_ASSERT(fun->isSelfHostedBuiltin());
    1663             :     RootedAtom funAtom(cx, &fun->getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).toString()->asAtom());
    1664             :     if (!funAtom)
    1665           0 :         return false;
    1666           0 :     Rooted<PropertyName*> funName(cx, funAtom->asPropertyName());
    1667           0 :     return cx->runtime()->cloneSelfHostedFunctionScript(cx, funName, fun);
    1668             : }
    1669           0 : 
    1670           0 : void
    1671             : JSFunction::maybeRelazify(JSRuntime* rt)
    1672             : {
    1673             :     // Try to relazify functions with a non-lazy script. Note: functions can be
    1674           0 :     // marked as interpreted despite having no script yet at some points when
    1675             :     // parsing.
    1676             :     if (!hasScript() || !u.scripted.s.script_)
    1677             :         return;
    1678             : 
    1679           0 :     // Don't relazify functions in compartments that are active.
    1680             :     Realm* realm = this->realm();
    1681             :     if (!rt->allowRelazificationForTesting) {
    1682             :         if (realm->compartment()->gcState.hasEnteredRealm)
    1683           0 :             return;
    1684           0 : 
    1685           0 :         MOZ_ASSERT(!realm->hasBeenEnteredIgnoringJit());
    1686             :     }
    1687             : 
    1688           0 :     // The caller should have checked we're not in the self-hosting zone (it's
    1689             :     // shared with worker runtimes so relazifying functions in it will race).
    1690             :     MOZ_ASSERT(!realm->isSelfHostingRealm());
    1691             : 
    1692             :     // Don't relazify if the realm is being debugged.
    1693           0 :     if (realm->isDebuggee())
    1694             :         return;
    1695             : 
    1696           0 :     // Don't relazify if the realm and/or runtime is instrumented to
    1697             :     // collect code coverage for analysis.
    1698             :     if (realm->collectCoverageForDebug())
    1699             :         return;
    1700             : 
    1701           0 :     // Don't relazify functions with JIT code.
    1702             :     if (!u.scripted.s.script_->isRelazifiable())
    1703             :         return;
    1704             : 
    1705           0 :     // To delazify self-hosted builtins we need the name of the function
    1706             :     // to clone. This name is stored in the first extended slot. Since
    1707             :     // that slot is sometimes also used for other purposes, make sure it
    1708             :     // contains a string.
    1709             :     if (isSelfHostedBuiltin() &&
    1710             :         (!isExtended() || !getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).isString()))
    1711             :     {
    1712           0 :         return;
    1713           0 :     }
    1714             : 
    1715             :     JSScript* script = nonLazyScript();
    1716             : 
    1717             :     flags_ &= ~INTERPRETED;
    1718           0 :     flags_ |= INTERPRETED_LAZY;
    1719             :     LazyScript* lazy = script->maybeLazyScript();
    1720           0 :     u.scripted.s.lazy_ = lazy;
    1721           0 :     if (lazy) {
    1722           0 :         MOZ_ASSERT(!isSelfHostedBuiltin());
    1723           0 :     } else {
    1724           0 :         MOZ_ASSERT(isSelfHostedBuiltin());
    1725           0 :         MOZ_ASSERT(isExtended());
    1726             :         MOZ_ASSERT(getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).toString()->isAtom());
    1727           0 :     }
    1728           0 : 
    1729           0 :     realm->scheduleDelazificationForDebugger();
    1730             : }
    1731             : 
    1732             : const JSFunctionSpec js::function_methods[] = {
    1733             :     JS_FN(js_toSource_str,   fun_toSource,   0,0),
    1734             :     JS_FN(js_toString_str,   fun_toString,   0,0),
    1735             :     JS_FN(js_apply_str,      fun_apply,      2,0),
    1736             :     JS_FN(js_call_str,       fun_call,       1,0),
    1737             :     JS_SELF_HOSTED_FN("bind", "FunctionBind", 2, 0),
    1738             :     JS_SYM_FN(hasInstance, fun_symbolHasInstance, 1, JSPROP_READONLY | JSPROP_PERMANENT),
    1739             :     JS_FS_END
    1740             : };
    1741             : 
    1742             : // ES2018 draft rev 2aea8f3e617b49df06414eb062ab44fad87661d3
    1743             : // 19.2.1.1.1 CreateDynamicFunction( constructor, newTarget, kind, args )
    1744             : static bool
    1745             : CreateDynamicFunction(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
    1746             :                       FunctionAsyncKind asyncKind)
    1747             : {
    1748          23 :     // Steps 1-5.
    1749             :     // Block this call if security callbacks forbid it.
    1750             :     Handle<GlobalObject*> global = cx->global();
    1751             :     if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
    1752             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
    1753          92 :         return false;
    1754          23 :     }
    1755           0 : 
    1756           0 :     bool isGenerator = generatorKind == GeneratorKind::Generator;
    1757             :     bool isAsync = asyncKind == FunctionAsyncKind::AsyncFunction;
    1758             : 
    1759          23 :     RootedScript maybeScript(cx);
    1760          23 :     const char* filename;
    1761             :     unsigned lineno;
    1762          46 :     bool mutedErrors;
    1763             :     uint32_t pcOffset;
    1764             :     DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset,
    1765             :                                          &mutedErrors);
    1766             : 
    1767           0 :     const char* introductionType = "Function";
    1768           0 :     if (isAsync) {
    1769             :         if (isGenerator)
    1770          23 :             introductionType = "AsyncGenerator";
    1771           0 :         else
    1772           0 :             introductionType = "AsyncFunction";
    1773             :     } else if (isGenerator) {
    1774             :         introductionType = "GeneratorFunction";
    1775           0 :     }
    1776           0 : 
    1777           0 :     const char* introducerFilename = filename;
    1778             :     if (maybeScript && maybeScript->scriptSource()->introducerFilename())
    1779             :         introducerFilename = maybeScript->scriptSource()->introducerFilename();
    1780           0 : 
    1781           0 :     CompileOptions options(cx);
    1782           0 :     options.setMutedErrors(mutedErrors)
    1783             :            .setFileAndLine(filename, 1)
    1784           0 :            .setNoScriptRval(false)
    1785          46 :            .setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset);
    1786           0 : 
    1787          46 :     StringBuffer sb(cx);
    1788           0 : 
    1789             :     if (isAsync) {
    1790          69 :         if (!sb.append("async "))
    1791             :             return false;
    1792           0 :     }
    1793           0 :     if (!sb.append("function"))
    1794             :          return false;
    1795             :     if (isGenerator) {
    1796          23 :         if (!sb.append('*'))
    1797             :             return false;
    1798          23 :     }
    1799           0 : 
    1800             :     if (!sb.append(" anonymous("))
    1801             :         return false;
    1802             : 
    1803           0 :     if (args.length() > 1) {
    1804             :         RootedString str(cx);
    1805             : 
    1806           0 :         // Steps 10, 14.d.
    1807          44 :         unsigned n = args.length() - 1;
    1808             : 
    1809             :         for (unsigned i = 0; i < n; i++) {
    1810           0 :             // Steps 14.a-b, 14.d.i-ii.
    1811             :             str = ToString<CanGC>(cx, args[i]);
    1812           0 :             if (!str)
    1813             :                 return false;
    1814         192 : 
    1815           0 :             // Steps 14.b, 14.d.iii.
    1816           0 :             if (!sb.append(str))
    1817             :                  return false;
    1818             : 
    1819          64 :             if (i < args.length() - 2) {
    1820             :                 // Step 14.d.iii.
    1821             :                 if (!sb.append(','))
    1822          64 :                     return false;
    1823             :             }
    1824          42 :         }
    1825             :     }
    1826             : 
    1827             :     if (!sb.append('\n'))
    1828             :         return false;
    1829             : 
    1830           0 :     // Remember the position of ")".
    1831             :     Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
    1832             :     MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
    1833             : 
    1834          46 :     if (!sb.append(FunctionConstructorMedialSigils))
    1835             :         return false;
    1836             : 
    1837          23 :     if (args.length() > 0) {
    1838             :         // Steps 13, 14.e, 15.
    1839             :         RootedString body(cx, ToString<CanGC>(cx, args[args.length() - 1]));
    1840           0 :         if (!body || !sb.append(body))
    1841             :              return false;
    1842          69 :      }
    1843           0 : 
    1844           0 :     if (!sb.append(FunctionConstructorFinalBrace))
    1845             :         return false;
    1846             : 
    1847           0 :     // The parser only accepts two byte strings.
    1848             :     if (!sb.ensureTwoByteChars())
    1849             :         return false;
    1850             : 
    1851           0 :     RootedString functionText(cx, sb.finishString());
    1852             :     if (!functionText)
    1853             :         return false;
    1854          46 : 
    1855          23 :     /*
    1856             :      * NB: (new Function) is not lexically closed by its caller, it's just an
    1857             :      * anonymous function in the top-level scope that its constructor inhabits.
    1858             :      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
    1859             :      * and so would a call to f from another top-level's script or function.
    1860             :      */
    1861             :     RootedAtom anonymousAtom(cx, cx->names().anonymous);
    1862             : 
    1863             :     // Initialize the function with the default prototype:
    1864          69 :     // Leave as nullptr to get the default from clasp for normal functions.
    1865             :     // Use %Generator% for generators and the unwrapped function of async
    1866             :     // functions and async generators.
    1867             :     RootedObject defaultProto(cx);
    1868             :     if (isGenerator || isAsync) {
    1869             :         defaultProto = GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, global);
    1870          46 :         if (!defaultProto)
    1871          23 :             return false;
    1872           0 :     }
    1873           0 : 
    1874             :     // Step 30-37 (reordered).
    1875             :     RootedObject globalLexical(cx, &global->lexicalEnvironment());
    1876             :     JSFunction::Flags flags = (isGenerator || isAsync)
    1877             :                               ? JSFunction::INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC
    1878           0 :                               : JSFunction::INTERPRETED_LAMBDA;
    1879             :     AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
    1880          23 :     RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
    1881          23 :                                                 flags, globalLexical,
    1882           0 :                                                 anonymousAtom, defaultProto,
    1883           0 :                                                 allocKind, TenuredObject));
    1884             :     if (!fun)
    1885             :         return false;
    1886           0 : 
    1887          23 :     if (!JSFunction::setTypeForScriptedFunction(cx, fun))
    1888             :         return false;
    1889             : 
    1890           0 :     // Steps 7.a-b, 8.a-b, 9.a-b, 16-28.
    1891             :     AutoStableStringChars stableChars(cx);
    1892             :     if (!stableChars.initTwoByte(cx, functionText))
    1893             :         return false;
    1894           0 : 
    1895           0 :     mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
    1896             :     SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
    1897             :                                               ? SourceBufferHolder::GiveOwnership
    1898           0 :                                               : SourceBufferHolder::NoOwnership;
    1899           0 :     SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
    1900           0 :     if (isAsync) {
    1901           0 :         if (isGenerator) {
    1902          46 :             if (!CompileStandaloneAsyncGenerator(cx, &fun, options, srcBuf, parameterListEnd))
    1903          23 :                 return false;
    1904           0 :         } else {
    1905           0 :             if (!CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd))
    1906             :                 return false;
    1907             :         }
    1908           0 :     } else {
    1909             :         if (isGenerator) {
    1910             :             if (!CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd))
    1911             :                 return false;
    1912           0 :         } else {
    1913           0 :             if (!CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd))
    1914             :                 return false;
    1915             :         }
    1916          46 :     }
    1917             : 
    1918             :     // Steps 6, 29.
    1919             :     RootedObject proto(cx);
    1920             :     if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
    1921             :         return false;
    1922           0 : 
    1923          23 :     if (isAsync) {
    1924             :         // Create the async function wrapper.
    1925             :         JSObject* wrapped;
    1926           0 :         if (isGenerator) {
    1927             :             wrapped = proto
    1928             :                       ? WrapAsyncGeneratorWithProto(cx, fun, proto)
    1929           0 :                       : WrapAsyncGenerator(cx, fun);
    1930           0 :         } else {
    1931           0 :             // Step 9.d, use %AsyncFunctionPrototype% as the fallback prototype.
    1932           0 :             wrapped = proto
    1933             :                       ? WrapAsyncFunctionWithProto(cx, fun, proto)
    1934             :                       : WrapAsyncFunction(cx, fun);
    1935           0 :         }
    1936           0 :         if (!wrapped)
    1937           0 :             return false;
    1938             : 
    1939           0 :         fun = &wrapped->as<JSFunction>();
    1940             :     } else {
    1941             :         // Steps 7.d, 8.d (implicit).
    1942           0 :         // Call SetPrototype if an explicit prototype was given.
    1943             :         if (proto && !SetPrototype(cx, fun, proto))
    1944             :             return false;
    1945             :     }
    1946          46 : 
    1947             :     // Step 38.
    1948             :     args.rval().setObject(*fun);
    1949             :     return true;
    1950             : }
    1951          69 : 
    1952           0 : bool
    1953             : js::Function(JSContext* cx, unsigned argc, Value* vp)
    1954             : {
    1955             :     CallArgs args = CallArgsFromVp(argc, vp);
    1956           0 :     return CreateDynamicFunction(cx, args, GeneratorKind::NotGenerator,
    1957             :                                  FunctionAsyncKind::SyncFunction);
    1958          23 : }
    1959             : 
    1960           0 : bool
    1961             : js::Generator(JSContext* cx, unsigned argc, Value* vp)
    1962             : {
    1963             :     CallArgs args = CallArgsFromVp(argc, vp);
    1964           0 :     return CreateDynamicFunction(cx, args, GeneratorKind::Generator,
    1965             :                                  FunctionAsyncKind::SyncFunction);
    1966           0 : }
    1967             : 
    1968           0 : bool
    1969             : js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
    1970             : {
    1971             :     CallArgs args = CallArgsFromVp(argc, vp);
    1972           0 :     return CreateDynamicFunction(cx, args, GeneratorKind::NotGenerator,
    1973             :                                  FunctionAsyncKind::AsyncFunction);
    1974           0 : }
    1975             : 
    1976           0 : bool
    1977             : js::AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp)
    1978             : {
    1979             :     CallArgs args = CallArgsFromVp(argc, vp);
    1980           0 :     return CreateDynamicFunction(cx, args, GeneratorKind::Generator,
    1981             :                                  FunctionAsyncKind::AsyncFunction);
    1982           0 : }
    1983             : 
    1984           0 : bool
    1985             : JSFunction::isBuiltinFunctionConstructor()
    1986             : {
    1987             :     return maybeNative() == Function || maybeNative() == Generator;
    1988         398 : }
    1989             : 
    1990           0 : bool
    1991             : JSFunction::needsExtraBodyVarEnvironment() const
    1992             : {
    1993             :     MOZ_ASSERT(!isInterpretedLazy());
    1994           0 : 
    1995             :     if (isNative())
    1996        1184 :         return false;
    1997             : 
    1998        1184 :     if (!nonLazyScript()->functionHasExtraBodyVarScope())
    1999             :         return false;
    2000             : 
    2001        1184 :     return nonLazyScript()->functionExtraBodyVarScope()->hasEnvironment();
    2002             : }
    2003             : 
    2004           0 : bool
    2005             : JSFunction::needsNamedLambdaEnvironment() const
    2006             : {
    2007             :     MOZ_ASSERT(!isInterpretedLazy());
    2008           0 : 
    2009             :     if (!isNamedLambda())
    2010       24056 :         return false;
    2011             : 
    2012           0 :     LexicalScope* scope = nonLazyScript()->maybeNamedLambdaScope();
    2013             :     if (!scope)
    2014             :         return false;
    2015           0 : 
    2016        2048 :     return scope->hasEnvironment();
    2017             : }
    2018             : 
    2019           0 : JSFunction*
    2020             : js::NewScriptedFunction(JSContext* cx, unsigned nargs,
    2021             :                         JSFunction::Flags flags, HandleAtom atom,
    2022             :                         HandleObject proto /* = nullptr */,
    2023        3906 :                         gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
    2024             :                         NewObjectKind newKind /* = GenericObject */,
    2025             :                         HandleObject enclosingEnvArg /* = nullptr */)
    2026             : {
    2027             :     RootedObject enclosingEnv(cx, enclosingEnvArg);
    2028             :     if (!enclosingEnv)
    2029             :         enclosingEnv = &cx->global()->lexicalEnvironment();
    2030           0 :     return NewFunctionWithProto(cx, nullptr, nargs, flags, enclosingEnv,
    2031        3906 :                                 atom, proto, allocKind, newKind);
    2032        9342 : }
    2033        7812 : 
    2034        7812 : #ifdef DEBUG
    2035             : static JSObject*
    2036             : SkipEnvironmentObjects(JSObject* env)
    2037             : {
    2038             :     if (!env)
    2039           0 :         return nullptr;
    2040             :     while (env->is<EnvironmentObject>())
    2041       72723 :         env = &env->as<EnvironmentObject>().enclosingEnvironment();
    2042             :     return env;
    2043      137680 : }
    2044      117222 : 
    2045             : static bool
    2046             : NewFunctionEnvironmentIsWellFormed(JSContext* cx, HandleObject env)
    2047             : {
    2048             :     // Assert that the terminating environment is null, global, or a debug
    2049       72723 :     // scope proxy. All other cases of polluting global scope behavior are
    2050             :     // handled by EnvironmentObjects (viz. non-syntactic DynamicWithObject and
    2051             :     // NonSyntacticVariablesObject).
    2052             :     RootedObject terminatingEnv(cx, SkipEnvironmentObjects(env));
    2053             :     return !terminatingEnv || terminatingEnv == cx->global() ||
    2054             :            terminatingEnv->is<DebugEnvironmentProxy>();
    2055      145446 : }
    2056      165904 : #endif
    2057       72722 : 
    2058             : JSFunction*
    2059             : js::NewFunctionWithProto(JSContext* cx, Native native,
    2060             :                          unsigned nargs, JSFunction::Flags flags, HandleObject enclosingEnv,
    2061             :                          HandleAtom atom, HandleObject proto,
    2062       56237 :                          gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
    2063             :                          NewObjectKind newKind /* = GenericObject */)
    2064             : {
    2065             :     MOZ_ASSERT(allocKind == AllocKind::FUNCTION || allocKind == AllocKind::FUNCTION_EXTENDED);
    2066             :     MOZ_ASSERT_IF(native, !enclosingEnv);
    2067             :     MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv));
    2068           0 : 
    2069           0 :     JSFunction* fun = NewObjectWithClassProto<JSFunction>(cx, proto, allocKind, newKind);
    2070       56237 :     if (!fun)
    2071             :         return nullptr;
    2072           0 : 
    2073           0 :     if (allocKind == AllocKind::FUNCTION_EXTENDED)
    2074             :         flags = JSFunction::Flags(flags | JSFunction::EXTENDED);
    2075             : 
    2076           0 :     /* Initialize all function members. */
    2077           0 :     fun->setArgCount(uint16_t(nargs));
    2078             :     fun->setFlags(flags);
    2079             :     if (fun->isInterpreted()) {
    2080           0 :         MOZ_ASSERT(!native);
    2081           0 :         if (fun->isInterpretedLazy())
    2082       56237 :             fun->initLazyScript(nullptr);
    2083           0 :         else
    2084           0 :             fun->initScript(nullptr);
    2085        3114 :         fun->initEnvironment(enclosingEnv);
    2086             :     } else {
    2087           0 :         MOZ_ASSERT(fun->isNative());
    2088           0 :         MOZ_ASSERT(native);
    2089             :         if (fun->isWasmOptimized())
    2090       39274 :             fun->initWasmNative(native);
    2091           0 :         else
    2092       39274 :             fun->initNative(native, nullptr);
    2093           0 :     }
    2094             :     if (allocKind == AllocKind::FUNCTION_EXTENDED)
    2095           0 :         fun->initializeExtended();
    2096             :     fun->initAtom(atom);
    2097           0 : 
    2098       25678 :     return fun;
    2099       56236 : }
    2100             : 
    2101           0 : bool
    2102             : js::CanReuseScriptForClone(JS::Compartment* compartment, HandleFunction fun,
    2103             :                            HandleObject newParent)
    2104             : {
    2105       32010 :     MOZ_ASSERT(fun->isInterpreted());
    2106             : 
    2107             :     if (compartment != fun->compartment() ||
    2108           0 :         fun->isSingleton() ||
    2109             :         ObjectGroup::useSingletonForClone(fun))
    2110      127081 :     {
    2111      125163 :         return false;
    2112       31051 :     }
    2113             : 
    2114             :     if (newParent->is<GlobalObject>())
    2115             :         return true;
    2116             : 
    2117       62102 :     // Don't need to clone the script if newParent is a syntactic scope, since
    2118             :     // in that case we have some actual scope objects on our scope chain and
    2119             :     // whatnot; whoever put them there should be responsible for setting our
    2120             :     // script's flags appropriately.  We hit this case for JSOP_LAMBDA, for
    2121             :     // example.
    2122             :     if (IsSyntacticEnvironment(newParent))
    2123             :         return true;
    2124             : 
    2125       31051 :     // We need to clone the script if we're not already marked as having a
    2126             :     // non-syntactic scope.
    2127             :     return fun->hasScript()
    2128             :         ? fun->nonLazyScript()->hasNonSyntacticScope()
    2129             :         : fun->lazyScript()->enclosingScope()->hasOnChain(ScopeKind::NonSyntactic);
    2130       27850 : }
    2131       41775 : 
    2132           0 : static inline JSFunction*
    2133             : NewFunctionClone(JSContext* cx, HandleFunction fun, NewObjectKind newKind,
    2134             :                  gc::AllocKind allocKind, HandleObject proto)
    2135             : {
    2136           0 :     RootedObject cloneProto(cx, proto);
    2137             :     if (!proto && (fun->isGenerator() || fun->isAsync())) {
    2138             :         cloneProto = GlobalObject::getOrCreateGeneratorFunctionPrototype(cx, cx->global());
    2139       33658 :         if (!cloneProto)
    2140       67044 :             return nullptr;
    2141        2262 :     }
    2142           0 : 
    2143             :     RootedFunction clone(cx);
    2144             :     clone = NewObjectWithClassProto<JSFunction>(cx, cloneProto, allocKind, newKind);
    2145             :     if (!clone)
    2146       33658 :         return nullptr;
    2147       33658 : 
    2148       16829 :     // JSFunction::HAS_INFERRED_NAME can be set at compile-time and at
    2149             :     // runtime. In the latter case we should actually clear the flag before
    2150             :     // cloning the function, but since we can't differentiate between both
    2151             :     // cases here, we'll end up with a momentarily incorrect function name.
    2152             :     // This will be fixed up in SetFunctionNameIfNoOwnName(), which should
    2153             :     // happen through JSOP_SETFUNNAME directly after JSOP_LAMBDA.
    2154             :     constexpr uint16_t NonCloneableFlags = JSFunction::EXTENDED |
    2155             :                                            JSFunction::RESOLVED_LENGTH |
    2156             :                                            JSFunction::RESOLVED_NAME;
    2157             : 
    2158             :     uint16_t flags = fun->flags() & ~NonCloneableFlags;
    2159           0 :     if (allocKind == AllocKind::FUNCTION_EXTENDED)
    2160             :         flags |= JSFunction::EXTENDED;
    2161           0 : 
    2162           0 :     clone->setArgCount(fun->nargs());
    2163       11607 :     clone->setFlags(flags);
    2164             : 
    2165           0 :     JSAtom* atom = fun->displayAtom();
    2166           0 :     if (atom)
    2167             :         cx->markAtom(atom);
    2168       33658 :     clone->initAtom(atom);
    2169           0 : 
    2170           0 :     if (allocKind == AllocKind::FUNCTION_EXTENDED) {
    2171           0 :         if (fun->isExtended() && fun->compartment() == cx->compartment()) {
    2172             :             for (unsigned i = 0; i < FunctionExtended::NUM_EXTENDED_SLOTS; i++)
    2173       16829 :                 clone->initExtendedSlot(i, fun->getExtendedSlot(i));
    2174           0 :         } else {
    2175       57330 :             clone->initializeExtended();
    2176       68796 :         }
    2177             :     }
    2178           0 : 
    2179             :     return clone;
    2180             : }
    2181             : 
    2182           0 : JSFunction*
    2183             : js::CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject enclosingEnv,
    2184             :                              gc::AllocKind allocKind /* = FUNCTION */ ,
    2185             :                              NewObjectKind newKind /* = GenericObject */,
    2186       15523 :                              HandleObject proto /* = nullptr */)
    2187             : {
    2188             :     MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv));
    2189             :     MOZ_ASSERT(fun->isInterpreted());
    2190             :     MOZ_ASSERT(!fun->isBoundFunction());
    2191       15523 :     MOZ_ASSERT(CanReuseScriptForClone(cx->compartment(), fun, enclosingEnv));
    2192           0 : 
    2193           0 :     RootedFunction clone(cx, NewFunctionClone(cx, fun, newKind, allocKind, proto));
    2194       31046 :     if (!clone)
    2195             :         return nullptr;
    2196           0 : 
    2197           0 :     if (fun->hasScript()) {
    2198             :         clone->initScript(fun->nonLazyScript());
    2199             :         clone->initEnvironment(enclosingEnv);
    2200           1 :     } else {
    2201           1 :         MOZ_ASSERT(fun->isInterpretedLazy());
    2202           1 :         MOZ_ASSERT(fun->compartment() == clone->compartment());
    2203             :         LazyScript* lazy = fun->lazyScriptOrNull();
    2204           0 :         clone->initLazyScript(lazy);
    2205           0 :         clone->initEnvironment(enclosingEnv);
    2206           0 :     }
    2207           0 : 
    2208           0 :     /*
    2209             :      * Clone the function, reusing its script. We can use the same group as
    2210             :      * the original function provided that its prototype is correct.
    2211             :      */
    2212             :     if (fun->staticPrototype() == clone->staticPrototype())
    2213             :         clone->setGroup(fun->group());
    2214             :     return clone;
    2215       31046 : }
    2216       30890 : 
    2217           0 : JSFunction*
    2218             : js::CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject enclosingEnv,
    2219             :                            HandleScope newScope, gc::AllocKind allocKind /* = FUNCTION */,
    2220             :                            HandleObject proto /* = nullptr */)
    2221           0 : {
    2222             :     MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv));
    2223             :     MOZ_ASSERT(fun->isInterpreted());
    2224             :     MOZ_ASSERT(!fun->isBoundFunction());
    2225           0 : 
    2226           0 :     JSScript::AutoDelazify funScript(cx, fun);
    2227        1928 :     if (!funScript)
    2228             :         return nullptr;
    2229           0 : 
    2230           0 :     RootedFunction clone(cx, NewFunctionClone(cx, fun, SingletonObject, allocKind, proto));
    2231             :     if (!clone)
    2232             :         return nullptr;
    2233           0 : 
    2234           0 :     clone->initScript(nullptr);
    2235             :     clone->initEnvironment(enclosingEnv);
    2236             : 
    2237         964 :     /*
    2238        1928 :      * Across compartments or if we have to introduce a non-syntactic scope we
    2239             :      * have to clone the script for interpreted functions. Cross-compartment
    2240             :      * cloning only happens via JSAPI (JS::CloneFunctionObject) which
    2241             :      * dynamically ensures that 'script' has no enclosing lexical scope (only
    2242             :      * the global scope or other non-lexical scope).
    2243             :      */
    2244             : #ifdef DEBUG
    2245             :     RootedObject terminatingEnv(cx, enclosingEnv);
    2246             :     while (IsSyntacticEnvironment(terminatingEnv))
    2247             :         terminatingEnv = terminatingEnv->enclosingEnvironment();
    2248        1928 :     MOZ_ASSERT_IF(!terminatingEnv->is<GlobalObject>(),
    2249        2838 :                   newScope->hasOnChain(ScopeKind::NonSyntactic));
    2250        1874 : #endif
    2251           0 : 
    2252             :     RootedScript script(cx, fun->nonLazyScript());
    2253             :     MOZ_ASSERT(script->compartment() == fun->compartment());
    2254             :     MOZ_ASSERT(cx->compartment() == clone->compartment(),
    2255        1928 :                "Otherwise we could relazify clone below!");
    2256           0 : 
    2257           0 :     RootedScript clonedScript(cx, CloneScriptIntoFunction(cx, newScope, clone, script));
    2258             :     if (!clonedScript)
    2259             :         return nullptr;
    2260        2892 :     Debugger::onNewScript(cx, clonedScript);
    2261           0 : 
    2262             :     return clone;
    2263         964 : }
    2264             : 
    2265           0 : JSFunction*
    2266             : js::CloneAsmJSModuleFunction(JSContext* cx, HandleFunction fun)
    2267             : {
    2268             :     MOZ_ASSERT(fun->isNative());
    2269           0 :     MOZ_ASSERT(IsAsmJSModule(fun));
    2270             :     MOZ_ASSERT(fun->isExtended());
    2271           0 :     MOZ_ASSERT(cx->compartment() == fun->compartment());
    2272           0 : 
    2273           0 :     JSFunction* clone = NewFunctionClone(cx, fun, GenericObject, AllocKind::FUNCTION_EXTENDED,
    2274           0 :                                          /* proto = */ nullptr);
    2275             :     if (!clone)
    2276           0 :         return nullptr;
    2277           0 : 
    2278           0 :     MOZ_ASSERT(fun->native() == InstantiateAsmJS);
    2279             :     MOZ_ASSERT(!fun->hasJitInfo());
    2280             :     clone->initNative(InstantiateAsmJS, nullptr);
    2281           0 : 
    2282           0 :     clone->setGroup(fun->group());
    2283           0 :     return clone;
    2284             : }
    2285           0 : 
    2286           0 : JSFunction*
    2287             : js::CloneSelfHostingIntrinsic(JSContext* cx, HandleFunction fun)
    2288             : {
    2289             :     MOZ_ASSERT(fun->isNative());
    2290           0 :     MOZ_ASSERT(fun->realm()->isSelfHostingRealm());
    2291             :     MOZ_ASSERT(!fun->isExtended());
    2292         684 :     MOZ_ASSERT(cx->compartment() != fun->compartment());
    2293           0 : 
    2294           0 :     JSFunction* clone = NewFunctionClone(cx, fun, SingletonObject, AllocKind::FUNCTION,
    2295           0 :                                          /* proto = */ nullptr);
    2296             :     if (!clone)
    2297         684 :         return nullptr;
    2298           0 : 
    2299           0 :     clone->initNative(fun->native(), fun->hasJitInfo() ? fun->jitInfo() : nullptr);
    2300             :     return clone;
    2301             : }
    2302        1326 : 
    2303           0 : static JSAtom*
    2304             : SymbolToFunctionName(JSContext* cx, JS::Symbol* symbol, FunctionPrefixKind prefixKind)
    2305             : {
    2306             :     // Step 4.a.
    2307         859 :     JSAtom* desc = symbol->description();
    2308             : 
    2309             :     // Step 4.b, no prefix fastpath.
    2310           0 :     if (!desc && prefixKind == FunctionPrefixKind::None)
    2311             :         return cx->names().empty;
    2312             : 
    2313           0 :     // Step 5 (reordered).
    2314           0 :     StringBuffer sb(cx);
    2315             :     if (prefixKind == FunctionPrefixKind::Get) {
    2316             :         if (!sb.append("get "))
    2317           0 :             return nullptr;
    2318           0 :     } else if (prefixKind == FunctionPrefixKind::Set) {
    2319          25 :         if (!sb.append("set "))
    2320             :             return nullptr;
    2321         834 :     }
    2322           0 : 
    2323             :     // Step 4.b.
    2324             :     if (desc) {
    2325             :         // Step 4.c.
    2326             :         if (!sb.append('[') || !sb.append(desc) || !sb.append(']'))
    2327         859 :             return nullptr;
    2328             :     }
    2329        1718 :     return sb.finishAtom();
    2330             : }
    2331             : 
    2332           0 : static JSAtom*
    2333             : NameToFunctionName(JSContext* cx, HandleValue name, FunctionPrefixKind prefixKind)
    2334             : {
    2335             :     MOZ_ASSERT(name.isString() || name.isNumber());
    2336           0 : 
    2337             :     if (prefixKind == FunctionPrefixKind::None)
    2338       16160 :         return ToAtom<CanGC>(cx, name);
    2339             : 
    2340           0 :     JSString* nameStr = ToString(cx, name);
    2341           7 :     if (!nameStr)
    2342             :         return nullptr;
    2343           0 : 
    2344           0 :     StringBuffer sb(cx);
    2345             :     if (prefixKind == FunctionPrefixKind::Get) {
    2346             :         if (!sb.append("get "))
    2347       16153 :             return nullptr;
    2348           0 :     } else {
    2349        9868 :         if (!sb.append("set "))
    2350             :             return nullptr;
    2351             :     }
    2352        6285 :     if (!sb.append(nameStr))
    2353             :         return nullptr;
    2354             :     return sb.finishAtom();
    2355       16153 : }
    2356             : 
    2357       16153 : /*
    2358             :  * Return an atom for use as the name of a builtin method with the given
    2359             :  * property id.
    2360             :  *
    2361             :  * Function names are always strings. If id is the well-known @@iterator
    2362             :  * symbol, this returns "[Symbol.iterator]".  If a prefix is supplied the final
    2363             :  * name is |prefix + " " + name|.
    2364             :  *
    2365             :  * Implements steps 3-5 of 9.2.11 SetFunctionName in ES2016.
    2366             :  */
    2367             : JSAtom*
    2368             : js::IdToFunctionName(JSContext* cx, HandleId id,
    2369             :                      FunctionPrefixKind prefixKind /* = FunctionPrefixKind::None */)
    2370             : {
    2371       29363 :     MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SYMBOL(id) || JSID_IS_INT(id));
    2372             : 
    2373             :     // No prefix fastpath.
    2374           0 :     if (JSID_IS_ATOM(id) && prefixKind == FunctionPrefixKind::None)
    2375             :         return JSID_TO_ATOM(id);
    2376             : 
    2377       29363 :     // Step 3 (implicit).
    2378       24771 : 
    2379             :     // Step 4.
    2380             :     if (JSID_IS_SYMBOL(id))
    2381             :         return SymbolToFunctionName(cx, JSID_TO_SYMBOL(id), prefixKind);
    2382             : 
    2383           0 :     // Step 5.
    2384           0 :     RootedValue idv(cx, IdToValue(id));
    2385             :     return NameToFunctionName(cx, idv, prefixKind);
    2386             : }
    2387       32306 : 
    2388           0 : bool
    2389             : js::SetFunctionNameIfNoOwnName(JSContext* cx, HandleFunction fun, HandleValue name,
    2390             :                                FunctionPrefixKind prefixKind)
    2391             : {
    2392          42 :     MOZ_ASSERT(name.isString() || name.isSymbol() || name.isNumber());
    2393             : 
    2394             :     // An inferred name may already be set if this function is a clone of a
    2395          77 :     // singleton function. Clear the inferred name in all cases, even if we
    2396             :     // end up not adding a new inferred name if |fun| is a class constructor.
    2397             :     if (fun->hasInferredName()) {
    2398             :         MOZ_ASSERT(fun->isSingleton());
    2399             :         fun->clearInferredName();
    2400          84 :     }
    2401           0 : 
    2402           0 :     if (fun->isClassConstructor()) {
    2403             :         // A class may have static 'name' method or accessor.
    2404             :         if (fun->contains(cx, cx->names().name))
    2405          84 :             return true;
    2406             :     } else {
    2407           0 :         // Anonymous function shouldn't have own 'name' property at this point.
    2408             :         MOZ_ASSERT(!fun->containsPure(cx->names().name));
    2409             :     }
    2410             : 
    2411           0 :     JSAtom* funName = name.isSymbol()
    2412             :                       ? SymbolToFunctionName(cx, name.toSymbol(), prefixKind)
    2413             :                       : NameToFunctionName(cx, name, prefixKind);
    2414          42 :     if (!funName)
    2415          77 :         return false;
    2416          42 : 
    2417          42 :     // RESOLVED_NAME shouldn't yet be set, at least as long as we don't
    2418             :     // support the "static public fields" or "decorators" proposal.
    2419             :     // These two proposals allow to access class constructors before
    2420             :     // JSOP_SETFUNNAME is executed, which means user code may have set the
    2421             :     // RESOLVED_NAME flag when we reach this point.
    2422             :     MOZ_ASSERT(!fun->hasResolvedName());
    2423             : 
    2424             :     fun->setInferredName(funName);
    2425           0 : 
    2426             :     return true;
    2427          42 : }
    2428             : 
    2429           0 : JSFunction*
    2430             : js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native,
    2431             :                    unsigned nargs, unsigned flags, AllocKind allocKind /* = AllocKind::FUNCTION */)
    2432             : {
    2433           0 :     RootedAtom atom(cx, IdToFunctionName(cx, id));
    2434             :     if (!atom)
    2435             :         return nullptr;
    2436           0 : 
    2437           0 :     RootedFunction fun(cx);
    2438             :     if (!native)
    2439             :         fun = NewScriptedFunction(cx, nargs,
    2440        2308 :                                   JSFunction::INTERPRETED_LAZY, atom,
    2441           1 :                                   /* proto = */ nullptr,
    2442           0 :                                   allocKind, GenericObject, obj);
    2443             :     else if (flags & JSFUN_CONSTRUCTOR)
    2444             :         fun = NewNativeConstructor(cx, native, nargs, atom, allocKind);
    2445           0 :     else
    2446        1154 :         fun = NewNativeFunction(cx, native, nargs, atom, allocKind);
    2447           0 : 
    2448             :     if (!fun)
    2449        2200 :         return nullptr;
    2450             : 
    2451           0 :     RootedValue funVal(cx, ObjectValue(*fun));
    2452             :     if (!DefineDataProperty(cx, obj, id, funVal, flags & ~JSFUN_FLAGS_MASK))
    2453             :         return nullptr;
    2454           0 : 
    2455        2308 :     return fun;
    2456             : }
    2457             : 
    2458           0 : void
    2459             : js::ReportIncompatibleMethod(JSContext* cx, const CallArgs& args, const Class* clasp)
    2460             : {
    2461             :     RootedValue thisv(cx, args.thisv());
    2462           0 : 
    2463             : #ifdef DEBUG
    2464           0 :     if (thisv.isObject()) {
    2465             :         MOZ_ASSERT(thisv.toObject().getClass() != clasp ||
    2466             :                    !thisv.toObject().isNative() ||
    2467           0 :                    !thisv.toObject().staticPrototype() ||
    2468           0 :                    thisv.toObject().staticPrototype()->getClass() != clasp);
    2469             :     } else if (thisv.isString()) {
    2470             :         MOZ_ASSERT(clasp != &StringObject::class_);
    2471             :     } else if (thisv.isNumber()) {
    2472           0 :         MOZ_ASSERT(clasp != &NumberObject::class_);
    2473           0 :     } else if (thisv.isBoolean()) {
    2474           0 :         MOZ_ASSERT(clasp != &BooleanObject::class_);
    2475           0 :     } else if (thisv.isSymbol()) {
    2476           0 :         MOZ_ASSERT(clasp != &SymbolObject::class_);
    2477           0 :     } else {
    2478           0 :         MOZ_ASSERT(thisv.isUndefined() || thisv.isNull());
    2479           0 :     }
    2480             : #endif
    2481           0 : 
    2482             :     if (JSFunction* fun = ReportIfNotFunction(cx, args.calleev())) {
    2483             :         JSAutoByteString funNameBytes;
    2484             :         if (const char* funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
    2485           0 :             JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
    2486           0 :                                        clasp->name, funName, InformalValueTypeName(thisv));
    2487           0 :         }
    2488           0 :     }
    2489           0 : }
    2490             : 
    2491             : void
    2492           0 : js::ReportIncompatible(JSContext* cx, const CallArgs& args)
    2493             : {
    2494             :     if (JSFunction* fun = ReportIfNotFunction(cx, args.calleev())) {
    2495           0 :         JSAutoByteString funNameBytes;
    2496             :         if (const char* funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
    2497           0 :             JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_METHOD,
    2498           0 :                                        funName, "method", InformalValueTypeName(args.thisv()));
    2499           0 :         }
    2500           0 :     }
    2501           0 : }
    2502             : 
    2503             : namespace JS {
    2504           0 : namespace detail {
    2505             : 
    2506             : JS_PUBLIC_API(void)
    2507             : CheckIsValidConstructible(const Value& calleev)
    2508             : {
    2509             :     JSObject* callee = &calleev.toObject();
    2510           0 :     if (callee->is<JSFunction>())
    2511             :         MOZ_ASSERT(callee->as<JSFunction>().isConstructor());
    2512           0 :     else
    2513           0 :         MOZ_ASSERT(callee->constructHook() != nullptr);
    2514             : }
    2515             : 
    2516             : } // namespace detail
    2517             : } // namespace JS

Generated by: LCOV version 1.13-14-ga5dd952