LCOV - code coverage report
Current view: directory - js/src - jsfun.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 902 696 77.2 %
Date: 2012-06-02 Functions: 52 49 94.2 %

       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 "jsversion.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                 : #include "jsexn.h"
      70                 : 
      71                 : #include "frontend/BytecodeCompiler.h"
      72                 : #include "frontend/BytecodeEmitter.h"
      73                 : #include "frontend/TokenStream.h"
      74                 : #include "vm/Debugger.h"
      75                 : #include "vm/MethodGuard.h"
      76                 : #include "vm/ScopeObject.h"
      77                 : 
      78                 : #if JS_HAS_GENERATORS
      79                 : # include "jsiter.h"
      80                 : #endif
      81                 : 
      82                 : #if JS_HAS_XDR
      83                 : # include "jsxdrapi.h"
      84                 : #endif
      85                 : 
      86                 : #ifdef JS_METHODJIT
      87                 : #include "methodjit/MethodJIT.h"
      88                 : #endif
      89                 : 
      90                 : #include "jsatominlines.h"
      91                 : #include "jsfuninlines.h"
      92                 : #include "jsinferinlines.h"
      93                 : #include "jsobjinlines.h"
      94                 : #include "jsscriptinlines.h"
      95                 : #include "vm/ArgumentsObject-inl.h"
      96                 : #include "vm/ScopeObject-inl.h"
      97                 : #include "vm/Stack-inl.h"
      98                 : 
      99                 : using namespace mozilla;
     100                 : using namespace js;
     101                 : using namespace js::gc;
     102                 : using namespace js::types;
     103                 : 
     104                 : js::ArgumentsObject *
     105          620688 : ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee)
     106                 : {
     107          620688 :     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
     108                 : 
     109          620688 :     JSObject *proto = callee.global().getOrCreateObjectPrototype(cx);
     110          620688 :     if (!proto)
     111               0 :         return NULL;
     112                 : 
     113         1241376 :     RootedVarTypeObject type(cx);
     114                 : 
     115          620688 :     type = proto->getNewType(cx);
     116          620688 :     if (!type)
     117               0 :         return NULL;
     118                 : 
     119          620688 :     bool strict = callee.toFunction()->inStrictMode();
     120          620688 :     Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
     121                 : 
     122         1241376 :     RootedVarShape emptyArgumentsShape(cx);
     123                 :     emptyArgumentsShape =
     124                 :         EmptyShape::getInitialShape(cx, clasp, proto,
     125                 :                                     proto->getParent(), FINALIZE_KIND,
     126          620688 :                                     BaseShape::INDEXED);
     127          620688 :     if (!emptyArgumentsShape)
     128               0 :         return NULL;
     129                 : 
     130                 :     ArgumentsData *data = (ArgumentsData *)
     131          620688 :         cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
     132          620688 :     if (!data)
     133               0 :         return NULL;
     134                 : 
     135          620688 :     data->callee.init(ObjectValue(callee));
     136         2435195 :     for (HeapValue *vp = data->slots; vp != data->slots + argc; vp++)
     137         1814507 :         vp->init(UndefinedValue());
     138                 : 
     139                 :     /* We have everything needed to fill in the object, so make the object. */
     140          620688 :     JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL);
     141          620688 :     if (!obj)
     142               0 :         return NULL;
     143                 : 
     144          620688 :     ArgumentsObject &argsobj = obj->asArguments();
     145                 : 
     146          620688 :     JS_ASSERT(UINT32_MAX > (uint64_t(argc) << PACKED_BITS_COUNT));
     147          620688 :     argsobj.initInitialLength(argc);
     148          620688 :     argsobj.initData(data);
     149          620688 :     argsobj.setStackFrame(NULL);
     150                 : 
     151          620688 :     JS_ASSERT(argsobj.numFixedSlots() >= NormalArgumentsObject::RESERVED_SLOTS);
     152          620688 :     JS_ASSERT(argsobj.numFixedSlots() >= StrictArgumentsObject::RESERVED_SLOTS);
     153                 : 
     154          620688 :     return &argsobj;
     155                 : }
     156                 : 
     157                 : struct STATIC_SKIP_INFERENCE PutArg
     158                 : {
     159          620670 :     PutArg(JSCompartment *comp, HeapValue *dst) : dst(dst), compartment(comp) {}
     160                 :     HeapValue *dst;
     161                 :     JSCompartment *compartment;
     162         1814507 :     bool operator()(unsigned, Value *src) {
     163         1814507 :         JS_ASSERT(dst->isMagic(JS_ARGS_HOLE) || dst->isUndefined());
     164         1814507 :         if (!dst->isMagic(JS_ARGS_HOLE))
     165         1814156 :             dst->set(compartment, *src);
     166         1814507 :         ++dst;
     167         1814507 :         return true;
     168                 :     }
     169                 : };
     170                 : 
     171                 : ArgumentsObject *
     172          670300 : js_GetArgsObject(JSContext *cx, StackFrame *fp)
     173                 : {
     174                 :     /*
     175                 :      * Arguments and Call objects are owned by the enclosing non-eval function
     176                 :      * frame, thus any eval frames must be skipped before testing hasArgsObj.
     177                 :      */
     178          670300 :     JS_ASSERT(fp->isFunctionFrame());
     179         1340600 :     while (fp->isEvalInFunction())
     180               0 :         fp = fp->prev();
     181                 : 
     182                 :     /*
     183                 :      * Mark all functions which have ever had arguments objects constructed,
     184                 :      * which will prevent lazy arguments optimizations in the method JIT.
     185                 :      */
     186          670300 :     if (!fp->script()->createdArgs)
     187            3299 :         types::MarkArgumentsCreated(cx, fp->script());
     188                 : 
     189                 :     /* Create an arguments object for fp only if it lacks one. */
     190          670300 :     JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
     191          670300 :     if (fp->hasArgsObj())
     192           50143 :         return &fp->argsObj();
     193                 : 
     194          620157 :     ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee());
     195          620157 :     if (!argsobj)
     196               0 :         return argsobj;
     197                 : 
     198                 :     /*
     199                 :      * Strict mode functions have arguments objects that copy the initial
     200                 :      * actual parameter values.  It is the caller's responsibility to get the
     201                 :      * arguments object before any parameters are modified!  (The emitter
     202                 :      * ensures this by synthesizing an arguments access at the start of any
     203                 :      * strict mode function that contains an assignment to a parameter, or
     204                 :      * that calls eval.)  Non-strict mode arguments use the frame pointer to
     205                 :      * retrieve up-to-date parameter values.
     206                 :      */
     207          620157 :     if (argsobj->isStrictArguments())
     208           36267 :         fp->forEachCanonicalActualArg(PutArg(cx->compartment, argsobj->data()->slots));
     209                 :     else
     210          583890 :         argsobj->setStackFrame(fp);
     211                 : 
     212          620157 :     fp->setArgsObj(*argsobj);
     213          620157 :     return argsobj;
     214                 : }
     215                 : 
     216                 : void
     217          620130 : js_PutArgsObject(StackFrame *fp)
     218                 : {
     219          620130 :     ArgumentsObject &argsobj = fp->argsObj();
     220          620130 :     if (argsobj.isNormalArguments()) {
     221          583872 :         JS_ASSERT(argsobj.maybeStackFrame() == fp);
     222          583872 :         JSCompartment *comp = fp->scopeChain().compartment();
     223          583872 :         fp->forEachCanonicalActualArg(PutArg(comp, argsobj.data()->slots));
     224          583872 :         argsobj.setStackFrame(NULL);
     225                 :     } else {
     226           36258 :         JS_ASSERT(!argsobj.maybeStackFrame());
     227                 :     }
     228          620130 : }
     229                 : 
     230                 : static JSBool
     231             837 : args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     232                 : {
     233             837 :     ArgumentsObject &argsobj = obj->asArguments();
     234             837 :     if (JSID_IS_INT(id)) {
     235             405 :         unsigned arg = unsigned(JSID_TO_INT(id));
     236             405 :         if (arg < argsobj.initialLength())
     237             405 :             argsobj.setElement(arg, MagicValue(JS_ARGS_HOLE));
     238             432 :     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
     239             432 :         argsobj.markLengthOverridden();
     240               0 :     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) {
     241               0 :         argsobj.asNormalArguments().clearCallee();
     242                 :     }
     243             837 :     return true;
     244                 : }
     245                 : 
     246                 : static JSBool
     247            3117 : ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     248                 : {
     249            3117 :     if (!obj->isNormalArguments())
     250               0 :         return true;
     251                 : 
     252            3117 :     NormalArgumentsObject &argsobj = obj->asNormalArguments();
     253            3117 :     if (JSID_IS_INT(id)) {
     254                 :         /*
     255                 :          * arg can exceed the number of arguments if a script changed the
     256                 :          * prototype to point to another Arguments object with a bigger argc.
     257                 :          */
     258            1362 :         unsigned arg = unsigned(JSID_TO_INT(id));
     259            1362 :         if (arg < argsobj.initialLength()) {
     260            1362 :             JS_ASSERT(!argsobj.element(arg).isMagic(JS_ARGS_HOLE));
     261            1362 :             if (StackFrame *fp = argsobj.maybeStackFrame())
     262            1269 :                 *vp = fp->canonicalActualArg(arg);
     263                 :             else
     264              93 :                 *vp = argsobj.element(arg);
     265                 :         }
     266            1755 :     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
     267             240 :         if (!argsobj.hasOverriddenLength())
     268             240 :             vp->setInt32(argsobj.initialLength());
     269                 :     } else {
     270            1515 :         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
     271            1515 :         const Value &v = argsobj.callee();
     272            1515 :         if (!v.isMagic(JS_ARGS_HOLE))
     273            1515 :             *vp = v;
     274                 :     }
     275            3117 :     return true;
     276                 : }
     277                 : 
     278                 : static JSBool
     279             909 : ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
     280                 : {
     281             909 :     if (!obj->isNormalArguments())
     282               0 :         return true;
     283                 : 
     284             909 :     NormalArgumentsObject &argsobj = obj->asNormalArguments();
     285                 : 
     286             909 :     if (JSID_IS_INT(id)) {
     287             504 :         unsigned arg = unsigned(JSID_TO_INT(id));
     288             504 :         if (arg < argsobj.initialLength()) {
     289             504 :             if (StackFrame *fp = argsobj.maybeStackFrame()) {
     290             468 :                 JSScript *script = fp->functionScript();
     291             468 :                 if (script->usesArguments) {
     292             468 :                     if (arg < fp->numFormalArgs())
     293             297 :                         TypeScript::SetArgument(cx, script, arg, *vp);
     294             468 :                     fp->canonicalActualArg(arg) = *vp;
     295                 :                 }
     296             468 :                 return true;
     297                 :             }
     298                 :         }
     299                 :     } else {
     300             405 :         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
     301             405 :                   JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
     302                 :     }
     303                 : 
     304                 :     /*
     305                 :      * For simplicity we use delete/define to replace the property with one
     306                 :      * backed by the default Object getter and setter. Note that we rely on
     307                 :      * args_delProperty to clear the corresponding reserved slot so the GC can
     308                 :      * collect its value. Note also that we must define the property instead
     309                 :      * of setting it in case the user has changed the prototype to an object
     310                 :      * that has a setter for this id.
     311                 :      */
     312             882 :     AutoValueRooter tvr(cx);
     313             441 :     return js_DeleteGeneric(cx, &argsobj, id, tvr.addr(), false) &&
     314             441 :            js_DefineProperty(cx, &argsobj, id, vp, NULL, NULL, JSPROP_ENUMERATE);
     315                 : }
     316                 : 
     317                 : static JSBool
     318            8219 : args_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
     319                 :              JSObject **objp)
     320                 : {
     321            8219 :     *objp = NULL;
     322                 : 
     323            8219 :     NormalArgumentsObject &argsobj = obj->asNormalArguments();
     324                 : 
     325            8219 :     unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
     326            8219 :     if (JSID_IS_INT(id)) {
     327            6563 :         uint32_t arg = uint32_t(JSID_TO_INT(id));
     328            6563 :         if (arg >= argsobj.initialLength() || argsobj.element(arg).isMagic(JS_ARGS_HOLE))
     329            4896 :             return true;
     330                 : 
     331            1667 :         attrs |= JSPROP_ENUMERATE;
     332            1656 :     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
     333             661 :         if (argsobj.hasOverriddenLength())
     334              27 :             return true;
     335                 :     } else {
     336             995 :         if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom))
     337             362 :             return true;
     338                 : 
     339             633 :         if (argsobj.callee().isMagic(JS_ARGS_HOLE))
     340               0 :             return true;
     341                 :     }
     342                 : 
     343            2934 :     Value undef = UndefinedValue();
     344            2934 :     if (!js_DefineProperty(cx, &argsobj, id, &undef, ArgGetter, ArgSetter, attrs))
     345               0 :         return JS_FALSE;
     346                 : 
     347            2934 :     *objp = &argsobj;
     348            2934 :     return true;
     349                 : }
     350                 : 
     351                 : static JSBool
     352             180 : args_enumerate(JSContext *cx, JSObject *obj)
     353                 : {
     354             180 :     NormalArgumentsObject &argsobj = obj->asNormalArguments();
     355                 : 
     356                 :     /*
     357                 :      * Trigger reflection in args_resolve using a series of js_LookupProperty
     358                 :      * calls.
     359                 :      */
     360             180 :     int argc = int(argsobj.initialLength());
     361             540 :     for (int i = -2; i != argc; i++) {
     362                 :         jsid id = (i == -2)
     363             180 :                   ? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)
     364                 :                   : (i == -1)
     365             180 :                   ? ATOM_TO_JSID(cx->runtime->atomState.calleeAtom)
     366             720 :                   : INT_TO_JSID(i);
     367                 : 
     368                 :         JSObject *pobj;
     369                 :         JSProperty *prop;
     370             360 :         if (!js_LookupProperty(cx, &argsobj, id, &pobj, &prop))
     371               0 :             return false;
     372                 :     }
     373             180 :     return true;
     374                 : }
     375                 : 
     376                 : static JSBool
     377             337 : StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     378                 : {
     379             337 :     if (!obj->isStrictArguments())
     380               0 :         return true;
     381                 : 
     382             337 :     StrictArgumentsObject &argsobj = obj->asStrictArguments();
     383                 : 
     384             337 :     if (JSID_IS_INT(id)) {
     385                 :         /*
     386                 :          * arg can exceed the number of arguments if a script changed the
     387                 :          * prototype to point to another Arguments object with a bigger argc.
     388                 :          */
     389             206 :         unsigned arg = unsigned(JSID_TO_INT(id));
     390             206 :         if (arg < argsobj.initialLength()) {
     391             206 :             const Value &v = argsobj.element(arg);
     392             206 :             if (!v.isMagic(JS_ARGS_HOLE))
     393             206 :                 *vp = v;
     394                 :         }
     395                 :     } else {
     396             131 :         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
     397             131 :         if (!argsobj.hasOverriddenLength())
     398             131 :             vp->setInt32(argsobj.initialLength());
     399                 :     }
     400             337 :     return true;
     401                 : }
     402                 : 
     403                 : static JSBool
     404             279 : StrictArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
     405                 : {
     406             279 :     if (!obj->isStrictArguments())
     407               0 :         return true;
     408                 : 
     409             279 :     StrictArgumentsObject &argsobj = obj->asStrictArguments();
     410                 : 
     411             279 :     if (JSID_IS_INT(id)) {
     412             279 :         unsigned arg = unsigned(JSID_TO_INT(id));
     413             279 :         if (arg < argsobj.initialLength()) {
     414             279 :             argsobj.setElement(arg, *vp);
     415             279 :             return true;
     416                 :         }
     417                 :     } else {
     418               0 :         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
     419                 :     }
     420                 : 
     421                 :     /*
     422                 :      * For simplicity we use delete/set to replace the property with one
     423                 :      * backed by the default Object getter and setter. Note that we rely on
     424                 :      * args_delProperty to clear the corresponding reserved slot so the GC can
     425                 :      * collect its value.
     426                 :      */
     427               0 :     AutoValueRooter tvr(cx);
     428               0 :     return js_DeleteGeneric(cx, &argsobj, id, tvr.addr(), strict) &&
     429               0 :            js_SetPropertyHelper(cx, &argsobj, id, 0, vp, strict);
     430                 : }
     431                 : 
     432                 : static JSBool
     433            1206 : strictargs_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSObject **objp)
     434                 : {
     435            1206 :     *objp = NULL;
     436                 : 
     437            1206 :     StrictArgumentsObject &argsobj = obj->asStrictArguments();
     438                 : 
     439            1206 :     unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
     440            1206 :     PropertyOp getter = StrictArgGetter;
     441            1206 :     StrictPropertyOp setter = StrictArgSetter;
     442                 : 
     443            1206 :     if (JSID_IS_INT(id)) {
     444            1093 :         uint32_t arg = uint32_t(JSID_TO_INT(id));
     445            1093 :         if (arg >= argsobj.initialLength() || argsobj.element(arg).isMagic(JS_ARGS_HOLE))
     446             603 :             return true;
     447                 : 
     448             490 :         attrs |= JSPROP_ENUMERATE;
     449             113 :     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
     450             113 :         if (argsobj.hasOverriddenLength())
     451               0 :             return true;
     452                 :     } else {
     453               0 :         if (!JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom) &&
     454               0 :             !JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
     455               0 :             return true;
     456                 :         }
     457                 : 
     458               0 :         attrs = JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED;
     459               0 :         getter = CastAsPropertyOp(argsobj.global().getThrowTypeError());
     460               0 :         setter = CastAsStrictPropertyOp(argsobj.global().getThrowTypeError());
     461                 :     }
     462                 : 
     463             603 :     Value undef = UndefinedValue();
     464             603 :     if (!js_DefineProperty(cx, &argsobj, id, &undef, getter, setter, attrs))
     465               0 :         return false;
     466                 : 
     467             603 :     *objp = &argsobj;
     468             603 :     return true;
     469                 : }
     470                 : 
     471                 : static JSBool
     472               0 : strictargs_enumerate(JSContext *cx, JSObject *obj)
     473                 : {
     474               0 :     StrictArgumentsObject *argsobj = &obj->asStrictArguments();
     475                 : 
     476                 :     /*
     477                 :      * Trigger reflection in strictargs_resolve using a series of
     478                 :      * js_LookupProperty calls.
     479                 :      */
     480                 :     JSObject *pobj;
     481                 :     JSProperty *prop;
     482                 : 
     483                 :     // length
     484               0 :     if (!js_LookupProperty(cx, argsobj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop))
     485               0 :         return false;
     486                 : 
     487                 :     // callee
     488               0 :     if (!js_LookupProperty(cx, argsobj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop))
     489               0 :         return false;
     490                 : 
     491                 :     // caller
     492               0 :     if (!js_LookupProperty(cx, argsobj, ATOM_TO_JSID(cx->runtime->atomState.callerAtom), &pobj, &prop))
     493               0 :         return false;
     494                 : 
     495               0 :     for (uint32_t i = 0, argc = argsobj->initialLength(); i < argc; i++) {
     496               0 :         if (!js_LookupProperty(cx, argsobj, INT_TO_JSID(i), &pobj, &prop))
     497               0 :             return false;
     498                 :     }
     499                 : 
     500               0 :     return true;
     501                 : }
     502                 : 
     503                 : static void
     504          620688 : args_finalize(JSContext *cx, JSObject *obj)
     505                 : {
     506          620688 :     cx->free_(reinterpret_cast<void *>(obj->asArguments().data()));
     507          620688 : }
     508                 : 
     509                 : static void
     510            2859 : args_trace(JSTracer *trc, JSObject *obj)
     511                 : {
     512            2859 :     ArgumentsObject &argsobj = obj->asArguments();
     513            2859 :     ArgumentsData *data = argsobj.data();
     514            2859 :     MarkValue(trc, &data->callee, js_callee_str);
     515            2859 :     MarkValueRange(trc, argsobj.initialLength(), data->slots, js_arguments_str);
     516                 : 
     517                 :     /*
     518                 :      * If a generator's arguments or call object escapes, and the generator
     519                 :      * frame is not executing, the generator object needs to be marked because
     520                 :      * it is not otherwise reachable. An executing generator is rooted by its
     521                 :      * invocation.  To distinguish the two cases (which imply different access
     522                 :      * paths to the generator object), we use the JSFRAME_FLOATING_GENERATOR
     523                 :      * flag, which is only set on the StackFrame kept in the generator object's
     524                 :      * JSGenerator.
     525                 :      */
     526                 : #if JS_HAS_GENERATORS
     527            2859 :     StackFrame *fp = argsobj.maybeStackFrame();
     528            2859 :     if (fp && fp->isFloatingGenerator())
     529             386 :         MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object");
     530                 : #endif
     531            2859 : }
     532                 : 
     533                 : /*
     534                 :  * The classes below collaborate to lazily reflect and synchronize actual
     535                 :  * argument values, argument count, and callee function object stored in a
     536                 :  * StackFrame with their corresponding property values in the frame's
     537                 :  * arguments object.
     538                 :  */
     539                 : Class js::NormalArgumentsObjectClass = {
     540                 :     "Arguments",
     541                 :     JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS |
     542                 :     JSCLASS_HAS_RESERVED_SLOTS(NormalArgumentsObject::RESERVED_SLOTS) |
     543                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
     544                 :     JSCLASS_FOR_OF_ITERATION,
     545                 :     JS_PropertyStub,         /* addProperty */
     546                 :     args_delProperty,
     547                 :     JS_PropertyStub,         /* getProperty */
     548                 :     JS_StrictPropertyStub,   /* setProperty */
     549                 :     args_enumerate,
     550                 :     reinterpret_cast<JSResolveOp>(args_resolve),
     551                 :     JS_ConvertStub,
     552                 :     args_finalize,           /* finalize   */
     553                 :     NULL,                    /* checkAccess */
     554                 :     NULL,                    /* call        */
     555                 :     NULL,                    /* construct   */
     556                 :     NULL,                    /* hasInstance */
     557                 :     args_trace,
     558                 :     {
     559                 :         NULL,       /* equality    */
     560                 :         NULL,       /* outerObject */
     561                 :         NULL,       /* innerObject */
     562                 :         JS_ElementIteratorStub,
     563                 :         NULL,       /* unused      */
     564                 :         false,      /* isWrappedNative */
     565                 :     }
     566                 : };
     567                 : 
     568                 : /*
     569                 :  * Strict mode arguments is significantly less magical than non-strict mode
     570                 :  * arguments, so it is represented by a different class while sharing some
     571                 :  * functionality.
     572                 :  */
     573                 : Class js::StrictArgumentsObjectClass = {
     574                 :     "Arguments",
     575                 :     JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS |
     576                 :     JSCLASS_HAS_RESERVED_SLOTS(StrictArgumentsObject::RESERVED_SLOTS) |
     577                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_Object) |
     578                 :     JSCLASS_FOR_OF_ITERATION,
     579                 :     JS_PropertyStub,         /* addProperty */
     580                 :     args_delProperty,
     581                 :     JS_PropertyStub,         /* getProperty */
     582                 :     JS_StrictPropertyStub,   /* setProperty */
     583                 :     strictargs_enumerate,
     584                 :     reinterpret_cast<JSResolveOp>(strictargs_resolve),
     585                 :     JS_ConvertStub,
     586                 :     args_finalize,           /* finalize   */
     587                 :     NULL,                    /* checkAccess */
     588                 :     NULL,                    /* call        */
     589                 :     NULL,                    /* construct   */
     590                 :     NULL,                    /* hasInstance */
     591                 :     args_trace,
     592                 :     {
     593                 :         NULL,       /* equality    */
     594                 :         NULL,       /* outerObject */
     595                 :         NULL,       /* innerObject */
     596                 :         JS_ElementIteratorStub,
     597                 :         NULL,       /* unused      */
     598                 :         false,      /* isWrappedNative */
     599                 :     }
     600                 : };
     601                 : 
     602                 : bool
     603            5455 : StackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
     604                 : {
     605            5455 :     if (!isFunctionFrame()) {
     606             297 :         vp->setNull();
     607             297 :         return true;
     608                 :     }
     609                 : 
     610            5158 :     JSFunction *fun = this->callee().toFunction();
     611            5158 :     vp->setObject(*fun);
     612                 : 
     613                 :     /*
     614                 :      * Check for an escape attempt by a joined function object, which must go
     615                 :      * through the frame's |this| object's method read barrier for the method
     616                 :      * atom by which it was uniquely associated with a property.
     617                 :      */
     618            5158 :     const Value &thisv = functionThis();
     619            5158 :     if (thisv.isObject() && fun->methodAtom() && !fun->isClonedMethod()) {
     620               0 :         JSObject *thisp = &thisv.toObject();
     621               0 :         JSObject *first_barriered_thisp = NULL;
     622                 : 
     623               0 :         do {
     624                 :             /*
     625                 :              * While a non-native object is responsible for handling its
     626                 :              * entire prototype chain, notable non-natives including dense
     627                 :              * and typed arrays have native prototypes, so keep going.
     628                 :              */
     629               0 :             if (!thisp->isNative())
     630               0 :                 continue;
     631                 : 
     632               0 :             const Shape *shape = thisp->nativeLookup(cx, ATOM_TO_JSID(fun->methodAtom()));
     633               0 :             if (shape) {
     634                 :                 /*
     635                 :                  * Two cases follow: the method barrier was not crossed
     636                 :                  * yet, so we cross it here; the method barrier *was*
     637                 :                  * crossed but after the call, in which case we fetch
     638                 :                  * and validate the cloned (unjoined) funobj from the
     639                 :                  * method property's slot.
     640                 :                  *
     641                 :                  * In either case we must allow for the method property
     642                 :                  * to have been replaced, or its value overwritten.
     643                 :                  */
     644               0 :                 if (shape->isMethod() && thisp->nativeGetMethod(shape) == fun) {
     645               0 :                     if (!thisp->methodReadBarrier(cx, *shape, vp))
     646               0 :                         return false;
     647               0 :                     overwriteCallee(vp->toObject());
     648               0 :                     return true;
     649                 :                 }
     650                 : 
     651               0 :                 if (shape->hasSlot()) {
     652               0 :                     Value v = thisp->getSlot(shape->slot());
     653                 :                     JSFunction *clone;
     654                 : 
     655               0 :                     if (IsFunctionObject(v, &clone) &&
     656               0 :                         clone->isInterpreted() &&
     657               0 :                         clone->script() == fun->script() &&
     658               0 :                         clone->methodObj() == thisp) {
     659                 :                         /*
     660                 :                          * N.B. If the method barrier was on a function
     661                 :                          * with singleton type, then while crossing the
     662                 :                          * method barrier CloneFunctionObject will have
     663                 :                          * ignored the attempt to clone the function.
     664                 :                          */
     665               0 :                         JS_ASSERT_IF(!clone->hasSingletonType(), clone != fun);
     666               0 :                         *vp = v;
     667               0 :                         overwriteCallee(*clone);
     668               0 :                         return true;
     669                 :                     }
     670                 :                 }
     671                 :             }
     672                 : 
     673               0 :             if (!first_barriered_thisp)
     674               0 :                 first_barriered_thisp = thisp;
     675               0 :         } while ((thisp = thisp->getProto()) != NULL);
     676                 : 
     677               0 :         if (!first_barriered_thisp)
     678               0 :             return true;
     679                 : 
     680                 :         /*
     681                 :          * At this point, we couldn't find an already-existing clone (or
     682                 :          * force to exist a fresh clone) created via thisp's method read
     683                 :          * barrier, so we must clone fun and store it in fp's callee to
     684                 :          * avoid re-cloning upon repeated foo.caller access.
     685                 :          *
     686                 :          * This must mean the code in js_DeleteGeneric could not find this
     687                 :          * stack frame on the stack when the method was deleted. We've lost
     688                 :          * track of the method, so we associate it with the first barriered
     689                 :          * object found starting from thisp on the prototype chain.
     690                 :          */
     691               0 :         JSFunction *newfunobj = CloneFunctionObject(cx, fun);
     692               0 :         if (!newfunobj)
     693               0 :             return false;
     694               0 :         newfunobj->setMethodObj(*first_barriered_thisp);
     695               0 :         overwriteCallee(*newfunobj);
     696               0 :         vp->setObject(*newfunobj);
     697               0 :         return true;
     698                 :     }
     699                 : 
     700            5158 :     return true;
     701                 : }
     702                 : 
     703                 : static JSBool
     704            1942 : fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     705                 : {
     706            3884 :     while (!obj->isFunction()) {
     707               0 :         obj = obj->getProto();
     708               0 :         if (!obj)
     709               0 :             return true;
     710                 :     }
     711            1942 :     JSFunction *fun = obj->toFunction();
     712                 : 
     713                 :     /*
     714                 :      * Mark the function's script as uninlineable, to expand any of its
     715                 :      * frames on the stack before we go looking for them. This allows the
     716                 :      * below walk to only check each explicit frame rather than needing to
     717                 :      * check any calls that were inlined.
     718                 :      */
     719            1942 :     if (fun->isInterpreted()) {
     720            1942 :         fun->script()->uninlineable = true;
     721            1942 :         MarkTypeObjectFlags(cx, fun, OBJECT_FLAG_UNINLINEABLE);
     722                 :     }
     723                 : 
     724                 :     /* Set to early to null in case of error */
     725            1942 :     vp->setNull();
     726                 : 
     727                 :     /* Find fun's top-most activation record. */
     728            1942 :     StackFrame *fp = js_GetTopStackFrame(cx, FRAME_EXPAND_NONE);
     729            2185 :     for (; fp; fp = fp->prev()) {
     730            2111 :         if (!fp->isFunctionFrame() || fp->isEvalFrame())
     731              81 :             continue;
     732                 :         Value callee;
     733            2030 :         if (!fp->getValidCalleeObject(cx, &callee))
     734               0 :             return false;
     735            2030 :         if (&callee.toObject() == fun)
     736            1868 :             break;
     737                 :     }
     738            1942 :     if (!fp)
     739              74 :         return true;
     740                 : 
     741                 : #ifdef JS_METHODJIT
     742            1868 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom) && fp && fp->prev()) {
     743                 :         /*
     744                 :          * If the frame was called from within an inlined frame, mark the
     745                 :          * innermost function as uninlineable to expand its frame and allow us
     746                 :          * to recover its callee object.
     747                 :          */
     748                 :         JSInlinedSite *inlined;
     749            1337 :         jsbytecode *prevpc = fp->prev()->pcQuadratic(cx->stack, fp, &inlined);
     750            1337 :         if (inlined) {
     751               0 :             mjit::JITChunk *chunk = fp->prev()->jit()->chunk(prevpc);
     752               0 :             JSFunction *fun = chunk->inlineFrames()[inlined->inlineIndex].fun;
     753               0 :             fun->script()->uninlineable = true;
     754               0 :             MarkTypeObjectFlags(cx, fun, OBJECT_FLAG_UNINLINEABLE);
     755                 :         }
     756                 :     }
     757                 : #endif
     758                 : 
     759            1868 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.argumentsAtom)) {
     760                 :         /* Warn if strict about f.arguments or equivalent unqualified uses. */
     761             531 :         if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT, js_GetErrorMessage,
     762             531 :                                           NULL, JSMSG_DEPRECATED_USAGE, js_arguments_str)) {
     763               0 :             return false;
     764                 :         }
     765                 : 
     766                 :         /*
     767                 :          * Purposefully disconnect the returned arguments object from the frame
     768                 :          * by always creating a new copy that does not alias formal parameters.
     769                 :          * This allows function-local analysis to determine that formals are
     770                 :          * not aliased and generally simplifies arguments objects.
     771                 :          */
     772             531 :         ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee());
     773             531 :         if (!argsobj)
     774               0 :             return false;
     775                 : 
     776             531 :         fp->forEachCanonicalActualArg(PutArg(cx->compartment, argsobj->data()->slots));
     777             531 :         *vp = ObjectValue(*argsobj);
     778             531 :         return true;
     779                 :     }
     780                 : 
     781            1337 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.callerAtom)) {
     782            1337 :         if (!fp->prev())
     783               0 :             return true;
     784                 : 
     785            1337 :         StackFrame *frame = fp->prev();
     786            2674 :         while (frame && frame->isDummyFrame())
     787               0 :             frame = frame->prev();
     788                 : 
     789            1337 :         if (frame && !frame->getValidCalleeObject(cx, vp))
     790               0 :             return false;
     791                 : 
     792            1337 :         if (!vp->isObject()) {
     793             297 :             JS_ASSERT(vp->isNull());
     794             297 :             return true;
     795                 :         }
     796                 : 
     797                 :         /* Censor the caller if it is from another compartment. */
     798            1040 :         JSObject &caller = vp->toObject();
     799            1040 :         if (caller.compartment() != cx->compartment) {
     800               0 :             vp->setNull();
     801            1040 :         } else if (caller.isFunction()) {
     802            1040 :             JSFunction *callerFun = caller.toFunction();
     803            1040 :             if (callerFun->isInterpreted() && callerFun->inStrictMode()) {
     804                 :                 JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
     805               0 :                                              JSMSG_CALLER_IS_STRICT);
     806               0 :                 return false;
     807                 :             }
     808                 :         }
     809                 : 
     810            1040 :         return true;
     811                 :     }
     812                 : 
     813               0 :     JS_NOT_REACHED("fun_getProperty");
     814                 :     return false;
     815                 : }
     816                 : 
     817                 : 
     818                 : 
     819                 : /* NB: no sentinels at ends -- use ArrayLength to bound loops.
     820                 :  * Properties censored into [[ThrowTypeError]] in strict mode. */
     821                 : static const uint16_t poisonPillProps[] = {
     822                 :     ATOM_OFFSET(arguments),
     823                 :     ATOM_OFFSET(caller),
     824                 : };
     825                 : 
     826                 : static JSBool
     827          249735 : fun_enumerate(JSContext *cx, JSObject *obj)
     828                 : {
     829          249735 :     JS_ASSERT(obj->isFunction());
     830                 : 
     831          499470 :     RootObject root(cx, &obj);
     832                 : 
     833                 :     jsid id;
     834                 :     bool found;
     835                 : 
     836          249735 :     if (!obj->isBoundFunction()) {
     837          249735 :         id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
     838          249735 :         if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
     839               0 :             return false;
     840                 :     }
     841                 : 
     842          249735 :     id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
     843          249735 :     if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
     844               0 :         return false;
     845                 :         
     846          249735 :     id = ATOM_TO_JSID(cx->runtime->atomState.nameAtom);
     847          249735 :     if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
     848               0 :         return false;
     849                 : 
     850          749205 :     for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
     851          499470 :         const uint16_t offset = poisonPillProps[i];
     852          499470 :         id = ATOM_TO_JSID(OFFSET_TO_ATOM(cx->runtime, offset));
     853          499470 :         if (!obj->hasProperty(cx, id, &found, JSRESOLVE_QUALIFIED))
     854               0 :             return false;
     855                 :     }
     856                 : 
     857          249735 :     return true;
     858                 : }
     859                 : 
     860                 : static JSObject *
     861           40694 : ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
     862                 : {
     863                 : #ifdef DEBUG
     864           40694 :     JSFunction *fun = obj->toFunction();
     865           40694 :     JS_ASSERT(fun->isInterpreted());
     866           40694 :     JS_ASSERT(!fun->isFunctionPrototype());
     867                 : #endif
     868                 : 
     869                 :     /*
     870                 :      * Assert that fun is not a compiler-created function object, which
     871                 :      * must never leak to script or embedding code and then be mutated.
     872                 :      * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
     873                 :      */
     874           40694 :     JS_ASSERT(!IsInternalFunctionObject(obj));
     875           40694 :     JS_ASSERT(!obj->isBoundFunction());
     876                 : 
     877                 :     /*
     878                 :      * Make the prototype object an instance of Object with the same parent
     879                 :      * as the function object itself.
     880                 :      */
     881           40694 :     JSObject *objProto = obj->global().getOrCreateObjectPrototype(cx);
     882           40694 :     if (!objProto)
     883               0 :         return NULL;
     884           40694 :     JSObject *proto = NewObjectWithGivenProto(cx, &ObjectClass, objProto, NULL);
     885           40694 :     if (!proto || !proto->setSingletonType(cx))
     886               0 :         return NULL;
     887                 : 
     888                 :     /*
     889                 :      * Per ES5 15.3.5.2 a user-defined function's .prototype property is
     890                 :      * initially non-configurable, non-enumerable, and writable.  Per ES5 13.2
     891                 :      * the prototype's .constructor property is configurable, non-enumerable,
     892                 :      * and writable.
     893                 :      */
     894           81388 :     if (!obj->defineProperty(cx, cx->runtime->atomState.classPrototypeAtom,
     895                 :                              ObjectValue(*proto), JS_PropertyStub, JS_StrictPropertyStub,
     896           40694 :                              JSPROP_PERMANENT) ||
     897                 :         !proto->defineProperty(cx, cx->runtime->atomState.constructorAtom,
     898           40694 :                                ObjectValue(*obj), JS_PropertyStub, JS_StrictPropertyStub, 0))
     899                 :     {
     900               0 :        return NULL;
     901                 :     }
     902                 : 
     903           40694 :     return proto;
     904                 : }
     905                 : 
     906                 : static JSBool
     907         2036991 : fun_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
     908                 :             JSObject **objp)
     909                 : {
     910         2036991 :     if (!JSID_IS_ATOM(id))
     911            1484 :         return true;
     912                 : 
     913         4071014 :     RootedVarFunction fun(cx);
     914         2035507 :     fun = obj->toFunction();
     915                 : 
     916         2035507 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.classPrototypeAtom)) {
     917                 :         /*
     918                 :          * Native or "built-in" functions do not have a .prototype property per
     919                 :          * ECMA-262, or (Object.prototype, Function.prototype, etc.) have that
     920                 :          * property created eagerly.
     921                 :          *
     922                 :          * ES5 15.3.4: the non-native function object named Function.prototype
     923                 :          * does not have a .prototype property.
     924                 :          *
     925                 :          * ES5 15.3.4.5: bound functions don't have a prototype property. The
     926                 :          * isNative() test covers this case because bound functions are native
     927                 :          * functions by definition/construction.
     928                 :          */
     929          122091 :         if (fun->isNative() || fun->isFunctionPrototype())
     930           81397 :             return true;
     931                 : 
     932           40694 :         if (!ResolveInterpretedFunctionPrototype(cx, fun))
     933               0 :             return false;
     934           40694 :         *objp = fun;
     935           40694 :         return true;
     936                 :     }
     937                 : 
     938         3576269 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
     939         1662853 :         JSID_IS_ATOM(id, cx->runtime->atomState.nameAtom)) {
     940          501442 :         JS_ASSERT(!IsInternalFunctionObject(obj));
     941                 : 
     942                 :         Value v;
     943          501442 :         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
     944          250563 :             v.setInt32(fun->nargs);
     945                 :         else
     946          250879 :             v.setString(fun->atom ? fun->atom : cx->runtime->emptyString);
     947                 :         
     948          501442 :         if (!DefineNativeProperty(cx, fun, id, v, JS_PropertyStub, JS_StrictPropertyStub,
     949          501442 :                                   JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
     950               0 :             return false;
     951                 :         }
     952          501442 :         *objp = fun;
     953          501442 :         return true;
     954                 :     }
     955                 : 
     956         3487512 :     for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) {
     957         2574473 :         const uint16_t offset = poisonPillProps[i];
     958                 : 
     959         2574473 :         if (JSID_IS_ATOM(id, OFFSET_TO_ATOM(cx->runtime, offset))) {
     960          498935 :             JS_ASSERT(!IsInternalFunctionObject(fun));
     961                 : 
     962                 :             PropertyOp getter;
     963                 :             StrictPropertyOp setter;
     964          498935 :             unsigned attrs = JSPROP_PERMANENT;
     965          498935 :             if (fun->isInterpreted() ? fun->inStrictMode() : fun->isBoundFunction()) {
     966               0 :                 JSObject *throwTypeError = fun->global().getThrowTypeError();
     967                 : 
     968               0 :                 getter = CastAsPropertyOp(throwTypeError);
     969               0 :                 setter = CastAsStrictPropertyOp(throwTypeError);
     970               0 :                 attrs |= JSPROP_GETTER | JSPROP_SETTER;
     971                 :             } else {
     972          498935 :                 getter = fun_getProperty;
     973          498935 :                 setter = JS_StrictPropertyStub;
     974                 :             }
     975                 : 
     976          498935 :             if (!DefineNativeProperty(cx, fun, id, UndefinedValue(), getter, setter,
     977          498935 :                                       attrs, 0, 0)) {
     978               0 :                 return false;
     979                 :             }
     980          498935 :             *objp = fun;
     981          498935 :             return true;
     982                 :         }
     983                 :     }
     984                 : 
     985          913039 :     return true;
     986                 : }
     987                 : 
     988                 : #if JS_HAS_XDR
     989                 : 
     990                 : /* XXX store parent and proto, if defined */
     991                 : JSBool
     992          623626 : js::XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
     993                 : {
     994                 :     JSContext *cx;
     995                 :     JSFunction *fun;
     996                 :     uint32_t firstword;           /* flag telling whether fun->atom is non-null,
     997                 :                                    plus for fun->u.i.skipmin, fun->u.i.wrapper,
     998                 :                                    and 14 bits reserved for future use */
     999                 :     uint32_t flagsword;           /* word for argument count and fun->flags */
    1000                 : 
    1001          623626 :     cx = xdr->cx;
    1002                 :     JSScript *script;
    1003          623626 :     if (xdr->mode == JSXDR_ENCODE) {
    1004          449470 :         fun = (*objp)->toFunction();
    1005          449470 :         if (!fun->isInterpreted()) {
    1006               0 :             JSAutoByteString funNameBytes;
    1007               0 :             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
    1008                 :                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION,
    1009               0 :                                      name);
    1010                 :             }
    1011               0 :             return false;
    1012                 :         }
    1013          449470 :         firstword = !!fun->atom;
    1014          449470 :         flagsword = (fun->nargs << 16) | fun->flags;
    1015          449470 :         script = fun->script();
    1016                 :     } else {
    1017          348312 :         RootedVarObject parent(cx, NULL);
    1018          174156 :         fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, parent, NULL);
    1019          174156 :         if (!fun)
    1020               0 :             return false;
    1021          174156 :         if (!fun->clearParent(cx))
    1022               0 :             return false;
    1023          174156 :         if (!fun->clearType(cx))
    1024               0 :             return false;
    1025          348312 :         script = NULL;
    1026                 :     }
    1027                 : 
    1028          623626 :     if (!JS_XDRUint32(xdr, &firstword))
    1029               0 :         return false;
    1030          623626 :     if ((firstword & 1U) && !js_XDRAtom(xdr, &fun->atom))
    1031               0 :         return false;
    1032          623626 :     if (!JS_XDRUint32(xdr, &flagsword))
    1033               0 :         return false;
    1034                 : 
    1035          623626 :     if (!XDRScript(xdr, &script))
    1036               0 :         return false;
    1037                 : 
    1038          623626 :     if (xdr->mode == JSXDR_DECODE) {
    1039          174156 :         fun->nargs = flagsword >> 16;
    1040          174156 :         JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
    1041          174156 :         fun->flags = uint16_t(flagsword);
    1042          174156 :         fun->setScript(script);
    1043          174156 :         if (!script->typeSetFunction(cx, fun))
    1044               0 :             return false;
    1045          174156 :         JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
    1046          174156 :         js_CallNewScriptHook(cx, fun->script(), fun);
    1047          174156 :         *objp = fun;
    1048                 :     }
    1049                 : 
    1050          623626 :     return true;
    1051                 : }
    1052                 : 
    1053                 : #endif /* JS_HAS_XDR */
    1054                 : 
    1055                 : /*
    1056                 :  * [[HasInstance]] internal method for Function objects: fetch the .prototype
    1057                 :  * property of its 'this' parameter, and walks the prototype chain of v (only
    1058                 :  * if v is an object) returning true if .prototype is found.
    1059                 :  */
    1060                 : static JSBool
    1061         1060694 : fun_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
    1062                 : {
    1063         2121388 :     while (obj->isFunction()) {
    1064         1060694 :         if (!obj->isBoundFunction())
    1065         1060694 :             break;
    1066               0 :         obj = obj->toFunction()->getBoundFunctionTarget();
    1067                 :     }
    1068                 : 
    1069                 :     Value pval;
    1070         1060694 :     if (!obj->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &pval))
    1071               0 :         return JS_FALSE;
    1072                 : 
    1073         1060694 :     if (pval.isPrimitive()) {
    1074                 :         /*
    1075                 :          * Throw a runtime error if instanceof is called on a function that
    1076                 :          * has a non-object as its .prototype value.
    1077                 :          */
    1078               7 :         js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, ObjectValue(*obj), NULL);
    1079               7 :         return JS_FALSE;
    1080                 :     }
    1081                 : 
    1082         1060687 :     *bp = js_IsDelegate(cx, &pval.toObject(), *v);
    1083         1060687 :     return JS_TRUE;
    1084                 : }
    1085                 : 
    1086                 : inline void
    1087        42598904 : JSFunction::trace(JSTracer *trc)
    1088                 : {
    1089        42598904 :     if (isFlatClosure() && hasFlatClosureUpvars()) {
    1090         1442469 :         if (HeapValue *upvars = getFlatClosureUpvars())
    1091         1442469 :             MarkValueRange(trc, script()->bindings.countUpvars(), upvars, "upvars");
    1092                 :     }
    1093                 : 
    1094        42598904 :     if (isExtended()) {
    1095         6857965 :         MarkValueRange(trc, ArrayLength(toExtended()->extendedSlots),
    1096        13715930 :                        toExtended()->extendedSlots, "nativeReserved");
    1097                 :     }
    1098                 : 
    1099        42598904 :     if (atom)
    1100        34810200 :         MarkStringUnbarriered(trc, &atom, "atom");
    1101                 : 
    1102        42598904 :     if (isInterpreted()) {
    1103        13649237 :         if (u.i.script_)
    1104        13649237 :             MarkScriptUnbarriered(trc, &u.i.script_, "script");
    1105        13649237 :         if (u.i.env_)
    1106         7118894 :             MarkObjectUnbarriered(trc, &u.i.env_, "fun_callscope");
    1107                 :     }
    1108        42598904 : }
    1109                 : 
    1110                 : static void
    1111        42598904 : fun_trace(JSTracer *trc, JSObject *obj)
    1112                 : {
    1113        42598904 :     obj->toFunction()->trace(trc);
    1114        42598904 : }
    1115                 : 
    1116                 : static void
    1117        13871831 : fun_finalize(JSContext *cx, JSObject *obj)
    1118                 : {
    1119        13871831 :     if (obj->toFunction()->isFlatClosure())
    1120          684577 :         obj->toFunction()->finalizeUpvars();
    1121        13871831 : }
    1122                 : 
    1123                 : size_t
    1124           16046 : JSFunction::sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const
    1125                 : {
    1126           16884 :     return (isFlatClosure() && hasFlatClosureUpvars()) ?
    1127             439 :            mallocSizeOf(getFlatClosureUpvars()) :
    1128           17323 :            0;
    1129                 : }
    1130                 : 
    1131                 : /*
    1132                 :  * Reserve two slots in all function objects for XPConnect.  Note that this
    1133                 :  * does not bloat every instance, only those on which reserved slots are set,
    1134                 :  * and those on which ad-hoc properties are defined.
    1135                 :  */
    1136                 : JS_FRIEND_DATA(Class) js::FunctionClass = {
    1137                 :     js_Function_str,
    1138                 :     JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS |
    1139                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
    1140                 :     JS_PropertyStub,         /* addProperty */
    1141                 :     JS_PropertyStub,         /* delProperty */
    1142                 :     JS_PropertyStub,         /* getProperty */
    1143                 :     JS_StrictPropertyStub,   /* setProperty */
    1144                 :     fun_enumerate,
    1145                 :     (JSResolveOp)fun_resolve,
    1146                 :     JS_ConvertStub,
    1147                 :     fun_finalize,
    1148                 :     NULL,                    /* checkAccess */
    1149                 :     NULL,                    /* call        */
    1150                 :     NULL,                    /* construct   */
    1151                 :     fun_hasInstance,
    1152                 :     fun_trace
    1153                 : };
    1154                 : 
    1155                 : JSString *
    1156          270098 : fun_toStringHelper(JSContext *cx, JSObject *obj, unsigned indent)
    1157                 : {
    1158          270098 :     if (!obj->isFunction()) {
    1159               9 :         if (IsFunctionProxy(obj))
    1160               9 :             return Proxy::fun_toString(cx, obj, indent);
    1161                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
    1162                 :                              JSMSG_INCOMPATIBLE_PROTO,
    1163                 :                              js_Function_str, js_toString_str,
    1164               0 :                              "object");
    1165               0 :         return NULL;
    1166                 :     }
    1167                 : 
    1168          270089 :     JSFunction *fun = obj->toFunction();
    1169          270089 :     if (!fun)
    1170               0 :         return NULL;
    1171                 : 
    1172          270089 :     if (!indent && !cx->compartment->toSourceCache.empty()) {
    1173          258337 :         ToSourceCache::Ptr p = cx->compartment->toSourceCache.ref().lookup(fun);
    1174          258337 :         if (p)
    1175          257565 :             return p->value;
    1176                 :     }
    1177                 : 
    1178           12524 :     JSString *str = JS_DecompileFunction(cx, fun, indent);
    1179           12524 :     if (!str)
    1180               0 :         return NULL;
    1181                 : 
    1182           12524 :     if (!indent) {
    1183            1991 :         Maybe<ToSourceCache> &lazy = cx->compartment->toSourceCache;
    1184                 : 
    1185            1991 :         if (lazy.empty()) {
    1186            1219 :             lazy.construct();
    1187            1219 :             if (!lazy.ref().init())
    1188               0 :                 return NULL;
    1189                 :         }
    1190                 : 
    1191            1991 :         if (!lazy.ref().put(fun, str))
    1192               0 :             return NULL;
    1193                 :     }
    1194                 : 
    1195           12524 :     return str;
    1196                 : }
    1197                 : 
    1198                 : static JSBool
    1199          259556 : fun_toString(JSContext *cx, unsigned argc, Value *vp)
    1200                 : {
    1201          259556 :     JS_ASSERT(IsFunctionObject(vp[0]));
    1202          259556 :     uint32_t indent = 0;
    1203                 : 
    1204          259556 :     if (argc != 0 && !ToUint32(cx, vp[2], &indent))
    1205               0 :         return false;
    1206                 : 
    1207          259556 :     JSObject *obj = ToObject(cx, &vp[1]);
    1208          259556 :     if (!obj)
    1209               0 :         return false;
    1210                 : 
    1211          259556 :     JSString *str = fun_toStringHelper(cx, obj, indent);
    1212          259556 :     if (!str)
    1213               0 :         return false;
    1214                 : 
    1215          259556 :     vp->setString(str);
    1216          259556 :     return true;
    1217                 : }
    1218                 : 
    1219                 : #if JS_HAS_TOSOURCE
    1220                 : static JSBool
    1221           10533 : fun_toSource(JSContext *cx, unsigned argc, Value *vp)
    1222                 : {
    1223           10533 :     JS_ASSERT(IsFunctionObject(vp[0]));
    1224                 : 
    1225           10533 :     JSObject *obj = ToObject(cx, &vp[1]);
    1226           10533 :     if (!obj)
    1227               0 :         return false;
    1228                 : 
    1229           10533 :     JSString *str = fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT);
    1230           10533 :     if (!str)
    1231               0 :         return false;
    1232                 : 
    1233           10533 :     vp->setString(str);
    1234           10533 :     return true;
    1235                 : }
    1236                 : #endif
    1237                 : 
    1238                 : JSBool
    1239           77702 : js_fun_call(JSContext *cx, unsigned argc, Value *vp)
    1240                 : {
    1241           77702 :     Value fval = vp[1];
    1242                 : 
    1243           77702 :     if (!js_IsCallable(fval)) {
    1244              18 :         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &FunctionClass);
    1245              18 :         return false;
    1246                 :     }
    1247                 : 
    1248           77684 :     Value *argv = vp + 2;
    1249                 :     Value thisv;
    1250           77684 :     if (argc == 0) {
    1251             403 :         thisv.setUndefined();
    1252                 :     } else {
    1253           77281 :         thisv = argv[0];
    1254                 : 
    1255           77281 :         argc--;
    1256           77281 :         argv++;
    1257                 :     }
    1258                 : 
    1259                 :     /* Allocate stack space for fval, obj, and the args. */
    1260          155368 :     InvokeArgsGuard args;
    1261           77684 :     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
    1262               0 :         return JS_FALSE;
    1263                 : 
    1264                 :     /* Push fval, thisv, and the args. */
    1265           77684 :     args.calleev() = fval;
    1266           77684 :     args.thisv() = thisv;
    1267           77684 :     PodCopy(args.array(), argv, argc);
    1268                 : 
    1269           77684 :     bool ok = Invoke(cx, args);
    1270           77684 :     *vp = args.rval();
    1271           77684 :     return ok;
    1272                 : }
    1273                 : 
    1274                 : /* ES5 15.3.4.3 */
    1275                 : JSBool
    1276          529009 : js_fun_apply(JSContext *cx, unsigned argc, Value *vp)
    1277                 : {
    1278                 :     /* Step 1. */
    1279          529009 :     Value fval = vp[1];
    1280          529009 :     if (!js_IsCallable(fval)) {
    1281               8 :         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &FunctionClass);
    1282               8 :         return false;
    1283                 :     }
    1284                 : 
    1285                 :     /* Step 2. */
    1286          529001 :     if (argc < 2 || vp[3].isNullOrUndefined())
    1287            8250 :         return js_fun_call(cx, (argc > 0) ? 1 : 0, vp);
    1288                 : 
    1289                 :     /* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */
    1290                 : 
    1291                 :     /* Step 3. */
    1292          520751 :     if (!vp[3].isObject()) {
    1293               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str);
    1294               0 :         return false;
    1295                 :     }
    1296                 : 
    1297                 :     /*
    1298                 :      * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
    1299                 :      * original version of ES5).
    1300                 :      */
    1301          520751 :     JSObject *aobj = &vp[3].toObject();
    1302                 :     uint32_t length;
    1303          520751 :     if (!js_GetLengthProperty(cx, aobj, &length))
    1304               0 :         return false;
    1305                 : 
    1306                 :     /* Step 6. */
    1307          520751 :     if (length > StackSpace::ARGS_LENGTH_MAX) {
    1308              22 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
    1309              22 :         return false;
    1310                 :     }
    1311                 : 
    1312         1041458 :     InvokeArgsGuard args;
    1313          520729 :     if (!cx->stack.pushInvokeArgs(cx, length, &args))
    1314               0 :         return false;
    1315                 : 
    1316                 :     /* Push fval, obj, and aobj's elements as args. */
    1317          520729 :     args.calleev() = fval;
    1318          520729 :     args.thisv() = vp[2];
    1319                 : 
    1320                 :     /* Steps 7-8. */
    1321          520729 :     if (!GetElements(cx, aobj, length, args.array()))
    1322               0 :         return false;
    1323                 : 
    1324                 :     /* Step 9. */
    1325          520729 :     if (!Invoke(cx, args))
    1326            4290 :         return false;
    1327          516439 :     *vp = args.rval();
    1328          516439 :     return true;
    1329                 : }
    1330                 : 
    1331                 : namespace js {
    1332                 : 
    1333                 : JSBool
    1334                 : CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp);
    1335                 : 
    1336                 : }
    1337                 : 
    1338                 : static const uint32_t JSSLOT_BOUND_FUNCTION_THIS       = 0;
    1339                 : static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1;
    1340                 : 
    1341                 : static const uint32_t BOUND_FUNCTION_RESERVED_SLOTS = 2;
    1342                 : 
    1343                 : inline bool
    1344            5488 : JSFunction::initBoundFunction(JSContext *cx, const Value &thisArg,
    1345                 :                               const Value *args, unsigned argslen)
    1346                 : {
    1347            5488 :     JS_ASSERT(isFunction());
    1348                 : 
    1349                 :     /*
    1350                 :      * Convert to a dictionary to set the BOUND_FUNCTION flag and increase
    1351                 :      * the slot span to cover the arguments and additional slots for the 'this'
    1352                 :      * value and arguments count.
    1353                 :      */
    1354            5488 :     if (!toDictionaryMode(cx))
    1355               0 :         return false;
    1356                 : 
    1357            5488 :     if (!setFlag(cx, BaseShape::BOUND_FUNCTION))
    1358               0 :         return false;
    1359                 : 
    1360            5488 :     if (!setSlotSpan(cx, BOUND_FUNCTION_RESERVED_SLOTS + argslen))
    1361               0 :         return false;
    1362                 : 
    1363            5488 :     setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg);
    1364            5488 :     setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen));
    1365                 : 
    1366            5488 :     initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen);
    1367                 : 
    1368            5488 :     return true;
    1369                 : }
    1370                 : 
    1371                 : inline JSObject *
    1372            9515 : JSFunction::getBoundFunctionTarget() const
    1373                 : {
    1374            9515 :     JS_ASSERT(isFunction());
    1375            9515 :     JS_ASSERT(isBoundFunction());
    1376                 : 
    1377                 :     /* Bound functions abuse |parent| to store their target function. */
    1378            9515 :     return getParent();
    1379                 : }
    1380                 : 
    1381                 : inline const js::Value &
    1382            9515 : JSFunction::getBoundFunctionThis() const
    1383                 : {
    1384            9515 :     JS_ASSERT(isFunction());
    1385            9515 :     JS_ASSERT(isBoundFunction());
    1386                 : 
    1387            9515 :     return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
    1388                 : }
    1389                 : 
    1390                 : inline const js::Value &
    1391             802 : JSFunction::getBoundFunctionArgument(unsigned which) const
    1392                 : {
    1393             802 :     JS_ASSERT(isFunction());
    1394             802 :     JS_ASSERT(isBoundFunction());
    1395             802 :     JS_ASSERT(which < getBoundFunctionArgumentCount());
    1396                 : 
    1397             802 :     return getSlot(BOUND_FUNCTION_RESERVED_SLOTS + which);
    1398                 : }
    1399                 : 
    1400                 : inline size_t
    1401           10317 : JSFunction::getBoundFunctionArgumentCount() const
    1402                 : {
    1403           10317 :     JS_ASSERT(isFunction());
    1404           10317 :     JS_ASSERT(isBoundFunction());
    1405                 : 
    1406           10317 :     return getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
    1407                 : }
    1408                 : 
    1409                 : namespace js {
    1410                 : 
    1411                 : /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
    1412                 : JSBool
    1413            9515 : CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp)
    1414                 : {
    1415            9515 :     JSFunction *fun = vp[0].toObject().toFunction();
    1416            9515 :     JS_ASSERT(fun->isBoundFunction());
    1417                 : 
    1418            9515 :     bool constructing = IsConstructing(vp);
    1419                 : 
    1420                 :     /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
    1421            9515 :     unsigned argslen = fun->getBoundFunctionArgumentCount();
    1422                 : 
    1423            9515 :     if (argc + argslen > StackSpace::ARGS_LENGTH_MAX) {
    1424               0 :         js_ReportAllocationOverflow(cx);
    1425               0 :         return false;
    1426                 :     }
    1427                 : 
    1428                 :     /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
    1429            9515 :     JSObject *target = fun->getBoundFunctionTarget();
    1430                 : 
    1431                 :     /* 15.3.4.5.1 step 2. */
    1432            9515 :     const Value &boundThis = fun->getBoundFunctionThis();
    1433                 : 
    1434           19030 :     InvokeArgsGuard args;
    1435            9515 :     if (!cx->stack.pushInvokeArgs(cx, argc + argslen, &args))
    1436               0 :         return false;
    1437                 : 
    1438                 :     /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
    1439           10317 :     for (unsigned i = 0; i < argslen; i++)
    1440             802 :         args[i] = fun->getBoundFunctionArgument(i);
    1441            9515 :     PodCopy(args.array() + argslen, vp + 2, argc);
    1442                 : 
    1443                 :     /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
    1444            9515 :     args.calleev().setObject(*target);
    1445                 : 
    1446            9515 :     if (!constructing)
    1447            9299 :         args.thisv() = boundThis;
    1448                 : 
    1449            9515 :     if (constructing ? !InvokeConstructor(cx, args) : !Invoke(cx, args))
    1450              14 :         return false;
    1451                 : 
    1452            9501 :     *vp = args.rval();
    1453            9501 :     return true;
    1454                 : }
    1455                 : 
    1456                 : }
    1457                 : 
    1458                 : #if JS_HAS_GENERATORS
    1459                 : static JSBool
    1460               0 : fun_isGenerator(JSContext *cx, unsigned argc, Value *vp)
    1461                 : {
    1462                 :     JSFunction *fun;
    1463               0 :     if (!IsFunctionObject(vp[1], &fun)) {
    1464               0 :         JS_SET_RVAL(cx, vp, BooleanValue(false));
    1465               0 :         return true;
    1466                 :     }
    1467                 : 
    1468               0 :     bool result = false;
    1469               0 :     if (fun->isInterpreted()) {
    1470               0 :         JSScript *script = fun->script();
    1471               0 :         JS_ASSERT(script->length != 0);
    1472               0 :         result = script->code[0] == JSOP_GENERATOR;
    1473                 :     }
    1474                 : 
    1475               0 :     JS_SET_RVAL(cx, vp, BooleanValue(result));
    1476               0 :     return true;
    1477                 : }
    1478                 : #endif
    1479                 : 
    1480                 : /* ES5 15.3.4.5. */
    1481                 : static JSBool
    1482            5488 : fun_bind(JSContext *cx, unsigned argc, Value *vp)
    1483                 : {
    1484            5488 :     CallArgs args = CallArgsFromVp(argc, vp);
    1485                 : 
    1486                 :     /* Step 1. */
    1487            5488 :     Value &thisv = args.thisv();
    1488                 : 
    1489                 :     /* Step 2. */
    1490            5488 :     if (!js_IsCallable(thisv)) {
    1491               0 :         ReportIncompatibleMethod(cx, args, &FunctionClass);
    1492               0 :         return false;
    1493                 :     }
    1494                 : 
    1495           10976 :     RootedVarObject target(cx);
    1496            5488 :     target = &thisv.toObject();
    1497                 : 
    1498                 :     /* Step 3. */
    1499            5488 :     Value *boundArgs = NULL;
    1500            5488 :     unsigned argslen = 0;
    1501            5488 :     if (args.length() > 1) {
    1502            2309 :         boundArgs = args.array() + 1;
    1503            2309 :         argslen = args.length() - 1;
    1504                 :     }
    1505                 : 
    1506                 :     /* Steps 15-16. */
    1507            5488 :     unsigned length = 0;
    1508            5488 :     if (target->isFunction()) {
    1509            5488 :         unsigned nargs = target->toFunction()->nargs;
    1510            5488 :         if (nargs > argslen)
    1511            1118 :             length = nargs - argslen;
    1512                 :     }
    1513                 : 
    1514                 :     /* Step 4-6, 10-11. */
    1515            5488 :     JSAtom *name = target->isFunction() ? target->toFunction()->atom : NULL;
    1516                 : 
    1517                 :     JSObject *funobj =
    1518                 :         js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length,
    1519            5488 :                        JSFUN_CONSTRUCTOR, target, name);
    1520            5488 :     if (!funobj)
    1521               0 :         return false;
    1522                 : 
    1523                 :     /* NB: Bound functions abuse |parent| to store their target. */
    1524            5488 :     if (!funobj->setParent(cx, target))
    1525               0 :         return false;
    1526                 : 
    1527                 :     /* Steps 7-9. */
    1528            5488 :     Value thisArg = args.length() >= 1 ? args[0] : UndefinedValue();
    1529            5488 :     if (!funobj->toFunction()->initBoundFunction(cx, thisArg, boundArgs, argslen))
    1530               0 :         return false;
    1531                 : 
    1532                 :     /* Steps 17, 19-21 are handled by fun_resolve. */
    1533                 :     /* Step 18 is the default for new functions. */
    1534                 : 
    1535                 :     /* Step 22. */
    1536            5488 :     args.rval().setObject(*funobj);
    1537            5488 :     return true;
    1538                 : }
    1539                 : 
    1540                 : /*
    1541                 :  * Report "malformed formal parameter" iff no illegal char or similar scanner
    1542                 :  * error was already reported.
    1543                 :  */
    1544                 : static bool
    1545               9 : OnBadFormal(JSContext *cx, TokenKind tt)
    1546                 : {
    1547               9 :     if (tt != TOK_ERROR)
    1548               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_FORMAL);
    1549                 :     else
    1550               9 :         JS_ASSERT(cx->isExceptionPending());
    1551               9 :     return false;
    1552                 : }
    1553                 : 
    1554                 : namespace js {
    1555                 : 
    1556                 : JSFunctionSpec function_methods[] = {
    1557                 : #if JS_HAS_TOSOURCE
    1558                 :     JS_FN(js_toSource_str,   fun_toSource,   0,0),
    1559                 : #endif
    1560                 :     JS_FN(js_toString_str,   fun_toString,   0,0),
    1561                 :     JS_FN(js_apply_str,      js_fun_apply,   2,0),
    1562                 :     JS_FN(js_call_str,       js_fun_call,    1,0),
    1563                 :     JS_FN("bind",            fun_bind,       1,0),
    1564                 : #if JS_HAS_GENERATORS
    1565                 :     JS_FN("isGenerator",     fun_isGenerator,0,0),
    1566                 : #endif
    1567                 :     JS_FS_END
    1568                 : };
    1569                 : 
    1570                 : JSBool
    1571           10414 : Function(JSContext *cx, unsigned argc, Value *vp)
    1572                 : {
    1573           10414 :     CallArgs args = CallArgsFromVp(argc, vp);
    1574                 : 
    1575                 :     /* Block this call if security callbacks forbid it. */
    1576           20828 :     RootedVar<GlobalObject*> global(cx);
    1577           10414 :     global = &args.callee().global();
    1578           10414 :     if (!global->isRuntimeCodeGenEnabled(cx)) {
    1579               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
    1580               0 :         return false;
    1581                 :     }
    1582                 : 
    1583           20828 :     Bindings bindings(cx);
    1584                 : 
    1585                 :     const char *filename;
    1586                 :     unsigned lineno;
    1587                 :     JSPrincipals *originPrincipals;
    1588           10414 :     CurrentScriptFileLineOrigin(cx, &filename, &lineno, &originPrincipals);
    1589           10414 :     JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
    1590                 : 
    1591           10414 :     unsigned n = args.length() ? args.length() - 1 : 0;
    1592           10414 :     if (n > 0) {
    1593                 :         /*
    1594                 :          * Collect the function-argument arguments into one string, separated
    1595                 :          * by commas, then make a tokenstream from that string, and scan it to
    1596                 :          * get the arguments.  We need to throw the full scanner at the
    1597                 :          * problem, because the argument string can legitimately contain
    1598                 :          * comments and linefeeds.  XXX It might be better to concatenate
    1599                 :          * everything up into a function definition and pass it to the
    1600                 :          * compiler, but doing it this way is less of a delta from the old
    1601                 :          * code.  See ECMA 15.3.2.1.
    1602                 :          */
    1603            4727 :         size_t args_length = 0;
    1604            9463 :         for (unsigned i = 0; i < n; i++) {
    1605                 :             /* Collect the lengths for all the function-argument arguments. */
    1606            4736 :             JSString *arg = ToString(cx, args[i]);
    1607            4736 :             if (!arg)
    1608               0 :                 return false;
    1609            4736 :             args[i].setString(arg);
    1610                 : 
    1611                 :             /*
    1612                 :              * Check for overflow.  The < test works because the maximum
    1613                 :              * JSString length fits in 2 fewer bits than size_t has.
    1614                 :              */
    1615            4736 :             size_t old_args_length = args_length;
    1616            4736 :             args_length = old_args_length + arg->length();
    1617            4736 :             if (args_length < old_args_length) {
    1618               0 :                 js_ReportAllocationOverflow(cx);
    1619               0 :                 return false;
    1620                 :             }
    1621                 :         }
    1622                 : 
    1623                 :         /* Add 1 for each joining comma and check for overflow (two ways). */
    1624            4727 :         size_t old_args_length = args_length;
    1625            4727 :         args_length = old_args_length + n - 1;
    1626            4727 :         if (args_length < old_args_length ||
    1627                 :             args_length >= ~(size_t)0 / sizeof(jschar)) {
    1628               0 :             js_ReportAllocationOverflow(cx);
    1629               0 :             return false;
    1630                 :         }
    1631                 : 
    1632                 :         /*
    1633                 :          * Allocate a string to hold the concatenated arguments, including room
    1634                 :          * for a terminating 0. Mark cx->tempLifeAlloc for later release, to
    1635                 :          * free collected_args and its tokenstream in one swoop.
    1636                 :          */
    1637            9454 :         LifoAllocScope las(&cx->tempLifoAlloc());
    1638            4727 :         jschar *cp = cx->tempLifoAlloc().newArray<jschar>(args_length + 1);
    1639            4727 :         if (!cp) {
    1640               0 :             js_ReportOutOfMemory(cx);
    1641               0 :             return false;
    1642                 :         }
    1643            4727 :         jschar *collected_args = cp;
    1644                 : 
    1645                 :         /*
    1646                 :          * Concatenate the arguments into the new string, separated by commas.
    1647                 :          */
    1648            9463 :         for (unsigned i = 0; i < n; i++) {
    1649            4736 :             JSString *arg = args[i].toString();
    1650            4736 :             size_t arg_length = arg->length();
    1651            4736 :             const jschar *arg_chars = arg->getChars(cx);
    1652            4736 :             if (!arg_chars)
    1653               0 :                 return false;
    1654            4736 :             (void) js_strncpy(cp, arg_chars, arg_length);
    1655            4736 :             cp += arg_length;
    1656                 : 
    1657                 :             /* Add separating comma or terminating 0. */
    1658            4736 :             *cp++ = (i + 1 < n) ? ',' : 0;
    1659                 :         }
    1660                 : 
    1661                 :         /* Initialize a tokenstream that reads from the given string. */
    1662            9454 :         TokenStream ts(cx, principals, originPrincipals);
    1663            4727 :         if (!ts.init(collected_args, args_length, filename, lineno, cx->findVersion()))
    1664               0 :             return false;
    1665                 : 
    1666                 :         /* The argument string may be empty or contain no tokens. */
    1667            4727 :         TokenKind tt = ts.getToken();
    1668            4727 :         if (tt != TOK_EOF) {
    1669              18 :             for (;;) {
    1670                 :                 /*
    1671                 :                  * Check that it's a name.  This also implicitly guards against
    1672                 :                  * TOK_ERROR, which was already reported.
    1673                 :                  */
    1674            4745 :                 if (tt != TOK_NAME)
    1675               9 :                     return OnBadFormal(cx, tt);
    1676                 : 
    1677                 :                 /* Check for a duplicate parameter name. */
    1678            4736 :                 PropertyName *name = ts.currentToken().name();
    1679            4736 :                 if (bindings.hasBinding(cx, name)) {
    1680               0 :                     JSAutoByteString bytes;
    1681               0 :                     if (!js_AtomToPrintableString(cx, name, &bytes))
    1682               0 :                         return false;
    1683               0 :                     if (!ReportCompileErrorNumber(cx, &ts, NULL,
    1684                 :                                                   JSREPORT_WARNING | JSREPORT_STRICT,
    1685               0 :                                                   JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
    1686                 :                     {
    1687               0 :                         return false;
    1688                 :                     }
    1689                 :                 }
    1690                 : 
    1691                 :                 uint16_t dummy;
    1692            4736 :                 if (!bindings.addArgument(cx, name, &dummy))
    1693               0 :                     return false;
    1694                 : 
    1695                 :                 /*
    1696                 :                  * Get the next token.  Stop on end of stream.  Otherwise
    1697                 :                  * insist on a comma, get another name, and iterate.
    1698                 :                  */
    1699            4736 :                 tt = ts.getToken();
    1700            4736 :                 if (tt == TOK_EOF)
    1701                 :                     break;
    1702              18 :                 if (tt != TOK_COMMA)
    1703               0 :                     return OnBadFormal(cx, tt);
    1704              18 :                 tt = ts.getToken();
    1705                 :             }
    1706                 :         }
    1707                 :     }
    1708                 : 
    1709           20810 :     JS::Anchor<JSString *> strAnchor(NULL);
    1710                 :     const jschar *chars;
    1711                 :     size_t length;
    1712                 : 
    1713           10405 :     if (args.length()) {
    1714           10198 :         JSString *str = ToString(cx, args[args.length() - 1]);
    1715           10198 :         if (!str)
    1716               0 :             return false;
    1717           10198 :         strAnchor.set(str);
    1718           10198 :         chars = str->getChars(cx);
    1719           10198 :         length = str->length();
    1720                 :     } else {
    1721             207 :         chars = cx->runtime->emptyString->chars();
    1722             207 :         length = 0;
    1723                 :     }
    1724                 : 
    1725                 :     /*
    1726                 :      * NB: (new Function) is not lexically closed by its caller, it's just an
    1727                 :      * anonymous function in the top-level scope that its constructor inhabits.
    1728                 :      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
    1729                 :      * and so would a call to f from another top-level's script or function.
    1730                 :      */
    1731                 :     JSFunction *fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
    1732           10405 :                                      global, cx->runtime->atomState.anonymousAtom);
    1733           10405 :     if (!fun)
    1734               0 :         return false;
    1735                 : 
    1736                 :     bool ok = frontend::CompileFunctionBody(cx, fun, principals, originPrincipals,
    1737                 :                                             &bindings, chars, length, filename, lineno,
    1738           10405 :                                             cx->findVersion());
    1739           10405 :     args.rval().setObject(*fun);
    1740           10405 :     return ok;
    1741                 : }
    1742                 : 
    1743                 : bool
    1744           10454 : IsBuiltinFunctionConstructor(JSFunction *fun)
    1745                 : {
    1746           10454 :     return fun->maybeNative() == Function;
    1747                 : }
    1748                 : 
    1749                 : const Shape *
    1750               0 : LookupInterpretedFunctionPrototype(JSContext *cx, JSObject *funobj)
    1751                 : {
    1752                 : #ifdef DEBUG
    1753               0 :     JSFunction *fun = funobj->toFunction();
    1754               0 :     JS_ASSERT(fun->isInterpreted());
    1755               0 :     JS_ASSERT(!fun->isFunctionPrototype());
    1756               0 :     JS_ASSERT(!funobj->isBoundFunction());
    1757                 : #endif
    1758                 : 
    1759               0 :     jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
    1760               0 :     const Shape *shape = funobj->nativeLookup(cx, id);
    1761               0 :     if (!shape) {
    1762               0 :         if (!ResolveInterpretedFunctionPrototype(cx, funobj))
    1763               0 :             return NULL;
    1764               0 :         shape = funobj->nativeLookup(cx, id);
    1765                 :     }
    1766               0 :     JS_ASSERT(!shape->configurable());
    1767               0 :     JS_ASSERT(shape->isDataDescriptor());
    1768               0 :     JS_ASSERT(shape->hasSlot());
    1769               0 :     JS_ASSERT(!shape->isMethod());
    1770               0 :     return shape;
    1771                 : }
    1772                 : 
    1773                 : } /* namespace js */
    1774                 : 
    1775                 : JSFunction *
    1776        11495510 : js_NewFunction(JSContext *cx, JSObject *funobj, Native native, unsigned nargs,
    1777                 :                unsigned flags, HandleObject parent, JSAtom *atom, js::gc::AllocKind kind)
    1778                 : {
    1779        11495510 :     JS_ASSERT(kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
    1780        11495510 :     JS_ASSERT(sizeof(JSFunction) <= gc::Arena::thingSize(JSFunction::FinalizeKind));
    1781        11495510 :     JS_ASSERT(sizeof(FunctionExtended) <= gc::Arena::thingSize(JSFunction::ExtendedFinalizeKind));
    1782                 : 
    1783                 :     JSFunction *fun;
    1784                 : 
    1785        11495510 :     if (funobj) {
    1786          115911 :         JS_ASSERT(funobj->isFunction());
    1787          115911 :         JS_ASSERT(funobj->getParent() == parent);
    1788                 :     } else {
    1789        11379599 :         funobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind);
    1790        11379599 :         if (!funobj)
    1791               0 :             return NULL;
    1792                 :     }
    1793        11495510 :     fun = static_cast<JSFunction *>(funobj);
    1794                 : 
    1795                 :     /* Initialize all function members. */
    1796        11495510 :     fun->nargs = uint16_t(nargs);
    1797        11495510 :     fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK);
    1798        11495510 :     if ((flags & JSFUN_KINDMASK) >= JSFUN_INTERPRETED) {
    1799         1204089 :         JS_ASSERT(!native);
    1800         1204089 :         fun->script().init(NULL);
    1801         1204089 :         fun->initEnvironment(parent);
    1802                 :     } else {
    1803        10291421 :         fun->u.n.clasp = NULL;
    1804        10291421 :         fun->u.n.native = native;
    1805        10291421 :         JS_ASSERT(fun->u.n.native);
    1806                 :     }
    1807        11495510 :     if (kind == JSFunction::ExtendedFinalizeKind) {
    1808         2696899 :         fun->flags |= JSFUN_EXTENDED;
    1809         2696899 :         fun->initializeExtended();
    1810                 :     }
    1811        11495510 :     fun->atom = atom;
    1812                 : 
    1813        11495510 :     if (native && !fun->setSingletonType(cx))
    1814               0 :         return NULL;
    1815                 : 
    1816        11495510 :     return fun;
    1817                 : }
    1818                 : 
    1819                 : JSFunction * JS_FASTCALL
    1820         2380496 : js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
    1821                 :                        JSObject *proto, gc::AllocKind kind)
    1822                 : {
    1823         2380496 :     JS_ASSERT(parent);
    1824         2380496 :     JS_ASSERT(proto);
    1825                 : 
    1826         2380496 :     JSObject *cloneobj = NewObjectWithClassProto(cx, &FunctionClass, NULL, SkipScopeParent(parent), kind);
    1827         2380496 :     if (!cloneobj)
    1828               0 :         return NULL;
    1829         2380496 :     JSFunction *clone = static_cast<JSFunction *>(cloneobj);
    1830                 : 
    1831         2380496 :     clone->nargs = fun->nargs;
    1832         2380496 :     clone->flags = fun->flags & ~JSFUN_EXTENDED;
    1833         2380496 :     if (fun->isInterpreted()) {
    1834         2380496 :         clone->initScript(fun->script());
    1835         2380496 :         clone->initEnvironment(parent);
    1836                 :     } else {
    1837               0 :         clone->u.n = fun->u.n;
    1838                 :     }
    1839         2380496 :     clone->atom = fun->atom;
    1840                 : 
    1841         2380496 :     if (kind == JSFunction::ExtendedFinalizeKind) {
    1842          572345 :         clone->flags |= JSFUN_EXTENDED;
    1843          572345 :         clone->initializeExtended();
    1844                 :     }
    1845                 : 
    1846         2380496 :     if (cx->compartment == fun->compartment()) {
    1847                 :         /*
    1848                 :          * We can use the same type as the original function provided that (a)
    1849                 :          * its prototype is correct, and (b) its type is not a singleton. The
    1850                 :          * first case will hold in all compileAndGo code, and the second case
    1851                 :          * will have been caught by CloneFunctionObject coming from function
    1852                 :          * definitions or read barriers, so will not get here.
    1853                 :          */
    1854         2378217 :         if (fun->getProto() == proto && !fun->hasSingletonType())
    1855          964555 :             clone->setType(fun->type());
    1856                 :     } else {
    1857                 :         /*
    1858                 :          * Across compartments we have to clone the script for interpreted
    1859                 :          * functions.
    1860                 :          */
    1861            2279 :         if (clone->isInterpreted()) {
    1862            2279 :             JSScript *script = clone->script();
    1863            2279 :             JS_ASSERT(script);
    1864            2279 :             JS_ASSERT(script->compartment() == fun->compartment());
    1865            2279 :             JS_ASSERT(script->compartment() != cx->compartment);
    1866                 : 
    1867            2279 :             clone->script().init(NULL);
    1868            2279 :             JSScript *cscript = CloneScript(cx, script);
    1869            2279 :             if (!cscript)
    1870               0 :                 return NULL;
    1871                 : 
    1872            2279 :             cscript->globalObject = &clone->global();
    1873            2279 :             clone->setScript(cscript);
    1874            2279 :             if (!cscript->typeSetFunction(cx, clone))
    1875               0 :                 return NULL;
    1876                 : 
    1877            2279 :             js_CallNewScriptHook(cx, clone->script(), clone);
    1878            2279 :             Debugger::onNewScript(cx, clone->script(), NULL);
    1879                 :         }
    1880                 :     }
    1881         2380496 :     return clone;
    1882                 : }
    1883                 : 
    1884                 : /*
    1885                 :  * Create a new flat closure, but don't initialize the imported upvar
    1886                 :  * values. The tracer calls this function and then initializes the upvar
    1887                 :  * slots on trace.
    1888                 :  */
    1889                 : JSFunction * JS_FASTCALL
    1890          572345 : js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
    1891                 : {
    1892          572345 :     JS_ASSERT(fun->isFlatClosure());
    1893          572345 :     JS_ASSERT(JSScript::isValidOffset(fun->script()->upvarsOffset) ==
    1894          572345 :               fun->script()->bindings.hasUpvars());
    1895         1716311 :     JS_ASSERT_IF(JSScript::isValidOffset(fun->script()->upvarsOffset),
    1896         1716311 :                  fun->script()->upvars()->length == fun->script()->bindings.countUpvars());
    1897                 : 
    1898          572345 :     JSFunction *closure = CloneFunctionObject(cx, fun, scopeChain, JSFunction::ExtendedFinalizeKind);
    1899          572345 :     if (!closure)
    1900               0 :         return closure;
    1901                 : 
    1902          572345 :     uint32_t nslots = fun->script()->bindings.countUpvars();
    1903          572345 :     if (nslots == 0)
    1904             362 :         return closure;
    1905                 : 
    1906          571983 :     HeapValue *data = (HeapValue *) cx->malloc_(nslots * sizeof(HeapValue));
    1907          571983 :     if (!data)
    1908               0 :         return NULL;
    1909                 : 
    1910          571983 :     closure->setExtendedSlot(JSFunction::FLAT_CLOSURE_UPVARS_SLOT, PrivateValue(data));
    1911          571983 :     return closure;
    1912                 : }
    1913                 : 
    1914                 : JSFunction *
    1915          572345 : js_NewFlatClosure(JSContext *cx, JSFunction *fun)
    1916                 : {
    1917                 :     /*
    1918                 :      * Flat closures cannot yet be partial, that is, all upvars must be copied,
    1919                 :      * or the closure won't be flattened. Therefore they do not need to search
    1920                 :      * enclosing scope objects via JSOP_NAME, etc.
    1921                 :      */
    1922          572345 :     JSObject *scopeChain = &cx->fp()->scopeChain();
    1923                 : 
    1924          572345 :     JSFunction *closure = js_AllocFlatClosure(cx, fun, scopeChain);
    1925          572345 :     if (!closure || !fun->script()->bindings.hasUpvars())
    1926             362 :         return closure;
    1927                 : 
    1928          571983 :     unsigned level = fun->script()->staticLevel;
    1929          571983 :     JSUpvarArray *uva = fun->script()->upvars();
    1930                 : 
    1931         1315975 :     for (uint32_t i = 0, n = uva->length; i < n; i++)
    1932          743992 :         closure->initFlatClosureUpvar(i, GetUpvar(cx, level, uva->vector[i]));
    1933                 : 
    1934          571983 :     return closure;
    1935                 : }
    1936                 : 
    1937                 : JSFunction *
    1938         7225446 : js_DefineFunction(JSContext *cx, HandleObject obj, jsid id, Native native,
    1939                 :                   unsigned nargs, unsigned attrs, AllocKind kind)
    1940                 : {
    1941        14450892 :     RootId idRoot(cx, &id);
    1942                 : 
    1943                 :     PropertyOp gop;
    1944                 :     StrictPropertyOp sop;
    1945                 : 
    1946        14450892 :     RootedVarFunction fun(cx);
    1947                 : 
    1948         7225446 :     if (attrs & JSFUN_STUB_GSOPS) {
    1949                 :         /*
    1950                 :          * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
    1951                 :          * the defined property's attributes. This allows us to encode another,
    1952                 :          * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
    1953                 :          * for more on this.
    1954                 :          */
    1955         6956876 :         attrs &= ~JSFUN_STUB_GSOPS;
    1956         6956876 :         gop = JS_PropertyStub;
    1957         6956876 :         sop = JS_StrictPropertyStub;
    1958                 :     } else {
    1959          268570 :         gop = NULL;
    1960          268570 :         sop = NULL;
    1961                 :     }
    1962                 : 
    1963                 :     fun = js_NewFunction(cx, NULL, native, nargs,
    1964                 :                          attrs & (JSFUN_FLAGS_MASK),
    1965                 :                          obj,
    1966         7225446 :                          JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL,
    1967         7225446 :                          kind);
    1968         7225446 :     if (!fun)
    1969               0 :         return NULL;
    1970                 : 
    1971         7225446 :     if (!obj->defineGeneric(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK))
    1972               0 :         return NULL;
    1973                 : 
    1974         7225446 :     return fun;
    1975                 : }
    1976                 : 
    1977                 : JS_STATIC_ASSERT((JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK) == 0);
    1978                 : 
    1979                 : JSFunction *
    1980            6436 : js_ValueToFunction(JSContext *cx, const Value *vp, unsigned flags)
    1981                 : {
    1982                 :     JSFunction *fun;
    1983            6436 :     if (!IsFunctionObject(*vp, &fun)) {
    1984            1809 :         js_ReportIsNotFunction(cx, vp, flags);
    1985            1809 :         return NULL;
    1986                 :     }
    1987            4627 :     return fun;
    1988                 : }
    1989                 : 
    1990                 : JSObject *
    1991          159871 : js_ValueToCallableObject(JSContext *cx, Value *vp, unsigned flags)
    1992                 : {
    1993          159871 :     if (vp->isObject()) {
    1994          159871 :         JSObject *callable = &vp->toObject();
    1995          159871 :         if (callable->isCallable())
    1996          159862 :             return callable;
    1997                 :     }
    1998                 : 
    1999               9 :     js_ReportIsNotFunction(cx, vp, flags);
    2000               9 :     return NULL;
    2001                 : }
    2002                 : 
    2003                 : void
    2004            2992 : js_ReportIsNotFunction(JSContext *cx, const Value *vp, unsigned flags)
    2005                 : {
    2006            2992 :     const char *name = NULL, *source = NULL;
    2007            5984 :     AutoValueRooter tvr(cx);
    2008            2992 :     unsigned error = (flags & JSV2F_CONSTRUCT) ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
    2009                 : 
    2010                 :     /*
    2011                 :      * We try to the print the code that produced vp if vp is a value in the
    2012                 :      * most recent interpreted stack frame. Note that additional values, not
    2013                 :      * directly produced by the script, may have been pushed onto the frame's
    2014                 :      * expression stack (e.g. by pushInvokeArgs) thereby incrementing sp past
    2015                 :      * the depth simulated by ReconstructPCStack.
    2016                 :      *
    2017                 :      * Conversely, values may have been popped from the stack in preparation
    2018                 :      * for a call (e.g., by SplatApplyArgs). Since we must pass an offset from
    2019                 :      * the top of the simulated stack to js_ReportValueError3, we do bounds
    2020                 :      * checking using the minimum of both the simulated and actual stack depth.
    2021                 :      */
    2022            2992 :     ptrdiff_t spindex = 0;
    2023                 : 
    2024            2992 :     FrameRegsIter i(cx);
    2025            2992 :     if (!i.done()) {
    2026            2992 :         unsigned depth = js_ReconstructStackDepth(cx, i.fp()->script(), i.pc());
    2027            2992 :         Value *simsp = i.fp()->base() + depth;
    2028            2992 :         if (i.fp()->base() <= vp && vp < Min(simsp, i.sp()))
    2029            1156 :             spindex = vp - simsp;
    2030                 :     }
    2031                 : 
    2032            2992 :     if (!spindex)
    2033            1836 :         spindex = ((flags & JSV2F_SEARCH_STACK) ? JSDVG_SEARCH_STACK : JSDVG_IGNORE_STACK);
    2034                 : 
    2035            2992 :     js_ReportValueError3(cx, error, spindex, *vp, NULL, name, source);
    2036            2992 : }

Generated by: LCOV version 1.7