mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 20:47:44 +00:00
Bug 1137497 - Remove shape from unboxed objects, r=jandem.
This commit is contained in:
parent
171a1c0e84
commit
ace85caac2
@ -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
|
||||
|
@ -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_;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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_);
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
|
@ -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 *)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
115
js/src/jsobj.h
115
js/src/jsobj.h
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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_;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@ namespace js {
|
||||
// instantiated.
|
||||
class ProxyObject : public JSObject
|
||||
{
|
||||
HeapPtrShape shape;
|
||||
|
||||
// GetProxyDataLayout computes the address of this field.
|
||||
ProxyDataLayout data;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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_);
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user