js/src/jsscript.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * JS script operations.
     9  */
    11 #include "jsscriptinlines.h"
    13 #include "mozilla/DebugOnly.h"
    14 #include "mozilla/MathAlgorithms.h"
    15 #include "mozilla/MemoryReporting.h"
    16 #include "mozilla/PodOperations.h"
    18 #include <string.h>
    20 #include "jsapi.h"
    21 #include "jsatom.h"
    22 #include "jscntxt.h"
    23 #include "jsfun.h"
    24 #include "jsgc.h"
    25 #include "jsobj.h"
    26 #include "jsopcode.h"
    27 #include "jsprf.h"
    28 #include "jstypes.h"
    29 #include "jsutil.h"
    30 #include "jswrapper.h"
    32 #include "frontend/BytecodeCompiler.h"
    33 #include "frontend/BytecodeEmitter.h"
    34 #include "frontend/SharedContext.h"
    35 #include "gc/Marking.h"
    36 #include "jit/BaselineJIT.h"
    37 #include "jit/IonCode.h"
    38 #include "js/MemoryMetrics.h"
    39 #include "js/OldDebugAPI.h"
    40 #include "js/Utility.h"
    41 #include "vm/ArgumentsObject.h"
    42 #include "vm/Compression.h"
    43 #include "vm/Debugger.h"
    44 #include "vm/Opcodes.h"
    45 #include "vm/SelfHosting.h"
    46 #include "vm/Shape.h"
    47 #include "vm/Xdr.h"
    49 #include "jsfuninlines.h"
    50 #include "jsinferinlines.h"
    51 #include "jsobjinlines.h"
    53 #include "vm/ScopeObject-inl.h"
    54 #include "vm/Stack-inl.h"
    56 using namespace js;
    57 using namespace js::gc;
    58 using namespace js::frontend;
    60 using mozilla::PodCopy;
    61 using mozilla::PodZero;
    62 using mozilla::RotateLeft;
    64 typedef Rooted<GlobalObject *> RootedGlobalObject;
    66 /* static */ uint32_t
    67 Bindings::argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle bindings)
    68 {
    69     HandlePropertyName arguments = cx->names().arguments;
    70     BindingIter bi(bindings);
    71     while (bi->name() != arguments)
    72         bi++;
    73     return bi.frameIndex();
    74 }
    76 bool
    77 Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
    78                                    unsigned numArgs, uint32_t numVars,
    79                                    Binding *bindingArray, uint32_t numBlockScoped)
    80 {
    81     JS_ASSERT(!self->callObjShape_);
    82     JS_ASSERT(self->bindingArrayAndFlag_ == TEMPORARY_STORAGE_BIT);
    83     JS_ASSERT(!(uintptr_t(bindingArray) & TEMPORARY_STORAGE_BIT));
    84     JS_ASSERT(numArgs <= ARGC_LIMIT);
    85     JS_ASSERT(numVars <= LOCALNO_LIMIT);
    86     JS_ASSERT(numBlockScoped <= LOCALNO_LIMIT);
    87     JS_ASSERT(numVars <= LOCALNO_LIMIT - numBlockScoped);
    88     JS_ASSERT(UINT32_MAX - numArgs >= numVars + numBlockScoped);
    90     self->bindingArrayAndFlag_ = uintptr_t(bindingArray) | TEMPORARY_STORAGE_BIT;
    91     self->numArgs_ = numArgs;
    92     self->numVars_ = numVars;
    93     self->numBlockScoped_ = numBlockScoped;
    95     // Get the initial shape to use when creating CallObjects for this script.
    96     // After creation, a CallObject's shape may change completely (via direct eval() or
    97     // other operations that mutate the lexical scope). However, since the
    98     // lexical bindings added to the initial shape are permanent and the
    99     // allocKind/nfixed of a CallObject cannot change, one may assume that the
   100     // slot location (whether in the fixed or dynamic slots) of a variable is
   101     // the same as in the initial shape. (This is assumed by the interpreter and
   102     // JITs when interpreting/compiling aliasedvar ops.)
   104     // Since unaliased variables are, by definition, only accessed by local
   105     // operations and never through the scope chain, only give shapes to
   106     // aliased variables. While the debugger may observe any scope object at
   107     // any time, such accesses are mediated by DebugScopeProxy (see
   108     // DebugScopeProxy::handleUnaliasedAccess).
   109     uint32_t nslots = CallObject::RESERVED_SLOTS;
   110     for (BindingIter bi(self); bi; bi++) {
   111         if (bi->aliased())
   112             nslots++;
   113     }
   115     // Put as many of nslots inline into the object header as possible.
   116     uint32_t nfixed = gc::GetGCKindSlots(gc::GetGCObjectKind(nslots));
   118     // Start with the empty shape and then append one shape per aliased binding.
   119     RootedShape shape(cx,
   120         EmptyShape::getInitialShape(cx, &CallObject::class_, nullptr, nullptr, nullptr,
   121                                     nfixed, BaseShape::VAROBJ | BaseShape::DELEGATE));
   122     if (!shape)
   123         return false;
   125 #ifdef DEBUG
   126     HashSet<PropertyName *> added(cx);
   127     if (!added.init())
   128         return false;
   129 #endif
   131     uint32_t slot = CallObject::RESERVED_SLOTS;
   132     for (BindingIter bi(self); bi; bi++) {
   133         if (!bi->aliased())
   134             continue;
   136 #ifdef DEBUG
   137         // The caller ensures no duplicate aliased names.
   138         JS_ASSERT(!added.has(bi->name()));
   139         if (!added.put(bi->name()))
   140             return false;
   141 #endif
   143         StackBaseShape stackBase(cx, &CallObject::class_, nullptr, nullptr,
   144                                  BaseShape::VAROBJ | BaseShape::DELEGATE);
   146         UnownedBaseShape *base = BaseShape::getUnowned(cx, stackBase);
   147         if (!base)
   148             return false;
   150         unsigned attrs = JSPROP_PERMANENT |
   151                          JSPROP_ENUMERATE |
   152                          (bi->kind() == Binding::CONSTANT ? JSPROP_READONLY : 0);
   153         StackShape child(base, NameToId(bi->name()), slot, attrs, 0);
   155         shape = cx->compartment()->propertyTree.getChild(cx, shape, child);
   156         if (!shape)
   157             return false;
   159         JS_ASSERT(slot < nslots);
   160         slot++;
   161     }
   162     JS_ASSERT(slot == nslots);
   164     JS_ASSERT(!shape->inDictionary());
   165     self->callObjShape_.init(shape);
   166     return true;
   167 }
   169 uint8_t *
   170 Bindings::switchToScriptStorage(Binding *newBindingArray)
   171 {
   172     JS_ASSERT(bindingArrayUsingTemporaryStorage());
   173     JS_ASSERT(!(uintptr_t(newBindingArray) & TEMPORARY_STORAGE_BIT));
   175     if (count() > 0)
   176         PodCopy(newBindingArray, bindingArray(), count());
   177     bindingArrayAndFlag_ = uintptr_t(newBindingArray);
   178     return reinterpret_cast<uint8_t *>(newBindingArray + count());
   179 }
   181 bool
   182 Bindings::clone(JSContext *cx, InternalBindingsHandle self,
   183                 uint8_t *dstScriptData, HandleScript srcScript)
   184 {
   185     /* The clone has the same bindingArray_ offset as 'src'. */
   186     Bindings &src = srcScript->bindings;
   187     ptrdiff_t off = (uint8_t *)src.bindingArray() - srcScript->data;
   188     JS_ASSERT(off >= 0);
   189     JS_ASSERT(size_t(off) <= srcScript->dataSize());
   190     Binding *dstPackedBindings = (Binding *)(dstScriptData + off);
   192     /*
   193      * Since atoms are shareable throughout the runtime, we can simply copy
   194      * the source's bindingArray directly.
   195      */
   196     if (!initWithTemporaryStorage(cx, self, src.numArgs(), src.numVars(), src.bindingArray(),
   197                                   src.numBlockScoped()))
   198         return false;
   199     self->switchToScriptStorage(dstPackedBindings);
   200     return true;
   201 }
   203 /* static */ Bindings
   204 GCMethods<Bindings>::initial()
   205 {
   206     return Bindings();
   207 }
   209 template<XDRMode mode>
   210 static bool
   211 XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, uint32_t numVars,
   212                   HandleScript script, unsigned numBlockScoped)
   213 {
   214     JSContext *cx = xdr->cx();
   216     if (mode == XDR_ENCODE) {
   217         for (BindingIter bi(script); bi; bi++) {
   218             RootedAtom atom(cx, bi->name());
   219             if (!XDRAtom(xdr, &atom))
   220                 return false;
   221         }
   223         for (BindingIter bi(script); bi; bi++) {
   224             uint8_t u8 = (uint8_t(bi->kind()) << 1) | uint8_t(bi->aliased());
   225             if (!xdr->codeUint8(&u8))
   226                 return false;
   227         }
   228     } else {
   229         uint32_t nameCount = numArgs + numVars;
   231         AutoValueVector atoms(cx);
   232         if (!atoms.resize(nameCount))
   233             return false;
   234         for (uint32_t i = 0; i < nameCount; i++) {
   235             RootedAtom atom(cx);
   236             if (!XDRAtom(xdr, &atom))
   237                 return false;
   238             atoms[i] = StringValue(atom);
   239         }
   241         Binding *bindingArray = las.alloc().newArrayUninitialized<Binding>(nameCount);
   242         if (!bindingArray)
   243             return false;
   244         for (uint32_t i = 0; i < nameCount; i++) {
   245             uint8_t u8;
   246             if (!xdr->codeUint8(&u8))
   247                 return false;
   249             PropertyName *name = atoms[i].toString()->asAtom().asPropertyName();
   250             Binding::Kind kind = Binding::Kind(u8 >> 1);
   251             bool aliased = bool(u8 & 1);
   253             bindingArray[i] = Binding(name, kind, aliased);
   254         }
   256         InternalBindingsHandle bindings(script, &script->bindings);
   257         if (!Bindings::initWithTemporaryStorage(cx, bindings, numArgs, numVars, bindingArray,
   258                                                 numBlockScoped))
   259             return false;
   260     }
   262     return true;
   263 }
   265 bool
   266 Bindings::bindingIsAliased(uint32_t bindingIndex)
   267 {
   268     JS_ASSERT(bindingIndex < count());
   269     return bindingArray()[bindingIndex].aliased();
   270 }
   272 void
   273 Bindings::trace(JSTracer *trc)
   274 {
   275     if (callObjShape_)
   276         MarkShape(trc, &callObjShape_, "callObjShape");
   278     /*
   279      * As the comment in Bindings explains, bindingsArray may point into freed
   280      * storage when bindingArrayUsingTemporaryStorage so we don't mark it.
   281      * Note: during compilation, atoms are already kept alive by gcKeepAtoms.
   282      */
   283     if (bindingArrayUsingTemporaryStorage())
   284         return;
   286     for (Binding *b = bindingArray(), *end = b + count(); b != end; b++) {
   287         PropertyName *name = b->name();
   288         MarkStringUnbarriered(trc, &name, "bindingArray");
   289     }
   290 }
   292 bool
   293 js::FillBindingVector(HandleScript fromScript, BindingVector *vec)
   294 {
   295     for (BindingIter bi(fromScript); bi; bi++) {
   296         if (!vec->append(*bi))
   297             return false;
   298     }
   300     return true;
   301 }
   303 template<XDRMode mode>
   304 bool
   305 js::XDRScriptConst(XDRState<mode> *xdr, MutableHandleValue vp)
   306 {
   307     JSContext *cx = xdr->cx();
   309     /*
   310      * A script constant can be an arbitrary primitive value as they are used
   311      * to implement JSOP_LOOKUPSWITCH. But they cannot be objects, see
   312      * bug 407186.
   313      */
   314     enum ConstTag {
   315         SCRIPT_INT     = 0,
   316         SCRIPT_DOUBLE  = 1,
   317         SCRIPT_ATOM    = 2,
   318         SCRIPT_TRUE    = 3,
   319         SCRIPT_FALSE   = 4,
   320         SCRIPT_NULL    = 5,
   321         SCRIPT_OBJECT  = 6,
   322         SCRIPT_VOID    = 7,
   323         SCRIPT_HOLE    = 8
   324     };
   326     uint32_t tag;
   327     if (mode == XDR_ENCODE) {
   328         if (vp.isInt32()) {
   329             tag = SCRIPT_INT;
   330         } else if (vp.isDouble()) {
   331             tag = SCRIPT_DOUBLE;
   332         } else if (vp.isString()) {
   333             tag = SCRIPT_ATOM;
   334         } else if (vp.isTrue()) {
   335             tag = SCRIPT_TRUE;
   336         } else if (vp.isFalse()) {
   337             tag = SCRIPT_FALSE;
   338         } else if (vp.isNull()) {
   339             tag = SCRIPT_NULL;
   340         } else if (vp.isObject()) {
   341             tag = SCRIPT_OBJECT;
   342         } else if (vp.isMagic(JS_ELEMENTS_HOLE)) {
   343             tag = SCRIPT_HOLE;
   344         } else {
   345             JS_ASSERT(vp.isUndefined());
   346             tag = SCRIPT_VOID;
   347         }
   348     }
   350     if (!xdr->codeUint32(&tag))
   351         return false;
   353     switch (tag) {
   354       case SCRIPT_INT: {
   355         uint32_t i;
   356         if (mode == XDR_ENCODE)
   357             i = uint32_t(vp.toInt32());
   358         if (!xdr->codeUint32(&i))
   359             return false;
   360         if (mode == XDR_DECODE)
   361             vp.set(Int32Value(int32_t(i)));
   362         break;
   363       }
   364       case SCRIPT_DOUBLE: {
   365         double d;
   366         if (mode == XDR_ENCODE)
   367             d = vp.toDouble();
   368         if (!xdr->codeDouble(&d))
   369             return false;
   370         if (mode == XDR_DECODE)
   371             vp.set(DoubleValue(d));
   372         break;
   373       }
   374       case SCRIPT_ATOM: {
   375         RootedAtom atom(cx);
   376         if (mode == XDR_ENCODE)
   377             atom = &vp.toString()->asAtom();
   378         if (!XDRAtom(xdr, &atom))
   379             return false;
   380         if (mode == XDR_DECODE)
   381             vp.set(StringValue(atom));
   382         break;
   383       }
   384       case SCRIPT_TRUE:
   385         if (mode == XDR_DECODE)
   386             vp.set(BooleanValue(true));
   387         break;
   388       case SCRIPT_FALSE:
   389         if (mode == XDR_DECODE)
   390             vp.set(BooleanValue(false));
   391         break;
   392       case SCRIPT_NULL:
   393         if (mode == XDR_DECODE)
   394             vp.set(NullValue());
   395         break;
   396       case SCRIPT_OBJECT: {
   397         RootedObject obj(cx);
   398         if (mode == XDR_ENCODE)
   399             obj = &vp.toObject();
   401         if (!XDRObjectLiteral(xdr, &obj))
   402             return false;
   404         if (mode == XDR_DECODE)
   405             vp.setObject(*obj);
   406         break;
   407       }
   408       case SCRIPT_VOID:
   409         if (mode == XDR_DECODE)
   410             vp.set(UndefinedValue());
   411         break;
   412       case SCRIPT_HOLE:
   413         if (mode == XDR_DECODE)
   414             vp.setMagic(JS_ELEMENTS_HOLE);
   415         break;
   416     }
   417     return true;
   418 }
   420 template bool
   421 js::XDRScriptConst(XDRState<XDR_ENCODE> *, MutableHandleValue);
   423 template bool
   424 js::XDRScriptConst(XDRState<XDR_DECODE> *, MutableHandleValue);
   426 // Code LazyScript's free variables.
   427 template<XDRMode mode>
   428 static bool
   429 XDRLazyFreeVariables(XDRState<mode> *xdr, MutableHandle<LazyScript *> lazy)
   430 {
   431     JSContext *cx = xdr->cx();
   432     RootedAtom atom(cx);
   433     HeapPtrAtom *freeVariables = lazy->freeVariables();
   434     size_t numFreeVariables = lazy->numFreeVariables();
   435     for (size_t i = 0; i < numFreeVariables; i++) {
   436         if (mode == XDR_ENCODE)
   437             atom = freeVariables[i];
   439         if (!XDRAtom(xdr, &atom))
   440             return false;
   442         if (mode == XDR_DECODE)
   443             freeVariables[i] = atom;
   444     }
   446     return true;
   447 }
   449 // Code the missing part needed to re-create a LazyScript from a JSScript.
   450 template<XDRMode mode>
   451 static bool
   452 XDRRelazificationInfo(XDRState<mode> *xdr, HandleFunction fun, HandleScript script,
   453                       MutableHandle<LazyScript *> lazy)
   454 {
   455     MOZ_ASSERT_IF(mode == XDR_ENCODE, script->isRelazifiable() && script->maybeLazyScript());
   456     MOZ_ASSERT_IF(mode == XDR_ENCODE, !lazy->numInnerFunctions());
   458     JSContext *cx = xdr->cx();
   460     uint64_t packedFields;
   461     {
   462         uint32_t begin = script->sourceStart();
   463         uint32_t end = script->sourceEnd();
   464         uint32_t lineno = script->lineno();
   465         uint32_t column = script->column();
   467         if (mode == XDR_ENCODE) {
   468             packedFields = lazy->packedFields();
   469             MOZ_ASSERT(begin == lazy->begin());
   470             MOZ_ASSERT(end == lazy->end());
   471             MOZ_ASSERT(lineno == lazy->lineno());
   472             MOZ_ASSERT(column == lazy->column());
   473         }
   475         if (!xdr->codeUint64(&packedFields))
   476             return false;
   478         if (mode == XDR_DECODE) {
   479             lazy.set(LazyScript::Create(cx, fun, packedFields, begin, end, lineno, column));
   481             // As opposed to XDRLazyScript, we need to restore the runtime bits
   482             // of the script, as we are trying to match the fact this function
   483             // has already been parsed and that it would need to be re-lazified.
   484             lazy->initRuntimeFields(packedFields);
   485         }
   486     }
   488     // Code free variables.
   489     if (!XDRLazyFreeVariables(xdr, lazy))
   490         return false;
   492     return true;
   493 }
   495 static inline uint32_t
   496 FindScopeObjectIndex(JSScript *script, NestedScopeObject &scope)
   497 {
   498     ObjectArray *objects = script->objects();
   499     HeapPtrObject *vector = objects->vector;
   500     unsigned length = objects->length;
   501     for (unsigned i = 0; i < length; ++i) {
   502         if (vector[i] == &scope)
   503             return i;
   504     }
   506     MOZ_ASSUME_UNREACHABLE("Scope not found");
   507 }
   509 static bool
   510 SaveSharedScriptData(ExclusiveContext *, Handle<JSScript *>, SharedScriptData *, uint32_t);
   512 enum XDRClassKind {
   513     CK_BlockObject = 0,
   514     CK_WithObject  = 1,
   515     CK_JSFunction  = 2,
   516     CK_JSObject    = 3
   517 };
   519 template<XDRMode mode>
   520 bool
   521 js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
   522               HandleFunction fun, MutableHandleScript scriptp)
   523 {
   524     /* NB: Keep this in sync with CloneScript. */
   526     enum ScriptBits {
   527         NoScriptRval,
   528         SavedCallerFun,
   529         Strict,
   530         ContainsDynamicNameAccess,
   531         FunHasExtensibleScope,
   532         FunNeedsDeclEnvObject,
   533         FunHasAnyAliasedFormal,
   534         ArgumentsHasVarBinding,
   535         NeedsArgsObj,
   536         IsGeneratorExp,
   537         IsLegacyGenerator,
   538         IsStarGenerator,
   539         OwnSource,
   540         ExplicitUseStrict,
   541         SelfHosted,
   542         IsCompileAndGo,
   543         HasSingleton,
   544         TreatAsRunOnce,
   545         HasLazyScript
   546     };
   548     uint32_t length, lineno, column, nslots, staticLevel;
   549     uint32_t natoms, nsrcnotes, i;
   550     uint32_t nconsts, nobjects, nregexps, ntrynotes, nblockscopes;
   551     uint32_t prologLength, version;
   552     uint32_t funLength = 0;
   553     uint32_t nTypeSets = 0;
   554     uint32_t scriptBits = 0;
   556     JSContext *cx = xdr->cx();
   557     RootedScript script(cx);
   558     natoms = nsrcnotes = 0;
   559     nconsts = nobjects = nregexps = ntrynotes = nblockscopes = 0;
   561     /* XDR arguments and vars. */
   562     uint16_t nargs = 0;
   563     uint16_t nblocklocals = 0;
   564     uint32_t nvars = 0;
   565     if (mode == XDR_ENCODE) {
   566         script = scriptp.get();
   567         JS_ASSERT_IF(enclosingScript, enclosingScript->compartment() == script->compartment());
   569         nargs = script->bindings.numArgs();
   570         nblocklocals = script->bindings.numBlockScoped();
   571         nvars = script->bindings.numVars();
   572     }
   573     if (!xdr->codeUint16(&nargs))
   574         return false;
   575     if (!xdr->codeUint16(&nblocklocals))
   576         return false;
   577     if (!xdr->codeUint32(&nvars))
   578         return false;
   580     if (mode == XDR_ENCODE)
   581         length = script->length();
   582     if (!xdr->codeUint32(&length))
   583         return false;
   585     if (mode == XDR_ENCODE) {
   586         prologLength = script->mainOffset();
   587         JS_ASSERT(script->getVersion() != JSVERSION_UNKNOWN);
   588         version = script->getVersion();
   589         lineno = script->lineno();
   590         column = script->column();
   591         nslots = script->nslots();
   592         staticLevel = script->staticLevel();
   593         natoms = script->natoms();
   595         nsrcnotes = script->numNotes();
   597         if (script->hasConsts())
   598             nconsts = script->consts()->length;
   599         if (script->hasObjects())
   600             nobjects = script->objects()->length;
   601         if (script->hasRegexps())
   602             nregexps = script->regexps()->length;
   603         if (script->hasTrynotes())
   604             ntrynotes = script->trynotes()->length;
   605         if (script->hasBlockScopes())
   606             nblockscopes = script->blockScopes()->length;
   608         nTypeSets = script->nTypeSets();
   609         funLength = script->funLength();
   611         if (script->noScriptRval())
   612             scriptBits |= (1 << NoScriptRval);
   613         if (script->savedCallerFun())
   614             scriptBits |= (1 << SavedCallerFun);
   615         if (script->strict())
   616             scriptBits |= (1 << Strict);
   617         if (script->explicitUseStrict())
   618             scriptBits |= (1 << ExplicitUseStrict);
   619         if (script->selfHosted())
   620             scriptBits |= (1 << SelfHosted);
   621         if (script->bindingsAccessedDynamically())
   622             scriptBits |= (1 << ContainsDynamicNameAccess);
   623         if (script->funHasExtensibleScope())
   624             scriptBits |= (1 << FunHasExtensibleScope);
   625         if (script->funNeedsDeclEnvObject())
   626             scriptBits |= (1 << FunNeedsDeclEnvObject);
   627         if (script->funHasAnyAliasedFormal())
   628             scriptBits |= (1 << FunHasAnyAliasedFormal);
   629         if (script->argumentsHasVarBinding())
   630             scriptBits |= (1 << ArgumentsHasVarBinding);
   631         if (script->analyzedArgsUsage() && script->needsArgsObj())
   632             scriptBits |= (1 << NeedsArgsObj);
   633         if (!enclosingScript || enclosingScript->scriptSource() != script->scriptSource())
   634             scriptBits |= (1 << OwnSource);
   635         if (script->isGeneratorExp())
   636             scriptBits |= (1 << IsGeneratorExp);
   637         if (script->isLegacyGenerator())
   638             scriptBits |= (1 << IsLegacyGenerator);
   639         if (script->isStarGenerator())
   640             scriptBits |= (1 << IsStarGenerator);
   641         if (script->compileAndGo())
   642             scriptBits |= (1 << IsCompileAndGo);
   643         if (script->hasSingletons())
   644             scriptBits |= (1 << HasSingleton);
   645         if (script->treatAsRunOnce())
   646             scriptBits |= (1 << TreatAsRunOnce);
   647         if (script->isRelazifiable())
   648             scriptBits |= (1 << HasLazyScript);
   649     }
   651     if (!xdr->codeUint32(&prologLength))
   652         return false;
   653     if (!xdr->codeUint32(&version))
   654         return false;
   656     // To fuse allocations, we need lengths of all embedded arrays early.
   657     if (!xdr->codeUint32(&natoms))
   658         return false;
   659     if (!xdr->codeUint32(&nsrcnotes))
   660         return false;
   661     if (!xdr->codeUint32(&nconsts))
   662         return false;
   663     if (!xdr->codeUint32(&nobjects))
   664         return false;
   665     if (!xdr->codeUint32(&nregexps))
   666         return false;
   667     if (!xdr->codeUint32(&ntrynotes))
   668         return false;
   669     if (!xdr->codeUint32(&nblockscopes))
   670         return false;
   671     if (!xdr->codeUint32(&nTypeSets))
   672         return false;
   673     if (!xdr->codeUint32(&funLength))
   674         return false;
   675     if (!xdr->codeUint32(&scriptBits))
   676         return false;
   678     if (mode == XDR_DECODE) {
   679         JSVersion version_ = JSVersion(version);
   680         JS_ASSERT((version_ & VersionFlags::MASK) == unsigned(version_));
   682         // staticLevel is set below.
   683         CompileOptions options(cx);
   684         options.setVersion(version_)
   685                .setNoScriptRval(!!(scriptBits & (1 << NoScriptRval)))
   686                .setSelfHostingMode(!!(scriptBits & (1 << SelfHosted)));
   687         RootedScriptSource sourceObject(cx);
   688         if (scriptBits & (1 << OwnSource)) {
   689             ScriptSource *ss = cx->new_<ScriptSource>();
   690             if (!ss)
   691                 return false;
   692             ScriptSourceHolder ssHolder(ss);
   694             /*
   695              * We use this CompileOptions only to initialize the
   696              * ScriptSourceObject. Most CompileOptions fields aren't used by
   697              * ScriptSourceObject, and those that are (element; elementAttributeName)
   698              * aren't preserved by XDR. So this can be simple.
   699              */
   700             CompileOptions options(cx);
   701             options.setOriginPrincipals(xdr->originPrincipals());
   702             ss->initFromOptions(cx, options);
   703             sourceObject = ScriptSourceObject::create(cx, ss, options);
   704             if (!sourceObject)
   705                 return false;
   706         } else {
   707             JS_ASSERT(enclosingScript);
   708             // When decoding, all the scripts and the script source object
   709             // are in the same compartment, so the script's source object
   710             // should never be a cross-compartment wrapper.
   711             JS_ASSERT(enclosingScript->sourceObject()->is<ScriptSourceObject>());
   712             sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>();
   713         }
   714         script = JSScript::Create(cx, enclosingScope, !!(scriptBits & (1 << SavedCallerFun)),
   715                                   options, /* staticLevel = */ 0, sourceObject, 0, 0);
   716         if (!script)
   717             return false;
   718     }
   720     /* JSScript::partiallyInit assumes script->bindings is fully initialized. */
   721     LifoAllocScope las(&cx->tempLifoAlloc());
   722     if (!XDRScriptBindings(xdr, las, nargs, nvars, script, nblocklocals))
   723         return false;
   725     if (mode == XDR_DECODE) {
   726         if (!JSScript::partiallyInit(cx, script, nconsts, nobjects, nregexps, ntrynotes,
   727                                      nblockscopes, nTypeSets))
   728         {
   729             return false;
   730         }
   732         JS_ASSERT(!script->mainOffset());
   733         script->mainOffset_ = prologLength;
   734         script->setLength(length);
   735         script->funLength_ = funLength;
   737         scriptp.set(script);
   739         if (scriptBits & (1 << Strict))
   740             script->strict_ = true;
   741         if (scriptBits & (1 << ExplicitUseStrict))
   742             script->explicitUseStrict_ = true;
   743         if (scriptBits & (1 << ContainsDynamicNameAccess))
   744             script->bindingsAccessedDynamically_ = true;
   745         if (scriptBits & (1 << FunHasExtensibleScope))
   746             script->funHasExtensibleScope_ = true;
   747         if (scriptBits & (1 << FunNeedsDeclEnvObject))
   748             script->funNeedsDeclEnvObject_ = true;
   749         if (scriptBits & (1 << FunHasAnyAliasedFormal))
   750             script->funHasAnyAliasedFormal_ = true;
   751         if (scriptBits & (1 << ArgumentsHasVarBinding))
   752             script->setArgumentsHasVarBinding();
   753         if (scriptBits & (1 << NeedsArgsObj))
   754             script->setNeedsArgsObj(true);
   755         if (scriptBits & (1 << IsGeneratorExp))
   756             script->isGeneratorExp_ = true;
   757         if (scriptBits & (1 << IsCompileAndGo))
   758             script->compileAndGo_ = true;
   759         if (scriptBits & (1 << HasSingleton))
   760             script->hasSingletons_ = true;
   761         if (scriptBits & (1 << TreatAsRunOnce))
   762             script->treatAsRunOnce_ = true;
   764         if (scriptBits & (1 << IsLegacyGenerator)) {
   765             JS_ASSERT(!(scriptBits & (1 << IsStarGenerator)));
   766             script->setGeneratorKind(LegacyGenerator);
   767         } else if (scriptBits & (1 << IsStarGenerator))
   768             script->setGeneratorKind(StarGenerator);
   769     }
   771     JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
   772     JS_STATIC_ASSERT(sizeof(jssrcnote) == 1);
   774     if (scriptBits & (1 << OwnSource)) {
   775         if (!script->scriptSource()->performXDR<mode>(xdr))
   776             return false;
   777     }
   778     if (!xdr->codeUint32(&script->sourceStart_))
   779         return false;
   780     if (!xdr->codeUint32(&script->sourceEnd_))
   781         return false;
   783     if (!xdr->codeUint32(&lineno) ||
   784         !xdr->codeUint32(&column) ||
   785         !xdr->codeUint32(&nslots) ||
   786         !xdr->codeUint32(&staticLevel))
   787     {
   788         return false;
   789     }
   791     if (mode == XDR_DECODE) {
   792         script->lineno_ = lineno;
   793         script->column_ = column;
   794         script->nslots_ = nslots;
   795         script->staticLevel_ = staticLevel;
   796     }
   798     jsbytecode *code = script->code();
   799     SharedScriptData *ssd;
   800     if (mode == XDR_DECODE) {
   801         ssd = SharedScriptData::new_(cx, length, nsrcnotes, natoms);
   802         if (!ssd)
   803             return false;
   804         code = ssd->data;
   805         if (natoms != 0) {
   806             script->natoms_ = natoms;
   807             script->atoms = ssd->atoms();
   808         }
   809     }
   811     if (!xdr->codeBytes(code, length) || !xdr->codeBytes(code + length, nsrcnotes)) {
   812         if (mode == XDR_DECODE)
   813             js_free(ssd);
   814         return false;
   815     }
   817     for (i = 0; i != natoms; ++i) {
   818         if (mode == XDR_DECODE) {
   819             RootedAtom tmp(cx);
   820             if (!XDRAtom(xdr, &tmp))
   821                 return false;
   822             script->atoms[i].init(tmp);
   823         } else {
   824             RootedAtom tmp(cx, script->atoms[i]);
   825             if (!XDRAtom(xdr, &tmp))
   826                 return false;
   827         }
   828     }
   830     if (mode == XDR_DECODE) {
   831         if (!SaveSharedScriptData(cx, script, ssd, nsrcnotes))
   832             return false;
   833     }
   835     if (nconsts) {
   836         HeapValue *vector = script->consts()->vector;
   837         RootedValue val(cx);
   838         for (i = 0; i != nconsts; ++i) {
   839             if (mode == XDR_ENCODE)
   840                 val = vector[i];
   841             if (!XDRScriptConst(xdr, &val))
   842                 return false;
   843             if (mode == XDR_DECODE)
   844                 vector[i].init(val);
   845         }
   846     }
   848     /*
   849      * Here looping from 0-to-length to xdr objects is essential to ensure that
   850      * all references to enclosing blocks (via FindScopeObjectIndex below) happen
   851      * after the enclosing block has been XDR'd.
   852      */
   853     for (i = 0; i != nobjects; ++i) {
   854         HeapPtr<JSObject> *objp = &script->objects()->vector[i];
   855         XDRClassKind classk;
   857         if (mode == XDR_ENCODE) {
   858             JSObject *obj = *objp;
   859             if (obj->is<BlockObject>())
   860                 classk = CK_BlockObject;
   861             else if (obj->is<StaticWithObject>())
   862                 classk = CK_WithObject;
   863             else if (obj->is<JSFunction>())
   864                 classk = CK_JSFunction;
   865             else if (obj->is<JSObject>() || obj->is<ArrayObject>())
   866                 classk = CK_JSObject;
   867             else
   868                 MOZ_ASSUME_UNREACHABLE("Cannot encode this class of object.");
   869         }
   871         if (!xdr->codeEnum32(&classk))
   872             return false;
   874         switch (classk) {
   875           case CK_BlockObject:
   876           case CK_WithObject: {
   877             /* Code the nested block's enclosing scope. */
   878             uint32_t enclosingStaticScopeIndex = 0;
   879             if (mode == XDR_ENCODE) {
   880                 NestedScopeObject &scope = (*objp)->as<NestedScopeObject>();
   881                 if (NestedScopeObject *enclosing = scope.enclosingNestedScope())
   882                     enclosingStaticScopeIndex = FindScopeObjectIndex(script, *enclosing);
   883                 else
   884                     enclosingStaticScopeIndex = UINT32_MAX;
   885             }
   886             if (!xdr->codeUint32(&enclosingStaticScopeIndex))
   887                 return false;
   888             Rooted<JSObject*> enclosingStaticScope(cx);
   889             if (mode == XDR_DECODE) {
   890                 if (enclosingStaticScopeIndex != UINT32_MAX) {
   891                     JS_ASSERT(enclosingStaticScopeIndex < i);
   892                     enclosingStaticScope = script->objects()->vector[enclosingStaticScopeIndex];
   893                 } else {
   894                     enclosingStaticScope = fun;
   895                 }
   896             }
   898             if (classk == CK_BlockObject) {
   899                 Rooted<StaticBlockObject*> tmp(cx, static_cast<StaticBlockObject *>(objp->get()));
   900                 if (!XDRStaticBlockObject(xdr, enclosingStaticScope, tmp.address()))
   901                     return false;
   902                 *objp = tmp;
   903             } else {
   904                 Rooted<StaticWithObject*> tmp(cx, static_cast<StaticWithObject *>(objp->get()));
   905                 if (!XDRStaticWithObject(xdr, enclosingStaticScope, tmp.address()))
   906                     return false;
   907                 *objp = tmp;
   908             }
   909             break;
   910           }
   912           case CK_JSFunction: {
   913             /* Code the nested function's enclosing scope. */
   914             uint32_t funEnclosingScopeIndex = 0;
   915             RootedObject funEnclosingScope(cx);
   916             if (mode == XDR_ENCODE) {
   917                 RootedFunction function(cx, &(*objp)->as<JSFunction>());
   919                 if (function->isInterpretedLazy())
   920                     funEnclosingScope = function->lazyScript()->enclosingScope();
   921                 else
   922                     funEnclosingScope = function->nonLazyScript()->enclosingStaticScope();
   924                 StaticScopeIter<NoGC> ssi(funEnclosingScope);
   925                 if (ssi.done() || ssi.type() == StaticScopeIter<NoGC>::FUNCTION) {
   926                     JS_ASSERT(ssi.done() == !fun);
   927                     funEnclosingScopeIndex = UINT32_MAX;
   928                 } else if (ssi.type() == StaticScopeIter<NoGC>::BLOCK) {
   929                     funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block());
   930                     JS_ASSERT(funEnclosingScopeIndex < i);
   931                 } else {
   932                     funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.staticWith());
   933                     JS_ASSERT(funEnclosingScopeIndex < i);
   934                 }
   935             }
   937             if (!xdr->codeUint32(&funEnclosingScopeIndex))
   938                 return false;
   940             if (mode == XDR_DECODE) {
   941                 if (funEnclosingScopeIndex == UINT32_MAX) {
   942                     funEnclosingScope = fun;
   943                 } else {
   944                     JS_ASSERT(funEnclosingScopeIndex < i);
   945                     funEnclosingScope = script->objects()->vector[funEnclosingScopeIndex];
   946                 }
   947             }
   949             // Code nested function and script.
   950             RootedObject tmp(cx, *objp);
   951             if (!XDRInterpretedFunction(xdr, funEnclosingScope, script, &tmp))
   952                 return false;
   953             *objp = tmp;
   954             break;
   955           }
   957           case CK_JSObject: {
   958             /* Code object literal. */
   959             RootedObject tmp(cx, *objp);
   960             if (!XDRObjectLiteral(xdr, &tmp))
   961                 return false;
   962             *objp = tmp;
   963             break;
   964           }
   966           default: {
   967             MOZ_ASSERT(false, "Unknown class kind.");
   968             return false;
   969           }
   970         }
   971     }
   973     for (i = 0; i != nregexps; ++i) {
   974         if (!XDRScriptRegExpObject(xdr, &script->regexps()->vector[i]))
   975             return false;
   976     }
   978     if (ntrynotes != 0) {
   979         JSTryNote *tnfirst = script->trynotes()->vector;
   980         JS_ASSERT(script->trynotes()->length == ntrynotes);
   981         JSTryNote *tn = tnfirst + ntrynotes;
   982         do {
   983             --tn;
   984             if (!xdr->codeUint8(&tn->kind) ||
   985                 !xdr->codeUint32(&tn->stackDepth) ||
   986                 !xdr->codeUint32(&tn->start) ||
   987                 !xdr->codeUint32(&tn->length)) {
   988                 return false;
   989             }
   990         } while (tn != tnfirst);
   991     }
   993     for (i = 0; i < nblockscopes; ++i) {
   994         BlockScopeNote *note = &script->blockScopes()->vector[i];
   995         if (!xdr->codeUint32(&note->index) ||
   996             !xdr->codeUint32(&note->start) ||
   997             !xdr->codeUint32(&note->length) ||
   998             !xdr->codeUint32(&note->parent))
   999         {
  1000             return false;
  1004     if (scriptBits & (1 << HasLazyScript)) {
  1005         Rooted<LazyScript *> lazy(cx);
  1006         if (mode == XDR_ENCODE)
  1007             lazy = script->maybeLazyScript();
  1009         if (!XDRRelazificationInfo(xdr, fun, script, &lazy))
  1010             return false;
  1012         if (mode == XDR_DECODE)
  1013             script->setLazyScript(lazy);
  1016     if (mode == XDR_DECODE) {
  1017         scriptp.set(script);
  1019         /* see BytecodeEmitter::tellDebuggerAboutCompiledScript */
  1020         CallNewScriptHook(cx, script, fun);
  1021         if (!fun) {
  1022             RootedGlobalObject global(cx, script->compileAndGo() ? &script->global() : nullptr);
  1023             Debugger::onNewScript(cx, script, global);
  1027     return true;
  1030 template bool
  1031 js::XDRScript(XDRState<XDR_ENCODE> *, HandleObject, HandleScript, HandleFunction,
  1032               MutableHandleScript);
  1034 template bool
  1035 js::XDRScript(XDRState<XDR_DECODE> *, HandleObject, HandleScript, HandleFunction,
  1036               MutableHandleScript);
  1038 template<XDRMode mode>
  1039 bool
  1040 js::XDRLazyScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
  1041                   HandleFunction fun, MutableHandle<LazyScript *> lazy)
  1043     JSContext *cx = xdr->cx();
  1046         uint32_t begin;
  1047         uint32_t end;
  1048         uint32_t lineno;
  1049         uint32_t column;
  1050         uint64_t packedFields;
  1052         if (mode == XDR_ENCODE) {
  1053             MOZ_ASSERT(!lazy->maybeScript());
  1054             MOZ_ASSERT(fun == lazy->functionNonDelazifying());
  1056             begin = lazy->begin();
  1057             end = lazy->end();
  1058             lineno = lazy->lineno();
  1059             column = lazy->column();
  1060             packedFields = lazy->packedFields();
  1063         if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
  1064             !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
  1065             !xdr->codeUint64(&packedFields))
  1067             return false;
  1070         if (mode == XDR_DECODE)
  1071             lazy.set(LazyScript::Create(cx, fun, packedFields, begin, end, lineno, column));
  1074     // Code free variables.
  1075     if (!XDRLazyFreeVariables(xdr, lazy))
  1076         return false;
  1078     // Code inner functions.
  1080         RootedObject func(cx);
  1081         HeapPtrFunction *innerFunctions = lazy->innerFunctions();
  1082         size_t numInnerFunctions = lazy->numInnerFunctions();
  1083         for (size_t i = 0; i < numInnerFunctions; i++) {
  1084             if (mode == XDR_ENCODE)
  1085                 func = innerFunctions[i];
  1087             if (!XDRInterpretedFunction(xdr, fun, enclosingScript, &func))
  1088                 return false;
  1090             if (mode == XDR_DECODE)
  1091                 innerFunctions[i] = &func->as<JSFunction>();
  1095     if (mode == XDR_DECODE) {
  1096         JS_ASSERT(!lazy->sourceObject());
  1097         ScriptSourceObject *sourceObject = &enclosingScript->scriptSourceUnwrap();
  1099         // Set the enclosing scope of the lazy function, this would later be
  1100         // used to define the environment when the function would be used.
  1101         lazy->setParent(enclosingScope, sourceObject);
  1104     return true;
  1107 template bool
  1108 js::XDRLazyScript(XDRState<XDR_ENCODE> *, HandleObject, HandleScript,
  1109                   HandleFunction, MutableHandle<LazyScript *>);
  1111 template bool
  1112 js::XDRLazyScript(XDRState<XDR_DECODE> *, HandleObject, HandleScript,
  1113                   HandleFunction, MutableHandle<LazyScript *>);
  1115 void
  1116 JSScript::setSourceObject(JSObject *object)
  1118     JS_ASSERT(compartment() == object->compartment());
  1119     sourceObject_ = object;
  1122 js::ScriptSourceObject &
  1123 JSScript::scriptSourceUnwrap() const {
  1124     return UncheckedUnwrap(sourceObject())->as<ScriptSourceObject>();
  1127 js::ScriptSource *
  1128 JSScript::scriptSource() const {
  1129     return scriptSourceUnwrap().source();
  1132 bool
  1133 JSScript::initScriptCounts(JSContext *cx)
  1135     JS_ASSERT(!hasScriptCounts());
  1137     size_t n = 0;
  1139     for (jsbytecode *pc = code(); pc < codeEnd(); pc += GetBytecodeLength(pc))
  1140         n += PCCounts::numCounts(JSOp(*pc));
  1142     size_t bytes = (length() * sizeof(PCCounts)) + (n * sizeof(double));
  1143     char *base = (char *) cx->calloc_(bytes);
  1144     if (!base)
  1145         return false;
  1147     /* Create compartment's scriptCountsMap if necessary. */
  1148     ScriptCountsMap *map = compartment()->scriptCountsMap;
  1149     if (!map) {
  1150         map = cx->new_<ScriptCountsMap>();
  1151         if (!map || !map->init()) {
  1152             js_free(base);
  1153             js_delete(map);
  1154             return false;
  1156         compartment()->scriptCountsMap = map;
  1159     char *cursor = base;
  1161     ScriptCounts scriptCounts;
  1162     scriptCounts.pcCountsVector = (PCCounts *) cursor;
  1163     cursor += length() * sizeof(PCCounts);
  1165     for (jsbytecode *pc = code(); pc < codeEnd(); pc += GetBytecodeLength(pc)) {
  1166         JS_ASSERT(uintptr_t(cursor) % sizeof(double) == 0);
  1167         scriptCounts.pcCountsVector[pcToOffset(pc)].counts = (double *) cursor;
  1168         size_t capacity = PCCounts::numCounts(JSOp(*pc));
  1169 #ifdef DEBUG
  1170         scriptCounts.pcCountsVector[pcToOffset(pc)].capacity = capacity;
  1171 #endif
  1172         cursor += capacity * sizeof(double);
  1175     if (!map->putNew(this, scriptCounts)) {
  1176         js_free(base);
  1177         return false;
  1179     hasScriptCounts_ = true; // safe to set this;  we can't fail after this point
  1181     JS_ASSERT(size_t(cursor - base) == bytes);
  1183     /* Enable interrupts in any interpreter frames running on this script. */
  1184     for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
  1185         if (iter->isInterpreter())
  1186             iter->asInterpreter()->enableInterruptsIfRunning(this);
  1189     return true;
  1192 static inline ScriptCountsMap::Ptr GetScriptCountsMapEntry(JSScript *script)
  1194     JS_ASSERT(script->hasScriptCounts());
  1195     ScriptCountsMap *map = script->compartment()->scriptCountsMap;
  1196     ScriptCountsMap::Ptr p = map->lookup(script);
  1197     JS_ASSERT(p);
  1198     return p;
  1201 js::PCCounts
  1202 JSScript::getPCCounts(jsbytecode *pc) {
  1203     JS_ASSERT(containsPC(pc));
  1204     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
  1205     return p->value().pcCountsVector[pcToOffset(pc)];
  1208 void
  1209 JSScript::addIonCounts(jit::IonScriptCounts *ionCounts)
  1211     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
  1212     if (p->value().ionCounts)
  1213         ionCounts->setPrevious(p->value().ionCounts);
  1214     p->value().ionCounts = ionCounts;
  1217 jit::IonScriptCounts *
  1218 JSScript::getIonCounts()
  1220     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
  1221     return p->value().ionCounts;
  1224 ScriptCounts
  1225 JSScript::releaseScriptCounts()
  1227     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
  1228     ScriptCounts counts = p->value();
  1229     compartment()->scriptCountsMap->remove(p);
  1230     hasScriptCounts_ = false;
  1231     return counts;
  1234 void
  1235 JSScript::destroyScriptCounts(FreeOp *fop)
  1237     if (hasScriptCounts()) {
  1238         ScriptCounts scriptCounts = releaseScriptCounts();
  1239         scriptCounts.destroy(fop);
  1243 void
  1244 ScriptSourceObject::setSource(ScriptSource *source)
  1246     if (source)
  1247         source->incref();
  1248     if (this->source())
  1249         this->source()->decref();
  1250     setReservedSlot(SOURCE_SLOT, PrivateValue(source));
  1253 JSObject *
  1254 ScriptSourceObject::element() const
  1256     return getReservedSlot(ELEMENT_SLOT).toObjectOrNull();
  1259 void
  1260 ScriptSourceObject::initElement(HandleObject element)
  1262     JS_ASSERT(getReservedSlot(ELEMENT_SLOT).isNull());
  1263     setReservedSlot(ELEMENT_SLOT, ObjectOrNullValue(element));
  1266 const Value &
  1267 ScriptSourceObject::elementAttributeName() const
  1269     const Value &prop = getReservedSlot(ELEMENT_PROPERTY_SLOT);
  1270     JS_ASSERT(prop.isUndefined() || prop.isString());
  1271     return prop;
  1274 void
  1275 ScriptSourceObject::initIntroductionScript(JSScript *script)
  1277     JS_ASSERT(!getReservedSlot(INTRODUCTION_SCRIPT_SLOT).toPrivate());
  1279     // There is no equivalent of cross-compartment wrappers for scripts. If
  1280     // the introduction script would be in a different compartment from the
  1281     // compiled code, we would be creating a cross-compartment script
  1282     // reference, which would be bogus. In that case, just don't bother to
  1283     // retain the introduction script.
  1284     if (script && script->compartment() == compartment())
  1285         setReservedSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(script));
  1288 void
  1289 ScriptSourceObject::trace(JSTracer *trc, JSObject *obj)
  1291     ScriptSourceObject *sso = static_cast<ScriptSourceObject *>(obj);
  1293     if (JSScript *script = sso->introductionScript()) {
  1294         MarkScriptUnbarriered(trc, &script, "ScriptSourceObject introductionScript");
  1295         sso->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(script));
  1299 void
  1300 ScriptSourceObject::finalize(FreeOp *fop, JSObject *obj)
  1302     // ScriptSource::setSource automatically takes care of the refcount
  1303     obj->as<ScriptSourceObject>().setSource(nullptr);
  1306 const Class ScriptSourceObject::class_ = {
  1307     "ScriptSource",
  1308     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
  1309     JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_IS_ANONYMOUS,
  1310     JS_PropertyStub,        /* addProperty */
  1311     JS_DeletePropertyStub,  /* delProperty */
  1312     JS_PropertyStub,        /* getProperty */
  1313     JS_StrictPropertyStub,  /* setProperty */
  1314     JS_EnumerateStub,
  1315     JS_ResolveStub,
  1316     JS_ConvertStub,
  1317     finalize,
  1318     nullptr,                /* call        */
  1319     nullptr,                /* hasInstance */
  1320     nullptr,                /* construct   */
  1321     trace
  1322 };
  1324 ScriptSourceObject *
  1325 ScriptSourceObject::create(ExclusiveContext *cx, ScriptSource *source,
  1326                            const ReadOnlyCompileOptions &options)
  1328     RootedObject object(cx, NewObjectWithGivenProto(cx, &class_, nullptr, cx->global()));
  1329     if (!object)
  1330         return nullptr;
  1331     RootedScriptSource sourceObject(cx, &object->as<ScriptSourceObject>());
  1333     source->incref();
  1334     sourceObject->initSlot(SOURCE_SLOT, PrivateValue(source));
  1335     sourceObject->initSlot(ELEMENT_SLOT, ObjectOrNullValue(options.element()));
  1336     if (options.elementAttributeName())
  1337         sourceObject->initSlot(ELEMENT_PROPERTY_SLOT, StringValue(options.elementAttributeName()));
  1338     else
  1339         sourceObject->initSlot(ELEMENT_PROPERTY_SLOT, UndefinedValue());
  1341     sourceObject->initSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(nullptr));
  1342     sourceObject->initIntroductionScript(options.introductionScript());
  1344     return sourceObject;
  1347 static const unsigned char emptySource[] = "";
  1349 /* Adjust the amount of memory this script source uses for source data,
  1350    reallocating if needed. */
  1351 bool
  1352 ScriptSource::adjustDataSize(size_t nbytes)
  1354     // Allocating 0 bytes has undefined behavior, so special-case it.
  1355     if (nbytes == 0) {
  1356         if (data.compressed != emptySource)
  1357             js_free(data.compressed);
  1358         data.compressed = const_cast<unsigned char *>(emptySource);
  1359         return true;
  1362     // |data.compressed| can be nullptr.
  1363     void *buf = js_realloc(data.compressed, nbytes);
  1364     if (!buf && data.compressed != emptySource)
  1365         js_free(data.compressed);
  1366     data.compressed = static_cast<unsigned char *>(buf);
  1367     return !!data.compressed;
  1370 /* static */ bool
  1371 JSScript::loadSource(JSContext *cx, ScriptSource *ss, bool *worked)
  1373     JS_ASSERT(!ss->hasSourceData());
  1374     *worked = false;
  1375     if (!cx->runtime()->sourceHook || !ss->sourceRetrievable())
  1376         return true;
  1377     jschar *src = nullptr;
  1378     size_t length;
  1379     if (!cx->runtime()->sourceHook->load(cx, ss->filename(), &src, &length))
  1380         return false;
  1381     if (!src)
  1382         return true;
  1383     ss->setSource(src, length);
  1384     *worked = true;
  1385     return true;
  1388 JSFlatString *
  1389 JSScript::sourceData(JSContext *cx)
  1391     JS_ASSERT(scriptSource()->hasSourceData());
  1392     return scriptSource()->substring(cx, sourceStart(), sourceEnd());
  1395 SourceDataCache::AutoHoldEntry::AutoHoldEntry()
  1396   : cache_(nullptr), source_(nullptr), charsToFree_(nullptr)
  1400 void
  1401 SourceDataCache::AutoHoldEntry::holdEntry(SourceDataCache *cache, ScriptSource *source)
  1403     // Initialise the holder for a specific cache and script source. This will
  1404     // hold on to the cached source chars in the event that the cache is purged.
  1405     JS_ASSERT(!cache_ && !source_ && !charsToFree_);
  1406     cache_ = cache;
  1407     source_ = source;
  1410 void
  1411 SourceDataCache::AutoHoldEntry::deferDelete(const jschar *chars)
  1413     // Take ownership of source chars now the cache is being purged. Remove our
  1414     // reference to the ScriptSource which might soon be destroyed.
  1415     JS_ASSERT(cache_ && source_ && !charsToFree_);
  1416     cache_ = nullptr;
  1417     source_ = nullptr;
  1418     charsToFree_ = chars;
  1421 SourceDataCache::AutoHoldEntry::~AutoHoldEntry()
  1423     // The holder is going out of scope. If it has taken ownership of cached
  1424     // chars then delete them, otherwise unregister ourself with the cache.
  1425     if (charsToFree_) {
  1426         JS_ASSERT(!cache_ && !source_);
  1427         js_free(const_cast<jschar *>(charsToFree_));
  1428     } else if (cache_) {
  1429         JS_ASSERT(source_);
  1430         cache_->releaseEntry(*this);
  1434 void
  1435 SourceDataCache::holdEntry(AutoHoldEntry &holder, ScriptSource *ss)
  1437     JS_ASSERT(!holder_);
  1438     holder.holdEntry(this, ss);
  1439     holder_ = &holder;
  1442 void
  1443 SourceDataCache::releaseEntry(AutoHoldEntry &holder)
  1445     JS_ASSERT(holder_ == &holder);
  1446     holder_ = nullptr;
  1449 const jschar *
  1450 SourceDataCache::lookup(ScriptSource *ss, AutoHoldEntry &holder)
  1452     JS_ASSERT(!holder_);
  1453     if (!map_)
  1454         return nullptr;
  1455     if (Map::Ptr p = map_->lookup(ss)) {
  1456         holdEntry(holder, ss);
  1457         return p->value();
  1459     return nullptr;
  1462 bool
  1463 SourceDataCache::put(ScriptSource *ss, const jschar *str, AutoHoldEntry &holder)
  1465     JS_ASSERT(!holder_);
  1467     if (!map_) {
  1468         map_ = js_new<Map>();
  1469         if (!map_)
  1470             return false;
  1472         if (!map_->init()) {
  1473             js_delete(map_);
  1474             map_ = nullptr;
  1475             return false;
  1479     if (!map_->put(ss, str))
  1480         return false;
  1482     holdEntry(holder, ss);
  1483     return true;
  1486 void
  1487 SourceDataCache::purge()
  1489     if (!map_)
  1490         return;
  1492     for (Map::Range r = map_->all(); !r.empty(); r.popFront()) {
  1493         const jschar *chars = r.front().value();
  1494         if (holder_ && r.front().key() == holder_->source()) {
  1495             holder_->deferDelete(chars);
  1496             holder_ = nullptr;
  1497         } else {
  1498             js_free(const_cast<jschar*>(chars));
  1502     js_delete(map_);
  1503     map_ = nullptr;
  1506 size_t
  1507 SourceDataCache::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
  1509     size_t n = 0;
  1510     if (map_ && !map_->empty()) {
  1511         n += map_->sizeOfIncludingThis(mallocSizeOf);
  1512         for (Map::Range r = map_->all(); !r.empty(); r.popFront()) {
  1513             const jschar *v = r.front().value();
  1514             n += mallocSizeOf(v);
  1517     return n;
  1520 const jschar *
  1521 ScriptSource::chars(JSContext *cx, SourceDataCache::AutoHoldEntry &holder)
  1523     if (const jschar *chars = getOffThreadCompressionChars(cx))
  1524         return chars;
  1525     JS_ASSERT(ready());
  1527 #ifdef USE_ZLIB
  1528     if (compressed()) {
  1529         if (const jschar *decompressed = cx->runtime()->sourceDataCache.lookup(this, holder))
  1530             return decompressed;
  1532         const size_t nbytes = sizeof(jschar) * (length_ + 1);
  1533         jschar *decompressed = static_cast<jschar *>(js_malloc(nbytes));
  1534         if (!decompressed)
  1535             return nullptr;
  1537         if (!DecompressString(data.compressed, compressedLength_,
  1538                               reinterpret_cast<unsigned char *>(decompressed), nbytes)) {
  1539             JS_ReportOutOfMemory(cx);
  1540             js_free(decompressed);
  1541             return nullptr;
  1544         decompressed[length_] = 0;
  1546         if (!cx->runtime()->sourceDataCache.put(this, decompressed, holder)) {
  1547             JS_ReportOutOfMemory(cx);
  1548             js_free(decompressed);
  1549             return nullptr;
  1552         return decompressed;
  1554 #endif
  1555     return data.source;
  1558 JSFlatString *
  1559 ScriptSource::substring(JSContext *cx, uint32_t start, uint32_t stop)
  1561     JS_ASSERT(start <= stop);
  1562     SourceDataCache::AutoHoldEntry holder;
  1563     const jschar *chars = this->chars(cx, holder);
  1564     if (!chars)
  1565         return nullptr;
  1566     return js_NewStringCopyN<CanGC>(cx, chars + start, stop - start);
  1569 bool
  1570 ScriptSource::setSourceCopy(ExclusiveContext *cx, SourceBufferHolder &srcBuf,
  1571                             bool argumentsNotIncluded, SourceCompressionTask *task)
  1573     JS_ASSERT(!hasSourceData());
  1574     length_ = srcBuf.length();
  1575     argumentsNotIncluded_ = argumentsNotIncluded;
  1577     // There are several cases where source compression is not a good idea:
  1578     //  - If the script is tiny, then compression will save little or no space.
  1579     //  - If the script is enormous, then decompression can take seconds. With
  1580     //    lazy parsing, decompression is not uncommon, so this can significantly
  1581     //    increase latency.
  1582     //  - If there is only one core, then compression will contend with JS
  1583     //    execution (which hurts benchmarketing).
  1584     //  - If the source contains a giant string, then parsing will finish much
  1585     //    faster than compression which increases latency (this case is handled
  1586     //    in Parser::stringLiteral).
  1587     //
  1588     // Lastly, since the parsing thread will eventually perform a blocking wait
  1589     // on the compresion task's worker thread, require that there are at least 2
  1590     // worker threads:
  1591     //  - If we are on a worker thread, there must be another worker thread to
  1592     //    execute our compression task.
  1593     //  - If we are on the main thread, there must be at least two worker
  1594     //    threads since at most one worker thread can be blocking on the main
  1595     //    thread (see WorkerThreadState::canStartParseTask) which would cause a
  1596     //    deadlock if there wasn't a second worker thread that could make
  1597     //    progress on our compression task.
  1598 #ifdef JS_THREADSAFE
  1599     bool canCompressOffThread =
  1600         WorkerThreadState().cpuCount > 1 &&
  1601         WorkerThreadState().threadCount >= 2;
  1602 #else
  1603     bool canCompressOffThread = false;
  1604 #endif
  1605     const size_t TINY_SCRIPT = 256;
  1606     const size_t HUGE_SCRIPT = 5 * 1024 * 1024;
  1607     if (TINY_SCRIPT <= srcBuf.length() && srcBuf.length() < HUGE_SCRIPT && canCompressOffThread) {
  1608         task->ss = this;
  1609         task->chars = srcBuf.get();
  1610         ready_ = false;
  1611         if (!StartOffThreadCompression(cx, task))
  1612             return false;
  1613     } else if (srcBuf.ownsChars()) {
  1614         data.source = srcBuf.take();
  1615     } else {
  1616         if (!adjustDataSize(sizeof(jschar) * srcBuf.length()))
  1617             return false;
  1618         PodCopy(data.source, srcBuf.get(), length_);
  1621     return true;
  1624 void
  1625 ScriptSource::setSource(const jschar *src, size_t length)
  1627     JS_ASSERT(!hasSourceData());
  1628     length_ = length;
  1629     JS_ASSERT(!argumentsNotIncluded_);
  1630     data.source = const_cast<jschar *>(src);
  1633 bool
  1634 SourceCompressionTask::work()
  1636     // A given compression token can be compressed on any thread, and the ss
  1637     // not being ready indicates to other threads that its fields might change
  1638     // with no lock held.
  1639     JS_ASSERT(!ss->ready());
  1641     size_t compressedLength = 0;
  1642     size_t nbytes = sizeof(jschar) * ss->length_;
  1644     // Memory allocation functions on JSRuntime and JSContext are not
  1645     // threadsafe. We have to use the js_* variants.
  1647 #ifdef USE_ZLIB
  1648     // Try to keep the maximum memory usage down by only allocating half the
  1649     // size of the string, first.
  1650     size_t firstSize = nbytes / 2;
  1651     if (!ss->adjustDataSize(firstSize))
  1652         return false;
  1653     Compressor comp(reinterpret_cast<const unsigned char *>(chars), nbytes);
  1654     if (!comp.init())
  1655         return false;
  1656     comp.setOutput(ss->data.compressed, firstSize);
  1657     bool cont = !abort_;
  1658     while (cont) {
  1659         switch (comp.compressMore()) {
  1660           case Compressor::CONTINUE:
  1661             break;
  1662           case Compressor::MOREOUTPUT: {
  1663             if (comp.outWritten() == nbytes) {
  1664                 cont = false;
  1665                 break;
  1668             // The compressed output is greater than half the size of the
  1669             // original string. Reallocate to the full size.
  1670             if (!ss->adjustDataSize(nbytes))
  1671                 return false;
  1672             comp.setOutput(ss->data.compressed, nbytes);
  1673             break;
  1675           case Compressor::DONE:
  1676             cont = false;
  1677             break;
  1678           case Compressor::OOM:
  1679             return false;
  1681         cont = cont && !abort_;
  1683     compressedLength = comp.outWritten();
  1684     if (abort_ || compressedLength == nbytes)
  1685         compressedLength = 0;
  1686 #endif
  1688     if (compressedLength == 0) {
  1689         if (!ss->adjustDataSize(nbytes))
  1690             return false;
  1691         PodCopy(ss->data.source, chars, ss->length());
  1692     } else {
  1693         // Shrink the buffer to the size of the compressed data. Shouldn't fail.
  1694         JS_ALWAYS_TRUE(ss->adjustDataSize(compressedLength));
  1696     ss->compressedLength_ = compressedLength;
  1697     return true;
  1700 void
  1701 ScriptSource::destroy()
  1703     JS_ASSERT(ready());
  1704     adjustDataSize(0);
  1705     if (introducerFilename_ != filename_)
  1706         js_free(introducerFilename_);
  1707     js_free(filename_);
  1708     js_free(displayURL_);
  1709     js_free(sourceMapURL_);
  1710     if (originPrincipals_)
  1711         JS_DropPrincipals(TlsPerThreadData.get()->runtimeFromMainThread(), originPrincipals_);
  1712     ready_ = false;
  1713     js_free(this);
  1716 void
  1717 ScriptSource::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
  1718                                      JS::ScriptSourceInfo *info) const
  1720     if (ready() && data.compressed != emptySource) {
  1721         if (compressed())
  1722             info->compressed += mallocSizeOf(data.compressed);
  1723         else
  1724             info->uncompressed += mallocSizeOf(data.source);
  1726     info->misc += mallocSizeOf(this) + mallocSizeOf(filename_);
  1727     info->numScripts++;
  1730 template<XDRMode mode>
  1731 bool
  1732 ScriptSource::performXDR(XDRState<mode> *xdr)
  1734     uint8_t hasSource = hasSourceData();
  1735     if (!xdr->codeUint8(&hasSource))
  1736         return false;
  1738     uint8_t retrievable = sourceRetrievable_;
  1739     if (!xdr->codeUint8(&retrievable))
  1740         return false;
  1741     sourceRetrievable_ = retrievable;
  1743     if (hasSource && !sourceRetrievable_) {
  1744         // Only set members when we know decoding cannot fail. This prevents the
  1745         // script source from being partially initialized.
  1746         uint32_t length = length_;
  1747         if (!xdr->codeUint32(&length))
  1748             return false;
  1750         uint32_t compressedLength = compressedLength_;
  1751         if (!xdr->codeUint32(&compressedLength))
  1752             return false;
  1754         uint8_t argumentsNotIncluded = argumentsNotIncluded_;
  1755         if (!xdr->codeUint8(&argumentsNotIncluded))
  1756             return false;
  1758         size_t byteLen = compressedLength ? compressedLength : (length * sizeof(jschar));
  1759         if (mode == XDR_DECODE) {
  1760             if (!adjustDataSize(byteLen))
  1761                 return false;
  1763         if (!xdr->codeBytes(data.compressed, byteLen)) {
  1764             if (mode == XDR_DECODE) {
  1765                 js_free(data.compressed);
  1766                 data.compressed = nullptr;
  1768             return false;
  1770         length_ = length;
  1771         compressedLength_ = compressedLength;
  1772         argumentsNotIncluded_ = argumentsNotIncluded;
  1775     uint8_t haveSourceMap = hasSourceMapURL();
  1776     if (!xdr->codeUint8(&haveSourceMap))
  1777         return false;
  1779     if (haveSourceMap) {
  1780         uint32_t sourceMapURLLen = (mode == XDR_DECODE) ? 0 : js_strlen(sourceMapURL_);
  1781         if (!xdr->codeUint32(&sourceMapURLLen))
  1782             return false;
  1784         if (mode == XDR_DECODE) {
  1785             size_t byteLen = (sourceMapURLLen + 1) * sizeof(jschar);
  1786             sourceMapURL_ = static_cast<jschar *>(xdr->cx()->malloc_(byteLen));
  1787             if (!sourceMapURL_)
  1788                 return false;
  1790         if (!xdr->codeChars(sourceMapURL_, sourceMapURLLen)) {
  1791             if (mode == XDR_DECODE) {
  1792                 js_free(sourceMapURL_);
  1793                 sourceMapURL_ = nullptr;
  1795             return false;
  1797         sourceMapURL_[sourceMapURLLen] = '\0';
  1800     uint8_t haveDisplayURL = hasDisplayURL();
  1801     if (!xdr->codeUint8(&haveDisplayURL))
  1802         return false;
  1804     if (haveDisplayURL) {
  1805         uint32_t displayURLLen = (mode == XDR_DECODE) ? 0 : js_strlen(displayURL_);
  1806         if (!xdr->codeUint32(&displayURLLen))
  1807             return false;
  1809         if (mode == XDR_DECODE) {
  1810             size_t byteLen = (displayURLLen + 1) * sizeof(jschar);
  1811             displayURL_ = static_cast<jschar *>(xdr->cx()->malloc_(byteLen));
  1812             if (!displayURL_)
  1813                 return false;
  1815         if (!xdr->codeChars(displayURL_, displayURLLen)) {
  1816             if (mode == XDR_DECODE) {
  1817                 js_free(displayURL_);
  1818                 displayURL_ = nullptr;
  1820             return false;
  1822         displayURL_[displayURLLen] = '\0';
  1825     uint8_t haveFilename = !!filename_;
  1826     if (!xdr->codeUint8(&haveFilename))
  1827         return false;
  1829     if (haveFilename) {
  1830         const char *fn = filename();
  1831         if (!xdr->codeCString(&fn))
  1832             return false;
  1833         if (mode == XDR_DECODE && !setFilename(xdr->cx(), fn))
  1834             return false;
  1837     if (mode == XDR_DECODE)
  1838         ready_ = true;
  1840     return true;
  1843 // Format and return a cx->malloc_'ed URL for a generated script like:
  1844 //   {filename} line {lineno} > {introducer}
  1845 // For example:
  1846 //   foo.js line 7 > eval
  1847 // indicating code compiled by the call to 'eval' on line 7 of foo.js.
  1848 static char *
  1849 FormatIntroducedFilename(ExclusiveContext *cx, const char *filename, unsigned lineno,
  1850                          const char *introducer)
  1852     // Compute the length of the string in advance, so we can allocate a
  1853     // buffer of the right size on the first shot.
  1854     //
  1855     // (JS_smprintf would be perfect, as that allocates the result
  1856     // dynamically as it formats the string, but it won't allocate from cx,
  1857     // and wants us to use a special free function.)
  1858     char linenoBuf[15];
  1859     size_t filenameLen = strlen(filename);
  1860     size_t linenoLen = JS_snprintf(linenoBuf, 15, "%u", lineno);
  1861     size_t introducerLen = strlen(introducer);
  1862     size_t len = filenameLen                    +
  1863                  6 /* == strlen(" line ") */    +
  1864                  linenoLen                      +
  1865                  3 /* == strlen(" > ") */       +
  1866                  introducerLen                  +
  1867                  1 /* \0 */;
  1868     char *formatted = cx->pod_malloc<char>(len);
  1869     if (!formatted)
  1870         return nullptr;
  1871     mozilla::DebugOnly<size_t> checkLen = JS_snprintf(formatted, len, "%s line %s > %s",
  1872                                                       filename, linenoBuf, introducer);
  1873     JS_ASSERT(checkLen == len - 1);
  1875     return formatted;
  1878 bool
  1879 ScriptSource::initFromOptions(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
  1881     JS_ASSERT(!filename_);
  1882     JS_ASSERT(!introducerFilename_);
  1884     originPrincipals_ = options.originPrincipals(cx);
  1885     if (originPrincipals_)
  1886         JS_HoldPrincipals(originPrincipals_);
  1888     introductionType_ = options.introductionType;
  1889     setIntroductionOffset(options.introductionOffset);
  1891     if (options.hasIntroductionInfo) {
  1892         JS_ASSERT(options.introductionType != nullptr);
  1893         const char *filename = options.filename() ? options.filename() : "<unknown>";
  1894         char *formatted = FormatIntroducedFilename(cx, filename, options.introductionLineno,
  1895                                                    options.introductionType);
  1896         if (!formatted)
  1897             return false;
  1898         filename_ = formatted;
  1899     } else if (options.filename()) {
  1900         if (!setFilename(cx, options.filename()))
  1901             return false;
  1904     if (options.introducerFilename()) {
  1905         introducerFilename_ = js_strdup(cx, options.introducerFilename());
  1906         if (!introducerFilename_)
  1907             return false;
  1908     } else {
  1909         introducerFilename_ = filename_;
  1912     return true;
  1915 bool
  1916 ScriptSource::setFilename(ExclusiveContext *cx, const char *filename)
  1918     JS_ASSERT(!filename_);
  1919     filename_ = js_strdup(cx, filename);
  1920     if (!filename_)
  1921         return false;
  1922     return true;
  1925 bool
  1926 ScriptSource::setDisplayURL(ExclusiveContext *cx, const jschar *displayURL)
  1928     JS_ASSERT(displayURL);
  1929     if (hasDisplayURL()) {
  1930         if (cx->isJSContext() &&
  1931             !JS_ReportErrorFlagsAndNumber(cx->asJSContext(), JSREPORT_WARNING,
  1932                                           js_GetErrorMessage, nullptr,
  1933                                           JSMSG_ALREADY_HAS_PRAGMA, filename_,
  1934                                           "//# sourceURL"))
  1936             return false;
  1939     size_t len = js_strlen(displayURL) + 1;
  1940     if (len == 1)
  1941         return true;
  1942     displayURL_ = js_strdup(cx, displayURL);
  1943     if (!displayURL_)
  1944         return false;
  1945     return true;
  1948 const jschar *
  1949 ScriptSource::displayURL()
  1951     JS_ASSERT(hasDisplayURL());
  1952     return displayURL_;
  1955 bool
  1956 ScriptSource::setSourceMapURL(ExclusiveContext *cx, const jschar *sourceMapURL)
  1958     JS_ASSERT(sourceMapURL);
  1959     if (hasSourceMapURL()) {
  1960         if (cx->isJSContext() &&
  1961             !JS_ReportErrorFlagsAndNumber(cx->asJSContext(), JSREPORT_WARNING,
  1962                                           js_GetErrorMessage, nullptr,
  1963                                           JSMSG_ALREADY_HAS_PRAGMA, filename_,
  1964                                           "//# sourceMappingURL"))
  1966             return false;
  1970     size_t len = js_strlen(sourceMapURL) + 1;
  1971     if (len == 1)
  1972         return true;
  1973     sourceMapURL_ = js_strdup(cx, sourceMapURL);
  1974     if (!sourceMapURL_)
  1975         return false;
  1976     return true;
  1979 const jschar *
  1980 ScriptSource::sourceMapURL()
  1982     JS_ASSERT(hasSourceMapURL());
  1983     return sourceMapURL_;
  1986 /*
  1987  * Shared script data management.
  1988  */
  1990 SharedScriptData *
  1991 js::SharedScriptData::new_(ExclusiveContext *cx, uint32_t codeLength,
  1992                            uint32_t srcnotesLength, uint32_t natoms)
  1994     /*
  1995      * Ensure the atoms are aligned, as some architectures don't allow unaligned
  1996      * access.
  1997      */
  1998     const uint32_t pointerSize = sizeof(JSAtom *);
  1999     const uint32_t pointerMask = pointerSize - 1;
  2000     const uint32_t dataOffset = offsetof(SharedScriptData, data);
  2001     uint32_t baseLength = codeLength + srcnotesLength;
  2002     uint32_t padding = (pointerSize - ((baseLength + dataOffset) & pointerMask)) & pointerMask;
  2003     uint32_t length = baseLength + padding + pointerSize * natoms;
  2005     SharedScriptData *entry = (SharedScriptData *)cx->malloc_(length + dataOffset);
  2006     if (!entry)
  2007         return nullptr;
  2009     entry->length = length;
  2010     entry->natoms = natoms;
  2011     entry->marked = false;
  2012     memset(entry->data + baseLength, 0, padding);
  2014     /*
  2015      * Call constructors to initialize the storage that will be accessed as a
  2016      * HeapPtrAtom array via atoms().
  2017      */
  2018     HeapPtrAtom *atoms = entry->atoms();
  2019     JS_ASSERT(reinterpret_cast<uintptr_t>(atoms) % sizeof(JSAtom *) == 0);
  2020     for (unsigned i = 0; i < natoms; ++i)
  2021         new (&atoms[i]) HeapPtrAtom();
  2023     return entry;
  2026 /*
  2027  * Takes ownership of its *ssd parameter and either adds it into the runtime's
  2028  * ScriptDataTable or frees it if a matching entry already exists.
  2030  * Sets the |code| and |atoms| fields on the given JSScript.
  2031  */
  2032 static bool
  2033 SaveSharedScriptData(ExclusiveContext *cx, Handle<JSScript *> script, SharedScriptData *ssd,
  2034                      uint32_t nsrcnotes)
  2036     ASSERT(script != nullptr);
  2037     ASSERT(ssd != nullptr);
  2039     AutoLockForExclusiveAccess lock(cx);
  2041     ScriptBytecodeHasher::Lookup l(ssd);
  2043     ScriptDataTable::AddPtr p = cx->scriptDataTable().lookupForAdd(l);
  2044     if (p) {
  2045         js_free(ssd);
  2046         ssd = *p;
  2047     } else {
  2048         if (!cx->scriptDataTable().add(p, ssd)) {
  2049             script->setCode(nullptr);
  2050             script->atoms = nullptr;
  2051             js_free(ssd);
  2052             js_ReportOutOfMemory(cx);
  2053             return false;
  2057 #ifdef JSGC_INCREMENTAL
  2058     /*
  2059      * During the IGC we need to ensure that bytecode is marked whenever it is
  2060      * accessed even if the bytecode was already in the table: at this point
  2061      * old scripts or exceptions pointing to the bytecode may no longer be
  2062      * reachable. This is effectively a read barrier.
  2063      */
  2064     if (cx->isJSContext()) {
  2065         JSRuntime *rt = cx->asJSContext()->runtime();
  2066         if (JS::IsIncrementalGCInProgress(rt) && rt->gcIsFull)
  2067             ssd->marked = true;
  2069 #endif
  2071     script->setCode(ssd->data);
  2072     script->atoms = ssd->atoms();
  2073     return true;
  2076 static inline void
  2077 MarkScriptData(JSRuntime *rt, const jsbytecode *bytecode)
  2079     /*
  2080      * As an invariant, a ScriptBytecodeEntry should not be 'marked' outside of
  2081      * a GC. Since SweepScriptBytecodes is only called during a full gc,
  2082      * to preserve this invariant, only mark during a full gc.
  2083      */
  2084     if (rt->gcIsFull)
  2085         SharedScriptData::fromBytecode(bytecode)->marked = true;
  2088 void
  2089 js::UnmarkScriptData(JSRuntime *rt)
  2091     JS_ASSERT(rt->gcIsFull);
  2092     ScriptDataTable &table = rt->scriptDataTable();
  2093     for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront()) {
  2094         SharedScriptData *entry = e.front();
  2095         entry->marked = false;
  2099 void
  2100 js::SweepScriptData(JSRuntime *rt)
  2102     JS_ASSERT(rt->gcIsFull);
  2103     ScriptDataTable &table = rt->scriptDataTable();
  2105     if (rt->keepAtoms())
  2106         return;
  2108     for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront()) {
  2109         SharedScriptData *entry = e.front();
  2110         if (!entry->marked) {
  2111             js_free(entry);
  2112             e.removeFront();
  2117 void
  2118 js::FreeScriptData(JSRuntime *rt)
  2120     ScriptDataTable &table = rt->scriptDataTable();
  2121     if (!table.initialized())
  2122         return;
  2124     for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront())
  2125         js_free(e.front());
  2127     table.clear();
  2130 /*
  2131  * JSScript::data and SharedScriptData::data have complex,
  2132  * manually-controlled, memory layouts.
  2134  * JSScript::data begins with some optional array headers. They are optional
  2135  * because they often aren't needed, i.e. the corresponding arrays often have
  2136  * zero elements. Each header has a bit in JSScript::hasArrayBits that
  2137  * indicates if it's present within |data|; from this the offset of each
  2138  * present array header can be computed. Each header has an accessor function
  2139  * in JSScript that encapsulates this offset computation.
  2141  * Array type       Array elements  Accessor
  2142  * ----------       --------------  --------
  2143  * ConstArray       Consts          consts()
  2144  * ObjectArray      Objects         objects()
  2145  * ObjectArray      Regexps         regexps()
  2146  * TryNoteArray     Try notes       trynotes()
  2147  * BlockScopeArray  Scope notes     blockScopes()
  2149  * Then are the elements of several arrays.
  2150  * - Most of these arrays have headers listed above (if present). For each of
  2151  *   these, the array pointer and the array length is stored in the header.
  2152  * - The remaining arrays have pointers and lengths that are stored directly in
  2153  *   JSScript. This is because, unlike the others, they are nearly always
  2154  *   non-zero length and so the optional-header space optimization isn't
  2155  *   worthwhile.
  2157  * Array elements   Pointed to by         Length
  2158  * --------------   -------------         ------
  2159  * Consts           consts()->vector      consts()->length
  2160  * Objects          objects()->vector     objects()->length
  2161  * Regexps          regexps()->vector     regexps()->length
  2162  * Try notes        trynotes()->vector    trynotes()->length
  2163  * Scope notes      blockScopes()->vector blockScopes()->length
  2165  * IMPORTANT: This layout has two key properties.
  2166  * - It ensures that everything has sufficient alignment; in particular, the
  2167  *   consts() elements need jsval alignment.
  2168  * - It ensures there are no gaps between elements, which saves space and makes
  2169  *   manual layout easy. In particular, in the second part, arrays with larger
  2170  *   elements precede arrays with smaller elements.
  2172  * SharedScriptData::data contains data that can be shared within a
  2173  * runtime. These items' layout is manually controlled to make it easier to
  2174  * manage both during (temporary) allocation and during matching against
  2175  * existing entries in the runtime. As the jsbytecode has to come first to
  2176  * enable lookup by bytecode identity, SharedScriptData::data, the atoms part
  2177  * has to manually be aligned sufficiently by adding padding after the notes
  2178  * part.
  2180  * Array elements   Pointed to by         Length
  2181  * --------------   -------------         ------
  2182  * jsbytecode       code                  length
  2183  * jsscrnote        notes()               numNotes()
  2184  * Atoms            atoms                 natoms
  2186  * The following static assertions check JSScript::data's alignment properties.
  2187  */
  2189 #define KEEPS_JSVAL_ALIGNMENT(T) \
  2190     (JS_ALIGNMENT_OF(jsval) % JS_ALIGNMENT_OF(T) == 0 && \
  2191      sizeof(T) % sizeof(jsval) == 0)
  2193 #define HAS_JSVAL_ALIGNMENT(T) \
  2194     (JS_ALIGNMENT_OF(jsval) == JS_ALIGNMENT_OF(T) && \
  2195      sizeof(T) == sizeof(jsval))
  2197 #define NO_PADDING_BETWEEN_ENTRIES(T1, T2) \
  2198     (JS_ALIGNMENT_OF(T1) % JS_ALIGNMENT_OF(T2) == 0)
  2200 /*
  2201  * These assertions ensure that there is no padding between the array headers,
  2202  * and also that the consts() elements (which follow immediately afterward) are
  2203  * jsval-aligned.  (There is an assumption that |data| itself is jsval-aligned;
  2204  * we check this below).
  2205  */
  2206 JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ConstArray));
  2207 JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(ObjectArray));       /* there are two of these */
  2208 JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(TryNoteArray));
  2209 JS_STATIC_ASSERT(KEEPS_JSVAL_ALIGNMENT(BlockScopeArray));
  2211 /* These assertions ensure there is no padding required between array elements. */
  2212 JS_STATIC_ASSERT(HAS_JSVAL_ALIGNMENT(HeapValue));
  2213 JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapValue, HeapPtrObject));
  2214 JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, HeapPtrObject));
  2215 JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, JSTryNote));
  2216 JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(JSTryNote, uint32_t));
  2217 JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(uint32_t, uint32_t));
  2219 JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapValue, BlockScopeNote));
  2220 JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(BlockScopeNote, BlockScopeNote));
  2221 JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(JSTryNote, BlockScopeNote));
  2222 JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(HeapPtrObject, BlockScopeNote));
  2223 JS_STATIC_ASSERT(NO_PADDING_BETWEEN_ENTRIES(BlockScopeNote, uint32_t));
  2225 static inline size_t
  2226 ScriptDataSize(uint32_t nbindings, uint32_t nconsts, uint32_t nobjects, uint32_t nregexps,
  2227                uint32_t ntrynotes, uint32_t nblockscopes)
  2229     size_t size = 0;
  2231     if (nconsts != 0)
  2232         size += sizeof(ConstArray) + nconsts * sizeof(Value);
  2233     if (nobjects != 0)
  2234         size += sizeof(ObjectArray) + nobjects * sizeof(JSObject *);
  2235     if (nregexps != 0)
  2236         size += sizeof(ObjectArray) + nregexps * sizeof(JSObject *);
  2237     if (ntrynotes != 0)
  2238         size += sizeof(TryNoteArray) + ntrynotes * sizeof(JSTryNote);
  2239     if (nblockscopes != 0)
  2240         size += sizeof(BlockScopeArray) + nblockscopes * sizeof(BlockScopeNote);
  2242     if (nbindings != 0) {
  2243 	// Make sure bindings are sufficiently aligned.
  2244         size = JS_ROUNDUP(size, JS_ALIGNMENT_OF(Binding)) + nbindings * sizeof(Binding);
  2247     return size;
  2250 void
  2251 JSScript::initCompartment(ExclusiveContext *cx)
  2253     compartment_ = cx->compartment_;
  2256 JSScript *
  2257 JSScript::Create(ExclusiveContext *cx, HandleObject enclosingScope, bool savedCallerFun,
  2258                  const ReadOnlyCompileOptions &options, unsigned staticLevel,
  2259                  HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd)
  2261     JS_ASSERT(bufStart <= bufEnd);
  2263     RootedScript script(cx, js_NewGCScript(cx));
  2264     if (!script)
  2265         return nullptr;
  2267     PodZero(script.get());
  2268     new (&script->bindings) Bindings;
  2270     script->enclosingScopeOrOriginalFunction_ = enclosingScope;
  2271     script->savedCallerFun_ = savedCallerFun;
  2272     script->initCompartment(cx);
  2274     script->compileAndGo_ = options.compileAndGo;
  2275     script->selfHosted_ = options.selfHostingMode;
  2276     script->noScriptRval_ = options.noScriptRval;
  2278     script->version = options.version;
  2279     JS_ASSERT(script->getVersion() == options.version);     // assert that no overflow occurred
  2281     // This is an unsigned-to-uint16_t conversion, test for too-high values.
  2282     // In practice, recursion in Parser and/or BytecodeEmitter will blow the
  2283     // stack if we nest functions more than a few hundred deep, so this will
  2284     // never trigger.  Oh well.
  2285     if (staticLevel > UINT16_MAX) {
  2286         if (cx->isJSContext()) {
  2287             JS_ReportErrorNumber(cx->asJSContext(),
  2288                                  js_GetErrorMessage, nullptr, JSMSG_TOO_DEEP, js_function_str);
  2290         return nullptr;
  2292     script->staticLevel_ = uint16_t(staticLevel);
  2294     script->setSourceObject(sourceObject);
  2295     script->sourceStart_ = bufStart;
  2296     script->sourceEnd_ = bufEnd;
  2298     return script;
  2301 static inline uint8_t *
  2302 AllocScriptData(ExclusiveContext *cx, size_t size)
  2304     uint8_t *data = static_cast<uint8_t *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value))));
  2305     if (!data)
  2306         return nullptr;
  2308     // All script data is optional, so size might be 0. In that case, we don't care about alignment.
  2309     JS_ASSERT(size == 0 || size_t(data) % sizeof(Value) == 0);
  2310     return data;
  2313 /* static */ bool
  2314 JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t nconsts,
  2315                         uint32_t nobjects, uint32_t nregexps, uint32_t ntrynotes,
  2316                         uint32_t nblockscopes, uint32_t nTypeSets)
  2318     size_t size = ScriptDataSize(script->bindings.count(), nconsts, nobjects, nregexps, ntrynotes,
  2319                                  nblockscopes);
  2320     if (size > 0) {
  2321         script->data = AllocScriptData(cx, size);
  2322         if (!script->data)
  2323             return false;
  2324     } else {
  2325         script->data = nullptr;
  2327     script->dataSize_ = size;
  2329     JS_ASSERT(nTypeSets <= UINT16_MAX);
  2330     script->nTypeSets_ = uint16_t(nTypeSets);
  2332     uint8_t *cursor = script->data;
  2333     if (nconsts != 0) {
  2334         script->setHasArray(CONSTS);
  2335         cursor += sizeof(ConstArray);
  2337     if (nobjects != 0) {
  2338         script->setHasArray(OBJECTS);
  2339         cursor += sizeof(ObjectArray);
  2341     if (nregexps != 0) {
  2342         script->setHasArray(REGEXPS);
  2343         cursor += sizeof(ObjectArray);
  2345     if (ntrynotes != 0) {
  2346         script->setHasArray(TRYNOTES);
  2347         cursor += sizeof(TryNoteArray);
  2349     if (nblockscopes != 0) {
  2350         script->setHasArray(BLOCK_SCOPES);
  2351         cursor += sizeof(BlockScopeArray);
  2354     if (nconsts != 0) {
  2355         JS_ASSERT(reinterpret_cast<uintptr_t>(cursor) % sizeof(jsval) == 0);
  2356         script->consts()->length = nconsts;
  2357         script->consts()->vector = (HeapValue *)cursor;
  2358         cursor += nconsts * sizeof(script->consts()->vector[0]);
  2361     if (nobjects != 0) {
  2362         script->objects()->length = nobjects;
  2363         script->objects()->vector = (HeapPtr<JSObject> *)cursor;
  2364         cursor += nobjects * sizeof(script->objects()->vector[0]);
  2367     if (nregexps != 0) {
  2368         script->regexps()->length = nregexps;
  2369         script->regexps()->vector = (HeapPtr<JSObject> *)cursor;
  2370         cursor += nregexps * sizeof(script->regexps()->vector[0]);
  2373     if (ntrynotes != 0) {
  2374         script->trynotes()->length = ntrynotes;
  2375         script->trynotes()->vector = reinterpret_cast<JSTryNote *>(cursor);
  2376         size_t vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
  2377 #ifdef DEBUG
  2378         memset(cursor, 0, vectorSize);
  2379 #endif
  2380         cursor += vectorSize;
  2383     if (nblockscopes != 0) {
  2384         script->blockScopes()->length = nblockscopes;
  2385         script->blockScopes()->vector = reinterpret_cast<BlockScopeNote *>(cursor);
  2386         size_t vectorSize = nblockscopes * sizeof(script->blockScopes()->vector[0]);
  2387 #ifdef DEBUG
  2388         memset(cursor, 0, vectorSize);
  2389 #endif
  2390         cursor += vectorSize;
  2393     if (script->bindings.count() != 0) {
  2394 	// Make sure bindings are sufficiently aligned.
  2395 	cursor = reinterpret_cast<uint8_t*>
  2396 	    (JS_ROUNDUP(reinterpret_cast<uintptr_t>(cursor), JS_ALIGNMENT_OF(Binding)));
  2398     cursor = script->bindings.switchToScriptStorage(reinterpret_cast<Binding *>(cursor));
  2400     JS_ASSERT(cursor == script->data + size);
  2401     return true;
  2404 /* static */ bool
  2405 JSScript::fullyInitTrivial(ExclusiveContext *cx, Handle<JSScript*> script)
  2407     if (!partiallyInit(cx, script, 0, 0, 0, 0, 0, 0))
  2408         return false;
  2410     SharedScriptData *ssd = SharedScriptData::new_(cx, 1, 1, 0);
  2411     if (!ssd)
  2412         return false;
  2414     ssd->data[0] = JSOP_RETRVAL;
  2415     ssd->data[1] = SRC_NULL;
  2416     script->setLength(1);
  2417     return SaveSharedScriptData(cx, script, ssd, 1);
  2420 /* static */ bool
  2421 JSScript::fullyInitFromEmitter(ExclusiveContext *cx, HandleScript script, BytecodeEmitter *bce)
  2423     /* The counts of indexed things must be checked during code generation. */
  2424     JS_ASSERT(bce->atomIndices->count() <= INDEX_LIMIT);
  2425     JS_ASSERT(bce->objectList.length <= INDEX_LIMIT);
  2426     JS_ASSERT(bce->regexpList.length <= INDEX_LIMIT);
  2428     uint32_t mainLength = bce->offset();
  2429     uint32_t prologLength = bce->prologOffset();
  2430     uint32_t nsrcnotes;
  2431     if (!FinishTakingSrcNotes(cx, bce, &nsrcnotes))
  2432         return false;
  2433     uint32_t natoms = bce->atomIndices->count();
  2434     if (!partiallyInit(cx, script,
  2435                        bce->constList.length(), bce->objectList.length, bce->regexpList.length,
  2436                        bce->tryNoteList.length(), bce->blockScopeList.length(), bce->typesetCount))
  2438         return false;
  2441     JS_ASSERT(script->mainOffset() == 0);
  2442     script->mainOffset_ = prologLength;
  2444     script->lineno_ = bce->firstLine;
  2446     script->setLength(prologLength + mainLength);
  2447     script->natoms_ = natoms;
  2448     SharedScriptData *ssd = SharedScriptData::new_(cx, script->length(), nsrcnotes, natoms);
  2449     if (!ssd)
  2450         return false;
  2452     jsbytecode *code = ssd->data;
  2453     PodCopy<jsbytecode>(code, bce->prolog.code.begin(), prologLength);
  2454     PodCopy<jsbytecode>(code + prologLength, bce->code().begin(), mainLength);
  2455     CopySrcNotes(bce, (jssrcnote *)(code + script->length()), nsrcnotes);
  2456     InitAtomMap(bce->atomIndices.getMap(), ssd->atoms());
  2458     if (!SaveSharedScriptData(cx, script, ssd, nsrcnotes))
  2459         return false;
  2461     FunctionBox *funbox = bce->sc->isFunctionBox() ? bce->sc->asFunctionBox() : nullptr;
  2463     if (bce->constList.length() != 0)
  2464         bce->constList.finish(script->consts());
  2465     if (bce->objectList.length != 0)
  2466         bce->objectList.finish(script->objects());
  2467     if (bce->regexpList.length != 0)
  2468         bce->regexpList.finish(script->regexps());
  2469     if (bce->tryNoteList.length() != 0)
  2470         bce->tryNoteList.finish(script->trynotes());
  2471     if (bce->blockScopeList.length() != 0)
  2472         bce->blockScopeList.finish(script->blockScopes());
  2473     script->strict_ = bce->sc->strict;
  2474     script->explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
  2475     script->bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
  2476     script->funHasExtensibleScope_ = funbox ? funbox->hasExtensibleScope() : false;
  2477     script->funNeedsDeclEnvObject_ = funbox ? funbox->needsDeclEnvObject() : false;
  2478     script->hasSingletons_ = bce->hasSingletons;
  2480     if (funbox) {
  2481         if (funbox->argumentsHasLocalBinding()) {
  2482             // This must precede the script->bindings.transfer() call below
  2483             script->setArgumentsHasVarBinding();
  2484             if (funbox->definitelyNeedsArgsObj())
  2485                 script->setNeedsArgsObj(true);
  2486         } else {
  2487             JS_ASSERT(!funbox->definitelyNeedsArgsObj());
  2490         script->funLength_ = funbox->length;
  2493     RootedFunction fun(cx, nullptr);
  2494     if (funbox) {
  2495         JS_ASSERT(!bce->script->noScriptRval());
  2496         script->isGeneratorExp_ = funbox->inGenexpLambda;
  2497         script->setGeneratorKind(funbox->generatorKind());
  2498         script->setFunction(funbox->function());
  2501     // The call to nfixed() depends on the above setFunction() call.
  2502     if (UINT32_MAX - script->nfixed() < bce->maxStackDepth) {
  2503         bce->reportError(nullptr, JSMSG_NEED_DIET, "script");
  2504         return false;
  2506     script->nslots_ = script->nfixed() + bce->maxStackDepth;
  2508     for (unsigned i = 0, n = script->bindings.numArgs(); i < n; ++i) {
  2509         if (script->formalIsAliased(i)) {
  2510             script->funHasAnyAliasedFormal_ = true;
  2511             break;
  2515     return true;
  2518 size_t
  2519 JSScript::computedSizeOfData() const
  2521     return dataSize();
  2524 size_t
  2525 JSScript::sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const
  2527     return mallocSizeOf(data);
  2530 size_t
  2531 JSScript::sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const
  2533     return types->sizeOfIncludingThis(mallocSizeOf);
  2536 /*
  2537  * Nb: srcnotes are variable-length.  This function computes the number of
  2538  * srcnote *slots*, which may be greater than the number of srcnotes.
  2539  */
  2540 uint32_t
  2541 JSScript::numNotes()
  2543     jssrcnote *sn;
  2544     jssrcnote *notes_ = notes();
  2545     for (sn = notes_; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
  2546         continue;
  2547     return sn - notes_ + 1;    /* +1 for the terminator */
  2550 js::GlobalObject&
  2551 JSScript::uninlinedGlobal() const
  2553     return global();
  2556 void
  2557 js::CallNewScriptHook(JSContext *cx, HandleScript script, HandleFunction fun)
  2559     if (script->selfHosted())
  2560         return;
  2562     JS_ASSERT(!script->isActiveEval());
  2563     if (JSNewScriptHook hook = cx->runtime()->debugHooks.newScriptHook) {
  2564         AutoKeepAtoms keepAtoms(cx->perThreadData);
  2565         hook(cx, script->filename(), script->lineno(), script, fun,
  2566              cx->runtime()->debugHooks.newScriptHookData);
  2570 void
  2571 js::CallDestroyScriptHook(FreeOp *fop, JSScript *script)
  2573     if (script->selfHosted())
  2574         return;
  2576     // The hook will only call into JS if a GC is not running.
  2577     if (JSDestroyScriptHook hook = fop->runtime()->debugHooks.destroyScriptHook)
  2578         hook(fop, script, fop->runtime()->debugHooks.destroyScriptHookData);
  2579     script->clearTraps(fop);
  2582 void
  2583 JSScript::finalize(FreeOp *fop)
  2585     // NOTE: this JSScript may be partially initialized at this point.  E.g. we
  2586     // may have created it and partially initialized it with
  2587     // JSScript::Create(), but not yet finished initializing it with
  2588     // fullyInitFromEmitter() or fullyInitTrivial().
  2590     CallDestroyScriptHook(fop, this);
  2591     fop->runtime()->spsProfiler.onScriptFinalized(this);
  2593     if (types)
  2594         types->destroy();
  2596 #ifdef JS_ION
  2597     jit::DestroyIonScripts(fop, this);
  2598 #endif
  2600     destroyScriptCounts(fop);
  2601     destroyDebugScript(fop);
  2603     if (data) {
  2604         JS_POISON(data, 0xdb, computedSizeOfData());
  2605         fop->free_(data);
  2608     fop->runtime()->lazyScriptCache.remove(this);
  2611 static const uint32_t GSN_CACHE_THRESHOLD = 100;
  2613 void
  2614 GSNCache::purge()
  2616     code = nullptr;
  2617     if (map.initialized())
  2618         map.finish();
  2621 jssrcnote *
  2622 js::GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc)
  2624     size_t target = pc - script->code();
  2625     if (target >= script->length())
  2626         return nullptr;
  2628     if (cache.code == script->code()) {
  2629         JS_ASSERT(cache.map.initialized());
  2630         GSNCache::Map::Ptr p = cache.map.lookup(pc);
  2631         return p ? p->value() : nullptr;
  2634     size_t offset = 0;
  2635     jssrcnote *result;
  2636     for (jssrcnote *sn = script->notes(); ; sn = SN_NEXT(sn)) {
  2637         if (SN_IS_TERMINATOR(sn)) {
  2638             result = nullptr;
  2639             break;
  2641         offset += SN_DELTA(sn);
  2642         if (offset == target && SN_IS_GETTABLE(sn)) {
  2643             result = sn;
  2644             break;
  2648     if (cache.code != script->code() && script->length() >= GSN_CACHE_THRESHOLD) {
  2649         unsigned nsrcnotes = 0;
  2650         for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn);
  2651              sn = SN_NEXT(sn)) {
  2652             if (SN_IS_GETTABLE(sn))
  2653                 ++nsrcnotes;
  2655         if (cache.code) {
  2656             JS_ASSERT(cache.map.initialized());
  2657             cache.map.finish();
  2658             cache.code = nullptr;
  2660         if (cache.map.init(nsrcnotes)) {
  2661             pc = script->code();
  2662             for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn);
  2663                  sn = SN_NEXT(sn)) {
  2664                 pc += SN_DELTA(sn);
  2665                 if (SN_IS_GETTABLE(sn))
  2666                     JS_ALWAYS_TRUE(cache.map.put(pc, sn));
  2668             cache.code = script->code();
  2672     return result;
  2675 jssrcnote *
  2676 js_GetSrcNote(JSContext *cx, JSScript *script, jsbytecode *pc)
  2678     return GetSrcNote(cx->runtime()->gsnCache, script, pc);
  2681 unsigned
  2682 js::PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc,
  2683                    unsigned *columnp)
  2685     unsigned lineno = startLine;
  2686     unsigned column = 0;
  2688     /*
  2689      * Walk through source notes accumulating their deltas, keeping track of
  2690      * line-number notes, until we pass the note for pc's offset within
  2691      * script->code.
  2692      */
  2693     ptrdiff_t offset = 0;
  2694     ptrdiff_t target = pc - code;
  2695     for (jssrcnote *sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
  2696         offset += SN_DELTA(sn);
  2697         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
  2698         if (type == SRC_SETLINE) {
  2699             if (offset <= target)
  2700                 lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
  2701             column = 0;
  2702         } else if (type == SRC_NEWLINE) {
  2703             if (offset <= target)
  2704                 lineno++;
  2705             column = 0;
  2708         if (offset > target)
  2709             break;
  2711         if (type == SRC_COLSPAN) {
  2712             ptrdiff_t colspan = js_GetSrcNoteOffset(sn, 0);
  2714             if (colspan >= SN_COLSPAN_DOMAIN / 2)
  2715                 colspan -= SN_COLSPAN_DOMAIN;
  2716             JS_ASSERT(ptrdiff_t(column) + colspan >= 0);
  2717             column += colspan;
  2721     if (columnp)
  2722         *columnp = column;
  2724     return lineno;
  2727 unsigned
  2728 js::PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp)
  2730     /* Cope with InterpreterFrame.pc value prior to entering Interpret. */
  2731     if (!pc)
  2732         return 0;
  2734     return PCToLineNumber(script->lineno(), script->notes(), script->code(), pc, columnp);
  2737 jsbytecode *
  2738 js_LineNumberToPC(JSScript *script, unsigned target)
  2740     ptrdiff_t offset = 0;
  2741     ptrdiff_t best = -1;
  2742     unsigned lineno = script->lineno();
  2743     unsigned bestdiff = SN_MAX_OFFSET;
  2744     for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
  2745         /*
  2746          * Exact-match only if offset is not in the prolog; otherwise use
  2747          * nearest greater-or-equal line number match.
  2748          */
  2749         if (lineno == target && offset >= ptrdiff_t(script->mainOffset()))
  2750             goto out;
  2751         if (lineno >= target) {
  2752             unsigned diff = lineno - target;
  2753             if (diff < bestdiff) {
  2754                 bestdiff = diff;
  2755                 best = offset;
  2758         offset += SN_DELTA(sn);
  2759         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
  2760         if (type == SRC_SETLINE) {
  2761             lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
  2762         } else if (type == SRC_NEWLINE) {
  2763             lineno++;
  2766     if (best >= 0)
  2767         offset = best;
  2768 out:
  2769     return script->offsetToPC(offset);
  2772 JS_FRIEND_API(unsigned)
  2773 js_GetScriptLineExtent(JSScript *script)
  2775     unsigned lineno = script->lineno();
  2776     unsigned maxLineNo = lineno;
  2777     for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
  2778         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
  2779         if (type == SRC_SETLINE)
  2780             lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
  2781         else if (type == SRC_NEWLINE)
  2782             lineno++;
  2784         if (maxLineNo < lineno)
  2785             maxLineNo = lineno;
  2788     return 1 + maxLineNo - script->lineno();
  2791 void
  2792 js::DescribeScriptedCallerForCompilation(JSContext *cx, MutableHandleScript maybeScript,
  2793                                          const char **file, unsigned *linenop,
  2794                                          uint32_t *pcOffset, JSPrincipals **origin,
  2795                                          LineOption opt)
  2797     if (opt == CALLED_FROM_JSOP_EVAL) {
  2798         jsbytecode *pc = nullptr;
  2799         maybeScript.set(cx->currentScript(&pc));
  2800         JS_ASSERT(JSOp(*pc) == JSOP_EVAL || JSOp(*pc) == JSOP_SPREADEVAL);
  2801         JS_ASSERT(*(pc + (JSOp(*pc) == JSOP_EVAL ? JSOP_EVAL_LENGTH
  2802                                                  : JSOP_SPREADEVAL_LENGTH)) == JSOP_LINENO);
  2803         *file = maybeScript->filename();
  2804         *linenop = GET_UINT16(pc + (JSOp(*pc) == JSOP_EVAL ? JSOP_EVAL_LENGTH
  2805                                                            : JSOP_SPREADEVAL_LENGTH));
  2806         *pcOffset = pc - maybeScript->code();
  2807         *origin = maybeScript->originPrincipals();
  2808         return;
  2811     NonBuiltinFrameIter iter(cx);
  2813     if (iter.done()) {
  2814         maybeScript.set(nullptr);
  2815         *file = nullptr;
  2816         *linenop = 0;
  2817         *pcOffset = 0;
  2818         *origin = cx->compartment()->principals;
  2819         return;
  2822     *file = iter.scriptFilename();
  2823     *linenop = iter.computeLine();
  2824     *origin = iter.originPrincipals();
  2826     // These values are only used for introducer fields which are debugging
  2827     // information and can be safely left null for asm.js frames.
  2828     if (iter.hasScript()) {
  2829         maybeScript.set(iter.script());
  2830         *pcOffset = iter.pc() - maybeScript->code();
  2831     } else {
  2832         maybeScript.set(nullptr);
  2833         *pcOffset = 0;
  2837 template <class T>
  2838 static inline T *
  2839 Rebase(JSScript *dst, JSScript *src, T *srcp)
  2841     size_t off = reinterpret_cast<uint8_t *>(srcp) - src->data;
  2842     return reinterpret_cast<T *>(dst->data + off);
  2845 JSScript *
  2846 js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, HandleScript src,
  2847                 NewObjectKind newKind /* = GenericObject */)
  2849     /* NB: Keep this in sync with XDRScript. */
  2851     /* Some embeddings are not careful to use ExposeObjectToActiveJS as needed. */
  2852     JS_ASSERT(!src->sourceObject()->isMarked(gc::GRAY));
  2854     uint32_t nconsts   = src->hasConsts()   ? src->consts()->length   : 0;
  2855     uint32_t nobjects  = src->hasObjects()  ? src->objects()->length  : 0;
  2856     uint32_t nregexps  = src->hasRegexps()  ? src->regexps()->length  : 0;
  2857     uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
  2858     uint32_t nblockscopes = src->hasBlockScopes() ? src->blockScopes()->length : 0;
  2860     /* Script data */
  2862     size_t size = src->dataSize();
  2863     uint8_t *data = AllocScriptData(cx, size);
  2864     if (!data)
  2865         return nullptr;
  2867     /* Bindings */
  2869     Rooted<Bindings> bindings(cx);
  2870     InternalHandle<Bindings*> bindingsHandle =
  2871         InternalHandle<Bindings*>::fromMarkedLocation(bindings.address());
  2872     if (!Bindings::clone(cx, bindingsHandle, data, src))
  2873         return nullptr;
  2875     /* Objects */
  2877     AutoObjectVector objects(cx);
  2878     if (nobjects != 0) {
  2879         HeapPtrObject *vector = src->objects()->vector;
  2880         for (unsigned i = 0; i < nobjects; i++) {
  2881             RootedObject obj(cx, vector[i]);
  2882             RootedObject clone(cx);
  2883             if (obj->is<NestedScopeObject>()) {
  2884                 Rooted<NestedScopeObject*> innerBlock(cx, &obj->as<NestedScopeObject>());
  2886                 RootedObject enclosingScope(cx);
  2887                 if (NestedScopeObject *enclosingBlock = innerBlock->enclosingNestedScope())
  2888                     enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)];
  2889                 else
  2890                     enclosingScope = fun;
  2892                 clone = CloneNestedScopeObject(cx, enclosingScope, innerBlock);
  2893             } else if (obj->is<JSFunction>()) {
  2894                 RootedFunction innerFun(cx, &obj->as<JSFunction>());
  2895                 if (innerFun->isNative()) {
  2896                     assertSameCompartment(cx, innerFun);
  2897                     clone = innerFun;
  2898                 } else {
  2899                     if (innerFun->isInterpretedLazy()) {
  2900                         AutoCompartment ac(cx, innerFun);
  2901                         if (!innerFun->getOrCreateScript(cx))
  2902                             return nullptr;
  2904                     RootedObject staticScope(cx, innerFun->nonLazyScript()->enclosingStaticScope());
  2905                     StaticScopeIter<CanGC> ssi(cx, staticScope);
  2906                     RootedObject enclosingScope(cx);
  2907                     if (ssi.done() || ssi.type() == StaticScopeIter<CanGC>::FUNCTION)
  2908                         enclosingScope = fun;
  2909                     else if (ssi.type() == StaticScopeIter<CanGC>::BLOCK)
  2910                         enclosingScope = objects[FindScopeObjectIndex(src, ssi.block())];
  2911                     else
  2912                         enclosingScope = objects[FindScopeObjectIndex(src, ssi.staticWith())];
  2914                     clone = CloneFunctionAndScript(cx, enclosingScope, innerFun);
  2916             } else {
  2917                 /*
  2918                  * Clone object literals emitted for the JSOP_NEWOBJECT opcode. We only emit that
  2919                  * instead of the less-optimized JSOP_NEWINIT for self-hosted code or code compiled
  2920                  * with JSOPTION_COMPILE_N_GO set. As we don't clone the latter type of code, this
  2921                  * case should only ever be hit when cloning objects from self-hosted code.
  2922                  */
  2923                 clone = CloneObjectLiteral(cx, cx->global(), obj);
  2925             if (!clone || !objects.append(clone))
  2926                 return nullptr;
  2930     /* RegExps */
  2932     AutoObjectVector regexps(cx);
  2933     for (unsigned i = 0; i < nregexps; i++) {
  2934         HeapPtrObject *vector = src->regexps()->vector;
  2935         for (unsigned i = 0; i < nregexps; i++) {
  2936             JSObject *clone = CloneScriptRegExpObject(cx, vector[i]->as<RegExpObject>());
  2937             if (!clone || !regexps.append(clone))
  2938                 return nullptr;
  2942     /*
  2943      * Wrap the script source object as needed. Self-hosted scripts may be
  2944      * in another runtime, so lazily create a new script source object to
  2945      * use for them.
  2946      */
  2947     RootedObject sourceObject(cx);
  2948     if (cx->runtime()->isSelfHostingCompartment(src->compartment())) {
  2949         if (!cx->compartment()->selfHostingScriptSource) {
  2950             CompileOptions options(cx);
  2951             FillSelfHostingCompileOptions(options);
  2953             ScriptSourceObject *obj = frontend::CreateScriptSourceObject(cx, options);
  2954             if (!obj)
  2955                 return nullptr;
  2956             cx->compartment()->selfHostingScriptSource = obj;
  2958         sourceObject = cx->compartment()->selfHostingScriptSource;
  2959     } else {
  2960         sourceObject = src->sourceObject();
  2961         if (!cx->compartment()->wrap(cx, &sourceObject))
  2962             return nullptr;
  2965     /* Now that all fallible allocation is complete, create the GC thing. */
  2967     CompileOptions options(cx);
  2968     options.setOriginPrincipals(src->originPrincipals())
  2969            .setCompileAndGo(src->compileAndGo())
  2970            .setSelfHostingMode(src->selfHosted())
  2971            .setNoScriptRval(src->noScriptRval())
  2972            .setVersion(src->getVersion());
  2974     RootedScript dst(cx, JSScript::Create(cx, enclosingScope, src->savedCallerFun(),
  2975                                           options, src->staticLevel(),
  2976                                           sourceObject, src->sourceStart(), src->sourceEnd()));
  2977     if (!dst) {
  2978         js_free(data);
  2979         return nullptr;
  2982     dst->bindings = bindings;
  2984     /* This assignment must occur before all the Rebase calls. */
  2985     dst->data = data;
  2986     dst->dataSize_ = size;
  2987     memcpy(data, src->data, size);
  2989     /* Script filenames, bytecodes and atoms are runtime-wide. */
  2990     dst->setCode(src->code());
  2991     dst->atoms = src->atoms;
  2993     dst->setLength(src->length());
  2994     dst->lineno_ = src->lineno();
  2995     dst->mainOffset_ = src->mainOffset();
  2996     dst->natoms_ = src->natoms();
  2997     dst->funLength_ = src->funLength();
  2998     dst->nTypeSets_ = src->nTypeSets();
  2999     dst->nslots_ = src->nslots();
  3000     if (src->argumentsHasVarBinding()) {
  3001         dst->setArgumentsHasVarBinding();
  3002         if (src->analyzedArgsUsage())
  3003             dst->setNeedsArgsObj(src->needsArgsObj());
  3005     dst->cloneHasArray(src);
  3006     dst->strict_ = src->strict();
  3007     dst->explicitUseStrict_ = src->explicitUseStrict();
  3008     dst->bindingsAccessedDynamically_ = src->bindingsAccessedDynamically();
  3009     dst->funHasExtensibleScope_ = src->funHasExtensibleScope();
  3010     dst->funNeedsDeclEnvObject_ = src->funNeedsDeclEnvObject();
  3011     dst->funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
  3012     dst->hasSingletons_ = src->hasSingletons();
  3013     dst->treatAsRunOnce_ = src->treatAsRunOnce();
  3014     dst->isGeneratorExp_ = src->isGeneratorExp();
  3015     dst->setGeneratorKind(src->generatorKind());
  3017     /* Copy over hints. */
  3018     dst->shouldInline_ = src->shouldInline();
  3019     dst->shouldCloneAtCallsite_ = src->shouldCloneAtCallsite();
  3020     dst->isCallsiteClone_ = src->isCallsiteClone();
  3022     if (nconsts != 0) {
  3023         HeapValue *vector = Rebase<HeapValue>(dst, src, src->consts()->vector);
  3024         dst->consts()->vector = vector;
  3025         for (unsigned i = 0; i < nconsts; ++i)
  3026             JS_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom());
  3028     if (nobjects != 0) {
  3029         HeapPtrObject *vector = Rebase<HeapPtr<JSObject> >(dst, src, src->objects()->vector);
  3030         dst->objects()->vector = vector;
  3031         for (unsigned i = 0; i < nobjects; ++i)
  3032             vector[i].init(objects[i]);
  3034     if (nregexps != 0) {
  3035         HeapPtrObject *vector = Rebase<HeapPtr<JSObject> >(dst, src, src->regexps()->vector);
  3036         dst->regexps()->vector = vector;
  3037         for (unsigned i = 0; i < nregexps; ++i)
  3038             vector[i].init(regexps[i]);
  3040     if (ntrynotes != 0)
  3041         dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
  3042     if (nblockscopes != 0)
  3043         dst->blockScopes()->vector = Rebase<BlockScopeNote>(dst, src, src->blockScopes()->vector);
  3045     return dst;
  3048 bool
  3049 js::CloneFunctionScript(JSContext *cx, HandleFunction original, HandleFunction clone,
  3050                         NewObjectKind newKind /* = GenericObject */)
  3052     JS_ASSERT(clone->isInterpreted());
  3054     RootedScript script(cx, clone->nonLazyScript());
  3055     JS_ASSERT(script);
  3056     JS_ASSERT(script->compartment() == original->compartment());
  3057     JS_ASSERT_IF(script->compartment() != cx->compartment(),
  3058                  !script->enclosingStaticScope());
  3060     RootedObject scope(cx, script->enclosingStaticScope());
  3062     clone->mutableScript().init(nullptr);
  3064     JSScript *cscript = CloneScript(cx, scope, clone, script, newKind);
  3065     if (!cscript)
  3066         return false;
  3068     clone->setScript(cscript);
  3069     cscript->setFunction(clone);
  3071     script = clone->nonLazyScript();
  3072     CallNewScriptHook(cx, script, clone);
  3073     RootedGlobalObject global(cx, script->compileAndGo() ? &script->global() : nullptr);
  3074     Debugger::onNewScript(cx, script, global);
  3076     return true;
  3079 DebugScript *
  3080 JSScript::debugScript()
  3082     JS_ASSERT(hasDebugScript_);
  3083     DebugScriptMap *map = compartment()->debugScriptMap;
  3084     JS_ASSERT(map);
  3085     DebugScriptMap::Ptr p = map->lookup(this);
  3086     JS_ASSERT(p);
  3087     return p->value();
  3090 DebugScript *
  3091 JSScript::releaseDebugScript()
  3093     JS_ASSERT(hasDebugScript_);
  3094     DebugScriptMap *map = compartment()->debugScriptMap;
  3095     JS_ASSERT(map);
  3096     DebugScriptMap::Ptr p = map->lookup(this);
  3097     JS_ASSERT(p);
  3098     DebugScript *debug = p->value();
  3099     map->remove(p);
  3100     hasDebugScript_ = false;
  3101     return debug;
  3104 void
  3105 JSScript::destroyDebugScript(FreeOp *fop)
  3107     if (hasDebugScript_) {
  3108         for (jsbytecode *pc = code(); pc < codeEnd(); pc++) {
  3109             if (BreakpointSite *site = getBreakpointSite(pc)) {
  3110                 /* Breakpoints are swept before finalization. */
  3111                 JS_ASSERT(site->firstBreakpoint() == nullptr);
  3112                 site->clearTrap(fop, nullptr, nullptr);
  3113                 JS_ASSERT(getBreakpointSite(pc) == nullptr);
  3116         fop->free_(releaseDebugScript());
  3120 bool
  3121 JSScript::ensureHasDebugScript(JSContext *cx)
  3123     if (hasDebugScript_)
  3124         return true;
  3126     size_t nbytes = offsetof(DebugScript, breakpoints) + length() * sizeof(BreakpointSite*);
  3127     DebugScript *debug = (DebugScript *) cx->calloc_(nbytes);
  3128     if (!debug)
  3129         return false;
  3131     /* Create compartment's debugScriptMap if necessary. */
  3132     DebugScriptMap *map = compartment()->debugScriptMap;
  3133     if (!map) {
  3134         map = cx->new_<DebugScriptMap>();
  3135         if (!map || !map->init()) {
  3136             js_free(debug);
  3137             js_delete(map);
  3138             return false;
  3140         compartment()->debugScriptMap = map;
  3143     if (!map->putNew(this, debug)) {
  3144         js_free(debug);
  3145         return false;
  3147     hasDebugScript_ = true; // safe to set this;  we can't fail after this point
  3149     /*
  3150      * Ensure that any Interpret() instances running on this script have
  3151      * interrupts enabled. The interrupts must stay enabled until the
  3152      * debug state is destroyed.
  3153      */
  3154     for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
  3155         if (iter->isInterpreter())
  3156             iter->asInterpreter()->enableInterruptsIfRunning(this);
  3159     return true;
  3162 void
  3163 JSScript::setNewStepMode(FreeOp *fop, uint32_t newValue)
  3165     DebugScript *debug = debugScript();
  3166     uint32_t prior = debug->stepMode;
  3167     debug->stepMode = newValue;
  3169     if (!prior != !newValue) {
  3170 #ifdef JS_ION
  3171         if (hasBaselineScript())
  3172             baseline->toggleDebugTraps(this, nullptr);
  3173 #endif
  3175         if (!stepModeEnabled() && !debug->numSites)
  3176             fop->free_(releaseDebugScript());
  3180 bool
  3181 JSScript::setStepModeFlag(JSContext *cx, bool step)
  3183     if (!ensureHasDebugScript(cx))
  3184         return false;
  3186     setNewStepMode(cx->runtime()->defaultFreeOp(),
  3187                    (debugScript()->stepMode & stepCountMask) |
  3188                    (step ? stepFlagMask : 0));
  3189     return true;
  3192 bool
  3193 JSScript::incrementStepModeCount(JSContext *cx)
  3195     assertSameCompartment(cx, this);
  3196     MOZ_ASSERT(cx->compartment()->debugMode());
  3198     if (!ensureHasDebugScript(cx))
  3199         return false;
  3201     DebugScript *debug = debugScript();
  3202     uint32_t count = debug->stepMode & stepCountMask;
  3203     MOZ_ASSERT(((count + 1) & stepCountMask) == count + 1);
  3205     setNewStepMode(cx->runtime()->defaultFreeOp(),
  3206                    (debug->stepMode & stepFlagMask) |
  3207                    ((count + 1) & stepCountMask));
  3208     return true;
  3211 void
  3212 JSScript::decrementStepModeCount(FreeOp *fop)
  3214     DebugScript *debug = debugScript();
  3215     uint32_t count = debug->stepMode & stepCountMask;
  3217     setNewStepMode(fop,
  3218                    (debug->stepMode & stepFlagMask) |
  3219                    ((count - 1) & stepCountMask));
  3222 BreakpointSite *
  3223 JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc)
  3225     if (!ensureHasDebugScript(cx))
  3226         return nullptr;
  3228     DebugScript *debug = debugScript();
  3229     BreakpointSite *&site = debug->breakpoints[pcToOffset(pc)];
  3231     if (!site) {
  3232         site = cx->runtime()->new_<BreakpointSite>(this, pc);
  3233         if (!site) {
  3234             js_ReportOutOfMemory(cx);
  3235             return nullptr;
  3237         debug->numSites++;
  3240     return site;
  3243 void
  3244 JSScript::destroyBreakpointSite(FreeOp *fop, jsbytecode *pc)
  3246     DebugScript *debug = debugScript();
  3247     BreakpointSite *&site = debug->breakpoints[pcToOffset(pc)];
  3248     JS_ASSERT(site);
  3250     fop->delete_(site);
  3251     site = nullptr;
  3253     if (--debug->numSites == 0 && !stepModeEnabled())
  3254         fop->free_(releaseDebugScript());
  3257 void
  3258 JSScript::clearBreakpointsIn(FreeOp *fop, js::Debugger *dbg, JSObject *handler)
  3260     if (!hasAnyBreakpointsOrStepMode())
  3261         return;
  3263     for (jsbytecode *pc = code(); pc < codeEnd(); pc++) {
  3264         BreakpointSite *site = getBreakpointSite(pc);
  3265         if (site) {
  3266             Breakpoint *nextbp;
  3267             for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
  3268                 nextbp = bp->nextInSite();
  3269                 if ((!dbg || bp->debugger == dbg) && (!handler || bp->getHandler() == handler))
  3270                     bp->destroy(fop);
  3276 bool
  3277 JSScript::hasBreakpointsAt(jsbytecode *pc)
  3279     BreakpointSite *site = getBreakpointSite(pc);
  3280     if (!site)
  3281         return false;
  3283     return site->enabledCount > 0 || site->trapHandler;
  3286 void
  3287 JSScript::clearTraps(FreeOp *fop)
  3289     if (!hasAnyBreakpointsOrStepMode())
  3290         return;
  3292     for (jsbytecode *pc = code(); pc < codeEnd(); pc++) {
  3293         BreakpointSite *site = getBreakpointSite(pc);
  3294         if (site)
  3295             site->clearTrap(fop);
  3299 void
  3300 JSScript::markChildren(JSTracer *trc)
  3302     // NOTE: this JSScript may be partially initialized at this point.  E.g. we
  3303     // may have created it and partially initialized it with
  3304     // JSScript::Create(), but not yet finished initializing it with
  3305     // fullyInitFromEmitter() or fullyInitTrivial().
  3307     JS_ASSERT_IF(trc->runtime()->gcStrictCompartmentChecking, zone()->isCollecting());
  3309     for (uint32_t i = 0; i < natoms(); ++i) {
  3310         if (atoms[i])
  3311             MarkString(trc, &atoms[i], "atom");
  3314     if (hasObjects()) {
  3315         ObjectArray *objarray = objects();
  3316         MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
  3319     if (hasRegexps()) {
  3320         ObjectArray *objarray = regexps();
  3321         MarkObjectRange(trc, objarray->length, objarray->vector, "objects");
  3324     if (hasConsts()) {
  3325         ConstArray *constarray = consts();
  3326         MarkValueRange(trc, constarray->length, constarray->vector, "consts");
  3329     if (sourceObject()) {
  3330         JS_ASSERT(sourceObject()->compartment() == compartment());
  3331         MarkObject(trc, &sourceObject_, "sourceObject");
  3334     if (functionNonDelazifying())
  3335         MarkObject(trc, &function_, "function");
  3337     if (enclosingScopeOrOriginalFunction_)
  3338         MarkObject(trc, &enclosingScopeOrOriginalFunction_, "enclosing");
  3340     if (maybeLazyScript())
  3341         MarkLazyScriptUnbarriered(trc, &lazyScript, "lazyScript");
  3343     if (IS_GC_MARKING_TRACER(trc)) {
  3344         compartment()->mark();
  3346         if (code())
  3347             MarkScriptData(trc->runtime(), code());
  3350     bindings.trace(trc);
  3352     if (hasAnyBreakpointsOrStepMode()) {
  3353         for (unsigned i = 0; i < length(); i++) {
  3354             BreakpointSite *site = debugScript()->breakpoints[i];
  3355             if (site && site->trapHandler)
  3356                 MarkValue(trc, &site->trapClosure, "trap closure");
  3360 #ifdef JS_ION
  3361     jit::TraceIonScripts(trc, this);
  3362 #endif
  3365 void
  3366 LazyScript::markChildren(JSTracer *trc)
  3368     if (function_)
  3369         MarkObject(trc, &function_, "function");
  3371     if (sourceObject_)
  3372         MarkObject(trc, &sourceObject_, "sourceObject");
  3374     if (enclosingScope_)
  3375         MarkObject(trc, &enclosingScope_, "enclosingScope");
  3377     if (script_)
  3378         MarkScript(trc, &script_, "realScript");
  3380     HeapPtrAtom *freeVariables = this->freeVariables();
  3381     for (size_t i = 0; i < numFreeVariables(); i++)
  3382         MarkString(trc, &freeVariables[i], "lazyScriptFreeVariable");
  3384     HeapPtrFunction *innerFunctions = this->innerFunctions();
  3385     for (size_t i = 0; i < numInnerFunctions(); i++)
  3386         MarkObject(trc, &innerFunctions[i], "lazyScriptInnerFunction");
  3389 void
  3390 LazyScript::finalize(FreeOp *fop)
  3392     if (table_)
  3393         fop->free_(table_);
  3396 NestedScopeObject *
  3397 JSScript::getStaticScope(jsbytecode *pc)
  3399     JS_ASSERT(containsPC(pc));
  3401     if (!hasBlockScopes())
  3402         return nullptr;
  3404     ptrdiff_t offset = pc - main();
  3406     if (offset < 0)
  3407         return nullptr;
  3409     BlockScopeArray *scopes = blockScopes();
  3410     NestedScopeObject *blockChain = nullptr;
  3412     // Find the innermost block chain using a binary search.
  3413     size_t bottom = 0;
  3414     size_t top = scopes->length;
  3416     while (bottom < top) {
  3417         size_t mid = bottom + (top - bottom) / 2;
  3418         const BlockScopeNote *note = &scopes->vector[mid];
  3419         if (note->start <= offset) {
  3420             // Block scopes are ordered in the list by their starting offset, and since
  3421             // blocks form a tree ones earlier in the list may cover the pc even if
  3422             // later blocks end before the pc. This only happens when the earlier block
  3423             // is a parent of the later block, so we need to check parents of |mid| in
  3424             // the searched range for coverage.
  3425             size_t check = mid;
  3426             while (check >= bottom) {
  3427                 const BlockScopeNote *checkNote = &scopes->vector[check];
  3428                 JS_ASSERT(checkNote->start <= offset);
  3429                 if (offset < checkNote->start + checkNote->length) {
  3430                     // We found a matching block chain but there may be inner ones
  3431                     // at a higher block chain index than mid. Continue the binary search.
  3432                     if (checkNote->index == BlockScopeNote::NoBlockScopeIndex)
  3433                         blockChain = nullptr;
  3434                     else
  3435                         blockChain = &getObject(checkNote->index)->as<NestedScopeObject>();
  3436                     break;
  3438                 if (checkNote->parent == UINT32_MAX)
  3439                     break;
  3440                 check = checkNote->parent;
  3442             bottom = mid + 1;
  3443         } else {
  3444             top = mid;
  3448     return blockChain;
  3451 void
  3452 JSScript::setArgumentsHasVarBinding()
  3454     argsHasVarBinding_ = true;
  3455 #ifdef JS_ION
  3456     needsArgsAnalysis_ = true;
  3457 #else
  3458     // The arguments analysis is performed by IonBuilder.
  3459     needsArgsObj_ = true;
  3460 #endif
  3463 void
  3464 JSScript::setNeedsArgsObj(bool needsArgsObj)
  3466     JS_ASSERT_IF(needsArgsObj, argumentsHasVarBinding());
  3467     needsArgsAnalysis_ = false;
  3468     needsArgsObj_ = needsArgsObj;
  3471 void
  3472 js::SetFrameArgumentsObject(JSContext *cx, AbstractFramePtr frame,
  3473                             HandleScript script, JSObject *argsobj)
  3475     /*
  3476      * Replace any optimized arguments in the frame with an explicit arguments
  3477      * object. Note that 'arguments' may have already been overwritten.
  3478      */
  3480     InternalBindingsHandle bindings(script, &script->bindings);
  3481     const uint32_t var = Bindings::argumentsVarIndex(cx, bindings);
  3483     if (script->varIsAliased(var)) {
  3484         /*
  3485          * Scan the script to find the slot in the call object that 'arguments'
  3486          * is assigned to.
  3487          */
  3488         jsbytecode *pc = script->code();
  3489         while (*pc != JSOP_ARGUMENTS)
  3490             pc += GetBytecodeLength(pc);
  3491         pc += JSOP_ARGUMENTS_LENGTH;
  3492         JS_ASSERT(*pc == JSOP_SETALIASEDVAR);
  3494         // Note that here and below, it is insufficient to only check for
  3495         // JS_OPTIMIZED_ARGUMENTS, as Ion could have optimized out the
  3496         // arguments slot.
  3497         if (IsOptimizedPlaceholderMagicValue(frame.callObj().as<ScopeObject>().aliasedVar(pc)))
  3498             frame.callObj().as<ScopeObject>().setAliasedVar(cx, pc, cx->names().arguments, ObjectValue(*argsobj));
  3499     } else {
  3500         if (IsOptimizedPlaceholderMagicValue(frame.unaliasedLocal(var)))
  3501             frame.unaliasedLocal(var) = ObjectValue(*argsobj);
  3505 /* static */ bool
  3506 JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
  3508     JS_ASSERT(script->functionNonDelazifying());
  3509     JS_ASSERT(script->analyzedArgsUsage());
  3510     JS_ASSERT(script->argumentsHasVarBinding());
  3512     /*
  3513      * It is possible that the arguments optimization has already failed,
  3514      * everything has been fixed up, but there was an outstanding magic value
  3515      * on the stack that has just now flowed into an apply. In this case, there
  3516      * is nothing to do; GuardFunApplySpeculation will patch in the real
  3517      * argsobj.
  3518      */
  3519     if (script->needsArgsObj())
  3520         return true;
  3522     JS_ASSERT(!script->isGenerator());
  3524     script->needsArgsObj_ = true;
  3526 #ifdef JS_ION
  3527     /*
  3528      * Since we can't invalidate baseline scripts, set a flag that's checked from
  3529      * JIT code to indicate the arguments optimization failed and JSOP_ARGUMENTS
  3530      * should create an arguments object next time.
  3531      */
  3532     if (script->hasBaselineScript())
  3533         script->baselineScript()->setNeedsArgsObj();
  3534 #endif
  3536     /*
  3537      * By design, the arguments optimization is only made when there are no
  3538      * outstanding cases of MagicValue(JS_OPTIMIZED_ARGUMENTS) at any points
  3539      * where the optimization could fail, other than an active invocation of
  3540      * 'f.apply(x, arguments)'. Thus, there are no outstanding values of
  3541      * MagicValue(JS_OPTIMIZED_ARGUMENTS) on the stack. However, there are
  3542      * three things that need fixup:
  3543      *  - there may be any number of activations of this script that don't have
  3544      *    an argsObj that now need one.
  3545      *  - jit code compiled (and possible active on the stack) with the static
  3546      *    assumption of !script->needsArgsObj();
  3547      *  - type inference data for the script assuming script->needsArgsObj
  3548      */
  3549     for (AllFramesIter i(cx); !i.done(); ++i) {
  3550         /*
  3551          * We cannot reliably create an arguments object for Ion activations of
  3552          * this script.  To maintain the invariant that "script->needsArgsObj
  3553          * implies fp->hasArgsObj", the Ion bail mechanism will create an
  3554          * arguments object right after restoring the BaselineFrame and before
  3555          * entering Baseline code (in jit::FinishBailoutToBaseline).
  3556          */
  3557         if (i.isIon())
  3558             continue;
  3559         AbstractFramePtr frame = i.abstractFramePtr();
  3560         if (frame.isFunctionFrame() && frame.script() == script) {
  3561             ArgumentsObject *argsobj = ArgumentsObject::createExpected(cx, frame);
  3562             if (!argsobj) {
  3563                 /*
  3564                  * We can't leave stack frames with script->needsArgsObj but no
  3565                  * arguments object. It is, however, safe to leave frames with
  3566                  * an arguments object but !script->needsArgsObj.
  3567                  */
  3568                 script->needsArgsObj_ = false;
  3569                 return false;
  3572             SetFrameArgumentsObject(cx, frame, script, argsobj);
  3576     return true;
  3579 bool
  3580 JSScript::varIsAliased(uint32_t varSlot)
  3582     return bindings.bindingIsAliased(bindings.numArgs() + varSlot);
  3585 bool
  3586 JSScript::formalIsAliased(unsigned argSlot)
  3588     return bindings.bindingIsAliased(argSlot);
  3591 bool
  3592 JSScript::formalLivesInArgumentsObject(unsigned argSlot)
  3594     return argsObjAliasesFormals() && !formalIsAliased(argSlot);
  3597 LazyScript::LazyScript(JSFunction *fun, void *table, uint64_t packedFields, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
  3598   : script_(nullptr),
  3599     function_(fun),
  3600     enclosingScope_(nullptr),
  3601     sourceObject_(nullptr),
  3602     table_(table),
  3603     packedFields_(packedFields),
  3604     begin_(begin),
  3605     end_(end),
  3606     lineno_(lineno),
  3607     column_(column)
  3609     JS_ASSERT(begin <= end);
  3612 void
  3613 LazyScript::initScript(JSScript *script)
  3615     JS_ASSERT(script && !script_);
  3616     script_ = script;
  3619 void
  3620 LazyScript::resetScript()
  3622     JS_ASSERT(script_);
  3623     script_ = nullptr;
  3626 void
  3627 LazyScript::setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject)
  3629     JS_ASSERT(!sourceObject_ && !enclosingScope_);
  3630     JS_ASSERT_IF(enclosingScope, function_->compartment() == enclosingScope->compartment());
  3631     JS_ASSERT(function_->compartment() == sourceObject->compartment());
  3633     enclosingScope_ = enclosingScope;
  3634     sourceObject_ = sourceObject;
  3637 ScriptSourceObject *
  3638 LazyScript::sourceObject() const
  3640     return sourceObject_ ? &sourceObject_->as<ScriptSourceObject>() : nullptr;
  3643 /* static */ LazyScript *
  3644 LazyScript::CreateRaw(ExclusiveContext *cx, HandleFunction fun,
  3645                       uint64_t packedFields, uint32_t begin, uint32_t end,
  3646                       uint32_t lineno, uint32_t column)
  3648     union {
  3649         PackedView p;
  3650         uint64_t packed;
  3651     };
  3653     packed = packedFields;
  3655     // Reset runtime flags to obtain a fresh LazyScript.
  3656     p.hasBeenCloned = false;
  3657     p.treatAsRunOnce = false;
  3659     size_t bytes = (p.numFreeVariables * sizeof(HeapPtrAtom))
  3660                  + (p.numInnerFunctions * sizeof(HeapPtrFunction));
  3662     ScopedJSFreePtr<void> table(bytes ? cx->malloc_(bytes) : nullptr);
  3663     if (bytes && !table)
  3664         return nullptr;
  3666     LazyScript *res = js_NewGCLazyScript(cx);
  3667     if (!res)
  3668         return nullptr;
  3670     cx->compartment()->scheduleDelazificationForDebugMode();
  3672     return new (res) LazyScript(fun, table.forget(), packed, begin, end, lineno, column);
  3675 /* static */ LazyScript *
  3676 LazyScript::CreateRaw(ExclusiveContext *cx, HandleFunction fun,
  3677                       uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version,
  3678                       uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
  3680     union {
  3681         PackedView p;
  3682         uint64_t packedFields;
  3683     };
  3685     p.version = version;
  3686     p.numFreeVariables = numFreeVariables;
  3687     p.numInnerFunctions = numInnerFunctions;
  3688     p.generatorKindBits = GeneratorKindAsBits(NotGenerator);
  3689     p.strict = false;
  3690     p.bindingsAccessedDynamically = false;
  3691     p.hasDebuggerStatement = false;
  3692     p.directlyInsideEval = false;
  3693     p.usesArgumentsAndApply = false;
  3695     LazyScript *res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
  3696     JS_ASSERT_IF(res, res->version() == version);
  3697     return res;
  3700 /* static */ LazyScript *
  3701 LazyScript::Create(ExclusiveContext *cx, HandleFunction fun,
  3702                    uint64_t packedFields, uint32_t begin, uint32_t end,
  3703                    uint32_t lineno, uint32_t column)
  3705     // Dummy atom which is not a valid property name.
  3706     RootedAtom dummyAtom(cx, cx->names().comma);
  3708     // Dummy function which is not a valid function as this is the one which is
  3709     // holding this lazy script.
  3710     HandleFunction dummyFun = fun;
  3712     LazyScript *res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, lineno, column);
  3713     if (!res)
  3714         return nullptr;
  3716     // Fill with dummies, to be GC-safe after the initialization of the free
  3717     // variables and inner functions.
  3718     size_t i, num;
  3719     HeapPtrAtom *variables = res->freeVariables();
  3720     for (i = 0, num = res->numFreeVariables(); i < num; i++)
  3721         variables[i].init(dummyAtom);
  3723     HeapPtrFunction *functions = res->innerFunctions();
  3724     for (i = 0, num = res->numInnerFunctions(); i < num; i++)
  3725         functions[i].init(dummyFun);
  3727     return res;
  3730 void
  3731 LazyScript::initRuntimeFields(uint64_t packedFields)
  3733     union {
  3734         PackedView p;
  3735         uint64_t packed;
  3736     };
  3738     packed = packedFields;
  3739     p_.hasBeenCloned = p.hasBeenCloned;
  3740     p_.treatAsRunOnce = p.treatAsRunOnce;
  3743 bool
  3744 LazyScript::hasUncompiledEnclosingScript() const
  3746     // It can happen that we created lazy scripts while compiling an enclosing
  3747     // script, but we errored out while compiling that script. When we iterate
  3748     // over lazy script in a compartment, we might see lazy scripts that never
  3749     // escaped to script and should be ignored.
  3750     //
  3751     // If the enclosing scope is a function with a null script or has a script
  3752     // without code, it was not successfully compiled.
  3754     if (!enclosingScope() || !enclosingScope()->is<JSFunction>())
  3755         return false;
  3757     JSFunction &fun = enclosingScope()->as<JSFunction>();
  3758     return fun.isInterpreted() && (!fun.mutableScript() || !fun.nonLazyScript()->code());
  3761 uint32_t
  3762 LazyScript::staticLevel(JSContext *cx) const
  3764     for (StaticScopeIter<NoGC> ssi(enclosingScope()); !ssi.done(); ssi++) {
  3765         if (ssi.type() == StaticScopeIter<NoGC>::FUNCTION)
  3766             return ssi.funScript()->staticLevel() + 1;
  3768     return 1;
  3771 void
  3772 JSScript::updateBaselineOrIonRaw()
  3774 #ifdef JS_ION
  3775     if (hasIonScript()) {
  3776         baselineOrIonRaw = ion->method()->raw();
  3777         baselineOrIonSkipArgCheck = ion->method()->raw() + ion->getSkipArgCheckEntryOffset();
  3778     } else if (hasBaselineScript()) {
  3779         baselineOrIonRaw = baseline->method()->raw();
  3780         baselineOrIonSkipArgCheck = baseline->method()->raw();
  3781     } else {
  3782         baselineOrIonRaw = nullptr;
  3783         baselineOrIonSkipArgCheck = nullptr;
  3785 #endif
  3788 bool
  3789 JSScript::hasLoops()
  3791     if (!hasTrynotes())
  3792         return false;
  3793     JSTryNote *tn = trynotes()->vector;
  3794     JSTryNote *tnlimit = tn + trynotes()->length;
  3795     for (; tn < tnlimit; tn++) {
  3796         if (tn->kind == JSTRY_ITER || tn->kind == JSTRY_LOOP)
  3797             return true;
  3799     return false;
  3802 static inline void
  3803 LazyScriptHash(uint32_t lineno, uint32_t column, uint32_t begin, uint32_t end,
  3804                HashNumber hashes[3])
  3806     HashNumber hash = lineno;
  3807     hash = RotateLeft(hash, 4) ^ column;
  3808     hash = RotateLeft(hash, 4) ^ begin;
  3809     hash = RotateLeft(hash, 4) ^ end;
  3811     hashes[0] = hash;
  3812     hashes[1] = RotateLeft(hashes[0], 4) ^ begin;
  3813     hashes[2] = RotateLeft(hashes[1], 4) ^ end;
  3816 void
  3817 LazyScriptHashPolicy::hash(const Lookup &lookup, HashNumber hashes[3])
  3819     LazyScript *lazy = lookup.lazy;
  3820     LazyScriptHash(lazy->lineno(), lazy->column(), lazy->begin(), lazy->end(), hashes);
  3823 void
  3824 LazyScriptHashPolicy::hash(JSScript *script, HashNumber hashes[3])
  3826     LazyScriptHash(script->lineno(), script->column(), script->sourceStart(), script->sourceEnd(), hashes);
  3829 bool
  3830 LazyScriptHashPolicy::match(JSScript *script, const Lookup &lookup)
  3832     JSContext *cx = lookup.cx;
  3833     LazyScript *lazy = lookup.lazy;
  3835     // To be a match, the script and lazy script need to have the same line
  3836     // and column and to be at the same position within their respective
  3837     // source blobs, and to have the same source contents and version.
  3838     //
  3839     // While the surrounding code in the source may differ, this is
  3840     // sufficient to ensure that compiling the lazy script will yield an
  3841     // identical result to compiling the original script.
  3842     //
  3843     // Note that the filenames and origin principals of the lazy script and
  3844     // original script can differ. If there is a match, these will be fixed
  3845     // up in the resulting clone by the caller.
  3847     if (script->lineno() != lazy->lineno() ||
  3848         script->column() != lazy->column() ||
  3849         script->getVersion() != lazy->version() ||
  3850         script->sourceStart() != lazy->begin() ||
  3851         script->sourceEnd() != lazy->end())
  3853         return false;
  3856     SourceDataCache::AutoHoldEntry holder;
  3858     const jschar *scriptChars = script->scriptSource()->chars(cx, holder);
  3859     if (!scriptChars)
  3860         return false;
  3862     const jschar *lazyChars = lazy->source()->chars(cx, holder);
  3863     if (!lazyChars)
  3864         return false;
  3866     size_t begin = script->sourceStart();
  3867     size_t length = script->sourceEnd() - begin;
  3868     return !memcmp(scriptChars + begin, lazyChars + begin, length);

mercurial