LCOV - code coverage report
Current view: top level - js/src - jsscript.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1519 2480 61.2 %
Date: 2017-07-14 16:53:18 Functions: 108 191 56.5 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : /*
       8             :  * JS script operations.
       9             :  */
      10             : 
      11             : #include "jsscriptinlines.h"
      12             : 
      13             : #include "mozilla/DebugOnly.h"
      14             : #include "mozilla/MathAlgorithms.h"
      15             : #include "mozilla/MemoryReporting.h"
      16             : #include "mozilla/PodOperations.h"
      17             : #include "mozilla/ScopeExit.h"
      18             : #include "mozilla/Sprintf.h"
      19             : #include "mozilla/Unused.h"
      20             : #include "mozilla/Vector.h"
      21             : 
      22             : #include <algorithm>
      23             : #include <string.h>
      24             : 
      25             : #include "jsapi.h"
      26             : #include "jsatom.h"
      27             : #include "jscntxt.h"
      28             : #include "jsfun.h"
      29             : #include "jsgc.h"
      30             : #include "jsobj.h"
      31             : #include "jsopcode.h"
      32             : #include "jsprf.h"
      33             : #include "jstypes.h"
      34             : #include "jsutil.h"
      35             : #include "jswrapper.h"
      36             : 
      37             : #include "frontend/BytecodeCompiler.h"
      38             : #include "frontend/BytecodeEmitter.h"
      39             : #include "frontend/SharedContext.h"
      40             : #include "gc/Marking.h"
      41             : #include "jit/BaselineJIT.h"
      42             : #include "jit/Ion.h"
      43             : #include "jit/IonCode.h"
      44             : #include "js/MemoryMetrics.h"
      45             : #include "js/Utility.h"
      46             : #include "vm/ArgumentsObject.h"
      47             : #include "vm/Compression.h"
      48             : #include "vm/Debugger.h"
      49             : #include "vm/Opcodes.h"
      50             : #include "vm/SelfHosting.h"
      51             : #include "vm/Shape.h"
      52             : #include "vm/SharedImmutableStringsCache.h"
      53             : #include "vm/StringBuffer.h"
      54             : #include "vm/Xdr.h"
      55             : #include "vtune/VTuneWrapper.h"
      56             : 
      57             : #include "jsfuninlines.h"
      58             : #include "jsobjinlines.h"
      59             : 
      60             : #include "vm/EnvironmentObject-inl.h"
      61             : #include "vm/NativeObject-inl.h"
      62             : #include "vm/SharedImmutableStringsCache-inl.h"
      63             : #include "vm/Stack-inl.h"
      64             : 
      65             : using namespace js;
      66             : using namespace js::gc;
      67             : using namespace js::frontend;
      68             : 
      69             : using mozilla::AsVariant;
      70             : using mozilla::PodCopy;
      71             : using mozilla::PodZero;
      72             : using mozilla::RotateLeft;
      73             : 
      74             : template<XDRMode mode>
      75             : bool
      76       22594 : js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
      77             : {
      78       22594 :     JSContext* cx = xdr->cx();
      79             : 
      80             :     /*
      81             :      * A script constant can be an arbitrary primitive value as they are used
      82             :      * to implement JSOP_LOOKUPSWITCH. But they cannot be objects, see
      83             :      * bug 407186.
      84             :      */
      85             :     enum ConstTag {
      86             :         SCRIPT_INT     = 0,
      87             :         SCRIPT_DOUBLE  = 1,
      88             :         SCRIPT_ATOM    = 2,
      89             :         SCRIPT_TRUE    = 3,
      90             :         SCRIPT_FALSE   = 4,
      91             :         SCRIPT_NULL    = 5,
      92             :         SCRIPT_OBJECT  = 6,
      93             :         SCRIPT_VOID    = 7,
      94             :         SCRIPT_HOLE    = 8
      95             :     };
      96             : 
      97             :     uint32_t tag;
      98             :     if (mode == XDR_ENCODE) {
      99        5901 :         if (vp.isInt32()) {
     100          27 :             tag = SCRIPT_INT;
     101        5874 :         } else if (vp.isDouble()) {
     102          14 :             tag = SCRIPT_DOUBLE;
     103        5860 :         } else if (vp.isString()) {
     104        3283 :             tag = SCRIPT_ATOM;
     105        2577 :         } else if (vp.isTrue()) {
     106           2 :             tag = SCRIPT_TRUE;
     107        2575 :         } else if (vp.isFalse()) {
     108           0 :             tag = SCRIPT_FALSE;
     109        2575 :         } else if (vp.isNull()) {
     110           0 :             tag = SCRIPT_NULL;
     111        2575 :         } else if (vp.isObject()) {
     112           0 :             tag = SCRIPT_OBJECT;
     113        2575 :         } else if (vp.isMagic(JS_ELEMENTS_HOLE)) {
     114           0 :             tag = SCRIPT_HOLE;
     115             :         } else {
     116        2575 :             MOZ_ASSERT(vp.isUndefined());
     117        2575 :             tag = SCRIPT_VOID;
     118             :         }
     119             :     }
     120             : 
     121       22594 :     if (!xdr->codeUint32(&tag))
     122           0 :         return false;
     123             : 
     124       22594 :     switch (tag) {
     125             :       case SCRIPT_INT: {
     126             :         uint32_t i;
     127             :         if (mode == XDR_ENCODE)
     128          27 :             i = uint32_t(vp.toInt32());
     129          32 :         if (!xdr->codeUint32(&i))
     130           0 :             return false;
     131             :         if (mode == XDR_DECODE)
     132           5 :             vp.set(Int32Value(int32_t(i)));
     133          32 :         break;
     134             :       }
     135             :       case SCRIPT_DOUBLE: {
     136             :         double d;
     137             :         if (mode == XDR_ENCODE)
     138          14 :             d = vp.toDouble();
     139          53 :         if (!xdr->codeDouble(&d))
     140           0 :             return false;
     141             :         if (mode == XDR_DECODE)
     142          39 :             vp.set(DoubleValue(d));
     143          53 :         break;
     144             :       }
     145             :       case SCRIPT_ATOM: {
     146       12390 :         RootedAtom atom(cx);
     147             :         if (mode == XDR_ENCODE)
     148        3283 :             atom = &vp.toString()->asAtom();
     149       12390 :         if (!XDRAtom(xdr, &atom))
     150           0 :             return false;
     151             :         if (mode == XDR_DECODE)
     152        9107 :             vp.set(StringValue(atom));
     153       12390 :         break;
     154             :       }
     155             :       case SCRIPT_TRUE:
     156             :         if (mode == XDR_DECODE)
     157           8 :             vp.set(BooleanValue(true));
     158          10 :         break;
     159             :       case SCRIPT_FALSE:
     160             :         if (mode == XDR_DECODE)
     161           6 :             vp.set(BooleanValue(false));
     162           6 :         break;
     163             :       case SCRIPT_NULL:
     164             :         if (mode == XDR_DECODE)
     165          14 :             vp.set(NullValue());
     166          14 :         break;
     167             :       case SCRIPT_OBJECT: {
     168           0 :         RootedObject obj(cx);
     169             :         if (mode == XDR_ENCODE)
     170           0 :             obj = &vp.toObject();
     171             : 
     172           0 :         if (!XDRObjectLiteral(xdr, &obj))
     173           0 :             return false;
     174             : 
     175             :         if (mode == XDR_DECODE)
     176           0 :             vp.setObject(*obj);
     177           0 :         break;
     178             :       }
     179             :       case SCRIPT_VOID:
     180             :         if (mode == XDR_DECODE)
     181        7514 :             vp.set(UndefinedValue());
     182       10089 :         break;
     183             :       case SCRIPT_HOLE:
     184             :         if (mode == XDR_DECODE)
     185           0 :             vp.setMagic(JS_ELEMENTS_HOLE);
     186           0 :         break;
     187             :     }
     188       22594 :     return true;
     189             : }
     190             : 
     191             : template bool
     192             : js::XDRScriptConst(XDRState<XDR_ENCODE>*, MutableHandleValue);
     193             : 
     194             : template bool
     195             : js::XDRScriptConst(XDRState<XDR_DECODE>*, MutableHandleValue);
     196             : 
     197             : // Code LazyScript's closed over bindings.
     198             : template<XDRMode mode>
     199             : static bool
     200        2679 : XDRLazyClosedOverBindings(XDRState<mode>* xdr, MutableHandle<LazyScript*> lazy)
     201             : {
     202        2679 :     JSContext* cx = xdr->cx();
     203        5358 :     RootedAtom atom(cx);
     204        9509 :     for (size_t i = 0; i < lazy->numClosedOverBindings(); i++) {
     205             :         uint8_t endOfScopeSentinel;
     206             :         if (mode == XDR_ENCODE) {
     207        1597 :             atom = lazy->closedOverBindings()[i];
     208        1597 :             endOfScopeSentinel = !atom;
     209             :         }
     210             : 
     211        6830 :         if (!xdr->codeUint8(&endOfScopeSentinel))
     212           0 :             return false;
     213             : 
     214        6830 :         if (endOfScopeSentinel)
     215        6516 :             atom = nullptr;
     216         314 :         else if (!XDRAtom(xdr, &atom))
     217           0 :             return false;
     218             : 
     219             :         if (mode == XDR_DECODE)
     220        5233 :             lazy->closedOverBindings()[i] = atom;
     221             :     }
     222             : 
     223        2679 :     return true;
     224             : }
     225             : 
     226             : // Code the missing part needed to re-create a LazyScript from a JSScript.
     227             : template<XDRMode mode>
     228             : static bool
     229        1168 : XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript script,
     230             :                       HandleScope enclosingScope, MutableHandle<LazyScript*> lazy)
     231             : {
     232         261 :     MOZ_ASSERT_IF(mode == XDR_ENCODE, script->isRelazifiable() && script->maybeLazyScript());
     233         261 :     MOZ_ASSERT_IF(mode == XDR_ENCODE, !lazy->numInnerFunctions());
     234             : 
     235        1168 :     JSContext* cx = xdr->cx();
     236             : 
     237             :     uint64_t packedFields;
     238             :     {
     239        1168 :         uint32_t begin = script->sourceStart();
     240        1168 :         uint32_t end = script->sourceEnd();
     241        1168 :         uint32_t toStringStart = script->toStringStart();
     242        1168 :         uint32_t toStringEnd = script->toStringEnd();
     243        1168 :         uint32_t lineno = script->lineno();
     244        1168 :         uint32_t column = script->column();
     245             : 
     246             :         if (mode == XDR_ENCODE) {
     247         261 :             packedFields = lazy->packedFields();
     248         261 :             MOZ_ASSERT(begin == lazy->begin());
     249         261 :             MOZ_ASSERT(end == lazy->end());
     250         261 :             MOZ_ASSERT(toStringStart == lazy->toStringStart());
     251         261 :             MOZ_ASSERT(toStringEnd == lazy->toStringEnd());
     252         261 :             MOZ_ASSERT(lineno == lazy->lineno());
     253         261 :             MOZ_ASSERT(column == lazy->column());
     254             :             // We can assert we have no inner functions because we don't
     255             :             // relazify scripts with inner functions.  See
     256             :             // JSFunction::createScriptForLazilyInterpretedFunction.
     257         261 :             MOZ_ASSERT(lazy->numInnerFunctions() == 0);
     258             :         }
     259             : 
     260        1168 :         if (!xdr->codeUint64(&packedFields))
     261           0 :             return false;
     262             : 
     263             :         if (mode == XDR_DECODE) {
     264        1814 :             RootedScriptSource sourceObject(cx, &script->scriptSourceUnwrap());
     265         907 :             lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, sourceObject,
     266             :                                         packedFields, begin, end, toStringStart, lineno, column));
     267         907 :             if (!lazy)
     268           0 :                 return false;
     269             : 
     270         907 :             lazy->setToStringEnd(toStringEnd);
     271             : 
     272             :             // As opposed to XDRLazyScript, we need to restore the runtime bits
     273             :             // of the script, as we are trying to match the fact this function
     274             :             // has already been parsed and that it would need to be re-lazified.
     275         907 :             lazy->initRuntimeFields(packedFields);
     276             :         }
     277             :     }
     278             : 
     279             :     // Code binding names.
     280        1168 :     if (!XDRLazyClosedOverBindings(xdr, lazy))
     281           0 :         return false;
     282             : 
     283             :     // No need to do anything with inner functions, since we asserted we don't
     284             :     // have any.
     285             : 
     286        1168 :     return true;
     287             : }
     288             : 
     289             : static inline uint32_t
     290       18142 : FindScopeIndex(JSScript* script, Scope& scope)
     291             : {
     292       18142 :     ScopeArray* scopes = script->scopes();
     293       18142 :     GCPtrScope* vector = scopes->vector;
     294       18142 :     unsigned length = scopes->length;
     295       28130 :     for (uint32_t i = 0; i < length; ++i) {
     296       28130 :         if (vector[i] == &scope)
     297       36284 :             return i;
     298             :     }
     299             : 
     300           0 :     MOZ_CRASH("Scope not found");
     301             : }
     302             : 
     303             : enum XDRClassKind {
     304             :     CK_RegexpObject,
     305             :     CK_JSFunction,
     306             :     CK_JSObject
     307             : };
     308             : 
     309             : template<XDRMode mode>
     310             : bool
     311       12152 : js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
     312             :               HandleScriptSource sourceObjectArg, HandleFunction fun,
     313             :               MutableHandleScript scriptp)
     314             : {
     315             :     /* NB: Keep this in sync with CopyScript. */
     316             : 
     317             :     enum ScriptBits {
     318             :         NoScriptRval,
     319             :         Strict,
     320             :         ContainsDynamicNameAccess,
     321             :         FunHasExtensibleScope,
     322             :         FunHasAnyAliasedFormal,
     323             :         ArgumentsHasVarBinding,
     324             :         NeedsArgsObj,
     325             :         HasMappedArgsObj,
     326             :         FunctionHasThisBinding,
     327             :         FunctionHasExtraBodyVarScope,
     328             :         IsGeneratorExp,
     329             :         IsLegacyGenerator,
     330             :         IsStarGenerator,
     331             :         IsAsync,
     332             :         HasRest,
     333             :         IsExprBody,
     334             :         OwnSource,
     335             :         ExplicitUseStrict,
     336             :         SelfHosted,
     337             :         HasSingleton,
     338             :         TreatAsRunOnce,
     339             :         HasLazyScript,
     340             :         HasNonSyntacticScope,
     341             :         HasInnerFunctions,
     342             :         NeedsHomeObject,
     343             :         IsDerivedClassConstructor,
     344             :         IsDefaultClassConstructor,
     345             :     };
     346             : 
     347             :     uint32_t length, lineno, column, nfixed, nslots;
     348             :     uint32_t natoms, nsrcnotes, i;
     349             :     uint32_t nconsts, nobjects, nscopes, nregexps, ntrynotes, nscopenotes, nyieldoffsets;
     350             :     uint32_t prologueLength, version;
     351       12152 :     uint32_t funLength = 0;
     352       12152 :     uint32_t nTypeSets = 0;
     353       12152 :     uint32_t scriptBits = 0;
     354       12152 :     uint32_t bodyScopeIndex = 0;
     355             : 
     356       12152 :     JSContext* cx = xdr->cx();
     357       24302 :     RootedScript script(cx);
     358       12152 :     natoms = nsrcnotes = 0;
     359       12152 :     nconsts = nobjects = nscopes = nregexps = ntrynotes = nscopenotes = nyieldoffsets = 0;
     360             : 
     361             :     if (mode == XDR_ENCODE) {
     362        2893 :         script = scriptp.get();
     363        2893 :         MOZ_ASSERT(script->functionNonDelazifying() == fun);
     364             : 
     365        2893 :         if (!fun && script->treatAsRunOnce() && script->hasRunOnce()) {
     366             :             // This is a toplevel or eval script that's runOnce.  We want to
     367             :             // make sure that we're not XDR-saving an object we emitted for
     368             :             // JSOP_OBJECT that then got modified.  So throw if we're not
     369             :             // cloning in JSOP_OBJECT or if we ever didn't clone in it in the
     370             :             // past.
     371           0 :             JSCompartment* comp = cx->compartment();
     372           0 :             if (!comp->creationOptions().cloneSingletons() ||
     373           0 :                 !comp->behaviors().getSingletonsAsTemplates())
     374             :             {
     375           0 :                 return xdr->fail(JS::TranscodeResult_Failure_RunOnceNotSupported);
     376             :             }
     377             :         }
     378             :     }
     379             : 
     380             :     if (mode == XDR_ENCODE)
     381        2893 :         length = script->length();
     382       12152 :     if (!xdr->codeUint32(&length))
     383           0 :         return false;
     384             : 
     385             :     if (mode == XDR_ENCODE) {
     386        2893 :         prologueLength = script->mainOffset();
     387        2893 :         MOZ_ASSERT(script->getVersion() != JSVERSION_UNKNOWN);
     388        2893 :         version = script->getVersion();
     389        2893 :         lineno = script->lineno();
     390        2893 :         column = script->column();
     391        2893 :         nfixed = script->nfixed();
     392        2893 :         nslots = script->nslots();
     393             : 
     394        2893 :         bodyScopeIndex = script->bodyScopeIndex();
     395        2893 :         natoms = script->natoms();
     396             : 
     397        2893 :         nsrcnotes = script->numNotes();
     398             : 
     399        2893 :         if (script->hasConsts())
     400          11 :             nconsts = script->consts()->length;
     401        2893 :         if (script->hasObjects())
     402         858 :             nobjects = script->objects()->length;
     403        2893 :         nscopes = script->scopes()->length;
     404        2893 :         if (script->hasTrynotes())
     405         496 :             ntrynotes = script->trynotes()->length;
     406        2893 :         if (script->hasScopeNotes())
     407        1058 :             nscopenotes = script->scopeNotes()->length;
     408        2893 :         if (script->hasYieldAndAwaitOffsets())
     409          99 :             nyieldoffsets = script->yieldAndAwaitOffsets().length();
     410             : 
     411        2893 :         nTypeSets = script->nTypeSets();
     412        2893 :         funLength = script->funLength();
     413             : 
     414        2893 :         if (script->noScriptRval())
     415          82 :             scriptBits |= (1 << NoScriptRval);
     416        2893 :         if (script->strict())
     417        2116 :             scriptBits |= (1 << Strict);
     418        2893 :         if (script->explicitUseStrict())
     419          57 :             scriptBits |= (1 << ExplicitUseStrict);
     420        2893 :         if (script->selfHosted())
     421           0 :             scriptBits |= (1 << SelfHosted);
     422        2893 :         if (script->bindingsAccessedDynamically())
     423           0 :             scriptBits |= (1 << ContainsDynamicNameAccess);
     424        2893 :         if (script->funHasExtensibleScope())
     425           0 :             scriptBits |= (1 << FunHasExtensibleScope);
     426        2893 :         if (script->funHasAnyAliasedFormal())
     427         210 :             scriptBits |= (1 << FunHasAnyAliasedFormal);
     428        2893 :         if (script->argumentsHasVarBinding())
     429           6 :             scriptBits |= (1 << ArgumentsHasVarBinding);
     430        2893 :         if (script->analyzedArgsUsage() && script->needsArgsObj())
     431           1 :             scriptBits |= (1 << NeedsArgsObj);
     432        2893 :         if (script->hasMappedArgsObj())
     433         731 :             scriptBits |= (1 << HasMappedArgsObj);
     434        2893 :         if (script->functionHasThisBinding())
     435        1154 :             scriptBits |= (1 << FunctionHasThisBinding);
     436        2893 :         if (script->functionHasExtraBodyVarScope())
     437          32 :             scriptBits |= (1 << FunctionHasExtraBodyVarScope);
     438        2893 :         MOZ_ASSERT_IF(sourceObjectArg, sourceObjectArg->source() == script->scriptSource());
     439        2893 :         if (!sourceObjectArg)
     440          82 :             scriptBits |= (1 << OwnSource);
     441        2893 :         if (script->isGeneratorExp())
     442           0 :             scriptBits |= (1 << IsGeneratorExp);
     443        2893 :         if (script->isLegacyGenerator())
     444           0 :             scriptBits |= (1 << IsLegacyGenerator);
     445        2893 :         if (script->isStarGenerator())
     446           9 :             scriptBits |= (1 << IsStarGenerator);
     447        2893 :         if (script->asyncKind() == AsyncFunction)
     448          90 :             scriptBits |= (1 << IsAsync);
     449        2893 :         if (script->hasRest())
     450          33 :             scriptBits |= (1 << HasRest);
     451        2893 :         if (script->isExprBody())
     452         264 :             scriptBits |= (1 << IsExprBody);
     453        2893 :         if (script->hasSingletons())
     454           0 :             scriptBits |= (1 << HasSingleton);
     455        2893 :         if (script->treatAsRunOnce())
     456           0 :             scriptBits |= (1 << TreatAsRunOnce);
     457        2893 :         if (script->isRelazifiable())
     458         261 :             scriptBits |= (1 << HasLazyScript);
     459        2893 :         if (script->hasNonSyntacticScope())
     460         268 :             scriptBits |= (1 << HasNonSyntacticScope);
     461        2893 :         if (script->hasInnerFunctions())
     462         441 :             scriptBits |= (1 << HasInnerFunctions);
     463        2893 :         if (script->needsHomeObject())
     464           7 :             scriptBits |= (1 << NeedsHomeObject);
     465        2893 :         if (script->isDerivedClassConstructor())
     466           8 :             scriptBits |= (1 << IsDerivedClassConstructor);
     467        2893 :         if (script->isDefaultClassConstructor())
     468           0 :             scriptBits |= (1 << IsDefaultClassConstructor);
     469             :     }
     470             : 
     471       12152 :     if (!xdr->codeUint32(&prologueLength))
     472           0 :         return false;
     473       12152 :     if (!xdr->codeUint32(&version))
     474           0 :         return false;
     475             : 
     476             :     // To fuse allocations, we need lengths of all embedded arrays early.
     477       12152 :     if (!xdr->codeUint32(&natoms))
     478           0 :         return false;
     479       12152 :     if (!xdr->codeUint32(&nsrcnotes))
     480           0 :         return false;
     481       12152 :     if (!xdr->codeUint32(&nconsts))
     482           0 :         return false;
     483       12152 :     if (!xdr->codeUint32(&nobjects))
     484           0 :         return false;
     485       12152 :     if (!xdr->codeUint32(&nscopes))
     486           0 :         return false;
     487       12152 :     if (!xdr->codeUint32(&ntrynotes))
     488           0 :         return false;
     489       12152 :     if (!xdr->codeUint32(&nscopenotes))
     490           0 :         return false;
     491       12152 :     if (!xdr->codeUint32(&nyieldoffsets))
     492           0 :         return false;
     493       12152 :     if (!xdr->codeUint32(&nTypeSets))
     494           0 :         return false;
     495       12152 :     if (!xdr->codeUint32(&funLength))
     496           0 :         return false;
     497       12152 :     if (!xdr->codeUint32(&scriptBits))
     498           0 :         return false;
     499             : 
     500       12152 :     MOZ_ASSERT(!!(scriptBits & (1 << OwnSource)) == !sourceObjectArg);
     501       24302 :     RootedScriptSource sourceObject(cx, sourceObjectArg);
     502             : 
     503             :     if (mode == XDR_DECODE) {
     504        9259 :         JSVersion version_ = JSVersion(version);
     505        9259 :         MOZ_ASSERT((version_ & VersionFlags::MASK) == unsigned(version_));
     506             : 
     507             :         // When loading from the bytecode cache, we get the CompileOption from
     508             :         // the document, which specify the version to use. If the version does
     509             :         // not match, then we should fail. This only applies to the top-level,
     510             :         // and not its inner functions.
     511       18518 :         mozilla::Maybe<CompileOptions> options;
     512        9259 :         if (xdr->hasOptions() && (scriptBits & (1 << OwnSource))) {
     513         179 :             options.emplace(xdr->cx(), xdr->options());
     514         537 :             if (options->version != version_ ||
     515         358 :                 options->noScriptRval != !!(scriptBits & (1 << NoScriptRval)) ||
     516         179 :                 options->selfHostingMode != !!(scriptBits & (1 << SelfHosted)))
     517             :             {
     518           0 :                 return xdr->fail(JS::TranscodeResult_Failure_WrongCompileOption);
     519             :             }
     520             :         } else {
     521        9080 :             options.emplace(xdr->cx(), version_);
     522       27240 :             (*options).setNoScriptRval(!!(scriptBits & (1 << NoScriptRval)))
     523       27240 :                       .setSelfHostingMode(!!(scriptBits & (1 << SelfHosted)));
     524             :         }
     525             : 
     526        9259 :         if (scriptBits & (1 << OwnSource)) {
     527        1352 :             ScriptSource* ss = cx->new_<ScriptSource>();
     528        1351 :             if (!ss)
     529           0 :                 return false;
     530        2703 :             ScriptSourceHolder ssHolder(ss);
     531             : 
     532             :             /*
     533             :              * We use this CompileOptions only to initialize the
     534             :              * ScriptSourceObject. Most CompileOptions fields aren't used by
     535             :              * ScriptSourceObject, and those that are (element; elementAttributeName)
     536             :              * aren't preserved by XDR. So this can be simple.
     537             :              */
     538        1351 :             if (!ss->initFromOptions(cx, *options))
     539           0 :                 return false;
     540             : 
     541        1352 :             sourceObject = ScriptSourceObject::create(cx, ss);
     542        1352 :             if (xdr->hasScriptSourceObjectOut()) {
     543             :                 // When the ScriptSourceObjectOut is provided by ParseTask, it
     544             :                 // is stored in a location which is traced by the GC.
     545         179 :                 *xdr->scriptSourceObjectOut() = sourceObject;
     546             :             } else {
     547        4692 :                 if (!sourceObject ||
     548        4692 :                     !ScriptSourceObject::initFromOptions(cx, sourceObject, *options))
     549             :                 {
     550           0 :                     return false;
     551             :                 }
     552             :             }
     553             :         }
     554             : 
     555        9259 :         script = JSScript::Create(cx, *options, sourceObject, 0, 0, 0, 0);
     556        9259 :         if (!script)
     557           0 :             return false;
     558             : 
     559             :         // Set the script in its function now so that inner scripts to be
     560             :         // decoded may iterate the static scope chain.
     561        9259 :         if (fun)
     562        8998 :             fun->initScript(script);
     563             :     } else {
     564             :         // When encoding, we do not mutate any of the JSScript or LazyScript, so
     565             :         // we can safely unwrap it here.
     566        2893 :         sourceObject = &script->scriptSourceUnwrap();
     567             :     }
     568             : 
     569             :     if (mode == XDR_DECODE) {
     570        9259 :         if (!JSScript::partiallyInit(cx, script, nscopes, nconsts, nobjects, ntrynotes,
     571             :                                      nscopenotes, nyieldoffsets, nTypeSets))
     572             :         {
     573           0 :             return false;
     574             :         }
     575             : 
     576        9259 :         MOZ_ASSERT(!script->mainOffset());
     577        9259 :         script->mainOffset_ = prologueLength;
     578        9259 :         script->funLength_ = funLength;
     579             : 
     580        9259 :         scriptp.set(script);
     581             : 
     582        9259 :         if (scriptBits & (1 << Strict))
     583        4800 :             script->strict_ = true;
     584        9259 :         if (scriptBits & (1 << ExplicitUseStrict))
     585         169 :             script->explicitUseStrict_ = true;
     586        9259 :         if (scriptBits & (1 << ContainsDynamicNameAccess))
     587           0 :             script->bindingsAccessedDynamically_ = true;
     588        9259 :         if (scriptBits & (1 << FunHasExtensibleScope))
     589           0 :             script->funHasExtensibleScope_ = true;
     590        9259 :         if (scriptBits & (1 << FunHasAnyAliasedFormal))
     591         637 :             script->funHasAnyAliasedFormal_ = true;
     592        9259 :         if (scriptBits & (1 << ArgumentsHasVarBinding))
     593          56 :             script->setArgumentsHasVarBinding();
     594        9259 :         if (scriptBits & (1 << NeedsArgsObj))
     595           6 :             script->setNeedsArgsObj(true);
     596        9259 :         if (scriptBits & (1 << HasMappedArgsObj))
     597        4308 :             script->hasMappedArgsObj_ = true;
     598        9259 :         if (scriptBits & (1 << FunctionHasThisBinding))
     599        4941 :             script->functionHasThisBinding_ = true;
     600        9259 :         if (scriptBits & (1 << FunctionHasExtraBodyVarScope))
     601         110 :             script->functionHasExtraBodyVarScope_ = true;
     602        9259 :         if (scriptBits & (1 << IsGeneratorExp))
     603           0 :             script->isGeneratorExp_ = true;
     604        9259 :         if (scriptBits & (1 << HasSingleton))
     605           0 :             script->hasSingletons_ = true;
     606        9259 :         if (scriptBits & (1 << TreatAsRunOnce))
     607           0 :             script->treatAsRunOnce_ = true;
     608        9259 :         if (scriptBits & (1 << HasNonSyntacticScope))
     609         970 :             script->hasNonSyntacticScope_ = true;
     610        9259 :         if (scriptBits & (1 << HasInnerFunctions))
     611        1298 :             script->hasInnerFunctions_ = true;
     612        9259 :         if (scriptBits & (1 << NeedsHomeObject))
     613          32 :             script->needsHomeObject_ = true;
     614        9259 :         if (scriptBits & (1 << IsDerivedClassConstructor))
     615          42 :             script->isDerivedClassConstructor_ = true;
     616        9259 :         if (scriptBits & (1 << IsDefaultClassConstructor))
     617           0 :             script->isDefaultClassConstructor_ = true;
     618             : 
     619        9259 :         if (scriptBits & (1 << IsLegacyGenerator)) {
     620           0 :             MOZ_ASSERT(!(scriptBits & (1 << IsStarGenerator)));
     621           0 :             script->setGeneratorKind(LegacyGenerator);
     622        9259 :         } else if (scriptBits & (1 << IsStarGenerator))
     623          21 :             script->setGeneratorKind(StarGenerator);
     624             : 
     625        9259 :         if (scriptBits & (1 << IsAsync))
     626         297 :             script->setAsyncKind(AsyncFunction);
     627        9259 :         if (scriptBits & (1 << HasRest))
     628          48 :             script->setHasRest();
     629        9259 :         if (scriptBits & (1 << IsExprBody))
     630         552 :             script->setIsExprBody();
     631             :     }
     632             : 
     633             :     JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
     634             :     JS_STATIC_ASSERT(sizeof(jssrcnote) == 1);
     635             : 
     636       12152 :     if (scriptBits & (1 << OwnSource)) {
     637        1434 :         if (!sourceObject->source()->performXDR<mode>(xdr))
     638           0 :             return false;
     639             :     }
     640       12152 :     if (!xdr->codeUint32(&script->sourceStart_))
     641           0 :         return false;
     642       12152 :     if (!xdr->codeUint32(&script->sourceEnd_))
     643           0 :         return false;
     644       12152 :     if (!xdr->codeUint32(&script->toStringStart_))
     645           0 :         return false;
     646       12152 :     if (!xdr->codeUint32(&script->toStringEnd_))
     647           0 :         return false;
     648             : 
     649       36456 :     if (!xdr->codeUint32(&lineno) ||
     650       24304 :         !xdr->codeUint32(&column) ||
     651       36456 :         !xdr->codeUint32(&nfixed) ||
     652       12152 :         !xdr->codeUint32(&nslots))
     653             :     {
     654           0 :         return false;
     655             :     }
     656             : 
     657       12152 :     if (!xdr->codeUint32(&bodyScopeIndex))
     658           0 :         return false;
     659             : 
     660             :     if (mode == XDR_DECODE) {
     661        9259 :         script->lineno_ = lineno;
     662        9259 :         script->column_ = column;
     663        9259 :         script->nfixed_ = nfixed;
     664        9259 :         script->nslots_ = nslots;
     665        9259 :         script->bodyScopeIndex_ = bodyScopeIndex;
     666             :     }
     667             : 
     668             :     if (mode == XDR_DECODE) {
     669        9259 :         if (!script->createScriptData(cx, length, nsrcnotes, natoms)) {
     670           0 :             return false;
     671             :         }
     672             :     }
     673             : 
     674           0 :     auto scriptDataGuard = mozilla::MakeScopeExit([&] {
     675             :         if (mode == XDR_DECODE)
     676           0 :             script->freeScriptData();
     677       24302 :     });
     678             : 
     679       12152 :     jsbytecode* code = script->code();
     680       12152 :     if (!xdr->codeBytes(code, length) || !xdr->codeBytes(code + length, nsrcnotes)) {
     681           0 :         return false;
     682             :     }
     683             : 
     684      132426 :     for (i = 0; i != natoms; ++i) {
     685             :         if (mode == XDR_DECODE) {
     686      183578 :             RootedAtom tmp(cx);
     687       91789 :             if (!XDRAtom(xdr, &tmp))
     688           0 :                 return false;
     689       91788 :             script->atoms()[i].init(tmp);
     690             :         } else {
     691       56970 :             RootedAtom tmp(cx, script->atoms()[i]);
     692       28485 :             if (!XDRAtom(xdr, &tmp))
     693           0 :                 return false;
     694             :         }
     695             :     }
     696             : 
     697       12152 :     scriptDataGuard.release();
     698             :     if (mode == XDR_DECODE) {
     699        9259 :         if (!script->shareScriptData(cx))
     700           0 :             return false;
     701             :     }
     702             : 
     703       12152 :     if (nconsts) {
     704          31 :         GCPtrValue* vector = script->consts()->vector;
     705          62 :         RootedValue val(cx);
     706          84 :         for (i = 0; i != nconsts; ++i) {
     707             :             if (mode == XDR_ENCODE)
     708          14 :                 val = vector[i];
     709          53 :             if (!XDRScriptConst(xdr, &val))
     710           0 :                 return false;
     711             :             if (mode == XDR_DECODE)
     712          39 :                 vector[i].init(val);
     713             :         }
     714             :     }
     715             : 
     716             :     {
     717       12152 :         MOZ_ASSERT(nscopes != 0);
     718       12152 :         GCPtrScope* vector = script->scopes()->vector;
     719       24304 :         RootedScope scope(cx);
     720       24304 :         RootedScope enclosing(cx);
     721             :         ScopeKind scopeKind;
     722       12152 :         uint32_t enclosingScopeIndex = 0;
     723       33734 :         for (i = 0; i != nscopes; ++i) {
     724             :             if (mode == XDR_ENCODE) {
     725        5213 :                 scope = vector[i];
     726        5213 :                 scopeKind = scope->kind();
     727             :             } else {
     728       16369 :                 scope = nullptr;
     729             :             }
     730             : 
     731       21582 :             if (!xdr->codeEnum32(&scopeKind))
     732           0 :                 return false;
     733             : 
     734             :             if (mode == XDR_ENCODE) {
     735        5213 :                 if (i == 0) {
     736        2893 :                     enclosingScopeIndex = UINT32_MAX;
     737             :                 } else {
     738        2320 :                     MOZ_ASSERT(scope->enclosing());
     739        2320 :                     enclosingScopeIndex = FindScopeIndex(script, *scope->enclosing());
     740             :                 }
     741             :             }
     742             : 
     743       21582 :             if (!xdr->codeUint32(&enclosingScopeIndex))
     744           0 :                 return false;
     745             : 
     746             :             if (mode == XDR_DECODE) {
     747       16369 :                 if (i == 0) {
     748        9259 :                     MOZ_ASSERT(enclosingScopeIndex == UINT32_MAX);
     749        9259 :                     enclosing = scriptEnclosingScope;
     750             :                 } else {
     751        7110 :                     MOZ_ASSERT(enclosingScopeIndex < i);
     752        7110 :                     enclosing = vector[enclosingScopeIndex];
     753             :                 }
     754             :             }
     755             : 
     756       21582 :             switch (scopeKind) {
     757             :               case ScopeKind::Function:
     758       11809 :                 MOZ_ASSERT(i == script->bodyScopeIndex());
     759       11809 :                 if (!FunctionScope::XDR(xdr, fun, enclosing, &scope))
     760           0 :                     return false;
     761       11809 :                 break;
     762             :               case ScopeKind::FunctionBodyVar:
     763             :               case ScopeKind::ParameterExpressionVar:
     764         142 :                 if (!VarScope::XDR(xdr, scopeKind, enclosing, &scope))
     765           0 :                     return false;
     766         142 :                 break;
     767             :               case ScopeKind::Lexical:
     768             :               case ScopeKind::SimpleCatch:
     769             :               case ScopeKind::Catch:
     770             :               case ScopeKind::NamedLambda:
     771             :               case ScopeKind::StrictNamedLambda:
     772        9288 :                 if (!LexicalScope::XDR(xdr, scopeKind, enclosing, &scope))
     773           0 :                     return false;
     774        9288 :                 break;
     775             :               case ScopeKind::With:
     776             :                 if (mode == XDR_DECODE) {
     777           0 :                     scope = WithScope::create(cx, enclosing);
     778           0 :                     if (!scope)
     779           0 :                         return false;
     780             :                 }
     781           0 :                 break;
     782             :               case ScopeKind::Eval:
     783             :               case ScopeKind::StrictEval:
     784           0 :                 if (!EvalScope::XDR(xdr, scopeKind, enclosing, &scope))
     785           0 :                     return false;
     786           0 :                 break;
     787             :               case ScopeKind::Global:
     788             :               case ScopeKind::NonSyntactic:
     789         343 :                 if (!GlobalScope::XDR(xdr, scopeKind, &scope))
     790           0 :                     return false;
     791         343 :                 break;
     792             :               case ScopeKind::Module:
     793           0 :                 MOZ_CRASH("NYI");
     794             :                 break;
     795             :               case ScopeKind::WasmFunction:
     796           0 :                 MOZ_CRASH("wasm functions cannot be nested in JSScripts");
     797             :                 break;
     798             :             }
     799             : 
     800             :             if (mode == XDR_DECODE)
     801       16369 :                 vector[i].init(scope);
     802             :         }
     803             :     }
     804             : 
     805             :     /*
     806             :      * Here looping from 0-to-length to xdr objects is essential to ensure that
     807             :      * all references to enclosing blocks (via FindScopeIndex below) happen
     808             :      * after the enclosing block has been XDR'd.
     809             :      */
     810       28991 :     for (i = 0; i != nobjects; ++i) {
     811       16841 :         GCPtrObject* objp = &script->objects()->vector[i];
     812             :         XDRClassKind classk;
     813             : 
     814             :         if (mode == XDR_ENCODE) {
     815        4399 :             JSObject* obj = *objp;
     816        4399 :             if (obj->is<RegExpObject>())
     817          88 :                 classk = CK_RegexpObject;
     818        4311 :             else if (obj->is<JSFunction>())
     819        3040 :                 classk = CK_JSFunction;
     820        1271 :             else if (obj->is<PlainObject>() || obj->is<ArrayObject>())
     821        1271 :                 classk = CK_JSObject;
     822             :             else
     823           0 :                 MOZ_CRASH("Cannot encode this class of object.");
     824             :         }
     825             : 
     826       16841 :         if (!xdr->codeEnum32(&classk))
     827           0 :             return false;
     828             : 
     829       16841 :         switch (classk) {
     830             :           case CK_RegexpObject: {
     831         348 :             Rooted<RegExpObject*> regexp(cx);
     832             :             if (mode == XDR_ENCODE)
     833          88 :                 regexp = &(*objp)->as<RegExpObject>();
     834         348 :             if (!XDRScriptRegExpObject(xdr, &regexp))
     835           0 :                 return false;
     836             :             if (mode == XDR_DECODE)
     837         259 :                 *objp = regexp;
     838         347 :             break;
     839             :           }
     840             : 
     841             :           case CK_JSFunction: {
     842             :             /* Code the nested function's enclosing scope. */
     843       11959 :             uint32_t funEnclosingScopeIndex = 0;
     844       11959 :             RootedScope funEnclosingScope(cx);
     845             :             if (mode == XDR_ENCODE) {
     846        6080 :                 RootedFunction function(cx, &(*objp)->as<JSFunction>());
     847             : 
     848        3040 :                 if (function->isInterpretedLazy()) {
     849         229 :                     funEnclosingScope = function->lazyScript()->enclosingScope();
     850        2811 :                 } else if (function->isInterpreted()) {
     851        2811 :                     funEnclosingScope = function->nonLazyScript()->enclosingScope();
     852             :                 } else {
     853           0 :                     MOZ_ASSERT(function->isAsmJSNative());
     854           0 :                     return xdr->fail(JS::TranscodeResult_Failure_AsmJSNotSupported);
     855             :                 }
     856             : 
     857        3040 :                 funEnclosingScopeIndex = FindScopeIndex(script, *funEnclosingScope);
     858             :             }
     859             : 
     860       11959 :             if (!xdr->codeUint32(&funEnclosingScopeIndex))
     861           0 :                 return false;
     862             : 
     863             :             if (mode == XDR_DECODE) {
     864        8919 :                 MOZ_ASSERT(funEnclosingScopeIndex < script->scopes()->length);
     865        8919 :                 funEnclosingScope = script->scopes()->vector[funEnclosingScopeIndex];
     866             :             }
     867             : 
     868             :             // Code nested function and script.
     869       11959 :             RootedFunction tmp(cx);
     870             :             if (mode == XDR_ENCODE)
     871        3040 :                 tmp = &(*objp)->as<JSFunction>();
     872       11959 :             if (!XDRInterpretedFunction(xdr, funEnclosingScope, sourceObject, &tmp))
     873           0 :                 return false;
     874       11958 :             *objp = tmp;
     875       11958 :             break;
     876             :           }
     877             : 
     878             :           case CK_JSObject: {
     879             :             /* Code object literal. */
     880        4534 :             RootedObject tmp(cx, *objp);
     881        4534 :             if (!XDRObjectLiteral(xdr, &tmp))
     882           0 :                 return false;
     883        4534 :             *objp = tmp;
     884        4534 :             break;
     885             :           }
     886             : 
     887             :           default: {
     888           0 :             MOZ_ASSERT(false, "Unknown class kind.");
     889             :             return xdr->fail(JS::TranscodeResult_Failure_UnknownClassKind);
     890             :           }
     891             :         }
     892             :     }
     893             : 
     894       12150 :     if (ntrynotes != 0) {
     895        2007 :         JSTryNote* tnfirst = script->trynotes()->vector;
     896        2007 :         MOZ_ASSERT(script->trynotes()->length == ntrynotes);
     897        2007 :         JSTryNote* tn = tnfirst + ntrynotes;
     898        4438 :         do {
     899        6445 :             --tn;
     900       19335 :             if (!xdr->codeUint8(&tn->kind) ||
     901       12890 :                 !xdr->codeUint32(&tn->stackDepth) ||
     902       19335 :                 !xdr->codeUint32(&tn->start) ||
     903        6445 :                 !xdr->codeUint32(&tn->length)) {
     904           0 :                 return false;
     905             :             }
     906        6445 :         } while (tn != tnfirst);
     907             :     }
     908             : 
     909       25328 :     for (i = 0; i < nscopenotes; ++i) {
     910       13178 :         ScopeNote* note = &script->scopeNotes()->vector[i];
     911       39534 :         if (!xdr->codeUint32(&note->index) ||
     912       26356 :             !xdr->codeUint32(&note->start) ||
     913       39534 :             !xdr->codeUint32(&note->length) ||
     914       13178 :             !xdr->codeUint32(&note->parent))
     915             :         {
     916           0 :             return false;
     917             :         }
     918             :     }
     919             : 
     920       13351 :     for (i = 0; i < nyieldoffsets; ++i) {
     921        1201 :         uint32_t* offset = &script->yieldAndAwaitOffsets()[i];
     922        1201 :         if (!xdr->codeUint32(offset))
     923           0 :             return false;
     924             :     }
     925             : 
     926       12150 :     if (scriptBits & (1 << HasLazyScript)) {
     927        2336 :         Rooted<LazyScript*> lazy(cx);
     928             :         if (mode == XDR_ENCODE)
     929         261 :             lazy = script->maybeLazyScript();
     930             : 
     931        1168 :         if (!XDRRelazificationInfo(xdr, fun, script, scriptEnclosingScope, &lazy))
     932           0 :             return false;
     933             : 
     934             :         if (mode == XDR_DECODE)
     935         907 :             script->setLazyScript(lazy);
     936             :     }
     937             : 
     938             :     if (mode == XDR_DECODE) {
     939        9257 :         scriptp.set(script);
     940             : 
     941             :         /* see BytecodeEmitter::tellDebuggerAboutCompiledScript */
     942        9257 :         if (!fun && !cx->helperThread())
     943          82 :             Debugger::onNewScript(cx, script);
     944             :     }
     945             : 
     946       12150 :     return true;
     947             : }
     948             : 
     949             : template bool
     950             : js::XDRScript(XDRState<XDR_ENCODE>*, HandleScope, HandleScriptSource, HandleFunction,
     951             :               MutableHandleScript);
     952             : 
     953             : template bool
     954             : js::XDRScript(XDRState<XDR_DECODE>*, HandleScope, HandleScriptSource, HandleFunction,
     955             :               MutableHandleScript);
     956             : 
     957             : template<XDRMode mode>
     958             : bool
     959        1511 : js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
     960             :                   HandleScriptSource sourceObject, HandleFunction fun,
     961             :                   MutableHandle<LazyScript*> lazy)
     962             : {
     963        1511 :     JSContext* cx = xdr->cx();
     964             : 
     965             :     {
     966             :         uint32_t begin;
     967             :         uint32_t end;
     968             :         uint32_t toStringStart;
     969             :         uint32_t toStringEnd;
     970             :         uint32_t lineno;
     971             :         uint32_t column;
     972             :         uint64_t packedFields;
     973             : 
     974             :         if (mode == XDR_ENCODE) {
     975             :             // Note: it's possible the LazyScript has a non-null script_ pointer
     976             :             // to a JSScript. We don't encode it: we can just delazify the
     977             :             // lazy script.
     978             : 
     979         285 :             MOZ_ASSERT(fun == lazy->functionNonDelazifying());
     980             : 
     981         285 :             begin = lazy->begin();
     982         285 :             end = lazy->end();
     983         285 :             toStringStart = lazy->toStringStart();
     984         285 :             toStringEnd = lazy->toStringEnd();
     985         285 :             lineno = lazy->lineno();
     986         285 :             column = lazy->column();
     987         285 :             packedFields = lazy->packedFields();
     988             :         }
     989             : 
     990        6044 :         if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) ||
     991        3022 :             !xdr->codeUint32(&toStringStart) ||
     992        3022 :             !xdr->codeUint32(&toStringEnd) ||
     993        6044 :             !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) ||
     994        1511 :             !xdr->codeUint64(&packedFields))
     995             :         {
     996           0 :             return false;
     997             :         }
     998             : 
     999             :         if (mode == XDR_DECODE) {
    1000        1226 :             lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, sourceObject,
    1001             :                                         packedFields, begin, end, toStringStart, lineno, column));
    1002        1226 :             if (!lazy)
    1003           0 :                 return false;
    1004        1226 :             lazy->setToStringEnd(toStringEnd);
    1005        1226 :             fun->initLazyScript(lazy);
    1006             :         }
    1007             :     }
    1008             : 
    1009             :     // Code closed-over bindings.
    1010        1511 :     if (!XDRLazyClosedOverBindings(xdr, lazy))
    1011           0 :         return false;
    1012             : 
    1013             :     // Code inner functions.
    1014             :     {
    1015        3022 :         RootedFunction func(cx);
    1016        1511 :         GCPtrFunction* innerFunctions = lazy->innerFunctions();
    1017        1511 :         size_t numInnerFunctions = lazy->numInnerFunctions();
    1018        1781 :         for (size_t i = 0; i < numInnerFunctions; i++) {
    1019             :             if (mode == XDR_ENCODE)
    1020          56 :                 func = innerFunctions[i];
    1021             : 
    1022         270 :             if (!XDRInterpretedFunction(xdr, nullptr, nullptr, &func))
    1023           0 :                 return false;
    1024             : 
    1025             :             if (mode == XDR_DECODE)
    1026         214 :                 innerFunctions[i] = func;
    1027             :         }
    1028             :     }
    1029             : 
    1030        1511 :     return true;
    1031             : }
    1032             : 
    1033             : template bool
    1034             : js::XDRLazyScript(XDRState<XDR_ENCODE>*, HandleScope, HandleScriptSource,
    1035             :                   HandleFunction, MutableHandle<LazyScript*>);
    1036             : 
    1037             : template bool
    1038             : js::XDRLazyScript(XDRState<XDR_DECODE>*, HandleScope, HandleScriptSource,
    1039             :                   HandleFunction, MutableHandle<LazyScript*>);
    1040             : 
    1041             : void
    1042       24877 : JSScript::setSourceObject(JSObject* object)
    1043             : {
    1044       24877 :     MOZ_ASSERT(compartment() == object->compartment());
    1045       24877 :     sourceObject_ = object;
    1046       24878 : }
    1047             : 
    1048             : void
    1049           3 : JSScript::setDefaultClassConstructorSpan(JSObject* sourceObject, uint32_t start, uint32_t end)
    1050             : {
    1051           3 :     MOZ_ASSERT(isDefaultClassConstructor());
    1052           3 :     setSourceObject(sourceObject);
    1053           3 :     toStringStart_ = start;
    1054           3 :     toStringEnd_ = end;
    1055           3 : }
    1056             : 
    1057             : js::ScriptSourceObject&
    1058       42392 : JSScript::scriptSourceUnwrap() const {
    1059             :     // This may be called off the main thread. It's OK not to expose the source
    1060             :     // object here as it doesn't escape.
    1061       42392 :     return UncheckedUnwrapWithoutExpose(sourceObject())->as<ScriptSourceObject>();
    1062             : }
    1063             : 
    1064             : js::ScriptSource*
    1065       38592 : JSScript::scriptSource() const {
    1066       38592 :     return scriptSourceUnwrap().source();
    1067             : }
    1068             : 
    1069             : js::ScriptSource*
    1070           0 : JSScript::maybeForwardedScriptSource() const {
    1071           0 :     JSObject* source = MaybeForwarded(sourceObject());
    1072             :     // This may be called during GC. It's OK not to expose the source object
    1073             :     // here as it doesn't escape.
    1074           0 :     return UncheckedUnwrapWithoutExpose(source)->as<ScriptSourceObject>().source();
    1075             : }
    1076             : 
    1077             : bool
    1078         613 : JSScript::initScriptCounts(JSContext* cx)
    1079             : {
    1080         613 :     MOZ_ASSERT(!hasScriptCounts());
    1081             : 
    1082             :     // Record all pc which are the first instruction of a basic block.
    1083        1226 :     mozilla::Vector<jsbytecode*, 16, SystemAllocPolicy> jumpTargets;
    1084         613 :     jsbytecode* mainPc = main();
    1085         613 :     jsbytecode* end = codeEnd();
    1086       61310 :     for (jsbytecode* pc = code(); pc != end; pc = GetNextPc(pc)) {
    1087       60697 :         if (BytecodeIsJumpTarget(JSOp(*pc)) || pc == mainPc) {
    1088        7311 :             if (!jumpTargets.append(pc)) {
    1089           0 :                 ReportOutOfMemory(cx);
    1090           0 :                 return false;
    1091             :             }
    1092             :         }
    1093             :     }
    1094             : 
    1095             :     // Initialize all PCCounts counters to 0.
    1096        1226 :     ScriptCounts::PCCountsVector base;
    1097         613 :     if (!base.reserve(jumpTargets.length())) {
    1098           0 :         ReportOutOfMemory(cx);
    1099           0 :         return false;
    1100             :     }
    1101             : 
    1102        7924 :     for (size_t i = 0; i < jumpTargets.length(); i++)
    1103        7311 :         base.infallibleEmplaceBack(pcToOffset(jumpTargets[i]));
    1104             : 
    1105             :     // Create compartment's scriptCountsMap if necessary.
    1106         613 :     ScriptCountsMap* map = compartment()->scriptCountsMap;
    1107         613 :     if (!map) {
    1108          75 :         map = cx->new_<ScriptCountsMap>();
    1109          75 :         if (!map) {
    1110           0 :             ReportOutOfMemory(cx);
    1111           0 :             return false;
    1112             :         }
    1113             : 
    1114          75 :         if (!map->init()) {
    1115           0 :             js_delete(map);
    1116           0 :             ReportOutOfMemory(cx);
    1117           0 :             return false;
    1118             :         }
    1119             : 
    1120          75 :         compartment()->scriptCountsMap = map;
    1121             :     }
    1122             : 
    1123             :     // Allocate the ScriptCounts.
    1124         613 :     ScriptCounts* sc = cx->new_<ScriptCounts>(Move(base));
    1125         613 :     if (!sc) {
    1126           0 :         ReportOutOfMemory(cx);
    1127           0 :         return false;
    1128             :     }
    1129           0 :     auto guardScriptCounts = mozilla::MakeScopeExit([&] () {
    1130           0 :         js_delete(sc);
    1131        1226 :     });
    1132             : 
    1133             :     // Register the current ScriptCounts in the compartment's map.
    1134         613 :     if (!map->putNew(this, sc)) {
    1135           0 :         ReportOutOfMemory(cx);
    1136           0 :         return false;
    1137             :     }
    1138             : 
    1139             :     // safe to set this;  we can't fail after this point.
    1140         613 :     hasScriptCounts_ = true;
    1141         613 :     guardScriptCounts.release();
    1142             : 
    1143             :     // Enable interrupts in any interpreter frames running on this script. This
    1144             :     // is used to let the interpreter increment the PCCounts, if present.
    1145        5108 :     for (ActivationIterator iter(cx); !iter.done(); ++iter) {
    1146        4495 :         if (iter->isInterpreter())
    1147        3584 :             iter->asInterpreter()->enableInterruptsIfRunning(this);
    1148             :     }
    1149             : 
    1150         613 :     return true;
    1151             : }
    1152             : 
    1153       13600 : static inline ScriptCountsMap::Ptr GetScriptCountsMapEntry(JSScript* script)
    1154             : {
    1155       13600 :     MOZ_ASSERT(script->hasScriptCounts());
    1156       13600 :     ScriptCountsMap* map = script->compartment()->scriptCountsMap;
    1157       13600 :     ScriptCountsMap::Ptr p = map->lookup(script);
    1158       13600 :     MOZ_ASSERT(p);
    1159       13600 :     return p;
    1160             : }
    1161             : 
    1162             : static inline ScriptNameMap::Ptr
    1163           0 : GetScriptNameMapEntry(JSScript* script)
    1164             : {
    1165           0 :     ScriptNameMap* map = script->compartment()->scriptNameMap;
    1166           0 :     auto p = map->lookup(script);
    1167           0 :     MOZ_ASSERT(p);
    1168           0 :     return p;
    1169             : }
    1170             : 
    1171             : ScriptCounts&
    1172       13600 : JSScript::getScriptCounts()
    1173             : {
    1174       13600 :     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
    1175       13600 :     return *p->value();
    1176             : }
    1177             : 
    1178             : const char*
    1179           0 : JSScript::getScriptName()
    1180             : {
    1181           0 :     auto p = GetScriptNameMapEntry(this);
    1182           0 :     return p->value();
    1183             : }
    1184             : 
    1185             : js::PCCounts*
    1186       10685 : ScriptCounts::maybeGetPCCounts(size_t offset) {
    1187       10685 :     PCCounts searched = PCCounts(offset);
    1188       10685 :     PCCounts* elem = std::lower_bound(pcCounts_.begin(), pcCounts_.end(), searched);
    1189       10685 :     if (elem == pcCounts_.end() || elem->pcOffset() != offset)
    1190           0 :         return nullptr;
    1191       10685 :     return elem;
    1192             : }
    1193             : 
    1194             : const js::PCCounts*
    1195           0 : ScriptCounts::maybeGetPCCounts(size_t offset) const {
    1196           0 :     PCCounts searched = PCCounts(offset);
    1197           0 :     const PCCounts* elem = std::lower_bound(pcCounts_.begin(), pcCounts_.end(), searched);
    1198           0 :     if (elem == pcCounts_.end() || elem->pcOffset() != offset)
    1199           0 :         return nullptr;
    1200           0 :     return elem;
    1201             : }
    1202             : 
    1203             : js::PCCounts*
    1204         920 : ScriptCounts::getImmediatePrecedingPCCounts(size_t offset)
    1205             : {
    1206         920 :     PCCounts searched = PCCounts(offset);
    1207         920 :     PCCounts* elem = std::lower_bound(pcCounts_.begin(), pcCounts_.end(), searched);
    1208         920 :     if (elem == pcCounts_.end())
    1209           0 :         return &pcCounts_.back();
    1210         920 :     if (elem->pcOffset() == offset)
    1211         898 :         return elem;
    1212          22 :     if (elem != pcCounts_.begin())
    1213          22 :         return elem - 1;
    1214           0 :     return nullptr;
    1215             : }
    1216             : 
    1217             : const js::PCCounts*
    1218           0 : ScriptCounts::maybeGetThrowCounts(size_t offset) const {
    1219           0 :     PCCounts searched = PCCounts(offset);
    1220           0 :     const PCCounts* elem = std::lower_bound(throwCounts_.begin(), throwCounts_.end(), searched);
    1221           0 :     if (elem == throwCounts_.end() || elem->pcOffset() != offset)
    1222           0 :         return nullptr;
    1223           0 :     return elem;
    1224             : }
    1225             : 
    1226             : const js::PCCounts*
    1227          22 : ScriptCounts::getImmediatePrecedingThrowCounts(size_t offset) const
    1228             : {
    1229          22 :     PCCounts searched = PCCounts(offset);
    1230          22 :     const PCCounts* elem = std::lower_bound(throwCounts_.begin(), throwCounts_.end(), searched);
    1231          22 :     if (elem == throwCounts_.end()) {
    1232          20 :         if (throwCounts_.begin() == throwCounts_.end())
    1233          20 :             return nullptr;
    1234           0 :         return &throwCounts_.back();
    1235             :     }
    1236           2 :     if (elem->pcOffset() == offset)
    1237           0 :         return elem;
    1238           2 :     if (elem != throwCounts_.begin())
    1239           0 :         return elem - 1;
    1240           2 :     return nullptr;
    1241             : }
    1242             : 
    1243             : js::PCCounts*
    1244        1995 : ScriptCounts::getThrowCounts(size_t offset) {
    1245        1995 :     PCCounts searched = PCCounts(offset);
    1246        1995 :     PCCounts* elem = std::lower_bound(throwCounts_.begin(), throwCounts_.end(), searched);
    1247        1995 :     if (elem == throwCounts_.end() || elem->pcOffset() != offset)
    1248           9 :         elem = throwCounts_.insert(elem, searched);
    1249        1995 :     return elem;
    1250             : }
    1251             : 
    1252             : void
    1253          38 : JSScript::setIonScript(JSRuntime* maybeRuntime, js::jit::IonScript* ionScript)
    1254             : {
    1255          38 :     MOZ_ASSERT_IF(ionScript != ION_DISABLED_SCRIPT, !baselineScript()->hasPendingIonBuilder());
    1256          38 :     if (hasIonScript())
    1257           5 :         js::jit::IonScript::writeBarrierPre(zone(), ion);
    1258          38 :     ion = ionScript;
    1259          38 :     MOZ_ASSERT_IF(hasIonScript(), hasBaselineScript());
    1260          38 :     updateBaselineOrIonRaw(maybeRuntime);
    1261          38 : }
    1262             : 
    1263             : js::PCCounts*
    1264       10685 : JSScript::maybeGetPCCounts(jsbytecode* pc) {
    1265       10685 :     MOZ_ASSERT(containsPC(pc));
    1266       10685 :     return getScriptCounts().maybeGetPCCounts(pcToOffset(pc));
    1267             : }
    1268             : 
    1269             : const js::PCCounts*
    1270           0 : JSScript::maybeGetThrowCounts(jsbytecode* pc) {
    1271           0 :     MOZ_ASSERT(containsPC(pc));
    1272           0 :     return getScriptCounts().maybeGetThrowCounts(pcToOffset(pc));
    1273             : }
    1274             : 
    1275             : js::PCCounts*
    1276        1995 : JSScript::getThrowCounts(jsbytecode* pc) {
    1277        1995 :     MOZ_ASSERT(containsPC(pc));
    1278        1995 :     return getScriptCounts().getThrowCounts(pcToOffset(pc));
    1279             : }
    1280             : 
    1281             : uint64_t
    1282         920 : JSScript::getHitCount(jsbytecode* pc)
    1283             : {
    1284         920 :     MOZ_ASSERT(containsPC(pc));
    1285         920 :     if (pc < main())
    1286          15 :         pc = main();
    1287             : 
    1288         920 :     ScriptCounts& sc = getScriptCounts();
    1289         920 :     size_t targetOffset = pcToOffset(pc);
    1290         920 :     const js::PCCounts* baseCount = sc.getImmediatePrecedingPCCounts(targetOffset);
    1291         920 :     if (!baseCount)
    1292           0 :         return 0;
    1293         920 :     if (baseCount->pcOffset() == targetOffset)
    1294         898 :         return baseCount->numExec();
    1295          22 :     MOZ_ASSERT(baseCount->pcOffset() < targetOffset);
    1296          22 :     uint64_t count = baseCount->numExec();
    1297             :     do {
    1298          22 :         const js::PCCounts* throwCount = sc.getImmediatePrecedingThrowCounts(targetOffset);
    1299          22 :         if (!throwCount)
    1300          22 :             return count;
    1301           0 :         if (throwCount->pcOffset() <= baseCount->pcOffset())
    1302           0 :             return count;
    1303           0 :         count -= throwCount->numExec();
    1304           0 :         targetOffset = throwCount->pcOffset() - 1;
    1305             :     } while (true);
    1306             : }
    1307             : 
    1308             : void
    1309           0 : JSScript::incHitCount(jsbytecode* pc)
    1310             : {
    1311           0 :     MOZ_ASSERT(containsPC(pc));
    1312           0 :     if (pc < main())
    1313           0 :         pc = main();
    1314             : 
    1315           0 :     ScriptCounts& sc = getScriptCounts();
    1316           0 :     js::PCCounts* baseCount = sc.getImmediatePrecedingPCCounts(pcToOffset(pc));
    1317           0 :     if (!baseCount)
    1318           0 :         return;
    1319           0 :     baseCount->numExec()++;
    1320             : }
    1321             : 
    1322             : void
    1323           0 : JSScript::addIonCounts(jit::IonScriptCounts* ionCounts)
    1324             : {
    1325           0 :     ScriptCounts& sc = getScriptCounts();
    1326           0 :     if (sc.ionCounts_)
    1327           0 :         ionCounts->setPrevious(sc.ionCounts_);
    1328           0 :     sc.ionCounts_ = ionCounts;
    1329           0 : }
    1330             : 
    1331             : jit::IonScriptCounts*
    1332           0 : JSScript::getIonCounts()
    1333             : {
    1334           0 :     return getScriptCounts().ionCounts_;
    1335             : }
    1336             : 
    1337             : void
    1338           0 : JSScript::takeOverScriptCountsMapEntry(ScriptCounts* entryValue)
    1339             : {
    1340             : #ifdef DEBUG
    1341           0 :     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
    1342           0 :     MOZ_ASSERT(entryValue == p->value());
    1343             : #endif
    1344           0 :     hasScriptCounts_ = false;
    1345           0 : }
    1346             : 
    1347             : void
    1348           0 : JSScript::releaseScriptCounts(ScriptCounts* counts)
    1349             : {
    1350           0 :     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
    1351           0 :     *counts = Move(*p->value());
    1352           0 :     js_delete(p->value());
    1353           0 :     compartment()->scriptCountsMap->remove(p);
    1354           0 :     hasScriptCounts_ = false;
    1355           0 : }
    1356             : 
    1357             : void
    1358           0 : JSScript::destroyScriptCounts(FreeOp* fop)
    1359             : {
    1360           0 :     if (hasScriptCounts()) {
    1361           0 :         ScriptCounts scriptCounts;
    1362           0 :         releaseScriptCounts(&scriptCounts);
    1363             :     }
    1364           0 : }
    1365             : 
    1366             : void
    1367           0 : JSScript::destroyScriptName()
    1368             : {
    1369           0 :     auto p = GetScriptNameMapEntry(this);
    1370           0 :     js_delete(p->value());
    1371           0 :     compartment()->scriptNameMap->remove(p);
    1372           0 : }
    1373             : 
    1374             : bool
    1375           0 : JSScript::hasScriptName()
    1376             : {
    1377           0 :     if (!compartment()->scriptNameMap)
    1378           0 :         return false;
    1379             : 
    1380           0 :     auto p = compartment()->scriptNameMap->lookup(this);
    1381           0 :     return p.found();
    1382             : }
    1383             : 
    1384             : void
    1385          22 : ScriptSourceObject::trace(JSTracer* trc, JSObject* obj)
    1386             : {
    1387          22 :     ScriptSourceObject* sso = static_cast<ScriptSourceObject*>(obj);
    1388             : 
    1389             :     // Don't trip over the poison 'not yet initialized' values.
    1390          22 :     if (!sso->getReservedSlot(INTRODUCTION_SCRIPT_SLOT).isMagic(JS_GENERIC_MAGIC)) {
    1391          22 :         JSScript* script = sso->introductionScript();
    1392          22 :         if (script) {
    1393           0 :             TraceManuallyBarrieredEdge(trc, &script, "ScriptSourceObject introductionScript");
    1394           0 :             sso->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(script));
    1395             :         }
    1396             :     }
    1397          22 : }
    1398             : 
    1399             : void
    1400           0 : ScriptSourceObject::finalize(FreeOp* fop, JSObject* obj)
    1401             : {
    1402           0 :     MOZ_ASSERT(fop->onActiveCooperatingThread());
    1403           0 :     ScriptSourceObject* sso = &obj->as<ScriptSourceObject>();
    1404           0 :     sso->source()->decref();
    1405           0 :     sso->setReservedSlot(SOURCE_SLOT, PrivateValue(nullptr));
    1406           0 : }
    1407             : 
    1408             : static const ClassOps ScriptSourceObjectClassOps = {
    1409             :     nullptr, /* addProperty */
    1410             :     nullptr, /* delProperty */
    1411             :     nullptr, /* getProperty */
    1412             :     nullptr, /* setProperty */
    1413             :     nullptr, /* enumerate */
    1414             :     nullptr, /* newEnumerate */
    1415             :     nullptr, /* resolve */
    1416             :     nullptr, /* mayResolve */
    1417             :     ScriptSourceObject::finalize,
    1418             :     nullptr, /* call */
    1419             :     nullptr, /* hasInstance */
    1420             :     nullptr, /* construct */
    1421             :     ScriptSourceObject::trace
    1422             : };
    1423             : 
    1424             : const Class ScriptSourceObject::class_ = {
    1425             :     "ScriptSource",
    1426             :     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
    1427             :     JSCLASS_IS_ANONYMOUS |
    1428             :     JSCLASS_FOREGROUND_FINALIZE,
    1429             :     &ScriptSourceObjectClassOps
    1430             : };
    1431             : 
    1432             : ScriptSourceObject*
    1433        2088 : ScriptSourceObject::create(JSContext* cx, ScriptSource* source)
    1434             : {
    1435        4176 :     RootedObject object(cx, NewObjectWithGivenProto(cx, &class_, nullptr));
    1436        2088 :     if (!object)
    1437           0 :         return nullptr;
    1438        4176 :     RootedScriptSource sourceObject(cx, &object->as<ScriptSourceObject>());
    1439             : 
    1440        2088 :     source->incref();    // The matching decref is in ScriptSourceObject::finalize.
    1441        2088 :     sourceObject->initReservedSlot(SOURCE_SLOT, PrivateValue(source));
    1442             : 
    1443             :     // The remaining slots should eventually be populated by a call to
    1444             :     // initFromOptions. Poison them until that point.
    1445        2088 :     sourceObject->initReservedSlot(ELEMENT_SLOT, MagicValue(JS_GENERIC_MAGIC));
    1446        2088 :     sourceObject->initReservedSlot(ELEMENT_PROPERTY_SLOT, MagicValue(JS_GENERIC_MAGIC));
    1447        2088 :     sourceObject->initReservedSlot(INTRODUCTION_SCRIPT_SLOT, MagicValue(JS_GENERIC_MAGIC));
    1448             : 
    1449        2088 :     return sourceObject;
    1450             : }
    1451             : 
    1452             : /* static */ bool
    1453        2085 : ScriptSourceObject::initFromOptions(JSContext* cx, HandleScriptSource source,
    1454             :                                     const ReadOnlyCompileOptions& options)
    1455             : {
    1456        2085 :     releaseAssertSameCompartment(cx, source);
    1457        2085 :     MOZ_ASSERT(source->getReservedSlot(ELEMENT_SLOT).isMagic(JS_GENERIC_MAGIC));
    1458        2085 :     MOZ_ASSERT(source->getReservedSlot(ELEMENT_PROPERTY_SLOT).isMagic(JS_GENERIC_MAGIC));
    1459        2085 :     MOZ_ASSERT(source->getReservedSlot(INTRODUCTION_SCRIPT_SLOT).isMagic(JS_GENERIC_MAGIC));
    1460             : 
    1461        4170 :     RootedValue element(cx, ObjectOrNullValue(options.element()));
    1462        2085 :     if (!cx->compartment()->wrap(cx, &element))
    1463           0 :         return false;
    1464        2085 :     source->setReservedSlot(ELEMENT_SLOT, element);
    1465             : 
    1466        4170 :     RootedValue elementAttributeName(cx);
    1467        2085 :     if (options.elementAttributeName())
    1468           7 :         elementAttributeName = StringValue(options.elementAttributeName());
    1469             :     else
    1470        2078 :         elementAttributeName = UndefinedValue();
    1471        2085 :     if (!cx->compartment()->wrap(cx, &elementAttributeName))
    1472           0 :         return false;
    1473        2085 :     source->setReservedSlot(ELEMENT_PROPERTY_SLOT, elementAttributeName);
    1474             : 
    1475             :     // There is no equivalent of cross-compartment wrappers for scripts. If the
    1476             :     // introduction script and ScriptSourceObject are in different compartments,
    1477             :     // we would be creating a cross-compartment script reference, which is
    1478             :     // forbidden. In that case, simply don't bother to retain the introduction
    1479             :     // script.
    1480        2091 :     if (options.introductionScript() &&
    1481           6 :         options.introductionScript()->compartment() == cx->compartment())
    1482             :     {
    1483           6 :         source->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, PrivateValue(options.introductionScript()));
    1484             :     } else {
    1485        2079 :         source->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, UndefinedValue());
    1486             :     }
    1487             : 
    1488        2085 :     return true;
    1489             : }
    1490             : 
    1491             : /* static */ bool
    1492           1 : JSScript::loadSource(JSContext* cx, ScriptSource* ss, bool* worked)
    1493             : {
    1494           1 :     MOZ_ASSERT(!ss->hasSourceData());
    1495           1 :     *worked = false;
    1496           1 :     if (!cx->runtime()->sourceHook.ref() || !ss->sourceRetrievable())
    1497           0 :         return true;
    1498           1 :     char16_t* src = nullptr;
    1499             :     size_t length;
    1500           1 :     if (!cx->runtime()->sourceHook->load(cx, ss->filename(), &src, &length))
    1501           0 :         return false;
    1502           1 :     if (!src)
    1503           0 :         return true;
    1504           1 :     if (!ss->setSource(cx, mozilla::UniquePtr<char16_t[], JS::FreePolicy>(src), length))
    1505           0 :         return false;
    1506             : 
    1507           1 :     *worked = true;
    1508           1 :     return true;
    1509             : }
    1510             : 
    1511             : /* static */ JSFlatString*
    1512           0 : JSScript::sourceData(JSContext* cx, HandleScript script)
    1513             : {
    1514           0 :     MOZ_ASSERT(script->scriptSource()->hasSourceData());
    1515           0 :     return script->scriptSource()->substring(cx, script->sourceStart(), script->sourceEnd());
    1516             : }
    1517             : 
    1518             : bool
    1519           1 : JSScript::appendSourceDataForToString(JSContext* cx, StringBuffer& buf)
    1520             : {
    1521           1 :     MOZ_ASSERT(scriptSource()->hasSourceData());
    1522           1 :     return scriptSource()->appendSubstring(cx, buf, toStringStart(), toStringEnd());
    1523             : }
    1524             : 
    1525        1408 : UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
    1526        1408 :   : cache_(nullptr), sourceChunk_()
    1527             : {
    1528        1408 : }
    1529             : 
    1530             : void
    1531           0 : UncompressedSourceCache::AutoHoldEntry::holdEntry(UncompressedSourceCache* cache,
    1532             :                                                   const ScriptSourceChunk& sourceChunk)
    1533             : {
    1534             :     // Initialise the holder for a specific cache and script source. This will
    1535             :     // hold on to the cached source chars in the event that the cache is purged.
    1536           0 :     MOZ_ASSERT(!cache_ && !sourceChunk_.valid() && !charsToFree_);
    1537           0 :     cache_ = cache;
    1538           0 :     sourceChunk_ = sourceChunk;
    1539           0 : }
    1540             : 
    1541             : void
    1542           0 : UncompressedSourceCache::AutoHoldEntry::holdChars(UniqueTwoByteChars chars)
    1543             : {
    1544           0 :     MOZ_ASSERT(!cache_ && !sourceChunk_.valid() && !charsToFree_);
    1545           0 :     charsToFree_ = Move(chars);
    1546           0 : }
    1547             : 
    1548             : void
    1549           0 : UncompressedSourceCache::AutoHoldEntry::deferDelete(UniqueTwoByteChars chars)
    1550             : {
    1551             :     // Take ownership of source chars now the cache is being purged. Remove our
    1552             :     // reference to the ScriptSource which might soon be destroyed.
    1553           0 :     MOZ_ASSERT(cache_ && sourceChunk_.valid() && !charsToFree_);
    1554           0 :     cache_ = nullptr;
    1555           0 :     sourceChunk_ = ScriptSourceChunk();
    1556           0 :     charsToFree_ = Move(chars);
    1557           0 : }
    1558             : 
    1559        2816 : UncompressedSourceCache::AutoHoldEntry::~AutoHoldEntry()
    1560             : {
    1561        1408 :     if (cache_) {
    1562           0 :         MOZ_ASSERT(sourceChunk_.valid());
    1563           0 :         cache_->releaseEntry(*this);
    1564             :     }
    1565        1408 : }
    1566             : 
    1567             : void
    1568           0 : UncompressedSourceCache::holdEntry(AutoHoldEntry& holder, const ScriptSourceChunk& ssc)
    1569             : {
    1570           0 :     MOZ_ASSERT(!holder_);
    1571           0 :     holder.holdEntry(this, ssc);
    1572           0 :     holder_ = &holder;
    1573           0 : }
    1574             : 
    1575             : void
    1576           0 : UncompressedSourceCache::releaseEntry(AutoHoldEntry& holder)
    1577             : {
    1578           0 :     MOZ_ASSERT(holder_ == &holder);
    1579           0 :     holder_ = nullptr;
    1580           0 : }
    1581             : 
    1582             : const char16_t*
    1583           0 : UncompressedSourceCache::lookup(const ScriptSourceChunk& ssc, AutoHoldEntry& holder)
    1584             : {
    1585           0 :     MOZ_ASSERT(!holder_);
    1586           0 :     if (!map_)
    1587           0 :         return nullptr;
    1588           0 :     if (Map::Ptr p = map_->lookup(ssc)) {
    1589           0 :         holdEntry(holder, ssc);
    1590           0 :         return p->value().get();
    1591             :     }
    1592           0 :     return nullptr;
    1593             : }
    1594             : 
    1595             : bool
    1596           0 : UncompressedSourceCache::put(const ScriptSourceChunk& ssc, UniqueTwoByteChars str,
    1597             :                              AutoHoldEntry& holder)
    1598             : {
    1599           0 :     MOZ_ASSERT(!holder_);
    1600             : 
    1601           0 :     if (!map_) {
    1602           0 :         UniquePtr<Map> map = MakeUnique<Map>();
    1603           0 :         if (!map || !map->init())
    1604           0 :             return false;
    1605             : 
    1606           0 :         map_ = Move(map);
    1607             :     }
    1608             : 
    1609           0 :     if (!map_->put(ssc, Move(str)))
    1610           0 :         return false;
    1611             : 
    1612           0 :     holdEntry(holder, ssc);
    1613           0 :     return true;
    1614             : }
    1615             : 
    1616             : void
    1617           1 : UncompressedSourceCache::purge()
    1618             : {
    1619           1 :     if (!map_)
    1620           1 :         return;
    1621             : 
    1622           0 :     for (Map::Range r = map_->all(); !r.empty(); r.popFront()) {
    1623           0 :         if (holder_ && r.front().key() == holder_->sourceChunk()) {
    1624           0 :             holder_->deferDelete(Move(r.front().value()));
    1625           0 :             holder_ = nullptr;
    1626             :         }
    1627             :     }
    1628             : 
    1629           0 :     map_.reset();
    1630             : }
    1631             : 
    1632             : size_t
    1633           0 : UncompressedSourceCache::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
    1634             : {
    1635           0 :     size_t n = 0;
    1636           0 :     if (map_ && !map_->empty()) {
    1637           0 :         n += map_->sizeOfIncludingThis(mallocSizeOf);
    1638           0 :         for (Map::Range r = map_->all(); !r.empty(); r.popFront())
    1639           0 :             n += mallocSizeOf(r.front().value().get());
    1640             :     }
    1641           0 :     return n;
    1642             : }
    1643             : 
    1644             : const char16_t*
    1645           0 : ScriptSource::chunkChars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
    1646             :                          size_t chunk)
    1647             : {
    1648           0 :     const Compressed& c = data.as<Compressed>();
    1649             : 
    1650           0 :     ScriptSourceChunk ssc(this, chunk);
    1651           0 :     if (const char16_t* decompressed = cx->caches().uncompressedSourceCache.lookup(ssc, holder))
    1652           0 :         return decompressed;
    1653             : 
    1654           0 :     size_t totalLengthInBytes = length() * sizeof(char16_t);
    1655           0 :     size_t chunkBytes = Compressor::chunkSize(totalLengthInBytes, chunk);
    1656             : 
    1657           0 :     MOZ_ASSERT((chunkBytes % sizeof(char16_t)) == 0);
    1658           0 :     const size_t lengthWithNull = (chunkBytes / sizeof(char16_t)) + 1;
    1659           0 :     UniqueTwoByteChars decompressed(js_pod_malloc<char16_t>(lengthWithNull));
    1660           0 :     if (!decompressed) {
    1661           0 :         JS_ReportOutOfMemory(cx);
    1662           0 :         return nullptr;
    1663             :     }
    1664             : 
    1665           0 :     if (!DecompressStringChunk((const unsigned char*) c.raw.chars(),
    1666             :                                chunk,
    1667           0 :                                reinterpret_cast<unsigned char*>(decompressed.get()),
    1668             :                                chunkBytes))
    1669             :     {
    1670           0 :         JS_ReportOutOfMemory(cx);
    1671           0 :         return nullptr;
    1672             :     }
    1673             : 
    1674           0 :     decompressed[lengthWithNull - 1] = '\0';
    1675             : 
    1676           0 :     const char16_t* ret = decompressed.get();
    1677           0 :     if (!cx->caches().uncompressedSourceCache.put(ssc, Move(decompressed), holder)) {
    1678           0 :         JS_ReportOutOfMemory(cx);
    1679           0 :         return nullptr;
    1680             :     }
    1681           0 :     return ret;
    1682             : }
    1683             : 
    1684        1408 : ScriptSource::PinnedChars::PinnedChars(JSContext* cx, ScriptSource* source,
    1685             :                                        UncompressedSourceCache::AutoHoldEntry& holder,
    1686        1408 :                                        size_t begin, size_t len)
    1687        1408 :   : source_(source)
    1688             : {
    1689        1408 :     chars_ = source->chars(cx, holder, begin, len);
    1690        1408 :     if (chars_) {
    1691        1408 :         stack_ = &source->pinnedCharsStack_;
    1692        1408 :         prev_ = *stack_;
    1693        1408 :         *stack_ = this;
    1694             :     }
    1695        1408 : }
    1696             : 
    1697        2816 : ScriptSource::PinnedChars::~PinnedChars()
    1698             : {
    1699        1408 :     if (chars_) {
    1700        1408 :         MOZ_ASSERT(*stack_ == this);
    1701        1408 :         *stack_ = prev_;
    1702        1408 :         if (!prev_)
    1703        1408 :             source_->movePendingCompressedSource();
    1704             :     }
    1705        1408 : }
    1706             : 
    1707             : void
    1708        1408 : ScriptSource::movePendingCompressedSource()
    1709             : {
    1710        1408 :     if (!pendingCompressed_)
    1711        1408 :         return;
    1712             : 
    1713           0 :     MOZ_ASSERT(data.is<Missing>() || data.is<Uncompressed>());
    1714           0 :     MOZ_ASSERT_IF(data.is<Uncompressed>(),
    1715             :                   data.as<Uncompressed>().string.length() ==
    1716             :                   pendingCompressed_->uncompressedLength);
    1717             : 
    1718           0 :     data = SourceType(Compressed(mozilla::Move(pendingCompressed_->raw),
    1719           0 :                                  pendingCompressed_->uncompressedLength));
    1720           0 :     pendingCompressed_ = mozilla::Nothing();
    1721             : }
    1722             : 
    1723             : const char16_t*
    1724        1408 : ScriptSource::chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder,
    1725             :                     size_t begin, size_t len)
    1726             : {
    1727        1408 :     MOZ_ASSERT(begin + len <= length());
    1728             : 
    1729        1408 :     if (data.is<Uncompressed>()) {
    1730        1408 :         const char16_t* chars = data.as<Uncompressed>().string.chars();
    1731        1408 :         if (!chars)
    1732           0 :             return nullptr;
    1733        1408 :         return chars + begin;
    1734             :     }
    1735             : 
    1736           0 :     if (data.is<Missing>())
    1737           0 :         MOZ_CRASH("ScriptSource::chars() on ScriptSource with SourceType = Missing");
    1738             : 
    1739           0 :     MOZ_ASSERT(data.is<Compressed>());
    1740             : 
    1741             :     // Determine which chunk(s) we are interested in, and the offsets within
    1742             :     // these chunks.
    1743             :     size_t firstChunk, lastChunk;
    1744             :     size_t firstChunkOffset, lastChunkOffset;
    1745           0 :     MOZ_ASSERT(len > 0);
    1746           0 :     Compressor::toChunkOffset(begin * sizeof(char16_t), &firstChunk, &firstChunkOffset);
    1747           0 :     Compressor::toChunkOffset((begin + len - 1) * sizeof(char16_t), &lastChunk, &lastChunkOffset);
    1748             : 
    1749           0 :     MOZ_ASSERT(firstChunkOffset % sizeof(char16_t) == 0);
    1750           0 :     size_t firstChar = firstChunkOffset / sizeof(char16_t);
    1751             : 
    1752           0 :     if (firstChunk == lastChunk) {
    1753           0 :         const char16_t* chars = chunkChars(cx, holder, firstChunk);
    1754           0 :         if (!chars)
    1755           0 :             return nullptr;
    1756           0 :         return chars + firstChar;
    1757             :     }
    1758             : 
    1759             :     // We need multiple chunks. Allocate a (null-terminated) buffer to hold
    1760             :     // |len| chars and copy uncompressed chars from the chunks into it. We use
    1761             :     // chunkChars() so we benefit from chunk caching by UncompressedSourceCache.
    1762             : 
    1763           0 :     MOZ_ASSERT(firstChunk < lastChunk);
    1764             : 
    1765           0 :     size_t lengthWithNull = len + 1;
    1766           0 :     UniqueTwoByteChars decompressed(js_pod_malloc<char16_t>(lengthWithNull));
    1767           0 :     if (!decompressed) {
    1768           0 :         JS_ReportOutOfMemory(cx);
    1769           0 :         return nullptr;
    1770             :     }
    1771             : 
    1772           0 :     size_t totalLengthInBytes = length() * sizeof(char16_t);
    1773           0 :     char16_t* cursor = decompressed.get();
    1774             : 
    1775           0 :     for (size_t i = firstChunk; i <= lastChunk; i++) {
    1776           0 :         UncompressedSourceCache::AutoHoldEntry chunkHolder;
    1777           0 :         const char16_t* chars = chunkChars(cx, chunkHolder, i);
    1778           0 :         if (!chars)
    1779           0 :             return nullptr;
    1780             : 
    1781           0 :         size_t numChars = Compressor::chunkSize(totalLengthInBytes, i) / sizeof(char16_t);
    1782           0 :         if (i == firstChunk) {
    1783           0 :             MOZ_ASSERT(firstChar < numChars);
    1784           0 :             chars += firstChar;
    1785           0 :             numChars -= firstChar;
    1786           0 :         } else if (i == lastChunk) {
    1787           0 :             size_t numCharsNew = lastChunkOffset / sizeof(char16_t) + 1;
    1788           0 :             MOZ_ASSERT(numCharsNew <= numChars);
    1789           0 :             numChars = numCharsNew;
    1790             :         }
    1791           0 :         mozilla::PodCopy(cursor, chars, numChars);
    1792           0 :         cursor += numChars;
    1793             :     }
    1794             : 
    1795           0 :     *cursor++ = '\0';
    1796           0 :     MOZ_ASSERT(size_t(cursor - decompressed.get()) == lengthWithNull);
    1797             : 
    1798             :     // Transfer ownership to |holder|.
    1799           0 :     const char16_t* ret = decompressed.get();
    1800           0 :     holder.holdChars(Move(decompressed));
    1801           0 :     return ret;
    1802             : }
    1803             : 
    1804             : JSFlatString*
    1805           0 : ScriptSource::substring(JSContext* cx, size_t start, size_t stop)
    1806             : {
    1807           0 :     MOZ_ASSERT(start <= stop);
    1808           0 :     size_t len = stop - start;
    1809           0 :     UncompressedSourceCache::AutoHoldEntry holder;
    1810           0 :     PinnedChars chars(cx, this, holder, start, len);
    1811           0 :     if (!chars.get())
    1812           0 :         return nullptr;
    1813           0 :     return NewStringCopyN<CanGC>(cx, chars.get(), len);
    1814             : }
    1815             : 
    1816             : JSFlatString*
    1817           0 : ScriptSource::substringDontDeflate(JSContext* cx, size_t start, size_t stop)
    1818             : {
    1819           0 :     MOZ_ASSERT(start <= stop);
    1820           0 :     size_t len = stop - start;
    1821           0 :     UncompressedSourceCache::AutoHoldEntry holder;
    1822           0 :     PinnedChars chars(cx, this, holder, start, len);
    1823           0 :     if (!chars.get())
    1824           0 :         return nullptr;
    1825           0 :     return NewStringCopyNDontDeflate<CanGC>(cx, chars.get(), len);
    1826             : }
    1827             : 
    1828             : bool
    1829           1 : ScriptSource::appendSubstring(JSContext* cx, StringBuffer& buf, size_t start, size_t stop)
    1830             : {
    1831           1 :     MOZ_ASSERT(start <= stop);
    1832           1 :     size_t len = stop - start;
    1833           2 :     UncompressedSourceCache::AutoHoldEntry holder;
    1834           2 :     PinnedChars chars(cx, this, holder, start, len);
    1835           1 :     if (!chars.get())
    1836           0 :         return false;
    1837             :     // Sources can be large and we don't want to check "is this char Latin1"
    1838             :     // for each source code character, so inflate the buffer here.
    1839           1 :     if (len > 100 && !buf.ensureTwoByteChars())
    1840           0 :         return false;
    1841           1 :     return buf.append(chars.get(), len);
    1842             : }
    1843             : 
    1844             : JSFlatString*
    1845           0 : ScriptSource::functionBodyString(JSContext* cx)
    1846             : {
    1847           0 :     MOZ_ASSERT(isFunctionBody());
    1848             : 
    1849           0 :     size_t start = parameterListEnd_ + (sizeof(FunctionConstructorMedialSigils) - 1);
    1850           0 :     size_t stop = length() - (sizeof(FunctionConstructorFinalBrace) - 1);
    1851           0 :     return substring(cx, start, stop);
    1852             : }
    1853             : 
    1854             : MOZ_MUST_USE bool
    1855        1486 : ScriptSource::setSource(JSContext* cx,
    1856             :                         mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& source,
    1857             :                         size_t length)
    1858             : {
    1859        1486 :     auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
    1860        2972 :     auto deduped = cache.getOrCreate(mozilla::Move(source), length);
    1861        1486 :     if (!deduped) {
    1862           0 :         ReportOutOfMemory(cx);
    1863           0 :         return false;
    1864             :     }
    1865        1486 :     setSource(mozilla::Move(*deduped));
    1866        1486 :     return true;
    1867             : }
    1868             : 
    1869             : void
    1870        1703 : ScriptSource::setSource(SharedImmutableTwoByteString&& string)
    1871             : {
    1872        1703 :     MOZ_ASSERT(data.is<Missing>());
    1873        1703 :     data = SourceType(Uncompressed(mozilla::Move(string)));
    1874        1703 : }
    1875             : 
    1876             : bool
    1877         461 : ScriptSource::tryCompressOffThread(JSContext* cx)
    1878             : {
    1879         461 :     if (!data.is<Uncompressed>())
    1880         183 :         return true;
    1881             : 
    1882             :     // There are several cases where source compression is not a good idea:
    1883             :     //  - If the script is tiny, then compression will save little or no space.
    1884             :     //  - If there is only one core, then compression will contend with JS
    1885             :     //    execution (which hurts benchmarketing).
    1886             :     //
    1887             :     // Otherwise, enqueue a compression task to be processed when a major
    1888             :     // GC is requested.
    1889             : 
    1890             :     bool canCompressOffThread =
    1891         556 :         HelperThreadState().cpuCount > 1 &&
    1892         556 :         HelperThreadState().threadCount >= 2 &&
    1893         556 :         CanUseExtraThreads();
    1894         278 :     const size_t TINY_SCRIPT = 256;
    1895         278 :     if (TINY_SCRIPT > length() || !canCompressOffThread)
    1896         123 :         return true;
    1897             : 
    1898             :     // The SourceCompressionTask needs to record the major GC number for
    1899             :     // scheduling. If we're parsing off thread, this number is not safe to
    1900             :     // access.
    1901             :     //
    1902             :     // When parsing on the main thread, the attempts made to compress off
    1903             :     // thread in BytecodeCompiler will succeed.
    1904             :     //
    1905             :     // When parsing off-thread, the above attempts will fail and the attempt
    1906             :     // made in ParseTask::finish will succeed.
    1907         155 :     if (!CurrentThreadCanAccessRuntime(cx->runtime()))
    1908           0 :         return true;
    1909             : 
    1910             :     // Heap allocate the task. It will be freed upon compression
    1911             :     // completing in AttachFinishedCompressedSources.
    1912         310 :     auto task = MakeUnique<SourceCompressionTask>(cx->runtime(), this);
    1913         155 :     if (!task) {
    1914           0 :         ReportOutOfMemory(cx);
    1915           0 :         return false;
    1916             :     }
    1917         155 :     return EnqueueOffThreadCompression(cx, Move(task));
    1918             : }
    1919             : 
    1920             : MOZ_MUST_USE bool
    1921           0 : ScriptSource::setCompressedSource(JSContext* cx,
    1922             :                                   mozilla::UniquePtr<char[], JS::FreePolicy>&& raw,
    1923             :                                   size_t rawLength,
    1924             :                                   size_t sourceLength)
    1925             : {
    1926           0 :     MOZ_ASSERT(raw);
    1927           0 :     auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
    1928           0 :     auto deduped = cache.getOrCreate(mozilla::Move(raw), rawLength);
    1929           0 :     if (!deduped) {
    1930           0 :         ReportOutOfMemory(cx);
    1931           0 :         return false;
    1932             :     }
    1933           0 :     setCompressedSource(mozilla::Move(*deduped), sourceLength);
    1934           0 :     return true;
    1935             : }
    1936             : 
    1937             : void
    1938           0 : ScriptSource::setCompressedSource(SharedImmutableString&& raw, size_t uncompressedLength)
    1939             : {
    1940           0 :     MOZ_ASSERT(data.is<Missing>() || data.is<Uncompressed>());
    1941           0 :     MOZ_ASSERT_IF(data.is<Uncompressed>(),
    1942             :                   data.as<Uncompressed>().string.length() == uncompressedLength);
    1943           0 :     if (pinnedCharsStack_)
    1944           0 :         pendingCompressed_ = mozilla::Some(Compressed(mozilla::Move(raw), uncompressedLength));
    1945             :     else
    1946           0 :         data = SourceType(Compressed(mozilla::Move(raw), uncompressedLength));
    1947           0 : }
    1948             : 
    1949             : bool
    1950         217 : ScriptSource::setSourceCopy(JSContext* cx, SourceBufferHolder& srcBuf)
    1951             : {
    1952         217 :     MOZ_ASSERT(!hasSourceData());
    1953             : 
    1954         217 :     JSRuntime* runtime = cx->zone()->runtimeFromAnyThread();
    1955         217 :     auto& cache = runtime->sharedImmutableStrings();
    1956         126 :     auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() {
    1957         347 :         return srcBuf.ownsChars()
    1958             :                ? mozilla::UniquePtr<char16_t[], JS::FreePolicy>(srcBuf.take())
    1959             :                : DuplicateString(srcBuf.get(), srcBuf.length());
    1960         781 :     });
    1961         217 :     if (!deduped) {
    1962           0 :         ReportOutOfMemory(cx);
    1963           0 :         return false;
    1964             :     }
    1965         217 :     setSource(mozilla::Move(*deduped));
    1966             : 
    1967         217 :     return true;
    1968             : }
    1969             : 
    1970             : static MOZ_MUST_USE bool
    1971           0 : reallocUniquePtr(UniquePtr<char[], JS::FreePolicy>& unique, size_t size)
    1972             : {
    1973           0 :     auto newPtr = static_cast<char*>(js_realloc(unique.get(), size));
    1974           0 :     if (!newPtr)
    1975           0 :         return false;
    1976             : 
    1977             :     // Since the realloc succeeded, unique is now holding a freed pointer.
    1978           0 :     mozilla::Unused << unique.release();
    1979           0 :     unique.reset(newPtr);
    1980           0 :     return true;
    1981             : }
    1982             : 
    1983             : void
    1984           0 : SourceCompressionTask::work()
    1985             : {
    1986           0 :     if (shouldCancel())
    1987           0 :         return;
    1988             : 
    1989           0 :     ScriptSource* source = sourceHolder_.get();
    1990           0 :     MOZ_ASSERT(source->data.is<ScriptSource::Uncompressed>());
    1991             : 
    1992             :     // Try to keep the maximum memory usage down by only allocating half the
    1993             :     // size of the string, first.
    1994           0 :     size_t inputBytes = source->length() * sizeof(char16_t);
    1995           0 :     size_t firstSize = inputBytes / 2;
    1996           0 :     mozilla::UniquePtr<char[], JS::FreePolicy> compressed(js_pod_malloc<char>(firstSize));
    1997           0 :     if (!compressed)
    1998           0 :         return;
    1999             : 
    2000           0 :     const char16_t* chars = source->data.as<ScriptSource::Uncompressed>().string.chars();
    2001             :     Compressor comp(reinterpret_cast<const unsigned char*>(chars),
    2002           0 :                     inputBytes);
    2003           0 :     if (!comp.init())
    2004           0 :         return;
    2005             : 
    2006           0 :     comp.setOutput(reinterpret_cast<unsigned char*>(compressed.get()), firstSize);
    2007           0 :     bool cont = true;
    2008           0 :     bool reallocated = false;
    2009           0 :     while (cont) {
    2010           0 :         if (shouldCancel())
    2011           0 :             return;
    2012             : 
    2013           0 :         switch (comp.compressMore()) {
    2014             :           case Compressor::CONTINUE:
    2015           0 :             break;
    2016             :           case Compressor::MOREOUTPUT: {
    2017           0 :             if (reallocated) {
    2018             :                 // The compressed string is longer than the original string.
    2019           0 :                 return;
    2020             :             }
    2021             : 
    2022             :             // The compressed output is greater than half the size of the
    2023             :             // original string. Reallocate to the full size.
    2024           0 :             if (!reallocUniquePtr(compressed, inputBytes))
    2025           0 :                 return;
    2026             : 
    2027           0 :             comp.setOutput(reinterpret_cast<unsigned char*>(compressed.get()), inputBytes);
    2028           0 :             reallocated = true;
    2029           0 :             break;
    2030             :           }
    2031             :           case Compressor::DONE:
    2032           0 :             cont = false;
    2033           0 :             break;
    2034             :           case Compressor::OOM:
    2035           0 :             return;
    2036             :         }
    2037             :     }
    2038             : 
    2039           0 :     size_t totalBytes = comp.totalBytesNeeded();
    2040             : 
    2041             :     // Shrink the buffer to the size of the compressed data.
    2042           0 :     if (!reallocUniquePtr(compressed, totalBytes))
    2043           0 :         return;
    2044             : 
    2045           0 :     comp.finish(compressed.get(), totalBytes);
    2046             : 
    2047           0 :     if (shouldCancel())
    2048           0 :         return;
    2049             : 
    2050           0 :     auto& strings = runtime_->sharedImmutableStrings();
    2051           0 :     resultString_ = strings.getOrCreate(mozilla::Move(compressed), totalBytes);
    2052             : }
    2053             : 
    2054             : void
    2055           0 : SourceCompressionTask::complete()
    2056             : {
    2057           0 :     if (!shouldCancel() && resultString_) {
    2058           0 :         ScriptSource* source = sourceHolder_.get();
    2059           0 :         source->setCompressedSource(mozilla::Move(*resultString_), source->length());
    2060             :     }
    2061           0 : }
    2062             : 
    2063             : void
    2064           0 : ScriptSource::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
    2065             :                                      JS::ScriptSourceInfo* info) const
    2066             : {
    2067           0 :     info->misc += mallocSizeOf(this) +
    2068           0 :                   mallocSizeOf(filename_.get()) +
    2069           0 :                   mallocSizeOf(introducerFilename_.get());
    2070           0 :     info->numScripts++;
    2071           0 : }
    2072             : 
    2073             : bool
    2074           0 : ScriptSource::xdrEncodeTopLevel(JSContext* cx, HandleScript script)
    2075             : {
    2076           0 :     xdrEncoder_ = js::MakeUnique<XDRIncrementalEncoder>(cx);
    2077           0 :     if (!xdrEncoder_) {
    2078           0 :         ReportOutOfMemory(cx);
    2079           0 :         return false;
    2080             :     }
    2081             : 
    2082           0 :     MOZ_ASSERT(hasEncoder());
    2083           0 :     auto failureCase = mozilla::MakeScopeExit([&] {
    2084           0 :         xdrEncoder_.reset(nullptr);
    2085           0 :     });
    2086             : 
    2087           0 :     if (!xdrEncoder_->init()) {
    2088           0 :         ReportOutOfMemory(cx);
    2089           0 :         return false;
    2090             :     }
    2091             : 
    2092           0 :     RootedScript s(cx, script);
    2093           0 :     if (!xdrEncoder_->codeScript(&s))
    2094           0 :         return false;
    2095             : 
    2096           0 :     failureCase.release();
    2097           0 :     return true;
    2098             : }
    2099             : 
    2100             : bool
    2101           0 : ScriptSource::xdrEncodeFunction(JSContext* cx, HandleFunction fun, HandleScriptSource sourceObject)
    2102             : {
    2103           0 :     MOZ_ASSERT(sourceObject->source() == this);
    2104           0 :     MOZ_ASSERT(hasEncoder());
    2105           0 :     auto failureCase = mozilla::MakeScopeExit([&] {
    2106           0 :         xdrEncoder_.reset(nullptr);
    2107           0 :     });
    2108             : 
    2109           0 :     RootedFunction f(cx, fun);
    2110           0 :     if (!xdrEncoder_->codeFunction(&f, sourceObject))
    2111           0 :         return false;
    2112             : 
    2113           0 :     failureCase.release();
    2114           0 :     return true;
    2115             : }
    2116             : 
    2117             : bool
    2118           0 : ScriptSource::xdrFinalizeEncoder(JS::TranscodeBuffer& buffer)
    2119             : {
    2120           0 :     if (!hasEncoder())
    2121           0 :         return false;
    2122             : 
    2123           0 :     auto cleanup = mozilla::MakeScopeExit([&] {
    2124           0 :         xdrEncoder_.reset(nullptr);
    2125           0 :     });
    2126             : 
    2127           0 :     if (!xdrEncoder_->linearize(buffer))
    2128           0 :         return false;
    2129           0 :     return true;
    2130             : }
    2131             : 
    2132             : template<XDRMode mode>
    2133             : bool
    2134        1434 : ScriptSource::performXDR(XDRState<mode>* xdr)
    2135             : {
    2136             :     struct CompressedLengthMatcher
    2137             :     {
    2138          18 :         size_t match(Uncompressed&) {
    2139          18 :             return 0;
    2140             :         }
    2141             : 
    2142           0 :         size_t match(Compressed& c) {
    2143           0 :             return c.raw.length();
    2144             :         }
    2145             : 
    2146           0 :         size_t match(Missing&) {
    2147           0 :             MOZ_CRASH("Missing source data in ScriptSource::performXDR");
    2148             :             return 0;
    2149             :         }
    2150             :     };
    2151             : 
    2152             :     struct RawDataMatcher
    2153             :     {
    2154          18 :         void* match(Uncompressed& u) {
    2155          18 :             return (void*) u.string.chars();
    2156             :         }
    2157             : 
    2158           0 :         void* match(Compressed& c) {
    2159           0 :             return (void*) c.raw.chars();
    2160             :         }
    2161             : 
    2162           0 :         void* match(Missing&) {
    2163           0 :             MOZ_CRASH("Missing source data in ScriptSource::performXDR");
    2164             :             return nullptr;
    2165             :         }
    2166             :     };
    2167             : 
    2168        1434 :     uint8_t hasSource = hasSourceData();
    2169        1434 :     if (!xdr->codeUint8(&hasSource))
    2170           0 :         return false;
    2171             : 
    2172        1434 :     uint8_t retrievable = sourceRetrievable_;
    2173        1434 :     if (!xdr->codeUint8(&retrievable))
    2174           0 :         return false;
    2175        1434 :     sourceRetrievable_ = retrievable;
    2176             : 
    2177        1434 :     if (hasSource && !sourceRetrievable_) {
    2178        1192 :         uint32_t len = 0;
    2179             :         if (mode == XDR_ENCODE)
    2180          18 :             len = length();
    2181        1192 :         if (!xdr->codeUint32(&len))
    2182           0 :             return false;
    2183             : 
    2184             :         uint32_t compressedLength;
    2185             :         if (mode == XDR_ENCODE) {
    2186             :             CompressedLengthMatcher m;
    2187          18 :             compressedLength = data.match(m);
    2188             :         }
    2189        1192 :         if (!xdr->codeUint32(&compressedLength))
    2190           0 :             return false;
    2191             : 
    2192        1192 :         size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
    2193             :         if (mode == XDR_DECODE) {
    2194        1174 :             uint8_t* p = xdr->cx()->template pod_malloc<uint8_t>(Max<size_t>(byteLen, 1));
    2195        1174 :             if (!p || !xdr->codeBytes(p, byteLen)) {
    2196           0 :                 js_free(p);
    2197           0 :                 return false;
    2198             :             }
    2199             : 
    2200        1174 :             if (compressedLength) {
    2201             :                 mozilla::UniquePtr<char[], JS::FreePolicy> compressedSource(
    2202           0 :                     reinterpret_cast<char*>(p));
    2203           0 :                 if (!setCompressedSource(xdr->cx(), mozilla::Move(compressedSource), byteLen, len))
    2204           0 :                     return false;
    2205             :             } else {
    2206             :                 mozilla::UniquePtr<char16_t[], JS::FreePolicy> source(
    2207        2348 :                     reinterpret_cast<char16_t*>(p));
    2208        1174 :                 if (!setSource(xdr->cx(), mozilla::Move(source), len))
    2209           0 :                     return false;
    2210             :             }
    2211             :         } else {
    2212             :             RawDataMatcher rdm;
    2213          18 :             void* p = data.match(rdm);
    2214          18 :             if (!xdr->codeBytes(p, byteLen))
    2215           0 :                 return false;
    2216             :         }
    2217             :     }
    2218             : 
    2219        1434 :     uint8_t haveSourceMap = hasSourceMapURL();
    2220        1434 :     if (!xdr->codeUint8(&haveSourceMap))
    2221           0 :         return false;
    2222             : 
    2223        1434 :     if (haveSourceMap) {
    2224           0 :         uint32_t sourceMapURLLen = (mode == XDR_DECODE) ? 0 : js_strlen(sourceMapURL_.get());
    2225           0 :         if (!xdr->codeUint32(&sourceMapURLLen))
    2226           0 :             return false;
    2227             : 
    2228             :         if (mode == XDR_DECODE) {
    2229           0 :             sourceMapURL_ = xdr->cx()->template make_pod_array<char16_t>(sourceMapURLLen + 1);
    2230           0 :             if (!sourceMapURL_)
    2231           0 :                 return false;
    2232             :         }
    2233           0 :         if (!xdr->codeChars(sourceMapURL_.get(), sourceMapURLLen)) {
    2234             :             if (mode == XDR_DECODE)
    2235           0 :                 sourceMapURL_ = nullptr;
    2236           0 :             return false;
    2237             :         }
    2238           0 :         sourceMapURL_[sourceMapURLLen] = '\0';
    2239             :     }
    2240             : 
    2241        1434 :     uint8_t haveDisplayURL = hasDisplayURL();
    2242        1434 :     if (!xdr->codeUint8(&haveDisplayURL))
    2243           0 :         return false;
    2244             : 
    2245        1434 :     if (haveDisplayURL) {
    2246           0 :         uint32_t displayURLLen = (mode == XDR_DECODE) ? 0 : js_strlen(displayURL_.get());
    2247           0 :         if (!xdr->codeUint32(&displayURLLen))
    2248           0 :             return false;
    2249             : 
    2250             :         if (mode == XDR_DECODE) {
    2251           0 :             displayURL_ = xdr->cx()->template make_pod_array<char16_t>(displayURLLen + 1);
    2252           0 :             if (!displayURL_)
    2253           0 :                 return false;
    2254             :         }
    2255           0 :         if (!xdr->codeChars(displayURL_.get(), displayURLLen)) {
    2256             :             if (mode == XDR_DECODE)
    2257           0 :                 displayURL_ = nullptr;
    2258           0 :             return false;
    2259             :         }
    2260           0 :         displayURL_[displayURLLen] = '\0';
    2261             :     }
    2262             : 
    2263        1434 :     uint8_t haveFilename = !!filename_;
    2264        1434 :     if (!xdr->codeUint8(&haveFilename))
    2265           0 :         return false;
    2266             : 
    2267        1434 :     if (haveFilename) {
    2268        1434 :         const char* fn = filename();
    2269        1434 :         if (!xdr->codeCString(&fn))
    2270           0 :             return false;
    2271             :         // Note: If the decoder has an option, then the filename is defined by
    2272             :         // the CompileOption from the document.
    2273        1434 :         MOZ_ASSERT_IF(mode == XDR_DECODE && xdr->hasOptions(), filename());
    2274        1434 :         if (mode == XDR_DECODE && !xdr->hasOptions() && !setFilename(xdr->cx(), fn))
    2275           0 :             return false;
    2276             :     }
    2277             : 
    2278        1434 :     return true;
    2279             : }
    2280             : 
    2281             : // Format and return a cx->zone()->pod_malloc'ed URL for a generated script like:
    2282             : //   {filename} line {lineno} > {introducer}
    2283             : // For example:
    2284             : //   foo.js line 7 > eval
    2285             : // indicating code compiled by the call to 'eval' on line 7 of foo.js.
    2286             : static char*
    2287           6 : FormatIntroducedFilename(JSContext* cx, const char* filename, unsigned lineno,
    2288             :                          const char* introducer)
    2289             : {
    2290             :     // Compute the length of the string in advance, so we can allocate a
    2291             :     // buffer of the right size on the first shot.
    2292             :     //
    2293             :     // (JS_smprintf would be perfect, as that allocates the result
    2294             :     // dynamically as it formats the string, but it won't allocate from cx,
    2295             :     // and wants us to use a special free function.)
    2296             :     char linenoBuf[15];
    2297           6 :     size_t filenameLen = strlen(filename);
    2298           6 :     size_t linenoLen = SprintfLiteral(linenoBuf, "%u", lineno);
    2299           6 :     size_t introducerLen = strlen(introducer);
    2300             :     size_t len = filenameLen                    +
    2301           6 :                  6 /* == strlen(" line ") */    +
    2302             :                  linenoLen                      +
    2303           6 :                  3 /* == strlen(" > ") */       +
    2304             :                  introducerLen                  +
    2305           6 :                  1 /* \0 */;
    2306           6 :     char* formatted = cx->zone()->pod_malloc<char>(len);
    2307           6 :     if (!formatted) {
    2308           0 :         ReportOutOfMemory(cx);
    2309           0 :         return nullptr;
    2310             :     }
    2311          12 :     mozilla::DebugOnly<size_t> checkLen = snprintf(formatted, len, "%s line %s > %s",
    2312          12 :                                                    filename, linenoBuf, introducer);
    2313           6 :     MOZ_ASSERT(checkLen == len - 1);
    2314             : 
    2315           6 :     return formatted;
    2316             : }
    2317             : 
    2318             : bool
    2319        2088 : ScriptSource::initFromOptions(JSContext* cx, const ReadOnlyCompileOptions& options,
    2320             :                               const Maybe<uint32_t>& parameterListEnd)
    2321             : {
    2322        2088 :     MOZ_ASSERT(!filename_);
    2323        2088 :     MOZ_ASSERT(!introducerFilename_);
    2324             : 
    2325        2088 :     mutedErrors_ = options.mutedErrors();
    2326             : 
    2327        2088 :     introductionType_ = options.introductionType;
    2328        2088 :     setIntroductionOffset(options.introductionOffset);
    2329        2088 :     startColumn_ = options.sourceStartColumn;
    2330        2088 :     parameterListEnd_ = parameterListEnd.isSome() ? parameterListEnd.value() : 0;
    2331             : 
    2332        2088 :     if (options.hasIntroductionInfo) {
    2333           6 :         MOZ_ASSERT(options.introductionType != nullptr);
    2334           6 :         const char* filename = options.filename() ? options.filename() : "<unknown>";
    2335           6 :         char* formatted = FormatIntroducedFilename(cx, filename, options.introductionLineno,
    2336          12 :                                                    options.introductionType);
    2337           6 :         if (!formatted)
    2338           0 :             return false;
    2339           6 :         filename_.reset(formatted);
    2340        2082 :     } else if (options.filename()) {
    2341         598 :         if (!setFilename(cx, options.filename()))
    2342           0 :             return false;
    2343             :     }
    2344             : 
    2345        2088 :     if (options.introducerFilename()) {
    2346           6 :         introducerFilename_ = DuplicateString(cx, options.introducerFilename());
    2347           6 :         if (!introducerFilename_)
    2348           0 :             return false;
    2349             :     }
    2350             : 
    2351        2088 :     return true;
    2352             : }
    2353             : 
    2354             : bool
    2355        1771 : ScriptSource::setFilename(JSContext* cx, const char* filename)
    2356             : {
    2357        1771 :     MOZ_ASSERT(!filename_);
    2358        1771 :     filename_ = DuplicateString(cx, filename);
    2359        1771 :     return filename_ != nullptr;
    2360             : }
    2361             : 
    2362             : bool
    2363           2 : ScriptSource::setDisplayURL(JSContext* cx, const char16_t* displayURL)
    2364             : {
    2365           2 :     MOZ_ASSERT(displayURL);
    2366           2 :     if (hasDisplayURL()) {
    2367             :         // FIXME: filename_.get() should be UTF-8 (bug 987069).
    2368           0 :         if (!cx->helperThread() &&
    2369           0 :             !JS_ReportErrorFlagsAndNumberLatin1(cx, JSREPORT_WARNING,
    2370             :                                                 GetErrorMessage, nullptr,
    2371             :                                                 JSMSG_ALREADY_HAS_PRAGMA, filename_.get(),
    2372             :                                                 "//# sourceURL"))
    2373             :         {
    2374           0 :             return false;
    2375             :         }
    2376             :     }
    2377           2 :     size_t len = js_strlen(displayURL) + 1;
    2378           2 :     if (len == 1)
    2379           0 :         return true;
    2380             : 
    2381           2 :     displayURL_ = DuplicateString(cx, displayURL);
    2382           2 :     return displayURL_ != nullptr;
    2383             : }
    2384             : 
    2385             : bool
    2386           0 : ScriptSource::setSourceMapURL(JSContext* cx, const char16_t* sourceMapURL)
    2387             : {
    2388           0 :     MOZ_ASSERT(sourceMapURL);
    2389             : 
    2390           0 :     size_t len = js_strlen(sourceMapURL) + 1;
    2391           0 :     if (len == 1)
    2392           0 :         return true;
    2393             : 
    2394           0 :     sourceMapURL_ = DuplicateString(cx, sourceMapURL);
    2395           0 :     return sourceMapURL_ != nullptr;
    2396             : }
    2397             : 
    2398             : /*
    2399             :  * Shared script data management.
    2400             :  */
    2401             : 
    2402             : SharedScriptData*
    2403       15245 : js::SharedScriptData::new_(JSContext* cx, uint32_t codeLength,
    2404             :                            uint32_t srcnotesLength, uint32_t natoms)
    2405             : {
    2406       15245 :     uint32_t dataLength = natoms * sizeof(GCPtrAtom) + codeLength + srcnotesLength;
    2407       15245 :     uint32_t allocLength = offsetof(SharedScriptData, data_) + dataLength;
    2408       15245 :     auto entry = reinterpret_cast<SharedScriptData*>(cx->zone()->pod_malloc<uint8_t>(allocLength));
    2409       15245 :     if (!entry) {
    2410           0 :         ReportOutOfMemory(cx);
    2411           0 :         return nullptr;
    2412             :     }
    2413             : 
    2414       15245 :     entry->refCount_ = 0;
    2415       15245 :     entry->dataLength_ = dataLength;
    2416       15245 :     entry->natoms_ = natoms;
    2417       15245 :     entry->codeLength_ = codeLength;
    2418             : 
    2419             :     /*
    2420             :      * Call constructors to initialize the storage that will be accessed as a
    2421             :      * GCPtrAtom array via atoms().
    2422             :      */
    2423       15245 :     GCPtrAtom* atoms = entry->atoms();
    2424       15245 :     MOZ_ASSERT(reinterpret_cast<uintptr_t>(atoms) % sizeof(GCPtrAtom*) == 0);
    2425      158883 :     for (unsigned i = 0; i < natoms; ++i)
    2426      143638 :         new (&atoms[i]) GCPtrAtom();
    2427             : 
    2428       15245 :     return entry;
    2429             : }
    2430             : 
    2431             : bool
    2432       15244 : JSScript::createScriptData(JSContext* cx, uint32_t codeLength, uint32_t srcnotesLength,
    2433             :                            uint32_t natoms)
    2434             : {
    2435       15244 :     MOZ_ASSERT(!scriptData());
    2436       15245 :     SharedScriptData* ssd = SharedScriptData::new_(cx, codeLength, srcnotesLength, natoms);
    2437       15245 :     if (!ssd)
    2438           0 :         return false;
    2439             : 
    2440       15245 :     setScriptData(ssd);
    2441       15245 :     return true;
    2442             : }
    2443             : 
    2444             : void
    2445        1093 : JSScript::freeScriptData()
    2446             : {
    2447        1093 :     MOZ_ASSERT(scriptData_->refCount() == 1);
    2448        1093 :     scriptData_->decRefCount();
    2449        1093 :     scriptData_ = nullptr;
    2450        1093 : }
    2451             : 
    2452             : void
    2453       25970 : JSScript::setScriptData(js::SharedScriptData* data)
    2454             : {
    2455       25970 :     MOZ_ASSERT(!scriptData_);
    2456       25970 :     scriptData_ = data;
    2457       25970 :     scriptData_->incRefCount();
    2458       25970 : }
    2459             : 
    2460             : /*
    2461             :  * Takes ownership of its *ssd parameter and either adds it into the runtime's
    2462             :  * ScriptDataTable or frees it if a matching entry already exists.
    2463             :  *
    2464             :  * Sets the |code| and |atoms| fields on the given JSScript.
    2465             :  */
    2466             : bool
    2467       15245 : JSScript::shareScriptData(JSContext* cx)
    2468             : {
    2469       15245 :     SharedScriptData* ssd = scriptData();
    2470       15245 :     MOZ_ASSERT(ssd);
    2471       15245 :     MOZ_ASSERT(ssd->refCount() == 1);
    2472             : 
    2473       30490 :     AutoLockForExclusiveAccess lock(cx);
    2474             : 
    2475       15245 :     ScriptBytecodeHasher::Lookup l(ssd);
    2476             : 
    2477       15245 :     ScriptDataTable::AddPtr p = cx->scriptDataTable(lock).lookupForAdd(l);
    2478       15245 :     if (p) {
    2479        1093 :         MOZ_ASSERT(ssd != *p);
    2480        1093 :         freeScriptData();
    2481        1093 :         setScriptData(*p);
    2482             :     } else {
    2483       14152 :         if (!cx->scriptDataTable(lock).add(p, ssd)) {
    2484           0 :             freeScriptData();
    2485           0 :             ReportOutOfMemory(cx);
    2486           0 :             return false;
    2487             :         }
    2488             : 
    2489             :         // Being in the table counts as a reference on the script data.
    2490       14152 :         scriptData()->incRefCount();
    2491             :     }
    2492             : 
    2493       15245 :     MOZ_ASSERT(scriptData()->refCount() >= 2);
    2494       15245 :     return true;
    2495             : }
    2496             : 
    2497             : void
    2498           0 : js::SweepScriptData(JSRuntime* rt, AutoLockForExclusiveAccess& lock)
    2499             : {
    2500             :     // Entries are removed from the table when their reference count is one,
    2501             :     // i.e. when the only reference to them is from the table entry.
    2502             : 
    2503           0 :     ScriptDataTable& table = rt->scriptDataTable(lock);
    2504             : 
    2505           0 :     for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront()) {
    2506           0 :         SharedScriptData* scriptData = e.front();
    2507           0 :         if (scriptData->refCount() == 1) {
    2508           0 :             scriptData->decRefCount();
    2509           0 :             e.removeFront();
    2510             :         }
    2511             :     }
    2512           0 : }
    2513             : 
    2514             : void
    2515           0 : js::FreeScriptData(JSRuntime* rt, AutoLockForExclusiveAccess& lock)
    2516             : {
    2517           0 :     ScriptDataTable& table = rt->scriptDataTable(lock);
    2518           0 :     if (!table.initialized())
    2519           0 :         return;
    2520             : 
    2521             :     // The table should be empty unless the embedding leaked GC things.
    2522           0 :     MOZ_ASSERT_IF(rt->gc.shutdownCollectedEverything(), table.empty());
    2523             : 
    2524           0 :     for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront()) {
    2525             : #ifdef DEBUG
    2526           0 :         SharedScriptData* scriptData = e.front();
    2527           0 :         fprintf(stderr, "ERROR: GC found live SharedScriptData %p with ref count %d at shutdown\n",
    2528           0 :                 scriptData, scriptData->refCount());
    2529             : #endif
    2530           0 :         js_free(e.front());
    2531             :     }
    2532             : 
    2533           0 :     table.clear();
    2534             : }
    2535             : 
    2536             : /*
    2537             :  * JSScript::data and SharedScriptData::data have complex,
    2538             :  * manually-controlled, memory layouts.
    2539             :  *
    2540             :  * JSScript::data begins with some optional array headers. They are optional
    2541             :  * because they often aren't needed, i.e. the corresponding arrays often have
    2542             :  * zero elements. Each header has a bit in JSScript::hasArrayBits that
    2543             :  * indicates if it's present within |data|; from this the offset of each
    2544             :  * present array header can be computed. Each header has an accessor function
    2545             :  * in JSScript that encapsulates this offset computation.
    2546             :  *
    2547             :  * Array type      Array elements  Accessor
    2548             :  * ----------      --------------  --------
    2549             :  * ConstArray      Consts          consts()
    2550             :  * ObjectArray     Objects         objects()
    2551             :  * ObjectArray     Regexps         regexps()
    2552             :  * TryNoteArray    Try notes       trynotes()
    2553             :  * ScopeNoteArray  Scope notes     scopeNotes()
    2554             :  *
    2555             :  * Then are the elements of several arrays.
    2556             :  * - Most of these arrays have headers listed above (if present). For each of
    2557             :  *   these, the array pointer and the array length is stored in the header.
    2558             :  * - The remaining arrays have pointers and lengths that are stored directly in
    2559             :  *   JSScript. This is because, unlike the others, they are nearly always
    2560             :  *   non-zero length and so the optional-header space optimization isn't
    2561             :  *   worthwhile.
    2562             :  *
    2563             :  * Array elements   Pointed to by         Length
    2564             :  * --------------   -------------         ------
    2565             :  * Consts           consts()->vector      consts()->length
    2566             :  * Objects          objects()->vector     objects()->length
    2567             :  * Regexps          regexps()->vector     regexps()->length
    2568             :  * Try notes        trynotes()->vector    trynotes()->length
    2569             :  * Scope notes      scopeNotes()->vector  scopeNotes()->length
    2570             :  *
    2571             :  * IMPORTANT: This layout has two key properties.
    2572             :  * - It ensures that everything has sufficient alignment; in particular, the
    2573             :  *   consts() elements need Value alignment.
    2574             :  * - It ensures there are no gaps between elements, which saves space and makes
    2575             :  *   manual layout easy. In particular, in the second part, arrays with larger
    2576             :  *   elements precede arrays with smaller elements.
    2577             :  *
    2578             :  * SharedScriptData::data contains data that can be shared within a
    2579             :  * runtime. These items' layout is manually controlled to make it easier to
    2580             :  * manage both during (temporary) allocation and during matching against
    2581             :  * existing entries in the runtime. As the jsbytecode has to come first to
    2582             :  * enable lookup by bytecode identity, SharedScriptData::data, the atoms part
    2583             :  * has to manually be aligned sufficiently by adding padding after the notes
    2584             :  * part.
    2585             :  *
    2586             :  * Array elements   Pointed to by         Length
    2587             :  * --------------   -------------         ------
    2588             :  * jsbytecode       code                  length
    2589             :  * jsscrnote        notes()               numNotes()
    2590             :  * Atoms            atoms                 natoms
    2591             :  *
    2592             :  * The following static assertions check JSScript::data's alignment properties.
    2593             :  */
    2594             : 
    2595             : template<class T>
    2596             : constexpr bool
    2597             : KeepsValueAlignment() {
    2598             :     return alignof(JS::Value) % alignof(T) == 0 &&
    2599             :            sizeof(T) % sizeof(JS::Value) == 0;
    2600             : }
    2601             : 
    2602             : template<class T>
    2603             : constexpr bool
    2604             : HasValueAlignment() {
    2605             :     return alignof(JS::Value) == alignof(T) &&
    2606             :            sizeof(T) == sizeof(JS::Value);
    2607             : }
    2608             : 
    2609             : template<class T1, class T2>
    2610             : constexpr bool
    2611             : NoPaddingBetweenEntries() {
    2612             :     return alignof(T1) % alignof(T2) == 0;
    2613             : }
    2614             : 
    2615             : /*
    2616             :  * These assertions ensure that there is no padding between the array headers,
    2617             :  * and also that the consts() elements (which follow immediately afterward) are
    2618             :  * Value-aligned.  (There is an assumption that |data| itself is Value-aligned;
    2619             :  * we check this below).
    2620             :  */
    2621             : JS_STATIC_ASSERT(KeepsValueAlignment<ConstArray>());
    2622             : JS_STATIC_ASSERT(KeepsValueAlignment<ObjectArray>());       /* there are two of these */
    2623             : JS_STATIC_ASSERT(KeepsValueAlignment<TryNoteArray>());
    2624             : JS_STATIC_ASSERT(KeepsValueAlignment<ScopeNoteArray>());
    2625             : 
    2626             : /* These assertions ensure there is no padding required between array elements. */
    2627             : JS_STATIC_ASSERT(HasValueAlignment<GCPtrValue>());
    2628             : JS_STATIC_ASSERT((NoPaddingBetweenEntries<GCPtrValue, GCPtrObject>()));
    2629             : JS_STATIC_ASSERT((NoPaddingBetweenEntries<GCPtrObject, GCPtrObject>()));
    2630             : JS_STATIC_ASSERT((NoPaddingBetweenEntries<GCPtrObject, JSTryNote>()));
    2631             : JS_STATIC_ASSERT((NoPaddingBetweenEntries<JSTryNote, uint32_t>()));
    2632             : JS_STATIC_ASSERT((NoPaddingBetweenEntries<uint32_t, uint32_t>()));
    2633             : 
    2634             : JS_STATIC_ASSERT((NoPaddingBetweenEntries<GCPtrValue, ScopeNote>()));
    2635             : JS_STATIC_ASSERT((NoPaddingBetweenEntries<ScopeNote, ScopeNote>()));
    2636             : JS_STATIC_ASSERT((NoPaddingBetweenEntries<JSTryNote, ScopeNote>()));
    2637             : JS_STATIC_ASSERT((NoPaddingBetweenEntries<GCPtrObject, ScopeNote>()));
    2638             : JS_STATIC_ASSERT((NoPaddingBetweenEntries<ScopeNote, uint32_t>()));
    2639             : 
    2640             : static inline size_t
    2641       15245 : ScriptDataSize(uint32_t nscopes, uint32_t nconsts, uint32_t nobjects,
    2642             :                uint32_t ntrynotes, uint32_t nscopenotes, uint32_t nyieldoffsets)
    2643             : {
    2644       15245 :     size_t size = 0;
    2645             : 
    2646       15245 :     MOZ_ASSERT(nscopes != 0);
    2647       15245 :     size += sizeof(ScopeArray) + nscopes * sizeof(Scope*);
    2648       15245 :     if (nconsts != 0)
    2649          58 :         size += sizeof(ConstArray) + nconsts * sizeof(Value);
    2650       15245 :     if (nobjects != 0)
    2651        4015 :         size += sizeof(ObjectArray) + nobjects * sizeof(NativeObject*);
    2652       15245 :     if (ntrynotes != 0)
    2653        2586 :         size += sizeof(TryNoteArray) + ntrynotes * sizeof(JSTryNote);
    2654       15245 :     if (nscopenotes != 0)
    2655        5092 :         size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote);
    2656       15245 :     if (nyieldoffsets != 0)
    2657         445 :         size += sizeof(YieldAndAwaitOffsetArray) + nyieldoffsets * sizeof(uint32_t);
    2658             : 
    2659       15245 :      return size;
    2660             : }
    2661             : 
    2662             : void
    2663       24874 : JSScript::initCompartment(JSContext* cx)
    2664             : {
    2665       24874 :     compartment_ = cx->compartment();
    2666       24874 : }
    2667             : 
    2668             : /* static */ JSScript*
    2669       24875 : JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
    2670             :                  HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd,
    2671             :                  uint32_t toStringStart, uint32_t toStringEnd)
    2672             : {
    2673             :     // bufStart and bufEnd specify the range of characters parsed by the
    2674             :     // Parser to produce this script. toStringStart and toStringEnd specify
    2675             :     // the range of characters to be returned for Function.prototype.toString.
    2676       24875 :     MOZ_ASSERT(bufStart <= bufEnd);
    2677       24875 :     MOZ_ASSERT(toStringStart <= toStringEnd);
    2678       24875 :     MOZ_ASSERT(toStringStart <= bufStart);
    2679       24875 :     MOZ_ASSERT(toStringEnd >= bufEnd);
    2680             : 
    2681       49750 :     RootedScript script(cx, Allocate<JSScript>(cx));
    2682       24875 :     if (!script)
    2683           0 :         return nullptr;
    2684             : 
    2685       24875 :     PodZero(script.get());
    2686             : 
    2687       24874 :     script->initCompartment(cx);
    2688             : 
    2689       24874 :     script->selfHosted_ = options.selfHostingMode;
    2690       24874 :     script->noScriptRval_ = options.noScriptRval;
    2691       24874 :     script->treatAsRunOnce_ = options.isRunOnce;
    2692             : 
    2693       24874 :     script->version = options.version;
    2694       24874 :     MOZ_ASSERT(script->getVersion() == options.version);     // assert that no overflow occurred
    2695             : 
    2696       24874 :     script->setSourceObject(sourceObject);
    2697       24875 :     if (cx->runtime()->lcovOutput().isEnabled() && !script->initScriptName(cx))
    2698           0 :         return nullptr;
    2699       24875 :     script->sourceStart_ = bufStart;
    2700       24875 :     script->sourceEnd_ = bufEnd;
    2701       24875 :     script->toStringStart_ = toStringStart;
    2702       24875 :     script->toStringEnd_ = toStringEnd;
    2703             : 
    2704             : #ifdef MOZ_VTUNE
    2705       24875 :     script->vtuneMethodId_ = vtune::GenerateUniqueMethodID();
    2706             : #endif
    2707             : 
    2708       24875 :     return script;
    2709             : }
    2710             : 
    2711             : bool
    2712           0 : JSScript::initScriptName(JSContext* cx)
    2713             : {
    2714           0 :     MOZ_ASSERT(!hasScriptName());
    2715             : 
    2716           0 :     if (!filename())
    2717           0 :         return true;
    2718             : 
    2719             :     // Create compartment's scriptNameMap if necessary.
    2720           0 :     ScriptNameMap* map = compartment()->scriptNameMap;
    2721           0 :     if (!map) {
    2722           0 :         map = cx->new_<ScriptNameMap>();
    2723           0 :         if (!map) {
    2724           0 :             ReportOutOfMemory(cx);
    2725           0 :             return false;
    2726             :         }
    2727             : 
    2728           0 :         if (!map->init()) {
    2729           0 :             js_delete(map);
    2730           0 :             ReportOutOfMemory(cx);
    2731           0 :             return false;
    2732             :         }
    2733             : 
    2734           0 :         compartment()->scriptNameMap = map;
    2735             :     }
    2736             : 
    2737           0 :     char* name = js_strdup(filename());
    2738           0 :     if (!name) {
    2739           0 :         ReportOutOfMemory(cx);
    2740           0 :         return false;
    2741             :     }
    2742             : 
    2743             :     // Register the script name in the compartment's map.
    2744           0 :     if (!map->putNew(this, name)) {
    2745           0 :         js_delete(name);
    2746           0 :         ReportOutOfMemory(cx);
    2747           0 :         return false;
    2748             :     }
    2749             : 
    2750           0 :     return true;
    2751             : }
    2752             : 
    2753             : static inline uint8_t*
    2754       24876 : AllocScriptData(JS::Zone* zone, size_t size)
    2755             : {
    2756       24876 :     if (!size)
    2757           0 :         return nullptr;
    2758             : 
    2759       24876 :     uint8_t* data = zone->pod_calloc<uint8_t>(JS_ROUNDUP(size, sizeof(Value)));
    2760       24877 :     if (!data)
    2761           0 :         return nullptr;
    2762       24877 :     MOZ_ASSERT(size_t(data) % sizeof(Value) == 0);
    2763       24877 :     return data;
    2764             : }
    2765             : 
    2766             : /* static */ bool
    2767       15245 : JSScript::partiallyInit(JSContext* cx, HandleScript script, uint32_t nscopes,
    2768             :                         uint32_t nconsts, uint32_t nobjects, uint32_t ntrynotes,
    2769             :                         uint32_t nscopenotes, uint32_t nyieldoffsets, uint32_t nTypeSets)
    2770             : {
    2771             :     size_t size = ScriptDataSize(nscopes, nconsts, nobjects, ntrynotes,
    2772       15245 :                                  nscopenotes, nyieldoffsets);
    2773       15245 :     script->data = AllocScriptData(script->zone(), size);
    2774       15245 :     if (size && !script->data) {
    2775           0 :         ReportOutOfMemory(cx);
    2776           0 :         return false;
    2777             :     }
    2778       15245 :     script->dataSize_ = size;
    2779             : 
    2780       15245 :     MOZ_ASSERT(nTypeSets <= UINT16_MAX);
    2781       15245 :     script->nTypeSets_ = uint16_t(nTypeSets);
    2782             : 
    2783       15245 :     uint8_t* cursor = script->data;
    2784             : 
    2785             :     // There must always be at least 1 scope, the body scope.
    2786       15245 :     MOZ_ASSERT(nscopes != 0);
    2787       15245 :     cursor += sizeof(ScopeArray);
    2788             : 
    2789       15245 :     if (nconsts != 0) {
    2790          58 :         script->setHasArray(CONSTS);
    2791          58 :         cursor += sizeof(ConstArray);
    2792             :     }
    2793       15245 :     if (nobjects != 0) {
    2794        4015 :         script->setHasArray(OBJECTS);
    2795        4015 :         cursor += sizeof(ObjectArray);
    2796             :     }
    2797             : 
    2798       15245 :     if (ntrynotes != 0) {
    2799        2586 :         script->setHasArray(TRYNOTES);
    2800        2586 :         cursor += sizeof(TryNoteArray);
    2801             :     }
    2802       15245 :     if (nscopenotes != 0) {
    2803        5092 :         script->setHasArray(SCOPENOTES);
    2804        5092 :         cursor += sizeof(ScopeNoteArray);
    2805             :     }
    2806             : 
    2807       15245 :     YieldAndAwaitOffsetArray* yieldAndAwaitOffsets = nullptr;
    2808       15245 :     if (nyieldoffsets != 0) {
    2809         445 :         yieldAndAwaitOffsets = reinterpret_cast<YieldAndAwaitOffsetArray*>(cursor);
    2810         445 :         cursor += sizeof(YieldAndAwaitOffsetArray);
    2811             :     }
    2812             : 
    2813       15245 :     if (nconsts != 0) {
    2814          58 :         MOZ_ASSERT(reinterpret_cast<uintptr_t>(cursor) % sizeof(JS::Value) == 0);
    2815          58 :         script->consts()->length = nconsts;
    2816          58 :         script->consts()->vector = (GCPtrValue*)cursor;
    2817          58 :         cursor += nconsts * sizeof(script->consts()->vector[0]);
    2818             :     }
    2819             : 
    2820       15245 :     script->scopes()->length = nscopes;
    2821       15245 :     script->scopes()->vector = (GCPtrScope*)cursor;
    2822       15245 :     cursor += nscopes * sizeof(script->scopes()->vector[0]);
    2823             : 
    2824       15245 :     if (nobjects != 0) {
    2825        4015 :         script->objects()->length = nobjects;
    2826        4015 :         script->objects()->vector = (GCPtrObject*)cursor;
    2827        4015 :         cursor += nobjects * sizeof(script->objects()->vector[0]);
    2828             :     }
    2829             : 
    2830       15245 :     if (ntrynotes != 0) {
    2831        2586 :         script->trynotes()->length = ntrynotes;
    2832        2586 :         script->trynotes()->vector = reinterpret_cast<JSTryNote*>(cursor);
    2833        2586 :         size_t vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
    2834             : #ifdef DEBUG
    2835        2586 :         memset(cursor, 0, vectorSize);
    2836             : #endif
    2837        2586 :         cursor += vectorSize;
    2838             :     }
    2839             : 
    2840       15245 :     if (nscopenotes != 0) {
    2841        5092 :         script->scopeNotes()->length = nscopenotes;
    2842        5092 :         script->scopeNotes()->vector = reinterpret_cast<ScopeNote*>(cursor);
    2843        5092 :         size_t vectorSize = nscopenotes * sizeof(script->scopeNotes()->vector[0]);
    2844             : #ifdef DEBUG
    2845        5092 :         memset(cursor, 0, vectorSize);
    2846             : #endif
    2847        5092 :         cursor += vectorSize;
    2848             :     }
    2849             : 
    2850       15245 :     if (nyieldoffsets != 0) {
    2851         445 :         yieldAndAwaitOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
    2852         445 :         size_t vectorSize = nyieldoffsets * sizeof(script->yieldAndAwaitOffsets()[0]);
    2853             : #ifdef DEBUG
    2854         445 :         memset(cursor, 0, vectorSize);
    2855             : #endif
    2856         445 :         cursor += vectorSize;
    2857             :     }
    2858             : 
    2859       15245 :     MOZ_ASSERT(cursor == script->data + size);
    2860       15245 :     return true;
    2861             : }
    2862             : 
    2863             : /* static */ bool
    2864         311 : JSScript::initFunctionPrototype(JSContext* cx, Handle<JSScript*> script,
    2865             :                                 HandleFunction functionProto)
    2866             : {
    2867         311 :     uint32_t numScopes = 1;
    2868         311 :     uint32_t numConsts = 0;
    2869         311 :     uint32_t numObjects = 0;
    2870         311 :     uint32_t numTryNotes = 0;
    2871         311 :     uint32_t numScopeNotes = 0;
    2872         311 :     uint32_t numYieldAndAwaitOffsets = 0;
    2873         311 :     uint32_t numTypeSets = 0;
    2874         311 :     if (!partiallyInit(cx, script, numScopes, numConsts, numObjects, numTryNotes,
    2875             :                        numScopeNotes, numYieldAndAwaitOffsets, numTypeSets))
    2876             :     {
    2877           0 :         return false;
    2878             :     }
    2879             : 
    2880         622 :     RootedScope enclosing(cx, &cx->global()->emptyGlobalScope());
    2881         622 :     Scope* functionProtoScope = FunctionScope::create(cx, nullptr, false, false, functionProto,
    2882         311 :                                                       enclosing);
    2883         311 :     if (!functionProtoScope)
    2884           0 :         return false;
    2885         311 :     script->scopes()->vector[0].init(functionProtoScope);
    2886             : 
    2887         311 :     uint32_t codeLength = 1;
    2888         311 :     uint32_t srcNotesLength = 1;
    2889         311 :     uint32_t numAtoms = 0;
    2890         311 :     if (!script->createScriptData(cx, codeLength, srcNotesLength, numAtoms))
    2891           0 :         return false;
    2892             : 
    2893         311 :     jsbytecode* code = script->code();
    2894         311 :     code[0] = JSOP_RETRVAL;
    2895         311 :     code[1] = SRC_NULL;
    2896         311 :     return script->shareScriptData(cx);
    2897             : }
    2898             : 
    2899             : static void
    2900        5675 : InitAtomMap(frontend::AtomIndexMap& indices, GCPtrAtom* atoms)
    2901             : {
    2902       57524 :     for (AtomIndexMap::Range r = indices.all(); !r.empty(); r.popFront()) {
    2903       51849 :         JSAtom* atom = r.front().key();
    2904       51849 :         uint32_t index = r.front().value();
    2905       51849 :         MOZ_ASSERT(index < indices.count());
    2906       51849 :         atoms[index].init(atom);
    2907             :     }
    2908        5675 : }
    2909             : 
    2910             : /* static */ void
    2911        5405 : JSScript::initFromFunctionBox(JSContext* cx, HandleScript script,
    2912             :                               frontend::FunctionBox* funbox)
    2913             : {
    2914        5405 :     JSFunction* fun = funbox->function();
    2915        5405 :     if (fun->isInterpretedLazy())
    2916        1407 :         fun->setUnlazifiedScript(script);
    2917             :     else
    2918        3998 :         fun->setScript(script);
    2919             : 
    2920        5405 :     script->funHasExtensibleScope_ = funbox->hasExtensibleScope();
    2921        5405 :     script->needsHomeObject_       = funbox->needsHomeObject();
    2922        5405 :     script->isDerivedClassConstructor_ = funbox->isDerivedClassConstructor();
    2923             : 
    2924        5405 :     if (funbox->argumentsHasLocalBinding()) {
    2925         264 :         script->setArgumentsHasVarBinding();
    2926         264 :         if (funbox->definitelyNeedsArgsObj())
    2927           3 :             script->setNeedsArgsObj(true);
    2928             :     } else {
    2929        5141 :         MOZ_ASSERT(!funbox->definitelyNeedsArgsObj());
    2930             :     }
    2931        5405 :     script->hasMappedArgsObj_ = funbox->hasMappedArgsObj();
    2932             : 
    2933        5405 :     script->functionHasThisBinding_ = funbox->hasThisBinding();
    2934        5405 :     script->functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope();
    2935             : 
    2936        5405 :     script->funLength_ = funbox->length;
    2937             : 
    2938        5405 :     script->isGeneratorExp_ = funbox->isGenexpLambda;
    2939        5405 :     script->setGeneratorKind(funbox->generatorKind());
    2940        5405 :     script->setAsyncKind(funbox->asyncKind());
    2941        5405 :     if (funbox->hasRest())
    2942          62 :         script->setHasRest();
    2943        5405 :     if (funbox->isExprBody())
    2944         355 :         script->setIsExprBody();
    2945             : 
    2946        5405 :     PositionalFormalParameterIter fi(script);
    2947       17041 :     while (fi && !fi.closedOver())
    2948        5818 :         fi++;
    2949        5405 :     script->funHasAnyAliasedFormal_ = !!fi;
    2950             : 
    2951        5405 :     script->setHasInnerFunctions(funbox->hasInnerFunctions());
    2952        5405 : }
    2953             : 
    2954             : /* static */ void
    2955           0 : JSScript::initFromModuleContext(JSContext* cx, HandleScript script,
    2956             :                                 frontend::ModuleSharedContext* modulesc)
    2957             : {
    2958           0 :     script->funHasExtensibleScope_ = false;
    2959           0 :     script->needsHomeObject_ = false;
    2960           0 :     script->isDerivedClassConstructor_ = false;
    2961           0 :     script->funLength_ = 0;
    2962             : 
    2963           0 :     script->isGeneratorExp_ = false;
    2964           0 :     script->setGeneratorKind(NotGenerator);
    2965             : 
    2966             :     // Since modules are only run once, mark the script so that initializers
    2967             :     // created within it may be given more precise types.
    2968           0 :     script->setTreatAsRunOnce();
    2969           0 :     MOZ_ASSERT(!script->hasRunOnce());
    2970           0 : }
    2971             : 
    2972             : /* static */ bool
    2973        5675 : JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script, BytecodeEmitter* bce)
    2974             : {
    2975             :     /* The counts of indexed things must be checked during code generation. */
    2976        5675 :     MOZ_ASSERT(bce->atomIndices->count() <= INDEX_LIMIT);
    2977        5675 :     MOZ_ASSERT(bce->objectList.length <= INDEX_LIMIT);
    2978             : 
    2979        5675 :     uint32_t mainLength = bce->offset();
    2980        5675 :     uint32_t prologueLength = bce->prologueOffset();
    2981             :     uint32_t nsrcnotes;
    2982        5675 :     if (!bce->finishTakingSrcNotes(&nsrcnotes))
    2983           0 :         return false;
    2984        5675 :     uint32_t natoms = bce->atomIndices->count();
    2985       28375 :     if (!partiallyInit(cx, script,
    2986        5675 :                        bce->scopeList.length(), bce->constList.length(), bce->objectList.length,
    2987       11350 :                        bce->tryNoteList.length(), bce->scopeNoteList.length(),
    2988       11350 :                        bce->yieldAndAwaitOffsetList.length(), bce->typesetCount))
    2989             :     {
    2990           0 :         return false;
    2991             :     }
    2992             : 
    2993        5675 :     MOZ_ASSERT(script->mainOffset() == 0);
    2994        5675 :     script->mainOffset_ = prologueLength;
    2995             : 
    2996        5675 :     script->lineno_ = bce->firstLine;
    2997             : 
    2998        5675 :     if (!script->createScriptData(cx, prologueLength + mainLength, nsrcnotes, natoms))
    2999           0 :         return false;
    3000             : 
    3001        5675 :     jsbytecode* code = script->code();
    3002        5675 :     PodCopy<jsbytecode>(code, bce->prologue.code.begin(), prologueLength);
    3003        5675 :     PodCopy<jsbytecode>(code + prologueLength, bce->main.code.begin(), mainLength);
    3004        5675 :     bce->copySrcNotes((jssrcnote*)(code + script->length()), nsrcnotes);
    3005        5675 :     InitAtomMap(*bce->atomIndices, script->atoms());
    3006             : 
    3007        5675 :     if (!script->shareScriptData(cx))
    3008           0 :         return false;
    3009             : 
    3010        5675 :     if (bce->constList.length() != 0)
    3011          38 :         bce->constList.finish(script->consts());
    3012        5675 :     if (bce->objectList.length != 0)
    3013        1382 :         bce->objectList.finish(script->objects());
    3014        5675 :     if (bce->scopeList.length() != 0)
    3015        5675 :         bce->scopeList.finish(script->scopes());
    3016        5675 :     if (bce->tryNoteList.length() != 0)
    3017        1074 :         bce->tryNoteList.finish(script->trynotes());
    3018        5675 :     if (bce->scopeNoteList.length() != 0)
    3019        1657 :         bce->scopeNoteList.finish(script->scopeNotes(), prologueLength);
    3020        5675 :     script->strict_ = bce->sc->strict();
    3021        5675 :     script->explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
    3022        5675 :     script->bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
    3023        5675 :     script->hasSingletons_ = bce->hasSingletons;
    3024             : 
    3025        5675 :     uint64_t nslots = bce->maxFixedSlots + static_cast<uint64_t>(bce->maxStackDepth);
    3026        5675 :     if (nslots > UINT32_MAX) {
    3027           0 :         bce->reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
    3028           0 :         return false;
    3029             :     }
    3030             : 
    3031        5675 :     script->nfixed_ = bce->maxFixedSlots;
    3032        5675 :     script->nslots_ = nslots;
    3033        5675 :     script->bodyScopeIndex_ = bce->bodyScopeIndex;
    3034        5675 :     script->hasNonSyntacticScope_ = bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic);
    3035             : 
    3036        5675 :     if (bce->sc->isFunctionBox())
    3037        5405 :         initFromFunctionBox(cx, script, bce->sc->asFunctionBox());
    3038         270 :     else if (bce->sc->isModuleContext())
    3039           0 :         initFromModuleContext(cx, script, bce->sc->asModuleContext());
    3040             : 
    3041             :     // Copy yield offsets last, as the generator kind is set in
    3042             :     // initFromFunctionBox.
    3043        5675 :     if (bce->yieldAndAwaitOffsetList.length() != 0)
    3044         127 :         bce->yieldAndAwaitOffsetList.finish(script->yieldAndAwaitOffsets(), prologueLength);
    3045             : 
    3046             : #ifdef DEBUG
    3047        5675 :     script->assertValidJumpTargets();
    3048             : #endif
    3049             : 
    3050        5675 :     return true;
    3051             : }
    3052             : 
    3053             : #ifdef DEBUG
    3054             : void
    3055        5675 : JSScript::assertValidJumpTargets() const
    3056             : {
    3057        5675 :     jsbytecode* end = codeEnd();
    3058        5675 :     jsbytecode* mainEntry = main();
    3059      394620 :     for (jsbytecode* pc = code(); pc != end; pc = GetNextPc(pc)) {
    3060             :         // Check jump instructions' target.
    3061      388945 :         if (IsJumpOpcode(JSOp(*pc))) {
    3062       19627 :             jsbytecode* target = pc + GET_JUMP_OFFSET(pc);
    3063       19627 :             MOZ_ASSERT(mainEntry <= target && target < end);
    3064       19627 :             MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*target)));
    3065             : 
    3066             :             // Check fallthrough of conditional jump instructions.
    3067       19627 :             if (BytecodeFallsThrough(JSOp(*pc))) {
    3068       13474 :                 jsbytecode* fallthrough = GetNextPc(pc);
    3069       13474 :                 MOZ_ASSERT(mainEntry <= fallthrough && fallthrough < end);
    3070       13474 :                 MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*fallthrough)));
    3071             :             }
    3072             :         }
    3073             : 
    3074             :         // Check table switch case labels.
    3075      388945 :         if (JSOp(*pc) == JSOP_TABLESWITCH) {
    3076          78 :             jsbytecode* pc2 = pc;
    3077          78 :             int32_t len = GET_JUMP_OFFSET(pc2);
    3078             : 
    3079             :             // Default target.
    3080          78 :             MOZ_ASSERT(mainEntry <= pc + len && pc + len < end);
    3081          78 :             MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*(pc + len))));
    3082             : 
    3083          78 :             pc2 += JUMP_OFFSET_LEN;
    3084          78 :             int32_t low = GET_JUMP_OFFSET(pc2);
    3085          78 :             pc2 += JUMP_OFFSET_LEN;
    3086          78 :             int32_t high = GET_JUMP_OFFSET(pc2);
    3087             : 
    3088         654 :             for (int i = 0; i < high - low + 1; i++) {
    3089         576 :                 pc2 += JUMP_OFFSET_LEN;
    3090         576 :                 int32_t off = (int32_t) GET_JUMP_OFFSET(pc2);
    3091             :                 // Case (i + low)
    3092         576 :                 MOZ_ASSERT_IF(off, mainEntry <= pc + off && pc + off < end);
    3093         576 :                 MOZ_ASSERT_IF(off, BytecodeIsJumpTarget(JSOp(*(pc + off))));
    3094             :             }
    3095             :         }
    3096             :     }
    3097             : 
    3098             :     // Check catch/finally blocks as jump targets.
    3099        5675 :     if (hasTrynotes()) {
    3100        1074 :         JSTryNote* tn = trynotes()->vector;
    3101        1074 :         JSTryNote* tnlimit = tn + trynotes()->length;
    3102        6764 :         for (; tn < tnlimit; tn++) {
    3103        2845 :             jsbytecode* tryStart = mainEntry + tn->start;
    3104        2845 :             jsbytecode* tryPc = tryStart - 1;
    3105        2845 :             if (tn->kind != JSTRY_CATCH && tn->kind != JSTRY_FINALLY)
    3106        1638 :                 continue;
    3107             : 
    3108        1207 :             MOZ_ASSERT(JSOp(*tryPc) == JSOP_TRY);
    3109        1207 :             jsbytecode* tryTarget = tryStart + tn->length;
    3110        1207 :             MOZ_ASSERT(mainEntry <= tryTarget && tryTarget < end);
    3111        1207 :             MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*tryTarget)));
    3112             :         }
    3113             :     }
    3114        5675 : }
    3115             : #endif
    3116             : 
    3117             : size_t
    3118           0 : JSScript::computedSizeOfData() const
    3119             : {
    3120           0 :     return dataSize();
    3121             : }
    3122             : 
    3123             : size_t
    3124           0 : JSScript::sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const
    3125             : {
    3126           0 :     return mallocSizeOf(data);
    3127             : }
    3128             : 
    3129             : size_t
    3130           0 : JSScript::sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const
    3131             : {
    3132           0 :     return types_->sizeOfIncludingThis(mallocSizeOf);
    3133             : }
    3134             : 
    3135             : /*
    3136             :  * Nb: srcnotes are variable-length.  This function computes the number of
    3137             :  * srcnote *slots*, which may be greater than the number of srcnotes.
    3138             :  */
    3139             : uint32_t
    3140        2893 : JSScript::numNotes()
    3141             : {
    3142             :     jssrcnote* sn;
    3143        2893 :     jssrcnote* notes_ = notes();
    3144      100846 :     for (sn = notes_; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
    3145       97953 :         continue;
    3146        2893 :     return sn - notes_ + 1;    /* +1 for the terminator */
    3147             : }
    3148             : 
    3149             : js::GlobalObject&
    3150           0 : JSScript::uninlinedGlobal() const
    3151             : {
    3152           0 :     return global();
    3153             : }
    3154             : 
    3155             : void
    3156           0 : JSScript::finalize(FreeOp* fop)
    3157             : {
    3158             :     // NOTE: this JSScript may be partially initialized at this point.  E.g. we
    3159             :     // may have created it and partially initialized it with
    3160             :     // JSScript::Create(), but not yet finished initializing it with
    3161             :     // fullyInitFromEmitter() or fullyInitTrivial().
    3162             : 
    3163             :     // Collect code coverage information for this script and all its inner
    3164             :     // scripts, and store the aggregated information on the compartment.
    3165           0 :     MOZ_ASSERT_IF(hasScriptName(), fop->runtime()->lcovOutput().isEnabled());
    3166           0 :     if (fop->runtime()->lcovOutput().isEnabled() && hasScriptName()) {
    3167           0 :         compartment()->lcovOutput.collectCodeCoverageInfo(compartment(), this, getScriptName());
    3168           0 :         destroyScriptName();
    3169             :     }
    3170             : 
    3171           0 :     fop->runtime()->geckoProfiler().onScriptFinalized(this);
    3172             : 
    3173           0 :     if (types_)
    3174           0 :         types_->destroy();
    3175             : 
    3176           0 :     jit::DestroyJitScripts(fop, this);
    3177             : 
    3178           0 :     destroyScriptCounts(fop);
    3179           0 :     destroyDebugScript(fop);
    3180             : 
    3181           0 :     if (data) {
    3182           0 :         JS_POISON(data, 0xdb, computedSizeOfData());
    3183           0 :         fop->free_(data);
    3184             :     }
    3185             : 
    3186           0 :     if (scriptData_)
    3187           0 :         scriptData_->decRefCount();
    3188             : 
    3189           0 :     fop->runtime()->caches().lazyScriptCache.remove(this);
    3190             : 
    3191             :     // In most cases, our LazyScript's script pointer will reference this
    3192             :     // script, and thus be nulled out by normal weakref processing. However, if
    3193             :     // we unlazified the LazyScript during incremental sweeping, it will have a
    3194             :     // completely different JSScript.
    3195           0 :     MOZ_ASSERT_IF(lazyScript && !IsAboutToBeFinalizedUnbarriered(&lazyScript),
    3196             :                   !lazyScript->hasScript() || lazyScript->maybeScriptUnbarriered() != this);
    3197           0 : }
    3198             : 
    3199             : static const uint32_t GSN_CACHE_THRESHOLD = 100;
    3200             : 
    3201             : void
    3202          11 : GSNCache::purge()
    3203             : {
    3204          11 :     code = nullptr;
    3205          11 :     if (map.initialized())
    3206           3 :         map.finish();
    3207          11 : }
    3208             : 
    3209             : jssrcnote*
    3210        2967 : js::GetSrcNote(GSNCache& cache, JSScript* script, jsbytecode* pc)
    3211             : {
    3212        2967 :     size_t target = pc - script->code();
    3213        2967 :     if (target >= script->length())
    3214           0 :         return nullptr;
    3215             : 
    3216        2967 :     if (cache.code == script->code()) {
    3217        2676 :         MOZ_ASSERT(cache.map.initialized());
    3218        2676 :         GSNCache::Map::Ptr p = cache.map.lookup(pc);
    3219        2676 :         return p ? p->value() : nullptr;
    3220             :     }
    3221             : 
    3222         291 :     size_t offset = 0;
    3223             :     jssrcnote* result;
    3224       15212 :     for (jssrcnote* sn = script->notes(); ; sn = SN_NEXT(sn)) {
    3225       30133 :         if (SN_IS_TERMINATOR(sn)) {
    3226         175 :             result = nullptr;
    3227         175 :             break;
    3228             :         }
    3229       15037 :         offset += SN_DELTA(sn);
    3230       15037 :         if (offset == target && SN_IS_GETTABLE(sn)) {
    3231         116 :             result = sn;
    3232         116 :             break;
    3233             :         }
    3234             :     }
    3235             : 
    3236         291 :     if (cache.code != script->code() && script->length() >= GSN_CACHE_THRESHOLD) {
    3237         232 :         unsigned nsrcnotes = 0;
    3238       22389 :         for (jssrcnote* sn = script->notes(); !SN_IS_TERMINATOR(sn);
    3239       22157 :              sn = SN_NEXT(sn))
    3240             :         {
    3241       22157 :             if (SN_IS_GETTABLE(sn))
    3242        2217 :                 ++nsrcnotes;
    3243             :         }
    3244         232 :         if (cache.code) {
    3245          93 :             MOZ_ASSERT(cache.map.initialized());
    3246          93 :             cache.map.finish();
    3247          93 :             cache.code = nullptr;
    3248             :         }
    3249         232 :         if (cache.map.init(nsrcnotes)) {
    3250         232 :             pc = script->code();
    3251       22389 :             for (jssrcnote* sn = script->notes(); !SN_IS_TERMINATOR(sn);
    3252       22157 :                  sn = SN_NEXT(sn))
    3253             :             {
    3254       22157 :                 pc += SN_DELTA(sn);
    3255       22157 :                 if (SN_IS_GETTABLE(sn))
    3256        2217 :                     cache.map.putNewInfallible(pc, sn);
    3257             :             }
    3258         232 :             cache.code = script->code();
    3259             :         }
    3260             :     }
    3261             : 
    3262         291 :     return result;
    3263             : }
    3264             : 
    3265             : jssrcnote*
    3266           3 : js::GetSrcNote(JSContext* cx, JSScript* script, jsbytecode* pc)
    3267             : {
    3268           3 :     return GetSrcNote(cx->caches().gsnCache, script, pc);
    3269             : }
    3270             : 
    3271             : unsigned
    3272        1053 : js::PCToLineNumber(unsigned startLine, jssrcnote* notes, jsbytecode* code, jsbytecode* pc,
    3273             :                    unsigned* columnp)
    3274             : {
    3275        1053 :     unsigned lineno = startLine;
    3276        1053 :     unsigned column = 0;
    3277             : 
    3278             :     /*
    3279             :      * Walk through source notes accumulating their deltas, keeping track of
    3280             :      * line-number notes, until we pass the note for pc's offset within
    3281             :      * script->code.
    3282             :      */
    3283        1053 :     ptrdiff_t offset = 0;
    3284        1053 :     ptrdiff_t target = pc - code;
    3285       91441 :     for (jssrcnote* sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
    3286       91438 :         offset += SN_DELTA(sn);
    3287       91438 :         if (offset > target)
    3288        1050 :             break;
    3289             : 
    3290       90388 :         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
    3291       90388 :         if (type == SRC_SETLINE) {
    3292        6556 :             lineno = unsigned(GetSrcNoteOffset(sn, 0));
    3293        6556 :             column = 0;
    3294       83832 :         } else if (type == SRC_NEWLINE) {
    3295       32088 :             lineno++;
    3296       32088 :             column = 0;
    3297       51744 :         } else if (type == SRC_COLSPAN) {
    3298       24989 :             ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, 0));
    3299       24989 :             MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
    3300       24989 :             column += colspan;
    3301             :         }
    3302             :     }
    3303             : 
    3304        1053 :     if (columnp)
    3305        1034 :         *columnp = column;
    3306             : 
    3307        1053 :     return lineno;
    3308             : }
    3309             : 
    3310             : unsigned
    3311        1053 : js::PCToLineNumber(JSScript* script, jsbytecode* pc, unsigned* columnp)
    3312             : {
    3313             :     /* Cope with InterpreterFrame.pc value prior to entering Interpret. */
    3314        1053 :     if (!pc)
    3315           0 :         return 0;
    3316             : 
    3317        1053 :     return PCToLineNumber(script->lineno(), script->notes(), script->code(), pc, columnp);
    3318             : }
    3319             : 
    3320             : jsbytecode*
    3321           0 : js::LineNumberToPC(JSScript* script, unsigned target)
    3322             : {
    3323           0 :     ptrdiff_t offset = 0;
    3324           0 :     ptrdiff_t best = -1;
    3325           0 :     unsigned lineno = script->lineno();
    3326           0 :     unsigned bestdiff = SN_MAX_OFFSET;
    3327           0 :     for (jssrcnote* sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
    3328             :         /*
    3329             :          * Exact-match only if offset is not in the prologue; otherwise use
    3330             :          * nearest greater-or-equal line number match.
    3331             :          */
    3332           0 :         if (lineno == target && offset >= ptrdiff_t(script->mainOffset()))
    3333           0 :             goto out;
    3334           0 :         if (lineno >= target) {
    3335           0 :             unsigned diff = lineno - target;
    3336           0 :             if (diff < bestdiff) {
    3337           0 :                 bestdiff = diff;
    3338           0 :                 best = offset;
    3339             :             }
    3340             :         }
    3341           0 :         offset += SN_DELTA(sn);
    3342           0 :         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
    3343           0 :         if (type == SRC_SETLINE) {
    3344           0 :             lineno = unsigned(GetSrcNoteOffset(sn, 0));
    3345           0 :         } else if (type == SRC_NEWLINE) {
    3346           0 :             lineno++;
    3347             :         }
    3348             :     }
    3349           0 :     if (best >= 0)
    3350           0 :         offset = best;
    3351             : out:
    3352           0 :     return script->offsetToPC(offset);
    3353             : }
    3354             : 
    3355             : JS_FRIEND_API(unsigned)
    3356           0 : js::GetScriptLineExtent(JSScript* script)
    3357             : {
    3358           0 :     unsigned lineno = script->lineno();
    3359           0 :     unsigned maxLineNo = lineno;
    3360           0 :     for (jssrcnote* sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
    3361           0 :         SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
    3362           0 :         if (type == SRC_SETLINE)
    3363           0 :             lineno = unsigned(GetSrcNoteOffset(sn, 0));
    3364           0 :         else if (type == SRC_NEWLINE)
    3365           0 :             lineno++;
    3366             : 
    3367           0 :         if (maxLineNo < lineno)
    3368           0 :             maxLineNo = lineno;
    3369             :     }
    3370             : 
    3371           0 :     return 1 + maxLineNo - script->lineno();
    3372             : }
    3373             : 
    3374             : void
    3375           6 : js::DescribeScriptedCallerForCompilation(JSContext* cx, MutableHandleScript maybeScript,
    3376             :                                          const char** file, unsigned* linenop,
    3377             :                                          uint32_t* pcOffset, bool* mutedErrors,
    3378             :                                          LineOption opt)
    3379             : {
    3380           6 :     if (opt == CALLED_FROM_JSOP_EVAL) {
    3381           2 :         jsbytecode* pc = nullptr;
    3382           2 :         maybeScript.set(cx->currentScript(&pc));
    3383             :         static_assert(JSOP_SPREADEVAL_LENGTH == JSOP_STRICTSPREADEVAL_LENGTH,
    3384             :                     "next op after a spread must be at consistent offset");
    3385             :         static_assert(JSOP_EVAL_LENGTH == JSOP_STRICTEVAL_LENGTH,
    3386             :                     "next op after a direct eval must be at consistent offset");
    3387           2 :         MOZ_ASSERT(JSOp(*pc) == JSOP_EVAL || JSOp(*pc) == JSOP_STRICTEVAL ||
    3388             :                    JSOp(*pc) == JSOP_SPREADEVAL || JSOp(*pc) == JSOP_STRICTSPREADEVAL);
    3389             : 
    3390           2 :         bool isSpread = JSOp(*pc) == JSOP_SPREADEVAL || JSOp(*pc) == JSOP_STRICTSPREADEVAL;
    3391           2 :         jsbytecode* nextpc = pc + (isSpread ? JSOP_SPREADEVAL_LENGTH : JSOP_EVAL_LENGTH);
    3392           2 :         MOZ_ASSERT(*nextpc == JSOP_LINENO);
    3393             : 
    3394           2 :         *file = maybeScript->filename();
    3395           2 :         *linenop = GET_UINT32(nextpc);
    3396           2 :         *pcOffset = pc - maybeScript->code();
    3397           2 :         *mutedErrors = maybeScript->mutedErrors();
    3398           2 :         return;
    3399             :     }
    3400             : 
    3401           8 :     NonBuiltinFrameIter iter(cx, cx->compartment()->principals());
    3402             : 
    3403           4 :     if (iter.done()) {
    3404           0 :         maybeScript.set(nullptr);
    3405           0 :         *file = nullptr;
    3406           0 :         *linenop = 0;
    3407           0 :         *pcOffset = 0;
    3408           0 :         *mutedErrors = false;
    3409           0 :         return;
    3410             :     }
    3411             : 
    3412           4 :     *file = iter.filename();
    3413           4 :     *linenop = iter.computeLine();
    3414           4 :     *mutedErrors = iter.mutedErrors();
    3415             : 
    3416             :     // These values are only used for introducer fields which are debugging
    3417             :     // information and can be safely left null for wasm frames.
    3418           4 :     if (iter.hasScript()) {
    3419           4 :         maybeScript.set(iter.script());
    3420           4 :         *pcOffset = iter.pc() - maybeScript->code();
    3421             :     } else {
    3422           0 :         maybeScript.set(nullptr);
    3423           0 :         *pcOffset = 0;
    3424             :     }
    3425             : }
    3426             : 
    3427             : template <class T>
    3428             : static inline T*
    3429       17127 : Rebase(JSScript* dst, JSScript* src, T* srcp)
    3430             : {
    3431       17127 :     size_t off = reinterpret_cast<uint8_t*>(srcp) - src->data;
    3432       17127 :     return reinterpret_cast<T*>(dst->data + off);
    3433             : }
    3434             : 
    3435             : static JSObject*
    3436        7385 : CloneInnerInterpretedFunction(JSContext* cx, HandleScope enclosingScope, HandleFunction srcFun)
    3437             : {
    3438             :     /* NB: Keep this in sync with XDRInterpretedFunction. */
    3439       14770 :     RootedObject cloneProto(cx);
    3440        7385 :     if (srcFun->isStarGenerator() || srcFun->isAsync()) {
    3441         194 :         cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
    3442         194 :         if (!cloneProto)
    3443           0 :             return nullptr;
    3444             :     }
    3445             : 
    3446        7385 :     gc::AllocKind allocKind = srcFun->getAllocKind();
    3447        7385 :     uint16_t flags = srcFun->flags();
    3448        7385 :     if (srcFun->isSelfHostedBuiltin()) {
    3449             :         // Functions in the self-hosting compartment are only extended in
    3450             :         // debug mode. For top-level functions, FUNCTION_EXTENDED gets used by
    3451             :         // the cloning algorithm. Do the same for inner functions here.
    3452          65 :         allocKind = gc::AllocKind::FUNCTION_EXTENDED;
    3453          65 :         flags |= JSFunction::Flags::EXTENDED;
    3454             :     }
    3455       14770 :     RootedAtom atom(cx, srcFun->displayAtom());
    3456        7385 :     if (atom)
    3457        7137 :         cx->markAtom(atom);
    3458       14770 :     RootedFunction clone(cx, NewFunctionWithProto(cx, nullptr, srcFun->nargs(),
    3459             :                                                   JSFunction::Flags(flags), nullptr, atom,
    3460       14770 :                                                   cloneProto, allocKind, TenuredObject));
    3461        7385 :     if (!clone)
    3462           0 :         return nullptr;
    3463             : 
    3464       14770 :     JSScript::AutoDelazify srcScript(cx, srcFun);
    3465        7385 :     if (!srcScript)
    3466           0 :         return nullptr;
    3467        7385 :     JSScript* cloneScript = CloneScriptIntoFunction(cx, enclosingScope, clone, srcScript);
    3468        7385 :     if (!cloneScript)
    3469           0 :         return nullptr;
    3470             : 
    3471        7385 :     if (!JSFunction::setTypeForScriptedFunction(cx, clone))
    3472           0 :         return nullptr;
    3473             : 
    3474        7385 :     return clone;
    3475             : }
    3476             : 
    3477             : bool
    3478        9632 : js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
    3479             :                        MutableHandle<GCVector<Scope*>> scopes)
    3480             : {
    3481        9632 :     if (src->treatAsRunOnce() && !src->functionNonDelazifying()) {
    3482           0 :         JS_ReportErrorASCII(cx, "No cloning toplevel run-once scripts");
    3483           0 :         return false;
    3484             :     }
    3485             : 
    3486             :     /* NB: Keep this in sync with XDRScript. */
    3487             : 
    3488             :     /* Some embeddings are not careful to use ExposeObjectToActiveJS as needed. */
    3489        9632 :     MOZ_ASSERT(!src->sourceObject()->isMarkedGray());
    3490             : 
    3491        9632 :     uint32_t nconsts   = src->hasConsts()   ? src->consts()->length   : 0;
    3492        9632 :     uint32_t nobjects  = src->hasObjects()  ? src->objects()->length  : 0;
    3493        9632 :     uint32_t nscopes   = src->scopes()->length;
    3494        9632 :     uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
    3495        9632 :     uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes()->length : 0;
    3496        9632 :     uint32_t nyieldoffsets = src->hasYieldAndAwaitOffsets() ? src->yieldAndAwaitOffsets().length() : 0;
    3497             : 
    3498             :     /* Script data */
    3499             : 
    3500        9632 :     size_t size = src->dataSize();
    3501       19264 :     ScopedJSFreePtr<uint8_t> data(AllocScriptData(cx->zone(), size));
    3502        9632 :     if (size && !data) {
    3503           0 :         ReportOutOfMemory(cx);
    3504           0 :         return false;
    3505             :     }
    3506             : 
    3507             :     /* Scopes */
    3508             : 
    3509             :     // The passed in scopes vector contains body scopes that needed to be
    3510             :     // cloned especially, depending on whether the script is a function or
    3511             :     // global scope. Starting at scopes.length() means we only deal with
    3512             :     // intra-body scopes.
    3513             :     {
    3514        9632 :         MOZ_ASSERT(nscopes != 0);
    3515        9632 :         MOZ_ASSERT(src->bodyScopeIndex() + 1 == scopes.length());
    3516        9632 :         GCPtrScope* vector = src->scopes()->vector;
    3517       19264 :         RootedScope original(cx);
    3518       19264 :         RootedScope clone(cx);
    3519       15029 :         for (uint32_t i = scopes.length(); i < nscopes; i++) {
    3520        5397 :             original = vector[i];
    3521        5397 :             clone = Scope::clone(cx, original, scopes[FindScopeIndex(src, *original->enclosing())]);
    3522        5397 :             if (!clone || !scopes.append(clone))
    3523           0 :                 return false;
    3524             :         }
    3525             :     }
    3526             : 
    3527             :     /* Objects */
    3528             : 
    3529       19264 :     AutoObjectVector objects(cx);
    3530        9632 :     if (nobjects != 0) {
    3531        2520 :         GCPtrObject* vector = src->objects()->vector;
    3532        5040 :         RootedObject obj(cx);
    3533        5040 :         RootedObject clone(cx);
    3534       13098 :         for (unsigned i = 0; i < nobjects; i++) {
    3535       10578 :             obj = vector[i];
    3536       10578 :             clone = nullptr;
    3537       10578 :             if (obj->is<RegExpObject>()) {
    3538         255 :                 clone = CloneScriptRegExpObject(cx, obj->as<RegExpObject>());
    3539       10323 :             } else if (obj->is<JSFunction>()) {
    3540       14770 :                 RootedFunction innerFun(cx, &obj->as<JSFunction>());
    3541        7385 :                 if (innerFun->isNative()) {
    3542           0 :                     if (cx->compartment() != innerFun->compartment()) {
    3543           0 :                         MOZ_ASSERT(innerFun->isAsmJSNative());
    3544           0 :                         JS_ReportErrorASCII(cx, "AsmJS modules do not yet support cloning.");
    3545           0 :                         return false;
    3546             :                     }
    3547           0 :                     clone = innerFun;
    3548             :                 } else {
    3549        7385 :                     if (innerFun->isInterpretedLazy()) {
    3550        2218 :                         AutoCompartment ac(cx, innerFun);
    3551        1109 :                         if (!JSFunction::getOrCreateScript(cx, innerFun))
    3552           0 :                             return false;
    3553             :                     }
    3554             : 
    3555        7385 :                     Scope* enclosing = innerFun->nonLazyScript()->enclosingScope();
    3556       14770 :                     RootedScope enclosingClone(cx, scopes[FindScopeIndex(src, *enclosing)]);
    3557        7385 :                     clone = CloneInnerInterpretedFunction(cx, enclosingClone, innerFun);
    3558             :                 }
    3559             :             } else {
    3560        2938 :                 clone = DeepCloneObjectLiteral(cx, obj, TenuredObject);
    3561             :             }
    3562             : 
    3563       10578 :             if (!clone || !objects.append(clone))
    3564           0 :                 return false;
    3565             :         }
    3566             :     }
    3567             : 
    3568             :     /* This assignment must occur before all the Rebase calls. */
    3569        9632 :     dst->data = data.forget();
    3570        9632 :     dst->dataSize_ = size;
    3571        9632 :     MOZ_ASSERT(bool(dst->data) == bool(src->data));
    3572        9632 :     if (dst->data)
    3573        9632 :         memcpy(dst->data, src->data, size);
    3574             : 
    3575        9632 :     if (cx->zone() != src->zoneFromAnyThread()) {
    3576       44144 :         for (size_t i = 0; i < src->scriptData()->natoms(); i++)
    3577       39737 :             cx->markAtom(src->scriptData()->atoms()[i]);
    3578             :     }
    3579             : 
    3580             :     /* Script filenames, bytecodes and atoms are runtime-wide. */
    3581        9632 :     dst->setScriptData(src->scriptData());
    3582             : 
    3583        9632 :     dst->lineno_ = src->lineno();
    3584        9632 :     dst->mainOffset_ = src->mainOffset();
    3585        9632 :     dst->nfixed_ = src->nfixed();
    3586        9632 :     dst->nslots_ = src->nslots();
    3587        9632 :     dst->bodyScopeIndex_ = src->bodyScopeIndex_;
    3588        9632 :     dst->funLength_ = src->funLength();
    3589        9632 :     dst->nTypeSets_ = src->nTypeSets();
    3590        9632 :     if (src->argumentsHasVarBinding()) {
    3591         212 :         dst->setArgumentsHasVarBinding();
    3592         212 :         if (src->analyzedArgsUsage())
    3593           6 :             dst->setNeedsArgsObj(src->needsArgsObj());
    3594             :     }
    3595        9632 :     dst->hasMappedArgsObj_ = src->hasMappedArgsObj();
    3596        9632 :     dst->functionHasThisBinding_ = src->functionHasThisBinding();
    3597        9632 :     dst->functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope();
    3598        9632 :     dst->cloneHasArray(src);
    3599        9632 :     dst->strict_ = src->strict();
    3600        9632 :     dst->explicitUseStrict_ = src->explicitUseStrict();
    3601        9632 :     dst->hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic);
    3602        9632 :     dst->bindingsAccessedDynamically_ = src->bindingsAccessedDynamically();
    3603        9632 :     dst->funHasExtensibleScope_ = src->funHasExtensibleScope();
    3604        9632 :     dst->funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal();
    3605        9632 :     dst->hasSingletons_ = src->hasSingletons();
    3606        9632 :     dst->treatAsRunOnce_ = src->treatAsRunOnce();
    3607        9632 :     dst->hasInnerFunctions_ = src->hasInnerFunctions();
    3608        9632 :     dst->isGeneratorExp_ = src->isGeneratorExp();
    3609        9632 :     dst->setGeneratorKind(src->generatorKind());
    3610        9632 :     dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
    3611        9632 :     dst->needsHomeObject_ = src->needsHomeObject();
    3612        9632 :     dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
    3613        9632 :     dst->isAsync_ = src->asyncKind() == AsyncFunction;
    3614        9632 :     dst->hasRest_ = src->hasRest_;
    3615        9632 :     dst->isExprBody_ = src->isExprBody_;
    3616             : 
    3617        9632 :     if (nconsts != 0) {
    3618         143 :         GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
    3619         143 :         dst->consts()->vector = vector;
    3620         313 :         for (unsigned i = 0; i < nconsts; ++i)
    3621         170 :             MOZ_ASSERT_IF(vector[i].isGCThing(), vector[i].toString()->isAtom());
    3622             :     }
    3623        9632 :     if (nobjects != 0) {
    3624        2520 :         GCPtrObject* vector = Rebase<GCPtrObject>(dst, src, src->objects()->vector);
    3625        2520 :         dst->objects()->vector = vector;
    3626       13098 :         for (unsigned i = 0; i < nobjects; ++i)
    3627       10578 :             vector[i].init(&objects[i]->as<NativeObject>());
    3628             :     }
    3629             :     {
    3630        9632 :         GCPtrScope* vector = Rebase<GCPtrScope>(dst, src, src->scopes()->vector);
    3631        9632 :         dst->scopes()->vector = vector;
    3632       25708 :         for (uint32_t i = 0; i < nscopes; ++i)
    3633       16076 :             vector[i].init(scopes[i]);
    3634             :     }
    3635        9632 :     if (ntrynotes != 0)
    3636        1484 :         dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
    3637        9632 :     if (nscopenotes != 0)
    3638        3154 :         dst->scopeNotes()->vector = Rebase<ScopeNote>(dst, src, src->scopeNotes()->vector);
    3639        9632 :     if (nyieldoffsets != 0) {
    3640         388 :         dst->yieldAndAwaitOffsets().vector_ =
    3641         194 :             Rebase<uint32_t>(dst, src, src->yieldAndAwaitOffsets().vector_);
    3642             :     }
    3643             : 
    3644             :     /*
    3645             :      * Function delazification assumes that their script does not have a
    3646             :      * non-syntactic global scope.  We ensure that as follows:
    3647             :      *
    3648             :      * 1) Initial parsing only creates lazy functions if
    3649             :      *    !hasNonSyntacticScope.
    3650             :      * 2) Cloning a lazy function into a non-global scope will always require
    3651             :      *    that its script be cloned.  See comments in
    3652             :      *    CloneFunctionObjectUseSameScript.
    3653             :      * 3) Cloning a script never sets a lazyScript on the clone, so the function
    3654             :      *    cannot be relazified.
    3655             :      *
    3656             :      * If you decide that lazy functions should be supported with a
    3657             :      * non-syntactic global scope, make sure delazification can deal.
    3658             :      */
    3659        9632 :     MOZ_ASSERT_IF(dst->hasNonSyntacticScope(), !dst->maybeLazyScript());
    3660        9632 :     MOZ_ASSERT_IF(dst->hasNonSyntacticScope(), !dst->isRelazifiable());
    3661        9632 :     return true;
    3662             : }
    3663             : 
    3664             : static JSScript*
    3665        9633 : CreateEmptyScriptForClone(JSContext* cx, HandleScript src)
    3666             : {
    3667             :     /*
    3668             :      * Wrap the script source object as needed. Self-hosted scripts may be
    3669             :      * in another runtime, so lazily create a new script source object to
    3670             :      * use for them.
    3671             :      */
    3672       19265 :     RootedObject sourceObject(cx);
    3673        9633 :     if (cx->runtime()->isSelfHostingCompartment(src->compartment())) {
    3674        1138 :         if (!cx->compartment()->selfHostingScriptSource) {
    3675         282 :             CompileOptions options(cx);
    3676         141 :             FillSelfHostingCompileOptions(options);
    3677             : 
    3678         141 :             ScriptSourceObject* obj = frontend::CreateScriptSourceObject(cx, options);
    3679         141 :             if (!obj)
    3680           0 :                 return nullptr;
    3681         141 :             cx->compartment()->selfHostingScriptSource.set(obj);
    3682             :         }
    3683        1138 :         sourceObject = cx->compartment()->selfHostingScriptSource;
    3684             :     } else {
    3685        8495 :         sourceObject = src->sourceObject();
    3686        8495 :         if (!cx->compartment()->wrap(cx, &sourceObject))
    3687           0 :             return nullptr;
    3688             :     }
    3689             : 
    3690       19264 :     CompileOptions options(cx);
    3691        9632 :     options.setMutedErrors(src->mutedErrors())
    3692       19264 :            .setSelfHostingMode(src->selfHosted())
    3693       19264 :            .setNoScriptRval(src->noScriptRval())
    3694       19264 :            .setVersion(src->getVersion());
    3695             : 
    3696       28896 :     return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd(),
    3697       28896 :                             src->toStringStart(), src->toStringEnd());
    3698             : }
    3699             : 
    3700             : JSScript*
    3701         229 : js::CloneGlobalScript(JSContext* cx, ScopeKind scopeKind, HandleScript src)
    3702             : {
    3703         229 :     MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
    3704             : 
    3705         457 :     RootedScript dst(cx, CreateEmptyScriptForClone(cx, src));
    3706         228 :     if (!dst)
    3707           0 :         return nullptr;
    3708             : 
    3709         228 :     MOZ_ASSERT(src->bodyScopeIndex() == 0);
    3710         456 :     Rooted<GCVector<Scope*>> scopes(cx, GCVector<Scope*>(cx));
    3711         456 :     Rooted<GlobalScope*> original(cx, &src->bodyScope()->as<GlobalScope>());
    3712         228 :     GlobalScope* clone = GlobalScope::clone(cx, original, scopeKind);
    3713         228 :     if (!clone || !scopes.append(clone))
    3714           0 :         return nullptr;
    3715             : 
    3716         228 :     if (!detail::CopyScript(cx, src, dst, &scopes))
    3717           0 :         return nullptr;
    3718             : 
    3719         228 :     return dst;
    3720             : }
    3721             : 
    3722             : JSScript*
    3723        9404 : js::CloneScriptIntoFunction(JSContext* cx, HandleScope enclosingScope, HandleFunction fun,
    3724             :                             HandleScript src)
    3725             : {
    3726        9404 :     MOZ_ASSERT(fun->isInterpreted());
    3727        9404 :     MOZ_ASSERT(!fun->hasScript() || fun->hasUncompiledScript());
    3728             : 
    3729       18808 :     RootedScript dst(cx, CreateEmptyScriptForClone(cx, src));
    3730        9404 :     if (!dst)
    3731           0 :         return nullptr;
    3732             : 
    3733             :     // Clone the non-intra-body scopes.
    3734       18808 :     Rooted<GCVector<Scope*>> scopes(cx, GCVector<Scope*>(cx));
    3735       18808 :     RootedScope original(cx);
    3736       18808 :     RootedScope enclosingClone(cx);
    3737       19855 :     for (uint32_t i = 0; i <= src->bodyScopeIndex(); i++) {
    3738       10451 :         original = src->getScope(i);
    3739             : 
    3740       10451 :         if (i == 0) {
    3741        9404 :             enclosingClone = enclosingScope;
    3742             :         } else {
    3743        1047 :             MOZ_ASSERT(src->getScope(i - 1) == original->enclosing());
    3744        1047 :             enclosingClone = scopes[i - 1];
    3745             :         }
    3746             : 
    3747             :         Scope* clone;
    3748       10451 :         if (original->is<FunctionScope>())
    3749        9404 :             clone = FunctionScope::clone(cx, original.as<FunctionScope>(), fun, enclosingClone);
    3750             :         else
    3751        1047 :             clone = Scope::clone(cx, original, enclosingClone);
    3752             : 
    3753       10451 :         if (!clone || !scopes.append(clone))
    3754           0 :             return nullptr;
    3755             :     }
    3756             : 
    3757             :     // Save flags in case we need to undo the early mutations.
    3758        9404 :     const int preservedFlags = fun->flags();
    3759        9404 :     if (!detail::CopyScript(cx, src, dst, &scopes)) {
    3760           0 :         fun->setFlags(preservedFlags);
    3761           0 :         return nullptr;
    3762             :     }
    3763             : 
    3764             :     // Finally set the script after all the fallible operations.
    3765        9404 :     if (fun->isInterpretedLazy())
    3766         556 :         fun->setUnlazifiedScript(dst);
    3767             :     else
    3768        8848 :         fun->initScript(dst);
    3769             : 
    3770        9404 :     return dst;
    3771             : }
    3772             : 
    3773             : DebugScript*
    3774           0 : JSScript::debugScript()
    3775             : {
    3776           0 :     MOZ_ASSERT(hasDebugScript_);
    3777           0 :     DebugScriptMap* map = compartment()->debugScriptMap;
    3778           0 :     MOZ_ASSERT(map);
    3779           0 :     DebugScriptMap::Ptr p = map->lookup(this);
    3780           0 :     MOZ_ASSERT(p);
    3781           0 :     return p->value();
    3782             : }
    3783             : 
    3784             : DebugScript*
    3785           0 : JSScript::releaseDebugScript()
    3786             : {
    3787           0 :     MOZ_ASSERT(hasDebugScript_);
    3788           0 :     DebugScriptMap* map = compartment()->debugScriptMap;
    3789           0 :     MOZ_ASSERT(map);
    3790           0 :     DebugScriptMap::Ptr p = map->lookup(this);
    3791           0 :     MOZ_ASSERT(p);
    3792           0 :     DebugScript* debug = p->value();
    3793           0 :     map->remove(p);
    3794           0 :     hasDebugScript_ = false;
    3795           0 :     return debug;
    3796             : }
    3797             : 
    3798             : void
    3799           0 : JSScript::destroyDebugScript(FreeOp* fop)
    3800             : {
    3801           0 :     if (hasDebugScript_) {
    3802             : #ifdef DEBUG
    3803           0 :         for (jsbytecode* pc = code(); pc < codeEnd(); pc++) {
    3804           0 :             if (BreakpointSite* site = getBreakpointSite(pc)) {
    3805             :                 /* Breakpoints are swept before finalization. */
    3806           0 :                 MOZ_ASSERT(site->firstBreakpoint() == nullptr);
    3807           0 :                 MOZ_ASSERT(getBreakpointSite(pc) == nullptr);
    3808             :             }
    3809             :         }
    3810             : #endif
    3811           0 :         fop->free_(releaseDebugScript());
    3812             :     }
    3813           0 : }
    3814             : 
    3815             : bool
    3816           0 : JSScript::ensureHasDebugScript(JSContext* cx)
    3817             : {
    3818           0 :     if (hasDebugScript_)
    3819           0 :         return true;
    3820             : 
    3821           0 :     size_t nbytes = offsetof(DebugScript, breakpoints) + length() * sizeof(BreakpointSite*);
    3822           0 :     DebugScript* debug = (DebugScript*) zone()->pod_calloc<uint8_t>(nbytes);
    3823           0 :     if (!debug)
    3824           0 :         return false;
    3825             : 
    3826             :     /* Create compartment's debugScriptMap if necessary. */
    3827           0 :     DebugScriptMap* map = compartment()->debugScriptMap;
    3828           0 :     if (!map) {
    3829           0 :         map = cx->new_<DebugScriptMap>();
    3830           0 :         if (!map || !map->init()) {
    3831           0 :             js_free(debug);
    3832           0 :             js_delete(map);
    3833           0 :             return false;
    3834             :         }
    3835           0 :         compartment()->debugScriptMap = map;
    3836             :     }
    3837             : 
    3838           0 :     if (!map->putNew(this, debug)) {
    3839           0 :         js_free(debug);
    3840           0 :         return false;
    3841             :     }
    3842           0 :     hasDebugScript_ = true; // safe to set this;  we can't fail after this point
    3843             : 
    3844             :     /*
    3845             :      * Ensure that any Interpret() instances running on this script have
    3846             :      * interrupts enabled. The interrupts must stay enabled until the
    3847             :      * debug state is destroyed.
    3848             :      */
    3849           0 :     for (ActivationIterator iter(cx); !iter.done(); ++iter) {
    3850           0 :         if (iter->isInterpreter())
    3851           0 :             iter->asInterpreter()->enableInterruptsIfRunning(this);
    3852             :     }
    3853             : 
    3854           0 :     return true;
    3855             : }
    3856             : 
    3857             : void
    3858           0 : JSScript::setNewStepMode(FreeOp* fop, uint32_t newValue)
    3859             : {
    3860           0 :     DebugScript* debug = debugScript();
    3861           0 :     uint32_t prior = debug->stepMode;
    3862           0 :     debug->stepMode = newValue;
    3863             : 
    3864           0 :     if (!prior != !newValue) {
    3865           0 :         if (hasBaselineScript())
    3866           0 :             baseline->toggleDebugTraps(this, nullptr);
    3867             : 
    3868           0 :         if (!stepModeEnabled() && !debug->numSites)
    3869           0 :             fop->free_(releaseDebugScript());
    3870             :     }
    3871           0 : }
    3872             : 
    3873             : bool
    3874           0 : JSScript::incrementStepModeCount(JSContext* cx)
    3875             : {
    3876           0 :     assertSameCompartment(cx, this);
    3877           0 :     MOZ_ASSERT(cx->compartment()->isDebuggee());
    3878             : 
    3879           0 :     if (!ensureHasDebugScript(cx))
    3880           0 :         return false;
    3881             : 
    3882           0 :     DebugScript* debug = debugScript();
    3883           0 :     uint32_t count = debug->stepMode;
    3884           0 :     setNewStepMode(cx->runtime()->defaultFreeOp(), count + 1);
    3885           0 :     return true;
    3886             : }
    3887             : 
    3888             : void
    3889           0 : JSScript::decrementStepModeCount(FreeOp* fop)
    3890             : {
    3891           0 :     DebugScript* debug = debugScript();
    3892           0 :     uint32_t count = debug->stepMode;
    3893           0 :     MOZ_ASSERT(count > 0);
    3894           0 :     setNewStepMode(fop, count - 1);
    3895           0 : }
    3896             : 
    3897             : BreakpointSite*
    3898           0 : JSScript::getOrCreateBreakpointSite(JSContext* cx, jsbytecode* pc)
    3899             : {
    3900           0 :     if (!ensureHasDebugScript(cx))
    3901           0 :         return nullptr;
    3902             : 
    3903           0 :     DebugScript* debug = debugScript();
    3904           0 :     BreakpointSite*& site = debug->breakpoints[pcToOffset(pc)];
    3905             : 
    3906           0 :     if (!site) {
    3907           0 :         site = cx->runtime()->new_<JSBreakpointSite>(this, pc);
    3908           0 :         if (!site) {
    3909           0 :             ReportOutOfMemory(cx);
    3910           0 :             return nullptr;
    3911             :         }
    3912           0 :         debug->numSites++;
    3913             :     }
    3914             : 
    3915           0 :     return site;
    3916             : }
    3917             : 
    3918             : void
    3919           0 : JSScript::destroyBreakpointSite(FreeOp* fop, jsbytecode* pc)
    3920             : {
    3921           0 :     DebugScript* debug = debugScript();
    3922           0 :     BreakpointSite*& site = debug->breakpoints[pcToOffset(pc)];
    3923           0 :     MOZ_ASSERT(site);
    3924             : 
    3925           0 :     fop->delete_(site);
    3926           0 :     site = nullptr;
    3927             : 
    3928           0 :     if (--debug->numSites == 0 && !stepModeEnabled())
    3929           0 :         fop->free_(releaseDebugScript());
    3930           0 : }
    3931             : 
    3932             : void
    3933           0 : JSScript::clearBreakpointsIn(FreeOp* fop, js::Debugger* dbg, JSObject* handler)
    3934             : {
    3935           0 :     if (!hasAnyBreakpointsOrStepMode())
    3936           0 :         return;
    3937             : 
    3938           0 :     for (jsbytecode* pc = code(); pc < codeEnd(); pc++) {
    3939           0 :         BreakpointSite* site = getBreakpointSite(pc);
    3940           0 :         if (site) {
    3941             :             Breakpoint* nextbp;
    3942           0 :             for (Breakpoint* bp = site->firstBreakpoint(); bp; bp = nextbp) {
    3943           0 :                 nextbp = bp->nextInSite();
    3944           0 :                 if ((!dbg || bp->debugger == dbg) && (!handler || bp->getHandler() == handler))
    3945           0 :                     bp->destroy(fop);
    3946             :             }
    3947             :         }
    3948             :     }
    3949             : }
    3950             : 
    3951             : bool
    3952           0 : JSScript::hasBreakpointsAt(jsbytecode* pc)
    3953             : {
    3954           0 :     BreakpointSite* site = getBreakpointSite(pc);
    3955           0 :     if (!site)
    3956           0 :         return false;
    3957             : 
    3958           0 :     return site->enabledCount > 0;
    3959             : }
    3960             : 
    3961             : void
    3962         299 : SharedScriptData::traceChildren(JSTracer* trc)
    3963             : {
    3964         299 :     MOZ_ASSERT(refCount() != 0);
    3965        2452 :     for (uint32_t i = 0; i < natoms(); ++i)
    3966        2153 :         TraceNullableEdge(trc, &atoms()[i], "atom");
    3967         299 : }
    3968             : 
    3969             : void
    3970         299 : JSScript::traceChildren(JSTracer* trc)
    3971             : {
    3972             :     // NOTE: this JSScript may be partially initialized at this point.  E.g. we
    3973             :     // may have created it and partially initialized it with
    3974             :     // JSScript::Create(), but not yet finished initializing it with
    3975             :     // fullyInitFromEmitter() or fullyInitTrivial().
    3976             : 
    3977         299 :     MOZ_ASSERT_IF(trc->isMarkingTracer() &&
    3978             :                   GCMarker::fromTracer(trc)->shouldCheckCompartments(),
    3979             :                   zone()->isCollecting());
    3980             : 
    3981         299 :     if (scriptData())
    3982         299 :         scriptData()->traceChildren(trc);
    3983             : 
    3984         299 :     if (ScopeArray* scopearray = scopes())
    3985         299 :         TraceRange(trc, scopearray->length, scopearray->vector, "scopes");
    3986             : 
    3987         299 :     if (hasConsts()) {
    3988           0 :         ConstArray* constarray = consts();
    3989           0 :         TraceRange(trc, constarray->length, constarray->vector, "consts");
    3990             :     }
    3991             : 
    3992         299 :     if (hasObjects()) {
    3993          67 :         ObjectArray* objarray = objects();
    3994          67 :         TraceRange(trc, objarray->length, objarray->vector, "objects");
    3995             :     }
    3996             : 
    3997         299 :     MOZ_ASSERT_IF(sourceObject(), MaybeForwarded(sourceObject())->compartment() == compartment());
    3998         299 :     TraceNullableEdge(trc, &sourceObject_, "sourceObject");
    3999             : 
    4000         299 :     if (maybeLazyScript())
    4001          87 :         TraceManuallyBarrieredEdge(trc, &lazyScript, "lazyScript");
    4002             : 
    4003         299 :     if (trc->isMarkingTracer())
    4004         299 :         compartment()->mark();
    4005             : 
    4006         299 :     jit::TraceJitScripts(trc, this);
    4007         299 : }
    4008             : 
    4009             : void
    4010           0 : LazyScript::finalize(FreeOp* fop)
    4011             : {
    4012           0 :     fop->free_(table_);
    4013           0 : }
    4014             : 
    4015             : size_t
    4016         132 : JSScript::calculateLiveFixed(jsbytecode* pc)
    4017             : {
    4018         132 :     size_t nlivefixed = numAlwaysLiveFixedSlots();
    4019             : 
    4020         132 :     if (nfixed() != nlivefixed) {
    4021          69 :         Scope* scope = lookupScope(pc);
    4022          69 :         if (scope)
    4023          45 :             scope = MaybeForwarded(scope);
    4024             : 
    4025             :         // Find the nearest LexicalScope in the same script.
    4026          69 :         while (scope && scope->is<WithScope>()) {
    4027           0 :             scope = scope->enclosing();
    4028           0 :             if (scope)
    4029           0 :                 scope = MaybeForwarded(scope);
    4030             :         }
    4031             : 
    4032          69 :         if (scope) {
    4033          45 :             if (scope->is<LexicalScope>())
    4034          45 :                 nlivefixed = scope->as<LexicalScope>().nextFrameSlot();
    4035           0 :             else if (scope->is<VarScope>())
    4036           0 :                 nlivefixed = scope->as<VarScope>().nextFrameSlot();
    4037             :         }
    4038             :     }
    4039             : 
    4040         132 :     MOZ_ASSERT(nlivefixed <= nfixed());
    4041         132 :     MOZ_ASSERT(nlivefixed >= numAlwaysLiveFixedSlots());
    4042             : 
    4043         132 :     return nlivefixed;
    4044             : }
    4045             : 
    4046             : Scope*
    4047       27011 : JSScript::lookupScope(jsbytecode* pc)
    4048             : {
    4049       27011 :     MOZ_ASSERT(containsPC(pc));
    4050             : 
    4051       27011 :     if (!hasScopeNotes())
    4052       12262 :         return nullptr;
    4053             : 
    4054       14749 :     size_t offset = pc - code();
    4055             : 
    4056       14749 :     ScopeNoteArray* notes = scopeNotes();
    4057       14749 :     Scope* scope = nullptr;
    4058             : 
    4059             :     // Find the innermost block chain using a binary search.
    4060       14749 :     size_t bottom = 0;
    4061       14749 :     size_t top = notes->length;
    4062             : 
    4063       72945 :     while (bottom < top) {
    4064       29098 :         size_t mid = bottom + (top - bottom) / 2;
    4065       29098 :         const ScopeNote* note = &notes->vector[mid];
    4066       29098 :         if (note->start <= offset) {
    4067             :             // Block scopes are ordered in the list by their starting offset, and since
    4068             :             // blocks form a tree ones earlier in the list may cover the pc even if
    4069             :             // later blocks end before the pc. This only happens when the earlier block
    4070             :             // is a parent of the later block, so we need to check parents of |mid| in
    4071             :             // the searched range for coverage.
    4072       13769 :             size_t check = mid;
    4073       28687 :             while (check >= bottom) {
    4074       19491 :                 const ScopeNote* checkNote = &notes->vector[check];
    4075       19491 :                 MOZ_ASSERT(checkNote->start <= offset);
    4076       19491 :                 if (offset < checkNote->start + checkNote->length) {
    4077             :                     // We found a matching block chain but there may be inner ones
    4078             :                     // at a higher block chain index than mid. Continue the binary search.
    4079       10561 :                     if (checkNote->index == ScopeNote::NoScopeIndex)
    4080           0 :                         scope = nullptr;
    4081             :                     else
    4082       10561 :                         scope = getScope(checkNote->index);
    4083       10561 :                     break;
    4084             :                 }
    4085        8930 :                 if (checkNote->parent == UINT32_MAX)
    4086        1471 :                     break;
    4087        7459 :                 check = checkNote->parent;
    4088             :             }
    4089       13769 :             bottom = mid + 1;
    4090             :         } else {
    4091       15329 :             top = mid;
    4092             :         }
    4093             :     }
    4094             : 
    4095       14749 :     return scope;
    4096             : }
    4097             : 
    4098             : Scope*
    4099       20107 : JSScript::innermostScope(jsbytecode* pc)
    4100             : {
    4101       20107 :     if (Scope* scope = lookupScope(pc))
    4102        2353 :         return scope;
    4103       17754 :     return bodyScope();
    4104             : }
    4105             : 
    4106             : void
    4107         532 : JSScript::setArgumentsHasVarBinding()
    4108             : {
    4109         532 :     argsHasVarBinding_ = true;
    4110         532 :     needsArgsAnalysis_ = true;
    4111         532 : }
    4112             : 
    4113             : void
    4114         273 : JSScript::setNeedsArgsObj(bool needsArgsObj)
    4115             : {
    4116         273 :     MOZ_ASSERT_IF(needsArgsObj, argumentsHasVarBinding());
    4117         273 :     needsArgsAnalysis_ = false;
    4118         273 :     needsArgsObj_ = needsArgsObj;
    4119         273 : }
    4120             : 
    4121             : void
    4122           0 : js::SetFrameArgumentsObject(JSContext* cx, AbstractFramePtr frame,
    4123             :                             HandleScript script, JSObject* argsobj)
    4124             : {
    4125             :     /*
    4126             :      * Replace any optimized arguments in the frame with an explicit arguments
    4127             :      * object. Note that 'arguments' may have already been overwritten.
    4128             :      */
    4129             : 
    4130           0 :     Rooted<BindingIter> bi(cx, BindingIter(script));
    4131           0 :     while (bi && bi.name() != cx->names().arguments)
    4132           0 :         bi++;
    4133           0 :     if (!bi)
    4134           0 :         return;
    4135             : 
    4136           0 :     if (bi.location().kind() == BindingLocation::Kind::Environment) {
    4137             :         /*
    4138             :          * Scan the script to find the slot in the call object that 'arguments'
    4139             :          * is assigned to.
    4140             :          */
    4141           0 :         jsbytecode* pc = script->code();
    4142           0 :         while (*pc != JSOP_ARGUMENTS)
    4143           0 :             pc += GetBytecodeLength(pc);
    4144           0 :         pc += JSOP_ARGUMENTS_LENGTH;
    4145           0 :         MOZ_ASSERT(*pc == JSOP_SETALIASEDVAR);
    4146             : 
    4147             :         // Note that here and below, it is insufficient to only check for
    4148             :         // JS_OPTIMIZED_ARGUMENTS, as Ion could have optimized out the
    4149             :         // arguments slot.
    4150           0 :         EnvironmentObject& env = frame.callObj().as<EnvironmentObject>();
    4151           0 :         if (IsOptimizedPlaceholderMagicValue(env.aliasedBinding(bi)))
    4152           0 :             env.setAliasedBinding(cx, bi, ObjectValue(*argsobj));
    4153             :     } else {
    4154           0 :         MOZ_ASSERT(bi.location().kind() == BindingLocation::Kind::Frame);
    4155           0 :         uint32_t frameSlot = bi.location().slot();
    4156           0 :         if (IsOptimizedPlaceholderMagicValue(frame.unaliasedLocal(frameSlot)))
    4157           0 :             frame.unaliasedLocal(frameSlot) = ObjectValue(*argsobj);
    4158             :     }
    4159             : }
    4160             : 
    4161             : /* static */ bool
    4162           0 : JSScript::argumentsOptimizationFailed(JSContext* cx, HandleScript script)
    4163             : {
    4164           0 :     MOZ_ASSERT(script->functionNonDelazifying());
    4165           0 :     MOZ_ASSERT(script->analyzedArgsUsage());
    4166           0 :     MOZ_ASSERT(script->argumentsHasVarBinding());
    4167             : 
    4168             :     /*
    4169             :      * It is possible that the arguments optimization has already failed,
    4170             :      * everything has been fixed up, but there was an outstanding magic value
    4171             :      * on the stack that has just now flowed into an apply. In this case, there
    4172             :      * is nothing to do; GuardFunApplySpeculation will patch in the real
    4173             :      * argsobj.
    4174             :      */
    4175           0 :     if (script->needsArgsObj())
    4176           0 :         return true;
    4177             : 
    4178           0 :     MOZ_ASSERT(!script->isStarGenerator());
    4179           0 :     MOZ_ASSERT(!script->isLegacyGenerator());
    4180           0 :     MOZ_ASSERT(!script->isAsync());
    4181             : 
    4182           0 :     script->needsArgsObj_ = true;
    4183             : 
    4184             :     /*
    4185             :      * Since we can't invalidate baseline scripts, set a flag that's checked from
    4186             :      * JIT code to indicate the arguments optimization failed and JSOP_ARGUMENTS
    4187             :      * should create an arguments object next time.
    4188             :      */
    4189           0 :     if (script->hasBaselineScript())
    4190           0 :         script->baselineScript()->setNeedsArgsObj();
    4191             : 
    4192             :     /*
    4193             :      * By design, the arguments optimization is only made when there are no
    4194             :      * outstanding cases of MagicValue(JS_OPTIMIZED_ARGUMENTS) at any points
    4195             :      * where the optimization could fail, other than an active invocation of
    4196             :      * 'f.apply(x, arguments)'. Thus, there are no outstanding values of
    4197             :      * MagicValue(JS_OPTIMIZED_ARGUMENTS) on the stack. However, there are
    4198             :      * three things that need fixup:
    4199             :      *  - there may be any number of activations of this script that don't have
    4200             :      *    an argsObj that now need one.
    4201             :      *  - jit code compiled (and possible active on the stack) with the static
    4202             :      *    assumption of !script->needsArgsObj();
    4203             :      *  - type inference data for the script assuming script->needsArgsObj
    4204             :      */
    4205           0 :     for (AllScriptFramesIter i(cx); !i.done(); ++i) {
    4206             :         /*
    4207             :          * We cannot reliably create an arguments object for Ion activations of
    4208             :          * this script.  To maintain the invariant that "script->needsArgsObj
    4209             :          * implies fp->hasArgsObj", the Ion bail mechanism will create an
    4210             :          * arguments object right after restoring the BaselineFrame and before
    4211             :          * entering Baseline code (in jit::FinishBailoutToBaseline).
    4212             :          */
    4213           0 :         if (i.isIon())
    4214           0 :             continue;
    4215           0 :         AbstractFramePtr frame = i.abstractFramePtr();
    4216           0 :         if (frame.isFunctionFrame() && frame.script() == script) {
    4217             :             /* We crash on OOM since cleaning up here would be complicated. */
    4218           0 :             AutoEnterOOMUnsafeRegion oomUnsafe;
    4219           0 :             ArgumentsObject* argsobj = ArgumentsObject::createExpected(cx, frame);
    4220           0 :             if (!argsobj)
    4221           0 :                 oomUnsafe.crash("JSScript::argumentsOptimizationFailed");
    4222           0 :             SetFrameArgumentsObject(cx, frame, script, argsobj);
    4223             :         }
    4224             :     }
    4225             : 
    4226           0 :     return true;
    4227             : }
    4228             : 
    4229             : bool
    4230       22498 : JSScript::formalIsAliased(unsigned argSlot)
    4231             : {
    4232       22498 :     if (functionHasParameterExprs())
    4233         571 :         return false;
    4234             : 
    4235       32669 :     for (PositionalFormalParameterIter fi(this); fi; fi++) {
    4236       32669 :         if (fi.argumentSlot() == argSlot)
    4237       21927 :             return fi.closedOver();
    4238             :     }
    4239           0 :     MOZ_CRASH("Argument slot not found");
    4240             : }
    4241             : 
    4242             : bool
    4243           0 : JSScript::formalLivesInArgumentsObject(unsigned argSlot)
    4244             : {
    4245           0 :     return argsObjAliasesFormals() && !formalIsAliased(argSlot);
    4246             : }
    4247             : 
    4248        4161 : LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
    4249             :                        uint32_t begin, uint32_t end,
    4250        4161 :                        uint32_t toStringStart, uint32_t lineno, uint32_t column)
    4251             :   : script_(nullptr),
    4252             :     function_(fun),
    4253             :     enclosingScope_(nullptr),
    4254             :     sourceObject_(nullptr),
    4255             :     table_(table),
    4256             :     packedFields_(packedFields),
    4257             :     begin_(begin),
    4258             :     end_(end),
    4259             :     toStringStart_(toStringStart),
    4260             :     toStringEnd_(end),
    4261             :     lineno_(lineno),
    4262        4161 :     column_(column)
    4263             : {
    4264        4161 :     MOZ_ASSERT(begin <= end);
    4265        4161 :     MOZ_ASSERT(toStringStart <= begin);
    4266        4161 : }
    4267             : 
    4268             : void
    4269        2314 : LazyScript::initScript(JSScript* script)
    4270             : {
    4271        2314 :     MOZ_ASSERT(script);
    4272        2314 :     MOZ_ASSERT(!script_.unbarrieredGet());
    4273        2314 :     script_.set(script);
    4274        2314 : }
    4275             : 
    4276             : void
    4277           0 : LazyScript::resetScript()
    4278             : {
    4279           0 :     MOZ_ASSERT(script_.unbarrieredGet());
    4280           0 :     script_.set(nullptr);
    4281           0 : }
    4282             : 
    4283             : void
    4284        3735 : LazyScript::setEnclosingScopeAndSource(Scope* enclosingScope, ScriptSourceObject* sourceObject)
    4285             : {
    4286        3735 :     MOZ_ASSERT(function_->compartment() == sourceObject->compartment());
    4287             :     // This method may be called to update the enclosing scope. See comment
    4288             :     // above the callsite in BytecodeEmitter::emitFunction.
    4289        3735 :     MOZ_ASSERT_IF(sourceObject_, sourceObject_ == sourceObject && enclosingScope_);
    4290        3735 :     MOZ_ASSERT_IF(!sourceObject_, !enclosingScope_);
    4291             : 
    4292        3735 :     enclosingScope_ = enclosingScope;
    4293        3735 :     sourceObject_ = sourceObject;
    4294        3735 : }
    4295             : 
    4296             : ScriptSourceObject*
    4297       12621 : LazyScript::sourceObject() const
    4298             : {
    4299       12621 :     return sourceObject_ ? &sourceObject_->as<ScriptSourceObject>() : nullptr;
    4300             : }
    4301             : 
    4302             : ScriptSource*
    4303           0 : LazyScript::maybeForwardedScriptSource() const
    4304             : {
    4305           0 :     JSObject* source = MaybeForwarded(sourceObject());
    4306           0 :     return UncheckedUnwrapWithoutExpose(source)->as<ScriptSourceObject>().source();
    4307             : }
    4308             : 
    4309             : /* static */ LazyScript*
    4310        4161 : LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
    4311             :                       uint64_t packedFields, uint32_t begin, uint32_t end,
    4312             :                       uint32_t toStringStart, uint32_t lineno, uint32_t column)
    4313             : {
    4314             :     union {
    4315             :         PackedView p;
    4316             :         uint64_t packed;
    4317        4161 :     };
    4318             : 
    4319        4161 :     packed = packedFields;
    4320             : 
    4321             :     // Reset runtime flags to obtain a fresh LazyScript.
    4322        4161 :     p.hasBeenCloned = false;
    4323        4161 :     p.treatAsRunOnce = false;
    4324             : 
    4325        4161 :     size_t bytes = (p.numClosedOverBindings * sizeof(JSAtom*))
    4326        4161 :                  + (p.numInnerFunctions * sizeof(GCPtrFunction));
    4327             : 
    4328        8322 :     ScopedJSFreePtr<uint8_t> table(bytes ? fun->zone()->pod_malloc<uint8_t>(bytes) : nullptr);
    4329        4161 :     if (bytes && !table) {
    4330           0 :         ReportOutOfMemory(cx);
    4331           0 :         return nullptr;
    4332             :     }
    4333             : 
    4334        4161 :     LazyScript* res = Allocate<LazyScript>(cx);
    4335        4161 :     if (!res)
    4336           0 :         return nullptr;
    4337             : 
    4338        4161 :     cx->compartment()->scheduleDelazificationForDebugger();
    4339             : 
    4340        4161 :     return new (res) LazyScript(fun, table.forget(), packed, begin, end,
    4341       12483 :                                 toStringStart, lineno, column);
    4342             : }
    4343             : 
    4344             : /* static */ LazyScript*
    4345        2028 : LazyScript::Create(JSContext* cx, HandleFunction fun,
    4346             :                    const frontend::AtomVector& closedOverBindings,
    4347             :                    Handle<GCVector<JSFunction*, 8>> innerFunctions,
    4348             :                    JSVersion version,
    4349             :                    uint32_t begin, uint32_t end,
    4350             :                    uint32_t toStringStart, uint32_t lineno, uint32_t column)
    4351             : {
    4352             :     union {
    4353             :         PackedView p;
    4354             :         uint64_t packedFields;
    4355        2028 :     };
    4356             : 
    4357        2028 :     p.version = version;
    4358        2028 :     p.shouldDeclareArguments = false;
    4359        2028 :     p.hasThisBinding = false;
    4360        2028 :     p.isAsync = false;
    4361        2028 :     p.hasRest = false;
    4362        2028 :     p.isExprBody = false;
    4363        2028 :     p.numClosedOverBindings = closedOverBindings.length();
    4364        2028 :     p.numInnerFunctions = innerFunctions.length();
    4365        2028 :     p.generatorKindBits = GeneratorKindAsBits(NotGenerator);
    4366        2028 :     p.strict = false;
    4367        2028 :     p.bindingsAccessedDynamically = false;
    4368        2028 :     p.hasDebuggerStatement = false;
    4369        2028 :     p.hasDirectEval = false;
    4370        2028 :     p.isLikelyConstructorWrapper = false;
    4371        2028 :     p.isDerivedClassConstructor = false;
    4372        2028 :     p.needsHomeObject = false;
    4373             : 
    4374             :     LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart,
    4375        2028 :                                             lineno, column);
    4376        2028 :     if (!res)
    4377           0 :         return nullptr;
    4378             : 
    4379        2028 :     JSAtom** resClosedOverBindings = res->closedOverBindings();
    4380        7681 :     for (size_t i = 0; i < res->numClosedOverBindings(); i++)
    4381        5653 :         resClosedOverBindings[i] = closedOverBindings[i];
    4382             : 
    4383        2028 :     GCPtrFunction* resInnerFunctions = res->innerFunctions();
    4384        2500 :     for (size_t i = 0; i < res->numInnerFunctions(); i++)
    4385         472 :         resInnerFunctions[i].init(innerFunctions[i]);
    4386             : 
    4387        2028 :     MOZ_ASSERT_IF(res, res->version() == version);
    4388        2028 :     return res;
    4389             : }
    4390             : 
    4391             : /* static */ LazyScript*
    4392        2133 : LazyScript::Create(JSContext* cx, HandleFunction fun,
    4393             :                    HandleScript script, HandleScope enclosingScope,
    4394             :                    HandleScriptSource sourceObject,
    4395             :                    uint64_t packedFields, uint32_t begin, uint32_t end,
    4396             :                    uint32_t toStringStart, uint32_t lineno, uint32_t column)
    4397             : {
    4398             :     // Dummy atom which is not a valid property name.
    4399        4266 :     RootedAtom dummyAtom(cx, cx->names().comma);
    4400             : 
    4401             :     // Dummy function which is not a valid function as this is the one which is
    4402             :     // holding this lazy script.
    4403        2133 :     HandleFunction dummyFun = fun;
    4404             : 
    4405        2133 :     LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart,
    4406        2133 :                                             lineno, column);
    4407        2133 :     if (!res)
    4408           0 :         return nullptr;
    4409             : 
    4410             :     // Fill with dummies, to be GC-safe after the initialization of the free
    4411             :     // variables and inner functions.
    4412             :     size_t i, num;
    4413        2133 :     JSAtom** closedOverBindings = res->closedOverBindings();
    4414        7366 :     for (i = 0, num = res->numClosedOverBindings(); i < num; i++)
    4415        5233 :         closedOverBindings[i] = dummyAtom;
    4416             : 
    4417        2133 :     GCPtrFunction* functions = res->innerFunctions();
    4418        2347 :     for (i = 0, num = res->numInnerFunctions(); i < num; i++)
    4419         214 :         functions[i].init(dummyFun);
    4420             : 
    4421             :     // Set the enclosing scope and source object of the lazy function. These
    4422             :     // values should only be non-null if we have a non-lazy enclosing script.
    4423             :     // AddLazyFunctionsForCompartment relies on the source object being null
    4424             :     // if we're nested inside another lazy function.
    4425        2133 :     MOZ_ASSERT(!!sourceObject == !!enclosingScope);
    4426        2133 :     MOZ_ASSERT(!res->sourceObject());
    4427        2133 :     MOZ_ASSERT(!res->enclosingScope());
    4428        2133 :     if (sourceObject)
    4429        1919 :         res->setEnclosingScopeAndSource(enclosingScope, sourceObject);
    4430             : 
    4431        2133 :     MOZ_ASSERT(!res->hasScript());
    4432        2133 :     if (script)
    4433         907 :         res->initScript(script);
    4434             : 
    4435        2133 :     return res;
    4436             : }
    4437             : 
    4438             : void
    4439         907 : LazyScript::initRuntimeFields(uint64_t packedFields)
    4440             : {
    4441             :     union {
    4442             :         PackedView p;
    4443             :         uint64_t packed;
    4444             :     };
    4445             : 
    4446         907 :     packed = packedFields;
    4447         907 :     p_.hasBeenCloned = p.hasBeenCloned;
    4448         907 :     p_.treatAsRunOnce = p.treatAsRunOnce;
    4449         907 : }
    4450             : 
    4451             : bool
    4452           0 : LazyScript::hasUncompiledEnclosingScript() const
    4453             : {
    4454             :     // It can happen that we created lazy scripts while compiling an enclosing
    4455             :     // script, but we errored out while compiling that script. When we iterate
    4456             :     // over lazy script in a compartment, we might see lazy scripts that never
    4457             :     // escaped to script and should be ignored.
    4458             :     //
    4459             :     // If the enclosing scope is a function with a null script or has a script
    4460             :     // without code, it was not successfully compiled.
    4461             : 
    4462           0 :     if (!enclosingScope() || !enclosingScope()->is<FunctionScope>())
    4463           0 :         return false;
    4464             : 
    4465           0 :     JSFunction* fun = enclosingScope()->as<FunctionScope>().canonicalFunction();
    4466           0 :     return !fun->hasScript() || fun->hasUncompiledScript() || !fun->nonLazyScript()->code();
    4467             : }
    4468             : 
    4469             : void
    4470        1228 : JSScript::updateBaselineOrIonRaw(JSRuntime* maybeRuntime)
    4471             : {
    4472        1228 :     if (hasBaselineScript() && baseline->hasPendingIonBuilder()) {
    4473           8 :         MOZ_ASSERT(maybeRuntime);
    4474           8 :         MOZ_ASSERT(!isIonCompilingOffThread());
    4475           8 :         baselineOrIonRaw = maybeRuntime->jitRuntime()->lazyLinkStub()->raw();
    4476           8 :         baselineOrIonSkipArgCheck = maybeRuntime->jitRuntime()->lazyLinkStub()->raw();
    4477        1220 :     } else if (hasIonScript()) {
    4478           5 :         baselineOrIonRaw = ion->method()->raw();
    4479           5 :         baselineOrIonSkipArgCheck = ion->method()->raw() + ion->getSkipArgCheckEntryOffset();
    4480        1215 :     } else if (hasBaselineScript()) {
    4481         668 :         baselineOrIonRaw = baseline->method()->raw();
    4482         668 :         baselineOrIonSkipArgCheck = baseline->method()->raw();
    4483             :     } else {
    4484         547 :         baselineOrIonRaw = nullptr;
    4485         547 :         baselineOrIonSkipArgCheck = nullptr;
    4486             :     }
    4487        1228 : }
    4488             : 
    4489             : bool
    4490          33 : JSScript::hasLoops()
    4491             : {
    4492          33 :     if (!hasTrynotes())
    4493          33 :         return false;
    4494           0 :     JSTryNote* tn = trynotes()->vector;
    4495           0 :     JSTryNote* tnlimit = tn + trynotes()->length;
    4496           0 :     for (; tn < tnlimit; tn++) {
    4497           0 :         if (tn->kind == JSTRY_FOR_IN || tn->kind == JSTRY_LOOP)
    4498           0 :             return true;
    4499             :     }
    4500           0 :     return false;
    4501             : }
    4502             : 
    4503             : bool
    4504         179 : JSScript::mayReadFrameArgsDirectly()
    4505             : {
    4506         179 :     return argumentsHasVarBinding() || hasRest();
    4507             : }
    4508             : 
    4509             : static inline void
    4510        2420 : LazyScriptHash(uint32_t lineno, uint32_t column, uint32_t begin, uint32_t end,
    4511             :                HashNumber hashes[3])
    4512             : {
    4513        2420 :     HashNumber hash = lineno;
    4514        2420 :     hash = RotateLeft(hash, 4) ^ column;
    4515        2420 :     hash = RotateLeft(hash, 4) ^ begin;
    4516        2420 :     hash = RotateLeft(hash, 4) ^ end;
    4517             : 
    4518        2420 :     hashes[0] = hash;
    4519        2420 :     hashes[1] = RotateLeft(hashes[0], 4) ^ begin;
    4520        2420 :     hashes[2] = RotateLeft(hashes[1], 4) ^ end;
    4521        2420 : }
    4522             : 
    4523             : void
    4524        2420 : LazyScriptHashPolicy::hash(const Lookup& lookup, HashNumber hashes[3])
    4525             : {
    4526        2420 :     LazyScript* lazy = lookup.lazy;
    4527        2420 :     LazyScriptHash(lazy->lineno(), lazy->column(), lazy->begin(), lazy->end(), hashes);
    4528        2420 : }
    4529             : 
    4530             : void
    4531           0 : LazyScriptHashPolicy::hash(JSScript* script, HashNumber hashes[3])
    4532             : {
    4533           0 :     LazyScriptHash(script->lineno(), script->column(), script->sourceStart(), script->sourceEnd(), hashes);
    4534           0 : }
    4535             : 
    4536             : bool
    4537           0 : LazyScriptHashPolicy::match(JSScript* script, const Lookup& lookup)
    4538             : {
    4539           0 :     JSContext* cx = lookup.cx;
    4540           0 :     LazyScript* lazy = lookup.lazy;
    4541             : 
    4542             :     // To be a match, the script and lazy script need to have the same line
    4543             :     // and column and to be at the same position within their respective
    4544             :     // source blobs, and to have the same source contents and version.
    4545             :     //
    4546             :     // While the surrounding code in the source may differ, this is
    4547             :     // sufficient to ensure that compiling the lazy script will yield an
    4548             :     // identical result to compiling the original script.
    4549             :     //
    4550             :     // Note that the filenames and origin principals of the lazy script and
    4551             :     // original script can differ. If there is a match, these will be fixed
    4552             :     // up in the resulting clone by the caller.
    4553             : 
    4554           0 :     if (script->lineno() != lazy->lineno() ||
    4555           0 :         script->column() != lazy->column() ||
    4556           0 :         script->getVersion() != lazy->version() ||
    4557           0 :         script->sourceStart() != lazy->begin() ||
    4558           0 :         script->sourceEnd() != lazy->end())
    4559             :     {
    4560           0 :         return false;
    4561             :     }
    4562             : 
    4563           0 :     UncompressedSourceCache::AutoHoldEntry holder;
    4564             : 
    4565           0 :     size_t scriptBegin = script->sourceStart();
    4566           0 :     size_t length = script->sourceEnd() - scriptBegin;
    4567           0 :     ScriptSource::PinnedChars scriptChars(cx, script->scriptSource(), holder, scriptBegin, length);
    4568           0 :     if (!scriptChars.get())
    4569           0 :         return false;
    4570             : 
    4571           0 :     MOZ_ASSERT(scriptBegin == lazy->begin());
    4572           0 :     ScriptSource::PinnedChars lazyChars(cx, lazy->scriptSource(), holder, scriptBegin, length);
    4573           0 :     if (!lazyChars.get())
    4574           0 :         return false;
    4575             : 
    4576           0 :     return !memcmp(scriptChars.get(), lazyChars.get(), length);
    4577             : }
    4578             : 
    4579             : void
    4580       11824 : JSScript::AutoDelazify::holdScript(JS::HandleFunction fun)
    4581             : {
    4582       11824 :     if (fun) {
    4583        8848 :         if (fun->compartment()->isSelfHosting) {
    4584             :             // The self-hosting compartment is shared across runtimes, so we
    4585             :             // can't use JSAutoCompartment: it could cause races. Functions in
    4586             :             // the self-hosting compartment will never be lazy, so we can safely
    4587             :             // assume we don't have to delazify.
    4588         582 :             script_ = fun->nonLazyScript();
    4589             :         } else {
    4590       16532 :             JSAutoCompartment ac(cx_, fun);
    4591        8266 :             script_ = JSFunction::getOrCreateScript(cx_, fun);
    4592        8266 :             if (script_) {
    4593        8266 :                 oldDoNotRelazify_ = script_->doNotRelazify_;
    4594        8266 :                 script_->setDoNotRelazify(true);
    4595             :             }
    4596             :         }
    4597             :     }
    4598       11824 : }
    4599             : 
    4600             : void
    4601       11824 : JSScript::AutoDelazify::dropScript()
    4602             : {
    4603             :     // Don't touch script_ if it's in the self-hosting compartment, see the
    4604             :     // comment in holdScript.
    4605       11824 :     if (script_ && !script_->compartment()->isSelfHosting)
    4606        8266 :         script_->setDoNotRelazify(oldDoNotRelazify_);
    4607       11824 :     script_ = nullptr;
    4608       11824 : }
    4609             : 
    4610             : JS::ubi::Node::Size
    4611           0 : JS::ubi::Concrete<JSScript>::size(mozilla::MallocSizeOf mallocSizeOf) const
    4612             : {
    4613           0 :     Size size = Arena::thingSize(get().asTenured().getAllocKind());
    4614             : 
    4615           0 :     size += get().sizeOfData(mallocSizeOf);
    4616           0 :     size += get().sizeOfTypeScript(mallocSizeOf);
    4617             : 
    4618           0 :     size_t baselineSize = 0;
    4619           0 :     size_t baselineStubsSize = 0;
    4620           0 :     jit::AddSizeOfBaselineData(&get(), mallocSizeOf, &baselineSize, &baselineStubsSize);
    4621           0 :     size += baselineSize;
    4622           0 :     size += baselineStubsSize;
    4623             : 
    4624           0 :     size += jit::SizeOfIonData(&get(), mallocSizeOf);
    4625             : 
    4626           0 :     MOZ_ASSERT(size > 0);
    4627           0 :     return size;
    4628             : }
    4629             : 
    4630             : const char*
    4631           0 : JS::ubi::Concrete<JSScript>::scriptFilename() const
    4632             : {
    4633           0 :     return get().filename();
    4634             : }
    4635             : 
    4636             : JS::ubi::Node::Size
    4637           0 : JS::ubi::Concrete<js::LazyScript>::size(mozilla::MallocSizeOf mallocSizeOf) const
    4638             : {
    4639           0 :     Size size = js::gc::Arena::thingSize(get().asTenured().getAllocKind());
    4640           0 :     size += get().sizeOfExcludingThis(mallocSizeOf);
    4641           0 :     return size;
    4642             : }
    4643             : 
    4644             : const char*
    4645           0 : JS::ubi::Concrete<js::LazyScript>::scriptFilename() const
    4646             : {
    4647           0 :     auto sourceObject = get().sourceObject();
    4648           0 :     if (!sourceObject)
    4649           0 :         return nullptr;
    4650             : 
    4651           0 :     auto source = sourceObject->source();
    4652           0 :     if (!source)
    4653           0 :         return nullptr;
    4654             : 
    4655           0 :     return source->filename();
    4656             : }

Generated by: LCOV version 1.13