Bug 1137497 - Remove shape from unboxed objects, r=jandem.

This commit is contained in:
Brian Hackett 2015-03-04 08:32:45 -06:00
parent 171a1c0e84
commit ace85caac2
35 changed files with 428 additions and 282 deletions

View File

@ -1633,6 +1633,8 @@ OutlineTypedObject::obj_trace(JSTracer *trc, JSObject *object)
{
OutlineTypedObject &typedObj = object->as<OutlineTypedObject>();
MarkShape(trc, &typedObj.shape_, "OutlineTypedObject_shape");
if (!typedObj.owner_)
return;
@ -2156,10 +2158,13 @@ InlineTypedObject::obj_trace(JSTracer *trc, JSObject *object)
{
InlineTypedObject &typedObj = object->as<InlineTypedObject>();
// Inline transparent objects do not have references and do not need to be
// traced. If they have an entry in the compartment's LazyArrayBufferTable,
MarkShape(trc, &typedObj.shape_, "InlineTypedObject_shape");
// Inline transparent objects do not have references and do not need more
// tracing. If there is an entry in the compartment's LazyArrayBufferTable,
// tracing that reference will be taken care of by the table itself.
MOZ_ASSERT(typedObj.is<InlineOpaqueTypedObject>());
if (typedObj.is<InlineTransparentTypedObject>())
return;
// When this is called for compacting GC, the related objects we touch here
// may not have had their slots updated yet.
@ -2337,7 +2342,7 @@ LazyArrayBufferTable::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
DEFINE_TYPEDOBJ_CLASS(OutlineTransparentTypedObject, OutlineTypedObject::obj_trace);
DEFINE_TYPEDOBJ_CLASS(OutlineOpaqueTypedObject, OutlineTypedObject::obj_trace);
DEFINE_TYPEDOBJ_CLASS(InlineTransparentTypedObject, nullptr);
DEFINE_TYPEDOBJ_CLASS(InlineTransparentTypedObject, InlineTypedObject::obj_trace);
DEFINE_TYPEDOBJ_CLASS(InlineOpaqueTypedObject, InlineTypedObject::obj_trace);
static int32_t

View File

@ -369,7 +369,7 @@ class ArrayTypeDescr;
* is no `class_` field because `ArrayType` is just a native
* constructor function.
*/
class ArrayMetaTypeDescr : public JSObject
class ArrayMetaTypeDescr : public NativeObject
{
private:
// Helper for creating a new ArrayType object.
@ -433,7 +433,7 @@ class ArrayTypeDescr : public ComplexTypeDescr
* is no `class_` field because `StructType` is just a native
* constructor function.
*/
class StructMetaTypeDescr : public JSObject
class StructMetaTypeDescr : public NativeObject
{
private:
static JSObject *create(JSContext *cx, HandleObject structTypeGlobal,
@ -510,7 +510,6 @@ class TypedObjectModuleObject : public NativeObject {
/* Base type for transparent and opaque typed objects. */
class TypedObject : public JSObject
{
private:
static const bool IsTypedObjectClass = true;
static bool obj_getArrayElement(JSContext *cx,
@ -520,6 +519,8 @@ class TypedObject : public JSObject
MutableHandleValue vp);
protected:
HeapPtrShape shape_;
static bool obj_lookupProperty(JSContext *cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
MutableHandleShape propp);
@ -601,6 +602,8 @@ class TypedObject : public JSObject
/* Accessors for self hosted code. */
static bool GetBuffer(JSContext *cx, unsigned argc, Value *vp);
static bool GetByteOffset(JSContext *cx, unsigned argc, Value *vp);
Shape *shapeFromGC() { return shape_; }
};
typedef Handle<TypedObject*> HandleTypedObject;
@ -711,8 +714,6 @@ class InlineTypedObject : public TypedObject
}
uint8_t *inlineTypedMem() const {
static_assert(offsetof(InlineTypedObject, data_) == sizeof(JSObject),
"The data for an inline typed object must follow the shape and type.");
return (uint8_t *) &data_;
}

View File

@ -1678,9 +1678,6 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
ObjectGroup *group = obj->groupFromGC();
traverse(group);
Shape *shape = obj->lastProperty();
PushMarkStack(this, shape);
/* Call the trace hook if necessary. */
const Class *clasp = group->clasp();
if (clasp->trace) {
@ -1691,11 +1688,13 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
(!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())),
clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
if (clasp->trace == InlineTypedObject::obj_trace) {
TypeDescr *descr = &obj->as<InlineOpaqueTypedObject>().typeDescr();
Shape *shape = obj->as<InlineTypedObject>().shapeFromGC();
PushMarkStack(this, shape);
TypeDescr *descr = &obj->as<InlineTypedObject>().typeDescr();
if (!descr->hasTraceList())
return;
unboxedTraceList = descr->traceList();
unboxedMemory = obj->as<InlineOpaqueTypedObject>().inlineTypedMem();
unboxedMemory = obj->as<InlineTypedObject>().inlineTypedMem();
goto scan_unboxed;
}
if (clasp == &UnboxedPlainObject::class_) {
@ -1709,10 +1708,14 @@ GCMarker::processMarkStackTop(SliceBudget &budget)
clasp->trace(this, obj);
}
if (!shape->isNative())
if (!clasp->isNative())
return;
NativeObject *nobj = &obj->as<NativeObject>();
Shape *shape = nobj->lastProperty();
PushMarkStack(this, shape);
unsigned nslots = nobj->slotSpan();
do {

View File

@ -691,15 +691,16 @@ js::Nursery::moveObjectToTenured(MinorCollectionTracer *trc,
NativeObject *ndst = &dst->as<NativeObject>(), *nsrc = &src->as<NativeObject>();
tenuredSize += moveSlotsToTenured(ndst, nsrc, dstKind);
tenuredSize += moveElementsToTenured(ndst, nsrc, dstKind);
// The shape's list head may point into the old object. This can only
// happen for dictionaries, which are native objects.
if (&nsrc->shape_ == ndst->shape_->listp)
ndst->shape_->listp = &ndst->shape_;
}
if (src->is<InlineTypedObject>())
InlineTypedObject::objectMovedDuringMinorGC(trc, dst, src);
/* The shape's list head may point into the old object. */
if (&src->shape_ == dst->shape_->listp)
dst->shape_->listp = &dst->shape_;
return tenuredSize;
}

View File

@ -3441,7 +3441,7 @@ IsCacheableSetPropWriteSlot(JSObject *obj, Shape *oldShape, JSObject *holder, Sh
return false;
// Object shape must not have changed during the property set.
if (obj->lastProperty() != oldShape)
if (!obj->isNative() || obj->as<NativeObject>().lastProperty() != oldShape)
return false;
// Currently we only optimize direct writes.
@ -3463,11 +3463,11 @@ IsCacheableSetPropAddSlot(JSContext *cx, HandleObject obj, HandleShape oldShape,
return false;
// Property must be set directly on object, and be last added property of object.
if (obj != holder || shape != obj->lastProperty())
if (!obj->isNative() || obj != holder || shape != obj->as<NativeObject>().lastProperty())
return false;
// Object must be extensible, oldShape must be immediate parent of curShape.
if (!obj->nonProxyIsExtensible() || obj->lastProperty()->previous() != oldShape)
if (!obj->nonProxyIsExtensible() || shape->previous() != oldShape)
return false;
// Basic shape checks.
@ -3562,7 +3562,7 @@ static const VMFunction LookupNoSuchMethodHandlerInfo =
FunctionInfo<LookupNoSuchMethodHandlerFn>(LookupNoSuchMethodHandler);
static bool
GetElemNativeStubExists(ICGetElem_Fallback *stub, HandleObject obj, HandleObject holder,
GetElemNativeStubExists(ICGetElem_Fallback *stub, HandleNativeObject obj, HandleNativeObject holder,
HandlePropertyName propName, bool needsAtomize)
{
bool indirect = (obj.get() != holder.get());
@ -3626,8 +3626,8 @@ GetElemNativeStubExists(ICGetElem_Fallback *stub, HandleObject obj, HandleObject
}
static void
RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, HandleObject obj,
HandleObject holder, HandlePropertyName propName,
RemoveExistingGetElemNativeStubs(JSContext *cx, ICGetElem_Fallback *stub, HandleNativeObject obj,
HandleNativeObject holder, HandlePropertyName propName,
bool needsAtomize)
{
bool indirect = (obj.get() != holder.get());
@ -3704,7 +3704,7 @@ TypedArrayGetElemStubExists(ICGetElem_Fallback *stub, HandleObject obj)
for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
if (!iter->isGetElem_TypedArray())
continue;
if (obj->lastProperty() == iter->toGetElem_TypedArray()->shape())
if (obj->maybeShape() == iter->toGetElem_TypedArray()->shape())
return true;
}
return false;
@ -3725,7 +3725,7 @@ ArgumentsGetElemStubExists(ICGetElem_Fallback *stub, ICGetElem_Arguments::Which
static bool
TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc,
ICGetElem_Fallback *stub, HandleObject obj,
ICGetElem_Fallback *stub, HandleNativeObject obj,
HandleValue key)
{
// Native-object GetElem stubs can't deal with non-string keys.
@ -3746,9 +3746,13 @@ TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc,
bool isCallElem = (JSOp(*pc) == JSOP_CALLELEM);
RootedShape shape(cx);
RootedObject holder(cx);
if (!EffectlesslyLookupProperty(cx, obj, propName, &holder, &shape))
RootedObject baseHolder(cx);
if (!EffectlesslyLookupProperty(cx, obj, propName, &baseHolder, &shape))
return false;
if (!baseHolder || !baseHolder->isNative())
return true;
HandleNativeObject holder = baseHolder.as<NativeObject>();
if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
// If a suitable stub already exists, nothing else to do.
@ -3787,7 +3791,7 @@ TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbytecode *pc,
bool getterIsScripted = false;
bool isTemporarilyUnoptimizable = false;
if (IsCacheableGetPropCall(cx, obj, holder, shape, &getterIsScripted,
if (IsCacheableGetPropCall(cx, obj, baseHolder, shape, &getterIsScripted,
&isTemporarilyUnoptimizable, /*isDOMProxy=*/false)) {
RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
@ -3949,7 +3953,7 @@ TryAttachGetElemStub(JSContext *cx, JSScript *script, jsbytecode *pc, ICGetElem_
if (rhs.isInt32() && rhs.toInt32() >= 0 && !IsAnyTypedArray(obj.get())) {
JitSpew(JitSpew_BaselineIC, " Generating GetElem(Native[Int32] dense) stub");
ICGetElem_Dense::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
obj->lastProperty(), isCallElem);
obj->as<NativeObject>().lastProperty(), isCallElem);
ICStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
if (!denseStub)
return false;
@ -3961,7 +3965,7 @@ TryAttachGetElemStub(JSContext *cx, JSScript *script, jsbytecode *pc, ICGetElem_
// Check for NativeObject[id] shape-optimizable accesses.
if (rhs.isString()) {
RootedScript rootedScript(cx, script);
if (!TryAttachNativeGetElemStub(cx, rootedScript, pc, stub, obj, rhs))
if (!TryAttachNativeGetElemStub(cx, rootedScript, pc, stub, obj.as<NativeObject>(), rhs))
return false;
script = rootedScript;
}
@ -3991,8 +3995,7 @@ TryAttachGetElemStub(JSContext *cx, JSScript *script, jsbytecode *pc, ICGetElem_
return true;
JitSpew(JitSpew_BaselineIC, " Generating GetElem(TypedArray[Int32]) stub");
ICGetElem_TypedArray::Compiler compiler(cx, obj->lastProperty(),
TypedThingElementType(obj));
ICGetElem_TypedArray::Compiler compiler(cx, obj->maybeShape(), TypedThingElementType(obj));
ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
if (!typedArrayStub)
return false;
@ -4887,23 +4890,29 @@ ICGetElem_Arguments::Compiler::generateStubCode(MacroAssembler &masm)
//
static bool
SetElemDenseAddHasSameShapes(ICSetElem_DenseAdd *stub, JSObject *obj)
SetElemDenseAddHasSameShapes(ICSetElem_DenseAdd *stub, NativeObject *obj)
{
size_t numShapes = stub->protoChainDepth() + 1;
for (size_t i = 0; i < numShapes; i++) {
static const size_t MAX_DEPTH = ICSetElem_DenseAdd::MAX_PROTO_CHAIN_DEPTH;
if (obj->lastProperty() != stub->toImplUnchecked<MAX_DEPTH>()->shape(i))
return false;
obj = obj->getProto();
if (!obj && i != numShapes - 1)
JSObject *proto = obj->getProto();
if (!proto) {
if (i != numShapes - 1)
return false;
break;
}
if (!proto->isNative())
return false;
obj = &proto->as<NativeObject>();
}
return true;
}
static bool
DenseSetElemStubExists(JSContext *cx, ICStub::Kind kind, ICSetElem_Fallback *stub, HandleObject obj)
DenseSetElemStubExists(JSContext *cx, ICStub::Kind kind, ICSetElem_Fallback *stub, HandleNativeObject obj)
{
MOZ_ASSERT(kind == ICStub::SetElem_Dense || kind == ICStub::SetElem_DenseAdd);
@ -4930,7 +4939,7 @@ TypedArraySetElemStubExists(ICSetElem_Fallback *stub, HandleObject obj, bool exp
if (!iter->isSetElem_TypedArray())
continue;
ICSetElem_TypedArray *taStub = iter->toSetElem_TypedArray();
if (obj->lastProperty() == taStub->shape() && taStub->expectOutOfBounds() == expectOOB)
if (obj->maybeShape() == taStub->shape() && taStub->expectOutOfBounds() == expectOOB)
return true;
}
return false;
@ -4943,7 +4952,7 @@ RemoveExistingTypedArraySetElemStub(JSContext *cx, ICSetElem_Fallback *stub, Han
if (!iter->isSetElem_TypedArray())
continue;
if (obj->lastProperty() != iter->toSetElem_TypedArray()->shape())
if (obj->maybeShape() != iter->toSetElem_TypedArray()->shape())
continue;
// TypedArraySetElem stubs are only removed using this procedure if
@ -5049,7 +5058,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub_
if (!obj)
return false;
RootedShape oldShape(cx, obj->lastProperty());
RootedShape oldShape(cx, obj->maybeShape());
// Check the old capacity
uint32_t oldCapacity = 0;
@ -5094,23 +5103,25 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub_
index.isInt32() && index.toInt32() >= 0 &&
!rhs.isMagic(JS_ELEMENTS_HOLE))
{
HandleNativeObject nobj = obj.as<NativeObject>();
bool addingCase;
size_t protoDepth;
if (CanOptimizeDenseSetElem(&obj->as<NativeObject>(), index.toInt32(),
if (CanOptimizeDenseSetElem(nobj, index.toInt32(),
oldShape, oldCapacity, oldInitLength,
&addingCase, &protoDepth))
{
RootedShape shape(cx, obj->lastProperty());
RootedShape shape(cx, nobj->lastProperty());
RootedObjectGroup group(cx, obj->getGroup(cx));
if (!group)
return false;
if (addingCase && !DenseSetElemStubExists(cx, ICStub::SetElem_DenseAdd, stub, obj)) {
if (addingCase && !DenseSetElemStubExists(cx, ICStub::SetElem_DenseAdd, stub, nobj)) {
JitSpew(JitSpew_BaselineIC,
" Generating SetElem_DenseAdd stub "
"(shape=%p, group=%p, protoDepth=%u)",
obj->lastProperty(), group.get(), protoDepth);
nobj->lastProperty(), group.get(), protoDepth);
ICSetElemDenseAddCompiler compiler(cx, obj, protoDepth);
ICUpdatedStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
if (!denseStub)
@ -5120,11 +5131,11 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub_
stub->addNewStub(denseStub);
} else if (!addingCase &&
!DenseSetElemStubExists(cx, ICStub::SetElem_Dense, stub, obj))
!DenseSetElemStubExists(cx, ICStub::SetElem_Dense, stub, nobj))
{
JitSpew(JitSpew_BaselineIC,
" Generating SetElem_Dense stub (shape=%p, group=%p)",
obj->lastProperty(), group.get());
nobj->lastProperty(), group.get());
ICSetElem_Dense::Compiler compiler(cx, shape, group);
ICUpdatedStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
if (!denseStub)
@ -5171,7 +5182,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub_
if (expectOutOfBounds)
RemoveExistingTypedArraySetElemStub(cx, stub, obj);
Shape *shape = obj->lastProperty();
Shape *shape = obj->maybeShape();
Scalar::Type type = TypedThingElementType(obj);
JitSpew(JitSpew_BaselineIC,
@ -5373,7 +5384,7 @@ GetProtoShapes(JSObject *obj, size_t protoChainDepth, AutoShapeVector *shapes)
{
JSObject *curProto = obj->getProto();
for (size_t i = 0; i < protoChainDepth; i++) {
if (!shapes->append(curProto->lastProperty()))
if (!shapes->append(curProto->as<NativeObject>().lastProperty()))
return false;
curProto = curProto->getProto();
}
@ -5389,7 +5400,7 @@ ICUpdatedStub *
ICSetElemDenseAddCompiler::getStub(ICStubSpace *space)
{
AutoShapeVector shapes(cx);
if (!shapes.append(obj_->lastProperty()))
if (!shapes.append(obj_->as<NativeObject>().lastProperty()))
return nullptr;
if (!GetProtoShapes(obj_, protoChainDepth_, &shapes))
@ -5762,7 +5773,7 @@ ICIn_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
static bool
UpdateExistingGetPropCallStubs(ICFallbackStub* fallbackStub,
ICStub::Kind kind,
HandleObject holder,
HandleNativeObject holder,
HandleObject receiver,
HandleFunction getter)
{
@ -5815,7 +5826,7 @@ UpdateExistingGetPropCallStubs(ICFallbackStub* fallbackStub,
static bool
UpdateExistingSetPropCallStubs(ICSetProp_Fallback* fallbackStub,
ICStub::Kind kind,
JSObject *holder,
NativeObject *holder,
ReceiverGuard::Token receiverGuard,
JSFunction *setter)
{
@ -5963,7 +5974,7 @@ TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *s
Shape *shape = nullptr;
while (scopeChain) {
if (!shapes.append(scopeChain->lastProperty()))
if (!shapes.append(scopeChain->maybeShape()))
return false;
if (scopeChain->is<GlobalObject>()) {
@ -6492,7 +6503,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
RootedObject obj(cx, &val.toObject());
if (oldShape != obj->lastProperty()) {
if (obj->isNative() && oldShape != obj->as<NativeObject>().lastProperty()) {
// No point attaching anything, since we know the shape guard will fail
return true;
}
@ -6565,7 +6576,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
MOZ_ASSERT(callee->hasScript());
if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallScripted,
holder, obj, callee)) {
holder.as<NativeObject>(), obj, callee)) {
*attached = true;
return true;
}
@ -6671,7 +6682,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
newStub = compiler.getStub(compiler.getStubSpace(script));
} else if (obj == holder) {
if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallNative,
obj, JS::NullPtr(), callee)) {
obj.as<NativeObject>(), JS::NullPtr(), callee)) {
*attached = true;
return true;
}
@ -6681,7 +6692,7 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
newStub = compiler.getStub(compiler.getStubSpace(script));
} else {
if (UpdateExistingGetPropCallStubs(stub, ICStub::GetProp_CallNativePrototype,
holder, obj, callee)) {
holder.as<NativeObject>(), obj, callee)) {
*attached = true;
return true;
}
@ -6760,7 +6771,7 @@ TryAttachTypedObjectGetPropStub(JSContext *cx, HandleScript script,
uint32_t fieldOffset = structDescr->fieldOffset(fieldIndex);
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
ICGetProp_TypedObject::Compiler compiler(cx, monitorStub, obj->lastProperty(),
ICGetProp_TypedObject::Compiler compiler(cx, monitorStub, obj->maybeShape(),
fieldOffset, &fieldDescr->as<SimpleTypeDescr>());
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
@ -6923,7 +6934,7 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_
// Grab our old shape before it goes away.
RootedShape oldShape(cx);
if (val.isObject())
oldShape = val.toObject().lastProperty();
oldShape = val.toObject().maybeShape();
// After the Genericstub was added, we should never reach the Fallbackstub again.
MOZ_ASSERT(!stub->hasStub(ICStub::GetProp_Generic));
@ -7167,14 +7178,14 @@ ICGetPropNativeCompiler::getStub(ICStubSpace *space)
switch (kind) {
case ICStub::GetProp_Native: {
MOZ_ASSERT(obj_ == holder_);
RootedShape shape(cx, obj_->lastProperty());
RootedShape shape(cx, obj_->as<NativeObject>().lastProperty());
return ICStub::New<ICGetProp_Native>(space, getStubCode(), firstMonitorStub_, shape, offset_);
}
case ICStub::GetProp_NativePrototype: {
MOZ_ASSERT(obj_ != holder_);
ReceiverGuard::Token guard = ReceiverGuard::objectToken(obj_);
Shape *holderShape = holder_->lastProperty();
Shape *holderShape = holder_->as<NativeObject>().lastProperty();
return ICStub::New<ICGetProp_NativePrototype>(space, getStubCode(), firstMonitorStub_, guard,
offset_, holder_, holderShape);
}
@ -7691,8 +7702,8 @@ ICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler &masm)
ICStub *
ICGetPropCallDOMProxyNativeCompiler::getStub(ICStubSpace *space)
{
RootedShape shape(cx, proxy_->lastProperty());
RootedShape holderShape(cx, holder_->lastProperty());
RootedShape shape(cx, proxy_->maybeShape());
RootedShape holderShape(cx, holder_->as<NativeObject>().lastProperty());
Value expandoSlot = GetProxyExtra(proxy_, GetDOMProxyExpandoSlot());
RootedShape expandoShape(cx, nullptr);
@ -7712,7 +7723,7 @@ ICGetPropCallDOMProxyNativeCompiler::getStub(ICStubSpace *space)
}
if (expandoVal.isObject())
expandoShape = expandoVal.toObject().lastProperty();
expandoShape = expandoVal.toObject().as<NativeObject>().lastProperty();
if (kind == ICStub::GetProp_CallDOMProxyNative) {
return ICStub::New<ICGetProp_CallDOMProxyNative>(
@ -7729,7 +7740,7 @@ ICGetPropCallDOMProxyNativeCompiler::getStub(ICStubSpace *space)
ICStub *
ICGetProp_DOMProxyShadowed::Compiler::getStub(ICStubSpace *space)
{
RootedShape shape(cx, proxy_->lastProperty());
RootedShape shape(cx, proxy_->maybeShape());
return New<ICGetProp_DOMProxyShadowed>(space, getStubCode(), firstMonitorStub_, shape,
proxy_->handler(), name_, pcOffset_);
}
@ -8115,7 +8126,7 @@ TryAttachSetValuePropStub(JSContext *cx, HandleScript script, jsbytecode *pc, IC
GetFixedOrDynamicSlotOffset(&obj->as<NativeObject>(), shape->slot(), &isFixedSlot, &offset);
JitSpew(JitSpew_BaselineIC, " Generating SetProp(NativeObject.PROP) stub");
MOZ_ASSERT(obj->lastProperty() == oldShape,
MOZ_ASSERT(obj->as<NativeObject>().lastProperty() == oldShape,
"Should this really be a SetPropWriteSlot?");
ICSetProp_Native::Compiler compiler(cx, obj, isFixedSlot, offset);
ICSetProp_Native *newStub = compiler.getStub(compiler.getStubSpace(script));
@ -8167,7 +8178,7 @@ TryAttachSetAccessorPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
MOZ_ASSERT(callee->hasScript());
if (UpdateExistingSetPropCallStubs(stub, ICStub::SetProp_CallScripted,
holder, receiverGuard, callee)) {
&holder->as<NativeObject>(), receiverGuard, callee)) {
*attached = true;
return true;
}
@ -8192,7 +8203,7 @@ TryAttachSetAccessorPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
MOZ_ASSERT(callee->isNative());
if (UpdateExistingSetPropCallStubs(stub, ICStub::SetProp_CallNative,
holder, receiverGuard, callee)) {
&holder->as<NativeObject>(), receiverGuard, callee)) {
*attached = true;
return true;
}
@ -8275,7 +8286,7 @@ TryAttachTypedObjectSetPropStub(JSContext *cx, HandleScript script,
uint32_t fieldOffset = structDescr->fieldOffset(fieldIndex);
ICSetProp_TypedObject::Compiler compiler(cx, obj->lastProperty(), obj->group(), fieldOffset,
ICSetProp_TypedObject::Compiler compiler(cx, obj->maybeShape(), obj->group(), fieldOffset,
&fieldDescr->as<SimpleTypeDescr>());
ICUpdatedStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
@ -8324,7 +8335,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_
if (!obj)
return false;
ReceiverGuard::Token oldGuard = ReceiverGuard::objectToken(obj);
RootedShape oldShape(cx, obj->lastProperty());
RootedShape oldShape(cx, obj->maybeShape());
RootedObjectGroup oldGroup(cx, obj->getGroup(cx));
if (!oldGroup)
return false;
@ -11983,7 +11994,7 @@ ICSetProp_Native::Compiler::getStub(ICStubSpace *space)
if (!group)
return nullptr;
RootedShape shape(cx, obj_->lastProperty());
RootedShape shape(cx, obj_->as<NativeObject>().lastProperty());
ICSetProp_Native *stub = ICStub::New<ICSetProp_Native>(space, getStubCode(), group, shape, offset_);
if (!stub || !stub->initUpdatingChain(cx, space))
return nullptr;

View File

@ -2921,7 +2921,7 @@ class ICGetElemNativeCompiler : public ICStubCompiler
{}
ICStub *getStub(ICStubSpace *space) {
RootedShape shape(cx, obj_->lastProperty());
RootedShape shape(cx, obj_->as<NativeObject>().lastProperty());
if (kind == ICStub::GetElem_NativeSlot) {
MOZ_ASSERT(obj_ == holder_);
return ICStub::New<ICGetElem_NativeSlot>(
@ -2930,7 +2930,7 @@ class ICGetElemNativeCompiler : public ICStubCompiler
}
MOZ_ASSERT(obj_ != holder_);
RootedShape holderShape(cx, holder_->lastProperty());
RootedShape holderShape(cx, holder_->as<NativeObject>().lastProperty());
if (kind == ICStub::GetElem_NativePrototypeSlot) {
return ICStub::New<ICGetElem_NativePrototypeSlot>(
space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
@ -3812,7 +3812,7 @@ class ICGetProp_Primitive : public ICMonitoredStub
{}
ICStub *getStub(ICStubSpace *space) {
RootedShape protoShape(cx, prototype_->lastProperty());
RootedShape protoShape(cx, prototype_->as<NativeObject>().lastProperty());
return ICStub::New<ICGetProp_Primitive>(space, getStubCode(), firstMonitorStub_,
protoShape, offset_);
}
@ -3929,7 +3929,7 @@ class ReceiverGuard
static Token objectToken(JSObject *obj) {
if (obj->is<UnboxedPlainObject>())
return groupToken(obj->group());
return shapeToken(obj->lastProperty());
return shapeToken(obj->maybeShape());
}
explicit ReceiverGuard(Token token)
@ -4421,7 +4421,7 @@ class ICGetProp_CallScripted : public ICGetPropCallPrototypeGetter
ICStub *getStub(ICStubSpace *space) {
ReceiverGuard::Token guard = ReceiverGuard::objectToken(receiver_);
Shape *holderShape = holder_->lastProperty();
Shape *holderShape = holder_->as<NativeObject>().lastProperty();
return ICStub::New<ICGetProp_CallScripted>(space, getStubCode(), firstMonitorStub_,
guard, holder_, holderShape, getter_,
pcOffset_);
@ -4467,7 +4467,7 @@ class ICGetProp_CallNative : public ICGetPropCallGetter
{}
ICStub *getStub(ICStubSpace *space) {
RootedShape shape(cx, holder_->lastProperty());
RootedShape shape(cx, holder_->as<NativeObject>().lastProperty());
return ICStub::New<ICGetProp_CallNative>(space, getStubCode(), firstMonitorStub_,
holder_, shape, getter_, pcOffset_);
}
@ -4514,7 +4514,7 @@ class ICGetProp_CallNativePrototype : public ICGetPropCallPrototypeGetter
ICStub *getStub(ICStubSpace *space) {
ReceiverGuard::Token guard = ReceiverGuard::objectToken(receiver_);
Shape *holderShape = holder_->lastProperty();
Shape *holderShape = holder_->as<NativeObject>().lastProperty();
return ICStub::New<ICGetProp_CallNativePrototype>(space, getStubCode(), firstMonitorStub_,
guard, holder_, holderShape,
getter_, pcOffset_);
@ -4964,7 +4964,7 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler
if (newGroup == oldGroup_)
newGroup = nullptr;
RootedShape newShape(cx, obj_->lastProperty());
RootedShape newShape(cx, obj_->as<NativeObject>().lastProperty());
return ICStub::New<ICSetProp_NativeAddImpl<ProtoChainDepth>>(
space, getStubCode(), oldGroup_, shapes, newShape, newGroup, offset_);
@ -5230,7 +5230,7 @@ class ICSetProp_CallScripted : public ICSetPropCallSetter
ICStub *getStub(ICStubSpace *space) {
ReceiverGuard::Token guard = ReceiverGuard::objectToken(obj_);
Shape *holderShape = holder_->lastProperty();
Shape *holderShape = holder_->as<NativeObject>().lastProperty();
return ICStub::New<ICSetProp_CallScripted>(space, getStubCode(), guard, holder_,
holderShape, setter_, pcOffset_);
}
@ -5266,7 +5266,7 @@ class ICSetProp_CallNative : public ICSetPropCallSetter
ICStub *getStub(ICStubSpace *space) {
ReceiverGuard::Token guard = ReceiverGuard::objectToken(obj_);
Shape *holderShape = holder_->lastProperty();
Shape *holderShape = holder_->as<NativeObject>().lastProperty();
return ICStub::New<ICSetProp_CallNative>(space, getStubCode(), guard, holder_,
holderShape, setter_, pcOffset_);
}

View File

@ -4599,7 +4599,7 @@ CodeGenerator::visitNewSingletonCallObject(LNewSingletonCallObject *lir)
uint32_t lexicalBegin = script->bindings.aliasedBodyLevelLexicalBegin();
OutOfLineCode *ool;
ool = oolCallVM(NewSingletonCallObjectInfo, lir,
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
(ArgList(), ImmGCPtr(templateObj->as<CallObject>().lastProperty()),
Imm32(lexicalBegin)),
StoreRegisterTo(objReg));

View File

@ -1777,7 +1777,7 @@ TrackAllProperties(JSContext *cx, JSObject *obj)
{
MOZ_ASSERT(obj->isSingleton());
for (Shape::Range<NoGC> range(obj->lastProperty()); !range.empty(); range.popFront())
for (Shape::Range<NoGC> range(obj->as<NativeObject>().lastProperty()); !range.empty(); range.popFront())
EnsureTrackPropertyTypes(cx, obj, range.front().propid());
}

View File

@ -775,7 +775,7 @@ CheckDOMProxyExpandoDoesNotShadow(JSContext *cx, MacroAssembler &masm, JSObject
masm.extractObject(tempVal, tempVal.scratchReg());
masm.branchPtr(Assembler::Equal,
Address(tempVal.scratchReg(), JSObject::offsetOfShape()),
ImmGCPtr(expandoVal.toObject().lastProperty()),
ImmGCPtr(expandoVal.toObject().as<NativeObject>().lastProperty()),
&domProxyOk);
}
@ -810,7 +810,7 @@ GenerateReadSlot(JSContext *cx, IonScript *ion, MacroAssembler &masm,
if (obj->isNative()) {
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()),
ImmGCPtr(obj->as<NativeObject>().lastProperty()),
failures);
} else {
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
@ -874,7 +874,7 @@ GenerateReadSlot(JSContext *cx, IonScript *ion, MacroAssembler &masm,
// Guard the shape of the current prototype.
masm.branchPtr(Assembler::NotEqual,
Address(scratchReg, JSObject::offsetOfShape()),
ImmGCPtr(proto->lastProperty()),
ImmGCPtr(proto->as<NativeObject>().lastProperty()),
&prototypeFailures);
proto = proto->getProto();
@ -1098,6 +1098,15 @@ EmitGetterCall(JSContext *cx, MacroAssembler &masm,
return true;
}
static void
TestMatchingReceiver(MacroAssembler &masm, Register object, JSObject *obj, Label *failure)
{
if (Shape *shape = obj->maybeShape())
masm.branchTestObjShape(Assembler::NotEqual, object, shape, failure);
else
masm.branchTestObjGroup(Assembler::NotEqual, object, obj->group(), failure);
}
static bool
GenerateCallGetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
IonCache::StubAttacher &attacher, JSObject *obj, PropertyName *name,
@ -1110,13 +1119,7 @@ GenerateCallGetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
Label stubFailure;
failures = failures ? failures : &stubFailure;
// Initial shape/group check.
if (obj->isNative())
masm.branchTestObjShape(Assembler::NotEqual, object, obj->lastProperty(), failures);
else if (obj->is<UnboxedPlainObject>())
masm.branchTestObjGroup(Assembler::NotEqual, object, obj->group(), failures);
else
MOZ_CRASH("Unexpected object");
TestMatchingReceiver(masm, object, obj, failures);
Register scratchReg = output.valueReg().scratchReg();
bool spillObjReg = scratchReg == object;
@ -1138,7 +1141,7 @@ GenerateCallGetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
masm.movePtr(ImmMaybeNurseryPtr(holder), holderReg);
masm.branchPtr(Assembler::NotEqual,
Address(holderReg, JSObject::offsetOfShape()),
ImmGCPtr(holder->lastProperty()),
ImmGCPtr(holder->as<NativeObject>().lastProperty()),
maybePopAndFail);
if (spillObjReg)
@ -1172,7 +1175,7 @@ GenerateArrayLength(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher
Label failures;
// Guard object is a dense array.
RootedShape shape(cx, obj->lastProperty());
RootedShape shape(cx, obj->as<ArrayObject>().lastProperty());
if (!shape)
return false;
masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
@ -1556,7 +1559,7 @@ GetPropertyIC::tryAttachDOMProxyShadowed(JSContext *cx, HandleScript outerScript
// Guard on the shape of the object.
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object(), JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()),
ImmGCPtr(obj->maybeShape()),
&failures);
// No need for more guards: we know this is a DOM proxy, since the shape
@ -1625,7 +1628,7 @@ GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext *cx, HandleScript outerScri
// Guard on the shape of the object.
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object(), JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()),
ImmGCPtr(obj->maybeShape()),
&failures);
// Guard that our expando object hasn't started shadowing this property.
@ -2239,7 +2242,7 @@ SetPropertyIC::attachDOMProxyShadowed(JSContext *cx, HandleScript outerScript, I
// Guard on the shape of the object.
masm.branchPtr(Assembler::NotEqual,
Address(object(), JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()), &failures);
ImmGCPtr(obj->maybeShape()), &failures);
// No need for more guards: we know this is a DOM proxy, since the shape
// guard enforces a given JSClass, so just go ahead and emit the call to
@ -2289,7 +2292,7 @@ GenerateCallSetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
masm.movePtr(ImmMaybeNurseryPtr(holder), scratchReg);
masm.branchPtr(Assembler::NotEqual,
Address(scratchReg, JSObject::offsetOfShape()),
ImmGCPtr(holder->lastProperty()),
ImmGCPtr(holder->as<NativeObject>().lastProperty()),
&protoFailure);
masm.jump(&protoSuccess);
@ -2513,7 +2516,7 @@ SetPropertyIC::attachDOMProxyUnshadowed(JSContext *cx, HandleScript outerScript,
// Guard on the shape of the object.
masm.branchPtr(Assembler::NotEqual,
Address(object(), JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()), &failures);
ImmGCPtr(obj->maybeShape()), &failures);
// Guard that our expando object hasn't started shadowing this property.
CheckDOMProxyExpandoDoesNotShadow(cx, masm, obj, name(), object(), &failures);
@ -2564,12 +2567,7 @@ SetPropertyIC::attachCallSetter(JSContext *cx, HandleScript outerScript, IonScri
RepatchStubAppender attacher(*this);
Label failure;
if (obj->isNative())
masm.branchTestObjShape(Assembler::NotEqual, object(), obj->lastProperty(), &failure);
else if (obj->is<UnboxedPlainObject>())
masm.branchTestObjGroup(Assembler::NotEqual, object(), obj->group(), &failure);
else
MOZ_CRASH("Unexpected object");
TestMatchingReceiver(masm, object(), obj, &failure);
if (!GenerateCallSetter(cx, ion, masm, attacher, obj, holder, shape, strict(),
object(), value(), &failure, liveRegs_, returnAddr))
@ -2617,7 +2615,7 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
JSObject *proto = obj->getProto();
Register protoReg = object;
while (proto) {
Shape *protoShape = proto->lastProperty();
Shape *protoShape = proto->as<NativeObject>().lastProperty();
// load next prototype
masm.loadObjProto(protoReg, protoReg);
@ -3026,7 +3024,7 @@ SetPropertyIC::update(JSContext *cx, HandleScript outerScript, size_t cacheIndex
}
uint32_t oldSlots = obj->is<NativeObject>() ? obj->as<NativeObject>().numDynamicSlots() : 0;
RootedShape oldShape(cx, obj->lastProperty());
RootedShape oldShape(cx, obj->maybeShape());
// Set/Add the property on the object, the inlined cache are setup for the next execution.
if (!SetProperty(cx, obj, name, value, cache.strict(), cache.pc()))
@ -3195,7 +3193,7 @@ GenerateDenseElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher
Label failures;
// Guard object's shape.
RootedShape shape(cx, obj->lastProperty());
RootedShape shape(cx, obj->as<NativeObject>().lastProperty());
if (!shape)
return false;
masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
@ -3303,7 +3301,6 @@ GenerateDenseElementHole(JSContext *cx, MacroAssembler &masm, IonCache::StubAtta
Register object, ConstantOrRegister index, TypedOrValueRegister output)
{
MOZ_ASSERT(GetElementIC::canAttachDenseElementHole(obj, idval, output));
MOZ_ASSERT(obj->lastProperty());
Register scratchReg = output.valueReg().scratchReg();
@ -3311,7 +3308,7 @@ GenerateDenseElementHole(JSContext *cx, MacroAssembler &masm, IonCache::StubAtta
Label failures;
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()), &failures);
ImmGCPtr(obj->as<NativeObject>().lastProperty()), &failures);
if (obj->hasUncacheableProto()) {
@ -3323,7 +3320,7 @@ GenerateDenseElementHole(JSContext *cx, MacroAssembler &masm, IonCache::StubAtta
JSObject *pobj = obj->getProto();
while (pobj) {
MOZ_ASSERT(pobj->lastProperty());
MOZ_ASSERT(pobj->as<NativeObject>().lastProperty());
masm.movePtr(ImmMaybeNurseryPtr(pobj), scratchReg);
if (pobj->hasUncacheableProto()) {
@ -3334,7 +3331,7 @@ GenerateDenseElementHole(JSContext *cx, MacroAssembler &masm, IonCache::StubAtta
// Make sure the shape matches, to avoid non-dense elements.
masm.branchPtr(Assembler::NotEqual, Address(scratchReg, JSObject::offsetOfShape()),
ImmGCPtr(pobj->lastProperty()), &failures);
ImmGCPtr(pobj->as<NativeObject>().lastProperty()), &failures);
// Load elements vector.
masm.loadPtr(Address(scratchReg, NativeObject::offsetOfElements()), scratchReg);
@ -3872,7 +3869,7 @@ GenerateSetDenseElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttac
Label markElem, storeElement; // used if TI protects us from worrying about holes.
// Guard object is a dense array.
Shape *shape = obj->lastProperty();
Shape *shape = obj->as<NativeObject>().lastProperty();
if (!shape)
return false;
masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
@ -4148,7 +4145,8 @@ GenerateScopeChainGuard(MacroAssembler &masm, JSObject *scopeObj,
}
Address shapeAddr(scopeObjReg, JSObject::offsetOfShape());
masm.branchPtr(Assembler::NotEqual, shapeAddr, ImmGCPtr(scopeObj->lastProperty()), failures);
masm.branchPtr(Assembler::NotEqual, shapeAddr,
ImmGCPtr(scopeObj->as<NativeObject>().lastProperty()), failures);
}
static void
@ -4189,7 +4187,7 @@ BindNameIC::attachNonGlobal(JSContext *cx, HandleScript outerScript, IonScript *
Label failures;
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(scopeChainReg(), JSObject::offsetOfShape()),
ImmGCPtr(scopeChain->lastProperty()),
ImmGCPtr(scopeChain->as<NativeObject>().lastProperty()),
holder != scopeChain ? &failures : nullptr);
if (holder != scopeChain) {

View File

@ -1219,9 +1219,11 @@ MacroAssembler::initGCThing(Register obj, Register slots, JSObject *templateObj,
{
// Fast initialization of an empty object returned by allocateObject().
storePtr(ImmGCPtr(templateObj->lastProperty()), Address(obj, JSObject::offsetOfShape()));
storePtr(ImmGCPtr(templateObj->group()), Address(obj, JSObject::offsetOfGroup()));
if (Shape *shape = templateObj->maybeShape())
storePtr(ImmGCPtr(shape), Address(obj, JSObject::offsetOfShape()));
if (templateObj->isNative()) {
NativeObject *ntemplate = &templateObj->as<NativeObject>();
MOZ_ASSERT_IF(!ntemplate->denseElementsAreCopyOnWrite(), !ntemplate->hasDynamicElements());
@ -1280,6 +1282,8 @@ MacroAssembler::initGCThing(Register obj, Register slots, JSObject *templateObj,
} else if (templateObj->is<UnboxedPlainObject>()) {
const UnboxedLayout &layout = templateObj->as<UnboxedPlainObject>().layout();
storePtr(ImmWord(0), Address(obj, JSObject::offsetOfShape()));
// Initialize reference fields of the object, per UnboxedPlainObject::create.
if (const int32_t *list = layout.traceList()) {
while (*list != -1) {

View File

@ -168,7 +168,7 @@ IsObjectEscaped(MInstruction *ins, JSObject *objDefault = nullptr)
case MDefinition::Op_GuardShape: {
MGuardShape *guard = def->toGuardShape();
MOZ_ASSERT(!ins->isGuardShape());
if (obj->lastProperty() != guard->shape()) {
if (obj->as<NativeObject>().lastProperty() != guard->shape()) {
JitSpewDef(JitSpew_Escape, "Object ", ins);
JitSpewDef(JitSpew_Escape, " has a non-matching guard shape\n", guard);
return true;

View File

@ -1143,8 +1143,8 @@ AssertValidObjectPtr(JSContext *cx, JSObject *obj)
MOZ_ASSERT(obj->compartment() == cx->compartment());
MOZ_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
MOZ_ASSERT_IF(!obj->hasLazyGroup(),
obj->group()->clasp() == obj->lastProperty()->getObjectClass());
MOZ_ASSERT_IF(!obj->hasLazyGroup() && obj->maybeShape(),
obj->group()->clasp() == obj->maybeShape()->getObjectClass());
if (obj->isTenured()) {
MOZ_ASSERT(obj->isAligned());

View File

@ -2754,7 +2754,7 @@ GetIndexedPropertiesInRange(JSContext *cx, HandleObject obj, uint32_t begin, uin
// Append sparse elements.
if (pobj->isIndexed()) {
Shape::Range<NoGC> r(pobj->lastProperty());
Shape::Range<NoGC> r(pobj->as<NativeObject>().lastProperty());
for (; !r.empty(); r.popFront()) {
Shape &shape = r.front();
jsid id = shape.propid();
@ -3535,7 +3535,7 @@ js::NewDenseFullyAllocatedArrayWithTemplate(JSContext *cx, uint32_t length, JSOb
allocKind = GetBackgroundAllocKind(allocKind);
RootedObjectGroup group(cx, templateObject->group());
RootedShape shape(cx, templateObject->lastProperty());
RootedShape shape(cx, templateObject->as<ArrayObject>().lastProperty());
gc::InitialHeap heap = GetInitialHeap(GenericObject, &ArrayObject::class_);
Rooted<ArrayObject *> arr(cx, ArrayObject::createArray(cx, allocKind,

View File

@ -321,10 +321,10 @@ js::IsCallObject(JSObject *obj)
return obj->is<CallObject>();
}
JS_FRIEND_API(JSObject *)
js::GetObjectParentMaybeScope(JSObject *obj)
JS_FRIEND_API(bool)
js::CanAccessObjectShape(JSObject *obj)
{
return obj->enclosingScope();
return obj->maybeShape() != nullptr;
}
JS_FRIEND_API(JSObject *)

View File

@ -563,8 +563,9 @@ public:
static const uint32_t FIXED_SLOTS_SHIFT = 27;
};
// This layout is shared by all objects except for Typed Objects (which still
// have a shape and group).
// This layout is shared by all native objects. For non-native objects, the
// group may always be accessed safely, and other members may be as well,
// depending on the object's specific layout.
struct Object {
shadow::ObjectGroup *group;
shadow::Shape *shape;
@ -683,10 +684,14 @@ IsScopeObject(JSObject *obj);
JS_FRIEND_API(bool)
IsCallObject(JSObject *obj);
JS_FRIEND_API(bool)
CanAccessObjectShape(JSObject *obj);
inline JSObject *
GetObjectParent(JSObject *obj)
{
MOZ_ASSERT(!IsScopeObject(obj));
MOZ_ASSERT(CanAccessObjectShape(obj));
return reinterpret_cast<shadow::Object*>(obj)->shape->base->parent;
}
@ -696,9 +701,6 @@ GetObjectCompartment(JSObject *obj)
return reinterpret_cast<shadow::Object*>(obj)->group->compartment;
}
JS_FRIEND_API(JSObject *)
GetObjectParentMaybeScope(JSObject *obj);
JS_FRIEND_API(JSObject *)
GetGlobalForObjectCrossCompartment(JSObject *obj);

View File

@ -510,8 +510,8 @@ AllocateObject(ExclusiveContext *cx, AllocKind kind, size_t nDynamicSlots, Initi
size_t thingSize = Arena::thingSize(kind);
MOZ_ASSERT(thingSize == Arena::thingSize(kind));
MOZ_ASSERT(thingSize >= sizeof(JSObject));
static_assert(sizeof(JSObject) >= CellSize,
MOZ_ASSERT(thingSize >= sizeof(JSObject_Slots0));
static_assert(sizeof(JSObject_Slots0) >= CellSize,
"All allocations must be at least the allocator-imposed minimum size.");
if (!CheckAllocatorState<allowGC>(cx, kind))
@ -579,9 +579,11 @@ AllocateNonObject(ExclusiveContext *cx)
* fail the allocation, forcing the non-cached path.
*/
template <AllowGC allowGC>
inline JSObject *
inline NativeObject *
AllocateObjectForCacheHit(JSContext *cx, AllocKind kind, InitialHeap heap, const js::Class *clasp)
{
MOZ_ASSERT(clasp->isNative());
if (ShouldNurseryAllocateObject(cx->nursery(), heap)) {
size_t thingSize = Arena::thingSize(kind);
@ -594,7 +596,7 @@ AllocateObjectForCacheHit(JSContext *cx, AllocKind kind, InitialHeap heap, const
cx->minorGC(JS::gcreason::OUT_OF_NURSERY);
return nullptr;
}
return obj;
return reinterpret_cast<NativeObject *>(obj);
}
JSObject *obj = AllocateObject<NoGC>(cx, kind, 0, heap, clasp);
@ -603,7 +605,7 @@ AllocateObjectForCacheHit(JSContext *cx, AllocKind kind, InitialHeap heap, const
return nullptr;
}
return obj;
return reinterpret_cast<NativeObject *>(obj);
}
inline bool

View File

@ -600,7 +600,7 @@ VectorToKeyIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVecto
JSObject *pobj = obj;
size_t ind = 0;
do {
ni->shapes_array[ind++] = pobj->lastProperty();
ni->shapes_array[ind++] = pobj->as<NativeObject>().lastProperty();
pobj = pobj->getProto();
} while (pobj);
MOZ_ASSERT(ind == slength);
@ -711,12 +711,12 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleOb
if (!(lastni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
obj->isNative() &&
obj->as<NativeObject>().hasEmptyElements() &&
obj->lastProperty() == lastni->shapes_array[0])
obj->as<NativeObject>().lastProperty() == lastni->shapes_array[0])
{
JSObject *proto = obj->getProto();
if (proto->isNative() &&
proto->as<NativeObject>().hasEmptyElements() &&
proto->lastProperty() == lastni->shapes_array[1] &&
proto->as<NativeObject>().lastProperty() == lastni->shapes_array[1] &&
!proto->getProto())
{
objp.set(last);
@ -747,7 +747,7 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleOb
shapes.clear();
goto miss;
}
Shape *shape = pobj->lastProperty();
Shape *shape = pobj->as<NativeObject>().lastProperty();
key = (key + (key << 16)) ^ (uintptr_t(shape) >> 3);
if (!shapes.append(shape))
return false;

View File

@ -2213,7 +2213,7 @@ js::CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj)
if (!res)
return nullptr;
RootedShape newShape(cx, ReshapeForParentAndAllocKind(cx, srcObj->lastProperty(),
RootedShape newShape(cx, ReshapeForParentAndAllocKind(cx, srcObj->as<PlainObject>().lastProperty(),
TaggedProto(proto), parent, kind));
if (!newShape || !res->setLastProperty(cx, newShape))
return nullptr;
@ -2294,7 +2294,7 @@ JSObject::fixDictionaryShapeAfterSwap()
// Dictionary shapes can point back to their containing objects, so after
// swapping the guts of those objects fix the pointers up.
if (isNative() && as<NativeObject>().inDictionaryMode())
shape_->listp = &shape_;
as<NativeObject>().shape_->listp = &as<NativeObject>().shape_;
}
/* Use this method with extreme caution. It trades the guts of two objects. */
@ -3660,7 +3660,7 @@ js::GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
Shape *shape;
if (obj->isNative()) {
shape = obj->lastProperty();
shape = obj->as<NativeObject>().lastProperty();
while (shape && (!shape->hasSlot() || shape->slot() != slot))
shape = shape->previous();
} else {
@ -3937,7 +3937,7 @@ JSObject::dump()
if (obj->isNative()) {
fprintf(stderr, "properties:\n");
Vector<Shape *, 8, SystemAllocPolicy> props;
for (Shape::Range<NoGC> r(obj->lastProperty()); !r.empty(); r.popFront())
for (Shape::Range<NoGC> r(obj->as<NativeObject>().lastProperty()); !r.empty(); r.popFront())
props.append(&r.front());
for (size_t i = props.length(); i-- != 0;)
DumpProperty(&obj->as<NativeObject>(), *props[i]);
@ -4117,14 +4117,15 @@ JSObject::markChildren(JSTracer *trc)
{
MarkObjectGroup(trc, &group_, "group");
MarkShape(trc, &shape_, "shape");
const Class *clasp = group_->clasp();
if (clasp->trace)
clasp->trace(trc, this);
if (shape_->isNative()) {
if (clasp->isNative()) {
NativeObject *nobj = &as<NativeObject>();
MarkShape(trc, &nobj->shape_, "shape");
MarkObjectSlots(trc, nobj, 0, nobj->slotSpan());
do {
@ -4143,3 +4144,16 @@ JSObject::markChildren(JSTracer *trc)
} while (false);
}
}
JSObject *
JSObject::getParent() const
{
if (Shape *shape = maybeShape())
return shape->getObjectParent();
// Avoid the parent-link checking in JSObject::global. Unboxed plain
// objects keep their compartment's global alive through their layout, and
// don't need a read barrier here.
MOZ_ASSERT(is<UnboxedPlainObject>());
return compartment()->unsafeUnbarrieredMaybeGlobal();
}

View File

@ -92,20 +92,21 @@ bool SetImmutablePrototype(js::ExclusiveContext *cx, JS::HandleObject obj, bool
/*
* A JavaScript object. The members common to all objects are as follows:
*
* - The |shape_| member stores the shape of the object, which includes the
* object's class and the layout of all its properties.
*
* - The |group_| member stores the group of the object, which contains its
* prototype object and the possible types of its properties.
* prototype object, its class and the possible types of its properties.
*
* Subclasses of JSObject --- mainly NativeObject and JSFunction --- add more
* members.
* members. Notable among these is the object's shape, which stores flags and
* some other state, and, for native objects, the layout of all its properties.
* The second word of a JSObject generally stores its shape; if the second word
* stores anything else, the value stored cannot be a valid Shape* pointer, so
* that shape guards can be performed on objects without regard to the specific
* layout in use.
*/
class JSObject : public js::gc::Cell
{
protected:
js::HeapPtrObjectGroup group_;
js::HeapPtrShape shape_;
private:
friend class js::Shape;
@ -121,13 +122,8 @@ class JSObject : public js::gc::Cell
static js::ObjectGroup *makeLazyGroup(JSContext *cx, js::HandleObject obj);
public:
js::Shape * lastProperty() const {
MOZ_ASSERT(shape_);
return shape_;
}
bool isNative() const {
return lastProperty()->isNative();
return getClass()->isNative();
}
const js::Class *getClass() const {
@ -172,6 +168,9 @@ class JSObject : public js::gc::Cell
return group_->compartment();
}
inline js::Shape *maybeShape() const;
inline js::Shape *ensureShape(js::ExclusiveContext *cx);
/*
* Make a non-array object with the specified initial state. This method
* takes ownership of any extantSlots it is passed.
@ -182,6 +181,13 @@ class JSObject : public js::gc::Cell
js::HandleShape shape,
js::HandleObjectGroup group);
// Set the shape of an object. This pointer is valid for native objects and
// some non-native objects. After creating an object, tobjects for which
// the shape pointer is invalid need to overwrite this pointer before a GC
// can occur.
inline void setInitialShapeMaybeNonNative(js::Shape *shape);
inline void setShapeMaybeNonNative(js::Shape *shape);
// Set the initial slots and elements of an object. These pointers are only
// valid for native objects, but during initialization are set for all
// objects. For non-native objects, these must not be dynamically allocated
@ -194,8 +200,9 @@ class JSObject : public js::gc::Cell
GENERATE_SHAPE
};
bool setFlags(js::ExclusiveContext *cx, /*BaseShape::Flag*/ uint32_t flags,
bool setFlags(js::ExclusiveContext *cx, js::BaseShape::Flag flags,
GenerateShape generateShape = GENERATE_NONE);
inline bool hasAllFlags(js::BaseShape::Flag flags) const;
/*
* An object is a delegate if it is on another object's prototype or scope
@ -206,23 +213,15 @@ class JSObject : public js::gc::Cell
* definition helps to optimize shape-based property cache invalidation
* (see Purge{Scope,Proto}Chain in jsobj.cpp).
*/
bool isDelegate() const {
return lastProperty()->hasObjectFlag(js::BaseShape::DELEGATE);
}
inline bool isDelegate() const;
bool setDelegate(js::ExclusiveContext *cx) {
return setFlags(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE);
}
bool isBoundFunction() const {
return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION);
}
inline bool isBoundFunction() const;
inline bool hasSpecialEquality() const;
bool watched() const {
return lastProperty()->hasObjectFlag(js::BaseShape::WATCHED);
}
inline bool watched() const;
bool setWatched(js::ExclusiveContext *cx) {
return setFlags(cx, js::BaseShape::WATCHED, GENERATE_SHAPE);
}
@ -244,9 +243,7 @@ class JSObject : public js::gc::Cell
* and JIT inline caches should not be filled for lookups across prototype
* lookups on the object.
*/
bool hasUncacheableProto() const {
return lastProperty()->hasObjectFlag(js::BaseShape::UNCACHEABLE_PROTO);
}
inline bool hasUncacheableProto() const;
bool setUncacheableProto(js::ExclusiveContext *cx) {
return setFlags(cx, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE);
}
@ -255,9 +252,7 @@ class JSObject : public js::gc::Cell
* Whether SETLELEM was used to access this object. See also the comment near
* PropertyTree::MAX_HEIGHT.
*/
bool hadElementsAccess() const {
return lastProperty()->hasObjectFlag(js::BaseShape::HAD_ELEMENTS_ACCESS);
}
inline bool hadElementsAccess() const;
bool setHadElementsAccess(js::ExclusiveContext *cx) {
return setFlags(cx, js::BaseShape::HAD_ELEMENTS_ACCESS);
}
@ -266,17 +261,7 @@ class JSObject : public js::gc::Cell
* Whether there may be indexed properties on this object, excluding any in
* the object's elements.
*/
bool isIndexed() const {
return lastProperty()->hasObjectFlag(js::BaseShape::INDEXED);
}
uint32_t propertyCount() const {
return lastProperty()->entryCount();
}
bool hasShapeTable() const {
return lastProperty()->hasTable();
}
inline bool isIndexed() const;
/* GC support. */
@ -295,7 +280,7 @@ class JSObject : public js::gc::Cell
return JS::shadow::Zone::asShadowZone(zone());
}
MOZ_ALWAYS_INLINE JS::Zone *zoneFromAnyThread() const {
return shape_->zoneFromAnyThread();
return group_->zoneFromAnyThread();
}
MOZ_ALWAYS_INLINE JS::shadow::Zone *shadowZoneFromAnyThread() const {
return JS::shadow::Zone::asShadowZone(zoneFromAnyThread());
@ -377,10 +362,7 @@ class JSObject : public js::gc::Cell
// True iff this object's [[Prototype]] is immutable. Must not be called
// on proxies with lazy [[Prototype]]!
bool nonLazyPrototypeIsImmutable() const {
MOZ_ASSERT(!hasLazyPrototype());
return lastProperty()->hasObjectFlag(js::BaseShape::IMMUTABLE_PROTOTYPE);
}
inline bool nonLazyPrototypeIsImmutable() const;
inline void setGroup(js::ObjectGroup *group);
@ -389,9 +371,7 @@ class JSObject : public js::gc::Cell
* to recover this information in the object's type information after it
* is purged on GC.
*/
bool isIteratedSingleton() const {
return lastProperty()->hasObjectFlag(js::BaseShape::ITERATED_SINGLETON);
}
inline bool isIteratedSingleton() const;
bool setIteratedSingleton(js::ExclusiveContext *cx) {
return setFlags(cx, js::BaseShape::ITERATED_SINGLETON);
}
@ -400,15 +380,11 @@ class JSObject : public js::gc::Cell
* Mark an object as requiring its default 'new' type to have unknown
* properties.
*/
bool isNewGroupUnknown() const {
return lastProperty()->hasObjectFlag(js::BaseShape::NEW_GROUP_UNKNOWN);
}
inline bool isNewGroupUnknown() const;
static bool setNewGroupUnknown(JSContext *cx, const js::Class *clasp, JS::HandleObject obj);
// Mark an object as having its 'new' script information cleared.
bool wasNewScriptCleared() const {
return lastProperty()->hasObjectFlag(js::BaseShape::NEW_SCRIPT_CLEARED);
}
inline bool wasNewScriptCleared() const;
bool setNewScriptCleared(js::ExclusiveContext *cx) {
return setFlags(cx, js::BaseShape::NEW_SCRIPT_CLEARED);
}
@ -449,9 +425,7 @@ class JSObject : public js::gc::Cell
*/
/* Access the parent link of an object. */
JSObject *getParent() const {
return lastProperty()->getObjectParent();
}
JSObject *getParent() const;
static bool setParent(JSContext *cx, js::HandleObject obj, js::HandleObject newParent);
/*
@ -462,9 +436,7 @@ class JSObject : public js::gc::Cell
inline JSObject *enclosingScope();
/* Access the metadata on an object. */
inline JSObject *getMetadata() const {
return lastProperty()->getObjectMetadata();
}
inline JSObject *getMetadata() const;
static bool setMetadata(JSContext *cx, js::HandleObject obj, js::HandleObject newMetadata);
inline js::GlobalObject &global() const;
@ -479,12 +451,7 @@ class JSObject : public js::gc::Cell
// This method really shouldn't exist -- but there are a few internal
// places that want it (JITs and the like), and it'd be a pain to mark them
// all as friends.
bool nonProxyIsExtensible() const {
MOZ_ASSERT(!uninlinedIsProxy());
// [[Extensible]] for ordinary non-proxy objects is an object flag.
return !lastProperty()->hasObjectFlag(js::BaseShape::NOT_EXTENSIBLE);
}
inline bool nonProxyIsExtensible() const;
public:
/*
@ -576,8 +543,8 @@ class JSObject : public js::gc::Cell
/* JIT Accessors */
static size_t offsetOfShape() { return offsetof(JSObject, shape_); }
static size_t offsetOfGroup() { return offsetof(JSObject, group_); }
static size_t offsetOfShape() { return sizeof(JSObject); }
// Maximum size in bytes of a JSObject.
static const size_t MAX_BYTE_SIZE = 4 * sizeof(void *) + 16 * sizeof(JS::Value);
@ -624,12 +591,12 @@ operator!=(const JSObject &lhs, const JSObject &rhs)
}
// Size of the various GC thing allocation sizes used for objects.
struct JSObject_Slots0 : JSObject { void *data[2]; };
struct JSObject_Slots2 : JSObject { void *data[2]; js::Value fslots[2]; };
struct JSObject_Slots4 : JSObject { void *data[2]; js::Value fslots[4]; };
struct JSObject_Slots8 : JSObject { void *data[2]; js::Value fslots[8]; };
struct JSObject_Slots12 : JSObject { void *data[2]; js::Value fslots[12]; };
struct JSObject_Slots16 : JSObject { void *data[2]; js::Value fslots[16]; };
struct JSObject_Slots0 : JSObject { void *data[3]; };
struct JSObject_Slots2 : JSObject { void *data[3]; js::Value fslots[2]; };
struct JSObject_Slots4 : JSObject { void *data[3]; js::Value fslots[4]; };
struct JSObject_Slots8 : JSObject { void *data[3]; js::Value fslots[8]; };
struct JSObject_Slots12 : JSObject { void *data[3]; js::Value fslots[12]; };
struct JSObject_Slots16 : JSObject { void *data[3]; js::Value fslots[16]; };
/* static */ MOZ_ALWAYS_INLINE void
JSObject::readBarrier(JSObject *obj)

View File

@ -25,6 +25,24 @@
#include "vm/TypeInference-inl.h"
inline js::Shape *
JSObject::maybeShape() const
{
if (is<js::UnboxedPlainObject>())
return nullptr;
return *reinterpret_cast<js::Shape **>(uintptr_t(this) + offsetOfShape());
}
inline js::Shape *
JSObject::ensureShape(js::ExclusiveContext *cx)
{
if (is<js::UnboxedPlainObject>() && !js::UnboxedPlainObject::convertToNative(cx->asJSContext(), this))
return nullptr;
js::Shape *shape = maybeShape();
MOZ_ASSERT(shape);
return shape;
}
inline void
JSObject::finalize(js::FreeOp *fop)
{
@ -67,8 +85,8 @@ JSObject::finalize(js::FreeOp *fop)
// unreachable shapes may be marked whose listp points into this object.
// In case this happens, null out the shape's pointer here so that a moving
// GC will not try to access the dead object.
if (shape_->listp == &shape_)
shape_->listp = nullptr;
if (nobj->shape_->listp == &nobj->shape_)
nobj->shape_->listp = nullptr;
}
/* static */ inline bool
@ -188,7 +206,7 @@ JSObject::isQualifiedVarObj()
{
if (is<js::DebugScopeObject>())
return as<js::DebugScopeObject>().scope().isQualifiedVarObj();
return lastProperty()->hasObjectFlag(js::BaseShape::QUALIFIED_VAROBJ);
return hasAllFlags(js::BaseShape::QUALIFIED_VAROBJ);
}
inline bool
@ -196,7 +214,7 @@ JSObject::isUnqualifiedVarObj()
{
if (is<js::DebugScopeObject>())
return as<js::DebugScopeObject>().scope().isUnqualifiedVarObj();
return lastProperty()->hasObjectFlag(js::BaseShape::UNQUALIFIED_VAROBJ);
return hasAllFlags(js::BaseShape::UNQUALIFIED_VAROBJ);
}
namespace js {
@ -247,9 +265,10 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
if (!obj)
return nullptr;
obj->shape_.init(shape);
obj->group_.init(group);
obj->setInitialShapeMaybeNonNative(shape);
// Note: slots are created and assigned internally by NewGCObject.
obj->setInitialElementsMaybeNonNative(js::emptyObjectElements);
@ -268,6 +287,19 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
return obj;
}
inline void
JSObject::setInitialShapeMaybeNonNative(js::Shape *shape)
{
static_cast<js::NativeObject *>(this)->shape_.init(shape);
}
inline void
JSObject::setShapeMaybeNonNative(js::Shape *shape)
{
MOZ_ASSERT(!is<js::UnboxedPlainObject>());
static_cast<js::NativeObject *>(this)->shape_ = shape;
}
inline void
JSObject::setInitialSlotsMaybeNonNative(js::HeapSlot *slots)
{
@ -280,6 +312,14 @@ JSObject::setInitialElementsMaybeNonNative(js::HeapSlot *elements)
static_cast<js::NativeObject *>(this)->elements_ = elements;
}
inline JSObject *
JSObject::getMetadata() const
{
if (js::Shape *shape = maybeShape())
return shape->getObjectMetadata();
return nullptr;
}
inline js::GlobalObject &
JSObject::global() const
{
@ -303,6 +343,85 @@ JSObject::isOwnGlobal() const
return &global() == this;
}
inline bool
JSObject::hasAllFlags(js::BaseShape::Flag flags) const
{
MOZ_ASSERT(flags);
if (js::Shape *shape = maybeShape())
return shape->hasAllObjectFlags(flags);
return false;
}
inline bool
JSObject::nonProxyIsExtensible() const
{
MOZ_ASSERT(!uninlinedIsProxy());
// [[Extensible]] for ordinary non-proxy objects is an object flag.
return !hasAllFlags(js::BaseShape::NOT_EXTENSIBLE);
}
inline bool
JSObject::isBoundFunction() const
{
return hasAllFlags(js::BaseShape::BOUND_FUNCTION);
}
inline bool
JSObject::watched() const
{
return hasAllFlags(js::BaseShape::WATCHED);
}
inline bool
JSObject::isDelegate() const
{
return hasAllFlags(js::BaseShape::DELEGATE);
}
inline bool
JSObject::hasUncacheableProto() const
{
return hasAllFlags(js::BaseShape::UNCACHEABLE_PROTO);
}
inline bool
JSObject::hadElementsAccess() const
{
return hasAllFlags(js::BaseShape::HAD_ELEMENTS_ACCESS);
}
inline bool
JSObject::isIndexed() const
{
return hasAllFlags(js::BaseShape::INDEXED);
}
inline bool
JSObject::nonLazyPrototypeIsImmutable() const
{
MOZ_ASSERT(!hasLazyPrototype());
return hasAllFlags(js::BaseShape::IMMUTABLE_PROTOTYPE);
}
inline bool
JSObject::isIteratedSingleton() const
{
return hasAllFlags(js::BaseShape::ITERATED_SINGLETON);
}
inline bool
JSObject::isNewGroupUnknown() const
{
return hasAllFlags(js::BaseShape::NEW_GROUP_UNKNOWN);
}
inline bool
JSObject::wasNewScriptCleared() const
{
return hasAllFlags(js::BaseShape::NEW_SCRIPT_CLEARED);
}
namespace js {
PropDesc::PropDesc(const Value &getter, const Value &setter,

View File

@ -253,8 +253,8 @@ Shape::fixupDictionaryShapeAfterMovingGC()
} else {
// listp points to the shape_ field of an object.
JSObject *last = reinterpret_cast<JSObject *>(uintptr_t(listp) -
offsetof(JSObject, shape_));
listp = &gc::MaybeForwarded(last)->shape_;
JSObject::offsetOfShape());
listp = &gc::MaybeForwarded(last)->as<NativeObject>().shape_;
}
}

View File

@ -611,6 +611,8 @@ ProxyObject::trace(JSTracer *trc, JSObject *obj)
{
ProxyObject *proxy = &obj->as<ProxyObject>();
MarkShape(trc, &proxy->shape, "ProxyObject_shape");
#ifdef DEBUG
if (trc->runtime()->gc.isStrictProxyCheckingEnabled() && proxy->is<WrapperObject>()) {
JSObject *referent = MaybeForwarded(&proxy->private_().toObject());

View File

@ -2884,7 +2884,7 @@ ShapeOf(JSContext *cx, unsigned argc, JS::Value *vp)
return false;
}
JSObject *obj = &args[0].toObject();
args.rval().set(JS_NumberValue(double(uintptr_t(obj->lastProperty()) >> 3)));
args.rval().set(JS_NumberValue(double(uintptr_t(obj->maybeShape()) >> 3)));
return true;
}

View File

@ -386,13 +386,14 @@ void
NativeObject::setLastPropertyMakeNative(ExclusiveContext *cx, Shape *shape)
{
MOZ_ASSERT(getClass()->isNative());
MOZ_ASSERT(!lastProperty()->isNative());
MOZ_ASSERT(shape->isNative());
MOZ_ASSERT(!inDictionaryMode());
MOZ_ASSERT(!shape->inDictionary());
MOZ_ASSERT(shape->compartment() == compartment());
shape_ = shape;
// This method is used to convert unboxed objects into native objects. In
// this case, the shape_ field was previously used to store other data and
// this should be treated as an initialization.
shape_.init(shape);
slots_ = nullptr;
elements_ = emptyObjectElements;

View File

@ -341,6 +341,9 @@ DenseRangeWriteBarrierPost(JSRuntime *rt, NativeObject *obj, uint32_t start, uin
class NativeObject : public JSObject
{
protected:
// Property layout description and other state.
HeapPtrShape shape_;
/* Slots for object properties. */
js::HeapSlot *slots_;
@ -378,6 +381,19 @@ class NativeObject : public JSObject
}
public:
Shape *lastProperty() const {
MOZ_ASSERT(shape_);
return shape_;
}
uint32_t propertyCount() const {
return lastProperty()->entryCount();
}
bool hasShapeTable() const {
return lastProperty()->hasTable();
}
HeapSlotArray getDenseElements() {
return HeapSlotArray(elements_, !getElementsHeader()->isCopyOnWrite());
}

View File

@ -312,7 +312,7 @@ JSObject::makeLazyGroup(JSContext *cx, HandleObject obj)
// Don't track whether singletons are packed.
ObjectGroupFlags initialFlags = OBJECT_FLAG_SINGLETON | OBJECT_FLAG_NON_PACKED;
if (obj->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
if (obj->isIteratedSingleton())
initialFlags |= OBJECT_FLAG_ITERATED;
if (obj->isIndexed())

View File

@ -170,7 +170,7 @@ js::ForOfPIC::Chain::getMatchingStub(JSObject *obj)
// Check if there is a matching stub.
for (Stub *stub = stubs(); stub != nullptr; stub = stub->next()) {
if (stub->shape() == obj->lastProperty())
if (stub->shape() == obj->maybeShape())
return stub;
}

View File

@ -16,6 +16,8 @@ namespace js {
// instantiated.
class ProxyObject : public JSObject
{
HeapPtrShape shape;
// GetProxyDataLayout computes the address of this field.
ProxyDataLayout data;

View File

@ -38,7 +38,7 @@ NewObjectCache::fillGlobal(EntryIndex entry, const Class *clasp, js::GlobalObjec
return fill(entry, clasp, global, kind, obj);
}
inline JSObject *
inline NativeObject *
NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entryIndex, js::gc::InitialHeap heap)
{
// The new object cache does not account for metadata attached via callbacks.
@ -47,7 +47,7 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entryIndex, js::gc::I
MOZ_ASSERT(unsigned(entryIndex) < mozilla::ArrayLength(entries));
Entry *entry = &entries[entryIndex];
JSObject *templateObj = reinterpret_cast<JSObject *>(&entry->templateObject);
NativeObject *templateObj = reinterpret_cast<NativeObject *>(&entry->templateObject);
// Do an end run around JSObject::group() to avoid doing AutoUnprotectCell
// on the templateObj, which is not a GC thing and can't use runtimeFromAnyThread.
@ -59,7 +59,7 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entryIndex, js::gc::I
if (cx->runtime()->gc.upcomingZealousGC())
return nullptr;
JSObject *obj = js::gc::AllocateObjectForCacheHit<NoGC>(cx, entry->kind, heap, group->clasp());
NativeObject *obj = js::gc::AllocateObjectForCacheHit<NoGC>(cx, entry->kind, heap, group->clasp());
if (obj) {
copyCachedToObject(obj, templateObj, entry->kind);
probes::CreateObject(cx, obj);

View File

@ -297,7 +297,7 @@ class NewObjectCache
* nullptr if returning the object could possibly trigger GC (does not
* indicate failure).
*/
inline JSObject *newObjectFromHit(JSContext *cx, EntryIndex entry, js::gc::InitialHeap heap);
inline NativeObject *newObjectFromHit(JSContext *cx, EntryIndex entry, js::gc::InitialHeap heap);
/* Fill an entry after a cache miss. */
void fillProto(EntryIndex entry, const Class *clasp, js::TaggedProto proto,
@ -344,7 +344,7 @@ class NewObjectCache
js_memcpy(&entry->templateObject, obj, entry->nbytes);
}
static void copyCachedToObject(JSObject *dst, JSObject *src, gc::AllocKind kind) {
static void copyCachedToObject(NativeObject *dst, NativeObject *src, gc::AllocKind kind) {
js_memcpy(dst, src, gc::Arena::thingSize(kind));
Shape::writeBarrierPost(dst->shape_, &dst->shape_);
ObjectGroup::writeBarrierPost(dst->group_, &dst->group_);

View File

@ -499,7 +499,7 @@ NativeObject::addProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId
}
static bool
ShouldConvertToDictionary(JSObject *obj)
ShouldConvertToDictionary(NativeObject *obj)
{
/*
* Use a lower limit if this object is likely a hashmap (SETELEM was used
@ -1138,21 +1138,25 @@ JSObject::setParent(JSContext *cx, HandleObject obj, HandleObject parent)
return false;
if (obj->isNative() && obj->as<NativeObject>().inDictionaryMode()) {
StackBaseShape base(obj->lastProperty());
StackBaseShape base(obj->as<NativeObject>().lastProperty());
base.parent = parent;
UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base);
if (!nbase)
return false;
obj->lastProperty()->base()->adoptUnowned(nbase);
obj->as<NativeObject>().lastProperty()->base()->adoptUnowned(nbase);
return true;
}
Shape *newShape = Shape::setObjectParent(cx, parent, obj->getTaggedProto(), obj->shape_);
Shape *existingShape = obj->ensureShape(cx);
if (!existingShape)
return false;
Shape *newShape = Shape::setObjectParent(cx, parent, obj->getTaggedProto(), existingShape);
if (!newShape)
return false;
obj->shape_ = newShape;
obj->setShapeMaybeNonNative(newShape);
return true;
}
@ -1173,21 +1177,25 @@ Shape::setObjectParent(ExclusiveContext *cx, JSObject *parent, TaggedProto proto
JSObject::setMetadata(JSContext *cx, HandleObject obj, HandleObject metadata)
{
if (obj->isNative() && obj->as<NativeObject>().inDictionaryMode()) {
StackBaseShape base(obj->lastProperty());
StackBaseShape base(obj->as<NativeObject>().lastProperty());
base.metadata = metadata;
UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base);
if (!nbase)
return false;
obj->lastProperty()->base()->adoptUnowned(nbase);
obj->as<NativeObject>().lastProperty()->base()->adoptUnowned(nbase);
return true;
}
Shape *newShape = Shape::setObjectMetadata(cx, metadata, obj->getTaggedProto(), obj->shape_);
Shape *existingShape = obj->ensureShape(cx);
if (!existingShape)
return false;
Shape *newShape = Shape::setObjectMetadata(cx, metadata, obj->getTaggedProto(), existingShape);
if (!newShape)
return false;
obj->shape_ = newShape;
obj->setShapeMaybeNonNative(newShape);
return true;
}
@ -1205,12 +1213,9 @@ Shape::setObjectMetadata(JSContext *cx, JSObject *metadata, TaggedProto proto, S
}
bool
JSObject::setFlags(ExclusiveContext *cx, /*BaseShape::Flag*/ uint32_t flags_,
GenerateShape generateShape)
JSObject::setFlags(ExclusiveContext *cx, BaseShape::Flag flags, GenerateShape generateShape)
{
BaseShape::Flag flags = (BaseShape::Flag) flags_;
if ((lastProperty()->getObjectFlags() & flags) == flags)
if (hasAllFlags(flags))
return true;
RootedObject self(cx, this);
@ -1218,22 +1223,25 @@ JSObject::setFlags(ExclusiveContext *cx, /*BaseShape::Flag*/ uint32_t flags_,
if (isNative() && as<NativeObject>().inDictionaryMode()) {
if (generateShape == GENERATE_SHAPE && !as<NativeObject>().generateOwnShape(cx))
return false;
StackBaseShape base(self->lastProperty());
StackBaseShape base(self->as<NativeObject>().lastProperty());
base.flags |= flags;
UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base);
if (!nbase)
return false;
self->lastProperty()->base()->adoptUnowned(nbase);
self->as<NativeObject>().lastProperty()->base()->adoptUnowned(nbase);
return true;
}
Shape *newShape =
Shape::setObjectFlags(cx, flags, self->getTaggedProto(), self->lastProperty());
Shape *existingShape = self->ensureShape(cx);
if (!existingShape)
return false;
Shape *newShape = Shape::setObjectFlags(cx, flags, self->getTaggedProto(), existingShape);
if (!newShape)
return false;
self->shape_ = newShape;
self->setShapeMaybeNonNative(newShape);
return true;
}
@ -1241,9 +1249,9 @@ bool
NativeObject::clearFlag(ExclusiveContext *cx, BaseShape::Flag flag)
{
MOZ_ASSERT(inDictionaryMode());
MOZ_ASSERT(lastProperty()->getObjectFlags() & flag);
RootedObject self(cx, this);
RootedNativeObject self(cx, &as<NativeObject>());
MOZ_ASSERT(self->lastProperty()->getObjectFlags() & flag);
StackBaseShape base(self->lastProperty());
base.flags &= ~flag;

View File

@ -834,9 +834,10 @@ class Shape : public gc::TenuredCell
BaseShape::Flag flag, TaggedProto proto, Shape *last);
uint32_t getObjectFlags() const { return base()->getObjectFlags(); }
bool hasObjectFlag(BaseShape::Flag flag) const {
MOZ_ASSERT(!(flag & ~BaseShape::OBJECT_FLAG_MASK));
return !!(base()->flags & flag);
bool hasAllObjectFlags(BaseShape::Flag flags) const {
MOZ_ASSERT(flags);
MOZ_ASSERT(!(flags & ~BaseShape::OBJECT_FLAG_MASK));
return (base()->flags & flags) == flags;
}
protected:

View File

@ -2576,7 +2576,7 @@ ObjectGroup::matchDefiniteProperties(HandleObject obj)
unsigned slot = prop->types.definiteSlot();
bool found = false;
Shape *shape = obj->lastProperty();
Shape *shape = obj->as<NativeObject>().lastProperty();
while (!shape->isEmptyShape()) {
if (shape->slot() == slot && shape->propid() == prop->id) {
found = true;

View File

@ -288,29 +288,12 @@ UnboxedPlainObject::convertToNative(JSContext *cx, JSObject *obj)
return false;
}
uint32_t objectFlags = obj->lastProperty()->getObjectFlags();
RootedObject metadata(cx, obj->getMetadata());
obj->setGroup(layout.nativeGroup());
obj->as<PlainObject>().setLastPropertyMakeNative(cx, layout.nativeShape());
for (size_t i = 0; i < values.length(); i++)
obj->as<PlainObject>().initSlotUnchecked(i, values[i]);
if (objectFlags) {
RootedObject objRoot(cx, obj);
if (!obj->setFlags(cx, objectFlags))
return false;
obj = objRoot;
}
if (metadata) {
RootedObject objRoot(cx, obj);
RootedObject metadataRoot(cx, metadata);
if (!setMetadata(cx, objRoot, metadataRoot))
return false;
}
return true;
}
@ -326,6 +309,9 @@ UnboxedPlainObject::create(JSContext *cx, HandleObjectGroup group, NewObjectKind
if (!res)
return nullptr;
// Avoid spurious shape guard hits.
res->dummy_ = nullptr;
// Initialize reference fields of the object. All fields in the object will
// be overwritten shortly, but references need to be safe for the GC.
const int32_t *list = res->layout().traceList();

View File

@ -151,7 +151,10 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
// how their properties are stored.
class UnboxedPlainObject : public JSObject
{
// Start of the inline data, which immediately follows the shape and type.
// Placeholder for extra properties. See bug 1137180.
void *dummy_;
// Start of the inline data, which immediately follows the group and extra properties.
uint8_t data_[1];
public: