Bug 1615143 - Move JSScript::lazyScript / LazyScript::script_ to BaseScript. r=jandem

This patch creates a union field in BaseScript to hold either form of
pointer. An IsLazyScript flag is added to ImmutableFlags to know which union
arm to trace. We are also able to use a single trace function for both.
IsLazyScript flag to disambiguate the union arms.

Note that this field will be removed entirely once the JSScript and
LazyScript instances are merged.

Differential Revision: https://phabricator.services.mozilla.com/D62680

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ted Campbell 2020-02-13 14:32:39 +00:00
Родитель cd00e1a950
Коммит 432b2a7b18
5 изменённых файлов: 60 добавлений и 59 удалений

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

@ -937,10 +937,13 @@ static void CheckFlagsOnDelazification(uint32_t lazy, uint32_t nonLazy) {
// These flags are computed for lazy scripts and may have a different
// definition for non-lazy scripts.
//
// IsLazyScript: This flag will be removed in Bug 1529456.
//
// TreatAsRunOnce: Some conditions depend on parent context and are
// computed during lazy parsing, while other conditions
// need to full parse.
constexpr uint32_t CustomFlagsMask =
uint32_t(BaseScript::ImmutableFlags::IsLazyScript) |
uint32_t(BaseScript::ImmutableFlags::TreatAsRunOnce);
// These flags are expected to match between lazy and full parsing.

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

@ -4918,7 +4918,7 @@ void js::gc::SweepLazyScripts(GCParallelTask* task) {
for (SweepGroupZonesIter zone(task->gc); !zone.done(); zone.next()) {
AutoSetThreadIsSweeping threadIsSweeping(zone);
for (auto i = zone->cellIter<LazyScript>(); !i.done(); i.next()) {
WeakHeapPtrScript* edge = &i.unbarrieredGet()->script_;
WeakHeapPtrScript* edge = &i.unbarrieredGet()->u.script_;
if (*edge && IsAboutToBeFinalized(edge)) {
*edge = nullptr;
}

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

@ -750,20 +750,15 @@ struct ImplicitEdgeHolderType {
// For now, we only handle JSObject* and JSScript* keys, but the linear time
// algorithm can be easily extended by adding in more types here, then making
// GCMarker::traverse<T> call markPotentialEphemeronKey.
// GCMarker::traverse<T> call markImplicitEdges.
template <>
struct ImplicitEdgeHolderType<JSObject*> {
typedef JSObject* Type;
};
template <>
struct ImplicitEdgeHolderType<JSScript*> {
typedef JSScript* Type;
};
template <>
struct ImplicitEdgeHolderType<LazyScript*> {
typedef LazyScript* Type;
struct ImplicitEdgeHolderType<BaseScript*> {
typedef BaseScript* Type;
};
void GCMarker::markEphemeronValues(gc::Cell* markedCell,
@ -809,8 +804,7 @@ void GCMarker::markImplicitEdges(T* thing) {
}
template void GCMarker::markImplicitEdges(JSObject*);
template void GCMarker::markImplicitEdges(JSScript*);
template void GCMarker::markImplicitEdges(LazyScript*);
template void GCMarker::markImplicitEdges(BaseScript*);
} // namespace js
@ -1135,19 +1129,24 @@ void BaseScript::traceChildren(JSTracer* trc) {
DebugAPI::traceDebugScript(trc, script);
}
}
}
void LazyScript::traceChildren(JSTracer* trc) {
BaseScript::traceChildren(trc);
if (trc->traceWeakEdges()) {
TraceNullableEdge(trc, &script_, "script");
// Trace the edge to our twin. Note that it will have the opposite type of
// current script.
if (isLazyScript()) {
if (trc->traceWeakEdges()) {
TraceNullableEdge(trc, &u.script_, "script");
}
} else {
if (u.lazyScript) {
TraceManuallyBarrieredEdge(trc, &u.lazyScript, "lazyScript");
}
}
if (trc->isMarkingTracer()) {
GCMarker::fromTracer(trc)->markImplicitEdges(this);
}
}
inline void js::GCMarker::eagerlyMarkChildren(LazyScript* thing) {
traverseEdge(thing, static_cast<JSObject*>(thing->functionOrGlobal_));
traverseEdge(thing, static_cast<JSObject*>(thing->sourceObject_));

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

@ -5273,18 +5273,6 @@ void ScriptWarmUpData::trace(JSTracer* trc) {
}
}
void JSScript::traceChildren(JSTracer* trc) {
BaseScript::traceChildren(trc);
if (lazyScript) {
TraceManuallyBarrieredEdge(trc, &lazyScript, "lazyScript");
}
if (trc->isMarkingTracer()) {
GCMarker::fromTracer(trc)->markImplicitEdges(this);
}
}
size_t JSScript::calculateLiveFixed(jsbytecode* pc) {
size_t nlivefixed = numAlwaysLiveFixedSlots();
@ -5505,8 +5493,8 @@ bool JSScript::formalLivesInArgumentsObject(unsigned argSlot) {
void LazyScript::initScript(JSScript* script) {
MOZ_ASSERT(script);
MOZ_ASSERT(!script_.unbarrieredGet());
script_.set(script);
MOZ_ASSERT(!u.script_.unbarrieredGet());
u.script_.set(script);
}
/* static */
@ -5536,6 +5524,11 @@ LazyScript* LazyScript::CreateRaw(JSContext* cx, uint32_t ngcthings,
return nullptr;
}
// Mark this BaseScript as being a LazyScript and construct the appropriate
// union arm.
lazy->setFlag(ImmutableFlags::IsLazyScript);
new (&lazy->u.script_) WeakHeapPtrScript(nullptr);
// Allocate a PrivateScriptData if it will not be empty. Lazy class
// constructors also need PrivateScriptData for field lists.
if (ngcthings || fun->isClassConstructor()) {

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

@ -2021,6 +2021,25 @@ class BaseScript : public gc::TenuredCell {
ScriptWarmUpData warmUpData_ = {};
union TwinPointer {
// Information used to re-lazify a lazily-parsed interpreted function.
js::LazyScript* lazyScript;
// If non-nullptr, the script has been compiled and this is a forwarding
// pointer to the result. This is a weak pointer: after relazification, we
// can collect the script if there are no other pointers to it.
WeakHeapPtrScript script_;
// Default to the lazyScript union arm which is used by JSScripts. This
// corresponds to the default IsLazyScript flag being clear. Remember that a
// non-lazy script points *to* a LazyScript.
TwinPointer() : lazyScript(nullptr) {}
// The BaseScript uses a finalizer instead of a C++ destructor so this
// should never be run. We need to define to appease compiler though.
~TwinPointer() { MOZ_CRASH(); }
} u;
BaseScript(uint8_t* stubEntry, JSObject* functionOrGlobal,
ScriptSourceObject* sourceObject, uint32_t sourceStart,
uint32_t sourceEnd, uint32_t toStringStart, uint32_t toStringEnd,
@ -2131,6 +2150,10 @@ class BaseScript : public gc::TenuredCell {
// Whether this script contains a direct eval statement.
HasDirectEval = 1 << 27,
// Whether this BaseScript is a LazyScript. This flag will be removed after
// LazyScript and JSScript are merged in Bug 1529456.
IsLazyScript = 1 << 28,
};
// Mutable flags typically store information about runtime or deoptimization
@ -2376,6 +2399,7 @@ setterLevel: \
ShouldDeclareArguments)
IMMUTABLE_FLAG_GETTER(isFunction, IsFunction)
IMMUTABLE_FLAG_GETTER_SETTER_PUBLIC(hasDirectEval, HasDirectEval)
IMMUTABLE_FLAG_GETTER(isLazyScript, IsLazyScript)
MUTABLE_FLAG_GETTER_SETTER(warnedAboutUndefinedProp, WarnedAboutUndefinedProp)
MUTABLE_FLAG_GETTER_SETTER(hasRunOnce, HasRunOnce)
@ -2498,10 +2522,11 @@ setterLevel: \
return false;
}
protected:
void traceChildren(JSTracer* trc);
public:
friend class GCMarker;
friend void js::gc::SweepLazyScripts(GCParallelTask* task);
void traceChildren(JSTracer* trc);
void finalize(JSFreeOp* fop);
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
@ -2565,14 +2590,6 @@ struct DeletePolicy<js::PrivateScriptData>
} /* namespace JS */
class JSScript : public js::BaseScript {
private:
/* Information used to re-lazify a lazily-parsed interpreted function. */
js::LazyScript* lazyScript = nullptr;
//
// End of fields. Start methods.
//
private:
template <js::XDRMode mode>
friend js::XDRResult js::XDRScript(js::XDRState<mode>* xdr,
@ -2847,13 +2864,13 @@ class JSScript : public js::BaseScript {
// discard most JIT code before attempting relazification.
// - Specific subsystems (such as the Debugger) may disable scripts for
// their own reasons.
bool lazyAvailable = selfHosted() || lazyScript;
bool lazyAvailable = selfHosted() || u.lazyScript;
return isRelazifiable() && lazyAvailable && !hasJitScript() &&
!doNotRelazify();
}
void setLazyScript(js::LazyScript* lazy) { lazyScript = lazy; }
js::LazyScript* maybeLazyScript() { return lazyScript; }
void setLazyScript(js::LazyScript* lazy) { u.lazyScript = lazy; }
js::LazyScript* maybeLazyScript() { return u.lazyScript; }
bool isModule() const {
MOZ_ASSERT(hasFlag(ImmutableFlags::IsModule) ==
@ -3187,8 +3204,6 @@ class JSScript : public js::BaseScript {
static const JS::TraceKind TraceKind = JS::TraceKind::Script;
void traceChildren(JSTracer* trc);
// A helper class to prevent relazification of the given function's script
// while it's holding on to it. This class automatically roots the script.
class AutoDelazify;
@ -3231,12 +3246,6 @@ namespace js {
// Information about a script which may be (or has been) lazily compiled to
// bytecode from its source.
class LazyScript : public BaseScript {
// If non-nullptr, the script has been compiled and this is a forwarding
// pointer to the result. This is a weak pointer: after relazification, we
// can collect the script if there are no other pointers to it.
WeakHeapPtrScript script_ = nullptr;
friend void js::gc::SweepLazyScripts(GCParallelTask* task);
// The BaseScript::warmUpData_ field is used as follows:
// * LazyScript in which the script is nested. This case happens if the
// enclosing script is lazily parsed and have never been compiled.
@ -3370,11 +3379,11 @@ class LazyScript : public BaseScript {
void initScript(JSScript* script);
JSScript* maybeScript() { return script_; }
JSScript* maybeScript() { return u.script_; }
const JSScript* maybeScriptUnbarriered() const {
return script_.unbarrieredGet();
return u.script_.unbarrieredGet();
}
bool hasScript() const { return bool(script_); }
bool hasScript() const { return bool(u.script_); }
// Returns true if the enclosing script has ever been compiled.
// Once the enclosing script is compiled, the scope chain is created.
@ -3386,9 +3395,6 @@ class LazyScript : public BaseScript {
return warmUpData_.isEnclosingScope();
}
friend class GCMarker;
void traceChildren(JSTracer* trc);
static const JS::TraceKind TraceKind = JS::TraceKind::LazyScript;
};