LCOV - app.info - js/src/jsfun.cpp

LCOV - code coverage report
| Current view: | directory - js/src - jsfun.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 608 | 477 | 78.5 %
| Date: | 2012-04-07 | Functions: | 33 | 31 | 93.9 %

           1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=8 sw=4 et tw=99:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla Communicator client code, released
          18                 :  * March 31, 1998.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  * Netscape Communications Corporation.
          22                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          23                 :  * the Initial Developer. All Rights Reserved.
          24                 :  *
          25                 :  * Contributor(s):
          26                 :  *
          27                 :  * Alternatively, the contents of this file may be used under the terms of
          28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          31                 :  * of those above. If you wish to allow use of your version of this file only
          32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          33                 :  * use your version of this file under the terms of the MPL, indicate your
          34                 :  * decision by deleting the provisions above and replace them with the notice
          35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          36                 :  * the provisions above, a recipient may use your version of this file under
          37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          38                 :  *
          39                 :  * ***** END LICENSE BLOCK ***** */
          40                 :
          41                 : /*
          42                 :  * JS function support.
          43                 :  */
          44                 : #include <string.h>
          45                 :
          46                 : #include "mozilla/Util.h"
          47                 :
          48                 : #include "jstypes.h"
          49                 : #include "jsutil.h"
          50                 : #include "jsapi.h"
          51                 : #include "jsarray.h"
          52                 : #include "jsatom.h"
          53                 : #include "jsbool.h"
          54                 : #include "jscntxt.h"
          55                 : #include "jsexn.h"
          56                 : #include "jsfun.h"
          57                 : #include "jsgc.h"
          58                 : #include "jsgcmark.h"
          59                 : #include "jsinterp.h"
          60                 : #include "jslock.h"
          61                 : #include "jsnum.h"
          62                 : #include "jsobj.h"
          63                 : #include "jsopcode.h"
          64                 : #include "jspropertytree.h"
          65                 : #include "jsproxy.h"
          66                 : #include "jsscope.h"
          67                 : #include "jsscript.h"
          68                 : #include "jsstr.h"
          69                 :
          70                 : #include "frontend/BytecodeCompiler.h"
          71                 : #include "frontend/BytecodeEmitter.h"
          72                 : #include "frontend/TokenStream.h"
          73                 : #include "vm/Debugger.h"
          74                 : #include "vm/MethodGuard.h"
          75                 : #include "vm/ScopeObject.h"
          76                 : #include "vm/Xdr.h"
          77                 :
          78                 : #if JS_HAS_GENERATORS
          79                 : # include "jsiter.h"
          80                 : #endif
          81                 :
          82                 : #ifdef JS_METHODJIT
          83                 : #include "methodjit/MethodJIT.h"
          84                 : #endif
          85                 :
          86                 : #include "jsatominlines.h"
          87                 : #include "jsfuninlines.h"
          88                 : #include "jsinferinlines.h"
          89                 : #include "jsobjinlines.h"
          90                 : #include "jsscriptinlines.h"
          91                 : #include "vm/ArgumentsObject-inl.h"
          92                 : #include "vm/ScopeObject-inl.h"
          93                 : #include "vm/Stack-inl.h"
          94                 :
          95                 : using namespace mozilla;
          96                 : using namespace js;
          97                 : using namespace js::gc;
          98                 : using namespace js::types;
          99                 :
         100                 : static JSBool
         101            1910 : fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
         102                 : {
         103            3820 :     while (!obj->isFunction()) {
         104               0 :         obj = obj->getProto();
         105               0 :         if (!obj)
         106               0 :             return true;
         107                 :     }
         108            1910 :     JSFunction *fun = obj->toFunction();
         109                 :
         110                 :     /*
         111                 :      * Mark the function's script as uninlineable, to expand any of its
         112                 :      * frames on the stack before we go looking for them. This allows the
         113                 :      * below walk to only check each explicit frame rather than needing to
         114                 :      * check any calls that were inlined.
         115                 :      */
         116            1910 :     if (fun->isInterpreted()) {
         117            1910 :         fun->script()->uninlineable = true;
         118            1910 :         MarkTypeObjectFlags(cx, fun, OBJECT_FLAG_UNINLINEABLE);
         119                 :     }
         120                 :
         121                 :     /* Set to early to null in case of error */
         122            1910 :     vp->setNull();
         123                 :
         124                 :     /* Find fun's top-most activation record. */
         125            1910 :     StackFrame *fp = js_GetTopStackFrame(cx, FRAME_EXPAND_NONE);
         126            2153 :     for (; fp; fp = fp->prev()) {
         127            2079 :         if (!fp->isFunctionFrame() || fp->isEvalFrame())
         128              81 :             continue;
         129            1998 :         if (fp->callee().toFunction() == fun)
         130            1836 :             break;
         131                 :     }
         132            1910 :     if (!fp)
         133              74 :         return true;
         134                 :
         135                 : #ifdef JS_METHODJIT
         136            1836 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom) && fp && fp->prev()) {
         137                 :         /*
         138                 :          * If the frame was called from within an inlined frame, mark the
         139                 :          * innermost function as uninlineable to expand its frame and allow us
         140                 :          * to recover its callee object.
         141                 :          */
         142                 :         JSInlinedSite *inlined;
         143            1305 :         jsbytecode *prevpc = fp->prev()->pcQuadratic(cx->stack, fp, &inlined);
         144            1305 :         if (inlined) {
         145               0 :             mjit::JITChunk *chunk = fp->prev()->jit()->chunk(prevpc);
         146               0 :             JSFunction *fun = chunk->inlineFrames()[inlined->inlineIndex].fun;
         147               0 :             fun->script()->uninlineable = true;
         148               0 :             MarkTypeObjectFlags(cx, fun, OBJECT_FLAG_UNINLINEABLE);
         149                 :         }
         150                 :     }
         151                 : #endif
         152                 :
         153            1836 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.argumentsAtom)) {
         154                 :         /* Warn if strict about f.arguments or equivalent unqualified uses. */
         155             531 :         if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT, js_GetErrorMessage,
         156             531 :                                           NULL, JSMSG_DEPRECATED_USAGE, js_arguments_str)) {
         157               0 :             return false;
         158                 :         }
         159                 :
         160             531 :         ArgumentsObject *argsobj = ArgumentsObject::createUnexpected(cx, fp);
         161             531 :         if (!argsobj)
         162               0 :             return false;
         163                 :
         164             531 :         *vp = ObjectValue(*argsobj);
         165             531 :         return true;
         166                 :     }
         167                 :
         168            1305 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
         169            1305 :         if (!fp->prev())
         170               0 :             return true;
         171                 :
         172            1305 :         StackFrame *frame = fp->prev();
         173            2610 :         while (frame && frame->isDummyFrame())
         174               0 :             frame = frame->prev();
         175                 :
         176            1305 :         if (!frame || !frame->isFunctionFrame()) {
         177             297 :             JS_ASSERT(vp->isNull());
         178             297 :             return true;
         179                 :         }
         180                 :
         181            1008 :         vp->setObject(frame->callee());
         182                 :
         183                 :         /* Censor the caller if it is from another compartment. */
         184            1008 :         JSObject &caller = vp->toObject();
         185            1008 :         if (caller.compartment() != cx->compartment) {
         186               0 :             vp->setNull();
         187            1008 :         } else if (caller.isFunction()) {
         188            1008 :             JSFunction *callerFun = caller.toFunction();
         189            1008 :             if (callerFun->isInterpreted() && callerFun->inStrictMode()) {
         190                 :                 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
         191               0 :                                              JSMSG_CALLER_IS_STRICT);
         192               0 :                 return false;
         193                 :             }
         194                 :         }
         195                 :
         196            1008 :         return true;
         197                 :     }
         198                 :
         199               0 :     JS_NOT_REACHED("fun_getProperty");
         200                 :     return false;
         201                 : }
         202                 :
         203                 :
         204                 :
         205                 : /* NB: no sentinels at ends -- use ArrayLength to bound loops.
         206                 :  * Properties censored into [[ThrowTypeError]] in strict mode. */
         207                 : static const uint16_t poisonPillProps[] = {
         208                 :     ATOM_OFFSET(arguments),
         209                 :     ATOM_OFFSET(caller),
         210                 : };
         211                 :
         212                 : static JSBool
         213          258061 : fun_enumerate(JSContext *cx, JSObject *obj)
         214                 : {
         215          258061 :     JS_ASSERT(obj->isFunction());
         216                 :
         217          516122 :     RootObject root(cx, &obj);
         218                 :
         219                 :     jsid id;
         220                 :     bool found;
         221                 :
         222          258061 :     if (!obj->isBoundFunction()) {
         223          258061 :         id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
         224          258061 :         if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
         225               0 :             return false;
         226                 :     }
         227                 :
         228          258061 :     id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
         229          258061 :     if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
         230               0 :         return false;
         231                 :
         232          258061 :     id = ATOM_TO_JSID(cx->runtime->atomState.nameAtom);
         233          258061 :     if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
         234               0 :         return false;
         235                 :
         236          774183 :     for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
         237          516122 :         const uint16_t offset = poisonPillProps[i];
         238          516122 :         id = ATOM_TO_JSID(OFFSET_TO_ATOM(cx->runtime, offset));
         239          516122 :         if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
         240               0 :             return false;
         241                 :     }
         242                 :
         243          258061 :     return true;
         244                 : }
         245                 :
         246                 : static JSObject *
         247            2862 : ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
         248                 : {
         249                 : #ifdef DEBUG
         250            2862 :     JSFunction *fun = obj->toFunction();
         251            2862 :     JS_ASSERT(fun->isInterpreted());
         252            2862 :     JS_ASSERT(!fun->isFunctionPrototype());
         253                 : #endif
         254                 :
         255                 :     /*
         256                 :      * Assert that fun is not a compiler-created function object, which
         257                 :      * must never leak to script or embedding code and then be mutated.
         258                 :      * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
         259                 :      */
         260            2862 :     JS_ASSERT(!IsInternalFunctionObject(obj));
         261            2862 :     JS_ASSERT(!obj->isBoundFunction());
         262                 :
         263                 :     /*
         264                 :      * Make the prototype object an instance of Object with the same parent
         265                 :      * as the function object itself.
         266                 :      */
         267            2862 :     JSObject *objProto = obj->global().getOrCreateObjectPrototype(cx);
         268            2862 :     if (!objProto)
         269               0 :         return NULL;
         270            2862 :     JSObject *proto = NewObjectWithGivenProto(cx, &ObjectClass, objProto, NULL);
         271            2862 :     if (!proto || !proto->setSingletonType(cx))
         272               0 :         return NULL;
         273                 :
         274                 :     /*
         275                 :      * Per ES5 15.3.5.2 a user-defined function's .prototype property is
         276                 :      * initially non-configurable, non-enumerable, and writable.  Per ES5 13.2
         277                 :      * the prototype's .constructor property is configurable, non-enumerable,
         278                 :      * and writable.
         279                 :      */
         280            5724 :     if (!obj->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom,
         281                 :                              ObjectValue(*proto), JS_PropertyStub, JS_StrictPropertyStub,
         282            2862 :                              JSPROP_PERMANENT) ||
         283                 :         !proto->defineProperty(cx, cx->runtime->atomState.constructorAtom,
         284            2862 :                                ObjectValue(*obj), JS_PropertyStub, JS_StrictPropertyStub, 0))
         285                 :     {
         286               0 :        return NULL;
         287                 :     }
         288                 :
         289            2862 :     return proto;
         290                 : }
         291                 :
         292                 : static JSBool
         293         1836282 : fun_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
         294                 :             JSObject **objp)
         295                 : {
         296         1836282 :     if (!JSID_IS_ATOM(id))
         297            1484 :         return true;
         298                 :
         299         3669596 :     RootedVarFunction fun(cx);
         300         1834798 :     fun = obj->toFunction();
         301                 :
         302         1834798 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.classPrototypeAtom)) {
         303                 :         /*
         304                 :          * Native or "built-in" functions do not have a .prototype property per
         305                 :          * ECMA-262, or (Object.prototype, Function.prototype, etc.) have that
         306                 :          * property created eagerly.
         307                 :          *
         308                 :          * ES5 15.3.4: the non-native function object named Function.prototype
         309                 :          * does not have a .prototype property.
         310                 :          *
         311                 :          * ES5 15.3.4.5: bound functions don't have a prototype property. The
         312                 :          * isNative() test covers this case because bound functions are native
         313                 :          * functions by definition/construction.
         314                 :          */
         315           96101 :         if (fun->isNative() || fun->isFunctionPrototype())
         316           93239 :             return true;
         317                 :
         318            2862 :         if (!ResolveInterpretedFunctionPrototype(cx, fun))
         319               0 :             return false;
         320            2862 :         *objp = fun;
         321            2862 :         return true;
         322                 :     }
         323                 :
         324         3239556 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
         325         1500859 :         JSID_IS_ATOM(id, cx->runtime->atomState.nameAtom)) {
         326          474982 :         JS_ASSERT(!IsInternalFunctionObject(obj));
         327                 :
         328                 :         Value v;
         329          474982 :         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
         330          237838 :             v.setInt32(fun->nargs);
         331                 :         else
         332          237144 :             v.setString(fun->atom ? fun->atom : cx->runtime->emptyString);
         333                 :
         334          474982 :         if (!DefineNativeProperty(cx, fun, id, v, JS_PropertyStub, JS_StrictPropertyStub,
         335          474982 :                                   JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
         336               0 :             return false;
         337                 :         }
         338          474982 :         *objp = fun;
         339          474982 :         return true;
         340                 :     }
         341                 :
         342         3080508 :     for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
         343         2290545 :         const uint16_t offset = poisonPillProps[i];
         344                 :
         345         2290545 :         if (JSID_IS_ATOM(id, OFFSET_TO_ATOM(cx->runtime, offset))) {
         346          473752 :             JS_ASSERT(!IsInternalFunctionObject(fun));
         347                 :
         348                 :             PropertyOp getter;
         349                 :             StrictPropertyOp setter;
         350          473752 :             unsigned attrs = JSPROP_PERMANENT;
         351          473752 :             if (fun->isInterpreted() ? fun->inStrictMode() : fun->isBoundFunction()) {
         352               0 :                 JSObject *throwTypeError = fun->global().getThrowTypeError();
         353                 :
         354               0 :                 getter = CastAsPropertyOp(throwTypeError);
         355               0 :                 setter = CastAsStrictPropertyOp(throwTypeError);
         356               0 :                 attrs |= JSPROP_GETTER | JSPROP_SETTER;
         357                 :             } else {
         358          473752 :                 getter = fun_getProperty;
         359          473752 :                 setter = JS_StrictPropertyStub;
         360                 :             }
         361                 :
         362          473752 :             if (!DefineNativeProperty(cx, fun, id, UndefinedValue(), getter, setter,
         363          473752 :                                       attrs, 0, 0)) {
         364               0 :                 return false;
         365                 :             }
         366          473752 :             *objp = fun;
         367          473752 :             return true;
         368                 :         }
         369                 :     }
         370                 :
         371          789963 :     return true;
         372                 : }
         373                 :
         374                 : template<XDRMode mode>
         375                 : bool
         376             224 : js::XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript)
         377                 : {
         378                 :     JSFunction *fun;
         379                 :     JSAtom *atom;
         380                 :     uint32_t firstword;           /* flag telling whether fun->atom is non-null,
         381                 :                                    plus for fun->u.i.skipmin, fun->u.i.wrapper,
         382                 :                                    and 14 bits reserved for future use */
         383                 :     uint32_t flagsword;           /* word for argument count and fun->flags */
         384                 :
         385             224 :     JSContext *cx = xdr->cx();
         386                 :     JSScript *script;
         387                 :     if (mode == XDR_ENCODE) {
         388             112 :         fun = (*objp)->toFunction();
         389             112 :         if (!fun->isInterpreted()) {
         390               0 :             JSAutoByteString funNameBytes;
         391               0 :             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
         392               0 :                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION,
         393                 :                                      name);
         394                 :             }
         395               0 :             return false;
         396                 :         }
         397             112 :         firstword = !!fun->atom;
         398             112 :         flagsword = (fun->nargs << 16) | fun->flags;
         399             112 :         atom = fun->atom;
         400             112 :         script = fun->script();
         401                 :     } else {
         402             224 :         RootedVarObject parent(cx, NULL);
         403             112 :         fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, parent, NULL);
         404             112 :         if (!fun)
         405               0 :             return false;
         406             112 :         if (!fun->clearParent(cx))
         407               0 :             return false;
         408             112 :         if (!fun->clearType(cx))
         409               0 :             return false;
         410             112 :         atom = NULL;
         411             224 :         script = NULL;
         412                 :     }
         413                 :
         414             224 :     if (!xdr->codeUint32(&firstword))
         415               0 :         return false;
         416             224 :     if ((firstword & 1U) && !XDRAtom(xdr, &atom))
         417               0 :         return false;
         418             224 :     if (!xdr->codeUint32(&flagsword))
         419               0 :         return false;
         420                 :
         421             224 :     if (!XDRScript(xdr, &script, parentScript))
         422               0 :         return false;
         423                 :
         424                 :     if (mode == XDR_DECODE) {
         425             112 :         fun->nargs = flagsword >> 16;
         426             112 :         JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
         427             112 :         fun->flags = uint16_t(flagsword);
         428             112 :         fun->atom.init(atom);
         429             112 :         fun->initScript(script);
         430             112 :         if (!script->typeSetFunction(cx, fun))
         431               0 :             return false;
         432             112 :         JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
         433             112 :         js_CallNewScriptHook(cx, fun->script(), fun);
         434             112 :         *objp = fun;
         435                 :     }
         436                 :
         437             224 :     return true;
         438                 : }
         439                 :
         440                 : template bool
         441                 : js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *xdr, JSObject **objp, JSScript *parentScript);
         442                 :
         443                 : template bool
         444                 : js::XDRInterpretedFunction(XDRState<XDR_DECODE> *xdr, JSObject **objp, JSScript *parentScript);
         445                 :
         446                 : /*
         447                 :  * [[HasInstance]] internal method for Function objects: fetch the .prototype
         448                 :  * property of its 'this' parameter, and walks the prototype chain of v (only
         449                 :  * if v is an object) returning true if .prototype is found.
         450                 :  */
         451                 : static JSBool
         452         1050258 : fun_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
         453                 : {
         454         2100516 :     while (obj->isFunction()) {
         455         1050258 :         if (!obj->isBoundFunction())
         456         1050258 :             break;
         457               0 :         obj = obj->toFunction()->getBoundFunctionTarget();
         458                 :     }
         459                 :
         460                 :     Value pval;
         461         1050258 :     if (!obj->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &pval))
         462               0 :         return JS_FALSE;
         463                 :
         464         1050258 :     if (pval.isPrimitive()) {
         465                 :         /*
         466                 :          * Throw a runtime error if instanceof is called on a function that
         467                 :          * has a non-object as its .prototype value.
         468                 :          */
         469               7 :         js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, ObjectValue(*obj), NULL);
         470               7 :         return JS_FALSE;
         471                 :     }
         472                 :
         473         1050251 :     *bp = js_IsDelegate(cx, &pval.toObject(), *v);
         474         1050251 :     return JS_TRUE;
         475                 : }
         476                 :
         477                 : inline void
         478        13223025 : JSFunction::trace(JSTracer *trc)
         479                 : {
         480        13223025 :     if (isExtended()) {
         481          822111 :         MarkValueRange(trc, ArrayLength(toExtended()->extendedSlots),
         482         1644222 :                        toExtended()->extendedSlots, "nativeReserved");
         483                 :     }
         484                 :
         485        13223025 :     if (atom)
         486        11237169 :         MarkString(trc, &atom, "atom");
         487                 :
         488        13223025 :     if (isInterpreted()) {
         489          950866 :         if (u.i.script_)
         490          950866 :             MarkScriptUnbarriered(trc, &u.i.script_, "script");
         491          950866 :         if (u.i.env_)
         492          949955 :             MarkObjectUnbarriered(trc, &u.i.env_, "fun_callscope");
         493                 :     }
         494        13223025 : }
         495                 :
         496                 : static void
         497        13223025 : fun_trace(JSTracer *trc, JSObject *obj)
         498                 : {
         499        13223025 :     obj->toFunction()->trace(trc);
         500        13223025 : }
         501                 :
         502                 : /*
         503                 :  * Reserve two slots in all function objects for XPConnect.  Note that this
         504                 :  * does not bloat every instance, only those on which reserved slots are set,
         505                 :  * and those on which ad-hoc properties are defined.
         506                 :  */
         507                 : JS_FRIEND_DATA(Class) js::FunctionClass = {
         508                 :     js_Function_str,
         509                 :     JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS |
         510                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
         511                 :     JS_PropertyStub,         /* addProperty */
         512                 :     JS_PropertyStub,         /* delProperty */
         513                 :     JS_PropertyStub,         /* getProperty */
         514                 :     JS_StrictPropertyStub,   /* setProperty */
         515                 :     fun_enumerate,
         516                 :     (JSResolveOp)fun_resolve,
         517                 :     JS_ConvertStub,
         518                 :     NULL,                    /* finalize    */
         519                 :     NULL,                    /* checkAccess */
         520                 :     NULL,                    /* call        */
         521                 :     NULL,                    /* construct   */
         522                 :     fun_hasInstance,
         523                 :     fun_trace
         524                 : };
         525                 :
         526                 : JSString *
         527          267039 : fun_toStringHelper(JSContext *cx, JSObject *obj, unsigned indent)
         528                 : {
         529          267039 :     if (!obj->isFunction()) {
         530               9 :         if (IsFunctionProxy(obj))
         531               9 :             return Proxy::fun_toString(cx, obj, indent);
         532                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
         533                 :                              JSMSG_INCOMPATIBLE_PROTO,
         534                 :                              js_Function_str, js_toString_str,
         535               0 :                              "object");
         536               0 :         return NULL;
         537                 :     }
         538                 :
         539          267030 :     JSFunction *fun = obj->toFunction();
         540          267030 :     if (!fun)
         541               0 :         return NULL;
         542                 :
         543          267030 :     if (!indent && !cx->compartment->toSourceCache.empty()) {
         544          255717 :         ToSourceCache::Ptr p = cx->compartment->toSourceCache.ref().lookup(fun);
         545          255717 :         if (p)
         546          255501 :             return p->value;
         547                 :     }
         548                 :
         549           11529 :     JSString *str = JS_DecompileFunction(cx, fun, indent);
         550           11529 :     if (!str)
         551               0 :         return NULL;
         552                 :
         553           11529 :     if (!indent) {
         554             774 :         Maybe<ToSourceCache> &lazy = cx->compartment->toSourceCache;
         555                 :
         556             774 :         if (lazy.empty()) {
         557             558 :             lazy.construct();
         558             558 :             if (!lazy.ref().init())
         559               0 :                 return NULL;
         560                 :         }
         561                 :
         562             774 :         if (!lazy.ref().put(fun, str))
         563               0 :             return NULL;
         564                 :     }
         565                 :
         566           11529 :     return str;
         567                 : }
         568                 :
         569                 : static JSBool
         570          256275 : fun_toString(JSContext *cx, unsigned argc, Value *vp)
         571                 : {
         572          256275 :     JS_ASSERT(IsFunctionObject(vp[0]));
         573          256275 :     uint32_t indent = 0;
         574                 :
         575          256275 :     if (argc != 0 && !ToUint32(cx, vp[2], &indent))
         576               0 :         return false;
         577                 :
         578          256275 :     JSObject *obj = ToObject(cx, &vp[1]);
         579          256275 :     if (!obj)
         580               0 :         return false;
         581                 :
         582          256275 :     JSString *str = fun_toStringHelper(cx, obj, indent);
         583          256275 :     if (!str)
         584               0 :         return false;
         585                 :
         586          256275 :     vp->setString(str);
         587          256275 :     return true;
         588                 : }
         589                 :
         590                 : #if JS_HAS_TOSOURCE
         591                 : static JSBool
         592           10755 : fun_toSource(JSContext *cx, unsigned argc, Value *vp)
         593                 : {
         594           10755 :     JS_ASSERT(IsFunctionObject(vp[0]));
         595                 :
         596           10755 :     JSObject *obj = ToObject(cx, &vp[1]);
         597           10755 :     if (!obj)
         598               0 :         return false;
         599                 :
         600           10755 :     JSString *str = fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT);
         601           10755 :     if (!str)
         602               0 :         return false;
         603                 :
         604           10755 :     vp->setString(str);
         605           10755 :     return true;
         606                 : }
         607                 : #endif
         608                 :
         609                 : JSBool
         610           38988 : js_fun_call(JSContext *cx, unsigned argc, Value *vp)
         611                 : {
         612           38988 :     Value fval = vp[1];
         613                 :
         614           38988 :     if (!js_IsCallable(fval)) {
         615              18 :         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &FunctionClass);
         616              18 :         return false;
         617                 :     }
         618                 :
         619           38970 :     Value *argv = vp + 2;
         620                 :     Value thisv;
         621           38970 :     if (argc == 0) {
         622             387 :         thisv.setUndefined();
         623                 :     } else {
         624           38583 :         thisv = argv[0];
         625                 :
         626           38583 :         argc--;
         627           38583 :         argv++;
         628                 :     }
         629                 :
         630                 :     /* Allocate stack space for fval, obj, and the args. */
         631           77940 :     InvokeArgsGuard args;
         632           38970 :     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         633               0 :         return JS_FALSE;
         634                 :
         635                 :     /* Push fval, thisv, and the args. */
         636           38970 :     args.calleev() = fval;
         637           38970 :     args.thisv() = thisv;
         638           38970 :     PodCopy(args.array(), argv, argc);
         639                 :
         640           38970 :     bool ok = Invoke(cx, args);
         641           38970 :     *vp = args.rval();
         642           38970 :     return ok;
         643                 : }
         644                 :
         645                 : /* ES5 15.3.4.3 */
         646                 : JSBool
         647          462207 : js_fun_apply(JSContext *cx, unsigned argc, Value *vp)
         648                 : {
         649                 :     /* Step 1. */
         650          462207 :     Value fval = vp[1];
         651          462207 :     if (!js_IsCallable(fval)) {
         652               8 :         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &FunctionClass);
         653               8 :         return false;
         654                 :     }
         655                 :
         656                 :     /* Step 2. */
         657          462199 :     if (argc < 2 || vp[3].isNullOrUndefined())
         658             225 :         return js_fun_call(cx, (argc > 0) ? 1 : 0, vp);
         659                 :
         660          923948 :     InvokeArgsGuard args;
         661          461974 :     if (vp[3].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
         662                 :         /*
         663                 :          * Pretend we have been passed the 'arguments' object for the current
         664                 :          * function and read actuals out of the frame.
         665                 :          *
         666                 :          * N.B. Changes here need to be propagated to stubs::SplatApplyArgs.
         667                 :          */
         668                 :         /* Steps 4-6. */
         669          144060 :         unsigned length = cx->fp()->numActualArgs();
         670          144060 :         JS_ASSERT(length <= StackSpace::ARGS_LENGTH_MAX);
         671                 :
         672          144060 :         if (!cx->stack.pushInvokeArgs(cx, length, &args))
         673               0 :             return false;
         674                 :
         675                 :         /* Push fval, obj, and aobj's elements as args. */
         676          144060 :         args.calleev() = fval;
         677          144060 :         args.thisv() = vp[2];
         678                 :
         679                 :         /* Steps 7-8. */
         680          144060 :         cx->fp()->forEachCanonicalActualArg(CopyTo(args.array()));
         681                 :     } else {
         682                 :         /* Step 3. */
         683          317914 :         if (!vp[3].isObject()) {
         684               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str);
         685               0 :             return false;
         686                 :         }
         687                 :
         688                 :         /*
         689                 :          * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
         690                 :          * original version of ES5).
         691                 :          */
         692          317914 :         JSObject *aobj = &vp[3].toObject();
         693                 :         uint32_t length;
         694          317914 :         if (!js_GetLengthProperty(cx, aobj, &length))
         695               0 :             return false;
         696                 :
         697                 :         /* Step 6. */
         698          317914 :         if (length > StackSpace::ARGS_LENGTH_MAX) {
         699              22 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
         700              22 :             return false;
         701                 :         }
         702                 :
         703          317892 :         if (!cx->stack.pushInvokeArgs(cx, length, &args))
         704               0 :             return false;
         705                 :
         706                 :         /* Push fval, obj, and aobj's elements as args. */
         707          317892 :         args.calleev() = fval;
         708          317892 :         args.thisv() = vp[2];
         709                 :
         710                 :         /* Steps 7-8. */
         711          317892 :         if (!GetElements(cx, aobj, length, args.array()))
         712               0 :             return false;
         713                 :     }
         714                 :
         715                 :     /* Step 9. */
         716          461952 :     if (!Invoke(cx, args))
         717            4016 :         return false;
         718                 :
         719          457936 :     *vp = args.rval();
         720          457936 :     return true;
         721                 : }
         722                 :
         723                 : namespace js {
         724                 :
         725                 : JSBool
         726                 : CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp);
         727                 :
         728                 : }
         729                 :
         730                 : static const uint32_t JSSLOT_BOUND_FUNCTION_THIS       = 0;
         731                 : static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1;
         732                 :
         733                 : static const uint32_t BOUND_FUNCTION_RESERVED_SLOTS = 2;
         734                 :
         735                 : inline bool
         736            2235 : JSFunction::initBoundFunction(JSContext *cx, const Value &thisArg,
         737                 :                               const Value *args, unsigned argslen)
         738                 : {
         739            2235 :     JS_ASSERT(isFunction());
         740                 :
         741                 :     /*
         742                 :      * Convert to a dictionary to set the BOUND_FUNCTION flag and increase
         743                 :      * the slot span to cover the arguments and additional slots for the 'this'
         744                 :      * value and arguments count.
         745                 :      */
         746            2235 :     if (!toDictionaryMode(cx))
         747               0 :         return false;
         748                 :
         749            2235 :     if (!setFlag(cx, BaseShape::BOUND_FUNCTION))
         750               0 :         return false;
         751                 :
         752            2235 :     if (!setSlotSpan(cx, BOUND_FUNCTION_RESERVED_SLOTS + argslen))
         753               0 :         return false;
         754                 :
         755            2235 :     setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
         756            2235 :     setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
         757                 :
         758            2235 :     initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen);
         759                 :
         760            2235 :     return true;
         761                 : }
         762                 :
         763                 : inline JSObject *
         764             489 : JSFunction::getBoundFunctionTarget() const
         765                 : {
         766             489 :     JS_ASSERT(isFunction());
         767             489 :     JS_ASSERT(isBoundFunction());
         768                 :
         769                 :     /* Bound functions abuse |parent| to store their target function. */
         770             489 :     return getParent();
         771                 : }
         772                 :
         773                 : inline const js::Value &
         774             489 : JSFunction::getBoundFunctionThis() const
         775                 : {
         776             489 :     JS_ASSERT(isFunction());
         777             489 :     JS_ASSERT(isBoundFunction());
         778                 :
         779             489 :     return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
         780                 : }
         781                 :
         782                 : inline const js::Value &
         783             378 : JSFunction::getBoundFunctionArgument(unsigned which) const
         784                 : {
         785             378 :     JS_ASSERT(isFunction());
         786             378 :     JS_ASSERT(isBoundFunction());
         787             378 :     JS_ASSERT(which < getBoundFunctionArgumentCount());
         788                 :
         789             378 :     return getSlot(BOUND_FUNCTION_RESERVED_SLOTS + which);
         790                 : }
         791                 :
         792                 : inline size_t
         793             867 : JSFunction::getBoundFunctionArgumentCount() const
         794                 : {
         795             867 :     JS_ASSERT(isFunction());
         796             867 :     JS_ASSERT(isBoundFunction());
         797                 :
         798             867 :     return getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
         799                 : }
         800                 :
         801                 : namespace js {
         802                 :
         803                 : /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
         804                 : JSBool
         805             489 : CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp)
         806                 : {
         807             489 :     JSFunction *fun = vp[0].toObject().toFunction();
         808             489 :     JS_ASSERT(fun->isBoundFunction());
         809                 :
         810             489 :     bool constructing = IsConstructing(vp);
         811                 :
         812                 :     /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
         813             489 :     unsigned argslen = fun->getBoundFunctionArgumentCount();
         814                 :
         815             489 :     if (argc + argslen > StackSpace::ARGS_LENGTH_MAX) {
         816               0 :         js_ReportAllocationOverflow(cx);
         817               0 :         return false;
         818                 :     }
         819                 :
         820                 :     /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
         821             489 :     JSObject *target = fun->getBoundFunctionTarget();
         822                 :
         823                 :     /* 15.3.4.5.1 step 2. */
         824             489 :     const Value &boundThis = fun->getBoundFunctionThis();
         825                 :
         826             978 :     InvokeArgsGuard args;
         827             489 :     if (!cx->stack.pushInvokeArgs(cx, argc + argslen, &args))
         828               0 :         return false;
         829                 :
         830                 :     /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
         831             867 :     for (unsigned i = 0; i < argslen; i++)
         832             378 :         args[i] = fun->getBoundFunctionArgument(i);
         833             489 :     PodCopy(args.array() + argslen, vp + 2, argc);
         834                 :
         835                 :     /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
         836             489 :     args.calleev().setObject(*target);
         837                 :
         838             489 :     if (!constructing)
         839             273 :         args.thisv() = boundThis;
         840                 :
         841             489 :     if (constructing ? !InvokeConstructor(cx, args) : !Invoke(cx, args))
         842               9 :         return false;
         843                 :
         844             480 :     *vp = args.rval();
         845             480 :     return true;
         846                 : }
         847                 :
         848                 : }
         849                 :
         850                 : #if JS_HAS_GENERATORS
         851                 : static JSBool
         852               0 : fun_isGenerator(JSContext *cx, unsigned argc, Value *vp)
         853                 : {
         854                 :     JSFunction *fun;
         855               0 :     if (!IsFunctionObject(vp[1], &fun)) {
         856               0 :         JS_SET_RVAL(cx, vp, BooleanValue(false));
         857               0 :         return true;
         858                 :     }
         859                 :
         860               0 :     bool result = false;
         861               0 :     if (fun->isInterpreted()) {
         862               0 :         JSScript *script = fun->script();
         863               0 :         JS_ASSERT(script->length != 0);
         864               0 :         result = script->code[0] == JSOP_GENERATOR;
         865                 :     }
         866                 :
         867               0 :     JS_SET_RVAL(cx, vp, BooleanValue(result));
         868               0 :     return true;
         869                 : }
         870                 : #endif
         871                 :
         872                 : /* ES5 15.3.4.5. */
         873                 : static JSBool
         874            2234 : fun_bind(JSContext *cx, unsigned argc, Value *vp)
         875                 : {
         876            2234 :     CallArgs args = CallArgsFromVp(argc, vp);
         877                 :
         878                 :     /* Step 1. */
         879            2234 :     Value &thisv = args.thisv();
         880                 :
         881                 :     /* Step 2. */
         882            2234 :     if (!js_IsCallable(thisv)) {
         883               0 :         ReportIncompatibleMethod(cx, args, &FunctionClass);
         884               0 :         return false;
         885                 :     }
         886                 :
         887            4468 :     RootedVarObject target(cx);
         888            2234 :     target = &thisv.toObject();
         889                 :
         890                 :     /* Step 3. */
         891            2234 :     Value *boundArgs = NULL;
         892            2234 :     unsigned argslen = 0;
         893            2234 :     if (args.length() > 1) {
         894            1854 :         boundArgs = args.array() + 1;
         895            1854 :         argslen = args.length() - 1;
         896                 :     }
         897                 :
         898                 :     /* Steps 7-9. */
         899            2234 :     Value thisArg = args.length() >= 1 ? args[0] : UndefinedValue();
         900                 :
         901            2234 :     JSObject *boundFunction = js_fun_bind(cx, target, thisArg, boundArgs, argslen);
         902            2234 :     if (!boundFunction)
         903               0 :         return false;
         904                 :
         905                 :     /* Step 22. */
         906            2234 :     args.rval().setObject(*boundFunction);
         907            2234 :     return true;
         908                 : }
         909                 :
         910                 : JSObject*
         911            2235 : js_fun_bind(JSContext *cx, HandleObject target, Value thisArg,
         912                 :             Value *boundArgs, unsigned argslen)
         913                 : {
         914                 :     /* Steps 15-16. */
         915            2235 :     unsigned length = 0;
         916            2235 :     if (target->isFunction()) {
         917            2235 :         unsigned nargs = target->toFunction()->nargs;
         918            2235 :         if (nargs > argslen)
         919              27 :             length = nargs - argslen;
         920                 :     }
         921                 :
         922                 :     /* Step 4-6, 10-11. */
         923            2235 :     JSAtom *name = target->isFunction() ? target->toFunction()->atom.get() : NULL;
         924                 :
         925                 :     JSObject *funobj =
         926                 :         js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length,
         927            2235 :                        JSFUN_CONSTRUCTOR, target, name);
         928            2235 :     if (!funobj)
         929               0 :         return NULL;
         930                 :
         931                 :     /* NB: Bound functions abuse |parent| to store their target. */
         932            2235 :     if (!funobj->setParent(cx, target))
         933               0 :         return NULL;
         934                 :
         935            2235 :     if (!funobj->toFunction()->initBoundFunction(cx, thisArg, boundArgs, argslen))
         936               0 :         return NULL;
         937                 :
         938                 :     /* Steps 17, 19-21 are handled by fun_resolve. */
         939                 :     /* Step 18 is the default for new functions. */
         940            2235 :     return funobj;
         941                 : }
         942                 :
         943                 : /*
         944                 :  * Report "malformed formal parameter" iff no illegal char or similar scanner
         945                 :  * error was already reported.
         946                 :  */
         947                 : static bool
         948               9 : OnBadFormal(JSContext *cx, TokenKind tt)
         949                 : {
         950               9 :     if (tt != TOK_ERROR)
         951               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_FORMAL);
         952                 :     else
         953               9 :         JS_ASSERT(cx->isExceptionPending());
         954               9 :     return false;
         955                 : }
         956                 :
         957                 : namespace js {
         958                 :
         959                 : JSFunctionSpec function_methods[] = {
         960                 : #if JS_HAS_TOSOURCE
         961                 :     JS_FN(js_toSource_str,   fun_toSource,   0,0),
         962                 : #endif
         963                 :     JS_FN(js_toString_str,   fun_toString,   0,0),
         964                 :     JS_FN(js_apply_str,      js_fun_apply,   2,0),
         965                 :     JS_FN(js_call_str,       js_fun_call,    1,0),
         966                 :     JS_FN("bind",            fun_bind,       1,0),
         967                 : #if JS_HAS_GENERATORS
         968                 :     JS_FN("isGenerator",     fun_isGenerator,0,0),
         969                 : #endif
         970                 :     JS_FS_END
         971                 : };
         972                 :
         973                 : JSBool
         974           10612 : Function(JSContext *cx, unsigned argc, Value *vp)
         975                 : {
         976           10612 :     CallArgs args = CallArgsFromVp(argc, vp);
         977                 :
         978                 :     /* Block this call if security callbacks forbid it. */
         979           21224 :     RootedVar<GlobalObject*> global(cx);
         980           10612 :     global = &args.callee().global();
         981           10612 :     if (!global->isRuntimeCodeGenEnabled(cx)) {
         982               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
         983               0 :         return false;
         984                 :     }
         985                 :
         986           21224 :     Bindings bindings(cx);
         987                 :
         988                 :     const char *filename;
         989                 :     unsigned lineno;
         990                 :     JSPrincipals *originPrincipals;
         991           10612 :     CurrentScriptFileLineOrigin(cx, &filename, &lineno, &originPrincipals);
         992           10612 :     JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
         993                 :
         994           10612 :     unsigned n = args.length() ? args.length() - 1 : 0;
         995           10612 :     if (n > 0) {
         996                 :         /*
         997                 :          * Collect the function-argument arguments into one string, separated
         998                 :          * by commas, then make a tokenstream from that string, and scan it to
         999                 :          * get the arguments.  We need to throw the full scanner at the
        1000                 :          * problem, because the argument string can legitimately contain
        1001                 :          * comments and linefeeds.  XXX It might be better to concatenate
        1002                 :          * everything up into a function definition and pass it to the
        1003                 :          * compiler, but doing it this way is less of a delta from the old
        1004                 :          * code.  See ECMA 15.3.2.1.
        1005                 :          */
        1006            4907 :         size_t args_length = 0;
        1007            9823 :         for (unsigned i = 0; i < n; i++) {
        1008                 :             /* Collect the lengths for all the function-argument arguments. */
        1009            4916 :             JSString *arg = ToString(cx, args[i]);
        1010            4916 :             if (!arg)
        1011               0 :                 return false;
        1012            4916 :             args[i].setString(arg);
        1013                 :
        1014                 :             /*
        1015                 :              * Check for overflow.  The < test works because the maximum
        1016                 :              * JSString length fits in 2 fewer bits than size_t has.
        1017                 :              */
        1018            4916 :             size_t old_args_length = args_length;
        1019            4916 :             args_length = old_args_length + arg->length();
        1020            4916 :             if (args_length < old_args_length) {
        1021               0 :                 js_ReportAllocationOverflow(cx);
        1022               0 :                 return false;
        1023                 :             }
        1024                 :         }
        1025                 :
        1026                 :         /* Add 1 for each joining comma and check for overflow (two ways). */
        1027            4907 :         size_t old_args_length = args_length;
        1028            4907 :         args_length = old_args_length + n - 1;
        1029            4907 :         if (args_length < old_args_length ||
        1030                 :             args_length >= ~(size_t)0 / sizeof(jschar)) {
        1031               0 :             js_ReportAllocationOverflow(cx);
        1032               0 :             return false;
        1033                 :         }
        1034                 :
        1035                 :         /*
        1036                 :          * Allocate a string to hold the concatenated arguments, including room
        1037                 :          * for a terminating 0. Mark cx->tempLifeAlloc for later release, to
        1038                 :          * free collected_args and its tokenstream in one swoop.
        1039                 :          */
        1040            9814 :         LifoAllocScope las(&cx->tempLifoAlloc());
        1041            4907 :         jschar *cp = cx->tempLifoAlloc().newArray<jschar>(args_length + 1);
        1042            4907 :         if (!cp) {
        1043               0 :             js_ReportOutOfMemory(cx);
        1044               0 :             return false;
        1045                 :         }
        1046            4907 :         jschar *collected_args = cp;
        1047                 :
        1048                 :         /*
        1049                 :          * Concatenate the arguments into the new string, separated by commas.
        1050                 :          */
        1051            9823 :         for (unsigned i = 0; i < n; i++) {
        1052            4916 :             JSString *arg = args[i].toString();
        1053            4916 :             size_t arg_length = arg->length();
        1054            4916 :             const jschar *arg_chars = arg->getChars(cx);
        1055            4916 :             if (!arg_chars)
        1056               0 :                 return false;
        1057            4916 :             (void) js_strncpy(cp, arg_chars, arg_length);
        1058            4916 :             cp += arg_length;
        1059                 :
        1060                 :             /* Add separating comma or terminating 0. */
        1061            4916 :             *cp++ = (i + 1 < n) ? ',' : 0;
        1062                 :         }
        1063                 :
        1064                 :         /* Initialize a tokenstream that reads from the given string. */
        1065            9814 :         TokenStream ts(cx, principals, originPrincipals);
        1066            4907 :         if (!ts.init(collected_args, args_length, filename, lineno, cx->findVersion()))
        1067               0 :             return false;
        1068                 :
        1069                 :         /* The argument string may be empty or contain no tokens. */
        1070            4907 :         TokenKind tt = ts.getToken();
        1071            4907 :         if (tt != TOK_EOF) {
        1072              18 :             for (;;) {
        1073                 :                 /*
        1074                 :                  * Check that it's a name.  This also implicitly guards against
        1075                 :                  * TOK_ERROR, which was already reported.
        1076                 :                  */
        1077            4925 :                 if (tt != TOK_NAME)
        1078               9 :                     return OnBadFormal(cx, tt);
        1079                 :
        1080                 :                 /* Check for a duplicate parameter name. */
        1081            4916 :                 PropertyName *name = ts.currentToken().name();
        1082            4916 :                 if (bindings.hasBinding(cx, name)) {
        1083               0 :                     JSAutoByteString bytes;
        1084               0 :                     if (!js_AtomToPrintableString(cx, name, &bytes))
        1085               0 :                         return false;
        1086               0 :                     if (!ReportCompileErrorNumber(cx, &ts, NULL,
        1087                 :                                                   JSREPORT_WARNING | JSREPORT_STRICT,
        1088               0 :                                                   JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
        1089                 :                     {
        1090               0 :                         return false;
        1091                 :                     }
        1092                 :                 }
        1093                 :
        1094                 :                 uint16_t dummy;
        1095            4916 :                 if (!bindings.addArgument(cx, name, &dummy))
        1096               0 :                     return false;
        1097                 :
        1098                 :                 /*
        1099                 :                  * Get the next token.  Stop on end of stream.  Otherwise
        1100                 :                  * insist on a comma, get another name, and iterate.
        1101                 :                  */
        1102            4916 :                 tt = ts.getToken();
        1103            4916 :                 if (tt == TOK_EOF)
        1104                 :                     break;
        1105              18 :                 if (tt != TOK_COMMA)
        1106               0 :                     return OnBadFormal(cx, tt);
        1107              18 :                 tt = ts.getToken();
        1108                 :             }
        1109                 :         }
        1110                 :     }
        1111                 :
        1112           21206 :     JS::Anchor<JSString *> strAnchor(NULL);
        1113                 :     const jschar *chars;
        1114                 :     size_t length;
        1115                 :
        1116           10603 :     if (args.length()) {
        1117           10396 :         JSString *str = ToString(cx, args[args.length() - 1]);
        1118           10396 :         if (!str)
        1119               0 :             return false;
        1120           10396 :         strAnchor.set(str);
        1121           10396 :         chars = str->getChars(cx);
        1122           10396 :         length = str->length();
        1123                 :     } else {
        1124             207 :         chars = cx->runtime->emptyString->chars();
        1125             207 :         length = 0;
        1126                 :     }
        1127                 :
        1128                 :     /*
        1129                 :      * NB: (new Function) is not lexically closed by its caller, it's just an
        1130                 :      * anonymous function in the top-level scope that its constructor inhabits.
        1131                 :      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
        1132                 :      * and so would a call to f from another top-level's script or function.
        1133                 :      */
        1134                 :     JSFunction *fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
        1135           10603 :                                      global, cx->runtime->atomState.anonymousAtom);
        1136           10603 :     if (!fun)
        1137               0 :         return false;
        1138                 :
        1139                 :     bool ok = frontend::CompileFunctionBody(cx, fun, principals, originPrincipals,
        1140                 :                                             &bindings, chars, length, filename, lineno,
        1141           10603 :                                             cx->findVersion());
        1142           10603 :     args.rval().setObject(*fun);
        1143           10603 :     return ok;
        1144                 : }
        1145                 :
        1146                 : bool
        1147           10612 : IsBuiltinFunctionConstructor(JSFunction *fun)
        1148                 : {
        1149           10612 :     return fun->maybeNative() == Function;
        1150                 : }
        1151                 :
        1152                 : const Shape *
        1153               0 : LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj)
        1154                 : {
        1155                 : #ifdef DEBUG
        1156               0 :     JSFunction *fun = funobj->toFunction();
        1157               0 :     JS_ASSERT(fun->isInterpreted());
        1158               0 :     JS_ASSERT(!fun->isFunctionPrototype());
        1159               0 :     JS_ASSERT(!funobj->isBoundFunction());
        1160                 : #endif
        1161                 :
        1162               0 :     jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
        1163               0 :     const Shape *shape = funobj->nativeLookup(cx, id);
        1164               0 :     if (!shape) {
        1165               0 :         if (!ResolveInterpretedFunctionPrototype(cx, funobj))
        1166               0 :             return NULL;
        1167               0 :         shape = funobj->nativeLookup(cx, id);
        1168                 :     }
        1169               0 :     JS_ASSERT(!shape->configurable());
        1170               0 :     JS_ASSERT(shape->isDataDescriptor());
        1171               0 :     JS_ASSERT(shape->hasSlot());
        1172               0 :     return shape;
        1173                 : }
        1174                 :
        1175                 : } /* namespace js */
        1176                 :
        1177                 : JSFunction *
        1178         7075280 : js_NewFunction(JSContext *cx, JSObject *funobj, Native native, unsigned nargs,
        1179                 :                unsigned flags, HandleObject parent, JSAtom *atom, js::gc::AllocKind kind)
        1180                 : {
        1181         7075280 :     JS_ASSERT(kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
        1182         7075280 :     JS_ASSERT(sizeof(JSFunction) <= gc::Arena::thingSize(JSFunction::FinalizeKind));
        1183         7075280 :     JS_ASSERT(sizeof(FunctionExtended) <= gc::Arena::thingSize(JSFunction::ExtendedFinalizeKind));
        1184                 :
        1185                 :     JSFunction *fun;
        1186                 :
        1187         7075280 :     if (funobj) {
        1188           70887 :         JS_ASSERT(funobj->isFunction());
        1189           70887 :         JS_ASSERT(funobj->getParent() == parent);
        1190                 :     } else {
        1191         7004393 :         funobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind);
        1192         7004393 :         if (!funobj)
        1193               0 :             return NULL;
        1194                 :     }
        1195         7075280 :     fun = static_cast<JSFunction *>(funobj);
        1196                 :
        1197                 :     /* Initialize all function members. */
        1198         7075280 :     fun->nargs = uint16_t(nargs);
        1199         7075280 :     fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK);
        1200         7075280 :     if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
        1201          191130 :         JS_ASSERT(!native);
        1202          191130 :         fun->script().init(NULL);
        1203          191130 :         fun->initEnvironment(parent);
        1204                 :     } else {
        1205         6884150 :         fun->u.native = native;
        1206         6884150 :         JS_ASSERT(fun->u.native);
        1207                 :     }
        1208         7075280 :     if (kind == JSFunction::ExtendedFinalizeKind) {
        1209          623184 :         fun->flags |= JSFUN_EXTENDED;
        1210          623184 :         fun->initializeExtended();
        1211                 :     }
        1212         7075280 :     fun->atom.init(atom);
        1213                 :
        1214         7075280 :     if (native && !fun->setSingletonType(cx))
        1215               0 :         return NULL;
        1216                 :
        1217         7075280 :     return fun;
        1218                 : }
        1219                 :
        1220                 : JSFunction * JS_FASTCALL
        1221          971430 : js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
        1222                 :                        JSObject *proto, gc::AllocKind kind)
        1223                 : {
        1224          971430 :     JS_ASSERT(parent);
        1225          971430 :     JS_ASSERT(proto);
        1226                 :
        1227          971430 :     JSObject *cloneobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind);
        1228          971430 :     if (!cloneobj)
        1229               0 :         return NULL;
        1230          971430 :     JSFunction *clone = static_cast<JSFunction *>(cloneobj);
        1231                 :
        1232          971430 :     clone->nargs = fun->nargs;
        1233          971430 :     clone->flags = fun->flags & ~JSFUN_EXTENDED;
        1234          971430 :     if (fun->isInterpreted()) {
        1235          971430 :         clone->initScript(fun->script());
        1236          971430 :         clone->initEnvironment(parent);
        1237                 :     } else {
        1238               0 :         clone->u.native = fun->native();
        1239                 :     }
        1240          971430 :     clone->atom.init(fun->atom);
        1241                 :
        1242          971430 :     if (kind == JSFunction::ExtendedFinalizeKind) {
        1243               0 :         clone->flags |= JSFUN_EXTENDED;
        1244               0 :         clone->initializeExtended();
        1245                 :     }
        1246                 :
        1247          971430 :     if (cx->compartment == fun->compartment()) {
        1248                 :         /*
        1249                 :          * We can use the same type as the original function provided that (a)
        1250                 :          * its prototype is correct, and (b) its type is not a singleton. The
        1251                 :          * first case will hold in all compileAndGo code, and the second case
        1252                 :          * will have been caught by CloneFunctionObject coming from function
        1253                 :          * definitions or read barriers, so will not get here.
        1254                 :          */
        1255          969061 :         if (fun->getProto() == proto && !fun->hasSingletonType())
        1256          968291 :             clone->setType(fun->type());
        1257                 :     } else {
        1258                 :         /*
        1259                 :          * Across compartments we have to clone the script for interpreted
        1260                 :          * functions.
        1261                 :          */
        1262            2369 :         if (clone->isInterpreted()) {
        1263            2369 :             JSScript *script = clone->script();
        1264            2369 :             JS_ASSERT(script);
        1265            2369 :             JS_ASSERT(script->compartment() == fun->compartment());
        1266            2369 :             JS_ASSERT(script->compartment() != cx->compartment);
        1267                 :
        1268            2369 :             clone->script().init(NULL);
        1269            2369 :             JSScript *cscript = CloneScript(cx, script);
        1270            2369 :             if (!cscript)
        1271               0 :                 return NULL;
        1272                 :
        1273            2369 :             cscript->globalObject = &clone->global();
        1274            2369 :             clone->setScript(cscript);
        1275            2369 :             if (!cscript->typeSetFunction(cx, clone))
        1276               0 :                 return NULL;
        1277                 :
        1278            2369 :             js_CallNewScriptHook(cx, clone->script(), clone);
        1279            2369 :             Debugger::onNewScript(cx, clone->script(), NULL);
        1280                 :         }
        1281                 :     }
        1282          971430 :     return clone;
        1283                 : }
        1284                 :
        1285                 : JSFunction *
        1286         5600397 : js_DefineFunction(JSContext *cx, HandleObject obj, jsid id, Native native,
        1287                 :                   unsigned nargs, unsigned attrs, AllocKind kind)
        1288                 : {
        1289        11200794 :     RootId idRoot(cx, &id);
        1290                 :
        1291                 :     PropertyOp gop;
        1292                 :     StrictPropertyOp sop;
        1293                 :
        1294        11200794 :     RootedVarFunction fun(cx);
        1295                 :
        1296         5600397 :     if (attrs & JSFUN_STUB_GSOPS) {
        1297                 :         /*
        1298                 :          * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
        1299                 :          * the defined property's attributes. This allows us to encode another,
        1300                 :          * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
        1301                 :          * for more on this.
        1302                 :          */
        1303         5505494 :         attrs &= ~JSFUN_STUB_GSOPS;
        1304         5505494 :         gop = JS_PropertyStub;
        1305         5505494 :         sop = JS_StrictPropertyStub;
        1306                 :     } else {
        1307           94903 :         gop = NULL;
        1308           94903 :         sop = NULL;
        1309                 :     }
        1310                 :
        1311                 :     fun = js_NewFunction(cx, NULL, native, nargs,
        1312                 :                          attrs & (JSFUN_FLAGS_MASK),
        1313                 :                          obj,
        1314         5600397 :                          JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL,
        1315         5600397 :                          kind);
        1316         5600397 :     if (!fun)
        1317               0 :         return NULL;
        1318                 :
        1319         5600397 :     if (!obj->defineGeneric(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK))
        1320               0 :         return NULL;
        1321                 :
        1322         5600397 :     return fun;
        1323                 : }
        1324                 :
        1325                 : JS_STATIC_ASSERT((JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK) == 0);
        1326                 :
        1327                 : JSFunction *
        1328            4519 : js_ValueToFunction(JSContext *cx, const Value *vp, unsigned flags)
        1329                 : {
        1330                 :     JSFunction *fun;
        1331            4519 :     if (!IsFunctionObject(*vp, &fun)) {
        1332            1809 :         js_ReportIsNotFunction(cx, vp, flags);
        1333            1809 :         return NULL;
        1334                 :     }
        1335            2710 :     return fun;
        1336                 : }
        1337                 :
        1338                 : JSObject *
        1339           21188 : js_ValueToCallableObject(JSContext *cx, Value *vp, unsigned flags)
        1340                 : {
        1341           21188 :     if (vp->isObject()) {
        1342           21188 :         JSObject *callable = &vp->toObject();
        1343           21188 :         if (callable->isCallable())
        1344           21179 :             return callable;
        1345                 :     }
        1346                 :
        1347               9 :     js_ReportIsNotFunction(cx, vp, flags);
        1348               9 :     return NULL;
        1349                 : }
        1350                 :
        1351                 : void
        1352            2593 : js_ReportIsNotFunction(JSContext *cx, const Value *vp, unsigned flags)
        1353                 : {
        1354            2593 :     const char *name = NULL, *source = NULL;
        1355            5186 :     AutoValueRooter tvr(cx);
        1356            2593 :     unsigned error = (flags & JSV2F_CONSTRUCT) ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
        1357                 :
        1358                 :     /*
        1359                 :      * We try to the print the code that produced vp if vp is a value in the
        1360                 :      * most recent interpreted stack frame. Note that additional values, not
        1361                 :      * directly produced by the script, may have been pushed onto the frame's
        1362                 :      * expression stack (e.g. by pushInvokeArgs) thereby incrementing sp past
        1363                 :      * the depth simulated by ReconstructPCStack.
        1364                 :      *
        1365                 :      * Conversely, values may have been popped from the stack in preparation
        1366                 :      * for a call (e.g., by SplatApplyArgs). Since we must pass an offset from
        1367                 :      * the top of the simulated stack to js_ReportValueError3, we do bounds
        1368                 :      * checking using the minimum of both the simulated and actual stack depth.
        1369                 :      */
        1370            2593 :     ptrdiff_t spindex = 0;
        1371                 :
        1372            2593 :     FrameRegsIter i(cx);
        1373            2593 :     if (!i.done()) {
        1374            2593 :         unsigned depth = js_ReconstructStackDepth(cx, i.fp()->script(), i.pc());
        1375            2593 :         Value *simsp = i.fp()->base() + depth;
        1376            2593 :         if (i.fp()->base() <= vp && vp < Min(simsp, i.sp()))
        1377             757 :             spindex = vp - simsp;
        1378                 :     }
        1379                 :
        1380            2593 :     if (!spindex)
        1381            1836 :         spindex = ((flags & JSV2F_SEARCH_STACK) ? JSDVG_SEARCH_STACK : JSDVG_IGNORE_STACK);
        1382                 :
        1383            2593 :     js_ReportValueError3(cx, error, spindex, *vp, NULL, name, source);
        1384            2593 : }

Generated by: LCOV version 1.7