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