LCOV - code coverage report
Current view: directory - js/src - jsscript.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 954 780 81.8 %
Date: 2012-04-07 Functions: 47 42 89.4 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=78:
       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                 :  *   Nick Fitzgerald <nfitzgerald@mozilla.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      30                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : /*
      43                 :  * JS script operations.
      44                 :  */
      45                 : 
      46                 : #include <string.h>
      47                 : #include "jstypes.h"
      48                 : #include "jsutil.h"
      49                 : #include "jscrashreport.h"
      50                 : #include "jsprf.h"
      51                 : #include "jsapi.h"
      52                 : #include "jsatom.h"
      53                 : #include "jscntxt.h"
      54                 : #include "jsversion.h"
      55                 : #include "jsdbgapi.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 "jsopcode.h"
      63                 : #include "jsscope.h"
      64                 : #include "jsscript.h"
      65                 : 
      66                 : #include "frontend/BytecodeEmitter.h"
      67                 : #include "frontend/Parser.h"
      68                 : #include "js/MemoryMetrics.h"
      69                 : #include "methodjit/MethodJIT.h"
      70                 : #include "methodjit/Retcon.h"
      71                 : #include "vm/Debugger.h"
      72                 : #include "vm/Xdr.h"
      73                 : 
      74                 : #include "jsinferinlines.h"
      75                 : #include "jsinterpinlines.h"
      76                 : #include "jsobjinlines.h"
      77                 : #include "jsscriptinlines.h"
      78                 : 
      79                 : using namespace js;
      80                 : using namespace js::gc;
      81                 : using namespace js::frontend;
      82                 : 
      83                 : namespace js {
      84                 : 
      85                 : BindingKind
      86          881766 : Bindings::lookup(JSContext *cx, JSAtom *name, unsigned *indexp) const
      87                 : {
      88          881766 :     if (!lastBinding)
      89           13328 :         return NONE;
      90                 : 
      91                 :     Shape **spp;
      92          868438 :     Shape *shape = Shape::search(cx, lastBinding, ATOM_TO_JSID(name), &spp);
      93          868438 :     if (!shape)
      94          827428 :         return NONE;
      95                 : 
      96           41010 :     if (indexp)
      97           41001 :         *indexp = shape->shortid();
      98                 : 
      99           41010 :     if (shape->getter() == CallObject::getArgOp)
     100            2488 :         return ARGUMENT;
     101                 : 
     102           38522 :     return shape->writable() ? VARIABLE : CONSTANT;
     103                 : }
     104                 : 
     105                 : bool
     106          355333 : Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
     107                 : {
     108          355333 :     if (!ensureShape(cx))
     109               0 :         return false;
     110                 : 
     111                 :     /*
     112                 :      * We still follow 10.2.3 of ES3 and make argument and variable properties
     113                 :      * of the Call objects enumerable. ES5 reformulated all of its Clause 10 to
     114                 :      * avoid objects as activations, something we should do too.
     115                 :      */
     116          355333 :     unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
     117                 : 
     118                 :     uint16_t *indexp;
     119                 :     PropertyOp getter;
     120                 :     StrictPropertyOp setter;
     121          355333 :     uint32_t slot = CallObject::RESERVED_SLOTS;
     122                 : 
     123          355333 :     if (kind == ARGUMENT) {
     124          229339 :         JS_ASSERT(nvars == 0);
     125          229339 :         indexp = &nargs;
     126          229339 :         getter = CallObject::getArgOp;
     127          229339 :         setter = CallObject::setArgOp;
     128          229339 :         slot += nargs;
     129                 :     } else {
     130          125994 :         JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
     131                 : 
     132          125994 :         indexp = &nvars;
     133          125994 :         getter = CallObject::getVarOp;
     134          125994 :         setter = CallObject::setVarOp;
     135          125994 :         if (kind == CONSTANT)
     136              63 :             attrs |= JSPROP_READONLY;
     137          125994 :         slot += nargs + nvars;
     138                 :     }
     139                 : 
     140          355333 :     if (*indexp == BINDING_COUNT_LIMIT) {
     141                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
     142                 :                              (kind == ARGUMENT)
     143                 :                              ? JSMSG_TOO_MANY_FUN_ARGS
     144               0 :                              : JSMSG_TOO_MANY_LOCALS);
     145               0 :         return false;
     146                 :     }
     147                 : 
     148                 :     jsid id;
     149          355333 :     if (!name) {
     150              81 :         JS_ASSERT(kind == ARGUMENT); /* destructuring */
     151              81 :         id = INT_TO_JSID(nargs);
     152                 :     } else {
     153          355252 :         id = ATOM_TO_JSID(name);
     154                 :     }
     155                 : 
     156          355333 :     StackBaseShape base(&CallClass, NULL, BaseShape::VAROBJ);
     157          355333 :     base.updateGetterSetter(attrs, getter, setter);
     158                 : 
     159          355333 :     UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base);
     160          355333 :     if (!nbase)
     161               0 :         return NULL;
     162                 : 
     163          355333 :     StackShape child(nbase, id, slot, 0, attrs, Shape::HAS_SHORTID, *indexp);
     164                 : 
     165                 :     /* Shapes in bindings cannot be dictionaries. */
     166          355333 :     Shape *shape = lastBinding->getChildBinding(cx, child);
     167          355333 :     if (!shape)
     168               0 :         return false;
     169                 : 
     170          355333 :     lastBinding = shape;
     171          355333 :     ++*indexp;
     172          355333 :     return true;
     173                 : }
     174                 : 
     175                 : Shape *
     176          745077 : Bindings::callObjectShape(JSContext *cx) const
     177                 : {
     178          745077 :     if (!hasDup())
     179          745068 :         return lastShape();
     180                 : 
     181                 :     /*
     182                 :      * Build a vector of non-duplicate properties in order from last added
     183                 :      * to first (i.e., the order we normally have iterate over Shapes). Choose
     184                 :      * the last added property in each set of dups.
     185                 :      */
     186              18 :     Vector<const Shape *> shapes(cx);
     187              18 :     HashSet<jsid> seen(cx);
     188               9 :     if (!seen.init())
     189               0 :         return NULL;
     190                 : 
     191              27 :     for (Shape::Range r = lastShape()->all(); !r.empty(); r.popFront()) {
     192              18 :         const Shape &s = r.front();
     193              36 :         HashSet<jsid>::AddPtr p = seen.lookupForAdd(s.propid());
     194              18 :         if (!p) {
     195               9 :             if (!seen.add(p, s.propid()))
     196               0 :                 return NULL;
     197               9 :             if (!shapes.append(&s))
     198               0 :                 return NULL;
     199                 :         }
     200                 :     }
     201                 : 
     202                 :     /*
     203                 :      * Now build the Shape without duplicate properties.
     204                 :      */
     205              18 :     RootedVarShape shape(cx);
     206               9 :     shape = initialShape(cx);
     207              18 :     for (int i = shapes.length() - 1; i >= 0; --i) {
     208               9 :         shape = shape->getChildBinding(cx, shapes[i]);
     209               9 :         if (!shape)
     210               0 :             return NULL;
     211                 :     }
     212                 : 
     213               9 :     return shape;
     214                 : }
     215                 : 
     216                 : bool
     217           15424 : Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
     218                 : {
     219           15424 :     JS_ASSERT(lastBinding);
     220           15424 :     JS_ASSERT(hasLocalNames());
     221                 : 
     222           15424 :     Vector<JSAtom *> &names = *namesp;
     223           15424 :     JS_ASSERT(names.empty());
     224                 : 
     225           15424 :     unsigned n = countLocalNames();
     226           15424 :     if (!names.growByUninitialized(n))
     227               0 :         return false;
     228                 : 
     229                 : #ifdef DEBUG
     230           15424 :     JSAtom * const POISON = reinterpret_cast<JSAtom *>(0xdeadbeef);
     231           34956 :     for (unsigned i = 0; i < n; i++)
     232           19532 :         names[i] = POISON;
     233                 : #endif
     234                 : 
     235           34956 :     for (Shape::Range r = lastBinding->all(); !r.empty(); r.popFront()) {
     236           19532 :         const Shape &shape = r.front();
     237           19532 :         unsigned index = uint16_t(shape.shortid());
     238                 : 
     239           19532 :         if (shape.getter() == CallObject::getArgOp) {
     240           15569 :             JS_ASSERT(index < nargs);
     241                 :         } else {
     242            3963 :             JS_ASSERT(index < nvars);
     243            3963 :             index += nargs;
     244                 :         }
     245                 : 
     246           19532 :         if (JSID_IS_ATOM(shape.propid())) {
     247           19487 :             names[index] = JSID_TO_ATOM(shape.propid());
     248                 :         } else {
     249              45 :             JS_ASSERT(JSID_IS_INT(shape.propid()));
     250              45 :             JS_ASSERT(shape.getter() == CallObject::getArgOp);
     251              45 :             names[index] = NULL;
     252                 :         }
     253                 :     }
     254                 : 
     255                 : #ifdef DEBUG
     256           34956 :     for (unsigned i = 0; i < n; i++)
     257           19532 :         JS_ASSERT(names[i] != POISON);
     258                 : #endif
     259                 : 
     260           15424 :     return true;
     261                 : }
     262                 : 
     263                 : const Shape *
     264               0 : Bindings::lastArgument() const
     265                 : {
     266               0 :     JS_ASSERT(lastBinding);
     267                 : 
     268               0 :     const js::Shape *shape = lastVariable();
     269               0 :     if (nvars > 0) {
     270               0 :         while (shape->previous() && shape->getter() != CallObject::getArgOp)
     271               0 :             shape = shape->previous();
     272                 :     }
     273               0 :     return shape;
     274                 : }
     275                 : 
     276                 : const Shape *
     277             414 : Bindings::lastVariable() const
     278                 : {
     279             414 :     JS_ASSERT(lastBinding);
     280             414 :     return lastBinding;
     281                 : }
     282                 : 
     283                 : void
     284          261506 : Bindings::makeImmutable()
     285                 : {
     286          261506 :     JS_ASSERT(lastBinding);
     287          261506 :     JS_ASSERT(!lastBinding->inDictionary());
     288          261506 : }
     289                 : 
     290                 : void
     291          152545 : Bindings::trace(JSTracer *trc)
     292                 : {
     293          152545 :     if (lastBinding)
     294          105151 :         MarkShape(trc, &lastBinding, "shape");
     295          152545 : }
     296                 : 
     297                 : } /* namespace js */
     298                 : 
     299                 : template<XDRMode mode>
     300                 : static bool
     301               0 : XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp)
     302                 : {
     303                 :     /*
     304                 :      * A script constant can be an arbitrary primitive value as they are used
     305                 :      * to implement JSOP_LOOKUPSWITCH. But they cannot be objects, see
     306                 :      * bug 407186.
     307                 :      */
     308                 :     enum ConstTag {
     309                 :         SCRIPT_INT     = 0,
     310                 :         SCRIPT_DOUBLE  = 1,
     311                 :         SCRIPT_STRING  = 2,
     312                 :         SCRIPT_TRUE    = 3,
     313                 :         SCRIPT_FALSE   = 4,
     314                 :         SCRIPT_NULL    = 5,
     315                 :         SCRIPT_VOID    = 6
     316                 :     };
     317                 : 
     318                 :     uint32_t tag;
     319                 :     if (mode == XDR_ENCODE) {
     320               0 :         if (vp->isInt32()) {
     321               0 :             tag = SCRIPT_INT;
     322               0 :         } else if (vp->isDouble()) {
     323               0 :             tag = SCRIPT_DOUBLE;
     324               0 :         } else if (vp->isString()) {
     325               0 :             tag = SCRIPT_STRING;
     326               0 :         } else if (vp->isTrue()) {
     327               0 :             tag = SCRIPT_TRUE;
     328               0 :         } else if (vp->isFalse()) {
     329               0 :             tag = SCRIPT_FALSE;
     330               0 :         } else if (vp->isNull()) {
     331               0 :             tag = SCRIPT_NULL;
     332                 :         } else {
     333               0 :             JS_ASSERT(vp->isUndefined());
     334               0 :             tag = SCRIPT_VOID;
     335                 :         }
     336                 :     }
     337                 : 
     338               0 :     if (!xdr->codeUint32(&tag))
     339               0 :         return false;
     340                 : 
     341               0 :     switch (tag) {
     342                 :       case SCRIPT_INT: {
     343                 :         uint32_t i;
     344                 :         if (mode == XDR_ENCODE)
     345               0 :             i = uint32_t(vp->toInt32());
     346               0 :         if (!xdr->codeUint32(&i))
     347               0 :             return JS_FALSE;
     348                 :         if (mode == XDR_DECODE)
     349               0 :             vp->init(Int32Value(int32_t(i)));
     350               0 :         break;
     351                 :       }
     352                 :       case SCRIPT_DOUBLE: {
     353                 :         double d;
     354                 :         if (mode == XDR_ENCODE)
     355               0 :             d = vp->toDouble();
     356               0 :         if (!xdr->codeDouble(&d))
     357               0 :             return false;
     358                 :         if (mode == XDR_DECODE)
     359               0 :             vp->init(DoubleValue(d));
     360               0 :         break;
     361                 :       }
     362                 :       case SCRIPT_STRING: {
     363                 :         JSString *str;
     364                 :         if (mode == XDR_ENCODE)
     365               0 :             str = vp->toString();
     366               0 :         if (!xdr->codeString(&str))
     367               0 :             return false;
     368                 :         if (mode == XDR_DECODE)
     369               0 :             vp->init(StringValue(str));
     370               0 :         break;
     371                 :       }
     372                 :       case SCRIPT_TRUE:
     373                 :         if (mode == XDR_DECODE)
     374               0 :             vp->init(BooleanValue(true));
     375               0 :         break;
     376                 :       case SCRIPT_FALSE:
     377                 :         if (mode == XDR_DECODE)
     378               0 :             vp->init(BooleanValue(false));
     379               0 :         break;
     380                 :       case SCRIPT_NULL:
     381                 :         if (mode == XDR_DECODE)
     382               0 :             vp->init(NullValue());
     383               0 :         break;
     384                 :       case SCRIPT_VOID:
     385                 :         if (mode == XDR_DECODE)
     386               0 :             vp->init(UndefinedValue());
     387               0 :         break;
     388                 :     }
     389               0 :     return true;
     390                 : }
     391                 : 
     392                 : template<XDRMode mode>
     393                 : bool
     394            4992 : js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
     395                 : {
     396                 :     enum ScriptBits {
     397                 :         NoScriptRval,
     398                 :         SavedCallerFun,
     399                 :         StrictModeCode,
     400                 :         UsesEval,
     401                 :         MayNeedArgsObj,
     402                 :         NeedsArgsObj,
     403                 :         OwnFilename,
     404                 :         ParentFilename
     405                 :     };
     406                 : 
     407                 :     uint32_t length, lineno, nslots;
     408                 :     uint32_t natoms, nsrcnotes, ntrynotes, nobjects, nregexps, nconsts, nClosedArgs, nClosedVars, i;
     409                 :     uint32_t prologLength, version;
     410            4992 :     uint32_t nTypeSets = 0;
     411            4992 :     uint32_t scriptBits = 0;
     412                 : 
     413            4992 :     JSContext *cx = xdr->cx();
     414                 :     JSScript *script;
     415            4992 :     nsrcnotes = ntrynotes = natoms = nobjects = nregexps = nconsts = nClosedArgs = nClosedVars = 0;
     416            4992 :     jssrcnote *notes = NULL;
     417                 : 
     418                 :     /* XDR arguments, local vars, and upvars. */
     419                 :     uint16_t nargs, nvars;
     420                 : #if defined(DEBUG) || defined(__GNUC__) /* quell GCC overwarning */
     421            4992 :     script = NULL;
     422            4992 :     nargs = nvars = Bindings::BINDING_COUNT_LIMIT;
     423                 : #endif
     424                 :     uint32_t argsVars;
     425                 :     if (mode == XDR_ENCODE) {
     426            2496 :         script = *scriptp;
     427            2496 :         JS_ASSERT_IF(parentScript, parentScript->compartment() == script->compartment());
     428                 :     
     429                 :         /* Should not XDR scripts optimized for a single global object. */
     430            2496 :         JS_ASSERT(!JSScript::isValidOffset(script->globalsOffset));
     431                 : 
     432            2496 :         nargs = script->bindings.countArgs();
     433            2496 :         nvars = script->bindings.countVars();
     434            2496 :         argsVars = (nargs << 16) | nvars;
     435                 :     }
     436            4992 :     if (!xdr->codeUint32(&argsVars))
     437               0 :         return false;
     438                 :     if (mode == XDR_DECODE) {
     439            2496 :         nargs = argsVars >> 16;
     440            2496 :         nvars = argsVars & 0xFFFF;
     441                 :     }
     442            4992 :     JS_ASSERT(nargs != Bindings::BINDING_COUNT_LIMIT);
     443            4992 :     JS_ASSERT(nvars != Bindings::BINDING_COUNT_LIMIT);
     444                 : 
     445            9984 :     Bindings bindings(cx);
     446            4992 :     uint32_t nameCount = nargs + nvars;
     447            4992 :     if (nameCount > 0) {
     448            9480 :         LifoAllocScope las(&cx->tempLifoAlloc());
     449                 : 
     450                 :         /*
     451                 :          * To xdr the names we prefix the names with a bitmap descriptor and
     452                 :          * then xdr the names as strings. For argument names (indexes below
     453                 :          * nargs) the corresponding bit in the bitmap is unset when the name
     454                 :          * is null. Such null names are not encoded or decoded. For variable
     455                 :          * names (indexes starting from nargs) bitmap's bit is set when the
     456                 :          * name is declared as const, not as ordinary var.
     457                 :          * */
     458            4740 :         unsigned bitmapLength = JS_HOWMANY(nameCount, JS_BITS_PER_UINT32);
     459            4740 :         uint32_t *bitmap = cx->tempLifoAlloc().newArray<uint32_t>(bitmapLength);
     460            4740 :         if (!bitmap) {
     461               0 :             js_ReportOutOfMemory(cx);
     462               0 :             return false;
     463                 :         }
     464                 : 
     465            9480 :         Vector<JSAtom *> names(cx);
     466                 :         if (mode == XDR_ENCODE) {
     467            2370 :             if (!script->bindings.getLocalNameArray(cx, &names))
     468               0 :                 return false;
     469            2370 :             PodZero(bitmap, bitmapLength);
     470            5337 :             for (unsigned i = 0; i < nameCount; i++) {
     471            2967 :                 if (i < nargs && names[i])
     472            2371 :                     bitmap[i >> JS_BITS_PER_UINT32_LOG2] |= JS_BIT(i & (JS_BITS_PER_UINT32 - 1));
     473                 :             }
     474                 :         }
     475            9480 :         for (unsigned i = 0; i < bitmapLength; ++i) {
     476            4740 :             if (!xdr->codeUint32(&bitmap[i]))
     477               0 :                 return false;
     478                 :         }
     479                 : 
     480           10674 :         for (unsigned i = 0; i < nameCount; i++) {
     481            5934 :             if (i < nargs &&
     482                 :                 !(bitmap[i >> JS_BITS_PER_UINT32_LOG2] & JS_BIT(i & (JS_BITS_PER_UINT32 - 1))))
     483                 :             {
     484                 :                 if (mode == XDR_DECODE) {
     485                 :                     uint16_t dummy;
     486               0 :                     if (!bindings.addDestructuring(cx, &dummy))
     487               0 :                         return false;
     488                 :                 } else {
     489               0 :                     JS_ASSERT(!names[i]);
     490                 :                 }
     491               0 :                 continue;
     492                 :             }
     493                 : 
     494                 :             JSAtom *name;
     495                 :             if (mode == XDR_ENCODE)
     496            2967 :                 name = names[i];
     497            5934 :             if (!XDRAtom(xdr, &name))
     498               0 :                 return false;
     499                 :             if (mode == XDR_DECODE) {
     500                 :                 BindingKind kind = (i < nargs)
     501                 :                                    ? ARGUMENT
     502                 :                                    : (bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
     503                 :                                       JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
     504                 :                                      ? CONSTANT
     505            2967 :                                      : VARIABLE);
     506            2967 :                 if (!bindings.add(cx, name, kind))
     507               0 :                     return false;
     508                 :             }
     509                 :         }
     510                 :     }
     511                 : 
     512                 :     if (mode == XDR_DECODE) {
     513            2496 :         if (!bindings.ensureShape(cx))
     514               0 :             return false;
     515            2496 :         bindings.makeImmutable();
     516                 :     }
     517                 : 
     518                 :     if (mode == XDR_ENCODE)
     519            2496 :         length = script->length;
     520            4992 :     if (!xdr->codeUint32(&length))
     521               0 :         return JS_FALSE;
     522                 : 
     523                 :     if (mode == XDR_ENCODE) {
     524            2496 :         prologLength = script->mainOffset;
     525            2496 :         JS_ASSERT(script->getVersion() != JSVERSION_UNKNOWN);
     526            2496 :         version = (uint32_t)script->getVersion() | (script->nfixed << 16);
     527            2496 :         lineno = script->lineno;
     528            2496 :         nslots = (uint32_t)script->nslots;
     529            2496 :         nslots = (uint32_t)((script->staticLevel << 16) | script->nslots);
     530            2496 :         natoms = script->natoms;
     531                 : 
     532            2496 :         notes = script->notes();
     533            2496 :         nsrcnotes = script->numNotes();
     534                 : 
     535            2496 :         if (JSScript::isValidOffset(script->constsOffset))
     536               0 :             nconsts = script->consts()->length;
     537            2496 :         if (JSScript::isValidOffset(script->objectsOffset))
     538            1942 :             nobjects = script->objects()->length;
     539            2496 :         if (JSScript::isValidOffset(script->regexpsOffset))
     540               0 :             nregexps = script->regexps()->length;
     541            2496 :         if (JSScript::isValidOffset(script->trynotesOffset))
     542             396 :             ntrynotes = script->trynotes()->length;
     543                 :         /* no globals when encoding;  see assertion above */
     544            2496 :         nClosedArgs = script->nClosedArgs();
     545            2496 :         nClosedVars = script->nClosedVars();
     546                 : 
     547            2496 :         nTypeSets = script->nTypeSets;
     548                 : 
     549            2496 :         if (script->noScriptRval)
     550               0 :             scriptBits |= (1 << NoScriptRval);
     551            2496 :         if (script->savedCallerFun)
     552               0 :             scriptBits |= (1 << SavedCallerFun);
     553            2496 :         if (script->strictModeCode)
     554              45 :             scriptBits |= (1 << StrictModeCode);
     555            2496 :         if (script->usesEval)
     556             506 :             scriptBits |= (1 << UsesEval);
     557            2496 :         if (script->mayNeedArgsObj()) {
     558             505 :             scriptBits |= (1 << MayNeedArgsObj);
     559                 :             /*
     560                 :              * In some cases, the front-end calls setNeedsArgsObj when the
     561                 :              * script definitely needsArgsObj; preserve this information which
     562                 :              * would otherwise be lost.
     563                 :              */
     564             505 :             if (script->analyzedArgsUsage() && script->needsArgsObj())
     565             505 :                 scriptBits |= (1 << NeedsArgsObj);
     566                 :         }
     567            2496 :         if (script->filename) {
     568            2496 :             scriptBits |= (parentScript && parentScript->filename == script->filename)
     569                 :                           ? (1 << ParentFilename)
     570                 :                           : (1 << OwnFilename);
     571                 :         }
     572                 : 
     573            2496 :         JS_ASSERT(!script->compileAndGo);
     574            2496 :         JS_ASSERT(!script->hasSingletons);
     575                 :     }
     576                 : 
     577            4992 :     if (!xdr->codeUint32(&prologLength))
     578               0 :         return JS_FALSE;
     579            4992 :     if (!xdr->codeUint32(&version))
     580               0 :         return JS_FALSE;
     581                 : 
     582                 :     /*
     583                 :      * To fuse allocations, we need srcnote, atom, objects, regexp, and trynote
     584                 :      * counts early.
     585                 :      */
     586            4992 :     if (!xdr->codeUint32(&natoms))
     587               0 :         return JS_FALSE;
     588            4992 :     if (!xdr->codeUint32(&nsrcnotes))
     589               0 :         return JS_FALSE;
     590            4992 :     if (!xdr->codeUint32(&ntrynotes))
     591               0 :         return JS_FALSE;
     592            4992 :     if (!xdr->codeUint32(&nobjects))
     593               0 :         return JS_FALSE;
     594            4992 :     if (!xdr->codeUint32(&nregexps))
     595               0 :         return JS_FALSE;
     596            4992 :     if (!xdr->codeUint32(&nconsts))
     597               0 :         return JS_FALSE;
     598            4992 :     if (!xdr->codeUint32(&nClosedArgs))
     599               0 :         return JS_FALSE;
     600            4992 :     if (!xdr->codeUint32(&nClosedVars))
     601               0 :         return JS_FALSE;
     602            4992 :     if (!xdr->codeUint32(&nTypeSets))
     603               0 :         return JS_FALSE;
     604            4992 :     if (!xdr->codeUint32(&scriptBits))
     605               0 :         return JS_FALSE;
     606                 : 
     607                 :     if (mode == XDR_DECODE) {
     608                 :         /* Note: version is packed into the 32b space with another 16b value. */
     609            2496 :         JSVersion version_ = JSVersion(version & JS_BITMASK(16));
     610            2496 :         JS_ASSERT((version_ & VersionFlags::FULL_MASK) == unsigned(version_));
     611            2496 :         script = JSScript::NewScript(cx, length, nsrcnotes, natoms, nobjects,
     612                 :                                      nregexps, ntrynotes, nconsts, 0, nClosedArgs,
     613                 :                                      nClosedVars, nTypeSets, version_);
     614            2496 :         if (!script)
     615               0 :             return JS_FALSE;
     616                 : 
     617            2496 :         script->bindings.transfer(cx, &bindings);
     618            2496 :         JS_ASSERT(!script->mainOffset);
     619            2496 :         script->mainOffset = prologLength;
     620            2496 :         script->nfixed = uint16_t(version >> 16);
     621                 : 
     622                 :         /* If we know nsrcnotes, we allocated space for notes in script. */
     623            2496 :         notes = script->notes();
     624            2496 :         *scriptp = script;
     625                 : 
     626            2496 :         if (scriptBits & (1 << NoScriptRval))
     627               0 :             script->noScriptRval = true;
     628            2496 :         if (scriptBits & (1 << SavedCallerFun))
     629               0 :             script->savedCallerFun = true;
     630            2496 :         if (scriptBits & (1 << StrictModeCode))
     631              45 :             script->strictModeCode = true;
     632            2496 :         if (scriptBits & (1 << UsesEval))
     633             506 :             script->usesEval = true;
     634            2496 :         if (scriptBits & (1 << MayNeedArgsObj)) {
     635             505 :             script->setMayNeedArgsObj();
     636             505 :             if (scriptBits & (1 << NeedsArgsObj))
     637             505 :                 script->setNeedsArgsObj(true);
     638                 :         } else {
     639            1991 :             JS_ASSERT(!(scriptBits & (1 << NeedsArgsObj)));
     640                 :         }
     641                 :     }
     642                 : 
     643                 :     JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
     644                 :     JS_STATIC_ASSERT(sizeof(jssrcnote) == 1);
     645            4992 :     if (!xdr->codeBytes(script->code, length) ||
     646                 :         !xdr->codeBytes(notes, nsrcnotes) ||
     647                 :         !xdr->codeUint32(&lineno) ||
     648                 :         !xdr->codeUint32(&nslots)) {
     649               0 :         return false;
     650                 :     }
     651                 : 
     652            4992 :     if (scriptBits & (1 << OwnFilename)) {
     653                 :         const char *filename;
     654                 :         if (mode == XDR_ENCODE)
     655            2496 :             filename = script->filename;
     656            4992 :         if (!xdr->codeCString(&filename))
     657               0 :             return false;
     658                 :         if (mode == XDR_DECODE) {
     659            2496 :             script->filename = SaveScriptFilename(cx, filename);
     660            2496 :             if (!script->filename)
     661               0 :                 return false;
     662                 :         }
     663               0 :     } else if (scriptBits & (1 << ParentFilename)) {
     664               0 :         JS_ASSERT(parentScript);
     665                 :         if (mode == XDR_DECODE)
     666               0 :             script->filename = parentScript->filename;
     667                 :     }
     668                 : 
     669                 :     if (mode == XDR_DECODE) {
     670            2496 :         script->lineno = lineno;
     671            2496 :         script->nslots = uint16_t(nslots);
     672            2496 :         script->staticLevel = uint16_t(nslots >> 16);
     673            2496 :         xdr->initScriptPrincipals(script);
     674                 :     }
     675                 : 
     676            8654 :     for (i = 0; i != natoms; ++i) {
     677            3662 :         if (!XDRAtom(xdr, &script->atoms[i]))
     678               0 :             return false;
     679                 :     }
     680                 : 
     681                 :     /*
     682                 :      * Here looping from 0-to-length to xdr objects is essential. It ensures
     683                 :      * that block objects from the script->objects array will be written and
     684                 :      * restored in the outer-to-inner order. js_XDRBlockObject relies on this
     685                 :      * to restore the parent chain.
     686                 :      */
     687            9724 :     for (i = 0; i != nobjects; ++i) {
     688            4732 :         HeapPtr<JSObject> *objp = &script->objects()->vector[i];
     689                 :         uint32_t isBlock;
     690                 :         if (mode == XDR_ENCODE) {
     691            2366 :             JSObject *obj = *objp;
     692            2366 :             JS_ASSERT(obj->isFunction() || obj->isStaticBlock());
     693            2366 :             isBlock = obj->isBlock() ? 1 : 0;
     694                 :         }
     695            4732 :         if (!xdr->codeUint32(&isBlock))
     696               0 :             return false;
     697            4732 :         if (isBlock == 0) {
     698             212 :             JSObject *tmp = *objp;
     699             212 :             if (!XDRInterpretedFunction(xdr, &tmp, parentScript))
     700               0 :                 return false;
     701             212 :             *objp = tmp;
     702                 :         } else {
     703            4520 :             JS_ASSERT(isBlock == 1);
     704            4520 :             StaticBlockObject *tmp = static_cast<StaticBlockObject *>(objp->get());
     705            4520 :             if (!XDRStaticBlockObject(xdr, script, &tmp))
     706               0 :                 return false;
     707            4520 :             *objp = tmp;
     708                 :         }
     709                 :     }
     710            4992 :     for (i = 0; i != nregexps; ++i) {
     711               0 :         if (!XDRScriptRegExpObject(xdr, &script->regexps()->vector[i]))
     712               0 :             return false;
     713                 :     }
     714            5012 :     for (i = 0; i != nClosedArgs; ++i) {
     715              20 :         if (!xdr->codeUint32(&script->closedArgs()->vector[i]))
     716               0 :             return false;
     717                 :     }
     718            4992 :     for (i = 0; i != nClosedVars; ++i) {
     719               0 :         if (!xdr->codeUint32(&script->closedVars()->vector[i]))
     720               0 :             return false;
     721                 :     }
     722                 : 
     723            4992 :     if (ntrynotes != 0) {
     724                 :         /*
     725                 :          * We combine tn->kind and tn->stackDepth when serializing as XDR is not
     726                 :          * efficient when serializing small integer types.
     727                 :          */
     728                 :         JSTryNote *tn, *tnfirst;
     729                 :         uint32_t kindAndDepth;
     730                 :         JS_STATIC_ASSERT(sizeof(tn->kind) == sizeof(uint8_t));
     731                 :         JS_STATIC_ASSERT(sizeof(tn->stackDepth) == sizeof(uint16_t));
     732                 : 
     733             792 :         tnfirst = script->trynotes()->vector;
     734             792 :         JS_ASSERT(script->trynotes()->length == ntrynotes);
     735             792 :         tn = tnfirst + ntrynotes;
     736             900 :         do {
     737             900 :             --tn;
     738                 :             if (mode == XDR_ENCODE) {
     739             450 :                 kindAndDepth = (uint32_t(tn->kind) << 16)
     740                 :                                | uint32_t(tn->stackDepth);
     741                 :             }
     742             900 :             if (!xdr->codeUint32(&kindAndDepth) ||
     743                 :                 !xdr->codeUint32(&tn->start) ||
     744                 :                 !xdr->codeUint32(&tn->length)) {
     745               0 :                 return false;
     746                 :             }
     747                 :             if (mode == XDR_DECODE) {
     748             450 :                 tn->kind = uint8_t(kindAndDepth >> 16);
     749             450 :                 tn->stackDepth = uint16_t(kindAndDepth);
     750                 :             }
     751                 :         } while (tn != tnfirst);
     752                 :     }
     753                 : 
     754            4992 :     if (nconsts) {
     755               0 :         HeapValue *vector = script->consts()->vector;
     756               0 :         for (i = 0; i != nconsts; ++i) {
     757               0 :             if (!XDRScriptConst(xdr, &vector[i]))
     758               0 :                 return false;
     759                 :         }
     760                 :     }
     761                 : 
     762                 :     if (mode == XDR_DECODE) {
     763            2496 :         if (cx->hasRunOption(JSOPTION_PCCOUNT))
     764               0 :             (void) script->initScriptCounts(cx);
     765            2496 :         *scriptp = script;
     766                 :     }
     767                 : 
     768            4992 :     return true;
     769                 : }
     770                 : 
     771                 : template bool
     772                 : js::XDRScript(XDRState<XDR_ENCODE> *xdr, JSScript **scriptp, JSScript *parentScript);
     773                 : 
     774                 : template bool
     775                 : js::XDRScript(XDRState<XDR_DECODE> *xdr, JSScript **scriptp, JSScript *parentScript);
     776                 : 
     777                 : bool
     778               0 : JSScript::initScriptCounts(JSContext *cx)
     779                 : {
     780               0 :     JS_ASSERT(!scriptCounts);
     781                 : 
     782               0 :     size_t n = 0;
     783                 : 
     784                 :     jsbytecode *pc, *next;
     785               0 :     for (pc = code; pc < code + length; pc = next) {
     786               0 :         n += PCCounts::numCounts(JSOp(*pc));
     787               0 :         next = pc + GetBytecodeLength(pc);
     788                 :     }
     789                 : 
     790               0 :     size_t bytes = (length * sizeof(PCCounts)) + (n * sizeof(double));
     791               0 :     char *cursor = (char *) cx->calloc_(bytes);
     792               0 :     if (!cursor)
     793               0 :         return false;
     794                 : 
     795               0 :     DebugOnly<char *> base = cursor;
     796                 : 
     797               0 :     scriptCounts.pcCountsVector = (PCCounts *) cursor;
     798               0 :     cursor += length * sizeof(PCCounts);
     799                 : 
     800               0 :     for (pc = code; pc < code + length; pc = next) {
     801               0 :         scriptCounts.pcCountsVector[pc - code].counts = (double *) cursor;
     802               0 :         size_t capacity = PCCounts::numCounts(JSOp(*pc));
     803                 : #ifdef DEBUG
     804               0 :         scriptCounts.pcCountsVector[pc - code].capacity = capacity;
     805                 : #endif
     806               0 :         cursor += capacity * sizeof(double);
     807               0 :         next = pc + GetBytecodeLength(pc);
     808                 :     }
     809                 : 
     810               0 :     JS_ASSERT(size_t(cursor - base) == bytes);
     811                 : 
     812                 :     /* Enable interrupts in any interpreter frames running on this script. */
     813                 :     InterpreterFrames *frames;
     814               0 :     for (frames = cx->runtime->interpreterFrames; frames; frames = frames->older)
     815               0 :         frames->enableInterruptsIfRunning(this);
     816                 : 
     817               0 :     return true;
     818                 : }
     819                 : 
     820                 : void
     821          285135 : JSScript::destroyScriptCounts(FreeOp *fop)
     822                 : {
     823          285135 :     if (scriptCounts) {
     824               0 :         fop->free_(scriptCounts.pcCountsVector);
     825               0 :         scriptCounts.pcCountsVector = NULL;
     826                 :     }
     827          285135 : }
     828                 : 
     829                 : /*
     830                 :  * Shared script filename management.
     831                 :  */
     832                 : 
     833                 : const char *
     834         6038588 : js::SaveScriptFilename(JSContext *cx, const char *filename)
     835                 : {
     836         6038588 :     JSCompartment *comp = cx->compartment;
     837                 : 
     838        12077176 :     ScriptFilenameTable::AddPtr p = comp->scriptFilenameTable.lookupForAdd(filename);
     839         6038588 :     if (!p) {
     840           61168 :         size_t size = offsetof(ScriptFilenameEntry, filename) + strlen(filename) + 1;
     841           61168 :         ScriptFilenameEntry *entry = (ScriptFilenameEntry *) cx->malloc_(size);
     842           61168 :         if (!entry)
     843               0 :             return NULL;
     844           61168 :         entry->marked = false;
     845           61168 :         strcpy(entry->filename, filename);
     846                 : 
     847           61168 :         if (!comp->scriptFilenameTable.add(p, entry)) {
     848               0 :             Foreground::free_(entry);
     849               0 :             JS_ReportOutOfMemory(cx);
     850               0 :             return NULL;
     851                 :         }
     852                 :     }
     853                 : 
     854         6038588 :     ScriptFilenameEntry *sfe = *p;
     855                 : #ifdef JSGC_INCREMENTAL
     856                 :     /*
     857                 :      * During the IGC we need to ensure that filename is marked whenever it is
     858                 :      * accessed even if the name was already in the table. At this point old
     859                 :      * scripts or exceptions pointing to the filename may no longer be
     860                 :      * reachable.
     861                 :      */
     862         6038588 :     if (comp->needsBarrier() && !sfe->marked)
     863              56 :         sfe->marked = true;
     864                 : #endif
     865                 : 
     866         6038588 :     return sfe->filename;
     867                 : }
     868                 : 
     869                 : /*
     870                 :  * Back up from a saved filename by its offset within its hash table entry.
     871                 :  */
     872                 : #define FILENAME_TO_SFE(fn) \
     873                 :     ((ScriptFilenameEntry *) ((fn) - offsetof(ScriptFilenameEntry, filename)))
     874                 : 
     875                 : void
     876           91458 : js::MarkScriptFilename(const char *filename)
     877                 : {
     878           91458 :     ScriptFilenameEntry *sfe = FILENAME_TO_SFE(filename);
     879           91458 :     sfe->marked = true;
     880           91458 : }
     881                 : 
     882                 : void
     883           83697 : js::SweepScriptFilenames(JSCompartment *comp)
     884                 : {
     885           83697 :     ScriptFilenameTable &table = comp->scriptFilenameTable;
     886          205926 :     for (ScriptFilenameTable::Enum e(table); !e.empty(); e.popFront()) {
     887          122229 :         ScriptFilenameEntry *entry = e.front();
     888          122229 :         if (entry->marked) {
     889           61103 :             entry->marked = false;
     890           61126 :         } else if (!comp->rt->gcKeepAtoms) {
     891           61112 :             Foreground::free_(entry);
     892           61112 :             e.removeFront();
     893                 :         }
     894                 :     }
     895           83697 : }
     896                 : 
     897                 : void
     898           41285 : js::FreeScriptFilenames(JSCompartment *comp)
     899                 : {
     900           41285 :     ScriptFilenameTable &table = comp->scriptFilenameTable;
     901           41341 :     for (ScriptFilenameTable::Enum e(table); !e.empty(); e.popFront())
     902              56 :         Foreground::free_(e.front());
     903                 : 
     904           41285 :     table.clear();
     905           41285 : }
     906                 : 
     907                 : /*
     908                 :  * JSScript::data has a complex, manually-controlled, memory layout.
     909                 :  *
     910                 :  * First are some optional array headers.  They are optional because they
     911                 :  * often aren't needed, i.e. the corresponding arrays often have zero elements.
     912                 :  * Each header has an offset in JSScript that indicates its location within
     913                 :  * |data|; that offset is INVALID_OFFSET if the array header is not present.
     914                 :  * Each header also has an accessor function in JSScript.
     915                 :  *
     916                 :  * Array type       Array elements  Offset            Accessor
     917                 :  * ----------       --------------  ------            --------
     918                 :  * JSConstArray     Consts          constsOffset      consts()
     919                 :  * JSObjectArray    Objects         objectsOffset     objects()
     920                 :  * JSObjectArray    Regexps         regexpsOffset     regexps()
     921                 :  * JSTryNoteArray   Try notes       tryNotesOffset    trynotes()
     922                 :  * GlobalSlotArray  Globals         globalsOffset     globals()
     923                 :  * ClosedSlotArray  ClosedArgs      closedArgsOffset  closedArgs()
     924                 :  * ClosedSlotArray  ClosedVars      closedVarsOffset  closedVars()
     925                 :  *
     926                 :  * Then are the elements of several arrays.  
     927                 :  * - Most of these arrays have headers listed above (if present).  For each of
     928                 :  *   these, the array pointer and the array length is stored in the header.  
     929                 :  * - The remaining arrays have pointers and lengths that are stored directly in
     930                 :  *   JSScript.  This is because, unlike the others, they are nearly always
     931                 :  *   non-zero length and so the optional-header space optimization isn't
     932                 :  *   worthwhile.
     933                 :  *
     934                 :  * Array elements   Pointed to by         Length
     935                 :  * --------------   -------------         ------
     936                 :  * Consts           consts()->vector      consts()->length
     937                 :  * Atoms            atoms                 natoms
     938                 :  * Objects          objects()->vector     objects()->length
     939                 :  * Regexps          regexps()->vector     regexps()->length
     940                 :  * Try notes        trynotes()->vector    trynotes()->length
     941                 :  * Globals          globals()->vector     globals()->length
     942                 :  * Closed args      closedArgs()->vector  closedArgs()->length
     943                 :  * Closed vars      closedVars()->vector  closedVars()->length
     944                 :  * Bytecodes        code                  length
     945                 :  * Source notes     notes()               numNotes() * sizeof(jssrcnote)  
     946                 :  *
     947                 :  * IMPORTANT: This layout has two key properties.
     948                 :  * - It ensures that everything has sufficient alignment;  in particular, the
     949                 :  *   consts() elements need jsval alignment.
     950                 :  * - It ensures there are no gaps between elements, which saves space and makes
     951                 :  *   manual layout easy.  In particular, in the second part, arrays with larger
     952                 :  *   elements precede arrays with smaller elements.
     953                 :  *
     954                 :  * The following static assertions check these properties.
     955                 :  */
     956                 : 
     957                 : #define KEEPS_JSVAL_ALIGNMENT(T) \
     958                 :     (JS_ALIGNMENT_OF(jsval) % JS_ALIGNMENT_OF(T) == 0 && \
     959                 :      sizeof(T) % sizeof(jsval) == 0)
     960                 : 
     961                 : #define HAS_JSVAL_ALIGNMENT(T) \
     962                 :     (JS_ALIGNMENT_OF(jsval) == JS_ALIGNMENT_OF(T) && \
     963                 :      sizeof(T) == sizeof(jsval))
     964                 : 
     965                 : #define NO_PADDING_BETWEEN_ENTRIES(T1, T2) \
     966                 :     (JS_ALIGNMENT_OF(T1) % JS_ALIGNMENT_OF(T2) == 0)
     967                 : 
     968                 : /*
     969                 :  * These assertions ensure that there is no padding between the array headers,
     970                 :  * and also that the consts() elements (which follow immediately afterward) are
     971                 :  * jsval-aligned.  (There is an assumption that |data| itself is jsval-aligned;
     972                 :  * we check this below).
     973                 :  */
     974                 : JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(JSConstArray));
     975                 : JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(JSObjectArray));     /* there are two of these */
     976                 : JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(JSTryNoteArray));
     977                 : JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(GlobalSlotArray));
     978                 : JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ClosedSlotArray));   /* there are two of these */
     979                 : 
     980                 : /* These assertions ensure there is no padding required between array elements. */
     981                 : JS_STATIC_ASSERT(HAS_JSVAL_ALIGNMENT(HeapValue));
     982                 : JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapValue, JSAtom *));
     983                 : JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(JSAtom *, HeapPtrObject));
     984                 : JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, HeapPtrObject));
     985                 : JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, JSTryNote));
     986                 : JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(JSTryNote, GlobalSlotArray::Entry));
     987                 : JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(GlobalSlotArray::Entry, uint32_t));
     988                 : JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(uint32_t, uint32_t));
     989                 : JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(uint32_t, jsbytecode));
     990                 : JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(jsbytecode, jssrcnote));
     991                 : 
     992                 : /*
     993                 :  * Check that uint8_t offsets is enough to reach any optional array allocated
     994                 :  * within |data|. For that we check that the maximum possible offset for the
     995                 :  * closedVars array -- the last optional array -- still fits in 1 byte and does
     996                 :  * not coincide with INVALID_OFFSET.
     997                 :  */
     998                 : JS_STATIC_ASSERT(sizeof(JSConstArray) +
     999                 :                  sizeof(JSObjectArray) +
    1000                 :                  sizeof(JSObjectArray) +
    1001                 :                  sizeof(JSTryNoteArray) +
    1002                 :                  sizeof(js::GlobalSlotArray) +
    1003                 :                  sizeof(js::ClosedSlotArray)
    1004                 :                  < JSScript::INVALID_OFFSET);
    1005                 : JS_STATIC_ASSERT(JSScript::INVALID_OFFSET <= 255);
    1006                 : 
    1007                 : JSScript *
    1008          285135 : JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
    1009                 :                     uint32_t nobjects, uint32_t nregexps,
    1010                 :                     uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals,
    1011                 :                     uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets, JSVersion version)
    1012                 : {
    1013          285135 :     size_t size = 0;
    1014                 : 
    1015          285135 :     if (nconsts != 0)
    1016            2774 :         size += sizeof(JSConstArray) + nconsts * sizeof(Value);
    1017          285135 :     size += sizeof(JSAtom *) * natoms;
    1018          285135 :     if (nobjects != 0)
    1019           85246 :         size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *);
    1020          285135 :     if (nregexps != 0)
    1021            1391 :         size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *);
    1022          285135 :     if (ntrynotes != 0)
    1023            7768 :         size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote);
    1024          285135 :     if (nglobals != 0)
    1025           12668 :         size += sizeof(GlobalSlotArray) + nglobals * sizeof(GlobalSlotArray::Entry);
    1026          285135 :     if (nClosedArgs != 0)
    1027            1307 :         size += sizeof(ClosedSlotArray) + nClosedArgs * sizeof(uint32_t);
    1028          285135 :     if (nClosedVars != 0)
    1029            2106 :         size += sizeof(ClosedSlotArray) + nClosedVars * sizeof(uint32_t);
    1030                 : 
    1031          285135 :     size += length * sizeof(jsbytecode);
    1032          285135 :     size += nsrcnotes * sizeof(jssrcnote);
    1033                 : 
    1034                 :     /*
    1035                 :      * We assume that calloc aligns on sizeof(Value) if the size we ask to
    1036                 :      * allocate divides sizeof(Value).
    1037                 :      */
    1038                 :     JS_STATIC_ASSERT(sizeof(Value) == sizeof(double));
    1039          285135 :     uint8_t *data = static_cast<uint8_t *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value))));
    1040          285135 :     if (!data)
    1041               0 :         return NULL;
    1042                 : 
    1043          285135 :     JSScript *script = js_NewGCScript(cx);
    1044          285135 :     if (!script) {
    1045               0 :         Foreground::free_(data);
    1046               0 :         return NULL;
    1047                 :     }
    1048                 : 
    1049          285135 :     PodZero(script);
    1050          285135 :     script->data  = data;
    1051          285135 :     script->length = length;
    1052          285135 :     script->version = version;
    1053          285135 :     new (&script->bindings) Bindings(cx);
    1054                 : 
    1055          285135 :     uint8_t *cursor = data;
    1056          285135 :     if (nconsts != 0) {
    1057            2774 :         script->constsOffset = uint8_t(cursor - data);
    1058            2774 :         cursor += sizeof(JSConstArray);
    1059                 :     } else {
    1060          282361 :         script->constsOffset = JSScript::INVALID_OFFSET;
    1061                 :     }
    1062          285135 :     if (nobjects != 0) {
    1063           85246 :         script->objectsOffset = uint8_t(cursor - data);
    1064           85246 :         cursor += sizeof(JSObjectArray);
    1065                 :     } else {
    1066          199889 :         script->objectsOffset = JSScript::INVALID_OFFSET;
    1067                 :     }
    1068          285135 :     if (nregexps != 0) {
    1069            1391 :         script->regexpsOffset = uint8_t(cursor - data);
    1070            1391 :         cursor += sizeof(JSObjectArray);
    1071                 :     } else {
    1072          283744 :         script->regexpsOffset = JSScript::INVALID_OFFSET;
    1073                 :     }
    1074          285135 :     if (ntrynotes != 0) {
    1075            7768 :         script->trynotesOffset = uint8_t(cursor - data);
    1076            7768 :         cursor += sizeof(JSTryNoteArray);
    1077                 :     } else {
    1078          277367 :         script->trynotesOffset = JSScript::INVALID_OFFSET;
    1079                 :     }
    1080          285135 :     if (nglobals != 0) {
    1081           12668 :         script->globalsOffset = uint8_t(cursor - data);
    1082           12668 :         cursor += sizeof(GlobalSlotArray);
    1083                 :     } else {
    1084          272467 :         script->globalsOffset = JSScript::INVALID_OFFSET;
    1085                 :     }
    1086          285135 :     if (nClosedArgs != 0) {
    1087            1307 :         script->closedArgsOffset = uint8_t(cursor - data);
    1088            1307 :         cursor += sizeof(ClosedSlotArray);
    1089                 :     } else {
    1090          283828 :         script->closedArgsOffset = JSScript::INVALID_OFFSET;
    1091                 :     }
    1092          285135 :     JS_ASSERT(cursor - data < 0xFF);
    1093          285135 :     if (nClosedVars != 0) {
    1094            2106 :         script->closedVarsOffset = uint8_t(cursor - data);
    1095            2106 :         cursor += sizeof(ClosedSlotArray);
    1096                 :     } else {
    1097          283029 :         script->closedVarsOffset = JSScript::INVALID_OFFSET;
    1098                 :     }
    1099                 : 
    1100          285135 :     if (nconsts != 0) {
    1101            2774 :         JS_ASSERT(reinterpret_cast<uintptr_t>(cursor) % sizeof(jsval) == 0);
    1102            2774 :         script->consts()->length = nconsts;
    1103            2774 :         script->consts()->vector = (HeapValue *)cursor;
    1104            2774 :         cursor += nconsts * sizeof(script->consts()->vector[0]);
    1105                 :     }
    1106                 : 
    1107          285135 :     if (natoms != 0) {
    1108          167038 :         script->natoms = natoms;
    1109          167038 :         script->atoms = reinterpret_cast<JSAtom **>(cursor);
    1110          167038 :         cursor += natoms * sizeof(script->atoms[0]);
    1111                 :     }
    1112                 : 
    1113          285135 :     if (nobjects != 0) {
    1114           85246 :         script->objects()->length = nobjects;
    1115           85246 :         script->objects()->vector = (HeapPtr<JSObject> *)cursor;
    1116           85246 :         cursor += nobjects * sizeof(script->objects()->vector[0]);
    1117                 :     }
    1118                 : 
    1119          285135 :     if (nregexps != 0) {
    1120            1391 :         script->regexps()->length = nregexps;
    1121            1391 :         script->regexps()->vector = (HeapPtr<JSObject> *)cursor;
    1122            1391 :         cursor += nregexps * sizeof(script->regexps()->vector[0]);
    1123                 :     }
    1124                 : 
    1125          285135 :     if (ntrynotes != 0) {
    1126            7768 :         script->trynotes()->length = ntrynotes;
    1127            7768 :         script->trynotes()->vector = reinterpret_cast<JSTryNote *>(cursor);
    1128            7768 :         size_t vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
    1129                 : #ifdef DEBUG
    1130            7768 :         memset(cursor, 0, vectorSize);
    1131                 : #endif
    1132            7768 :         cursor += vectorSize;
    1133                 :     }
    1134                 : 
    1135          285135 :     if (nglobals != 0) {
    1136           12668 :         script->globals()->length = nglobals;
    1137           12668 :         script->globals()->vector = reinterpret_cast<GlobalSlotArray::Entry *>(cursor);
    1138           12668 :         cursor += nglobals * sizeof(script->globals()->vector[0]);
    1139                 :     }
    1140                 : 
    1141          285135 :     if (nClosedArgs != 0) {
    1142            1307 :         script->closedArgs()->length = nClosedArgs;
    1143            1307 :         script->closedArgs()->vector = reinterpret_cast<uint32_t *>(cursor);
    1144            1307 :         cursor += nClosedArgs * sizeof(script->closedArgs()->vector[0]);
    1145                 :     }
    1146                 : 
    1147          285135 :     if (nClosedVars != 0) {
    1148            2106 :         script->closedVars()->length = nClosedVars;
    1149            2106 :         script->closedVars()->vector = reinterpret_cast<uint32_t *>(cursor);
    1150            2106 :         cursor += nClosedVars * sizeof(script->closedVars()->vector[0]);
    1151                 :     }
    1152                 : 
    1153          285135 :     JS_ASSERT(nTypeSets <= UINT16_MAX);
    1154          285135 :     script->nTypeSets = uint16_t(nTypeSets);
    1155                 : 
    1156          285135 :     script->code = (jsbytecode *)cursor;
    1157          285135 :     JS_ASSERT(cursor + length * sizeof(jsbytecode) + nsrcnotes * sizeof(jssrcnote) == data + size);
    1158                 : 
    1159                 : #ifdef DEBUG
    1160          285135 :     script->id_ = 0;
    1161                 : #endif
    1162                 : 
    1163          285135 :     JS_ASSERT(script->getVersion() == version);
    1164          285135 :     return script;
    1165                 : }
    1166                 : 
    1167                 : JSScript *
    1168          259010 : JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
    1169                 : {
    1170                 :     uint32_t mainLength, prologLength, nfixed;
    1171                 :     JSScript *script;
    1172                 :     const char *filename;
    1173                 :     JSFunction *fun;
    1174                 : 
    1175                 :     /* The counts of indexed things must be checked during code generation. */
    1176          259010 :     JS_ASSERT(bce->atomIndices->count() <= INDEX_LIMIT);
    1177          259010 :     JS_ASSERT(bce->objectList.length <= INDEX_LIMIT);
    1178          259010 :     JS_ASSERT(bce->regexpList.length <= INDEX_LIMIT);
    1179                 : 
    1180          259010 :     mainLength = bce->offset();
    1181          259010 :     prologLength = bce->prologOffset();
    1182                 : 
    1183          259010 :     if (!bce->bindings.ensureShape(cx))
    1184               0 :         return NULL;
    1185                 : 
    1186          259010 :     uint32_t nsrcnotes = uint32_t(bce->countFinalSourceNotes());
    1187          259010 :     uint16_t nClosedArgs = uint16_t(bce->closedArgs.length());
    1188          259010 :     JS_ASSERT(nClosedArgs == bce->closedArgs.length());
    1189          259010 :     uint16_t nClosedVars = uint16_t(bce->closedVars.length());
    1190          259010 :     JS_ASSERT(nClosedVars == bce->closedVars.length());
    1191                 :     script = NewScript(cx, prologLength + mainLength, nsrcnotes,
    1192                 :                        bce->atomIndices->count(), bce->objectList.length,
    1193                 :                        bce->regexpList.length, bce->ntrynotes, bce->constList.length(),
    1194                 :                        bce->globalUses.length(), nClosedArgs, nClosedVars,
    1195          259010 :                        bce->typesetCount, bce->version());
    1196          259010 :     if (!script)
    1197               0 :         return NULL;
    1198                 : 
    1199          259010 :     bce->bindings.makeImmutable();
    1200                 : 
    1201          259010 :     JS_ASSERT(script->mainOffset == 0);
    1202          259010 :     script->mainOffset = prologLength;
    1203          259010 :     PodCopy<jsbytecode>(script->code, bce->prologBase(), prologLength);
    1204          259010 :     PodCopy<jsbytecode>(script->main(), bce->base(), mainLength);
    1205          259010 :     nfixed = bce->inFunction() ? bce->bindings.countVars() : 0;
    1206          259010 :     JS_ASSERT(nfixed < SLOTNO_LIMIT);
    1207          259010 :     script->nfixed = uint16_t(nfixed);
    1208          259010 :     js_InitAtomMap(cx, bce->atomIndices.getMap(), script->atoms);
    1209                 : 
    1210          259010 :     filename = bce->parser->tokenStream.getFilename();
    1211          259010 :     if (filename) {
    1212          259006 :         script->filename = SaveScriptFilename(cx, filename);
    1213          259006 :         if (!script->filename)
    1214               0 :             return NULL;
    1215                 :     }
    1216          259010 :     script->lineno = bce->firstLine;
    1217          259010 :     if (script->nfixed + bce->maxStackDepth >= JS_BIT(16)) {
    1218                 :         ReportCompileErrorNumber(cx, bce->tokenStream(), NULL, JSREPORT_ERROR, JSMSG_NEED_DIET,
    1219               0 :                                  "script");
    1220               0 :         return NULL;
    1221                 :     }
    1222          259010 :     script->nslots = script->nfixed + bce->maxStackDepth;
    1223          259010 :     script->staticLevel = uint16_t(bce->staticLevel);
    1224          259010 :     script->principals = bce->parser->principals;
    1225                 : 
    1226          259010 :     if (script->principals)
    1227             100 :         JS_HoldPrincipals(script->principals);
    1228                 : 
    1229                 :     /* Establish invariant: principals implies originPrincipals. */
    1230          259010 :     script->originPrincipals = bce->parser->originPrincipals;
    1231          259010 :     if (!script->originPrincipals)
    1232          258915 :         script->originPrincipals = script->principals;
    1233          259010 :     if (script->originPrincipals)
    1234             106 :         JS_HoldPrincipals(script->originPrincipals);
    1235                 : 
    1236          259010 :     script->sourceMap = (jschar *) bce->parser->tokenStream.releaseSourceMap();
    1237                 : 
    1238          259010 :     if (!FinishTakingSrcNotes(cx, bce, script->notes()))
    1239               0 :         return NULL;
    1240          259010 :     if (bce->ntrynotes != 0)
    1241            7372 :         FinishTakingTryNotes(bce, script->trynotes());
    1242          259010 :     if (bce->objectList.length != 0)
    1243           83304 :         bce->objectList.finish(script->objects());
    1244          259010 :     if (bce->regexpList.length != 0)
    1245            1391 :         bce->regexpList.finish(script->regexps());
    1246          259010 :     if (bce->constList.length() != 0)
    1247            2774 :         bce->constList.finish(script->consts());
    1248          259010 :     if (bce->flags & TCF_NO_SCRIPT_RVAL)
    1249           38232 :         script->noScriptRval = true;
    1250          259010 :     if (bce->flags & TCF_STRICT_MODE_CODE)
    1251            1589 :         script->strictModeCode = true;
    1252          259010 :     if (bce->flags & TCF_COMPILE_N_GO) {
    1253          248300 :         script->compileAndGo = true;
    1254          248300 :         const StackFrame *fp = bce->parser->callerFrame;
    1255          248300 :         if (fp && fp->isFunctionFrame())
    1256           30448 :             script->savedCallerFun = true;
    1257                 :     }
    1258          259010 :     if (bce->callsEval())
    1259            6241 :         script->usesEval = true;
    1260          259010 :     if (bce->flags & TCF_HAS_SINGLETONS)
    1261           28116 :         script->hasSingletons = true;
    1262                 : 
    1263                 :     /*
    1264                 :      * The arguments-usage analysis in analyzeSSA only looks at
    1265                 :      * JSOP_ARGUMENTS use. Therefore, anything else that definitely requires an
    1266                 :      * arguments object needs to be accounted for here.
    1267                 :      */
    1268          259010 :     if (bce->inFunction()) {
    1269          164453 :         bool needsArgsObj = bce->mayOverwriteArguments() || bce->needsEagerArguments();
    1270          164453 :         if (needsArgsObj || bce->usesArguments()) {
    1271            6624 :             script->setMayNeedArgsObj();
    1272            6624 :             if (needsArgsObj)
    1273            4158 :                 script->setNeedsArgsObj(true);
    1274                 :         }
    1275                 :     }
    1276                 : 
    1277          259010 :     if (bce->globalUses.length()) {
    1278           12668 :         PodCopy<GlobalSlotArray::Entry>(script->globals()->vector, &bce->globalUses[0],
    1279           25336 :                                         bce->globalUses.length());
    1280                 :     }
    1281                 : 
    1282          259010 :     if (nClosedArgs)
    1283            1297 :         PodCopy<uint32_t>(script->closedArgs()->vector, &bce->closedArgs[0], nClosedArgs);
    1284          259010 :     if (nClosedVars)
    1285            2106 :         PodCopy<uint32_t>(script->closedVars()->vector, &bce->closedVars[0], nClosedVars);
    1286                 : 
    1287          259010 :     script->bindings.transfer(cx, &bce->bindings);
    1288                 : 
    1289          259010 :     fun = NULL;
    1290          259010 :     if (bce->inFunction()) {
    1291                 :         /*
    1292                 :          * We initialize fun->script() to be the script constructed above
    1293                 :          * so that the debugger has a valid fun->script().
    1294                 :          */
    1295          164453 :         fun = bce->fun();
    1296          164453 :         JS_ASSERT(fun->isInterpreted());
    1297          164453 :         JS_ASSERT(!fun->script());
    1298          164453 :         if (bce->flags & TCF_FUN_HEAVYWEIGHT)
    1299           10243 :             fun->flags |= JSFUN_HEAVYWEIGHT;
    1300                 : 
    1301                 :         /*
    1302                 :          * Mark functions which will only be executed once as singletons.
    1303                 :          */
    1304                 :         bool singleton =
    1305          164453 :             cx->typeInferenceEnabled() &&
    1306                 :             bce->parent &&
    1307           85535 :             bce->parent->compiling() &&
    1308          249988 :             bce->parent->asBytecodeEmitter()->checkSingletonContext();
    1309                 : 
    1310          164453 :         if (!script->typeSetFunction(cx, fun, singleton))
    1311               0 :             return NULL;
    1312                 : 
    1313          164453 :         fun->setScript(script);
    1314          164453 :         script->globalObject = fun->getParent() ? &fun->getParent()->global() : NULL;
    1315                 :     } else {
    1316                 :         /*
    1317                 :          * Initialize script->object, if necessary, so that the debugger has a
    1318                 :          * valid holder object.
    1319                 :          */
    1320           94557 :         if (bce->flags & TCF_NEED_SCRIPT_GLOBAL)
    1321           60566 :             script->globalObject = GetCurrentGlobal(cx);
    1322                 :     }
    1323                 : 
    1324                 :     /* Tell the debugger about this compiled script. */
    1325          259010 :     js_CallNewScriptHook(cx, script, fun);
    1326          259010 :     if (!bce->parent) {
    1327          104860 :         GlobalObject *compileAndGoGlobal = NULL;
    1328          104860 :         if (script->compileAndGo) {
    1329           94521 :             compileAndGoGlobal = script->globalObject;
    1330           94521 :             if (!compileAndGoGlobal)
    1331           33991 :                 compileAndGoGlobal = &bce->scopeChain()->global();
    1332                 :         }
    1333          104860 :         Debugger::onNewScript(cx, script, compileAndGoGlobal);
    1334                 :     }
    1335                 : 
    1336          259010 :     if (cx->hasRunOption(JSOPTION_PCCOUNT))
    1337               0 :         (void) script->initScriptCounts(cx);
    1338                 : 
    1339          259010 :     return script;
    1340                 : }
    1341                 : 
    1342                 : size_t
    1343          285135 : JSScript::computedSizeOfData()
    1344                 : {
    1345          285135 :     uint8_t *dataEnd = code + length * sizeof(jsbytecode) + numNotes() * sizeof(jssrcnote);
    1346          285135 :     JS_ASSERT(dataEnd >= data);
    1347          285135 :     return dataEnd - data;
    1348                 : }
    1349                 : 
    1350                 : size_t
    1351               0 : JSScript::sizeOfData(JSMallocSizeOfFun mallocSizeOf)
    1352                 : {
    1353               0 :     return mallocSizeOf(data);
    1354                 : }
    1355                 : 
    1356                 : /*
    1357                 :  * Nb: srcnotes are variable-length.  This function computes the number of
    1358                 :  * srcnote *slots*, which may be greater than the number of srcnotes.
    1359                 :  */
    1360                 : uint32_t
    1361          287631 : JSScript::numNotes()
    1362                 : {
    1363                 :     jssrcnote *sn;
    1364          287631 :     jssrcnote *notes_ = notes();
    1365         3246688 :     for (sn = notes_; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
    1366         2959057 :         continue;
    1367          287631 :     return sn - notes_ + 1;    /* +1 for the terminator */
    1368                 : }
    1369                 : 
    1370                 : JS_FRIEND_API(void)
    1371          343732 : js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
    1372                 : {
    1373          343732 :     JS_ASSERT(!script->callDestroyHook);
    1374          343732 :     if (JSNewScriptHook hook = cx->runtime->debugHooks.newScriptHook) {
    1375               0 :         AutoKeepAtoms keep(cx->runtime);
    1376                 :         hook(cx, script->filename, script->lineno, script, fun,
    1377               0 :              cx->runtime->debugHooks.newScriptHookData);
    1378                 :     }
    1379          343732 :     script->callDestroyHook = true;
    1380          343732 : }
    1381                 : 
    1382                 : void
    1383          377723 : js::CallDestroyScriptHook(FreeOp *fop, JSScript *script)
    1384                 : {
    1385          377723 :     if (!script->callDestroyHook)
    1386           33991 :         return;
    1387                 : 
    1388          343732 :     if (JSDestroyScriptHook hook = fop->runtime()->debugHooks.destroyScriptHook)
    1389               0 :         hook(fop, script, fop->runtime()->debugHooks.destroyScriptHookData);
    1390          343732 :     script->callDestroyHook = false;
    1391          343732 :     script->clearTraps(fop);
    1392                 : }
    1393                 : 
    1394                 : void
    1395          285135 : JSScript::finalize(FreeOp *fop)
    1396                 : {
    1397          285135 :     CallDestroyScriptHook(fop, this);
    1398                 : 
    1399          285135 :     JS_ASSERT_IF(principals, originPrincipals);
    1400          285135 :     if (principals)
    1401             117 :         JS_DropPrincipals(fop->runtime(), principals);
    1402          285135 :     if (originPrincipals)
    1403             128 :         JS_DropPrincipals(fop->runtime(), originPrincipals);
    1404                 : 
    1405          285135 :     if (types)
    1406          153935 :         types->destroy();
    1407                 : 
    1408                 : #ifdef JS_METHODJIT
    1409          285135 :     mjit::ReleaseScriptCode(fop, this);
    1410                 : #endif
    1411                 : 
    1412          285135 :     destroyScriptCounts(fop);
    1413                 : 
    1414          285135 :     if (sourceMap)
    1415               1 :         fop->free_(sourceMap);
    1416                 : 
    1417          285135 :     if (debug) {
    1418               1 :         jsbytecode *end = code + length;
    1419              68 :         for (jsbytecode *pc = code; pc < end; pc++) {
    1420              67 :             if (BreakpointSite *site = getBreakpointSite(pc)) {
    1421                 :                 /* Breakpoints are swept before finalization. */
    1422               0 :                 JS_ASSERT(site->firstBreakpoint() == NULL);
    1423               0 :                 site->clearTrap(fop, NULL, NULL);
    1424               0 :                 JS_ASSERT(getBreakpointSite(pc) == NULL);
    1425                 :             }
    1426                 :         }
    1427               1 :         fop->free_(debug);
    1428                 :     }
    1429                 : 
    1430          285135 :     JS_POISON(data, 0xdb, computedSizeOfData());
    1431          285135 :     fop->free_(data);
    1432          285135 : }
    1433                 : 
    1434                 : namespace js {
    1435                 : 
    1436                 : static const uint32_t GSN_CACHE_THRESHOLD = 100;
    1437                 : static const uint32_t GSN_CACHE_MAP_INIT_SIZE = 20;
    1438                 : 
    1439                 : void
    1440           39964 : GSNCache::purge()
    1441                 : {
    1442           39964 :     code = NULL;
    1443           39964 :     if (map.initialized())
    1444            4038 :         map.finish();
    1445           39964 : }
    1446                 : 
    1447                 : } /* namespace js */
    1448                 : 
    1449                 : jssrcnote *
    1450        38338044 : js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
    1451                 : {
    1452        38338044 :     size_t target = pc - script->code;
    1453        38338044 :     if (target >= size_t(script->length))
    1454               0 :         return NULL;
    1455                 : 
    1456        38338044 :     GSNCache *cache = GetGSNCache(cx);
    1457        38338044 :     if (cache->code == script->code) {
    1458         5756530 :         JS_ASSERT(cache->map.initialized());
    1459         5756530 :         GSNCache::Map::Ptr p = cache->map.lookup(pc);
    1460         5756530 :         return p ? p->value : NULL;
    1461                 :     }
    1462                 : 
    1463        32581514 :     size_t offset = 0;
    1464                 :     jssrcnote *result;
    1465       220660687 :     for (jssrcnote *sn = script->notes(); ; sn = SN_NEXT(sn)) {
    1466       220660687 :         if (SN_IS_TERMINATOR(sn)) {
    1467        30694675 :             result = NULL;
    1468        30694675 :             break;
    1469                 :         }
    1470       189966012 :         offset += SN_DELTA(sn);
    1471       189966012 :         if (offset == target && SN_IS_GETTABLE(sn)) {
    1472         1886839 :             result = sn;
    1473         1886839 :             break;
    1474                 :         }
    1475                 :     }
    1476                 : 
    1477        32581514 :     if (cache->code != script->code && script->length >= GSN_CACHE_THRESHOLD) {
    1478           21570 :         unsigned nsrcnotes = 0;
    1479         2876115 :         for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn);
    1480         2854545 :              sn = SN_NEXT(sn)) {
    1481         2854545 :             if (SN_IS_GETTABLE(sn))
    1482         1095459 :                 ++nsrcnotes;
    1483                 :         }
    1484           21570 :         if (cache->code) {
    1485           17532 :             JS_ASSERT(cache->map.initialized());
    1486           17532 :             cache->map.finish();
    1487           17532 :             cache->code = NULL;
    1488                 :         }
    1489           21570 :         if (cache->map.init(nsrcnotes)) {
    1490           21570 :             pc = script->code;
    1491         2876115 :             for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn);
    1492         2854545 :                  sn = SN_NEXT(sn)) {
    1493         2854545 :                 pc += SN_DELTA(sn);
    1494         2854545 :                 if (SN_IS_GETTABLE(sn))
    1495         1095459 :                     JS_ALWAYS_TRUE(cache->map.put(pc, sn));
    1496                 :             }
    1497           21570 :             cache->code = script->code;
    1498                 :         }
    1499                 :     }
    1500                 : 
    1501        32581514 :     return result;
    1502                 : }
    1503                 : 
    1504                 : unsigned
    1505         6429462 : js::PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc)
    1506                 : {
    1507         6429462 :     unsigned lineno = startLine;
    1508                 : 
    1509                 :     /*
    1510                 :      * Walk through source notes accumulating their deltas, keeping track of
    1511                 :      * line-number notes, until we pass the note for pc's offset within
    1512                 :      * script->code.
    1513                 :      */
    1514         6429462 :     ptrdiff_t offset = 0;
    1515         6429462 :     ptrdiff_t target = pc - code;
    1516        51459189 :     for (jssrcnote *sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
    1517        48630120 :         offset += SN_DELTA(sn);
    1518        48630120 :         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
    1519        48630120 :         if (type == SRC_SETLINE) {
    1520          895302 :             if (offset <= target)
    1521          886440 :                 lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
    1522        47734818 :         } else if (type == SRC_NEWLINE) {
    1523        18134115 :             if (offset <= target)
    1524        18103869 :                 lineno++;
    1525                 :         }
    1526        48630120 :         if (offset > target)
    1527         3600393 :             break;
    1528                 :     }
    1529                 : 
    1530         6429462 :     return lineno;
    1531                 : }
    1532                 : 
    1533                 : unsigned
    1534         6429462 : js::PCToLineNumber(JSScript *script, jsbytecode *pc)
    1535                 : {
    1536                 :     /* Cope with StackFrame.pc value prior to entering js_Interpret. */
    1537         6429462 :     if (!pc)
    1538               0 :         return 0;
    1539                 : 
    1540         6429462 :     return PCToLineNumber(script->lineno, script->notes(), script->code, pc);
    1541                 : }
    1542                 : 
    1543                 : /* The line number limit is the same as the jssrcnote offset limit. */
    1544                 : #define SN_LINE_LIMIT   (SN_3BYTE_OFFSET_FLAG << 16)
    1545                 : 
    1546                 : jsbytecode *
    1547              12 : js_LineNumberToPC(JSScript *script, unsigned target)
    1548                 : {
    1549              12 :     ptrdiff_t offset = 0;
    1550              12 :     ptrdiff_t best = -1;
    1551              12 :     unsigned lineno = script->lineno;
    1552              12 :     unsigned bestdiff = SN_LINE_LIMIT;
    1553              81 :     for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
    1554                 :         /*
    1555                 :          * Exact-match only if offset is not in the prolog; otherwise use
    1556                 :          * nearest greater-or-equal line number match.
    1557                 :          */
    1558              72 :         if (lineno == target && offset >= ptrdiff_t(script->mainOffset))
    1559               3 :             goto out;
    1560              69 :         if (lineno >= target) {
    1561               2 :             unsigned diff = lineno - target;
    1562               2 :             if (diff < bestdiff) {
    1563               1 :                 bestdiff = diff;
    1564               1 :                 best = offset;
    1565                 :             }
    1566                 :         }
    1567              69 :         offset += SN_DELTA(sn);
    1568              69 :         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
    1569              69 :         if (type == SRC_SETLINE) {
    1570               3 :             lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
    1571              66 :         } else if (type == SRC_NEWLINE) {
    1572              34 :             lineno++;
    1573                 :         }
    1574                 :     }
    1575               9 :     if (best >= 0)
    1576               0 :         offset = best;
    1577                 : out:
    1578              12 :     return script->code + offset;
    1579                 : }
    1580                 : 
    1581                 : JS_FRIEND_API(unsigned)
    1582            2683 : js_GetScriptLineExtent(JSScript *script)
    1583                 : {
    1584            2683 :     unsigned lineno = script->lineno;
    1585            2683 :     unsigned maxLineNo = 0;
    1586            2683 :     bool counting = true;
    1587           13333 :     for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
    1588           10650 :         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
    1589           10650 :         if (type == SRC_SETLINE) {
    1590            3682 :             if (maxLineNo < lineno)
    1591            1261 :                 maxLineNo = lineno;
    1592            3682 :             lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
    1593            3682 :             counting = true;
    1594            3682 :             if (maxLineNo < lineno)
    1595            3681 :                 maxLineNo = lineno;
    1596                 :             else
    1597               1 :                 counting = false;
    1598            6968 :         } else if (type == SRC_NEWLINE) {
    1599            2295 :             if (counting)
    1600            2295 :                 lineno++;
    1601                 :         }
    1602                 :     }
    1603                 : 
    1604            2683 :     if (maxLineNo > lineno)
    1605               1 :         lineno = maxLineNo;
    1606                 : 
    1607            2683 :     return 1 + lineno - script->lineno;
    1608                 : }
    1609                 : 
    1610                 : namespace js {
    1611                 : 
    1612                 : unsigned
    1613          105137 : CurrentLine(JSContext *cx)
    1614                 : {
    1615          105137 :     return PCToLineNumber(cx->fp()->script(), cx->regs().pc);
    1616                 : }
    1617                 : 
    1618                 : void
    1619           24642 : CurrentScriptFileLineOriginSlow(JSContext *cx, const char **file, unsigned *linenop,
    1620                 :                                 JSPrincipals **origin)
    1621                 : {
    1622           24642 :     FrameRegsIter iter(cx);
    1623           49284 :     while (!iter.done() && !iter.fp()->isScriptFrame())
    1624               0 :         ++iter;
    1625                 : 
    1626           24642 :     if (iter.done()) {
    1627               4 :         *file = NULL;
    1628               4 :         *linenop = 0;
    1629               4 :         *origin = NULL;
    1630               4 :         return;
    1631                 :     }
    1632                 : 
    1633           24638 :     JSScript *script = iter.fp()->script();
    1634           24638 :     *file = script->filename;
    1635           24638 :     *linenop = PCToLineNumber(iter.fp()->script(), iter.pc());
    1636           24638 :     *origin = script->originPrincipals;
    1637                 : }
    1638                 : 
    1639                 : }  /* namespace js */
    1640                 : 
    1641                 : JSScript *
    1642            2369 : js::CloneScript(JSContext *cx, JSScript *script)
    1643                 : {
    1644            2369 :     JS_ASSERT(cx->compartment != script->compartment());
    1645                 : 
    1646                 :     /* Serialize script. */
    1647            4738 :     XDREncoder encoder(cx);
    1648                 : 
    1649            2369 :     if (!XDRScript(&encoder, &script, NULL))
    1650               0 :         return NULL;
    1651                 : 
    1652                 :     uint32_t nbytes;
    1653            2369 :     const void *p = encoder.getData(&nbytes);
    1654                 : 
    1655                 :     /* De-serialize script. */
    1656            2369 :     XDRDecoder decoder(cx, p, nbytes, cx->compartment->principals, script->originPrincipals);
    1657                 : 
    1658                 :     JSScript *newScript;
    1659            2369 :     if (!XDRScript(&decoder, &newScript, NULL))
    1660               0 :         return NULL;
    1661                 : 
    1662            2369 :     return newScript;
    1663                 : }
    1664                 : 
    1665                 : bool
    1666            2577 : JSScript::ensureHasDebug(JSContext *cx)
    1667                 : {
    1668            2577 :     if (debug)
    1669            1243 :         return true;
    1670                 : 
    1671            1334 :     size_t nbytes = offsetof(DebugScript, breakpoints) + length * sizeof(BreakpointSite*);
    1672            1334 :     debug = (DebugScript *) cx->calloc_(nbytes);
    1673            1334 :     if (!debug)
    1674               0 :         return false;
    1675                 : 
    1676                 :     /*
    1677                 :      * Ensure that any Interpret() instances running on this script have
    1678                 :      * interrupts enabled. The interrupts must stay enabled until the
    1679                 :      * debug state is destroyed.
    1680                 :      */
    1681                 :     InterpreterFrames *frames;
    1682            3875 :     for (frames = cx->runtime->interpreterFrames; frames; frames = frames->older)
    1683            2541 :         frames->enableInterruptsIfRunning(this);
    1684                 : 
    1685            1334 :     return true;
    1686                 : }
    1687                 : 
    1688                 : void
    1689             883 : JSScript::recompileForStepMode(FreeOp *fop)
    1690                 : {
    1691                 : #ifdef JS_METHODJIT
    1692             883 :     if (hasJITCode()) {
    1693             198 :         mjit::Recompiler::clearStackReferences(fop, this);
    1694             198 :         mjit::ReleaseScriptCode(fop, this);
    1695                 :     }
    1696                 : #endif
    1697             883 : }
    1698                 : 
    1699                 : bool
    1700             937 : JSScript::tryNewStepMode(JSContext *cx, uint32_t newValue)
    1701                 : {
    1702             937 :     JS_ASSERT(debug);
    1703                 : 
    1704             937 :     uint32_t prior = debug->stepMode;
    1705             937 :     debug->stepMode = newValue;
    1706                 : 
    1707             937 :     if (!prior != !newValue) {
    1708                 :         /* Step mode has been enabled or disabled. Alert the methodjit. */
    1709             883 :         recompileForStepMode(cx->runtime->defaultFreeOp());
    1710                 : 
    1711             883 :         if (!stepModeEnabled() && !debug->numSites) {
    1712             432 :             cx->free_(debug);
    1713             432 :             debug = NULL;
    1714                 :         }
    1715                 :     }
    1716                 : 
    1717             937 :     return true;
    1718                 : }
    1719                 : 
    1720                 : bool
    1721               1 : JSScript::setStepModeFlag(JSContext *cx, bool step)
    1722                 : {
    1723               1 :     if (!ensureHasDebug(cx))
    1724               0 :         return false;
    1725                 : 
    1726               1 :     return tryNewStepMode(cx, (debug->stepMode & stepCountMask) | (step ? stepFlagMask : 0));
    1727                 : }
    1728                 : 
    1729                 : bool
    1730             936 : JSScript::changeStepModeCount(JSContext *cx, int delta)
    1731                 : {
    1732             936 :     if (!ensureHasDebug(cx))
    1733               0 :         return false;
    1734                 : 
    1735             936 :     assertSameCompartment(cx, this);
    1736             936 :     JS_ASSERT_IF(delta > 0, cx->compartment->debugMode());
    1737                 : 
    1738             936 :     uint32_t count = debug->stepMode & stepCountMask;
    1739             936 :     JS_ASSERT(((count + delta) & stepCountMask) == count + delta);
    1740                 :     return tryNewStepMode(cx,
    1741                 :                           (debug->stepMode & stepFlagMask) |
    1742             936 :                           ((count + delta) & stepCountMask));
    1743                 : }
    1744                 : 
    1745                 : BreakpointSite *
    1746            1640 : JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
    1747                 :                                     GlobalObject *scriptGlobal)
    1748                 : {
    1749            1640 :     JS_ASSERT(size_t(pc - code) < length);
    1750                 : 
    1751            1640 :     if (!ensureHasDebug(cx))
    1752               0 :         return NULL;
    1753                 : 
    1754            1640 :     BreakpointSite *&site = debug->breakpoints[pc - code];
    1755                 : 
    1756            1640 :     if (!site) {
    1757            1172 :         site = cx->runtime->new_<BreakpointSite>(this, pc);
    1758            1172 :         if (!site) {
    1759               0 :             js_ReportOutOfMemory(cx);
    1760               0 :             return NULL;
    1761                 :         }
    1762            1172 :         debug->numSites++;
    1763                 :     }
    1764                 : 
    1765            1640 :     if (site->scriptGlobal)
    1766             279 :         JS_ASSERT_IF(scriptGlobal, site->scriptGlobal == scriptGlobal);
    1767                 :     else
    1768            1361 :         site->scriptGlobal = scriptGlobal;
    1769                 : 
    1770            1640 :     return site;
    1771                 : }
    1772                 : 
    1773                 : void
    1774            1172 : JSScript::destroyBreakpointSite(FreeOp *fop, jsbytecode *pc)
    1775                 : {
    1776            1172 :     JS_ASSERT(unsigned(pc - code) < length);
    1777                 : 
    1778            1172 :     BreakpointSite *&site = debug->breakpoints[pc - code];
    1779            1172 :     JS_ASSERT(site);
    1780                 : 
    1781            1172 :     fop->delete_(site);
    1782            1172 :     site = NULL;
    1783                 : 
    1784            1172 :     if (--debug->numSites == 0 && !stepModeEnabled()) {
    1785             901 :         fop->free_(debug);
    1786             901 :         debug = NULL;
    1787                 :     }
    1788            1172 : }
    1789                 : 
    1790                 : void
    1791            8819 : JSScript::clearBreakpointsIn(JSContext *cx, js::Debugger *dbg, JSObject *handler)
    1792                 : {
    1793            8819 :     if (!hasAnyBreakpointsOrStepMode())
    1794            8351 :         return;
    1795                 : 
    1796             468 :     jsbytecode *end = code + length;
    1797         8885736 :     for (jsbytecode *pc = code; pc < end; pc++) {
    1798         8885268 :         BreakpointSite *site = getBreakpointSite(pc);
    1799         8885268 :         if (site) {
    1800                 :             Breakpoint *nextbp;
    1801            1683 :             for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
    1802            1035 :                 nextbp = bp->nextInSite();
    1803            1035 :                 if ((!dbg || bp->debugger == dbg) && (!handler || bp->getHandler() == handler))
    1804             756 :                     bp->destroy(cx->runtime->defaultFreeOp());
    1805                 :             }
    1806                 :         }
    1807                 :     }
    1808                 : }
    1809                 : 
    1810                 : void
    1811          344247 : JSScript::clearTraps(FreeOp *fop)
    1812                 : {
    1813          344247 :     if (!hasAnyBreakpointsOrStepMode())
    1814          343731 :         return;
    1815                 : 
    1816             516 :     jsbytecode *end = code + length;
    1817           17807 :     for (jsbytecode *pc = code; pc < end; pc++) {
    1818           17291 :         BreakpointSite *site = getBreakpointSite(pc);
    1819           17291 :         if (site)
    1820             632 :             site->clearTrap(fop);
    1821                 :     }
    1822                 : }
    1823                 : 
    1824                 : void
    1825          152539 : JSScript::markChildren(JSTracer *trc)
    1826                 : {
    1827          152539 :     JS_ASSERT_IF(trc->runtime->gcStrictCompartmentChecking, compartment()->isCollecting());
    1828                 : 
    1829          540979 :     for (uint32_t i = 0; i < natoms; ++i) {
    1830          388440 :         if (atoms[i])
    1831          388440 :             MarkStringUnbarriered(trc, &atoms[i], "atom");
    1832                 :     }
    1833                 : 
    1834          152539 :     if (JSScript::isValidOffset(objectsOffset)) {
    1835           25946 :         JSObjectArray *objarray = objects();
    1836           25946 :         MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
    1837                 :     }
    1838                 : 
    1839          152539 :     if (JSScript::isValidOffset(regexpsOffset)) {
    1840             653 :         JSObjectArray *objarray = regexps();
    1841             653 :         MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
    1842                 :     }
    1843                 : 
    1844          152539 :     if (JSScript::isValidOffset(constsOffset)) {
    1845             253 :         JSConstArray *constarray = consts();
    1846             253 :         MarkValueRange(trc, constarray->length, constarray->vector, "consts");
    1847                 :     }
    1848                 : 
    1849          152539 :     if (function())
    1850          106798 :         MarkObject(trc, &function_, "function");
    1851                 : 
    1852          152539 :     if (!isCachedEval && globalObject)
    1853          101606 :         MarkObject(trc, &globalObject, "object");
    1854                 : 
    1855          152539 :     if (IS_GC_MARKING_TRACER(trc) && filename)
    1856           87678 :         MarkScriptFilename(filename);
    1857                 : 
    1858          152539 :     bindings.trace(trc);
    1859                 : 
    1860          152539 :     if (types)
    1861           70791 :         types->trace(trc);
    1862                 : 
    1863          152539 :     if (hasAnyBreakpointsOrStepMode()) {
    1864           23641 :         for (unsigned i = 0; i < length; i++) {
    1865           23007 :             BreakpointSite *site = debug->breakpoints[i];
    1866           23007 :             if (site && site->trapHandler)
    1867             629 :                 MarkValue(trc, &site->trapClosure, "trap closure");
    1868                 :         }
    1869                 :     }
    1870          152539 : }
    1871                 : 
    1872                 : void
    1873          155053 : JSScript::setNeedsArgsObj(bool needsArgsObj)
    1874                 : {
    1875          155053 :     JS_ASSERT(!analyzedArgsUsage_);
    1876          155053 :     analyzedArgsUsage_ = true;
    1877          155053 :     needsArgsObj_ = needsArgsObj;
    1878          155053 : }
    1879                 : 
    1880                 : bool
    1881              52 : JSScript::applySpeculationFailed(JSContext *cx)
    1882                 : {
    1883              52 :     JS_ASSERT(analyzedArgsUsage());
    1884              52 :     JS_ASSERT(!needsArgsObj());
    1885              52 :     needsArgsObj_ = true;
    1886                 : 
    1887                 :     /*
    1888                 :      * By design, the apply-arguments optimization is only made when there
    1889                 :      * are no outstanding cases of MagicValue(JS_OPTIMIZED_ARGUMENTS) other
    1890                 :      * than this particular invocation of 'f.apply(x, arguments)'. Thus, there
    1891                 :      * are no outstanding values of MagicValue(JS_OPTIMIZED_ARGUMENTS) on the
    1892                 :      * stack. However, there are three things that need fixup:
    1893                 :      *  - there may be any number of activations of this script that don't have
    1894                 :      *    an argsObj that now need one.
    1895                 :      *  - jit code compiled (and possible active on the stack) with the static
    1896                 :      *    assumption of !script->needsArgsObj();
    1897                 :      *  - type inference data for the script assuming script->needsArgsObj; and
    1898                 :      */
    1899             160 :     for (AllFramesIter i(cx->stack.space()); !i.done(); ++i) {
    1900             108 :         StackFrame *fp = i.fp();
    1901             108 :         if (fp->isFunctionFrame() && fp->script() == this) {
    1902              25 :             if (!fp->hasArgsObj() && !ArgumentsObject::create(cx, fp)) {
    1903                 :                 /*
    1904                 :                  * We can't leave stack frames where fp->script->needsArgsObj
    1905                 :                  * and !fp->hasArgsObj. It is, however, safe to leave frames
    1906                 :                  * where fp->hasArgsObj and !fp->script->needsArgsObj.
    1907                 :                  */
    1908               0 :                 needsArgsObj_ = false;
    1909               0 :                 return false;
    1910                 :             }
    1911                 :         }
    1912                 :     }
    1913                 : 
    1914                 : #ifdef JS_METHODJIT
    1915              52 :     if (hasJITCode()) {
    1916              47 :         mjit::Recompiler::clearStackReferences(cx->runtime->defaultFreeOp(), this);
    1917              47 :         mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), this);
    1918                 :     }
    1919                 : #endif
    1920                 : 
    1921              52 :     if (hasAnalysis() && analysis()->ranInference()) {
    1922              52 :         types::AutoEnterTypeInference enter(cx);
    1923             328 :         for (unsigned off = 0; off < length; off += GetBytecodeLength(code + off)) {
    1924             302 :             if (code[off] == JSOP_ARGUMENTS) {
    1925              26 :                 types::TypeSet *set = analysis()->pushedTypes(off, 0);
    1926              26 :                 JS_ASSERT(set->isLazyArguments(cx));
    1927              26 :                 set->addType(cx, types::Type::UnknownType());
    1928                 :             }
    1929                 :         }
    1930                 :     }
    1931                 : 
    1932              52 :     return true;
    1933                 : }

Generated by: LCOV version 1.7