зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1133369 - Use consistent allocation kinds for new objects after converting an unboxed group, r=jandem.
This commit is contained in:
Родитель
5024d7a796
Коммит
17643d2924
|
@ -252,7 +252,7 @@ class ObjectGroup : public gc::TenuredCell
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeNewScript *anyNewScript();
|
TypeNewScript *anyNewScript();
|
||||||
void detachNewScript(bool writeBarrier);
|
void detachNewScript(bool writeBarrier, ObjectGroup *replacement);
|
||||||
|
|
||||||
ObjectGroupFlags flagsDontCheckGeneration() {
|
ObjectGroupFlags flagsDontCheckGeneration() {
|
||||||
return flags_;
|
return flags_;
|
||||||
|
@ -480,7 +480,7 @@ class ObjectGroup : public gc::TenuredCell
|
||||||
void setFlags(ExclusiveContext *cx, ObjectGroupFlags flags);
|
void setFlags(ExclusiveContext *cx, ObjectGroupFlags flags);
|
||||||
void markUnknown(ExclusiveContext *cx);
|
void markUnknown(ExclusiveContext *cx);
|
||||||
void maybeClearNewScriptOnOOM();
|
void maybeClearNewScriptOnOOM();
|
||||||
void clearNewScript(ExclusiveContext *cx);
|
void clearNewScript(ExclusiveContext *cx, ObjectGroup *replacement = nullptr);
|
||||||
bool isPropertyNonData(jsid id);
|
bool isPropertyNonData(jsid id);
|
||||||
bool isPropertyNonWritable(jsid id);
|
bool isPropertyNonWritable(jsid id);
|
||||||
|
|
||||||
|
|
|
@ -2765,7 +2765,7 @@ ObjectGroup::anyNewScript()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ObjectGroup::detachNewScript(bool writeBarrier)
|
ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup *replacement)
|
||||||
{
|
{
|
||||||
// Clear the TypeNewScript from this ObjectGroup and, if it has been
|
// Clear the TypeNewScript from this ObjectGroup and, if it has been
|
||||||
// analyzed, remove it from the newObjectGroups table so that it will not be
|
// analyzed, remove it from the newObjectGroups table so that it will not be
|
||||||
|
@ -2775,8 +2775,16 @@ ObjectGroup::detachNewScript(bool writeBarrier)
|
||||||
MOZ_ASSERT(newScript);
|
MOZ_ASSERT(newScript);
|
||||||
|
|
||||||
if (newScript->analyzed()) {
|
if (newScript->analyzed()) {
|
||||||
newScript->function()->compartment()->objectGroups.removeDefaultNewGroup(nullptr, proto(),
|
ObjectGroupCompartment &objectGroups = newScript->function()->compartment()->objectGroups;
|
||||||
newScript->function());
|
if (replacement) {
|
||||||
|
MOZ_ASSERT(replacement->newScript()->function() == newScript->function());
|
||||||
|
objectGroups.replaceDefaultNewGroup(nullptr, proto(), newScript->function(),
|
||||||
|
replacement);
|
||||||
|
} else {
|
||||||
|
objectGroups.removeDefaultNewGroup(nullptr, proto(), newScript->function());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MOZ_ASSERT(!replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->newScript())
|
if (this->newScript())
|
||||||
|
@ -2800,13 +2808,13 @@ ObjectGroup::maybeClearNewScriptOnOOM()
|
||||||
addFlags(OBJECT_FLAG_NEW_SCRIPT_CLEARED);
|
addFlags(OBJECT_FLAG_NEW_SCRIPT_CLEARED);
|
||||||
|
|
||||||
// This method is called during GC sweeping, so don't trigger pre barriers.
|
// This method is called during GC sweeping, so don't trigger pre barriers.
|
||||||
detachNewScript(/* writeBarrier = */ false);
|
detachNewScript(/* writeBarrier = */ false, nullptr);
|
||||||
|
|
||||||
js_delete(newScript);
|
js_delete(newScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ObjectGroup::clearNewScript(ExclusiveContext *cx)
|
ObjectGroup::clearNewScript(ExclusiveContext *cx, ObjectGroup *replacement /* = nullptr*/)
|
||||||
{
|
{
|
||||||
TypeNewScript *newScript = anyNewScript();
|
TypeNewScript *newScript = anyNewScript();
|
||||||
if (!newScript)
|
if (!newScript)
|
||||||
|
@ -2814,6 +2822,7 @@ ObjectGroup::clearNewScript(ExclusiveContext *cx)
|
||||||
|
|
||||||
AutoEnterAnalysis enter(cx);
|
AutoEnterAnalysis enter(cx);
|
||||||
|
|
||||||
|
if (!replacement) {
|
||||||
// Invalidate any Ion code constructing objects of this type.
|
// Invalidate any Ion code constructing objects of this type.
|
||||||
setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
|
setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
|
||||||
|
|
||||||
|
@ -2821,8 +2830,9 @@ ObjectGroup::clearNewScript(ExclusiveContext *cx)
|
||||||
// will not try to construct another one later.
|
// will not try to construct another one later.
|
||||||
if (!newScript->function()->setNewScriptCleared(cx))
|
if (!newScript->function()->setNewScriptCleared(cx))
|
||||||
cx->recoverFromOutOfMemory();
|
cx->recoverFromOutOfMemory();
|
||||||
|
}
|
||||||
|
|
||||||
detachNewScript(/* writeBarrier = */ true);
|
detachNewScript(/* writeBarrier = */ true, replacement);
|
||||||
|
|
||||||
if (cx->isJSContext()) {
|
if (cx->isJSContext()) {
|
||||||
bool found = newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);
|
bool found = newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);
|
||||||
|
@ -3268,6 +3278,33 @@ TypeNewScript::make(JSContext *cx, ObjectGroup *group, JSFunction *fun)
|
||||||
gc::TraceTypeNewScript(group);
|
gc::TraceTypeNewScript(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make a TypeNewScript with the same initializer list as |newScript| but with
|
||||||
|
// a new template object.
|
||||||
|
/* static */ TypeNewScript *
|
||||||
|
TypeNewScript::makeNativeVersion(JSContext *cx, TypeNewScript *newScript,
|
||||||
|
PlainObject *templateObject)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(cx->zone()->types.activeAnalysis);
|
||||||
|
|
||||||
|
ScopedJSDeletePtr<TypeNewScript> nativeNewScript(cx->new_<TypeNewScript>());
|
||||||
|
if (!nativeNewScript)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
nativeNewScript->function_ = newScript->function();
|
||||||
|
nativeNewScript->templateObject_ = templateObject;
|
||||||
|
|
||||||
|
Initializer *cursor = newScript->initializerList;
|
||||||
|
while (cursor->kind != Initializer::DONE) { cursor++; }
|
||||||
|
size_t initializerLength = cursor - newScript->initializerList + 1;
|
||||||
|
|
||||||
|
nativeNewScript->initializerList = cx->zone()->pod_calloc<Initializer>(initializerLength);
|
||||||
|
if (!nativeNewScript->initializerList)
|
||||||
|
return nullptr;
|
||||||
|
PodCopy(nativeNewScript->initializerList, newScript->initializerList, initializerLength);
|
||||||
|
|
||||||
|
return nativeNewScript.forget();
|
||||||
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
TypeNewScript::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
TypeNewScript::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -827,8 +827,6 @@ class TypeNewScript
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Scripted function which this information was computed for.
|
// Scripted function which this information was computed for.
|
||||||
// If instances of the associated group are created without calling
|
|
||||||
// 'new' on this function, the new script information is cleared.
|
|
||||||
HeapPtrFunction function_;
|
HeapPtrFunction function_;
|
||||||
|
|
||||||
// Any preliminary objects with the type. The analyses are not performed
|
// Any preliminary objects with the type. The analyses are not performed
|
||||||
|
@ -902,6 +900,8 @@ class TypeNewScript
|
||||||
bool rollbackPartiallyInitializedObjects(JSContext *cx, ObjectGroup *group);
|
bool rollbackPartiallyInitializedObjects(JSContext *cx, ObjectGroup *group);
|
||||||
|
|
||||||
static void make(JSContext *cx, ObjectGroup *group, JSFunction *fun);
|
static void make(JSContext *cx, ObjectGroup *group, JSFunction *fun);
|
||||||
|
static TypeNewScript *makeNativeVersion(JSContext *cx, TypeNewScript *newScript,
|
||||||
|
PlainObject *templateObject);
|
||||||
|
|
||||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,6 +35,9 @@ UnboxedLayout::trace(JSTracer *trc)
|
||||||
|
|
||||||
if (nativeShape_)
|
if (nativeShape_)
|
||||||
MarkShape(trc, &nativeShape_, "unboxed_layout_nativeShape");
|
MarkShape(trc, &nativeShape_, "unboxed_layout_nativeShape");
|
||||||
|
|
||||||
|
if (replacementNewGroup_)
|
||||||
|
MarkObjectGroup(trc, &replacementNewGroup_, "unboxed_layout_replacementNewGroup");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
|
@ -172,18 +175,49 @@ UnboxedPlainObject::trace(JSTracer *trc, JSObject *obj)
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group)
|
UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group)
|
||||||
{
|
{
|
||||||
|
AutoEnterAnalysis enter(cx);
|
||||||
|
|
||||||
UnboxedLayout &layout = group->unboxedLayout();
|
UnboxedLayout &layout = group->unboxedLayout();
|
||||||
|
Rooted<TaggedProto> proto(cx, group->proto());
|
||||||
|
|
||||||
MOZ_ASSERT(!layout.nativeGroup());
|
MOZ_ASSERT(!layout.nativeGroup());
|
||||||
|
|
||||||
// Immediately clear any new script on the group, as
|
// Immediately clear any new script on the group. This is done by replacing
|
||||||
// rollbackPartiallyInitializedObjects() will be confused by the type
|
// the existing new script with one for a replacement default new group.
|
||||||
// changes we make later on.
|
// This is done so that the size of the replacment group's objects is the
|
||||||
group->clearNewScript(cx);
|
// same as that for the unboxed group, so that we do not see polymorphic
|
||||||
|
// slot accesses later on for sites that see converted objects from this
|
||||||
|
// group and objects that were allocated using the replacement new group.
|
||||||
|
RootedObjectGroup replacementNewGroup(cx);
|
||||||
|
if (layout.newScript()) {
|
||||||
|
replacementNewGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto);
|
||||||
|
if (!replacementNewGroup)
|
||||||
|
return false;
|
||||||
|
|
||||||
AutoEnterAnalysis enter(cx);
|
PlainObject *templateObject = NewObjectWithGroup<PlainObject>(cx, replacementNewGroup,
|
||||||
|
cx->global(), layout.getAllocKind(),
|
||||||
|
MaybeSingletonObject);
|
||||||
|
if (!templateObject)
|
||||||
|
return false;
|
||||||
|
|
||||||
Rooted<TaggedProto> proto(cx, group->proto());
|
for (size_t i = 0; i < layout.properties().length(); i++) {
|
||||||
|
const UnboxedLayout::Property &property = layout.properties()[i];
|
||||||
|
if (!templateObject->addDataProperty(cx, NameToId(property.name), i, JSPROP_ENUMERATE))
|
||||||
|
return false;
|
||||||
|
MOZ_ASSERT(templateObject->slotSpan() == i + 1);
|
||||||
|
MOZ_ASSERT(!templateObject->inDictionaryMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeNewScript *replacementNewScript =
|
||||||
|
TypeNewScript::makeNativeVersion(cx, layout.newScript(), templateObject);
|
||||||
|
if (!replacementNewScript)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
replacementNewGroup->setNewScript(replacementNewScript);
|
||||||
|
gc::TraceTypeNewScript(replacementNewGroup);
|
||||||
|
|
||||||
|
group->clearNewScript(cx, replacementNewGroup);
|
||||||
|
}
|
||||||
|
|
||||||
size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind());
|
size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind());
|
||||||
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto,
|
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto,
|
||||||
|
@ -224,6 +258,7 @@ UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group)
|
||||||
|
|
||||||
layout.nativeGroup_ = nativeGroup;
|
layout.nativeGroup_ = nativeGroup;
|
||||||
layout.nativeShape_ = shape;
|
layout.nativeShape_ = shape;
|
||||||
|
layout.replacementNewGroup_ = replacementNewGroup;
|
||||||
|
|
||||||
nativeGroup->setOriginalUnboxedGroup(group);
|
nativeGroup->setOriginalUnboxedGroup(group);
|
||||||
|
|
||||||
|
|
|
@ -71,10 +71,18 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
|
||||||
HeapPtrObjectGroup nativeGroup_;
|
HeapPtrObjectGroup nativeGroup_;
|
||||||
HeapPtrShape nativeShape_;
|
HeapPtrShape nativeShape_;
|
||||||
|
|
||||||
|
// If nativeGroup is set and this object originally had a TypeNewScript,
|
||||||
|
// this points to the default 'new' group which replaced this one (and
|
||||||
|
// which might itself have been cleared since). This link is only needed to
|
||||||
|
// keep the replacement group from being GC'ed. If it were GC'ed and a new
|
||||||
|
// one regenerated later, that new group might have a different allocation
|
||||||
|
// kind from this group.
|
||||||
|
HeapPtrObjectGroup replacementNewGroup_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UnboxedLayout(const PropertyVector &properties, size_t size)
|
UnboxedLayout(const PropertyVector &properties, size_t size)
|
||||||
: size_(size), newScript_(nullptr), traceList_(nullptr),
|
: size_(size), newScript_(nullptr), traceList_(nullptr),
|
||||||
nativeGroup_(nullptr), nativeShape_(nullptr)
|
nativeGroup_(nullptr), nativeShape_(nullptr), replacementNewGroup_(nullptr)
|
||||||
{
|
{
|
||||||
properties_.appendAll(properties);
|
properties_.appendAll(properties);
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче