author | Jeff Walden <jwalden@mit.edu> |
Wed, 16 May 2018 17:00:57 -0700 | |
changeset 418919 | 7c45180cea08bafea969777bbfe28ff2c0634fb8 |
parent 418918 | 1df7d4219611559f5289e869e51c28c0b42a2853 |
child 418920 | 6ae525ee499f45683e3f5ee302652c3782467034 |
push id | 103419 |
push user | jwalden@mit.edu |
push date | Fri, 18 May 2018 19:33:51 +0000 |
treeherder | mozilla-inbound@7658d2d1e0d7 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 1461556 |
milestone | 62.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/vm/JSScript-inl.h +++ b/js/src/vm/JSScript-inl.h @@ -199,12 +199,12 @@ JSScript::ensureHasAnalyzedArgsUsage(JSC if (analyzedArgsUsage()) return true; return js::jit::AnalyzeArgumentsUsage(cx, this); } inline bool JSScript::isDebuggee() const { - return realm_->debuggerObservesAllExecution() || hasDebugScript_; + return realm_->debuggerObservesAllExecution() || bitFields_.hasDebugScript_; } #endif /* vm_JSScript_inl_h */
--- a/js/src/vm/JSScript.cpp +++ b/js/src/vm/JSScript.cpp @@ -15,16 +15,17 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/PodOperations.h" #include "mozilla/ScopeExit.h" #include "mozilla/Sprintf.h" #include "mozilla/Unused.h" #include "mozilla/Vector.h" #include <algorithm> +#include <new> #include <string.h> #include "jsapi.h" #include "jstypes.h" #include "jsutil.h" #include "frontend/BytecodeCompiler.h" #include "frontend/BytecodeEmitter.h" @@ -63,17 +64,16 @@ #include "vm/Stack-inl.h" using namespace js; using namespace js::gc; using namespace js::frontend; using mozilla::Maybe; using mozilla::PodCopy; -using mozilla::PodZero; // Check that JSScript::data hasn't experienced obvious memory corruption. // This is a diagnositic for Bug 1367896. static void CheckScriptDataIntegrity(JSScript* script) { ScopeArray* sa = script->scopes(); @@ -553,49 +553,49 @@ js::XDRScript(XDRState<mode>* xdr, Handl MOZ_ASSERT(!script->mainOffset()); script->mainOffset_ = prologueLength; script->funLength_ = funLength; scriptp.set(script); if (scriptBits & (1 << Strict)) - script->strict_ = true; + script->bitFields_.strict_ = true; if (scriptBits & (1 << ExplicitUseStrict)) - script->explicitUseStrict_ = true; + script->bitFields_.explicitUseStrict_ = true; if (scriptBits & (1 << ContainsDynamicNameAccess)) - script->bindingsAccessedDynamically_ = true; + script->bitFields_.bindingsAccessedDynamically_ = true; if (scriptBits & (1 << FunHasExtensibleScope)) - script->funHasExtensibleScope_ = true; + script->bitFields_.funHasExtensibleScope_ = true; if (scriptBits & (1 << FunHasAnyAliasedFormal)) - script->funHasAnyAliasedFormal_ = true; + script->bitFields_.funHasAnyAliasedFormal_ = true; if (scriptBits & (1 << ArgumentsHasVarBinding)) script->setArgumentsHasVarBinding(); if (scriptBits & (1 << NeedsArgsObj)) script->setNeedsArgsObj(true); if (scriptBits & (1 << HasMappedArgsObj)) - script->hasMappedArgsObj_ = true; + script->bitFields_.hasMappedArgsObj_ = true; if (scriptBits & (1 << FunctionHasThisBinding)) - script->functionHasThisBinding_ = true; + script->bitFields_.functionHasThisBinding_ = true; if (scriptBits & (1 << FunctionHasExtraBodyVarScope)) - script->functionHasExtraBodyVarScope_ = true; + script->bitFields_.functionHasExtraBodyVarScope_ = true; if (scriptBits & (1 << HasSingleton)) - script->hasSingletons_ = true; + script->bitFields_.hasSingletons_ = true; if (scriptBits & (1 << TreatAsRunOnce)) - script->treatAsRunOnce_ = true; + script->bitFields_.treatAsRunOnce_ = true; if (scriptBits & (1 << HasNonSyntacticScope)) - script->hasNonSyntacticScope_ = true; + script->bitFields_.hasNonSyntacticScope_ = true; if (scriptBits & (1 << HasInnerFunctions)) - script->hasInnerFunctions_ = true; + script->bitFields_.hasInnerFunctions_ = true; if (scriptBits & (1 << NeedsHomeObject)) - script->needsHomeObject_ = true; + script->bitFields_.needsHomeObject_ = true; if (scriptBits & (1 << IsDerivedClassConstructor)) - script->isDerivedClassConstructor_ = true; + script->bitFields_.isDerivedClassConstructor_ = true; if (scriptBits & (1 << IsDefaultClassConstructor)) - script->isDefaultClassConstructor_ = true; + script->bitFields_.isDefaultClassConstructor_ = true; if (scriptBits & (1 << IsGenerator)) script->setGeneratorKind(GeneratorKind::Generator); if (scriptBits & (1 << IsAsync)) script->setAsyncKind(FunctionAsyncKind::AsyncFunction); if (scriptBits & (1 << HasRest)) script->setHasRest(); } @@ -1081,17 +1081,17 @@ JSScript::initScriptCounts(JSContext* cx // Register the current ScriptCounts in the compartment's map. if (!map->putNew(this, sc)) { ReportOutOfMemory(cx); return false; } // safe to set this; we can't fail after this point. - hasScriptCounts_ = true; + bitFields_.hasScriptCounts_ = true; guardScriptCounts.release(); // Enable interrupts in any interpreter frames running on this script. This // is used to let the interpreter increment the PCCounts, if present. for (ActivationIterator iter(cx); !iter.done(); ++iter) { if (iter->isInterpreter()) iter->asInterpreter()->enableInterruptsIfRunning(this); } @@ -1293,27 +1293,27 @@ JSScript::getIonCounts() void JSScript::takeOverScriptCountsMapEntry(ScriptCounts* entryValue) { #ifdef DEBUG ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this); MOZ_ASSERT(entryValue == p->value()); #endif - hasScriptCounts_ = false; + bitFields_.hasScriptCounts_ = false; } void JSScript::releaseScriptCounts(ScriptCounts* counts) { ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this); *counts = Move(*p->value()); js_delete(p->value()); compartment()->scriptCountsMap->remove(p); - hasScriptCounts_ = false; + bitFields_.hasScriptCounts_ = false; } void JSScript::destroyScriptCounts() { if (hasScriptCounts()) { ScriptCounts scriptCounts; releaseScriptCounts(&scriptCounts); @@ -2621,60 +2621,86 @@ ScriptDataSize(uint32_t nscopes, uint32_ if (nscopenotes != 0) size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote); if (nyieldoffsets != 0) size += sizeof(YieldAndAwaitOffsetArray) + nyieldoffsets * sizeof(uint32_t); return size; } -/* static */ JSScript* -JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options, - HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd, - uint32_t toStringStart, uint32_t toStringEnd) +JSScript::JSScript(JS::Realm* realm, uint8_t* stubEntry, const ReadOnlyCompileOptions& options, + HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd, + uint32_t toStringStart, uint32_t toStringEnd) + : +#ifndef JS_CODEGEN_NONE + jitCodeRaw_(stubEntry), + jitCodeSkipArgCheck_(stubEntry), +#endif + realm_(realm), + sourceStart_(bufStart), + sourceEnd_(bufEnd), + toStringStart_(toStringStart), + toStringEnd_(toStringEnd), +#ifdef MOZ_VTUNE + vtuneMethodId_(vtune::GenerateUniqueMethodID()), +#endif + bitFields_{} // zeroes everything -- some fields custom-assigned below { // bufStart and bufEnd specify the range of characters parsed by the // Parser to produce this script. toStringStart and toStringEnd specify // the range of characters to be returned for Function.prototype.toString. MOZ_ASSERT(bufStart <= bufEnd); MOZ_ASSERT(toStringStart <= toStringEnd); MOZ_ASSERT(toStringStart <= bufStart); MOZ_ASSERT(toStringEnd >= bufEnd); - RootedScript script(cx, Allocate<JSScript>(cx)); + bitFields_.noScriptRval_ = options.noScriptRval; + bitFields_.selfHosted_ = options.selfHostingMode; + bitFields_.treatAsRunOnce_ = options.isRunOnce; + bitFields_.hideScriptFromDebugger_ = options.hideScriptFromDebugger; + + setSourceObject(sourceObject); +} + +/* static */ JSScript* +JSScript::createInitialized(JSContext* cx, const ReadOnlyCompileOptions& options, + HandleObject sourceObject, + uint32_t bufStart, uint32_t bufEnd, + uint32_t toStringStart, uint32_t toStringEnd) +{ + void* script = Allocate<JSScript>(cx); if (!script) return nullptr; - PodZero(script.get()); - - script->realm_ = cx->realm(); - + uint8_t* stubEntry = #ifndef JS_CODEGEN_NONE - uint8_t* stubEntry = cx->runtime()->jitRuntime()->interpreterStub().value; - script->jitCodeRaw_ = stubEntry; - script->jitCodeSkipArgCheck_ = stubEntry; + cx->runtime()->jitRuntime()->interpreterStub().value +#else + nullptr #endif - - script->selfHosted_ = options.selfHostingMode; - script->noScriptRval_ = options.noScriptRval; - script->treatAsRunOnce_ = options.isRunOnce; - - script->setSourceObject(sourceObject); - if (cx->runtime()->lcovOutput().isEnabled() && !script->initScriptName(cx)) + ; + + return new (script) JSScript(cx->realm(), stubEntry, options, sourceObject, + bufStart, bufEnd, toStringStart, toStringEnd); +} + +/* static */ JSScript* +JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options, + HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd, + uint32_t toStringStart, uint32_t toStringEnd) +{ + RootedScript script(cx, createInitialized(cx, options, sourceObject, bufStart, bufEnd, + toStringStart, toStringEnd)); + if (!script) return nullptr; - script->sourceStart_ = bufStart; - script->sourceEnd_ = bufEnd; - script->toStringStart_ = toStringStart; - script->toStringEnd_ = toStringEnd; - - script->hideScriptFromDebugger_ = options.hideScriptFromDebugger; - -#ifdef MOZ_VTUNE - script->vtuneMethodId_ = vtune::GenerateUniqueMethodID(); -#endif + + if (cx->runtime()->lcovOutput().isEnabled()) { + if (!script->initScriptName(cx)) + return nullptr; + } return script; } bool JSScript::initScriptName(JSContext* cx) { MOZ_ASSERT(!hasScriptName()); @@ -2877,53 +2903,53 @@ InitAtomMap(frontend::AtomIndexMap& indi JSScript::initFromFunctionBox(HandleScript script, frontend::FunctionBox* funbox) { JSFunction* fun = funbox->function(); if (fun->isInterpretedLazy()) fun->setUnlazifiedScript(script); else fun->setScript(script); - script->funHasExtensibleScope_ = funbox->hasExtensibleScope(); - script->needsHomeObject_ = funbox->needsHomeObject(); - script->isDerivedClassConstructor_ = funbox->isDerivedClassConstructor(); + script->bitFields_.funHasExtensibleScope_ = funbox->hasExtensibleScope(); + script->bitFields_.needsHomeObject_ = funbox->needsHomeObject(); + script->bitFields_.isDerivedClassConstructor_ = funbox->isDerivedClassConstructor(); if (funbox->argumentsHasLocalBinding()) { script->setArgumentsHasVarBinding(); if (funbox->definitelyNeedsArgsObj()) script->setNeedsArgsObj(true); } else { MOZ_ASSERT(!funbox->definitelyNeedsArgsObj()); } - script->hasMappedArgsObj_ = funbox->hasMappedArgsObj(); - - script->functionHasThisBinding_ = funbox->hasThisBinding(); - script->functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope(); + script->bitFields_.hasMappedArgsObj_ = funbox->hasMappedArgsObj(); + + script->bitFields_.functionHasThisBinding_ = funbox->hasThisBinding(); + script->bitFields_.functionHasExtraBodyVarScope_ = funbox->hasExtraBodyVarScope(); script->funLength_ = funbox->length; script->setGeneratorKind(funbox->generatorKind()); script->setAsyncKind(funbox->asyncKind()); if (funbox->hasRest()) script->setHasRest(); PositionalFormalParameterIter fi(script); while (fi && !fi.closedOver()) fi++; - script->funHasAnyAliasedFormal_ = !!fi; + script->bitFields_.funHasAnyAliasedFormal_ = !!fi; script->setHasInnerFunctions(funbox->hasInnerFunctions()); } /* static */ void JSScript::initFromModuleContext(HandleScript script) { - script->funHasExtensibleScope_ = false; - script->needsHomeObject_ = false; - script->isDerivedClassConstructor_ = false; + script->bitFields_.funHasExtensibleScope_ = false; + script->bitFields_.needsHomeObject_ = false; + script->bitFields_.isDerivedClassConstructor_ = false; script->funLength_ = 0; script->setGeneratorKind(GeneratorKind::NotGenerator); // Since modules are only run once, mark the script so that initializers // created within it may be given more precise types. script->setTreatAsRunOnce(); MOZ_ASSERT(!script->hasRunOnce()); @@ -2972,31 +2998,32 @@ JSScript::fullyInitFromEmitter(JSContext if (bce->objectList.length != 0) bce->objectList.finish(script->objects()); if (bce->scopeList.length() != 0) bce->scopeList.finish(script->scopes()); if (bce->tryNoteList.length() != 0) bce->tryNoteList.finish(script->trynotes()); if (bce->scopeNoteList.length() != 0) bce->scopeNoteList.finish(script->scopeNotes(), prologueLength); - script->strict_ = bce->sc->strict(); - script->explicitUseStrict_ = bce->sc->hasExplicitUseStrict(); - script->bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically(); - script->hasSingletons_ = bce->hasSingletons; + script->bitFields_.strict_ = bce->sc->strict(); + script->bitFields_.explicitUseStrict_ = bce->sc->hasExplicitUseStrict(); + script->bitFields_.bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically(); + script->bitFields_.hasSingletons_ = bce->hasSingletons; uint64_t nslots = bce->maxFixedSlots + static_cast<uint64_t>(bce->maxStackDepth); if (nslots > UINT32_MAX) { bce->reportError(nullptr, JSMSG_NEED_DIET, js_script_str); return false; } script->nfixed_ = bce->maxFixedSlots; script->nslots_ = nslots; script->bodyScopeIndex_ = bce->bodyScopeIndex; - script->hasNonSyntacticScope_ = bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic); + script->bitFields_.hasNonSyntacticScope_ = + bce->outermostScope()->hasOnChain(ScopeKind::NonSyntactic); if (bce->sc->isFunctionBox()) initFromFunctionBox(script, bce->sc->asFunctionBox()); else if (bce->sc->isModuleContext()) initFromModuleContext(script); // Copy yield offsets last, as the generator kind is set in // initFromFunctionBox. @@ -3533,36 +3560,36 @@ js::detail::CopyScript(JSContext* cx, Ha dst->bodyScopeIndex_ = src->bodyScopeIndex_; dst->funLength_ = src->funLength(); dst->nTypeSets_ = src->nTypeSets(); if (src->argumentsHasVarBinding()) { dst->setArgumentsHasVarBinding(); if (src->analyzedArgsUsage()) dst->setNeedsArgsObj(src->needsArgsObj()); } - dst->hasMappedArgsObj_ = src->hasMappedArgsObj(); - dst->functionHasThisBinding_ = src->functionHasThisBinding(); - dst->functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope(); + dst->bitFields_.hasMappedArgsObj_ = src->hasMappedArgsObj(); + dst->bitFields_.functionHasThisBinding_ = src->functionHasThisBinding(); + dst->bitFields_.functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope(); dst->cloneHasArray(src); - dst->strict_ = src->strict(); - dst->explicitUseStrict_ = src->explicitUseStrict(); - dst->hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic); - dst->bindingsAccessedDynamically_ = src->bindingsAccessedDynamically(); - dst->funHasExtensibleScope_ = src->funHasExtensibleScope(); - dst->funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal(); - dst->hasSingletons_ = src->hasSingletons(); - dst->treatAsRunOnce_ = src->treatAsRunOnce(); - dst->hasInnerFunctions_ = src->hasInnerFunctions(); + dst->bitFields_.strict_ = src->strict(); + dst->bitFields_.explicitUseStrict_ = src->explicitUseStrict(); + dst->bitFields_.hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic); + dst->bitFields_.bindingsAccessedDynamically_ = src->bindingsAccessedDynamically(); + dst->bitFields_.funHasExtensibleScope_ = src->funHasExtensibleScope(); + dst->bitFields_.funHasAnyAliasedFormal_ = src->funHasAnyAliasedFormal(); + dst->bitFields_.hasSingletons_ = src->hasSingletons(); + dst->bitFields_.treatAsRunOnce_ = src->treatAsRunOnce(); + dst->bitFields_.hasInnerFunctions_ = src->hasInnerFunctions(); dst->setGeneratorKind(src->generatorKind()); - dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor(); - dst->needsHomeObject_ = src->needsHomeObject(); - dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor(); - dst->isAsync_ = src->isAsync_; - dst->hasRest_ = src->hasRest_; - dst->hideScriptFromDebugger_ = src->hideScriptFromDebugger_; + dst->bitFields_.isDerivedClassConstructor_ = src->isDerivedClassConstructor(); + dst->bitFields_.needsHomeObject_ = src->needsHomeObject(); + dst->bitFields_.isDefaultClassConstructor_ = src->isDefaultClassConstructor(); + dst->bitFields_.isAsync_ = src->bitFields_.isAsync_; + dst->bitFields_.hasRest_ = src->bitFields_.hasRest_; + dst->bitFields_.hideScriptFromDebugger_ = src->bitFields_.hideScriptFromDebugger_; if (nconsts != 0) { GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector); dst->consts()->vector = vector; for (unsigned i = 0; i < nconsts; ++i) MOZ_ASSERT_IF(vector[i].isGCThing(), vector[i].toString()->isAtom()); } if (nobjects != 0) { @@ -3695,59 +3722,59 @@ js::CloneScriptIntoFunction(JSContext* c fun->initScript(dst); return dst; } DebugScript* JSScript::debugScript() { - MOZ_ASSERT(hasDebugScript_); + MOZ_ASSERT(bitFields_.hasDebugScript_); DebugScriptMap* map = compartment()->debugScriptMap; MOZ_ASSERT(map); DebugScriptMap::Ptr p = map->lookup(this); MOZ_ASSERT(p); return p->value(); } DebugScript* JSScript::releaseDebugScript() { - MOZ_ASSERT(hasDebugScript_); + MOZ_ASSERT(bitFields_.hasDebugScript_); DebugScriptMap* map = compartment()->debugScriptMap; MOZ_ASSERT(map); DebugScriptMap::Ptr p = map->lookup(this); MOZ_ASSERT(p); DebugScript* debug = p->value(); map->remove(p); - hasDebugScript_ = false; + bitFields_.hasDebugScript_ = false; return debug; } void JSScript::destroyDebugScript(FreeOp* fop) { - if (hasDebugScript_) { + if (bitFields_.hasDebugScript_) { #ifdef DEBUG for (jsbytecode* pc = code(); pc < codeEnd(); pc++) { if (BreakpointSite* site = getBreakpointSite(pc)) { /* Breakpoints are swept before finalization. */ MOZ_ASSERT(site->firstBreakpoint() == nullptr); MOZ_ASSERT(getBreakpointSite(pc) == nullptr); } } #endif fop->free_(releaseDebugScript()); } } bool JSScript::ensureHasDebugScript(JSContext* cx) { - if (hasDebugScript_) + if (bitFields_.hasDebugScript_) return true; size_t nbytes = offsetof(DebugScript, breakpoints) + length() * sizeof(BreakpointSite*); DebugScript* debug = (DebugScript*) zone()->pod_calloc<uint8_t>(nbytes); if (!debug) return false; /* Create compartment's debugScriptMap if necessary. */ @@ -3761,17 +3788,17 @@ JSScript::ensureHasDebugScript(JSContext } compartment()->debugScriptMap = map; } if (!map->putNew(this, debug)) { js_free(debug); return false; } - hasDebugScript_ = true; // safe to set this; we can't fail after this point + bitFields_.hasDebugScript_ = true; // safe to set this; we can't fail after this point /* * Ensure that any Interpret() instances running on this script have * interrupts enabled. The interrupts must stay enabled until the * debug state is destroyed. */ for (ActivationIterator iter(cx); !iter.done(); ++iter) { if (iter->isInterpreter()) @@ -4028,26 +4055,26 @@ JSScript::innermostScope(jsbytecode* pc) if (Scope* scope = lookupScope(pc)) return scope; return bodyScope(); } void JSScript::setArgumentsHasVarBinding() { - argsHasVarBinding_ = true; - needsArgsAnalysis_ = true; + bitFields_.argsHasVarBinding_ = true; + bitFields_.needsArgsAnalysis_ = true; } void JSScript::setNeedsArgsObj(bool needsArgsObj) { MOZ_ASSERT_IF(needsArgsObj, argumentsHasVarBinding()); - needsArgsAnalysis_ = false; - needsArgsObj_ = needsArgsObj; + bitFields_.needsArgsAnalysis_ = false; + bitFields_.needsArgsObj_ = needsArgsObj; } void js::SetFrameArgumentsObject(JSContext* cx, AbstractFramePtr frame, HandleScript script, JSObject* argsobj) { /* * Replace any optimized arguments in the frame with an explicit arguments @@ -4100,17 +4127,17 @@ JSScript::argumentsOptimizationFailed(JS * argsobj. */ if (script->needsArgsObj()) return true; MOZ_ASSERT(!script->isGenerator()); MOZ_ASSERT(!script->isAsync()); - script->needsArgsObj_ = true; + script->bitFields_.needsArgsObj_ = true; /* * Since we can't invalidate baseline scripts, set a flag that's checked from * JIT code to indicate the arguments optimization failed and JSOP_ARGUMENTS * should create an arguments object next time. */ if (script->hasBaselineScript()) script->baselineScript()->setNeedsArgsObj(); @@ -4441,17 +4468,17 @@ JSScript::AutoDelazify::holdScript(JS::H // can't use JSAutoRealm: it could cause races. Functions in the // self-hosting compartment will never be lazy, so we can safely // assume we don't have to delazify. script_ = fun->nonLazyScript(); } else { JSAutoRealm ar(cx_, fun); script_ = JSFunction::getOrCreateScript(cx_, fun); if (script_) { - oldDoNotRelazify_ = script_->doNotRelazify_; + oldDoNotRelazify_ = script_->bitFields_.doNotRelazify_; script_->setDoNotRelazify(true); } } } } void JSScript::AutoDelazify::dropScript()
--- a/js/src/vm/JSScript.h +++ b/js/src/vm/JSScript.h @@ -895,79 +895,78 @@ SweepScriptData(JSRuntime* rt); extern void FreeScriptData(JSRuntime* rt); } /* namespace js */ class JSScript : public js::gc::TenuredCell { - template <js::XDRMode mode> - friend - js::XDRResult - js::XDRScript(js::XDRState<mode>* xdr, js::HandleScope enclosingScope, - js::HandleScriptSourceObject sourceObject, js::HandleFunction fun, - js::MutableHandleScript scriptp); - - friend bool - js::detail::CopyScript(JSContext* cx, js::HandleScript src, js::HandleScript dst, - js::MutableHandle<JS::GCVector<js::Scope*>> scopes); - private: // Pointer to baseline->method()->raw(), ion->method()->raw(), a wasm jit // entry, the JIT's EnterInterpreter stub, or the lazy link stub. Must be // non-null. - uint8_t* jitCodeRaw_; - uint8_t* jitCodeSkipArgCheck_; - - js::SharedScriptData* scriptData_; + uint8_t* jitCodeRaw_ = nullptr; + uint8_t* jitCodeSkipArgCheck_ = nullptr; + + js::SharedScriptData* scriptData_ = nullptr; + public: - uint8_t* data; /* pointer to variable-length data array (see - comment above Create() for details) */ - - JS::Realm* realm_; + // Pointer to variable-length data array (see comment above Create() for + // details). + uint8_t* data = nullptr; + + JS::Realm* realm_ = nullptr; private: /* Persistent type information retained across GCs. */ - js::TypeScript* types_; + js::TypeScript* types_ = nullptr; // This script's ScriptSourceObject, or a CCW thereof. // // (When we clone a JSScript into a new compartment, we don't clone its // source object. Instead, the clone refers to a wrapper.) - js::GCPtrObject sourceObject_; + js::GCPtrObject sourceObject_ = {}; /* * Information attached by Ion. Nexto a valid IonScript this could be * ION_DISABLED_SCRIPT, ION_COMPILING_SCRIPT or ION_PENDING_SCRIPT. * The later is a ion compilation that is ready, but hasn't been linked * yet. */ - js::jit::IonScript* ion; + js::jit::IonScript* ion = nullptr; /* Information attached by Baseline. */ - js::jit::BaselineScript* baseline; + js::jit::BaselineScript* baseline = nullptr; /* Information used to re-lazify a lazily-parsed interpreted function. */ - js::LazyScript* lazyScript; + js::LazyScript* lazyScript = nullptr; // 32-bit fields. - uint32_t dataSize_; /* size of the used part of the data array */ - - uint32_t lineno_; /* base line number of script */ - uint32_t column_; /* base column of script, optionally set */ - - uint32_t mainOffset_;/* offset of main entry point from code, after - predef'ing prologue */ - - uint32_t nfixed_; /* fixed frame slots */ - uint32_t nslots_; /* slots plus maximum stack depth */ - - uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */ + /* Size of the used part of the data array. */ + uint32_t dataSize_ = 0; + + /* Base line number of script. */ + uint32_t lineno_ = 0; + + /* Base column of script, optionally set. */ + uint32_t column_ = 0; + + /* Offset of main entry point from code, after predef'ing prologue. */ + uint32_t mainOffset_ = 0; + + /* Fixed frame slots. */ + uint32_t nfixed_ = 0; + + /* Slots plus maximum stack depth. */ + uint32_t nslots_ = 0; + + /* Index into the scopes array of the body scope */ + uint32_t bodyScopeIndex_ = 0; // Range of characters in scriptSource which contains this script's // source, that is, the range used by the Parser to produce this script. // // Most scripted functions have sourceStart_ == toStringStart_ and // sourceEnd_ == toStringEnd_. However, for functions with extra // qualifiers (e.g. generators, async) and for class constructors (which // need to return the entire class source), their values differ. @@ -985,193 +984,237 @@ class JSScript : public js::gc::TenuredC // offset is used. // // class C { constructor() { this.field = 42; } } // ^ ^ ^ ^ // | | | `---------` // | sourceStart_ sourceEnd_ | // | | // toStringStart_ toStringEnd_ - uint32_t sourceStart_; - uint32_t sourceEnd_; - uint32_t toStringStart_; - uint32_t toStringEnd_; + uint32_t sourceStart_ = 0; + uint32_t sourceEnd_ = 0; + uint32_t toStringStart_ = 0; + uint32_t toStringEnd_ = 0; #ifdef MOZ_VTUNE // Unique Method ID passed to the VTune profiler, or 0 if unset. // Allows attribution of different jitcode to the same source script. - uint32_t vtuneMethodId_; + uint32_t vtuneMethodId_ = 0; // Extra padding to maintain JSScript as a multiple of gc::CellAlignBytes. - uint32_t __vtune_unused_padding_; + uint32_t __vtune_unused_padding_; #endif // Number of times the script has been called or has had backedges taken. // When running in ion, also increased for any inlined scripts. Reset if // the script's JIT code is forcibly discarded. - mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount; + mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount = {}; // 16-bit fields. - uint16_t warmUpResetCount; /* Number of times the |warmUpCount| was - * forcibly discarded. The counter is reset when - * a script is successfully jit-compiled. */ - - uint16_t funLength_; /* ES6 function length */ - - uint16_t nTypeSets_; /* number of type sets used in this script for - dynamic type monitoring */ + /** + * Number of times the |warmUpCount| was forcibly discarded. The counter is + * reset when a script is successfully jit-compiled. + */ + uint16_t warmUpResetCount = 0; + + /* ES6 function length. */ + uint16_t funLength_ = 0; + + /* Number of type sets used in this script for dynamic type monitoring. */ + uint16_t nTypeSets_ = 0; // Bit fields. public: // The kinds of the optional arrays. enum ArrayKind { CONSTS, OBJECTS, TRYNOTES, SCOPENOTES, ARRAY_KIND_BITS }; private: - // The bits in this field indicate the presence/non-presence of several - // optional arrays in |data|. See the comments above Create() for details. - uint8_t hasArrayBits:ARRAY_KIND_BITS; - - // 1-bit fields. - - // No need for result value of last expression statement. - bool noScriptRval_:1; - - // Code is in strict mode. - bool strict_:1; - - // Code has "use strict"; explicitly. - bool explicitUseStrict_:1; - - // True if the script has a non-syntactic scope on its dynamic scope chain. - // That is, there are objects about which we know nothing between the - // outermost syntactic scope and the global. - bool hasNonSyntacticScope_:1; - - // see Parser::selfHostingMode. - bool selfHosted_:1; - - // See FunctionBox. - bool bindingsAccessedDynamically_:1; - bool funHasExtensibleScope_:1; - - // True if any formalIsAliased(i). - bool funHasAnyAliasedFormal_:1; - - // Have warned about uses of undefined properties in this script. - bool warnedAboutUndefinedProp_:1; - - // Script has singleton objects. - bool hasSingletons_:1; - - // Script is a lambda to treat as running once or a global or eval script - // that will only run once. Which one it is can be disambiguated by - // checking whether function() is null. - bool treatAsRunOnce_:1; - - // If treatAsRunOnce, whether script has executed. - bool hasRunOnce_:1; - - // Script has been reused for a clone. - bool hasBeenCloned_:1; - - // Script came from eval(), and is still active. - bool isActiveEval_:1; - - // Script came from eval(), and is in eval cache. - bool isCachedEval_:1; - - // 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper. - bool isLikelyConstructorWrapper_:1; - - // IonMonkey compilation hints. - bool failedBoundsCheck_:1; /* script has had hoisted bounds checks fail */ - bool failedShapeGuard_:1; /* script has had hoisted shape guard fail */ - bool hadFrequentBailouts_:1; - bool hadOverflowBailout_:1; - bool uninlineable_:1; /* explicitly marked as uninlineable */ - - // Idempotent cache has triggered invalidation. - bool invalidatedIdempotentCache_:1; - - // Lexical check did fail and bail out. - bool failedLexicalCheck_:1; - - // Script has an entry in JSCompartment::scriptCountsMap. - bool hasScriptCounts_:1; - - // Script has an entry in JSCompartment::debugScriptMap. - bool hasDebugScript_:1; - - // Freeze constraints for stack type sets have been generated. - bool hasFreezeConstraints_:1; - - /* See comments below. */ - bool argsHasVarBinding_:1; - bool needsArgsAnalysis_:1; - bool needsArgsObj_:1; - bool functionHasThisBinding_:1; - bool functionHasExtraBodyVarScope_:1; - - // Whether the arguments object for this script, if it needs one, should be - // mapped (alias formal parameters). - bool hasMappedArgsObj_:1; - - // Generation for this script's TypeScript. If out of sync with the - // TypeZone's generation, the TypeScript needs to be swept. - // - // This should be a uint32 but is instead a bool so that MSVC packs it - // correctly. - bool typesGeneration_:1; - - // Do not relazify this script. This is used by the relazify() testing - // function for scripts that are on the stack and also by the AutoDelazify - // RAII class. Usually we don't relazify functions in compartments with - // scripts on the stack, but the relazify() testing function overrides that, - // and sometimes we're working with a cross-compartment function and need to - // keep it from relazifying. - bool doNotRelazify_:1; - - // Script contains inner functions. Used to check if we can relazify the - // script. - bool hasInnerFunctions_:1; - - bool needsHomeObject_:1; - - bool isDerivedClassConstructor_:1; - bool isDefaultClassConstructor_:1; - - // True if this function is a generator function or async generator. - bool isGenerator_:1; - - // True if this function is an async function or async generator. - bool isAsync_:1; - - bool hasRest_:1; - - // True if the debugger's onNewScript hook has not yet been called. - bool hideScriptFromDebugger_:1; + struct BitFields + { + /* + * Bit-fields can't have member initializers til C++2a, i.e. probably + * C++20, so we can't initialize these to zero in place. Instead we + * braced-init this to all zeroes in the JSScript constructor, then + * custom-assign particular bit-fields in the constructor body. + */ + + // The bits in this field indicate the presence/non-presence of several + // optional arrays in |data|. See the comments above Create() for details. + uint8_t hasArrayBits_ : ARRAY_KIND_BITS; + + /* + * All remaining bit-fields are single-bit bools. + */ + + // No need for result value of last expression statement. + bool noScriptRval_ : 1; + + // Code is in strict mode. + bool strict_ : 1; + + // Code has "use strict"; explicitly. + bool explicitUseStrict_ : 1; + + // True if the script has a non-syntactic scope on its dynamic scope chain. + // That is, there are objects about which we know nothing between the + // outermost syntactic scope and the global. + bool hasNonSyntacticScope_ : 1; + + // see Parser::selfHostingMode. + bool selfHosted_ : 1; + + // See FunctionBox. + bool bindingsAccessedDynamically_ : 1; + bool funHasExtensibleScope_ : 1; + + // True if any formalIsAliased(i). + bool funHasAnyAliasedFormal_ : 1; + + // Have warned about uses of undefined properties in this script. + bool warnedAboutUndefinedProp_ : 1; + + // Script has singleton objects. + bool hasSingletons_ : 1; + + // Script is a lambda to treat as running once or a global or eval script + // that will only run once. Which one it is can be disambiguated by + // checking whether function() is null. + bool treatAsRunOnce_ : 1; + + // If treatAsRunOnce, whether script has executed. + bool hasRunOnce_ : 1; + + // Script has been reused for a clone. + bool hasBeenCloned_ : 1; + + // Script came from eval(), and is still active. + bool isActiveEval_ : 1; + + // Script came from eval(), and is in eval cache. + bool isCachedEval_ : 1; + + // 'this', 'arguments' and f.apply() are used. This is likely to be a wrapper. + bool isLikelyConstructorWrapper_ : 1; + + // IonMonkey compilation hints. + + /* Script has had hoisted bounds checks fail. */ + bool failedBoundsCheck_ : 1; + + /* Script has had hoisted shape guard fail. */ + bool failedShapeGuard_ : 1; + + bool hadFrequentBailouts_ : 1; + bool hadOverflowBailout_ : 1; + + /* Explicitly marked as uninlineable. */ + bool uninlineable_ : 1; + + // Idempotent cache has triggered invalidation. + bool invalidatedIdempotentCache_ : 1; + + // Lexical check did fail and bail out. + bool failedLexicalCheck_ : 1; + + // Script has an entry in JSCompartment::scriptCountsMap. + bool hasScriptCounts_ : 1; + + // Script has an entry in JSCompartment::debugScriptMap. + bool hasDebugScript_ : 1; + + // Freeze constraints for stack type sets have been generated. + bool hasFreezeConstraints_ : 1; + + /* See comments below. */ + bool argsHasVarBinding_ : 1; + bool needsArgsAnalysis_ : 1; + bool needsArgsObj_ : 1; + bool functionHasThisBinding_ : 1; + bool functionHasExtraBodyVarScope_ : 1; + + // Whether the arguments object for this script, if it needs one, should be + // mapped (alias formal parameters). + bool hasMappedArgsObj_ : 1; + + // Generation for this script's TypeScript. If out of sync with the + // TypeZone's generation, the TypeScript needs to be swept. + // + // This should be a uint32 but is instead a bool so that MSVC packs it + // correctly. + bool typesGeneration_ : 1; + + // Do not relazify this script. This is used by the relazify() testing + // function for scripts that are on the stack and also by the AutoDelazify + // RAII class. Usually we don't relazify functions in compartments with + // scripts on the stack, but the relazify() testing function overrides that, + // and sometimes we're working with a cross-compartment function and need to + // keep it from relazifying. + bool doNotRelazify_ : 1; + + // Script contains inner functions. Used to check if we can relazify the + // script. + bool hasInnerFunctions_ : 1; + + bool needsHomeObject_ : 1; + + bool isDerivedClassConstructor_ : 1; + bool isDefaultClassConstructor_ : 1; + + // True if this function is a generator function or async generator. + bool isGenerator_ : 1; + + // True if this function is an async function or async generator. + bool isAsync_ : 1; + + bool hasRest_ : 1; + + // True if the debugger's onNewScript hook has not yet been called. + bool hideScriptFromDebugger_ : 1; + } bitFields_; // Add padding so JSScript is gc::Cell aligned. Make padding protected // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 uint32_t padding_; #endif // // End of fields. Start methods. // + private: + template <js::XDRMode mode> + friend + js::XDRResult + js::XDRScript(js::XDRState<mode>* xdr, js::HandleScope enclosingScope, + js::HandleScriptSourceObject sourceObject, js::HandleFunction fun, + js::MutableHandleScript scriptp); + + friend bool + js::detail::CopyScript(JSContext* cx, js::HandleScript src, js::HandleScript dst, + js::MutableHandle<JS::GCVector<js::Scope*>> scopes); + + private: + JSScript(JS::Realm* realm, uint8_t* stubEntry, const JS::ReadOnlyCompileOptions& options, + js::HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd, + uint32_t toStringStart, uint32_t toStringend); + + static JSScript* createInitialized(JSContext* cx, const JS::ReadOnlyCompileOptions& options, + js::HandleObject sourceObject, + uint32_t bufStart, uint32_t bufEnd, + uint32_t toStringStart, uint32_t toStringEnd); + public: static JSScript* Create(JSContext* cx, const JS::ReadOnlyCompileOptions& options, js::HandleObject sourceObject, uint32_t sourceStart, uint32_t sourceEnd, uint32_t toStringStart, uint32_t toStringEnd); // Three ways ways to initialize a JSScript. Callers of partiallyInit() @@ -1322,234 +1365,236 @@ class JSScript : public js::gc::TenuredC return toStringStart_; } uint32_t toStringEnd() const { return toStringEnd_; } bool noScriptRval() const { - return noScriptRval_; + return bitFields_.noScriptRval_; } bool strict() const { - return strict_; + return bitFields_.strict_; } - bool explicitUseStrict() const { return explicitUseStrict_; } + bool explicitUseStrict() const { return bitFields_.explicitUseStrict_; } bool hasNonSyntacticScope() const { - return hasNonSyntacticScope_; + return bitFields_.hasNonSyntacticScope_; } - bool selfHosted() const { return selfHosted_; } - bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; } + bool selfHosted() const { return bitFields_.selfHosted_; } + bool bindingsAccessedDynamically() const { return bitFields_.bindingsAccessedDynamically_; } bool funHasExtensibleScope() const { - return funHasExtensibleScope_; + return bitFields_.funHasExtensibleScope_; } bool funHasAnyAliasedFormal() const { - return funHasAnyAliasedFormal_; + return bitFields_.funHasAnyAliasedFormal_; } - bool hasSingletons() const { return hasSingletons_; } + bool hasSingletons() const { return bitFields_.hasSingletons_; } bool treatAsRunOnce() const { - return treatAsRunOnce_; + return bitFields_.treatAsRunOnce_; } - bool hasRunOnce() const { return hasRunOnce_; } - bool hasBeenCloned() const { return hasBeenCloned_; } - - void setTreatAsRunOnce() { treatAsRunOnce_ = true; } - void setHasRunOnce() { hasRunOnce_ = true; } - void setHasBeenCloned() { hasBeenCloned_ = true; } - - bool isActiveEval() const { return isActiveEval_; } - bool isCachedEval() const { return isCachedEval_; } + bool hasRunOnce() const { return bitFields_.hasRunOnce_; } + bool hasBeenCloned() const { return bitFields_.hasBeenCloned_; } + + void setTreatAsRunOnce() { bitFields_.treatAsRunOnce_ = true; } + void setHasRunOnce() { bitFields_.hasRunOnce_ = true; } + void setHasBeenCloned() { bitFields_.hasBeenCloned_ = true; } + + bool isActiveEval() const { return bitFields_.isActiveEval_; } + bool isCachedEval() const { return bitFields_.isCachedEval_; } void cacheForEval() { - MOZ_ASSERT(isActiveEval() && !isCachedEval()); - isActiveEval_ = false; - isCachedEval_ = true; + MOZ_ASSERT(isActiveEval()); + MOZ_ASSERT(!isCachedEval()); + bitFields_.isActiveEval_ = false; + bitFields_.isCachedEval_ = true; // IsEvalCacheCandidate will make sure that there's nothing in this // script that would prevent reexecution even if isRunOnce is // true. So just pretend like we never ran this script. - hasRunOnce_ = false; + bitFields_.hasRunOnce_ = false; } void uncacheForEval() { - MOZ_ASSERT(isCachedEval() && !isActiveEval()); - isCachedEval_ = false; - isActiveEval_ = true; + MOZ_ASSERT(isCachedEval()); + MOZ_ASSERT(!isActiveEval()); + bitFields_.isCachedEval_ = false; + bitFields_.isActiveEval_ = true; } - void setActiveEval() { isActiveEval_ = true; } + void setActiveEval() { bitFields_.isActiveEval_ = true; } bool isLikelyConstructorWrapper() const { - return isLikelyConstructorWrapper_; + return bitFields_.isLikelyConstructorWrapper_; } - void setLikelyConstructorWrapper() { isLikelyConstructorWrapper_ = true; } + void setLikelyConstructorWrapper() { bitFields_.isLikelyConstructorWrapper_ = true; } bool failedBoundsCheck() const { - return failedBoundsCheck_; + return bitFields_.failedBoundsCheck_; } bool failedShapeGuard() const { - return failedShapeGuard_; + return bitFields_.failedShapeGuard_; } bool hadFrequentBailouts() const { - return hadFrequentBailouts_; + return bitFields_.hadFrequentBailouts_; } bool hadOverflowBailout() const { - return hadOverflowBailout_; + return bitFields_.hadOverflowBailout_; } bool uninlineable() const { - return uninlineable_; + return bitFields_.uninlineable_; } bool invalidatedIdempotentCache() const { - return invalidatedIdempotentCache_; + return bitFields_.invalidatedIdempotentCache_; } bool failedLexicalCheck() const { - return failedLexicalCheck_; + return bitFields_.failedLexicalCheck_; } bool isDefaultClassConstructor() const { - return isDefaultClassConstructor_; + return bitFields_.isDefaultClassConstructor_; } - void setFailedBoundsCheck() { failedBoundsCheck_ = true; } - void setFailedShapeGuard() { failedShapeGuard_ = true; } - void setHadFrequentBailouts() { hadFrequentBailouts_ = true; } - void setHadOverflowBailout() { hadOverflowBailout_ = true; } - void setUninlineable() { uninlineable_ = true; } - void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; } - void setFailedLexicalCheck() { failedLexicalCheck_ = true; } - void setIsDefaultClassConstructor() { isDefaultClassConstructor_ = true; } - - bool hasScriptCounts() const { return hasScriptCounts_; } + void setFailedBoundsCheck() { bitFields_.failedBoundsCheck_ = true; } + void setFailedShapeGuard() { bitFields_.failedShapeGuard_ = true; } + void setHadFrequentBailouts() { bitFields_.hadFrequentBailouts_ = true; } + void setHadOverflowBailout() { bitFields_.hadOverflowBailout_ = true; } + void setUninlineable() { bitFields_.uninlineable_ = true; } + void setInvalidatedIdempotentCache() { bitFields_.invalidatedIdempotentCache_ = true; } + void setFailedLexicalCheck() { bitFields_.failedLexicalCheck_ = true; } + void setIsDefaultClassConstructor() { bitFields_.isDefaultClassConstructor_ = true; } + + bool hasScriptCounts() const { return bitFields_.hasScriptCounts_; } bool hasScriptName(); - bool hasFreezeConstraints() const { return hasFreezeConstraints_; } - void setHasFreezeConstraints() { hasFreezeConstraints_ = true; } - - bool warnedAboutUndefinedProp() const { return warnedAboutUndefinedProp_; } - void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; } + bool hasFreezeConstraints() const { return bitFields_.hasFreezeConstraints_; } + void setHasFreezeConstraints() { bitFields_.hasFreezeConstraints_ = true; } + + bool warnedAboutUndefinedProp() const { return bitFields_.warnedAboutUndefinedProp_; } + void setWarnedAboutUndefinedProp() { bitFields_.warnedAboutUndefinedProp_ = true; } /* See ContextFlags::funArgumentsHasLocalBinding comment. */ bool argumentsHasVarBinding() const { - return argsHasVarBinding_; + return bitFields_.argsHasVarBinding_; } void setArgumentsHasVarBinding(); bool argumentsAliasesFormals() const { return argumentsHasVarBinding() && hasMappedArgsObj(); } js::GeneratorKind generatorKind() const { - return isGenerator_ ? js::GeneratorKind::Generator : js::GeneratorKind::NotGenerator; + return bitFields_.isGenerator_ ? js::GeneratorKind::Generator : js::GeneratorKind::NotGenerator; } - bool isGenerator() const { return isGenerator_; } + bool isGenerator() const { return bitFields_.isGenerator_; } void setGeneratorKind(js::GeneratorKind kind) { // A script only gets its generator kind set as part of initialization, // so it can only transition from not being a generator. MOZ_ASSERT(!isGenerator()); - isGenerator_ = kind == js::GeneratorKind::Generator; + bitFields_.isGenerator_ = kind == js::GeneratorKind::Generator; } js::FunctionAsyncKind asyncKind() const { - return isAsync_ + return bitFields_.isAsync_ ? js::FunctionAsyncKind::AsyncFunction : js::FunctionAsyncKind::SyncFunction; } bool isAsync() const { - return isAsync_; + return bitFields_.isAsync_; } void setAsyncKind(js::FunctionAsyncKind kind) { - isAsync_ = kind == js::FunctionAsyncKind::AsyncFunction; + bitFields_.isAsync_ = kind == js::FunctionAsyncKind::AsyncFunction; } bool hasRest() const { - return hasRest_; + return bitFields_.hasRest_; } void setHasRest() { - hasRest_ = true; + bitFields_.hasRest_ = true; } bool hideScriptFromDebugger() const { - return hideScriptFromDebugger_; + return bitFields_.hideScriptFromDebugger_; } void clearHideScriptFromDebugger() { - hideScriptFromDebugger_ = false; + bitFields_.hideScriptFromDebugger_ = false; } void setNeedsHomeObject() { - needsHomeObject_ = true; + bitFields_.needsHomeObject_ = true; } bool needsHomeObject() const { - return needsHomeObject_; + return bitFields_.needsHomeObject_; } bool isDerivedClassConstructor() const { - return isDerivedClassConstructor_; + return bitFields_.isDerivedClassConstructor_; } /* * As an optimization, even when argsHasLocalBinding, the function prologue * may not need to create an arguments object. This is determined by * needsArgsObj which is set by AnalyzeArgumentsUsage. When !needsArgsObj, * the prologue may simply write MagicValue(JS_OPTIMIZED_ARGUMENTS) to * 'arguments's slot and any uses of 'arguments' will be guaranteed to * handle this magic value. To avoid spurious arguments object creation, we * maintain the invariant that needsArgsObj is only called after the script * has been analyzed. */ - bool analyzedArgsUsage() const { return !needsArgsAnalysis_; } + bool analyzedArgsUsage() const { return !bitFields_.needsArgsAnalysis_; } inline bool ensureHasAnalyzedArgsUsage(JSContext* cx); bool needsArgsObj() const { MOZ_ASSERT(analyzedArgsUsage()); - return needsArgsObj_; + return bitFields_.needsArgsObj_; } void setNeedsArgsObj(bool needsArgsObj); static bool argumentsOptimizationFailed(JSContext* cx, js::HandleScript script); bool hasMappedArgsObj() const { - return hasMappedArgsObj_; + return bitFields_.hasMappedArgsObj_; } bool functionHasThisBinding() const { - return functionHasThisBinding_; + return bitFields_.functionHasThisBinding_; } /* * Arguments access (via JSOP_*ARG* opcodes) must access the canonical * location for the argument. If an arguments object exists AND it's mapped * ('arguments' aliases formals), then all access must go through the * arguments object. Otherwise, the local slot is the canonical location for * the arguments. Note: if a formal is aliased through the scope chain, then * script->formalIsAliased and JSOP_*ARG* opcodes won't be emitted at all. */ bool argsObjAliasesFormals() const { return needsArgsObj() && hasMappedArgsObj(); } uint32_t typesGeneration() const { - return (uint32_t) typesGeneration_; + return (uint32_t) bitFields_.typesGeneration_; } void setTypesGeneration(uint32_t generation) { MOZ_ASSERT(generation <= 1); - typesGeneration_ = (bool) generation; + bitFields_.typesGeneration_ = (bool) generation; } void setDoNotRelazify(bool b) { - doNotRelazify_ = b; + bitFields_.doNotRelazify_ = b; } void setHasInnerFunctions(bool b) { - hasInnerFunctions_ = b; + bitFields_.hasInnerFunctions_ = b; } bool hasInnerFunctions() const { - return hasInnerFunctions_; + return bitFields_.hasInnerFunctions_; } bool hasAnyIonScript() const { return hasIonScript(); } bool hasIonScript() const { bool res = ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT && @@ -1604,21 +1649,21 @@ class JSScript : public js::gc::TenuredC static constexpr size_t offsetOfJitCodeSkipArgCheck() { return offsetof(JSScript, jitCodeSkipArgCheck_); } uint8_t* jitCodeRaw() const { return jitCodeRaw_; } bool isRelazifiable() const { - return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ && + return (selfHosted() || lazyScript) && !bitFields_.hasInnerFunctions_ && !types_ && !isGenerator() && !isAsync() && !isDefaultClassConstructor() && !hasBaselineScript() && !hasAnyIonScript() && - !doNotRelazify_; + !bitFields_.doNotRelazify_; } void setLazyScript(js::LazyScript* lazy) { lazyScript = lazy; } js::LazyScript* maybeLazyScript() { return lazyScript; } @@ -1734,18 +1779,18 @@ class JSScript : public js::gc::TenuredC js::Scope* outermostScope() const { // The body scope may not be the outermost scope in the script when // the decl env scope is present. size_t index = 0; return getScope(index); } bool functionHasExtraBodyVarScope() const { - MOZ_ASSERT_IF(functionHasExtraBodyVarScope_, functionHasParameterExprs()); - return functionHasExtraBodyVarScope_; + MOZ_ASSERT_IF(bitFields_.functionHasExtraBodyVarScope_, functionHasParameterExprs()); + return bitFields_.functionHasExtraBodyVarScope_; } js::VarScope* functionExtraBodyVarScope() const { MOZ_ASSERT(functionHasExtraBodyVarScope()); for (uint32_t i = 0; i < scopes()->length; i++) { js::Scope* scope = getScope(i); if (scope->kind() == js::ScopeKind::FunctionBodyVar) return &scope->as<js::VarScope>(); @@ -1815,20 +1860,22 @@ class JSScript : public js::gc::TenuredC * sizeOfData() is the size of the block allocated to hold all the data * sections (which can be larger than the in-use size). */ size_t computedSizeOfData() const; size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const; size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const; bool hasArray(ArrayKind kind) const { - return hasArrayBits & (1 << kind); + return bitFields_.hasArrayBits_ & (1 << kind); } - void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); } - void cloneHasArray(JSScript* script) { hasArrayBits = script->hasArrayBits; } + void setHasArray(ArrayKind kind) { bitFields_.hasArrayBits_ |= (1 << kind); } + void cloneHasArray(JSScript* script) { + bitFields_.hasArrayBits_ = script->bitFields_.hasArrayBits_; + } bool hasConsts() const { return hasArray(CONSTS); } bool hasObjects() const { return hasArray(OBJECTS); } bool hasTrynotes() const { return hasArray(TRYNOTES); } bool hasScopeNotes() const { return hasArray(SCOPENOTES); } bool hasYieldAndAwaitOffsets() const { return isGenerator() || isAsync(); } @@ -1993,25 +2040,25 @@ class JSScript : public js::gc::TenuredC bool ensureHasDebugScript(JSContext* cx); js::DebugScript* debugScript(); js::DebugScript* releaseDebugScript(); void destroyDebugScript(js::FreeOp* fop); public: bool hasBreakpointsAt(jsbytecode* pc); - bool hasAnyBreakpointsOrStepMode() { return hasDebugScript_; } + bool hasAnyBreakpointsOrStepMode() { return bitFields_.hasDebugScript_; } // See comment above 'debugMode' in JSCompartment.h for explanation of // invariants of debuggee compartments, scripts, and frames. inline bool isDebuggee() const; js::BreakpointSite* getBreakpointSite(jsbytecode* pc) { - return hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr; + return bitFields_.hasDebugScript_ ? debugScript()->breakpoints[pcToOffset(pc)] : nullptr; } js::BreakpointSite* getOrCreateBreakpointSite(JSContext* cx, jsbytecode* pc); void destroyBreakpointSite(js::FreeOp* fop, jsbytecode* pc); void clearBreakpointsIn(js::FreeOp* fop, js::Debugger* dbg, JSObject* handler); @@ -2019,20 +2066,20 @@ class JSScript : public js::gc::TenuredC * Increment or decrement the single-step count. If the count is non-zero * then the script is in single-step mode. * * Only incrementing is fallible, as it could allocate a DebugScript. */ bool incrementStepModeCount(JSContext* cx); void decrementStepModeCount(js::FreeOp* fop); - bool stepModeEnabled() { return hasDebugScript_ && !!debugScript()->stepMode; } + bool stepModeEnabled() { return bitFields_.hasDebugScript_ && !!debugScript()->stepMode; } #ifdef DEBUG - uint32_t stepModeCount() { return hasDebugScript_ ? debugScript()->stepMode : 0; } + uint32_t stepModeCount() { return bitFields_.hasDebugScript_ ? debugScript()->stepMode : 0; } #endif void finalize(js::FreeOp* fop); static const JS::TraceKind TraceKind = JS::TraceKind::Script; void traceChildren(JSTracer* trc);
--- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -4541,32 +4541,32 @@ JSScript::sweepTypes(const js::AutoSweep !hasBaselineScript() && !hasIonScript()) { types_->destroy(); types_ = nullptr; // Freeze constraints on stack type sets need to be regenerated the // next time the script is analyzed. - hasFreezeConstraints_ = false; + bitFields_.hasFreezeConstraints_ = false; return; } unsigned num = TypeScript::NumTypeSets(this); StackTypeSet* typeArray = types_->typeArray(); // Remove constraints and references to dead objects from stack type sets. for (unsigned i = 0; i < num; i++) typeArray[i].sweep(sweep, zone(), *oom); if (oom->hadOOM()) { // It's possible we OOM'd while copying freeze constraints, so they // need to be regenerated. - hasFreezeConstraints_ = false; + bitFields_.hasFreezeConstraints_ = false; } } void TypeScript::destroy() { js_delete(this); }