js/src/jsfun.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     7 /*
     8  * JS function support.
     9  */
    11 #include "jsfuninlines.h"
    13 #include "mozilla/ArrayUtils.h"
    14 #include "mozilla/PodOperations.h"
    16 #include <string.h>
    18 #include "jsapi.h"
    19 #include "jsarray.h"
    20 #include "jsatom.h"
    21 #include "jscntxt.h"
    22 #include "jsobj.h"
    23 #include "jsproxy.h"
    24 #include "jsscript.h"
    25 #include "jsstr.h"
    26 #include "jstypes.h"
    27 #include "jswrapper.h"
    29 #include "builtin/Eval.h"
    30 #include "builtin/Object.h"
    31 #include "frontend/BytecodeCompiler.h"
    32 #include "frontend/TokenStream.h"
    33 #include "gc/Marking.h"
    34 #ifdef JS_ION
    35 #include "jit/Ion.h"
    36 #include "jit/JitFrameIterator.h"
    37 #endif
    38 #include "vm/Interpreter.h"
    39 #include "vm/Shape.h"
    40 #include "vm/StringBuffer.h"
    41 #include "vm/WrapperObject.h"
    42 #include "vm/Xdr.h"
    44 #include "jsscriptinlines.h"
    46 #include "vm/Interpreter-inl.h"
    47 #include "vm/Stack-inl.h"
    49 using namespace js;
    50 using namespace js::gc;
    51 using namespace js::types;
    52 using namespace js::frontend;
    54 using mozilla::ArrayLength;
    55 using mozilla::PodCopy;
    57 static bool
    58 fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValue vp)
    59 {
    60     RootedObject obj(cx, obj_);
    61     while (!obj->is<JSFunction>()) {
    62         if (!JSObject::getProto(cx, obj, &obj))
    63             return false;
    64         if (!obj)
    65             return true;
    66     }
    67     RootedFunction fun(cx, &obj->as<JSFunction>());
    69     /* Set to early to null in case of error */
    70     vp.setNull();
    72     /* Find fun's top-most activation record. */
    73     NonBuiltinScriptFrameIter iter(cx);
    74     for (; !iter.done(); ++iter) {
    75         if (!iter.isFunctionFrame() || iter.isEvalFrame())
    76             continue;
    77         if (iter.callee() == fun)
    78             break;
    79     }
    80     if (iter.done())
    81         return true;
    83     if (JSID_IS_ATOM(id, cx->names().arguments)) {
    84         if (fun->hasRest()) {
    85             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
    86                                  JSMSG_FUNCTION_ARGUMENTS_AND_REST);
    87             return false;
    88         }
    89         /* Warn if strict about f.arguments or equivalent unqualified uses. */
    90         if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT, js_GetErrorMessage,
    91                                           nullptr, JSMSG_DEPRECATED_USAGE, js_arguments_str)) {
    92             return false;
    93         }
    95         ArgumentsObject *argsobj = ArgumentsObject::createUnexpected(cx, iter);
    96         if (!argsobj)
    97             return false;
    99 #ifdef JS_ION
   100         // Disabling compiling of this script in IonMonkey.
   101         // IonMonkey does not guarantee |f.arguments| can be
   102         // fully recovered, so we try to mitigate observing this behavior by
   103         // detecting its use early.
   104         JSScript *script = iter.script();
   105         jit::ForbidCompilation(cx, script);
   106 #endif
   108         vp.setObject(*argsobj);
   109         return true;
   110     }
   112     if (JSID_IS_ATOM(id, cx->names().caller)) {
   113         ++iter;
   114         if (iter.done() || !iter.isFunctionFrame()) {
   115             JS_ASSERT(vp.isNull());
   116             return true;
   117         }
   119         /* Callsite clones should never escape to script. */
   120         JSObject &maybeClone = iter.calleev().toObject();
   121         if (maybeClone.is<JSFunction>())
   122             vp.setObject(*maybeClone.as<JSFunction>().originalFunction());
   123         else
   124             vp.set(iter.calleev());
   126         if (!cx->compartment()->wrap(cx, vp))
   127             return false;
   129         /*
   130          * Censor the caller if we don't have full access to it.
   131          */
   132         RootedObject caller(cx, &vp.toObject());
   133         if (caller->is<WrapperObject>() && Wrapper::wrapperHandler(caller)->hasSecurityPolicy()) {
   134             vp.setNull();
   135         } else if (caller->is<JSFunction>()) {
   136             JSFunction *callerFun = &caller->as<JSFunction>();
   137             if (callerFun->isInterpreted() && callerFun->strict()) {
   138                 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, nullptr,
   139                                              JSMSG_CALLER_IS_STRICT);
   140                 return false;
   141             }
   142         }
   144         return true;
   145     }
   147     MOZ_ASSUME_UNREACHABLE("fun_getProperty");
   148 }
   152 /* NB: no sentinels at ends -- use ArrayLength to bound loops.
   153  * Properties censored into [[ThrowTypeError]] in strict mode. */
   154 static const uint16_t poisonPillProps[] = {
   155     NAME_OFFSET(arguments),
   156     NAME_OFFSET(caller),
   157 };
   159 static bool
   160 fun_enumerate(JSContext *cx, HandleObject obj)
   161 {
   162     JS_ASSERT(obj->is<JSFunction>());
   164     RootedId id(cx);
   165     bool found;
   167     if (!obj->isBoundFunction() && !obj->as<JSFunction>().isArrow()) {
   168         id = NameToId(cx->names().prototype);
   169         if (!JSObject::hasProperty(cx, obj, id, &found))
   170             return false;
   171     }
   173     id = NameToId(cx->names().length);
   174     if (!JSObject::hasProperty(cx, obj, id, &found))
   175         return false;
   177     id = NameToId(cx->names().name);
   178     if (!JSObject::hasProperty(cx, obj, id, &found))
   179         return false;
   181     for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
   182         const uint16_t offset = poisonPillProps[i];
   183         id = NameToId(AtomStateOffsetToName(cx->names(), offset));
   184         if (!JSObject::hasProperty(cx, obj, id, &found))
   185             return false;
   186     }
   188     return true;
   189 }
   191 static JSObject *
   192 ResolveInterpretedFunctionPrototype(JSContext *cx, HandleObject obj)
   193 {
   194 #ifdef DEBUG
   195     JSFunction *fun = &obj->as<JSFunction>();
   196     JS_ASSERT(fun->isInterpreted());
   197     JS_ASSERT(!fun->isFunctionPrototype());
   198 #endif
   200     // Assert that fun is not a compiler-created function object, which
   201     // must never leak to script or embedding code and then be mutated.
   202     // Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
   203     JS_ASSERT(!IsInternalFunctionObject(obj));
   204     JS_ASSERT(!obj->isBoundFunction());
   206     // Make the prototype object an instance of Object with the same parent as
   207     // the function object itself, unless the function is an ES6 generator.  In
   208     // that case, per the 15 July 2013 ES6 draft, section 15.19.3, its parent is
   209     // the GeneratorObjectPrototype singleton.
   210     bool isStarGenerator = obj->as<JSFunction>().isStarGenerator();
   211     Rooted<GlobalObject*> global(cx, &obj->global());
   212     JSObject *objProto;
   213     if (isStarGenerator)
   214         objProto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global);
   215     else
   216         objProto = obj->global().getOrCreateObjectPrototype(cx);
   217     if (!objProto)
   218         return nullptr;
   219     const Class *clasp = &JSObject::class_;
   221     RootedObject proto(cx, NewObjectWithGivenProto(cx, clasp, objProto, nullptr, SingletonObject));
   222     if (!proto)
   223         return nullptr;
   225     // Per ES5 15.3.5.2 a user-defined function's .prototype property is
   226     // initially non-configurable, non-enumerable, and writable.
   227     RootedValue protoVal(cx, ObjectValue(*proto));
   228     if (!JSObject::defineProperty(cx, obj, cx->names().prototype,
   229                                   protoVal, JS_PropertyStub, JS_StrictPropertyStub,
   230                                   JSPROP_PERMANENT))
   231     {
   232         return nullptr;
   233     }
   235     // Per ES5 13.2 the prototype's .constructor property is configurable,
   236     // non-enumerable, and writable.  However, per the 15 July 2013 ES6 draft,
   237     // section 15.19.3, the .prototype of a generator function does not link
   238     // back with a .constructor.
   239     if (!isStarGenerator) {
   240         RootedValue objVal(cx, ObjectValue(*obj));
   241         if (!JSObject::defineProperty(cx, proto, cx->names().constructor,
   242                                       objVal, JS_PropertyStub, JS_StrictPropertyStub, 0))
   243         {
   244             return nullptr;
   245         }
   246     }
   248     return proto;
   249 }
   251 bool
   252 js::FunctionHasResolveHook(const JSAtomState &atomState, PropertyName *name)
   253 {
   254     if (name == atomState.prototype || name == atomState.length || name == atomState.name)
   255         return true;
   257     for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
   258         const uint16_t offset = poisonPillProps[i];
   260         if (name == AtomStateOffsetToName(atomState, offset))
   261             return true;
   262     }
   264     return false;
   265 }
   267 bool
   268 js::fun_resolve(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp)
   269 {
   270     if (!JSID_IS_ATOM(id))
   271         return true;
   273     RootedFunction fun(cx, &obj->as<JSFunction>());
   275     if (JSID_IS_ATOM(id, cx->names().prototype)) {
   276         /*
   277          * Built-in functions do not have a .prototype property per ECMA-262,
   278          * or (Object.prototype, Function.prototype, etc.) have that property
   279          * created eagerly.
   280          *
   281          * ES5 15.3.4: the non-native function object named Function.prototype
   282          * does not have a .prototype property.
   283          *
   284          * ES5 15.3.4.5: bound functions don't have a prototype property. The
   285          * isBuiltin() test covers this case because bound functions are native
   286          * (and thus built-in) functions by definition/construction.
   287          *
   288          * ES6 19.2.4.3: arrow functions also don't have a prototype property.
   289          */
   290         if (fun->isBuiltin() || fun->isArrow() || fun->isFunctionPrototype())
   291             return true;
   293         if (!ResolveInterpretedFunctionPrototype(cx, fun))
   294             return false;
   295         objp.set(fun);
   296         return true;
   297     }
   299     if (JSID_IS_ATOM(id, cx->names().length) || JSID_IS_ATOM(id, cx->names().name)) {
   300         JS_ASSERT(!IsInternalFunctionObject(obj));
   302         RootedValue v(cx);
   303         if (JSID_IS_ATOM(id, cx->names().length)) {
   304             if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
   305                 return false;
   306             uint16_t length = fun->hasScript() ? fun->nonLazyScript()->funLength() :
   307                 fun->nargs() - fun->hasRest();
   308             v.setInt32(length);
   309         } else {
   310             v.setString(fun->atom() == nullptr ? cx->runtime()->emptyString : fun->atom());
   311         }
   313         if (!DefineNativeProperty(cx, fun, id, v, JS_PropertyStub, JS_StrictPropertyStub,
   314                                   JSPROP_PERMANENT | JSPROP_READONLY)) {
   315             return false;
   316         }
   317         objp.set(fun);
   318         return true;
   319     }
   321     for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
   322         const uint16_t offset = poisonPillProps[i];
   324         if (JSID_IS_ATOM(id, AtomStateOffsetToName(cx->names(), offset))) {
   325             JS_ASSERT(!IsInternalFunctionObject(fun));
   327             PropertyOp getter;
   328             StrictPropertyOp setter;
   329             unsigned attrs = JSPROP_PERMANENT | JSPROP_SHARED;
   330             if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
   331                 return false;
   332             if (fun->isInterpreted() ? fun->strict() : fun->isBoundFunction()) {
   333                 JSObject *throwTypeError = fun->global().getThrowTypeError();
   335                 getter = CastAsPropertyOp(throwTypeError);
   336                 setter = CastAsStrictPropertyOp(throwTypeError);
   337                 attrs |= JSPROP_GETTER | JSPROP_SETTER;
   338             } else {
   339                 getter = fun_getProperty;
   340                 setter = JS_StrictPropertyStub;
   341             }
   343             if (!DefineNativeProperty(cx, fun, id, UndefinedHandleValue, getter, setter, attrs))
   344                 return false;
   345             objp.set(fun);
   346             return true;
   347         }
   348     }
   350     return true;
   351 }
   353 template<XDRMode mode>
   354 bool
   355 js::XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
   356                            MutableHandleObject objp)
   357 {
   358     enum FirstWordFlag {
   359         HasAtom             = 0x1,
   360         IsStarGenerator     = 0x2,
   361         IsLazy              = 0x4,
   362         HasSingletonType    = 0x8
   363     };
   365     /* NB: Keep this in sync with CloneFunctionAndScript. */
   366     RootedAtom atom(xdr->cx());
   367     uint32_t firstword = 0;        /* bitmask of FirstWordFlag */
   368     uint32_t flagsword = 0;        /* word for argument count and fun->flags */
   370     JSContext *cx = xdr->cx();
   371     RootedFunction fun(cx);
   372     RootedScript script(cx);
   373     Rooted<LazyScript *> lazy(cx);
   375     if (mode == XDR_ENCODE) {
   376         fun = &objp->as<JSFunction>();
   377         if (!fun->isInterpreted()) {
   378             JSAutoByteString funNameBytes;
   379             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
   380                 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
   381                                      JSMSG_NOT_SCRIPTED_FUNCTION, name);
   382             }
   383             return false;
   384         }
   386         if (fun->atom() || fun->hasGuessedAtom())
   387             firstword |= HasAtom;
   389         if (fun->isStarGenerator())
   390             firstword |= IsStarGenerator;
   392         if (fun->isInterpretedLazy()) {
   393             // This can only happen for re-lazified cloned functions, so this
   394             // does not apply to any JSFunction produced by the parser, only to
   395             // JSFunction created by the runtime.
   396             JS_ASSERT(!fun->lazyScript()->maybeScript());
   398             // Encode a lazy script.
   399             firstword |= IsLazy;
   400             lazy = fun->lazyScript();
   401         } else {
   402             // Encode the script.
   403             script = fun->nonLazyScript();
   404         }
   406         if (fun->hasSingletonType())
   407             firstword |= HasSingletonType;
   409         atom = fun->displayAtom();
   410         flagsword = (fun->nargs() << 16) | fun->flags();
   412         // The environment of any function which is not reused will always be
   413         // null, it is later defined when a function is cloned or reused to
   414         // mirror the scope chain.
   415         JS_ASSERT_IF(fun->hasSingletonType() &&
   416                      !((lazy && lazy->hasBeenCloned()) || (script && script->hasBeenCloned())),
   417                      fun->environment() == nullptr);
   418     }
   420     if (!xdr->codeUint32(&firstword))
   421         return false;
   423     if ((firstword & HasAtom) && !XDRAtom(xdr, &atom))
   424         return false;
   425     if (!xdr->codeUint32(&flagsword))
   426         return false;
   428     if (mode == XDR_DECODE) {
   429         JSObject *proto = nullptr;
   430         if (firstword & IsStarGenerator) {
   431             proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
   432             if (!proto)
   433                 return false;
   434         }
   436         gc::AllocKind allocKind = JSFunction::FinalizeKind;
   437         if (uint16_t(flagsword) & JSFunction::EXTENDED)
   438             allocKind = JSFunction::ExtendedFinalizeKind;
   439         fun = NewFunctionWithProto(cx, NullPtr(), nullptr, 0, JSFunction::INTERPRETED,
   440                                    /* parent = */ NullPtr(), NullPtr(), proto,
   441                                    allocKind, TenuredObject);
   442         if (!fun)
   443             return false;
   444         script = nullptr;
   445     }
   447     if (firstword & IsLazy) {
   448         if (!XDRLazyScript(xdr, enclosingScope, enclosingScript, fun, &lazy))
   449             return false;
   450     } else {
   451         if (!XDRScript(xdr, enclosingScope, enclosingScript, fun, &script))
   452             return false;
   453     }
   455     if (mode == XDR_DECODE) {
   456         fun->setArgCount(flagsword >> 16);
   457         fun->setFlags(uint16_t(flagsword));
   458         fun->initAtom(atom);
   459         if (firstword & IsLazy) {
   460             fun->initLazyScript(lazy);
   461         } else {
   462             fun->initScript(script);
   463             script->setFunction(fun);
   464             JS_ASSERT(fun->nargs() == script->bindings.numArgs());
   465         }
   467         bool singleton = firstword & HasSingletonType;
   468         if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
   469             return false;
   470         objp.set(fun);
   471     }
   473     return true;
   474 }
   476 template bool
   477 js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *, HandleObject, HandleScript, MutableHandleObject);
   479 template bool
   480 js::XDRInterpretedFunction(XDRState<XDR_DECODE> *, HandleObject, HandleScript, MutableHandleObject);
   482 JSObject *
   483 js::CloneFunctionAndScript(JSContext *cx, HandleObject enclosingScope, HandleFunction srcFun)
   484 {
   485     /* NB: Keep this in sync with XDRInterpretedFunction. */
   486     JSObject *cloneProto = nullptr;
   487     if (srcFun->isStarGenerator()) {
   488         cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
   489         if (!cloneProto)
   490             return nullptr;
   491     }
   493     gc::AllocKind allocKind = JSFunction::FinalizeKind;
   494     if (srcFun->isExtended())
   495         allocKind = JSFunction::ExtendedFinalizeKind;
   496     RootedFunction clone(cx, NewFunctionWithProto(cx, NullPtr(), nullptr, 0,
   497                                                   JSFunction::INTERPRETED, NullPtr(), NullPtr(),
   498                                                   cloneProto, allocKind, TenuredObject));
   499     if (!clone)
   500         return nullptr;
   502     RootedScript srcScript(cx, srcFun->getOrCreateScript(cx));
   503     if (!srcScript)
   504         return nullptr;
   505     RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, clone, srcScript));
   506     if (!clonedScript)
   507         return nullptr;
   509     clone->setArgCount(srcFun->nargs());
   510     clone->setFlags(srcFun->flags());
   511     clone->initAtom(srcFun->displayAtom());
   512     clone->initScript(clonedScript);
   513     clonedScript->setFunction(clone);
   514     if (!JSFunction::setTypeForScriptedFunction(cx, clone))
   515         return nullptr;
   517     RootedScript cloneScript(cx, clone->nonLazyScript());
   518     CallNewScriptHook(cx, cloneScript, clone);
   519     return clone;
   520 }
   522 /*
   523  * [[HasInstance]] internal method for Function objects: fetch the .prototype
   524  * property of its 'this' parameter, and walks the prototype chain of v (only
   525  * if v is an object) returning true if .prototype is found.
   526  */
   527 static bool
   528 fun_hasInstance(JSContext *cx, HandleObject objArg, MutableHandleValue v, bool *bp)
   529 {
   530     RootedObject obj(cx, objArg);
   532     while (obj->is<JSFunction>() && obj->isBoundFunction())
   533         obj = obj->as<JSFunction>().getBoundFunctionTarget();
   535     RootedValue pval(cx);
   536     if (!JSObject::getProperty(cx, obj, obj, cx->names().prototype, &pval))
   537         return false;
   539     if (pval.isPrimitive()) {
   540         /*
   541          * Throw a runtime error if instanceof is called on a function that
   542          * has a non-object as its .prototype value.
   543          */
   544         RootedValue val(cx, ObjectValue(*obj));
   545         js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, js::NullPtr());
   546         return false;
   547     }
   549     RootedObject pobj(cx, &pval.toObject());
   550     bool isDelegate;
   551     if (!IsDelegate(cx, pobj, v, &isDelegate))
   552         return false;
   553     *bp = isDelegate;
   554     return true;
   555 }
   557 inline void
   558 JSFunction::trace(JSTracer *trc)
   559 {
   560     if (isExtended()) {
   561         MarkValueRange(trc, ArrayLength(toExtended()->extendedSlots),
   562                        toExtended()->extendedSlots, "nativeReserved");
   563     }
   565     if (atom_)
   566         MarkString(trc, &atom_, "atom");
   568     if (isInterpreted()) {
   569         // Functions can be be marked as interpreted despite having no script
   570         // yet at some points when parsing, and can be lazy with no lazy script
   571         // for self-hosted code.
   572         if (hasScript() && u.i.s.script_) {
   573             // Functions can be relazified under the following conditions:
   574             // - their compartment isn't currently executing scripts or being
   575             //   debugged
   576             // - they are not in the self-hosting compartment
   577             // - they aren't generators
   578             // - they don't have JIT code attached
   579             // - they haven't ever been inlined
   580             // - they don't have child functions
   581             // - they have information for un-lazifying them again later
   582             // This information can either be a LazyScript, or the name of a
   583             // self-hosted function which can be cloned over again. The latter
   584             // is stored in the first extended slot.
   585             if (IS_GC_MARKING_TRACER(trc) && !compartment()->hasBeenEntered() &&
   586                 !compartment()->debugMode() && !compartment()->isSelfHosting &&
   587                 u.i.s.script_->isRelazifiable() && (!isSelfHostedBuiltin() || isExtended()))
   588             {
   589                 relazify(trc);
   590             } else {
   591                 MarkScriptUnbarriered(trc, &u.i.s.script_, "script");
   592             }
   593         } else if (isInterpretedLazy() && u.i.s.lazy_) {
   594             MarkLazyScriptUnbarriered(trc, &u.i.s.lazy_, "lazyScript");
   595         }
   596         if (u.i.env_)
   597             MarkObjectUnbarriered(trc, &u.i.env_, "fun_callscope");
   598     }
   599 }
   601 static void
   602 fun_trace(JSTracer *trc, JSObject *obj)
   603 {
   604     obj->as<JSFunction>().trace(trc);
   605 }
   607 const Class JSFunction::class_ = {
   608     js_Function_str,
   609     JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS |
   610     JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
   611     JS_PropertyStub,         /* addProperty */
   612     JS_DeletePropertyStub,   /* delProperty */
   613     JS_PropertyStub,         /* getProperty */
   614     JS_StrictPropertyStub,   /* setProperty */
   615     fun_enumerate,
   616     (JSResolveOp)js::fun_resolve,
   617     JS_ConvertStub,
   618     nullptr,                 /* finalize    */
   619     nullptr,                 /* call        */
   620     fun_hasInstance,
   621     nullptr,                 /* construct   */
   622     fun_trace
   623 };
   625 const Class* const js::FunctionClassPtr = &JSFunction::class_;
   627 /* Find the body of a function (not including braces). */
   628 bool
   629 js::FindBody(JSContext *cx, HandleFunction fun, ConstTwoByteChars chars, size_t length,
   630          size_t *bodyStart, size_t *bodyEnd)
   631 {
   632     // We don't need principals, since those are only used for error reporting.
   633     CompileOptions options(cx);
   634     options.setFileAndLine("internal-findBody", 0);
   636     // For asm.js modules, there's no script.
   637     if (fun->hasScript())
   638         options.setVersion(fun->nonLazyScript()->getVersion());
   640     AutoKeepAtoms keepAtoms(cx->perThreadData);
   641     TokenStream ts(cx, options, chars.get(), length, nullptr);
   642     int nest = 0;
   643     bool onward = true;
   644     // Skip arguments list.
   645     do {
   646         switch (ts.getToken()) {
   647           case TOK_NAME:
   648           case TOK_YIELD:
   649             if (nest == 0)
   650                 onward = false;
   651             break;
   652           case TOK_LP:
   653             nest++;
   654             break;
   655           case TOK_RP:
   656             if (--nest == 0)
   657                 onward = false;
   658             break;
   659           case TOK_ERROR:
   660             // Must be memory.
   661             return false;
   662           default:
   663             break;
   664         }
   665     } while (onward);
   666     TokenKind tt = ts.getToken();
   667     if (tt == TOK_ARROW)
   668         tt = ts.getToken();
   669     if (tt == TOK_ERROR)
   670         return false;
   671     bool braced = tt == TOK_LC;
   672     JS_ASSERT_IF(fun->isExprClosure(), !braced);
   673     *bodyStart = ts.currentToken().pos.begin;
   674     if (braced)
   675         *bodyStart += 1;
   676     ConstTwoByteChars end(chars.get() + length, chars.get(), length);
   677     if (end[-1] == '}') {
   678         end--;
   679     } else {
   680         JS_ASSERT(!braced);
   681         for (; unicode::IsSpaceOrBOM2(end[-1]); end--)
   682             ;
   683     }
   684     *bodyEnd = end - chars;
   685     JS_ASSERT(*bodyStart <= *bodyEnd);
   686     return true;
   687 }
   689 JSString *
   690 js::FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen)
   691 {
   692     if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
   693         return nullptr;
   695     if (IsAsmJSModule(fun))
   696         return AsmJSModuleToString(cx, fun, !lambdaParen);
   697     if (IsAsmJSFunction(fun))
   698         return AsmJSFunctionToString(cx, fun);
   700     StringBuffer out(cx);
   701     RootedScript script(cx);
   703     if (fun->hasScript()) {
   704         script = fun->nonLazyScript();
   705         if (script->isGeneratorExp()) {
   706             if ((!bodyOnly && !out.append("function genexp() {")) ||
   707                 !out.append("\n    [generator expression]\n") ||
   708                 (!bodyOnly && !out.append("}")))
   709             {
   710                 return nullptr;
   711             }
   712             return out.finishString();
   713         }
   714     }
   715     if (!bodyOnly) {
   716         // If we're not in pretty mode, put parentheses around lambda functions.
   717         if (fun->isInterpreted() && !lambdaParen && fun->isLambda() && !fun->isArrow()) {
   718             if (!out.append("("))
   719                 return nullptr;
   720         }
   721         if (!fun->isArrow()) {
   722             if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function ")))
   723                 return nullptr;
   724         }
   725         if (fun->atom()) {
   726             if (!out.append(fun->atom()))
   727                 return nullptr;
   728         }
   729     }
   730     bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
   731     if (haveSource && !script->scriptSource()->hasSourceData() &&
   732         !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
   733     {
   734         return nullptr;
   735     }
   736     if (haveSource) {
   737         RootedString srcStr(cx, script->sourceData(cx));
   738         if (!srcStr)
   739             return nullptr;
   740         Rooted<JSFlatString *> src(cx, srcStr->ensureFlat(cx));
   741         if (!src)
   742             return nullptr;
   744         ConstTwoByteChars chars(src->chars(), src->length());
   745         bool exprBody = fun->isExprClosure();
   747         // The source data for functions created by calling the Function
   748         // constructor is only the function's body.  This depends on the fact,
   749         // asserted below, that in Function("function f() {}"), the inner
   750         // function's sourceStart points to the '(', not the 'f'.
   751         bool funCon = !fun->isArrow() &&
   752                       script->sourceStart() == 0 &&
   753                       script->sourceEnd() == script->scriptSource()->length() &&
   754                       script->scriptSource()->argumentsNotIncluded();
   756         // Functions created with the constructor can't be arrow functions or
   757         // expression closures.
   758         JS_ASSERT_IF(funCon, !fun->isArrow());
   759         JS_ASSERT_IF(funCon, !exprBody);
   760         JS_ASSERT_IF(!funCon && !fun->isArrow(), src->length() > 0 && chars[0] == '(');
   762         // If a function inherits strict mode by having scopes above it that
   763         // have "use strict", we insert "use strict" into the body of the
   764         // function. This ensures that if the result of toString is evaled, the
   765         // resulting function will have the same semantics.
   766         bool addUseStrict = script->strict() && !script->explicitUseStrict() && !fun->isArrow();
   768         bool buildBody = funCon && !bodyOnly;
   769         if (buildBody) {
   770             // This function was created with the Function constructor. We don't
   771             // have source for the arguments, so we have to generate that. Part
   772             // of bug 755821 should be cobbling the arguments passed into the
   773             // Function constructor into the source string.
   774             if (!out.append("("))
   775                 return nullptr;
   777             // Fish out the argument names.
   778             BindingVector *localNames = cx->new_<BindingVector>(cx);
   779             ScopedJSDeletePtr<BindingVector> freeNames(localNames);
   780             if (!FillBindingVector(script, localNames))
   781                 return nullptr;
   782             for (unsigned i = 0; i < fun->nargs(); i++) {
   783                 if ((i && !out.append(", ")) ||
   784                     (i == unsigned(fun->nargs() - 1) && fun->hasRest() && !out.append("...")) ||
   785                     !out.append((*localNames)[i].name())) {
   786                     return nullptr;
   787                 }
   788             }
   789             if (!out.append(") {\n"))
   790                 return nullptr;
   791         }
   792         if ((bodyOnly && !funCon) || addUseStrict) {
   793             // We need to get at the body either because we're only supposed to
   794             // return the body or we need to insert "use strict" into the body.
   795             size_t bodyStart = 0, bodyEnd;
   797             // If the function is defined in the Function constructor, we
   798             // already have a body.
   799             if (!funCon) {
   800                 JS_ASSERT(!buildBody);
   801                 if (!FindBody(cx, fun, chars, src->length(), &bodyStart, &bodyEnd))
   802                     return nullptr;
   803             } else {
   804                 bodyEnd = src->length();
   805             }
   807             if (addUseStrict) {
   808                 // Output source up to beginning of body.
   809                 if (!out.append(chars, bodyStart))
   810                     return nullptr;
   811                 if (exprBody) {
   812                     // We can't insert a statement into a function with an
   813                     // expression body. Do what the decompiler did, and insert a
   814                     // comment.
   815                     if (!out.append("/* use strict */ "))
   816                         return nullptr;
   817                 } else {
   818                     if (!out.append("\n\"use strict\";\n"))
   819                         return nullptr;
   820                 }
   821             }
   823             // Output just the body (for bodyOnly) or the body and possibly
   824             // closing braces (for addUseStrict).
   825             size_t dependentEnd = bodyOnly ? bodyEnd : src->length();
   826             if (!out.append(chars + bodyStart, dependentEnd - bodyStart))
   827                 return nullptr;
   828         } else {
   829             if (!out.append(src))
   830                 return nullptr;
   831         }
   832         if (buildBody) {
   833             if (!out.append("\n}"))
   834                 return nullptr;
   835         }
   836         if (bodyOnly) {
   837             // Slap a semicolon on the end of functions with an expression body.
   838             if (exprBody && !out.append(";"))
   839                 return nullptr;
   840         } else if (!lambdaParen && fun->isLambda() && !fun->isArrow()) {
   841             if (!out.append(")"))
   842                 return nullptr;
   843         }
   844     } else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) {
   845         if ((!bodyOnly && !out.append("() {\n    ")) ||
   846             !out.append("[sourceless code]") ||
   847             (!bodyOnly && !out.append("\n}")))
   848             return nullptr;
   849         if (!lambdaParen && fun->isLambda() && !fun->isArrow() && !out.append(")"))
   850             return nullptr;
   851     } else {
   852         JS_ASSERT(!fun->isExprClosure());
   854         if ((!bodyOnly && !out.append("() {\n    "))
   855             || !out.append("[native code]")
   856             || (!bodyOnly && !out.append("\n}")))
   857         {
   858             return nullptr;
   859         }
   860     }
   861     return out.finishString();
   862 }
   864 JSString *
   865 fun_toStringHelper(JSContext *cx, HandleObject obj, unsigned indent)
   866 {
   867     if (!obj->is<JSFunction>()) {
   868         if (obj->is<ProxyObject>())
   869             return Proxy::fun_toString(cx, obj, indent);
   870         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
   871                              JSMSG_INCOMPATIBLE_PROTO,
   872                              js_Function_str, js_toString_str,
   873                              "object");
   874         return nullptr;
   875     }
   877     RootedFunction fun(cx, &obj->as<JSFunction>());
   878     return FunctionToString(cx, fun, false, indent != JS_DONT_PRETTY_PRINT);
   879 }
   881 static bool
   882 fun_toString(JSContext *cx, unsigned argc, Value *vp)
   883 {
   884     CallArgs args = CallArgsFromVp(argc, vp);
   885     JS_ASSERT(IsFunctionObject(args.calleev()));
   887     uint32_t indent = 0;
   889     if (args.length() != 0 && !ToUint32(cx, args[0], &indent))
   890         return false;
   892     RootedObject obj(cx, ToObject(cx, args.thisv()));
   893     if (!obj)
   894         return false;
   896     RootedString str(cx, fun_toStringHelper(cx, obj, indent));
   897     if (!str)
   898         return false;
   900     args.rval().setString(str);
   901     return true;
   902 }
   904 #if JS_HAS_TOSOURCE
   905 static bool
   906 fun_toSource(JSContext *cx, unsigned argc, Value *vp)
   907 {
   908     CallArgs args = CallArgsFromVp(argc, vp);
   909     JS_ASSERT(IsFunctionObject(args.calleev()));
   911     RootedObject obj(cx, ToObject(cx, args.thisv()));
   912     if (!obj)
   913         return false;
   915     RootedString str(cx);
   916     if (obj->isCallable())
   917         str = fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT);
   918     else
   919         str = ObjectToSource(cx, obj);
   921     if (!str)
   922         return false;
   923     args.rval().setString(str);
   924     return true;
   925 }
   926 #endif
   928 bool
   929 js_fun_call(JSContext *cx, unsigned argc, Value *vp)
   930 {
   931     CallArgs args = CallArgsFromVp(argc, vp);
   933     HandleValue fval = args.thisv();
   934     if (!js_IsCallable(fval)) {
   935         ReportIncompatibleMethod(cx, args, &JSFunction::class_);
   936         return false;
   937     }
   939     args.setCallee(fval);
   940     args.setThis(args.get(0));
   942     if (args.length() > 0) {
   943         for (size_t i = 0; i < args.length() - 1; i++)
   944             args[i].set(args[i + 1]);
   945         args = CallArgsFromVp(args.length() - 1, vp);
   946     }
   948     return Invoke(cx, args);
   949 }
   951 // ES5 15.3.4.3
   952 bool
   953 js_fun_apply(JSContext *cx, unsigned argc, Value *vp)
   954 {
   955     CallArgs args = CallArgsFromVp(argc, vp);
   957     // Step 1.
   958     HandleValue fval = args.thisv();
   959     if (!js_IsCallable(fval)) {
   960         ReportIncompatibleMethod(cx, args, &JSFunction::class_);
   961         return false;
   962     }
   964     // Step 2.
   965     if (args.length() < 2 || args[1].isNullOrUndefined())
   966         return js_fun_call(cx, (args.length() > 0) ? 1 : 0, vp);
   968     InvokeArgs args2(cx);
   970     // A JS_OPTIMIZED_ARGUMENTS magic value means that 'arguments' flows into
   971     // this apply call from a scripted caller and, as an optimization, we've
   972     // avoided creating it since apply can simply pull the argument values from
   973     // the calling frame (which we must do now).
   974     if (args[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
   975         // Step 3-6.
   976         ScriptFrameIter iter(cx);
   977         JS_ASSERT(iter.numActualArgs() <= ARGS_LENGTH_MAX);
   978         if (!args2.init(iter.numActualArgs()))
   979             return false;
   981         args2.setCallee(fval);
   982         args2.setThis(args[0]);
   984         // Steps 7-8.
   985         iter.unaliasedForEachActual(cx, CopyTo(args2.array()));
   986     } else {
   987         // Step 3.
   988         if (!args[1].isObject()) {
   989             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
   990                                  JSMSG_BAD_APPLY_ARGS, js_apply_str);
   991             return false;
   992         }
   994         // Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
   995         // original version of ES5).
   996         RootedObject aobj(cx, &args[1].toObject());
   997         uint32_t length;
   998         if (!GetLengthProperty(cx, aobj, &length))
   999             return false;
  1001         // Step 6.
  1002         if (length > ARGS_LENGTH_MAX) {
  1003             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
  1004             return false;
  1007         if (!args2.init(length))
  1008             return false;
  1010         // Push fval, obj, and aobj's elements as args.
  1011         args2.setCallee(fval);
  1012         args2.setThis(args[0]);
  1014         // Steps 7-8.
  1015         if (!GetElements(cx, aobj, length, args2.array()))
  1016             return false;
  1019     // Step 9.
  1020     if (!Invoke(cx, args2))
  1021         return false;
  1023     args.rval().set(args2.rval());
  1024     return true;
  1027 static const uint32_t JSSLOT_BOUND_FUNCTION_THIS       = 0;
  1028 static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1;
  1030 static const uint32_t BOUND_FUNCTION_RESERVED_SLOTS = 2;
  1032 inline bool
  1033 JSFunction::initBoundFunction(JSContext *cx, HandleValue thisArg,
  1034                               const Value *args, unsigned argslen)
  1036     RootedFunction self(cx, this);
  1038     /*
  1039      * Convert to a dictionary to set the BOUND_FUNCTION flag and increase
  1040      * the slot span to cover the arguments and additional slots for the 'this'
  1041      * value and arguments count.
  1042      */
  1043     if (!self->toDictionaryMode(cx))
  1044         return false;
  1046     if (!self->setFlag(cx, BaseShape::BOUND_FUNCTION))
  1047         return false;
  1049     if (!JSObject::setSlotSpan(cx, self, BOUND_FUNCTION_RESERVED_SLOTS + argslen))
  1050         return false;
  1052     self->setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
  1053     self->setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
  1055     self->initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen);
  1057     return true;
  1060 const js::Value &
  1061 JSFunction::getBoundFunctionThis() const
  1063     JS_ASSERT(isBoundFunction());
  1065     return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
  1068 const js::Value &
  1069 JSFunction::getBoundFunctionArgument(unsigned which) const
  1071     JS_ASSERT(isBoundFunction());
  1072     JS_ASSERT(which < getBoundFunctionArgumentCount());
  1074     return getSlot(BOUND_FUNCTION_RESERVED_SLOTS + which);
  1077 size_t
  1078 JSFunction::getBoundFunctionArgumentCount() const
  1080     JS_ASSERT(isBoundFunction());
  1082     return getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
  1085 /* static */ bool
  1086 JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFunction fun)
  1088     JS_ASSERT(fun->isInterpretedLazy());
  1090     Rooted<LazyScript*> lazy(cx, fun->lazyScriptOrNull());
  1091     if (lazy) {
  1092         // Trigger a pre barrier on the lazy script being overwritten.
  1093         if (cx->zone()->needsBarrier())
  1094             LazyScript::writeBarrierPre(lazy);
  1096         // Suppress GC for now although we should be able to remove this by
  1097         // making 'lazy' a Rooted<LazyScript*> (which requires adding a
  1098         // THING_ROOT_LAZY_SCRIPT).
  1099         AutoSuppressGC suppressGC(cx);
  1101         RootedScript script(cx, lazy->maybeScript());
  1103         if (script) {
  1104             fun->setUnlazifiedScript(script);
  1105             // Remember the lazy script on the compiled script, so it can be
  1106             // stored on the function again in case of re-lazification.
  1107             // Only functions without inner functions are re-lazified.
  1108             if (!lazy->numInnerFunctions())
  1109                 script->setLazyScript(lazy);
  1110             return true;
  1113         if (fun != lazy->functionNonDelazifying()) {
  1114             if (!lazy->functionDelazifying(cx))
  1115                 return false;
  1116             script = lazy->functionNonDelazifying()->nonLazyScript();
  1117             if (!script)
  1118                 return false;
  1120             fun->setUnlazifiedScript(script);
  1121             return true;
  1124         // Lazy script caching is only supported for leaf functions. If a
  1125         // script with inner functions was returned by the cache, those inner
  1126         // functions would be delazified when deep cloning the script, even if
  1127         // they have never executed.
  1128         //
  1129         // Additionally, the lazy script cache is not used during incremental
  1130         // GCs, to avoid resurrecting dead scripts after incremental sweeping
  1131         // has started.
  1132         if (!lazy->numInnerFunctions() && !JS::IsIncrementalGCInProgress(cx->runtime())) {
  1133             LazyScriptCache::Lookup lookup(cx, lazy);
  1134             cx->runtime()->lazyScriptCache.lookup(lookup, script.address());
  1137         if (script) {
  1138             RootedObject enclosingScope(cx, lazy->enclosingScope());
  1139             RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script));
  1140             if (!clonedScript)
  1141                 return false;
  1143             clonedScript->setSourceObject(lazy->sourceObject());
  1145             fun->initAtom(script->functionNonDelazifying()->displayAtom());
  1146             clonedScript->setFunction(fun);
  1148             fun->setUnlazifiedScript(clonedScript);
  1150             CallNewScriptHook(cx, clonedScript, fun);
  1152             if (!lazy->maybeScript())
  1153                 lazy->initScript(clonedScript);
  1154             return true;
  1157         JS_ASSERT(lazy->source()->hasSourceData());
  1159         // Parse and compile the script from source.
  1160         SourceDataCache::AutoHoldEntry holder;
  1161         const jschar *chars = lazy->source()->chars(cx, holder);
  1162         if (!chars)
  1163             return false;
  1165         const jschar *lazyStart = chars + lazy->begin();
  1166         size_t lazyLength = lazy->end() - lazy->begin();
  1168         if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength))
  1169             return false;
  1171         script = fun->nonLazyScript();
  1173         // Remember the compiled script on the lazy script itself, in case
  1174         // there are clones of the function still pointing to the lazy script.
  1175         if (!lazy->maybeScript())
  1176             lazy->initScript(script);
  1178         // Try to insert the newly compiled script into the lazy script cache.
  1179         if (!lazy->numInnerFunctions()) {
  1180             // A script's starting column isn't set by the bytecode emitter, so
  1181             // specify this from the lazy script so that if an identical lazy
  1182             // script is encountered later a match can be determined.
  1183             script->setColumn(lazy->column());
  1185             LazyScriptCache::Lookup lookup(cx, lazy);
  1186             cx->runtime()->lazyScriptCache.insert(lookup, script);
  1188             // Remember the lazy script on the compiled script, so it can be
  1189             // stored on the function again in case of re-lazification.
  1190             // Only functions without inner functions are re-lazified.
  1191             script->setLazyScript(lazy);
  1193         return true;
  1196     /* Lazily cloned self-hosted script. */
  1197     JS_ASSERT(fun->isSelfHostedBuiltin());
  1198     RootedAtom funAtom(cx, &fun->getExtendedSlot(0).toString()->asAtom());
  1199     if (!funAtom)
  1200         return false;
  1201     Rooted<PropertyName *> funName(cx, funAtom->asPropertyName());
  1202     return cx->runtime()->cloneSelfHostedFunctionScript(cx, funName, fun);
  1205 void
  1206 JSFunction::relazify(JSTracer *trc)
  1208     JSScript *script = nonLazyScript();
  1209     JS_ASSERT(script->isRelazifiable());
  1210     JS_ASSERT(!compartment()->hasBeenEntered());
  1211     JS_ASSERT(!compartment()->debugMode());
  1213     // If the script's canonical function isn't lazy, we have to mark the
  1214     // script. Otherwise, the following scenario would leave it unmarked
  1215     // and cause it to be swept while a function is still expecting it to be
  1216     // valid:
  1217     // 1. an incremental GC slice causes the canonical function to relazify
  1218     // 2. a clone is used and delazifies the canonical function
  1219     // 3. another GC slice causes the clone to relazify
  1220     // The result is that no function marks the script, but the canonical
  1221     // function expects it to be valid.
  1222     if (script->functionNonDelazifying()->hasScript())
  1223         MarkScriptUnbarriered(trc, &u.i.s.script_, "script");
  1225     flags_ &= ~INTERPRETED;
  1226     flags_ |= INTERPRETED_LAZY;
  1227     LazyScript *lazy = script->maybeLazyScript();
  1228     u.i.s.lazy_ = lazy;
  1229     if (lazy) {
  1230         JS_ASSERT(!isSelfHostedBuiltin());
  1231         // If this is the script stored in the lazy script to be cloned
  1232         // for un-lazifying other functions, reset it so the script can
  1233         // be freed.
  1234         if (lazy->maybeScript() == script)
  1235             lazy->resetScript();
  1236         MarkLazyScriptUnbarriered(trc, &u.i.s.lazy_, "lazyScript");
  1237     } else {
  1238         JS_ASSERT(isSelfHostedBuiltin());
  1239         JS_ASSERT(isExtended());
  1240         JS_ASSERT(getExtendedSlot(0).toString()->isAtom());
  1244 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
  1245 bool
  1246 js::CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp)
  1248     CallArgs args = CallArgsFromVp(argc, vp);
  1249     RootedFunction fun(cx, &args.callee().as<JSFunction>());
  1250     JS_ASSERT(fun->isBoundFunction());
  1252     /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
  1253     unsigned argslen = fun->getBoundFunctionArgumentCount();
  1255     if (args.length() + argslen > ARGS_LENGTH_MAX) {
  1256         js_ReportAllocationOverflow(cx);
  1257         return false;
  1260     /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
  1261     RootedObject target(cx, fun->getBoundFunctionTarget());
  1263     /* 15.3.4.5.1 step 2. */
  1264     const Value &boundThis = fun->getBoundFunctionThis();
  1266     InvokeArgs invokeArgs(cx);
  1267     if (!invokeArgs.init(args.length() + argslen))
  1268         return false;
  1270     /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
  1271     for (unsigned i = 0; i < argslen; i++)
  1272         invokeArgs[i].set(fun->getBoundFunctionArgument(i));
  1273     PodCopy(invokeArgs.array() + argslen, vp + 2, args.length());
  1275     /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
  1276     invokeArgs.setCallee(ObjectValue(*target));
  1278     bool constructing = args.isConstructing();
  1279     if (!constructing)
  1280         invokeArgs.setThis(boundThis);
  1282     if (constructing ? !InvokeConstructor(cx, invokeArgs) : !Invoke(cx, invokeArgs))
  1283         return false;
  1285     args.rval().set(invokeArgs.rval());
  1286     return true;
  1289 static bool
  1290 fun_isGenerator(JSContext *cx, unsigned argc, Value *vp)
  1292     CallArgs args = CallArgsFromVp(argc, vp);
  1293     JSFunction *fun;
  1294     if (!IsFunctionObject(args.thisv(), &fun)) {
  1295         args.rval().setBoolean(false);
  1296         return true;
  1299     args.rval().setBoolean(fun->isGenerator());
  1300     return true;
  1303 /* ES5 15.3.4.5. */
  1304 static bool
  1305 fun_bind(JSContext *cx, unsigned argc, Value *vp)
  1307     CallArgs args = CallArgsFromVp(argc, vp);
  1309     /* Step 1. */
  1310     Value thisv = args.thisv();
  1312     /* Step 2. */
  1313     if (!js_IsCallable(thisv)) {
  1314         ReportIncompatibleMethod(cx, args, &JSFunction::class_);
  1315         return false;
  1318     /* Step 3. */
  1319     Value *boundArgs = nullptr;
  1320     unsigned argslen = 0;
  1321     if (args.length() > 1) {
  1322         boundArgs = args.array() + 1;
  1323         argslen = args.length() - 1;
  1326     /* Steps 7-9. */
  1327     RootedValue thisArg(cx, args.length() >= 1 ? args[0] : UndefinedValue());
  1328     RootedObject target(cx, &thisv.toObject());
  1329     JSObject *boundFunction = js_fun_bind(cx, target, thisArg, boundArgs, argslen);
  1330     if (!boundFunction)
  1331         return false;
  1333     /* Step 22. */
  1334     args.rval().setObject(*boundFunction);
  1335     return true;
  1338 JSObject*
  1339 js_fun_bind(JSContext *cx, HandleObject target, HandleValue thisArg,
  1340             Value *boundArgs, unsigned argslen)
  1342     /* Steps 15-16. */
  1343     unsigned length = 0;
  1344     if (target->is<JSFunction>()) {
  1345         unsigned nargs = target->as<JSFunction>().nargs();
  1346         if (nargs > argslen)
  1347             length = nargs - argslen;
  1350     /* Step 4-6, 10-11. */
  1351     RootedAtom name(cx, target->is<JSFunction>() ? target->as<JSFunction>().atom() : nullptr);
  1353     RootedObject funobj(cx, NewFunction(cx, js::NullPtr(), CallOrConstructBoundFunction, length,
  1354                                         JSFunction::NATIVE_CTOR, target, name));
  1355     if (!funobj)
  1356         return nullptr;
  1358     /* NB: Bound functions abuse |parent| to store their target. */
  1359     if (!JSObject::setParent(cx, funobj, target))
  1360         return nullptr;
  1362     if (!funobj->as<JSFunction>().initBoundFunction(cx, thisArg, boundArgs, argslen))
  1363         return nullptr;
  1365     /* Steps 17, 19-21 are handled by fun_resolve. */
  1366     /* Step 18 is the default for new functions. */
  1367     return funobj;
  1370 /*
  1371  * Report "malformed formal parameter" iff no illegal char or similar scanner
  1372  * error was already reported.
  1373  */
  1374 static bool
  1375 OnBadFormal(JSContext *cx, TokenKind tt)
  1377     if (tt != TOK_ERROR)
  1378         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_FORMAL);
  1379     else
  1380         JS_ASSERT(cx->isExceptionPending());
  1381     return false;
  1384 const JSFunctionSpec js::function_methods[] = {
  1385 #if JS_HAS_TOSOURCE
  1386     JS_FN(js_toSource_str,   fun_toSource,   0,0),
  1387 #endif
  1388     JS_FN(js_toString_str,   fun_toString,   0,0),
  1389     JS_FN(js_apply_str,      js_fun_apply,   2,0),
  1390     JS_FN(js_call_str,       js_fun_call,    1,0),
  1391     JS_FN("bind",            fun_bind,       1,0),
  1392     JS_FN("isGenerator",     fun_isGenerator,0,0),
  1393     JS_FS_END
  1394 };
  1396 static bool
  1397 FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind generatorKind)
  1399     CallArgs args = CallArgsFromVp(argc, vp);
  1400     RootedString arg(cx);   // used multiple times below
  1402     /* Block this call if security callbacks forbid it. */
  1403     Rooted<GlobalObject*> global(cx, &args.callee().global());
  1404     if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
  1405         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
  1406         return false;
  1409     AutoKeepAtoms keepAtoms(cx->perThreadData);
  1410     AutoNameVector formals(cx);
  1412     bool hasRest = false;
  1414     bool isStarGenerator = generatorKind == StarGenerator;
  1415     JS_ASSERT(generatorKind != LegacyGenerator);
  1417     RootedScript maybeScript(cx);
  1418     const char *filename;
  1419     unsigned lineno;
  1420     JSPrincipals *originPrincipals;
  1421     uint32_t pcOffset;
  1422     DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset,
  1423                                          &originPrincipals);
  1425     const char *introductionType = "Function";
  1426     if (generatorKind != NotGenerator)
  1427         introductionType = "GeneratorFunction";
  1429     const char *introducerFilename = filename;
  1430     if (maybeScript && maybeScript->scriptSource()->introducerFilename())
  1431         introducerFilename = maybeScript->scriptSource()->introducerFilename();
  1433     CompileOptions options(cx);
  1434     options.setOriginPrincipals(originPrincipals)
  1435            .setFileAndLine(filename, 1)
  1436            .setNoScriptRval(false)
  1437            .setCompileAndGo(true)
  1438            .setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset);
  1440     unsigned n = args.length() ? args.length() - 1 : 0;
  1441     if (n > 0) {
  1442         /*
  1443          * Collect the function-argument arguments into one string, separated
  1444          * by commas, then make a tokenstream from that string, and scan it to
  1445          * get the arguments.  We need to throw the full scanner at the
  1446          * problem, because the argument string can legitimately contain
  1447          * comments and linefeeds.  XXX It might be better to concatenate
  1448          * everything up into a function definition and pass it to the
  1449          * compiler, but doing it this way is less of a delta from the old
  1450          * code.  See ECMA 15.3.2.1.
  1451          */
  1452         size_t args_length = 0;
  1453         for (unsigned i = 0; i < n; i++) {
  1454             /* Collect the lengths for all the function-argument arguments. */
  1455             arg = ToString<CanGC>(cx, args[i]);
  1456             if (!arg)
  1457                 return false;
  1458             args[i].setString(arg);
  1460             /*
  1461              * Check for overflow.  The < test works because the maximum
  1462              * JSString length fits in 2 fewer bits than size_t has.
  1463              */
  1464             size_t old_args_length = args_length;
  1465             args_length = old_args_length + arg->length();
  1466             if (args_length < old_args_length) {
  1467                 js_ReportAllocationOverflow(cx);
  1468                 return false;
  1472         /* Add 1 for each joining comma and check for overflow (two ways). */
  1473         size_t old_args_length = args_length;
  1474         args_length = old_args_length + n - 1;
  1475         if (args_length < old_args_length ||
  1476             args_length >= ~(size_t)0 / sizeof(jschar)) {
  1477             js_ReportAllocationOverflow(cx);
  1478             return false;
  1481         /*
  1482          * Allocate a string to hold the concatenated arguments, including room
  1483          * for a terminating 0. Mark cx->tempLifeAlloc for later release, to
  1484          * free collected_args and its tokenstream in one swoop.
  1485          */
  1486         LifoAllocScope las(&cx->tempLifoAlloc());
  1487         jschar *cp = cx->tempLifoAlloc().newArray<jschar>(args_length + 1);
  1488         if (!cp) {
  1489             js_ReportOutOfMemory(cx);
  1490             return false;
  1492         ConstTwoByteChars collected_args(cp, args_length + 1);
  1494         /*
  1495          * Concatenate the arguments into the new string, separated by commas.
  1496          */
  1497         for (unsigned i = 0; i < n; i++) {
  1498             arg = args[i].toString();
  1499             size_t arg_length = arg->length();
  1500             const jschar *arg_chars = arg->getChars(cx);
  1501             if (!arg_chars)
  1502                 return false;
  1503             (void) js_strncpy(cp, arg_chars, arg_length);
  1504             cp += arg_length;
  1506             /* Add separating comma or terminating 0. */
  1507             *cp++ = (i + 1 < n) ? ',' : 0;
  1510         /*
  1511          * Initialize a tokenstream that reads from the given string.  No
  1512          * StrictModeGetter is needed because this TokenStream won't report any
  1513          * strict mode errors.  Any strict mode errors which might be reported
  1514          * here (duplicate argument names, etc.) will be detected when we
  1515          * compile the function body.
  1516          */
  1517         TokenStream ts(cx, options, collected_args.get(), args_length,
  1518                        /* strictModeGetter = */ nullptr);
  1519         bool yieldIsValidName = ts.versionNumber() < JSVERSION_1_7 && !isStarGenerator;
  1521         /* The argument string may be empty or contain no tokens. */
  1522         TokenKind tt = ts.getToken();
  1523         if (tt != TOK_EOF) {
  1524             for (;;) {
  1525                 /*
  1526                  * Check that it's a name.  This also implicitly guards against
  1527                  * TOK_ERROR, which was already reported.
  1528                  */
  1529                 if (hasRest) {
  1530                     ts.reportError(JSMSG_PARAMETER_AFTER_REST);
  1531                     return false;
  1534                 if (tt == TOK_YIELD && yieldIsValidName)
  1535                     tt = TOK_NAME;
  1537                 if (tt != TOK_NAME) {
  1538                     if (tt == TOK_TRIPLEDOT) {
  1539                         hasRest = true;
  1540                         tt = ts.getToken();
  1541                         if (tt == TOK_YIELD && yieldIsValidName)
  1542                             tt = TOK_NAME;
  1543                         if (tt != TOK_NAME) {
  1544                             if (tt != TOK_ERROR)
  1545                                 ts.reportError(JSMSG_NO_REST_NAME);
  1546                             return false;
  1548                     } else {
  1549                         return OnBadFormal(cx, tt);
  1553                 if (!formals.append(ts.currentName()))
  1554                     return false;
  1556                 /*
  1557                  * Get the next token.  Stop on end of stream.  Otherwise
  1558                  * insist on a comma, get another name, and iterate.
  1559                  */
  1560                 tt = ts.getToken();
  1561                 if (tt == TOK_EOF)
  1562                     break;
  1563                 if (tt != TOK_COMMA)
  1564                     return OnBadFormal(cx, tt);
  1565                 tt = ts.getToken();
  1570 #ifdef DEBUG
  1571     for (unsigned i = 0; i < formals.length(); ++i) {
  1572         JSString *str = formals[i];
  1573         JS_ASSERT(str->asAtom().asPropertyName() == formals[i]);
  1575 #endif
  1577     RootedString str(cx);
  1578     if (!args.length())
  1579         str = cx->runtime()->emptyString;
  1580     else
  1581         str = ToString<CanGC>(cx, args[args.length() - 1]);
  1582     if (!str)
  1583         return false;
  1584     JSLinearString *linear = str->ensureLinear(cx);
  1585     if (!linear)
  1586         return false;
  1588     JS::Anchor<JSString *> strAnchor(str);
  1589     const jschar *chars = linear->chars();
  1590     size_t length = linear->length();
  1592     /*
  1593      * NB: (new Function) is not lexically closed by its caller, it's just an
  1594      * anonymous function in the top-level scope that its constructor inhabits.
  1595      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
  1596      * and so would a call to f from another top-level's script or function.
  1597      */
  1598     RootedAtom anonymousAtom(cx, cx->names().anonymous);
  1599     JSObject *proto = nullptr;
  1600     if (isStarGenerator) {
  1601         proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
  1602         if (!proto)
  1603             return false;
  1605     RootedFunction fun(cx, NewFunctionWithProto(cx, js::NullPtr(), nullptr, 0,
  1606                                                 JSFunction::INTERPRETED_LAMBDA, global,
  1607                                                 anonymousAtom, proto,
  1608                                                 JSFunction::FinalizeKind, TenuredObject));
  1609     if (!fun)
  1610         return false;
  1612     if (!JSFunction::setTypeForScriptedFunction(cx, fun))
  1613         return false;
  1615     if (hasRest)
  1616         fun->setHasRest();
  1618     bool ok;
  1619     SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
  1620     if (isStarGenerator)
  1621         ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
  1622     else
  1623         ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf);
  1624     args.rval().setObject(*fun);
  1625     return ok;
  1628 bool
  1629 js::Function(JSContext *cx, unsigned argc, Value *vp)
  1631     return FunctionConstructor(cx, argc, vp, NotGenerator);
  1634 bool
  1635 js::Generator(JSContext *cx, unsigned argc, Value *vp)
  1637     return FunctionConstructor(cx, argc, vp, StarGenerator);
  1640 bool
  1641 JSFunction::isBuiltinFunctionConstructor()
  1643     return maybeNative() == Function || maybeNative() == Generator;
  1646 JSFunction *
  1647 js::NewFunction(ExclusiveContext *cx, HandleObject funobjArg, Native native, unsigned nargs,
  1648                 JSFunction::Flags flags, HandleObject parent, HandleAtom atom,
  1649                 gc::AllocKind allocKind /* = JSFunction::FinalizeKind */,
  1650                 NewObjectKind newKind /* = GenericObject */)
  1652     return NewFunctionWithProto(cx, funobjArg, native, nargs, flags, parent, atom, nullptr,
  1653                                 allocKind, newKind);
  1656 JSFunction *
  1657 js::NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobjArg, Native native,
  1658                          unsigned nargs, JSFunction::Flags flags, HandleObject parent,
  1659                          HandleAtom atom, JSObject *proto,
  1660                          gc::AllocKind allocKind /* = JSFunction::FinalizeKind */,
  1661                          NewObjectKind newKind /* = GenericObject */)
  1663     JS_ASSERT(allocKind == JSFunction::FinalizeKind || allocKind == JSFunction::ExtendedFinalizeKind);
  1664     JS_ASSERT(sizeof(JSFunction) <= gc::Arena::thingSize(JSFunction::FinalizeKind));
  1665     JS_ASSERT(sizeof(FunctionExtended) <= gc::Arena::thingSize(JSFunction::ExtendedFinalizeKind));
  1667     RootedObject funobj(cx, funobjArg);
  1668     if (funobj) {
  1669         JS_ASSERT(funobj->is<JSFunction>());
  1670         JS_ASSERT(funobj->getParent() == parent);
  1671         JS_ASSERT_IF(native, funobj->hasSingletonType());
  1672     } else {
  1673         // Don't give asm.js module functions a singleton type since they
  1674         // are cloned (via CloneFunctionObjectIfNotSingleton) which assumes
  1675         // that hasSingletonType implies isInterpreted.
  1676         if (native && !IsAsmJSModuleNative(native))
  1677             newKind = SingletonObject;
  1678         funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto,
  1679                                          SkipScopeParent(parent), allocKind, newKind);
  1680         if (!funobj)
  1681             return nullptr;
  1683     RootedFunction fun(cx, &funobj->as<JSFunction>());
  1685     if (allocKind == JSFunction::ExtendedFinalizeKind)
  1686         flags = JSFunction::Flags(flags | JSFunction::EXTENDED);
  1688     /* Initialize all function members. */
  1689     fun->setArgCount(uint16_t(nargs));
  1690     fun->setFlags(flags);
  1691     if (fun->isInterpreted()) {
  1692         JS_ASSERT(!native);
  1693         fun->mutableScript().init(nullptr);
  1694         fun->initEnvironment(parent);
  1695     } else {
  1696         JS_ASSERT(fun->isNative());
  1697         JS_ASSERT(native);
  1698         fun->initNative(native, nullptr);
  1700     if (allocKind == JSFunction::ExtendedFinalizeKind)
  1701         fun->initializeExtended();
  1702     fun->initAtom(atom);
  1704     return fun;
  1707 JSFunction *
  1708 js::CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent, gc::AllocKind allocKind,
  1709                         NewObjectKind newKindArg /* = GenericObject */)
  1711     JS_ASSERT(parent);
  1712     JS_ASSERT(!fun->isBoundFunction());
  1714     bool useSameScript = cx->compartment() == fun->compartment() &&
  1715                          !fun->hasSingletonType() &&
  1716                          !types::UseNewTypeForClone(fun);
  1718     if (!useSameScript && fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
  1719         return nullptr;
  1721     NewObjectKind newKind = useSameScript ? newKindArg : SingletonObject;
  1722     JSObject *cloneProto = nullptr;
  1723     if (fun->isStarGenerator()) {
  1724         cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
  1725         if (!cloneProto)
  1726             return nullptr;
  1728     JSObject *cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto,
  1729                                                  SkipScopeParent(parent), allocKind, newKind);
  1730     if (!cloneobj)
  1731         return nullptr;
  1732     RootedFunction clone(cx, &cloneobj->as<JSFunction>());
  1734     uint16_t flags = fun->flags() & ~JSFunction::EXTENDED;
  1735     if (allocKind == JSFunction::ExtendedFinalizeKind)
  1736         flags |= JSFunction::EXTENDED;
  1738     clone->setArgCount(fun->nargs());
  1739     clone->setFlags(flags);
  1740     if (fun->hasScript()) {
  1741         clone->initScript(fun->nonLazyScript());
  1742         clone->initEnvironment(parent);
  1743     } else if (fun->isInterpretedLazy()) {
  1744         LazyScript *lazy = fun->lazyScriptOrNull();
  1745         clone->initLazyScript(lazy);
  1746         clone->initEnvironment(parent);
  1747     } else {
  1748         clone->initNative(fun->native(), fun->jitInfo());
  1750     clone->initAtom(fun->displayAtom());
  1752     if (allocKind == JSFunction::ExtendedFinalizeKind) {
  1753         if (fun->isExtended() && fun->compartment() == cx->compartment()) {
  1754             for (unsigned i = 0; i < FunctionExtended::NUM_EXTENDED_SLOTS; i++)
  1755                 clone->initExtendedSlot(i, fun->getExtendedSlot(i));
  1756         } else {
  1757             clone->initializeExtended();
  1761     if (useSameScript) {
  1762         /*
  1763          * Clone the function, reusing its script. We can use the same type as
  1764          * the original function provided that its prototype is correct.
  1765          */
  1766         if (fun->getProto() == clone->getProto())
  1767             clone->setType(fun->type());
  1768         return clone;
  1771     RootedFunction cloneRoot(cx, clone);
  1773     /*
  1774      * Across compartments we have to clone the script for interpreted
  1775      * functions. Cross-compartment cloning only happens via JSAPI
  1776      * (JS_CloneFunctionObject) which dynamically ensures that 'script' has
  1777      * no enclosing lexical scope (only the global scope).
  1778      */
  1779     if (cloneRoot->isInterpreted() && !CloneFunctionScript(cx, fun, cloneRoot, newKindArg))
  1780         return nullptr;
  1782     return cloneRoot;
  1785 JSFunction *
  1786 js::DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
  1787                    unsigned nargs, unsigned flags, AllocKind allocKind /* = FinalizeKind */,
  1788                    NewObjectKind newKind /* = GenericObject */)
  1790     PropertyOp gop;
  1791     StrictPropertyOp sop;
  1793     RootedFunction fun(cx);
  1795     if (flags & JSFUN_STUB_GSOPS) {
  1796         /*
  1797          * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
  1798          * the defined property's attributes. This allows us to encode another,
  1799          * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
  1800          * for more on this.
  1801          */
  1802         flags &= ~JSFUN_STUB_GSOPS;
  1803         gop = JS_PropertyStub;
  1804         sop = JS_StrictPropertyStub;
  1805     } else {
  1806         gop = nullptr;
  1807         sop = nullptr;
  1810     JSFunction::Flags funFlags;
  1811     if (!native)
  1812         funFlags = JSFunction::INTERPRETED_LAZY;
  1813     else
  1814         funFlags = JSAPIToJSFunctionFlags(flags);
  1815     RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr);
  1816     fun = NewFunction(cx, NullPtr(), native, nargs, funFlags, obj, atom, allocKind, newKind);
  1817     if (!fun)
  1818         return nullptr;
  1820     RootedValue funVal(cx, ObjectValue(*fun));
  1821     if (!JSObject::defineGeneric(cx, obj, id, funVal, gop, sop, flags & ~JSFUN_FLAGS_MASK))
  1822         return nullptr;
  1824     return fun;
  1827 bool
  1828 js::IsConstructor(const Value &v)
  1830     // Step 2.
  1831     if (!v.isObject())
  1832         return false;
  1834     // Step 3-4, a bit complex for us, since we have several flavors of
  1835     // [[Construct]] internal method.
  1836     JSObject &obj = v.toObject();
  1837     if (obj.is<JSFunction>()) {
  1838         JSFunction &fun = obj.as<JSFunction>();
  1839         return fun.isNativeConstructor() || fun.isInterpretedConstructor();
  1841     return obj.getClass()->construct != nullptr;
  1844 void
  1845 js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, const Class *clasp)
  1847     RootedValue thisv(cx, call.thisv());
  1849 #ifdef DEBUG
  1850     if (thisv.isObject()) {
  1851         JS_ASSERT(thisv.toObject().getClass() != clasp ||
  1852                   !thisv.toObject().isNative() ||
  1853                   !thisv.toObject().getProto() ||
  1854                   thisv.toObject().getProto()->getClass() != clasp);
  1855     } else if (thisv.isString()) {
  1856         JS_ASSERT(clasp != &StringObject::class_);
  1857     } else if (thisv.isNumber()) {
  1858         JS_ASSERT(clasp != &NumberObject::class_);
  1859     } else if (thisv.isBoolean()) {
  1860         JS_ASSERT(clasp != &BooleanObject::class_);
  1861     } else {
  1862         JS_ASSERT(thisv.isUndefined() || thisv.isNull());
  1864 #endif
  1866     if (JSFunction *fun = ReportIfNotFunction(cx, call.calleev())) {
  1867         JSAutoByteString funNameBytes;
  1868         if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
  1869             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
  1870                                  clasp->name, funName, InformalValueTypeName(thisv));
  1875 void
  1876 js::ReportIncompatible(JSContext *cx, CallReceiver call)
  1878     if (JSFunction *fun = ReportIfNotFunction(cx, call.calleev())) {
  1879         JSAutoByteString funNameBytes;
  1880         if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
  1881             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_METHOD,
  1882                                  funName, "method", InformalValueTypeName(call.thisv()));
  1887 bool
  1888 JSObject::hasIdempotentProtoChain() const
  1890     // Return false if obj (or an object on its proto chain) is non-native or
  1891     // has a resolve or lookup hook.
  1892     JSObject *obj = const_cast<JSObject *>(this);
  1893     while (true) {
  1894         if (!obj->isNative())
  1895             return false;
  1897         JSResolveOp resolve = obj->getClass()->resolve;
  1898         if (resolve != JS_ResolveStub && resolve != (JSResolveOp) js::fun_resolve)
  1899             return false;
  1901         if (obj->getOps()->lookupProperty || obj->getOps()->lookupGeneric || obj->getOps()->lookupElement)
  1902             return false;
  1904         obj = obj->getProto();
  1905         if (!obj)
  1906             return true;
  1909     MOZ_ASSUME_UNREACHABLE("Should not get here");
  1912 namespace JS {
  1913 namespace detail {
  1915 JS_PUBLIC_API(void)
  1916 CheckIsValidConstructible(Value calleev)
  1918     JSObject *callee = &calleev.toObject();
  1919     if (callee->is<JSFunction>())
  1920         JS_ASSERT(callee->as<JSFunction>().isNativeConstructor());
  1921     else
  1922         JS_ASSERT(callee->getClass()->construct != nullptr);
  1925 } // namespace detail
  1926 } // namespace JS

mercurial