Bug 1485347 - Part 5: Use js::PrivateScriptData for JSScript. r=jandem

- This makes JSScript::data arrays read-only. Initialization code
 directly uses PrivateScriptData to mutate.

MozReview-Commit-ID: LJFc8QazLfq
This commit is contained in:
Ted Campbell 2018-08-23 20:27:58 -04:00
Родитель 1b0db8ce6d
Коммит 19dbe58e02
3 изменённых файлов: 82 добавлений и 418 удалений

Просмотреть файл

@ -796,7 +796,7 @@ BaselineScript::computeYieldAndAwaitNativeOffsets(JSScript* script)
return nativeCode;
};
mozilla::Span<uint32_t> pcOffsets = script->yieldAndAwaitOffsets();
mozilla::Span<const uint32_t> pcOffsets = script->yieldAndAwaitOffsets();
uint8_t** nativeOffsets = yieldEntryList();
std::transform(pcOffsets.begin(), pcOffsets.end(), nativeOffsets, computeNative);
}

Просмотреть файл

@ -414,13 +414,13 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
nsrcnotes = script->numNotes();
nscopes = script->scopes().size();
if (script->hasConsts()) {
nconsts = script->consts().size();
}
if (script->hasObjects()) {
nobjects = script->objects().size();
}
nscopes = script->scopes().size();
if (script->hasTrynotes()) {
ntrynotes = script->trynotes().size();
}
@ -732,9 +732,11 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
}
}
js::PrivateScriptData* data = script->data_;
if (nconsts) {
RootedValue val(cx);
for (GCPtrValue& elem : script->consts()) {
for (GCPtrValue& elem : data->consts()) {
if (mode == XDR_ENCODE) {
val = elem.get();
}
@ -747,7 +749,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
{
MOZ_ASSERT(nscopes != 0);
GCPtrScope* vector = script->scopes().data();
GCPtrScope* vector = data->scopes().data();
RootedScope scope(cx);
RootedScope enclosing(cx);
ScopeKind scopeKind;
@ -844,7 +846,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
* after the enclosing block has been XDR'd.
*/
if (nobjects) {
for (GCPtrObject& elem : script->objects()) {
for (GCPtrObject& elem : data->objects()) {
XDRClassKind classk;
if (mode == XDR_ENCODE) {
@ -939,7 +941,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
MOZ_TRY(xdr->codeMarker(0xF83B989A));
if (ntrynotes) {
for (JSTryNote& elem : script->trynotes()) {
for (JSTryNote& elem : data->tryNotes()) {
MOZ_TRY(xdr->codeUint8(&elem.kind));
MOZ_TRY(xdr->codeUint32(&elem.stackDepth));
MOZ_TRY(xdr->codeUint32(&elem.start));
@ -948,7 +950,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
}
if (nscopenotes) {
for (ScopeNote& elem : script->scopeNotes()) {
for (ScopeNote& elem : data->scopeNotes()) {
MOZ_TRY(xdr->codeUint32(&elem.index));
MOZ_TRY(xdr->codeUint32(&elem.start));
MOZ_TRY(xdr->codeUint32(&elem.length));
@ -957,7 +959,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
}
if (nyieldoffsets) {
for (uint32_t& elem : script->yieldAndAwaitOffsets()) {
for (uint32_t& elem : data->yieldAndAwaitOffsets()) {
MOZ_TRY(xdr->codeUint32(&elem));
}
}
@ -3239,125 +3241,6 @@ PrivateScriptData::traceChildren(JSTracer* trc)
}
}
/*
* [SMDOC] JSScript data layout (unshared)
*
* JSScript::data and SharedScriptData::data have complex,
* manually-controlled, memory layouts.
*
* JSScript::data begins with some optional array headers. They are optional
* because they often aren't needed, i.e. the corresponding arrays often have
* zero elements. Each header has a bit in JSScript::hasArrayBits that
* indicates if it's present within |data|; from this the offset of each
* present array header can be computed. Each header has an accessor function
* in JSScript that encapsulates this offset computation.
*
* Array type Array elements Accessor
* ---------- -------------- --------
* ConstArray Consts consts()
* ObjectArray Objects objects()
* ObjectArray Regexps regexps()
* TryNoteArray Try notes trynotes()
* ScopeNoteArray Scope notes scopeNotes()
*
* Then are the elements of several arrays.
* - Most of these arrays have headers listed above (if present). For each of
* these, the array pointer and the array length is stored in the header.
* - The remaining arrays have pointers and lengths that are stored directly in
* JSScript. This is because, unlike the others, they are nearly always
* non-zero length and so the optional-header space optimization isn't
* worthwhile.
*
* Array elements Pointed to by Length
* -------------- ------------- ------
* Consts consts()->vector consts()->length
* Objects objects()->vector objects()->length
* Regexps regexps()->vector regexps()->length
* Try notes trynotes()->vector trynotes()->length
* Scope notes scopeNotes()->vector scopeNotes()->length
*
* IMPORTANT: This layout has two key properties.
* - It ensures that everything has sufficient alignment; in particular, the
* consts() elements need Value alignment.
* - It ensures there are no gaps between elements, which saves space and makes
* manual layout easy. In particular, in the second part, arrays with larger
* elements precede arrays with smaller elements.
*
* The following static assertions check JSScript::data's alignment properties.
*/
template<class T>
constexpr bool
KeepsValueAlignment() {
return alignof(JS::Value) % alignof(T) == 0 &&
sizeof(T) % sizeof(JS::Value) == 0;
}
template<class T>
constexpr bool
HasValueAlignment() {
return alignof(JS::Value) == alignof(T) &&
sizeof(T) == sizeof(JS::Value);
}
template<class T1, class T2>
constexpr bool
NoPaddingBetweenEntries() {
return alignof(T1) % alignof(T2) == 0;
}
/*
* These assertions ensure that there is no padding between the array headers,
* and also that the consts() elements (which follow immediately afterward) are
* Value-aligned. (There is an assumption that |data| itself is Value-aligned;
* we check this below).
*/
JS_STATIC_ASSERT(KeepsValueAlignment<ConstArray>());
JS_STATIC_ASSERT(KeepsValueAlignment<ObjectArray>()); /* there are two of these */
JS_STATIC_ASSERT(KeepsValueAlignment<TryNoteArray>());
JS_STATIC_ASSERT(KeepsValueAlignment<ScopeNoteArray>());
/* These assertions ensure there is no padding required between array elements. */
JS_STATIC_ASSERT(HasValueAlignment<GCPtrValue>());
JS_STATIC_ASSERT((NoPaddingBetweenEntries<GCPtrValue, GCPtrObject>()));
JS_STATIC_ASSERT((NoPaddingBetweenEntries<GCPtrObject, GCPtrObject>()));
JS_STATIC_ASSERT((NoPaddingBetweenEntries<GCPtrObject, JSTryNote>()));
JS_STATIC_ASSERT((NoPaddingBetweenEntries<JSTryNote, uint32_t>()));
JS_STATIC_ASSERT((NoPaddingBetweenEntries<uint32_t, uint32_t>()));
JS_STATIC_ASSERT((NoPaddingBetweenEntries<GCPtrValue, ScopeNote>()));
JS_STATIC_ASSERT((NoPaddingBetweenEntries<ScopeNote, ScopeNote>()));
JS_STATIC_ASSERT((NoPaddingBetweenEntries<JSTryNote, ScopeNote>()));
JS_STATIC_ASSERT((NoPaddingBetweenEntries<GCPtrObject, ScopeNote>()));
JS_STATIC_ASSERT((NoPaddingBetweenEntries<ScopeNote, uint32_t>()));
static inline size_t
ScriptDataSize(uint32_t nscopes, uint32_t nconsts, uint32_t nobjects,
uint32_t ntrynotes, uint32_t nscopenotes, uint32_t nyieldoffsets)
{
size_t size = 0;
MOZ_ASSERT(nscopes != 0);
size += sizeof(ScopeArray) + nscopes * sizeof(Scope*);
if (nconsts != 0) {
size += sizeof(ConstArray) + nconsts * sizeof(Value);
}
if (nobjects != 0) {
size += sizeof(ObjectArray) + nobjects * sizeof(NativeObject*);
}
if (ntrynotes != 0) {
size += sizeof(TryNoteArray) + ntrynotes * sizeof(JSTryNote);
}
if (nscopenotes != 0) {
size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote);
}
if (nyieldoffsets != 0) {
size += sizeof(YieldAndAwaitOffsetArray) + nyieldoffsets * sizeof(uint32_t);
}
return size;
}
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)
@ -3491,92 +3374,16 @@ JSScript::partiallyInit(JSContext* cx, HandleScript script, uint32_t nscopes,
{
cx->check(script);
size_t size = ScriptDataSize(nscopes, nconsts, nobjects, ntrynotes,
nscopenotes, nyieldoffsets);
script->data = AllocScriptData(cx, size);
if (size && !script->data) {
uint32_t dataSize;
PrivateScriptData* data = PrivateScriptData::new_(cx, nscopes, nconsts, nobjects, ntrynotes,
nscopenotes, nyieldoffsets, &dataSize);
if (!data) {
return false;
}
script->dataSize_ = size;
uint8_t* cursor = script->data;
// There must always be at least 1 scope, the body scope.
MOZ_ASSERT(nscopes != 0);
cursor += sizeof(ScopeArray);
if (nconsts != 0) {
script->setHasArray(CONSTS);
cursor += sizeof(ConstArray);
}
if (nobjects != 0) {
script->setHasArray(OBJECTS);
cursor += sizeof(ObjectArray);
}
if (ntrynotes != 0) {
script->setHasArray(TRYNOTES);
cursor += sizeof(TryNoteArray);
}
if (nscopenotes != 0) {
script->setHasArray(SCOPENOTES);
cursor += sizeof(ScopeNoteArray);
}
YieldAndAwaitOffsetArray* yieldAndAwaitOffsets = nullptr;
if (nyieldoffsets != 0) {
yieldAndAwaitOffsets = reinterpret_cast<YieldAndAwaitOffsetArray*>(cursor);
cursor += sizeof(YieldAndAwaitOffsetArray);
}
if (nconsts != 0) {
MOZ_ASSERT(reinterpret_cast<uintptr_t>(cursor) % sizeof(JS::Value) == 0);
script->constsRaw()->length = nconsts;
script->constsRaw()->vector = (GCPtrValue*)cursor;
cursor += nconsts * sizeof(script->constsRaw()->vector[0]);
}
script->scopesRaw()->length = nscopes;
script->scopesRaw()->vector = (GCPtrScope*)cursor;
cursor += nscopes * sizeof(script->scopesRaw()->vector[0]);
if (nobjects != 0) {
script->objectsRaw()->length = nobjects;
script->objectsRaw()->vector = (GCPtrObject*)cursor;
cursor += nobjects * sizeof(script->objectsRaw()->vector[0]);
}
if (ntrynotes != 0) {
script->trynotesRaw()->length = ntrynotes;
script->trynotesRaw()->vector = reinterpret_cast<JSTryNote*>(cursor);
size_t vectorSize = ntrynotes * sizeof(script->trynotesRaw()->vector[0]);
#ifdef DEBUG
memset(cursor, 0, vectorSize);
#endif
cursor += vectorSize;
}
if (nscopenotes != 0) {
script->scopeNotesRaw()->length = nscopenotes;
script->scopeNotesRaw()->vector = reinterpret_cast<ScopeNote*>(cursor);
size_t vectorSize = nscopenotes * sizeof(script->scopeNotesRaw()->vector[0]);
#ifdef DEBUG
memset(cursor, 0, vectorSize);
#endif
cursor += vectorSize;
}
if (nyieldoffsets != 0) {
yieldAndAwaitOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
size_t vectorSize = nyieldoffsets * sizeof(script->yieldAndAwaitOffsetsRaw()[0]);
#ifdef DEBUG
memset(cursor, 0, vectorSize);
#endif
cursor += vectorSize;
}
MOZ_ASSERT(cursor == script->data + size);
script->data_ = data;
script->dataSize_ = dataSize;
return true;
}
@ -3604,7 +3411,9 @@ JSScript::initFunctionPrototype(JSContext* cx, Handle<JSScript*> script,
if (!functionProtoScope) {
return false;
}
script->scopesRaw()->vector[0].init(functionProtoScope);
js::PrivateScriptData* data = script->data_;
data->scopes()[0].init(functionProtoScope);
uint32_t codeLength = 1;
uint32_t srcNotesLength = 1;
@ -3742,21 +3551,23 @@ JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script, frontend::Byt
return false;
}
js::PrivateScriptData* data = script->data_;
if (bce->numberList.length() != 0) {
bce->numberList.finish(script->consts());
bce->numberList.finish(data->consts());
}
if (bce->objectList.length != 0) {
bce->objectList.finish(script->objects());
bce->objectList.finish(data->objects());
}
if (bce->scopeList.length() != 0) {
bce->scopeList.finish(script->scopes());
bce->scopeList.finish(data->scopes());
}
if (bce->tryNoteList.length() != 0) {
bce->tryNoteList.finish(script->trynotes(), prologueLength);
bce->tryNoteList.finish(data->tryNotes(), prologueLength);
}
if (bce->scopeNoteList.length() != 0) {
bce->scopeNoteList.finish(script->scopeNotes(), prologueLength);
bce->scopeNoteList.finish(data->scopeNotes(), prologueLength);
}
script->bitFields_.strict_ = bce->sc->strict();
script->bitFields_.explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
script->bitFields_.bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
@ -3780,7 +3591,7 @@ JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script, frontend::Byt
// Copy yield offsets last, as the generator kind is set in
// initFromFunctionBox.
if (bce->yieldAndAwaitOffsetList.length() != 0) {
bce->yieldAndAwaitOffsetList.finish(script->yieldAndAwaitOffsets(), prologueLength);
bce->yieldAndAwaitOffsetList.finish(data->yieldAndAwaitOffsets(), prologueLength);
}
#ifdef DEBUG
@ -3861,7 +3672,7 @@ JSScript::computedSizeOfData() const
size_t
JSScript::sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const
{
return mallocSizeOf(data);
return mallocSizeOf(data_);
}
size_t
@ -3903,9 +3714,9 @@ JSScript::finalize(FreeOp* fop)
destroyScriptCounts();
destroyDebugScript(fop);
if (data) {
JS_POISON(data, 0xdb, computedSizeOfData(), MemCheckKind::MakeNoAccess);
fop->free_(data);
if (data_) {
JS_POISON(data_, 0xdb, computedSizeOfData(), MemCheckKind::MakeNoAccess);
fop->free_(data_);
}
if (scriptData_) {
@ -4157,14 +3968,6 @@ js::DescribeScriptedCallerForCompilation(JSContext* cx, MutableHandleScript mayb
}
}
template <class T>
static inline T*
Rebase(JSScript* dst, JSScript* src, T* srcp)
{
size_t off = reinterpret_cast<uint8_t*>(srcp) - src->data;
return reinterpret_cast<T*>(dst->data + off);
}
static JSObject*
CloneInnerInterpretedFunction(JSContext* cx, HandleScope enclosingScope, HandleFunction srcFun)
{
@ -4227,18 +4030,17 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
/* Some embeddings are not careful to use ExposeObjectToActiveJS as needed. */
MOZ_ASSERT(!src->sourceObject()->isMarkedGray());
uint32_t nconsts = src->hasConsts() ? src->consts().size() : 0;
uint32_t nobjects = src->hasObjects() ? src->objects().size() : 0;
uint32_t nscopes = src->scopes().size();
uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes().size() : 0;
uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes().size() : 0;
uint32_t nyieldoffsets = src->hasYieldAndAwaitOffsets() ? src->yieldAndAwaitOffsets().size() : 0;
#ifdef DEBUG
uint32_t nconsts = src->hasConsts() ? src->consts().size() : 0;
#endif
uint32_t nobjects = src->hasObjects() ? src->objects().size() : 0;
/* Script data */
size_t size = src->dataSize();
UniquePtr<uint8_t, JS::FreePolicy> data(AllocScriptData(cx, size));
if (size && !data) {
if (!data) {
return false;
}
@ -4304,13 +4106,9 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
}
}
/* This assignment must occur before all the Rebase calls. */
dst->data = data.release();
dst->data_ = reinterpret_cast<js::PrivateScriptData*>(data.release());
dst->dataSize_ = size;
MOZ_ASSERT(bool(dst->data) == bool(src->data));
if (dst->data) {
memcpy(dst->data, src->data, size);
}
memcpy(dst->data_, src->data_, size);
if (cx->zone() != src->zoneFromAnyThread()) {
for (size_t i = 0; i < src->scriptData()->natoms(); i++) {
@ -4337,7 +4135,6 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
dst->bitFields_.hasMappedArgsObj_ = src->hasMappedArgsObj();
dst->bitFields_.functionHasThisBinding_ = src->functionHasThisBinding();
dst->bitFields_.functionHasExtraBodyVarScope_ = src->functionHasExtraBodyVarScope();
dst->cloneHasArray(src);
dst->bitFields_.strict_ = src->strict();
dst->bitFields_.explicitUseStrict_ = src->explicitUseStrict();
dst->bitFields_.hasNonSyntacticScope_ = scopes[0]->hasOnChain(ScopeKind::NonSyntactic);
@ -4355,38 +4152,27 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
dst->bitFields_.hasRest_ = src->bitFields_.hasRest_;
dst->bitFields_.hideScriptFromDebugger_ = src->bitFields_.hideScriptFromDebugger_;
if (nconsts != 0) {
GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->constsRaw()->vector);
dst->constsRaw()->vector = vector;
{
auto array = dst->data_->scopes();
for (uint32_t i = 0; i < nscopes; ++i) {
array[i].init(scopes[i]);
}
}
#ifdef DEBUG
if (nconsts) {
auto array = dst->data_->consts();
for (unsigned i = 0; i < nconsts; ++i) {
// We don't support GCThings here and thus don't need to call |init|.
MOZ_ASSERT(!vector[i].isGCThing());
MOZ_ASSERT(!array[i].isGCThing());
}
}
if (nobjects != 0) {
GCPtrObject* vector = Rebase<GCPtrObject>(dst, src, src->objectsRaw()->vector);
dst->objectsRaw()->vector = vector;
#endif
if (nobjects) {
auto array = dst->data_->objects();
for (unsigned i = 0; i < nobjects; ++i) {
vector[i].init(&objects[i]->as<NativeObject>());
array[i].init(objects[i]);
}
}
{
GCPtrScope* vector = Rebase<GCPtrScope>(dst, src, src->scopesRaw()->vector);
dst->scopesRaw()->vector = vector;
for (uint32_t i = 0; i < nscopes; ++i) {
vector[i].init(scopes[i]);
}
}
if (ntrynotes != 0) {
dst->trynotesRaw()->vector = Rebase<JSTryNote>(dst, src, src->trynotesRaw()->vector);
}
if (nscopenotes != 0) {
dst->scopeNotesRaw()->vector = Rebase<ScopeNote>(dst, src, src->scopeNotesRaw()->vector);
}
if (nyieldoffsets != 0) {
dst->yieldAndAwaitOffsetsRaw().vector_ =
Rebase<uint32_t>(dst, src, src->yieldAndAwaitOffsetsRaw().vector_);
}
return true;
}
@ -4730,25 +4516,14 @@ JSScript::traceChildren(JSTracer* trc)
GCMarker::fromTracer(trc)->shouldCheckCompartments(),
zone()->isCollecting());
if (data_) {
data_->traceChildren(trc);
}
if (scriptData()) {
scriptData()->traceChildren(trc);
}
if (data) {
auto array = scopes();
TraceRange(trc, array.size(), array.data(), "scopes");
}
if (hasConsts()) {
auto array = consts();
TraceRange(trc, array.size(), array.data(), "consts");
}
if (hasObjects()) {
auto array = objects();
TraceRange(trc, array.size(), array.data(), "objects");
}
MOZ_ASSERT_IF(sourceObject(), MaybeForwarded(sourceObject())->compartment() == compartment());
TraceNullableEdge(trc, &sourceObject_, "sourceObject");

Просмотреть файл

@ -147,53 +147,6 @@ struct ScopeNote {
uint32_t parent; // Index of parent block scope in notes, or NoScopeNote.
};
struct ConstArray {
js::GCPtrValue* vector; // array of indexed constant values
uint32_t length;
};
struct ObjectArray {
js::GCPtrObject* vector; // Array of indexed objects.
uint32_t length; // Count of indexed objects.
};
struct ScopeArray {
js::GCPtrScope* vector; // Array of indexed scopes.
uint32_t length; // Count of indexed scopes.
};
struct TryNoteArray {
JSTryNote* vector; // Array of indexed try notes.
uint32_t length; // Count of indexed try notes.
};
struct ScopeNoteArray {
ScopeNote* vector; // Array of indexed ScopeNote records.
uint32_t length; // Count of indexed try notes.
};
class YieldAndAwaitOffsetArray {
friend bool
detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
MutableHandle<GCVector<Scope*>> scopes);
uint32_t* vector_; // Array of bytecode offsets.
uint32_t length_; // Count of bytecode offsets.
public:
void init(uint32_t* vector, uint32_t length) {
vector_ = vector;
length_ = length;
}
uint32_t& operator[](uint32_t index) {
MOZ_ASSERT(index < length_);
return vector_[index];
}
uint32_t length() const {
return length_;
}
};
class ScriptCounts
{
public:
@ -1580,13 +1533,13 @@ class JSScript : public js::gc::TenuredCell
uint8_t* jitCodeRaw_ = nullptr;
uint8_t* jitCodeSkipArgCheck_ = nullptr;
// Shareable script data
js::SharedScriptData* scriptData_ = nullptr;
public:
// Pointer to variable-length data array (see comment above Create() for
// details).
uint8_t* data = nullptr;
// Unshared variable-length data
js::PrivateScriptData* data_ = nullptr;
public:
JS::Realm* realm_ = nullptr;
private:
@ -1715,14 +1668,6 @@ class JSScript : public js::gc::TenuredCell
* 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;
@ -2568,99 +2513,43 @@ class JSScript : public js::gc::TenuredCell
size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const;
size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
bool hasArray(ArrayKind kind) const {
return bitFields_.hasArrayBits_ & (1 << kind);
}
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();
}
#define OFF(fooOff, hasFoo, t) (fooOff() + (hasFoo() ? sizeof(t) : 0))
size_t scopesOffset() const { return 0; }
size_t constsOffset() const { return scopesOffset() + sizeof(js::ScopeArray); }
size_t objectsOffset() const { return OFF(constsOffset, hasConsts, js::ConstArray); }
size_t trynotesOffset() const { return OFF(objectsOffset, hasObjects, js::ObjectArray); }
size_t scopeNotesOffset() const { return OFF(trynotesOffset, hasTrynotes, js::TryNoteArray); }
size_t yieldAndAwaitOffsetsOffset() const {
return OFF(scopeNotesOffset, hasScopeNotes, js::ScopeNoteArray);
}
#undef OFF
size_t dataSize() const { return dataSize_; }
private:
bool hasConsts() const { return data_->hasConsts(); }
bool hasObjects() const { return data_->hasObjects(); }
bool hasTrynotes() const { return data_->hasTryNotes(); }
bool hasScopeNotes() const { return data_->hasScopeNotes(); }
bool hasYieldAndAwaitOffsets() const {
return data_->hasYieldOffsets();
}
js::ConstArray* constsRaw() const {
mozilla::Span<const js::GCPtrScope> scopes() const {
return data_->scopes();
}
mozilla::Span<const js::GCPtrValue> consts() const {
MOZ_ASSERT(hasConsts());
return reinterpret_cast<js::ConstArray*>(data + constsOffset());
return data_->consts();
}
js::ObjectArray* objectsRaw() const {
mozilla::Span<const js::GCPtrObject> objects() const {
MOZ_ASSERT(hasObjects());
return reinterpret_cast<js::ObjectArray*>(data + objectsOffset());
return data_->objects();
}
js::ScopeArray* scopesRaw() const {
return reinterpret_cast<js::ScopeArray*>(data + scopesOffset());
}
js::TryNoteArray* trynotesRaw() const {
mozilla::Span<const JSTryNote> trynotes() const {
MOZ_ASSERT(hasTrynotes());
return reinterpret_cast<js::TryNoteArray*>(data + trynotesOffset());
return data_->tryNotes();
}
js::ScopeNoteArray* scopeNotesRaw() const {
mozilla::Span<const js::ScopeNote> scopeNotes() const {
MOZ_ASSERT(hasScopeNotes());
return reinterpret_cast<js::ScopeNoteArray*>(data + scopeNotesOffset());
return data_->scopeNotes();
}
js::YieldAndAwaitOffsetArray& yieldAndAwaitOffsetsRaw() const {
mozilla::Span<const uint32_t> yieldAndAwaitOffsets() const {
MOZ_ASSERT(hasYieldAndAwaitOffsets());
return *reinterpret_cast<js::YieldAndAwaitOffsetArray*>(data +
yieldAndAwaitOffsetsOffset());
}
public:
mozilla::Span<js::GCPtrValue> consts() const {
js::ConstArray* array = constsRaw();
return mozilla::MakeSpan(array->vector, array->length);
}
mozilla::Span<js::GCPtrObject> objects() const {
js::ObjectArray* array = objectsRaw();
return mozilla::MakeSpan(array->vector, array->length);
}
mozilla::Span<js::GCPtrScope> scopes() const {
js::ScopeArray* array = scopesRaw();
return mozilla::MakeSpan(array->vector, array->length);
}
mozilla::Span<JSTryNote> trynotes() const {
js::TryNoteArray* array = trynotesRaw();
return mozilla::MakeSpan(array->vector, array->length);
}
mozilla::Span<js::ScopeNote> scopeNotes() const {
js::ScopeNoteArray* array = scopeNotesRaw();
return mozilla::MakeSpan(array->vector, array->length);
}
mozilla::Span<uint32_t> yieldAndAwaitOffsets() const {
js::YieldAndAwaitOffsetArray& array = yieldAndAwaitOffsetsRaw();
return mozilla::MakeSpan(&array[0], array.length());
return data_->yieldAndAwaitOffsets();
}
bool hasLoops();