зеркало из 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();
|
||||
void detachNewScript(bool writeBarrier);
|
||||
void detachNewScript(bool writeBarrier, ObjectGroup *replacement);
|
||||
|
||||
ObjectGroupFlags flagsDontCheckGeneration() {
|
||||
return flags_;
|
||||
|
@ -480,7 +480,7 @@ class ObjectGroup : public gc::TenuredCell
|
|||
void setFlags(ExclusiveContext *cx, ObjectGroupFlags flags);
|
||||
void markUnknown(ExclusiveContext *cx);
|
||||
void maybeClearNewScriptOnOOM();
|
||||
void clearNewScript(ExclusiveContext *cx);
|
||||
void clearNewScript(ExclusiveContext *cx, ObjectGroup *replacement = nullptr);
|
||||
bool isPropertyNonData(jsid id);
|
||||
bool isPropertyNonWritable(jsid id);
|
||||
|
||||
|
|
|
@ -2765,7 +2765,7 @@ ObjectGroup::anyNewScript()
|
|||
}
|
||||
|
||||
void
|
||||
ObjectGroup::detachNewScript(bool writeBarrier)
|
||||
ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup *replacement)
|
||||
{
|
||||
// Clear the TypeNewScript from this ObjectGroup and, if it has been
|
||||
// analyzed, remove it from the newObjectGroups table so that it will not be
|
||||
|
@ -2775,8 +2775,16 @@ ObjectGroup::detachNewScript(bool writeBarrier)
|
|||
MOZ_ASSERT(newScript);
|
||||
|
||||
if (newScript->analyzed()) {
|
||||
newScript->function()->compartment()->objectGroups.removeDefaultNewGroup(nullptr, proto(),
|
||||
newScript->function());
|
||||
ObjectGroupCompartment &objectGroups = newScript->function()->compartment()->objectGroups;
|
||||
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())
|
||||
|
@ -2800,13 +2808,13 @@ ObjectGroup::maybeClearNewScriptOnOOM()
|
|||
addFlags(OBJECT_FLAG_NEW_SCRIPT_CLEARED);
|
||||
|
||||
// This method is called during GC sweeping, so don't trigger pre barriers.
|
||||
detachNewScript(/* writeBarrier = */ false);
|
||||
detachNewScript(/* writeBarrier = */ false, nullptr);
|
||||
|
||||
js_delete(newScript);
|
||||
}
|
||||
|
||||
void
|
||||
ObjectGroup::clearNewScript(ExclusiveContext *cx)
|
||||
ObjectGroup::clearNewScript(ExclusiveContext *cx, ObjectGroup *replacement /* = nullptr*/)
|
||||
{
|
||||
TypeNewScript *newScript = anyNewScript();
|
||||
if (!newScript)
|
||||
|
@ -2814,6 +2822,7 @@ ObjectGroup::clearNewScript(ExclusiveContext *cx)
|
|||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
if (!replacement) {
|
||||
// Invalidate any Ion code constructing objects of this type.
|
||||
setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
|
||||
|
||||
|
@ -2821,8 +2830,9 @@ ObjectGroup::clearNewScript(ExclusiveContext *cx)
|
|||
// will not try to construct another one later.
|
||||
if (!newScript->function()->setNewScriptCleared(cx))
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
|
||||
detachNewScript(/* writeBarrier = */ true);
|
||||
detachNewScript(/* writeBarrier = */ true, replacement);
|
||||
|
||||
if (cx->isJSContext()) {
|
||||
bool found = newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);
|
||||
|
@ -3268,6 +3278,33 @@ TypeNewScript::make(JSContext *cx, ObjectGroup *group, JSFunction *fun)
|
|||
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
|
||||
TypeNewScript::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
|
|
|
@ -827,8 +827,6 @@ class TypeNewScript
|
|||
|
||||
private:
|
||||
// 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_;
|
||||
|
||||
// Any preliminary objects with the type. The analyses are not performed
|
||||
|
@ -902,6 +900,8 @@ class TypeNewScript
|
|||
bool rollbackPartiallyInitializedObjects(JSContext *cx, ObjectGroup *group);
|
||||
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -35,6 +35,9 @@ UnboxedLayout::trace(JSTracer *trc)
|
|||
|
||||
if (nativeShape_)
|
||||
MarkShape(trc, &nativeShape_, "unboxed_layout_nativeShape");
|
||||
|
||||
if (replacementNewGroup_)
|
||||
MarkObjectGroup(trc, &replacementNewGroup_, "unboxed_layout_replacementNewGroup");
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -172,18 +175,49 @@ UnboxedPlainObject::trace(JSTracer *trc, JSObject *obj)
|
|||
/* static */ bool
|
||||
UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group)
|
||||
{
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
UnboxedLayout &layout = group->unboxedLayout();
|
||||
Rooted<TaggedProto> proto(cx, group->proto());
|
||||
|
||||
MOZ_ASSERT(!layout.nativeGroup());
|
||||
|
||||
// Immediately clear any new script on the group, as
|
||||
// rollbackPartiallyInitializedObjects() will be confused by the type
|
||||
// changes we make later on.
|
||||
group->clearNewScript(cx);
|
||||
// Immediately clear any new script on the group. This is done by replacing
|
||||
// the existing new script with one for a replacement default new group.
|
||||
// This is done so that the size of the replacment group's objects is the
|
||||
// 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());
|
||||
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto,
|
||||
|
@ -224,6 +258,7 @@ UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group)
|
|||
|
||||
layout.nativeGroup_ = nativeGroup;
|
||||
layout.nativeShape_ = shape;
|
||||
layout.replacementNewGroup_ = replacementNewGroup;
|
||||
|
||||
nativeGroup->setOriginalUnboxedGroup(group);
|
||||
|
||||
|
|
|
@ -71,10 +71,18 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
|
|||
HeapPtrObjectGroup nativeGroup_;
|
||||
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:
|
||||
UnboxedLayout(const PropertyVector &properties, size_t size)
|
||||
: size_(size), newScript_(nullptr), traceList_(nullptr),
|
||||
nativeGroup_(nullptr), nativeShape_(nullptr)
|
||||
nativeGroup_(nullptr), nativeShape_(nullptr), replacementNewGroup_(nullptr)
|
||||
{
|
||||
properties_.appendAll(properties);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче