Bug 1689413 part 6 - Move Realm* from ObjectGroup to BaseShape. r=jonco

Differential Revision: https://phabricator.services.mozilla.com/D106976
This commit is contained in:
Jan de Mooij 2021-03-06 01:05:21 +00:00
Родитель dbd6f24a18
Коммит 2204818bf0
32 изменённых файлов: 159 добавлений и 213 удалений

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

@ -56,7 +56,7 @@ inline const JSClass* GetClass(const JSObject* obj) {
* compartment of this realm.
*/
static MOZ_ALWAYS_INLINE Compartment* GetCompartment(JSObject* obj) {
Realm* realm = reinterpret_cast<shadow::Object*>(obj)->group->realm;
Realm* realm = reinterpret_cast<shadow::Object*>(obj)->shape->base->realm;
return GetCompartmentForRealm(realm);
}

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

@ -23,7 +23,6 @@ namespace shadow {
struct ObjectGroup {
int* unused;
JSObject* proto;
JS::Realm* realm;
};
} // namespace shadow

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

@ -27,6 +27,7 @@ namespace shadow {
struct BaseShape {
const JSClass* clasp;
JS::Realm* realm;
};
class Shape {

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

@ -3817,9 +3817,9 @@ static JSObject* CreateArrayPrototype(JSContext* cx, JSProtoKey key) {
return nullptr;
}
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &ArrayObject::class_,
TaggedProto(proto),
gc::AllocKind::OBJECT0));
RootedShape shape(cx, EmptyShape::getInitialShape(
cx, &ArrayObject::class_, cx->realm(),
TaggedProto(proto), gc::AllocKind::OBJECT0));
if (!shape) {
return nullptr;
}
@ -3972,9 +3972,9 @@ static MOZ_ALWAYS_INLINE ArrayObject* NewArray(JSContext* cx, uint32_t length,
* Get a shape with zero fixed slots, regardless of the size class.
* See JSObject::createArray.
*/
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &ArrayObject::class_,
TaggedProto(proto),
gc::AllocKind::OBJECT0));
RootedShape shape(cx, EmptyShape::getInitialShape(
cx, &ArrayObject::class_, cx->realm(),
TaggedProto(proto), gc::AllocKind::OBJECT0));
if (!shape) {
return nullptr;
}
@ -4089,14 +4089,14 @@ ArrayObject* js::NewDenseFullyAllocatedArrayWithTemplate(
}
// TODO(no-TI): clean up.
ArrayObject* js::NewArrayWithGroup(JSContext* cx, uint32_t length,
HandleObjectGroup group) {
// Ion can call this with a group from a different realm when calling
ArrayObject* js::NewArrayWithShape(JSContext* cx, uint32_t length,
HandleShape shape) {
// Ion can call this with a shape from a different realm when calling
// another realm's Array constructor.
Maybe<AutoRealm> ar;
if (cx->realm() != group->realm()) {
MOZ_ASSERT(cx->compartment() == group->compartment());
ar.emplace(cx, group);
if (cx->realm() != shape->realm()) {
MOZ_ASSERT(cx->compartment() == shape->compartment());
ar.emplace(cx, shape);
}
return NewDenseFullyAllocatedArray(cx, length);

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

@ -85,8 +85,8 @@ extern ArrayObject* NewDenseCopiedArray(JSContext* cx, uint32_t length,
extern ArrayObject* NewDenseFullyAllocatedArrayWithTemplate(
JSContext* cx, uint32_t length, ArrayObject* templateObject);
extern ArrayObject* NewArrayWithGroup(JSContext* cx, uint32_t length,
HandleObjectGroup group);
extern ArrayObject* NewArrayWithShape(JSContext* cx, uint32_t length,
HandleShape shape);
extern bool ToLength(JSContext* cx, HandleValue v, uint64_t* out);

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

@ -927,9 +927,10 @@ static bool InstantiateFunctions(JSContext* cx, CompilationInput& input,
if (!group) {
return false;
}
RootedShape shape(cx, EmptyShape::getInitialShape(
cx, &JSFunction::class_, TaggedProto(proto),
/* nfixed = */ 0, ObjectFlags()));
RootedShape shape(
cx, EmptyShape::getInitialShape(cx, &JSFunction::class_, cx->realm(),
TaggedProto(proto),
/* nfixed = */ 0, ObjectFlags()));
if (!shape) {
return false;
}

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

@ -8054,8 +8054,11 @@ void GCRuntime::mergeRealms(Realm* source, Realm* target) {
group->setProtoUnchecked(TaggedProto(targetProto));
}
}
}
group->realm_ = target;
for (auto baseShape = source->zone()->cellIterUnsafe<BaseShape>();
!baseShape.done(); baseShape.next()) {
baseShape->setRealmForMergeRealms(target);
}
// Fixup zone pointers in source's zone to refer to target's zone.

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

@ -1541,21 +1541,18 @@ void js::ObjectGroup::traceChildren(JSTracer* trc) {
if (proto().isObject()) {
TraceEdge(trc, &proto(), "group_proto");
}
// Note: the realm's global can be nullptr if we GC while creating the global.
if (JSObject* global = realm()->unsafeUnbarrieredMaybeGlobal()) {
TraceManuallyBarrieredEdge(trc, &global, "group_global");
}
}
void js::GCMarker::lazilyMarkChildren(ObjectGroup* group) {
if (group->proto().isObject()) {
markAndTraverseEdge(group, group->proto().toObject());
}
}
void BaseShape::traceChildren(JSTracer* trc) {
// Note: the realm's global can be nullptr if we GC while creating the global.
if (GlobalObject* global = group->realm()->unsafeUnbarrieredMaybeGlobal()) {
markAndTraverseEdge(group, static_cast<JSObject*>(global));
if (JSObject* global = realm()->unsafeUnbarrieredMaybeGlobal()) {
TraceManuallyBarrieredEdge(trc, &global, "baseshape_global");
}
}

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

@ -1,13 +0,0 @@
// Test that objects in different compartments can have the same shape if they
// have a null proto.
var g1 = newGlobal();
var g2 = newGlobal({sameZoneAs: g1});
g1.eval("x1 = {foo: 1}");
g2.eval("x2 = {foo: 2}");
assertEq(unwrappedObjectsHaveSameShape(g1.x1, g2.x2), false);
g1.eval("x1 = Object.create(null); x1.foo = 1;");
g2.eval("x2 = Object.create(null); x2.foo = 2;");
assertEq(unwrappedObjectsHaveSameShape(g1.x1, g2.x2), true);

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

@ -35,8 +35,9 @@ Match.Pattern([{node: gc, edge: "fun_environment"},
.assert(findPath(gc, o));
print(JSON.stringify(findPath(gc, o)));
Match.Pattern([{node: {}, edge: "group"},
{node: Match.Pattern.ANY, edge: "group_global"},
Match.Pattern([{node: {}, edge: "shape"},
{node: Match.Pattern.ANY, edge: "base"},
{node: Match.Pattern.ANY, edge: "baseshape_global"},
{node: {}, edge: "o"}])
.assert(findPath(o, o));
print(findPath(o, o).map((e) => e.edge).toString());

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

@ -6623,11 +6623,11 @@ void CodeGenerator::visitNewArrayCallVM(LNewArray* lir) {
JSObject* templateObject = lir->mir()->templateObject();
if (templateObject) {
pushArg(ImmGCPtr(templateObject->group()));
pushArg(ImmGCPtr(templateObject->shape()));
pushArg(Imm32(lir->mir()->length()));
using Fn = ArrayObject* (*)(JSContext*, uint32_t, HandleObjectGroup);
callVM<Fn, NewArrayWithGroup>(lir);
using Fn = ArrayObject* (*)(JSContext*, uint32_t, HandleShape);
callVM<Fn, NewArrayWithShape>(lir);
} else {
pushArg(Imm32(GenericObject));
pushArg(Imm32(lir->mir()->length()));

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

@ -1644,8 +1644,9 @@ void MacroAssembler::switchToRealm(const void* realm, Register scratch) {
}
void MacroAssembler::switchToObjectRealm(Register obj, Register scratch) {
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
loadPtr(Address(scratch, ObjectGroup::offsetOfRealm()), scratch);
loadPtr(Address(obj, JSObject::offsetOfShape()), scratch);
loadPtr(Address(scratch, Shape::offsetOfBaseShape()), scratch);
loadPtr(Address(scratch, BaseShape::offsetOfRealm()), scratch);
switchToRealm(scratch);
}
@ -1685,8 +1686,9 @@ void MacroAssembler::setIsCrossRealmArrayConstructor(Register obj,
// The object's realm must not be cx->realm.
Label isFalse, done;
loadPtr(Address(obj, JSObject::offsetOfGroup()), output);
loadPtr(Address(output, ObjectGroup::offsetOfRealm()), output);
loadPtr(Address(obj, JSObject::offsetOfShape()), output);
loadPtr(Address(output, Shape::offsetOfBaseShape()), output);
loadPtr(Address(output, BaseShape::offsetOfRealm()), output);
branchPtr(Assembler::Equal, AbsoluteAddress(ContextRealmPtr()), output,
&isFalse);
@ -3595,8 +3597,9 @@ void MacroAssembler::branchTestObjCompartment(Condition cond, Register obj,
const Address& compartment,
Register scratch, Label* label) {
MOZ_ASSERT(obj != scratch);
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
loadPtr(Address(scratch, ObjectGroup::offsetOfRealm()), scratch);
loadPtr(Address(obj, JSObject::offsetOfShape()), scratch);
loadPtr(Address(scratch, Shape::offsetOfBaseShape()), scratch);
loadPtr(Address(scratch, BaseShape::offsetOfRealm()), scratch);
loadPtr(Address(scratch, Realm::offsetOfCompartment()), scratch);
branchPtr(cond, compartment, scratch, label);
}
@ -3605,8 +3608,9 @@ void MacroAssembler::branchTestObjCompartment(
Condition cond, Register obj, const JS::Compartment* compartment,
Register scratch, Label* label) {
MOZ_ASSERT(obj != scratch);
loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
loadPtr(Address(scratch, ObjectGroup::offsetOfRealm()), scratch);
loadPtr(Address(obj, JSObject::offsetOfShape()), scratch);
loadPtr(Address(scratch, Shape::offsetOfBaseShape()), scratch);
loadPtr(Address(scratch, BaseShape::offsetOfRealm()), scratch);
loadPtr(Address(scratch, Realm::offsetOfCompartment()), scratch);
branchPtr(cond, scratch, ImmPtr(compartment), label);
}

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

@ -1571,9 +1571,9 @@ RNewArray::RNewArray(CompactBufferReader& reader) {
bool RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedObject templateObject(cx, &iter.read().toObject());
RootedValue result(cx);
RootedObjectGroup group(cx, templateObject->group());
RootedShape shape(cx, templateObject->shape());
ArrayObject* resultObject = NewArrayWithGroup(cx, count_, group);
ArrayObject* resultObject = NewArrayWithShape(cx, count_, shape);
if (!resultObject) {
return false;
}

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

@ -188,7 +188,7 @@ namespace jit {
_(NewArgumentsObject, js::jit::NewArgumentsObject) \
_(NewArrayIterator, js::NewArrayIterator) \
_(NewArrayOperation, js::NewArrayOperation) \
_(NewArrayWithGroup, js::NewArrayWithGroup) \
_(NewArrayWithShape, js::NewArrayWithShape) \
_(NewCallObject, js::jit::NewCallObject) \
_(NewObjectOperation, js::NewObjectOperation) \
_(NewObjectOperationWithTemplate, js::NewObjectOperationWithTemplate) \

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

@ -364,7 +364,7 @@ JS_FRIEND_API bool UninlinedIsCrossCompartmentWrapper(const JSObject* obj);
// getting a wrapper's realm usually doesn't make sense.
static MOZ_ALWAYS_INLINE JS::Realm* GetNonCCWObjectRealm(JSObject* obj) {
MOZ_ASSERT(!js::UninlinedIsCrossCompartmentWrapper(obj));
return reinterpret_cast<JS::shadow::Object*>(obj)->group->realm;
return reinterpret_cast<JS::shadow::Object*>(obj)->shape->base->realm;
}
JS_FRIEND_API void AssertSameCompartment(JSContext* cx, JSObject* obj);

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

@ -4653,21 +4653,6 @@ static bool GroupOf(JSContext* cx, unsigned argc, JS::Value* vp) {
return true;
}
static bool UnwrappedObjectsHaveSameShape(JSContext* cx, unsigned argc,
JS::Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.get(0).isObject() || !args.get(1).isObject()) {
JS_ReportErrorASCII(cx, "2 objects expected");
return false;
}
RootedObject obj1(cx, UncheckedUnwrap(&args[0].toObject()));
RootedObject obj2(cx, UncheckedUnwrap(&args[1].toObject()));
args.rval().setBoolean(obj1->shape() == obj2->shape());
return true;
}
static bool Sleep_fn(JSContext* cx, unsigned argc, Value* vp) {
ShellContext* sc = GetShellContext(cx);
CallArgs args = CallArgsFromVp(argc, vp);
@ -9045,12 +9030,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
"groupOf(obj)",
" Get the group of obj (an implementation detail)."),
JS_FN_HELP("unwrappedObjectsHaveSameShape", UnwrappedObjectsHaveSameShape, 2, 0,
"unwrappedObjectsHaveSameShape(obj1, obj2)",
" Returns true iff obj1 and obj2 have the same shape, false otherwise. Both\n"
" objects are unwrapped first, so this can be used on objects from different\n"
" globals."),
#ifdef DEBUG
JS_FN_HELP("arrayInfo", ArrayInfo, 1, 0,
"arrayInfo(a1, a2, ...)",

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

@ -1,42 +0,0 @@
// |reftest| skip-if(!xulRuntime.shell) -- requires evalcx
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 466905;
var summary = 'Sandbox shapes';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
printBugNumber(BUGNUMBER);
printStatus (summary);
if (typeof evalcx != 'function')
{
expect = actual = 'Test skipped: requires evalcx support';
}
else if (typeof shapeOf != 'function')
{
expect = actual = 'Test skipped: requires shapeOf support';
}
else
{
var s1 = evalcx('lazy');
var s2 = evalcx('lazy');
expect = shapeOf(s1);
actual = shapeOf(s2);
}
reportCompare(expect, actual, summary);
}

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

@ -278,9 +278,9 @@ ArgumentsObject* ArgumentsObject::createTemplateObject(JSContext* cx,
}
constexpr ObjectFlags objectFlags = {ObjectFlag::Indexed};
RootedShape shape(cx,
EmptyShape::getInitialShape(cx, clasp, TaggedProto(proto),
FINALIZE_KIND, objectFlags));
RootedShape shape(cx, EmptyShape::getInitialShape(
cx, clasp, cx->realm(), TaggedProto(proto),
FINALIZE_KIND, objectFlags));
if (!shape) {
return nullptr;
}

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

@ -50,11 +50,9 @@ inline NativeObject* NewObjectCache::newObjectFromHit(JSContext* cx,
NativeObject* templateObj =
reinterpret_cast<NativeObject*>(&entry->templateObject);
ObjectGroup* group = templateObj->group();
// If we did the lookup based on the proto we might have a group/object from a
// If we did the lookup based on the proto we might have a shape/object from a
// different (same-compartment) realm, so we have to do a realm check.
if (group->realm() != cx->realm()) {
if (templateObj->shape()->realm() != cx->realm()) {
return nullptr;
}

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

@ -591,9 +591,9 @@ static PropertyIteratorObject* NewPropertyIteratorObject(JSContext* cx) {
}
const JSClass* clasp = &PropertyIteratorObject::class_;
RootedShape shape(cx,
EmptyShape::getInitialShape(cx, clasp, TaggedProto(nullptr),
ITERATOR_FINALIZE_KIND));
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, cx->realm(),
TaggedProto(nullptr),
ITERATOR_FINALIZE_KIND));
if (!shape) {
return nullptr;
}

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

@ -374,7 +374,7 @@ inline void JSContext::enterRealmOf(JSScript* target) {
enterRealm(target->realm());
}
inline void JSContext::enterRealmOf(js::ObjectGroup* target) {
inline void JSContext::enterRealmOf(js::Shape* target) {
JS::AssertCellIsNotGray(target);
enterRealm(target->realm());
}

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

@ -329,7 +329,7 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext,
public:
inline void enterRealmOf(JSObject* target);
inline void enterRealmOf(JSScript* target);
inline void enterRealmOf(js::ObjectGroup* target);
inline void enterRealmOf(js::Shape* target);
inline void enterNullRealm();
inline void setRealmForJitExceptionHandler(JS::Realm* realm);

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

@ -132,7 +132,6 @@ js::NativeObject::updateDictionaryListPointerAfterMinorGC(NativeObject* old) {
inline void JSObject::setGroup(js::ObjectGroup* group) {
MOZ_RELEASE_ASSERT(group);
MOZ_ASSERT(maybeCCWRealm() == group->realm());
setGroupRaw(group);
}

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

@ -524,7 +524,7 @@ bool js::SetIntegrityLevel(JSContext* cx, HandleObject obj,
// dictionary mode.
RootedShape last(
cx, EmptyShape::getInitialShape(
cx, nobj->getClass(), nobj->taggedProto(),
cx, nobj->getClass(), nobj->realm(), nobj->taggedProto(),
nobj->numFixedSlots(), nobj->lastProperty()->objectFlags()));
if (!last) {
return false;
@ -771,8 +771,9 @@ static inline JSObject* NewObject(JSContext* cx, HandleObjectGroup group,
? GetGCKindSlots(gc::GetGCObjectKind(clasp), clasp)
: GetGCKindSlots(kind, clasp);
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, group->proto(),
nfixed, objectFlags));
RootedShape shape(
cx, EmptyShape::getInitialShape(cx, clasp, cx->realm(), group->proto(),
nfixed, objectFlags));
if (!shape) {
return nullptr;
}
@ -1194,7 +1195,8 @@ static bool InitializePropertiesFromCompatibleNativeObject(
// We need to generate a new shape for dst that has dst's proto but all
// the property information from src. Note that we asserted above that
// dst's object flags are empty.
shape = EmptyShape::getInitialShape(cx, dst->getClass(), dst->taggedProto(),
shape = EmptyShape::getInitialShape(cx, dst->getClass(), dst->realm(),
dst->taggedProto(),
dst->numFixedSlots(), ObjectFlags());
if (!shape) {
return false;
@ -1806,11 +1808,9 @@ static bool SetProto(JSContext* cx, HandleObject obj,
}
}
RootedObjectGroup oldGroup(cx, obj->group());
ObjectGroup* newGroup;
{
AutoRealm ar(cx, oldGroup);
AutoRealm ar(cx, obj->shape());
newGroup = ObjectGroup::defaultNewGroup(cx, obj->getClass(), proto);
if (!newGroup) {
return false;
@ -3813,7 +3813,7 @@ void JSObject::debugCheckNewObject(ObjectGroup* group, Shape* shape,
CanNurseryAllocateFinalizedClass(clasp) ||
clasp->isProxyObject());
MOZ_ASSERT(!group->realm()->hasObjectPendingMetadata());
MOZ_ASSERT(!shape->realm()->hasObjectPendingMetadata());
// Non-native classes manage their own data and slots, so numFixedSlots and
// slotSpan are always 0. Note that proxy classes can have reserved slots

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

@ -138,7 +138,7 @@ class JSObject
void initGroup(js::ObjectGroup* group) { initHeaderPtr(group); }
JS::Compartment* compartment() const { return group()->compartment(); }
JS::Compartment* compartment() const { return shape()->compartment(); }
JS::Compartment* maybeCompartment() const { return compartment(); }
void initShape(js::Shape* shape) {
@ -148,7 +148,7 @@ class JSObject
shape_.init(shape);
}
void setShape(js::Shape* shape) {
MOZ_ASSERT(zone() == shape->zone());
MOZ_ASSERT(maybeCCWRealm() == shape->realm());
shape_ = shape;
}
js::Shape* shape() const { return shape_; }
@ -363,14 +363,14 @@ class JSObject
JS::Realm* nonCCWRealm() const {
MOZ_ASSERT(!js::UninlinedIsCrossCompartmentWrapper(this));
return group()->realm();
return shape()->realm();
}
bool hasSameRealmAs(JSContext* cx) const;
// Returns the object's realm even if the object is a CCW (be careful, in
// this case the realm is not very meaningful because wrappers are shared by
// all realms in the compartment).
JS::Realm* maybeCCWRealm() const { return group()->realm(); }
JS::Realm* maybeCCWRealm() const { return shape()->realm(); }
/*
* ES5 meta-object properties and operations.

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

@ -47,22 +47,15 @@ static ObjectGroup* MakeGroup(JSContext* cx, Handle<TaggedProto> proto) {
if (!group) {
return nullptr;
}
new (group) ObjectGroup(proto, cx->realm());
new (group) ObjectGroup(proto);
return group;
}
ObjectGroup::ObjectGroup(TaggedProto proto, JS::Realm* realm)
: TenuredCellWithNonGCPointer(nullptr), proto_(proto), realm_(realm) {
ObjectGroup::ObjectGroup(TaggedProto proto)
: TenuredCellWithNonGCPointer(nullptr), proto_(proto) {
/* Windows may not appear on prototype chains. */
MOZ_ASSERT_IF(proto.isObject(), !IsWindow(proto.toObject()));
#ifdef DEBUG
GlobalObject* global = realm->unsafeUnbarrieredMaybeGlobal();
if (global) {
AssertTargetIsNotGray(global);
}
#endif
}
void ObjectGroup::setProtoUnchecked(TaggedProto proto) {

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

@ -49,8 +49,10 @@ class ObjectGroup : public gc::TenuredCellWithNonGCPointer<int> {
/* Prototype shared by objects in this group. */
GCPtr<TaggedProto> proto_; // set by constructor
/* Realm shared by objects in this group. */
JS::Realm* realm_; // set by constructor
#ifndef JS_64BIT
// Temporary padding to respect MinCellSize.
uint64_t padding_ = 0;
#endif
// END OF PROPERTIES
@ -59,17 +61,13 @@ class ObjectGroup : public gc::TenuredCellWithNonGCPointer<int> {
return offsetof(ObjectGroup, proto_);
}
static inline uint32_t offsetOfRealm() {
return offsetof(ObjectGroup, realm_);
}
friend class gc::GCRuntime;
// See JSObject::offsetOfGroup() comment.
friend class js::jit::MacroAssembler;
public:
inline ObjectGroup(TaggedProto proto, JS::Realm* realm);
inline explicit ObjectGroup(TaggedProto proto);
const GCPtr<TaggedProto>& proto() const { return proto_; }
@ -77,12 +75,6 @@ class ObjectGroup : public gc::TenuredCellWithNonGCPointer<int> {
void setProtoUnchecked(TaggedProto proto);
JS::Compartment* compartment() const {
return JS::GetCompartmentForRealm(realm_);
}
JS::Compartment* maybeCompartment() const { return compartment(); }
JS::Realm* realm() const { return realm_; }
/* Helpers */
void traceChildren(JSTracer* trc);

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

@ -101,7 +101,8 @@ ProxyObject* ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler,
return nullptr;
}
shape = EmptyShape::getInitialShape(cx, clasp, proto, /* nfixed = */ 0);
shape =
EmptyShape::getInitialShape(cx, clasp, realm, proto, /* nfixed = */ 0);
if (!shape) {
return nullptr;
}
@ -109,8 +110,7 @@ ProxyObject* ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler,
realm->newProxyCache.add(group, shape);
}
MOZ_ASSERT(group->realm() == realm);
MOZ_ASSERT(shape->zone() == cx->zone());
MOZ_ASSERT(shape->realm() == realm);
MOZ_ASSERT(!IsAboutToBeFinalizedUnbarriered(group.address()));
MOZ_ASSERT(!IsAboutToBeFinalizedUnbarriered(shape.address()));

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

@ -96,8 +96,8 @@ Shape* js::EmptyEnvironmentShape(JSContext* cx, const JSClass* cls,
uint32_t numSlots, ObjectFlags objectFlags) {
// Put as many slots into the object header as possible.
uint32_t numFixed = gc::GetGCKindSlots(gc::GetGCObjectKind(numSlots));
return EmptyShape::getInitialShape(cx, cls, TaggedProto(nullptr), numFixed,
objectFlags);
return EmptyShape::getInitialShape(cx, cls, cx->realm(), TaggedProto(nullptr),
numFixed, objectFlags);
}
static Shape* NextEnvironmentShape(JSContext* cx, HandleAtom name,
@ -542,9 +542,9 @@ uint32_t Scope::environmentChainLength() const {
}
Shape* Scope::maybeCloneEnvironmentShape(JSContext* cx) {
// Clone the environment shape if cloning into a different zone.
// Clone the environment shape if cloning into a different realm.
Shape* shape = environmentShape();
if (shape && shape->zoneFromAnyThread() != cx->zone()) {
if (shape && shape->realm() != cx->realm()) {
BindingIter bi(this);
return CreateEnvironmentShape(cx, bi, shape->getObjectClass(),
shape->slotSpan(), shape->objectFlags());

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

@ -29,7 +29,8 @@ inline AutoKeepShapeCaches::~AutoKeepShapeCaches() {
cx_->zone()->setKeepShapeCaches(prev_);
}
inline StackBaseShape::StackBaseShape(const JSClass* clasp) : clasp(clasp) {}
inline StackBaseShape::StackBaseShape(const JSClass* clasp, JS::Realm* realm)
: clasp(clasp), realm(realm) {}
MOZ_ALWAYS_INLINE Shape* Shape::search(JSContext* cx, jsid id) {
return search(cx, this, id);

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

@ -329,8 +329,8 @@ Shape* Shape::replaceLastProperty(JSContext* cx, ObjectFlags objectFlags,
if (!shape->parent) {
/* Treat as resetting the initial property of the shape hierarchy. */
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
return EmptyShape::getInitialShape(cx, shape->getObjectClass(), proto, kind,
objectFlags);
return EmptyShape::getInitialShape(
cx, shape->getObjectClass(), shape->realm(), proto, kind, objectFlags);
}
Rooted<StackShape> child(cx, StackShape(shape));
@ -1408,8 +1408,14 @@ Shape* Shape::setObjectFlag(JSContext* cx, ObjectFlag flag, TaggedProto proto,
}
inline BaseShape::BaseShape(const StackBaseShape& base)
: TenuredCellWithNonGCPointer(base.clasp) {
: TenuredCellWithNonGCPointer(base.clasp), realm_(base.realm) {
MOZ_ASSERT(JS::StringIsASCII(clasp()->name));
#ifdef DEBUG
if (GlobalObject* global = realm()->unsafeUnbarrieredMaybeGlobal()) {
AssertTargetIsNotGray(global);
}
#endif
}
/* static */
@ -1435,8 +1441,6 @@ BaseShape* BaseShape::get(JSContext* cx, StackBaseShape& base) {
return nbase;
}
void BaseShape::traceChildren(JSTracer* trc) {}
#ifdef DEBUG
bool Shape::canSkipMarkingShapeCache() {
// Check that every shape in the shape table will be marked by marking
@ -1501,8 +1505,8 @@ void Zone::checkInitialShapesTableAfterMovingGC() {
}
using Lookup = InitialShapeEntry::Lookup;
Lookup lookup(shape->getObjectClass(), proto, shape->numFixedSlots(),
shape->objectFlags());
Lookup lookup(shape->getObjectClass(), shape->realm(), proto,
shape->numFixedSlots(), shape->objectFlags());
InitialShapeSet::Ptr ptr = initialShapes().lookup(lookup);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
@ -1918,22 +1922,23 @@ void Shape::dumpSubtree(int level, js::GenericPrinter& out) const {
/* static */
Shape* EmptyShape::getInitialShape(JSContext* cx, const JSClass* clasp,
TaggedProto proto, size_t nfixed,
ObjectFlags objectFlags) {
JS::Realm* realm, TaggedProto proto,
size_t nfixed, ObjectFlags objectFlags) {
MOZ_ASSERT(cx->compartment() == realm->compartment());
MOZ_ASSERT_IF(proto.isObject(),
cx->isInsideCurrentCompartment(proto.toObject()));
auto& table = cx->zone()->initialShapes();
auto& table = realm->zone()->initialShapes();
using Lookup = InitialShapeEntry::Lookup;
auto protoPointer =
MakeDependentAddPtr(cx, table, Lookup(clasp, proto, nfixed, objectFlags));
auto protoPointer = MakeDependentAddPtr(
cx, table, Lookup(clasp, realm, proto, nfixed, objectFlags));
if (protoPointer) {
return protoPointer->shape;
}
Rooted<TaggedProto> protoRoot(cx, proto);
StackBaseShape base(clasp);
StackBaseShape base(clasp, realm);
Rooted<BaseShape*> nbase(cx, BaseShape::get(cx, base));
if (!nbase) {
return nullptr;
@ -1944,7 +1949,7 @@ Shape* EmptyShape::getInitialShape(JSContext* cx, const JSClass* clasp,
return nullptr;
}
Lookup lookup(clasp, protoRoot, nfixed, objectFlags);
Lookup lookup(clasp, realm, protoRoot, nfixed, objectFlags);
if (!protoPointer.add(cx, table, lookup,
InitialShapeEntry(shape, protoRoot))) {
return nullptr;
@ -1955,9 +1960,10 @@ Shape* EmptyShape::getInitialShape(JSContext* cx, const JSClass* clasp,
/* static */
Shape* EmptyShape::getInitialShape(JSContext* cx, const JSClass* clasp,
TaggedProto proto, gc::AllocKind kind,
JS::Realm* realm, TaggedProto proto,
gc::AllocKind kind,
ObjectFlags objectFlags) {
return getInitialShape(cx, clasp, proto, GetGCKindSlots(kind, clasp),
return getInitialShape(cx, clasp, realm, proto, GetGCKindSlots(kind, clasp),
objectFlags);
}
@ -1986,7 +1992,7 @@ void NewObjectCache::invalidateEntriesForShape(Shape* shape, JSObject* proto) {
void EmptyShape::insertInitialShape(JSContext* cx, HandleShape shape,
HandleObject proto) {
using Lookup = InitialShapeEntry::Lookup;
Lookup lookup(shape->getObjectClass(), TaggedProto(proto),
Lookup lookup(shape->getObjectClass(), shape->realm(), TaggedProto(proto),
shape->numFixedSlots(), shape->objectFlags());
InitialShapeSet::Ptr p = cx->zone()->initialShapes().lookup(lookup);
@ -2043,8 +2049,8 @@ void Zone::fixupInitialShapeTable() {
if (proto.isObject() && IsForwarded(proto.toObject())) {
entry.proto = TaggedProto(Forwarded(proto.toObject()));
using Lookup = InitialShapeEntry::Lookup;
Lookup relookup(shape->getObjectClass(), proto, shape->numFixedSlots(),
shape->objectFlags());
Lookup relookup(shape->getObjectClass(), shape->realm(), proto,
shape->numFixedSlots(), shape->objectFlags());
e.rekeyFront(relookup, entry);
}
}

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

@ -676,8 +676,11 @@ class BaseShape : public gc::TenuredCellWithNonGCPointer<const JSClass> {
const JSClass* clasp() const { return headerPtr(); }
private:
JS::Realm* realm_;
#ifndef JS_64BIT
// Temporary padding to respect MinCellSize.
uint64_t padding_ = 0;
#endif
BaseShape(const BaseShape& base) = delete;
BaseShape& operator=(const BaseShape& other) = delete;
@ -690,6 +693,14 @@ class BaseShape : public gc::TenuredCellWithNonGCPointer<const JSClass> {
/* Not defined: BaseShapes must not be stack allocated. */
~BaseShape() = delete;
JS::Realm* realm() const { return realm_; }
JS::Compartment* compartment() const {
return JS::GetCompartmentForRealm(realm());
}
JS::Compartment* maybeCompartment() const { return compartment(); }
void setRealmForMergeRealms(JS::Realm* realm) { realm_ = realm; }
/*
* Lookup base shapes from the zone's baseShapes table, adding if not
* already found.
@ -702,10 +713,14 @@ class BaseShape : public gc::TenuredCellWithNonGCPointer<const JSClass> {
static constexpr size_t offsetOfClasp() { return offsetOfHeaderPtr(); }
static constexpr size_t offsetOfRealm() {
return offsetof(BaseShape, realm_);
}
private:
static void staticAsserts() {
static_assert(offsetOfHeaderPtr() ==
offsetof(JS::shadow::BaseShape, clasp));
static_assert(offsetOfClasp() == offsetof(JS::shadow::BaseShape, clasp));
static_assert(offsetOfRealm() == offsetof(JS::shadow::BaseShape, realm));
static_assert(sizeof(BaseShape) % gc::CellAlignBytes == 0,
"Things inheriting from gc::Cell must have a size that's "
"a multiple of gc::CellAlignBytes");
@ -715,26 +730,28 @@ class BaseShape : public gc::TenuredCellWithNonGCPointer<const JSClass> {
/* Entries for the per-zone baseShapes set. */
struct StackBaseShape : public DefaultHasher<WeakHeapPtr<BaseShape*>> {
const JSClass* clasp;
JS::Realm* realm;
explicit inline StackBaseShape(const JSClass* clasp);
inline StackBaseShape(const JSClass* clasp, JS::Realm* realm);
struct Lookup {
const JSClass* clasp;
JS::Realm* realm;
MOZ_IMPLICIT Lookup(const StackBaseShape& base) : clasp(base.clasp) {}
MOZ_IMPLICIT Lookup(const StackBaseShape& base)
: clasp(base.clasp), realm(base.realm) {}
MOZ_IMPLICIT Lookup(BaseShape* base) : clasp(base->clasp()) {}
explicit Lookup(const WeakHeapPtr<BaseShape*>& base)
: clasp(base.unbarrieredGet()->clasp()) {}
MOZ_IMPLICIT Lookup(BaseShape* base)
: clasp(base->clasp()), realm(base->realm()) {}
};
static HashNumber hash(const Lookup& lookup) {
return mozilla::HashGeneric(lookup.clasp);
return mozilla::HashGeneric(lookup.clasp, lookup.realm);
}
static inline bool match(const WeakHeapPtr<BaseShape*>& key,
const Lookup& lookup) {
return key.unbarrieredGet()->clasp() == lookup.clasp;
return key.unbarrieredGet()->clasp() == lookup.clasp &&
key.unbarrieredGet()->realm() == lookup.realm;
}
};
@ -1014,6 +1031,12 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
};
const JSClass* getObjectClass() const { return base()->clasp(); }
JS::Realm* realm() const { return base()->realm(); }
JS::Compartment* compartment() const { return base()->compartment(); }
JS::Compartment* maybeCompartment() const {
return base()->maybeCompartment();
}
static Shape* setObjectFlag(JSContext* cx, ObjectFlag flag, TaggedProto proto,
Shape* last);
@ -1358,10 +1381,11 @@ struct EmptyShape : public js::Shape {
* shape if none was found.
*/
static Shape* getInitialShape(JSContext* cx, const JSClass* clasp,
TaggedProto proto, size_t nfixed,
ObjectFlags objectFlags = {});
JS::Realm* realm, TaggedProto proto,
size_t nfixed, ObjectFlags objectFlags = {});
static Shape* getInitialShape(JSContext* cx, const JSClass* clasp,
TaggedProto proto, gc::AllocKind kind,
JS::Realm* realm, TaggedProto proto,
gc::AllocKind kind,
ObjectFlags objectFlags = {});
/*
@ -1407,13 +1431,15 @@ struct InitialShapeEntry {
/* State used to determine a match on an initial shape. */
struct Lookup {
const JSClass* clasp;
JS::Realm* realm;
TaggedProto proto;
uint32_t nfixed;
ObjectFlags objectFlags;
Lookup(const JSClass* clasp, const TaggedProto& proto, uint32_t nfixed,
ObjectFlags objectFlags)
Lookup(const JSClass* clasp, JS::Realm* realm, const TaggedProto& proto,
uint32_t nfixed, ObjectFlags objectFlags)
: clasp(clasp),
realm(realm),
proto(proto),
nfixed(nfixed),
objectFlags(objectFlags) {}
@ -1424,13 +1450,14 @@ struct InitialShapeEntry {
static HashNumber hash(const Lookup& lookup) {
HashNumber hash = MovableCellHasher<TaggedProto>::hash(lookup.proto);
return mozilla::AddToHash(hash,
mozilla::HashGeneric(lookup.clasp, lookup.nfixed,
lookup.objectFlags.toRaw()));
return mozilla::AddToHash(
hash, mozilla::HashGeneric(lookup.clasp, lookup.realm, lookup.nfixed,
lookup.objectFlags.toRaw()));
}
static inline bool match(const InitialShapeEntry& key, const Lookup& lookup) {
const Shape* shape = key.shape.unbarrieredGet();
return lookup.clasp == shape->getObjectClass() &&
lookup.realm == shape->realm() &&
lookup.nfixed == shape->numFixedSlots() &&
lookup.objectFlags == shape->objectFlags() &&
key.proto.unbarrieredGet() == lookup.proto;