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

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