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

Generated by: LCOV version 1.13-14-ga5dd952