зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1505574 - Remove initial chunk of Unboxed Objects machinery r=iain
Differential Revision: https://phabricator.services.mozilla.com/D24037 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
b31262c6aa
Коммит
6d1bcb4f0f
|
@ -60,16 +60,7 @@ static bool VectorAppendNoDuplicate(S& list, T value) {
|
|||
}
|
||||
|
||||
static bool AddReceiver(
|
||||
const ReceiverGuard& receiver, BaselineInspector::ReceiverVector& receivers,
|
||||
BaselineInspector::ObjectGroupVector& convertUnboxedGroups) {
|
||||
if (receiver.group) {
|
||||
AutoSweepObjectGroup sweep(receiver.group);
|
||||
if (auto* layout = receiver.group->maybeUnboxedLayout(sweep)) {
|
||||
if (layout->nativeGroup()) {
|
||||
return VectorAppendNoDuplicate(convertUnboxedGroups, receiver.group);
|
||||
}
|
||||
}
|
||||
}
|
||||
const ReceiverGuard& receiver, BaselineInspector::ReceiverVector& receivers) {
|
||||
return VectorAppendNoDuplicate(receivers, receiver);
|
||||
}
|
||||
|
||||
|
@ -255,15 +246,11 @@ ICEntry* BaselineInspector::maybeICEntryFromPC(jsbytecode* pc) {
|
|||
}
|
||||
|
||||
bool BaselineInspector::maybeInfoForPropertyOp(
|
||||
jsbytecode* pc, ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups) {
|
||||
jsbytecode* pc, ReceiverVector& receivers) {
|
||||
// Return a list of the receivers seen by the baseline IC for the current
|
||||
// op. Empty lists indicate no receivers are known, or there was an
|
||||
// uncacheable access. convertUnboxedGroups is used for unboxed object
|
||||
// groups which have been seen, but have had instances converted to native
|
||||
// objects and should be eagerly converted by Ion.
|
||||
// uncacheable access.
|
||||
MOZ_ASSERT(receivers.empty());
|
||||
MOZ_ASSERT(convertUnboxedGroups.empty());
|
||||
|
||||
if (!hasICScript()) {
|
||||
return true;
|
||||
|
@ -296,7 +283,7 @@ bool BaselineInspector::maybeInfoForPropertyOp(
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) {
|
||||
if (!AddReceiver(receiver, receivers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1089,7 +1076,6 @@ static bool AddCacheIRGlobalGetter(
|
|||
ICCacheIR_Monitored* stub, bool innerized, JSObject** holder_,
|
||||
Shape** holderShape_, JSFunction** commonGetter, Shape** globalShape_,
|
||||
bool* isOwnProperty, BaselineInspector::ReceiverVector& receivers,
|
||||
BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
|
||||
JSScript* script) {
|
||||
// We are matching on the IR generated by tryAttachGlobalNameGetter:
|
||||
//
|
||||
|
@ -1155,7 +1141,7 @@ static bool AddCacheIRGlobalGetter(
|
|||
|
||||
ReceiverGuard receiver;
|
||||
receiver.shape = globalLexicalShape;
|
||||
if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) {
|
||||
if (!AddReceiver(receiver, receivers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1216,7 +1202,6 @@ static bool AddCacheIRGetPropFunction(
|
|||
ICCacheIR_Monitored* stub, jsid id, bool innerized, JSObject** holder,
|
||||
Shape** holderShape, JSFunction** commonGetter, Shape** globalShape,
|
||||
bool* isOwnProperty, BaselineInspector::ReceiverVector& receivers,
|
||||
BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
|
||||
JSScript* script) {
|
||||
// We match either an own getter:
|
||||
//
|
||||
|
@ -1255,7 +1240,7 @@ static bool AddCacheIRGetPropFunction(
|
|||
if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
|
||||
return AddCacheIRGlobalGetter(stub, innerized, holder, holderShape,
|
||||
commonGetter, globalShape, isOwnProperty,
|
||||
receivers, convertUnboxedGroups, script);
|
||||
receivers, script);
|
||||
}
|
||||
|
||||
if (!JSID_IS_EMPTY(id)) {
|
||||
|
@ -1358,7 +1343,7 @@ static bool AddCacheIRGetPropFunction(
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) {
|
||||
if (!AddReceiver(receiver, receivers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1372,15 +1357,13 @@ static bool AddCacheIRGetPropFunction(
|
|||
bool BaselineInspector::commonGetPropFunction(
|
||||
jsbytecode* pc, jsid id, bool innerized, JSObject** holder,
|
||||
Shape** holderShape, JSFunction** commonGetter, Shape** globalShape,
|
||||
bool* isOwnProperty, ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups) {
|
||||
bool* isOwnProperty, ReceiverVector& receivers) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsGetPropPC(pc) || IsGetElemPC(pc) || JSOp(*pc) == JSOP_GETGNAME);
|
||||
MOZ_ASSERT(receivers.empty());
|
||||
MOZ_ASSERT(convertUnboxedGroups.empty());
|
||||
|
||||
// Only GetElem operations need to guard against a specific property id.
|
||||
if (!IsGetElemPC(pc)) {
|
||||
|
@ -1395,8 +1378,7 @@ bool BaselineInspector::commonGetPropFunction(
|
|||
if (stub->isCacheIR_Monitored()) {
|
||||
if (!AddCacheIRGetPropFunction(stub->toCacheIR_Monitored(), id, innerized,
|
||||
holder, holderShape, commonGetter,
|
||||
globalShape, isOwnProperty, receivers,
|
||||
convertUnboxedGroups, script)) {
|
||||
globalShape, isOwnProperty, receivers, script)) {
|
||||
return false;
|
||||
}
|
||||
} else if (stub->isFallback()) {
|
||||
|
@ -1414,8 +1396,7 @@ bool BaselineInspector::commonGetPropFunction(
|
|||
}
|
||||
|
||||
MOZ_ASSERT(*isOwnProperty == !*holder);
|
||||
MOZ_ASSERT(*isOwnProperty ==
|
||||
(receivers.empty() && convertUnboxedGroups.empty()));
|
||||
MOZ_ASSERT(*isOwnProperty == receivers.empty());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1521,8 +1502,7 @@ bool BaselineInspector::megamorphicGetterSetterFunction(
|
|||
static bool AddCacheIRSetPropFunction(
|
||||
ICCacheIR_Updated* stub, JSObject** holder, Shape** holderShape,
|
||||
JSFunction** commonSetter, bool* isOwnProperty,
|
||||
BaselineInspector::ReceiverVector& receivers,
|
||||
BaselineInspector::ObjectGroupVector& convertUnboxedGroups) {
|
||||
BaselineInspector::ReceiverVector& receivers) {
|
||||
// We match either an own setter:
|
||||
//
|
||||
// GuardIsObject objId
|
||||
|
@ -1608,7 +1588,7 @@ static bool AddCacheIRSetPropFunction(
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) {
|
||||
if (!AddReceiver(receiver, receivers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1621,8 +1601,7 @@ static bool AddCacheIRSetPropFunction(
|
|||
|
||||
bool BaselineInspector::commonSetPropFunction(
|
||||
jsbytecode* pc, JSObject** holder, Shape** holderShape,
|
||||
JSFunction** commonSetter, bool* isOwnProperty, ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups) {
|
||||
JSFunction** commonSetter, bool* isOwnProperty, ReceiverVector& receivers) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1631,7 +1610,6 @@ bool BaselineInspector::commonSetPropFunction(
|
|||
JSOp(*pc) == JSOP_INITPROP || JSOp(*pc) == JSOP_INITLOCKEDPROP ||
|
||||
JSOp(*pc) == JSOP_INITHIDDENPROP);
|
||||
MOZ_ASSERT(receivers.empty());
|
||||
MOZ_ASSERT(convertUnboxedGroups.empty());
|
||||
|
||||
*commonSetter = nullptr;
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
|
@ -1640,7 +1618,7 @@ bool BaselineInspector::commonSetPropFunction(
|
|||
if (stub->isCacheIR_Updated()) {
|
||||
if (!AddCacheIRSetPropFunction(stub->toCacheIR_Updated(), holder,
|
||||
holderShape, commonSetter, isOwnProperty,
|
||||
receivers, convertUnboxedGroups)) {
|
||||
receivers)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!stub->isFallback() ||
|
||||
|
@ -1716,13 +1694,11 @@ static bool GetCacheIRReceiverForProtoReadSlot(ICCacheIR_Monitored* stub,
|
|||
}
|
||||
|
||||
bool BaselineInspector::maybeInfoForProtoReadSlot(
|
||||
jsbytecode* pc, ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups, JSObject** holder) {
|
||||
jsbytecode* pc, ReceiverVector& receivers, JSObject** holder) {
|
||||
// This is like maybeInfoForPropertyOp, but for when the property exists on
|
||||
// the prototype.
|
||||
|
||||
MOZ_ASSERT(receivers.empty());
|
||||
MOZ_ASSERT(convertUnboxedGroups.empty());
|
||||
MOZ_ASSERT(!*holder);
|
||||
|
||||
if (!hasICScript()) {
|
||||
|
@ -1746,7 +1722,7 @@ bool BaselineInspector::maybeInfoForProtoReadSlot(
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!AddReceiver(receiver, receivers, convertUnboxedGroups)) {
|
||||
if (!AddReceiver(receiver, receivers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,12 +78,10 @@ class BaselineInspector {
|
|||
typedef Vector<ReceiverGuard, 4, JitAllocPolicy> ReceiverVector;
|
||||
typedef Vector<ObjectGroup*, 4, JitAllocPolicy> ObjectGroupVector;
|
||||
MOZ_MUST_USE bool maybeInfoForPropertyOp(
|
||||
jsbytecode* pc, ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups);
|
||||
jsbytecode* pc, ReceiverVector& receivers);
|
||||
|
||||
MOZ_MUST_USE bool maybeInfoForProtoReadSlot(
|
||||
jsbytecode* pc, ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups, JSObject** holder);
|
||||
jsbytecode* pc, ReceiverVector& receivers, JSObject** holder);
|
||||
|
||||
SetElemICInspector setElemICInspector(jsbytecode* pc) {
|
||||
return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
|
||||
|
@ -123,16 +121,14 @@ class BaselineInspector {
|
|||
MOZ_MUST_USE bool commonGetPropFunction(
|
||||
jsbytecode* pc, jsid id, bool innerized, JSObject** holder,
|
||||
Shape** holderShape, JSFunction** commonGetter, Shape** globalShape,
|
||||
bool* isOwnProperty, ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups);
|
||||
bool* isOwnProperty, ReceiverVector& receivers);
|
||||
|
||||
MOZ_MUST_USE bool megamorphicGetterSetterFunction(
|
||||
jsbytecode* pc, jsid id, bool isGetter, JSFunction** getterOrSetter);
|
||||
|
||||
MOZ_MUST_USE bool commonSetPropFunction(
|
||||
jsbytecode* pc, JSObject** holder, Shape** holderShape,
|
||||
JSFunction** commonSetter, bool* isOwnProperty, ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups);
|
||||
JSFunction** commonSetter, bool* isOwnProperty, ReceiverVector& receivers);
|
||||
|
||||
MOZ_MUST_USE bool instanceOfData(jsbytecode* pc, Shape** shape,
|
||||
uint32_t* slot, JSObject** prototypeObject);
|
||||
|
|
|
@ -8459,9 +8459,6 @@ AbortReasonOr<Ok> IonBuilder::jsop_getelem() {
|
|||
}
|
||||
|
||||
obj = maybeUnboxForPropertyAccess(obj);
|
||||
if (obj->type() == MIRType::Object) {
|
||||
obj = convertUnboxedObjects(obj);
|
||||
}
|
||||
|
||||
if (!forceInlineCaches()) {
|
||||
// Note: no trackOptimizationAttempt call is needed, getElemTryGetProp
|
||||
|
@ -9535,7 +9532,7 @@ AbortReasonOr<Ok> IonBuilder::jsop_setelem() {
|
|||
|
||||
MDefinition* value = current->pop();
|
||||
MDefinition* index = current->pop();
|
||||
MDefinition* object = convertUnboxedObjects(current->pop());
|
||||
MDefinition* object = current->pop();
|
||||
|
||||
trackTypeInfo(TrackedTypeSite::Receiver, object->type(),
|
||||
object->resultTypeSet());
|
||||
|
@ -10954,9 +10951,6 @@ AbortReasonOr<Ok> IonBuilder::jsop_getprop(PropertyName* name) {
|
|||
}
|
||||
|
||||
obj = maybeUnboxForPropertyAccess(obj);
|
||||
if (obj->type() == MIRType::Object) {
|
||||
obj = convertUnboxedObjects(obj);
|
||||
}
|
||||
|
||||
BarrierKind barrier = PropertyReadNeedsTypeBarrier(
|
||||
analysisContext, alloc(), constraints(), obj, name, types);
|
||||
|
@ -11401,50 +11395,6 @@ AbortReasonOr<Ok> IonBuilder::getPropTryComplexPropOfTypedObject(
|
|||
fieldTypeObj);
|
||||
}
|
||||
|
||||
MDefinition* IonBuilder::convertUnboxedObjects(MDefinition* obj) {
|
||||
// If obj might be in any particular unboxed group which should be
|
||||
// converted to a native representation, perform that conversion. This does
|
||||
// not guarantee the object will not have such a group afterwards, if the
|
||||
// object's possible groups are not precisely known.
|
||||
TemporaryTypeSet* types = obj->resultTypeSet();
|
||||
if (!types || types->unknownObject() || !types->objectOrSentinel()) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
BaselineInspector::ObjectGroupVector list(alloc());
|
||||
for (size_t i = 0; i < types->getObjectCount(); i++) {
|
||||
TypeSet::ObjectKey* key = obj->resultTypeSet()->getObject(i);
|
||||
if (!key || !key->isGroup()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AutoSweepObjectGroup sweep(key->group());
|
||||
if (UnboxedLayout* layout = key->group()->maybeUnboxedLayout(sweep)) {
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (layout->nativeGroup() && !list.append(key->group())) {
|
||||
oomUnsafe.crash("IonBuilder::convertUnboxedObjects");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return convertUnboxedObjects(obj, list);
|
||||
}
|
||||
|
||||
MDefinition* IonBuilder::convertUnboxedObjects(
|
||||
MDefinition* obj, const BaselineInspector::ObjectGroupVector& list) {
|
||||
for (size_t i = 0; i < list.length(); i++) {
|
||||
ObjectGroup* group = list[i];
|
||||
if (TemporaryTypeSet* types = obj->resultTypeSet()) {
|
||||
if (!types->hasType(TypeSet::ObjectType(group))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
obj = MConvertUnboxedObjectToNative::New(alloc(), obj, group);
|
||||
current->add(obj->toInstruction());
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok> IonBuilder::getPropTryDefiniteSlot(bool* emitted,
|
||||
MDefinition* obj,
|
||||
PropertyName* name,
|
||||
|
@ -11637,13 +11587,10 @@ AbortReasonOr<Ok> IonBuilder::getPropTryUnboxed(bool* emitted, MDefinition* obj,
|
|||
MDefinition* IonBuilder::addShapeGuardsForGetterSetter(
|
||||
MDefinition* obj, JSObject* holder, Shape* holderShape,
|
||||
const BaselineInspector::ReceiverVector& receivers,
|
||||
const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
|
||||
bool isOwnProperty) {
|
||||
MOZ_ASSERT(isOwnProperty == !holder);
|
||||
MOZ_ASSERT(holderShape);
|
||||
|
||||
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
|
||||
|
||||
if (isOwnProperty) {
|
||||
MOZ_ASSERT(receivers.empty());
|
||||
return addShapeGuard(obj, holderShape, Bailout_ShapeGuard);
|
||||
|
@ -11673,10 +11620,9 @@ AbortReasonOr<Ok> IonBuilder::getPropTryCommonGetter(bool* emitted,
|
|||
JSObject* foundProto = nullptr;
|
||||
bool isOwnProperty = false;
|
||||
BaselineInspector::ReceiverVector receivers(alloc());
|
||||
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
|
||||
if (inspector->commonGetPropFunction(
|
||||
pc, id, innerized, &foundProto, &lastProperty, &commonGetter,
|
||||
&globalShape, &isOwnProperty, receivers, convertUnboxedGroups)) {
|
||||
&globalShape, &isOwnProperty, receivers)) {
|
||||
bool canUseTIForGetter = false;
|
||||
if (!isOwnProperty) {
|
||||
// If it's not an own property, try to use TI to avoid shape guards.
|
||||
|
@ -11690,7 +11636,7 @@ AbortReasonOr<Ok> IonBuilder::getPropTryCommonGetter(bool* emitted,
|
|||
// If it's an own property or type information is bad, we can still
|
||||
// optimize the getter if we shape guard.
|
||||
obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
|
||||
receivers, convertUnboxedGroups,
|
||||
receivers,
|
||||
isOwnProperty);
|
||||
if (!obj) {
|
||||
return abort(AbortReason::Alloc);
|
||||
|
@ -11890,8 +11836,7 @@ AbortReasonOr<Ok> IonBuilder::getPropTryInlineAccess(bool* emitted,
|
|||
MOZ_ASSERT(*emitted == false);
|
||||
|
||||
BaselineInspector::ReceiverVector receivers(alloc());
|
||||
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
|
||||
if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups)) {
|
||||
if (!inspector->maybeInfoForPropertyOp(pc, receivers)) {
|
||||
return abort(AbortReason::Alloc);
|
||||
}
|
||||
|
||||
|
@ -11899,8 +11844,6 @@ AbortReasonOr<Ok> IonBuilder::getPropTryInlineAccess(bool* emitted,
|
|||
return Ok();
|
||||
}
|
||||
|
||||
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
|
||||
|
||||
MIRType rvalType = types->getKnownMIRType();
|
||||
if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) {
|
||||
rvalType = MIRType::Value;
|
||||
|
@ -12020,9 +11963,8 @@ AbortReasonOr<Ok> IonBuilder::getPropTryInlineProtoAccess(
|
|||
MOZ_ASSERT(*emitted == false);
|
||||
|
||||
BaselineInspector::ReceiverVector receivers(alloc());
|
||||
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
|
||||
JSObject* holder = nullptr;
|
||||
if (!inspector->maybeInfoForProtoReadSlot(pc, receivers, convertUnboxedGroups,
|
||||
if (!inspector->maybeInfoForProtoReadSlot(pc, receivers,
|
||||
&holder)) {
|
||||
return abort(AbortReason::Alloc);
|
||||
}
|
||||
|
@ -12044,7 +11986,6 @@ AbortReasonOr<Ok> IonBuilder::getPropTryInlineProtoAccess(
|
|||
}
|
||||
|
||||
// Guard on the receiver shapes/groups.
|
||||
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
|
||||
obj = addGuardReceiverPolymorphic(obj, receivers);
|
||||
if (!obj) {
|
||||
return abort(AbortReason::Alloc);
|
||||
|
@ -12257,7 +12198,7 @@ AbortReasonOr<Ok> IonBuilder::getPropTryInnerize(bool* emitted,
|
|||
|
||||
AbortReasonOr<Ok> IonBuilder::jsop_setprop(PropertyName* name) {
|
||||
MDefinition* value = current->pop();
|
||||
MDefinition* obj = convertUnboxedObjects(current->pop());
|
||||
MDefinition* obj = current->pop();
|
||||
|
||||
bool emitted = false;
|
||||
startTrackingOptimizations();
|
||||
|
@ -12344,10 +12285,9 @@ AbortReasonOr<Ok> IonBuilder::setPropTryCommonSetter(bool* emitted,
|
|||
JSObject* foundProto = nullptr;
|
||||
bool isOwnProperty;
|
||||
BaselineInspector::ReceiverVector receivers(alloc());
|
||||
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
|
||||
if (inspector->commonSetPropFunction(pc, &foundProto, &lastProperty,
|
||||
&commonSetter, &isOwnProperty,
|
||||
receivers, convertUnboxedGroups)) {
|
||||
receivers)) {
|
||||
bool canUseTIForSetter = false;
|
||||
if (!isOwnProperty) {
|
||||
// If it's not an own property, try to use TI to avoid shape guards.
|
||||
|
@ -12361,8 +12301,7 @@ AbortReasonOr<Ok> IonBuilder::setPropTryCommonSetter(bool* emitted,
|
|||
// If it's an own property or type information is bad, we can still
|
||||
// optimize the setter if we shape guard.
|
||||
obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty,
|
||||
receivers, convertUnboxedGroups,
|
||||
isOwnProperty);
|
||||
receivers, isOwnProperty);
|
||||
if (!obj) {
|
||||
return abort(AbortReason::Alloc);
|
||||
}
|
||||
|
@ -12750,8 +12689,7 @@ AbortReasonOr<Ok> IonBuilder::setPropTryInlineAccess(
|
|||
}
|
||||
|
||||
BaselineInspector::ReceiverVector receivers(alloc());
|
||||
BaselineInspector::ObjectGroupVector convertUnboxedGroups(alloc());
|
||||
if (!inspector->maybeInfoForPropertyOp(pc, receivers, convertUnboxedGroups)) {
|
||||
if (!inspector->maybeInfoForPropertyOp(pc, receivers)) {
|
||||
return abort(AbortReason::Alloc);
|
||||
}
|
||||
|
||||
|
@ -12759,8 +12697,6 @@ AbortReasonOr<Ok> IonBuilder::setPropTryInlineAccess(
|
|||
return Ok();
|
||||
}
|
||||
|
||||
obj = convertUnboxedObjects(obj, convertUnboxedGroups);
|
||||
|
||||
if (receivers.length() == 1) {
|
||||
if (!receivers[0].group) {
|
||||
// Monomorphic store to a native object.
|
||||
|
@ -13406,7 +13342,7 @@ AbortReasonOr<Ok> IonBuilder::jsop_setaliasedvar(EnvironmentCoordinate ec) {
|
|||
}
|
||||
|
||||
AbortReasonOr<Ok> IonBuilder::jsop_in() {
|
||||
MDefinition* obj = convertUnboxedObjects(current->pop());
|
||||
MDefinition* obj = current->pop();
|
||||
MDefinition* id = current->pop();
|
||||
|
||||
if (!forceInlineCaches()) {
|
||||
|
@ -13562,7 +13498,7 @@ AbortReasonOr<Ok> IonBuilder::hasTryDefiniteSlotOrUnboxed(bool* emitted,
|
|||
}
|
||||
|
||||
AbortReasonOr<Ok> IonBuilder::jsop_hasown() {
|
||||
MDefinition* obj = convertUnboxedObjects(current->pop());
|
||||
MDefinition* obj = current->pop();
|
||||
MDefinition* id = current->pop();
|
||||
|
||||
if (!forceInlineCaches()) {
|
||||
|
|
|
@ -918,7 +918,6 @@ class IonBuilder : public MIRGenerator,
|
|||
MDefinition* addShapeGuardsForGetterSetter(
|
||||
MDefinition* obj, JSObject* holder, Shape* holderShape,
|
||||
const BaselineInspector::ReceiverVector& receivers,
|
||||
const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
|
||||
bool isOwnProperty);
|
||||
|
||||
AbortReasonOr<Ok> annotateGetPropertyCache(MDefinition* obj,
|
||||
|
@ -938,9 +937,7 @@ class IonBuilder : public MIRGenerator,
|
|||
bool ownProperty = false);
|
||||
|
||||
uint32_t getDefiniteSlot(TemporaryTypeSet* types, jsid id, uint32_t* pnfixed);
|
||||
MDefinition* convertUnboxedObjects(MDefinition* obj);
|
||||
MDefinition* convertUnboxedObjects(
|
||||
MDefinition* obj, const BaselineInspector::ObjectGroupVector& list);
|
||||
|
||||
uint32_t getUnboxedOffset(TemporaryTypeSet* types, jsid id,
|
||||
JSValueType* punboxedType);
|
||||
MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset,
|
||||
|
|
|
@ -911,7 +911,7 @@ IonBuilder::InliningResult IonBuilder::inlineArrayPopShift(
|
|||
OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW |
|
||||
OBJECT_FLAG_ITERATED | OBJECT_FLAG_NON_EXTENSIBLE_ELEMENTS;
|
||||
|
||||
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
|
||||
MDefinition* obj = callInfo.thisArg();
|
||||
TemporaryTypeSet* thisTypes = obj->resultTypeSet();
|
||||
if (!thisTypes) {
|
||||
return InliningStatus_NotInlined;
|
||||
|
@ -1018,7 +1018,7 @@ IonBuilder::InliningResult IonBuilder::inlineArrayPush(CallInfo& callInfo) {
|
|||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
|
||||
MDefinition* obj = callInfo.thisArg();
|
||||
for (uint32_t i = 0; i < callInfo.argc(); i++) {
|
||||
MDefinition* value = callInfo.getArg(i);
|
||||
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj,
|
||||
|
@ -1149,7 +1149,7 @@ IonBuilder::InliningResult IonBuilder::inlineArraySlice(CallInfo& callInfo) {
|
|||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
|
||||
MDefinition* obj = callInfo.thisArg();
|
||||
|
||||
// Ensure |this| and result are objects.
|
||||
if (getInlineReturnType() != MIRType::Object) {
|
||||
|
|
|
@ -84,9 +84,6 @@ bool SetImmutablePrototype(JSContext* cx, JS::HandleObject obj,
|
|||
* as before.
|
||||
* - JSObject::swap()
|
||||
* - UnboxedPlainObject::convertToNative()
|
||||
*
|
||||
* NOTE: UnboxedObjects may change class without changing |group_|.
|
||||
* - js::TryConvertToUnboxedLayout
|
||||
*/
|
||||
class JSObject : public js::gc::Cell {
|
||||
protected:
|
||||
|
|
|
@ -195,6 +195,8 @@ class ObjectGroup : public gc::TenuredCell {
|
|||
// assume objects of a previously seen group have the same class as before.
|
||||
//
|
||||
// See: TryConvertToUnboxedLayout
|
||||
//
|
||||
// MG:Unboxed: Verify above comment still holds
|
||||
bool hasUncacheableClass() const { return clasp_->isNative(); }
|
||||
|
||||
bool hasDynamicPrototype() const { return proto_.isDynamic(); }
|
||||
|
|
|
@ -3855,8 +3855,6 @@ void PreliminaryObjectArrayWithTemplate::maybeAnalyze(JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
TryConvertToUnboxedLayout(cx, enter, shape(), group,
|
||||
preliminaryObjects.get());
|
||||
AutoSweepObjectGroup sweep(group);
|
||||
if (group->maybeUnboxedLayout(sweep)) {
|
||||
return;
|
||||
|
@ -4156,12 +4154,6 @@ bool TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group,
|
|||
initializerVector.length());
|
||||
}
|
||||
|
||||
// Try to use an unboxed representation for the group.
|
||||
if (!TryConvertToUnboxedLayout(cx, enter, templateObject()->lastProperty(),
|
||||
group, preliminaryObjects)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
js_delete(preliminaryObjects);
|
||||
preliminaryObjects = nullptr;
|
||||
|
||||
|
|
|
@ -1216,196 +1216,11 @@ const Class UnboxedPlainObject::class_ = {
|
|||
// API
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool UnboxedTypeIncludes(JSValueType supertype, JSValueType subtype) {
|
||||
if (supertype == JSVAL_TYPE_DOUBLE && subtype == JSVAL_TYPE_INT32) {
|
||||
return true;
|
||||
}
|
||||
if (supertype == JSVAL_TYPE_OBJECT && subtype == JSVAL_TYPE_NULL) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CombineUnboxedTypes(const Value& value, JSValueType* existing) {
|
||||
JSValueType type =
|
||||
value.isDouble() ? JSVAL_TYPE_DOUBLE : value.extractNonDoubleType();
|
||||
|
||||
if (*existing == JSVAL_TYPE_MAGIC || *existing == type ||
|
||||
UnboxedTypeIncludes(type, *existing)) {
|
||||
*existing = type;
|
||||
return true;
|
||||
}
|
||||
if (UnboxedTypeIncludes(*existing, type)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return whether the property names and types in layout are a subset of the
|
||||
// specified vector.
|
||||
static bool PropertiesAreSuperset(
|
||||
const UnboxedLayout::PropertyVector& properties, UnboxedLayout* layout) {
|
||||
for (size_t i = 0; i < layout->properties().length(); i++) {
|
||||
const UnboxedLayout::Property& layoutProperty = layout->properties()[i];
|
||||
bool found = false;
|
||||
for (size_t j = 0; j < properties.length(); j++) {
|
||||
if (layoutProperty.name == properties[j].name) {
|
||||
found = (layoutProperty.type == properties[j].type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CombinePlainObjectProperties(
|
||||
PlainObject* obj, Shape* templateShape,
|
||||
UnboxedLayout::PropertyVector& properties) {
|
||||
// All preliminary objects must have been created with enough space to
|
||||
// fill in their unboxed data inline. This is ensured either by using
|
||||
// the largest allocation kind (which limits the maximum size of an
|
||||
// unboxed object), or by using an allocation kind that covers all
|
||||
// properties in the template, as the space used by unboxed properties
|
||||
// is less than or equal to that used by boxed properties.
|
||||
MOZ_ASSERT(gc::GetGCKindSlots(obj->asTenured().getAllocKind()) >=
|
||||
Min(NativeObject::MAX_FIXED_SLOTS, templateShape->slotSpan()));
|
||||
|
||||
if (obj->lastProperty() != templateShape || obj->hasDynamicElements()) {
|
||||
// Only use an unboxed representation if all created objects match
|
||||
// the template shape exactly.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < templateShape->slotSpan(); i++) {
|
||||
Value val = obj->getSlot(i);
|
||||
|
||||
JSValueType& existing = properties[i].type;
|
||||
if (!CombineUnboxedTypes(val, &existing)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t ComputePlainObjectLayout(
|
||||
JSContext* cx, ObjectGroupRealm& realm, Shape* templateShape,
|
||||
UnboxedLayout::PropertyVector& properties) {
|
||||
// Fill in the names for all the object's properties.
|
||||
for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
|
||||
size_t slot = r.front().slot();
|
||||
MOZ_ASSERT(!properties[slot].name);
|
||||
properties[slot].name = JSID_TO_ATOM(r.front().propid())->asPropertyName();
|
||||
}
|
||||
|
||||
// Fill in all the unboxed object's property offsets.
|
||||
uint32_t offset = 0;
|
||||
|
||||
// Search for an existing unboxed layout which is a subset of this one.
|
||||
// If there are multiple such layouts, use the largest one. If we're able
|
||||
// to find such a layout, use the same property offsets for the shared
|
||||
// properties, which will allow us to generate better code if the objects
|
||||
// have a subtype/supertype relation and are accessed at common sites.
|
||||
UnboxedLayout* bestExisting = nullptr;
|
||||
for (UnboxedLayout* existing : realm.unboxedLayouts) {
|
||||
if (PropertiesAreSuperset(properties, existing)) {
|
||||
if (!bestExisting || existing->properties().length() >
|
||||
bestExisting->properties().length()) {
|
||||
bestExisting = existing;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestExisting) {
|
||||
for (size_t i = 0; i < bestExisting->properties().length(); i++) {
|
||||
const UnboxedLayout::Property& existingProperty =
|
||||
bestExisting->properties()[i];
|
||||
for (size_t j = 0; j < templateShape->slotSpan(); j++) {
|
||||
if (existingProperty.name == properties[j].name) {
|
||||
MOZ_ASSERT(existingProperty.type == properties[j].type);
|
||||
properties[j].offset = existingProperty.offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
offset = bestExisting->size();
|
||||
}
|
||||
|
||||
// Order remaining properties from the largest down for the best space
|
||||
// utilization.
|
||||
static const size_t typeSizes[] = {8, 4, 1};
|
||||
|
||||
for (size_t i = 0; i < ArrayLength(typeSizes); i++) {
|
||||
size_t size = typeSizes[i];
|
||||
for (size_t j = 0; j < templateShape->slotSpan(); j++) {
|
||||
if (properties[j].offset != UINT32_MAX) {
|
||||
continue;
|
||||
}
|
||||
JSValueType type = properties[j].type;
|
||||
if (UnboxedTypeSize(type) == size) {
|
||||
offset = JS_ROUNDUP(offset, size);
|
||||
properties[j].offset = offset;
|
||||
offset += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The final offset is the amount of data needed by the object.
|
||||
return offset;
|
||||
}
|
||||
|
||||
static bool SetLayoutTraceList(JSContext* cx, UnboxedLayout* layout) {
|
||||
// Figure out the offsets of any objects or string properties.
|
||||
Vector<int32_t, 8, SystemAllocPolicy> objectOffsets, stringOffsets;
|
||||
for (size_t i = 0; i < layout->properties().length(); i++) {
|
||||
const UnboxedLayout::Property& property = layout->properties()[i];
|
||||
MOZ_ASSERT(property.offset != UINT32_MAX);
|
||||
if (property.type == JSVAL_TYPE_OBJECT) {
|
||||
if (!objectOffsets.append(property.offset)) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.type == JSVAL_TYPE_STRING) {
|
||||
if (!stringOffsets.append(property.offset)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the layout's trace list.
|
||||
if (!objectOffsets.empty() || !stringOffsets.empty()) {
|
||||
Vector<int32_t, 8, SystemAllocPolicy> entries;
|
||||
if (!entries.appendAll(stringOffsets) || !entries.append(-1) ||
|
||||
!entries.appendAll(objectOffsets) || !entries.append(-1) ||
|
||||
!entries.append(-1)) {
|
||||
return false;
|
||||
}
|
||||
int32_t* traceList = cx->zone()->pod_malloc<int32_t>(entries.length());
|
||||
if (!traceList) {
|
||||
return false;
|
||||
}
|
||||
PodCopy(traceList, entries.begin(), entries.length());
|
||||
layout->setTraceList(traceList);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline Value NextValue(Handle<GCVector<Value>> values,
|
||||
size_t* valueCursor) {
|
||||
return values[(*valueCursor)++];
|
||||
}
|
||||
|
||||
static bool GetValuesFromPreliminaryPlainObject(
|
||||
PlainObject* obj, MutableHandle<GCVector<Value>> values) {
|
||||
for (size_t i = 0; i < obj->slotSpan(); i++) {
|
||||
if (!values.append(obj->getSlot(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnboxedPlainObject::fillAfterConvert(JSContext* cx,
|
||||
Handle<GCVector<Value>> values,
|
||||
size_t* valueCursor) {
|
||||
|
@ -1415,159 +1230,4 @@ void UnboxedPlainObject::fillAfterConvert(JSContext* cx,
|
|||
MOZ_ALWAYS_TRUE(
|
||||
setValue(cx, layout().properties()[i], NextValue(values, valueCursor)));
|
||||
}
|
||||
}
|
||||
|
||||
bool js::TryConvertToUnboxedLayout(JSContext* cx, AutoEnterAnalysis& enter,
|
||||
Shape* templateShape, ObjectGroup* group,
|
||||
PreliminaryObjectArray* objects) {
|
||||
MOZ_ASSERT(templateShape);
|
||||
|
||||
if (jit::JitOptions.disableUnboxedObjects) {
|
||||
return true;
|
||||
}
|
||||
|
||||
AutoSweepObjectGroup sweep(group);
|
||||
|
||||
MOZ_ASSERT(!templateShape->getObjectFlags());
|
||||
|
||||
if (group->runtimeFromAnyThread()->isSelfHostingGlobal(cx->global())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (templateShape->slotSpan() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
UnboxedLayout::PropertyVector properties;
|
||||
if (!properties.appendN(UnboxedLayout::Property(),
|
||||
templateShape->slotSpan())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t objectCount = 0;
|
||||
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
|
||||
JSObject* obj = objects->get(i);
|
||||
if (!obj) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj->isSingleton() || obj->group() != group) {
|
||||
return true;
|
||||
}
|
||||
|
||||
objectCount++;
|
||||
|
||||
if (!CombinePlainObjectProperties(&obj->as<PlainObject>(), templateShape,
|
||||
properties)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
size_t layoutSize = 0;
|
||||
if (objectCount <= 1) {
|
||||
// If only one of the objects has been created, it is more likely
|
||||
// to have new properties added later.
|
||||
return true;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < templateShape->slotSpan(); i++) {
|
||||
// We can't use an unboxed representation if e.g. all the objects have
|
||||
// a null value for one of the properties, as we can't decide what type
|
||||
// it is supposed to have.
|
||||
if (UnboxedTypeSize(properties[i].type) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that all properties on the template shape are property
|
||||
// names, and not indexes.
|
||||
for (Shape::Range<NoGC> r(templateShape); !r.empty(); r.popFront()) {
|
||||
jsid id = r.front().propid();
|
||||
uint32_t dummy;
|
||||
if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectGroupRealm& realm = ObjectGroupRealm::get(group);
|
||||
layoutSize = ComputePlainObjectLayout(cx, realm, templateShape, properties);
|
||||
|
||||
// The entire object must be allocatable inline.
|
||||
if (UnboxedPlainObject::offsetOfData() + layoutSize >
|
||||
JSObject::MAX_BYTE_SIZE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
UniquePtr<UnboxedLayout>& layout = enter.unboxedLayoutToCleanUp;
|
||||
MOZ_ASSERT(!layout);
|
||||
layout = group->zone()->make_unique<UnboxedLayout>(group->zone());
|
||||
if (!layout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!layout->initProperties(properties, layoutSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The unboxedLayouts list only tracks layouts for plain objects.
|
||||
realm.unboxedLayouts.insertFront(layout.get());
|
||||
|
||||
if (!SetLayoutTraceList(cx, layout.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We've determined that all the preliminary objects can use the new layout
|
||||
// just constructed, so convert the existing group to use the unboxed class,
|
||||
// and update the preliminary objects to use the new layout. Do the
|
||||
// fallible stuff first before modifying any objects.
|
||||
|
||||
// Get an empty shape which we can use for the preliminary objects.
|
||||
Shape* newShape = EmptyShape::getInitialShape(cx, &UnboxedPlainObject::class_,
|
||||
group->proto(), 0);
|
||||
if (!newShape) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Accumulate a list of all the values in each preliminary object, and
|
||||
// update their shapes.
|
||||
Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
|
||||
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
|
||||
JSObject* obj = objects->get(i);
|
||||
if (!obj) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!GetValuesFromPreliminaryPlainObject(&obj->as<PlainObject>(),
|
||||
&values)) {
|
||||
cx->recoverFromOutOfMemory();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (TypeNewScript* newScript = group->newScript(sweep)) {
|
||||
layout->setNewScript(newScript);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
|
||||
if (JSObject* obj = objects->get(i)) {
|
||||
obj->as<NativeObject>().setLastPropertyMakeNonNative(newShape);
|
||||
}
|
||||
}
|
||||
|
||||
group->setClasp(&UnboxedPlainObject::class_);
|
||||
group->setUnboxedLayout(layout.release());
|
||||
|
||||
size_t valueCursor = 0;
|
||||
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
|
||||
JSObject* obj = objects->get(i);
|
||||
if (!obj) {
|
||||
continue;
|
||||
}
|
||||
|
||||
obj->as<UnboxedPlainObject>().fillAfterConvert(cx, values, &valueCursor);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(valueCursor == values.length());
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -285,13 +285,6 @@ inline bool IsUnboxedObjectClass(const Class* class_) {
|
|||
return class_ == &UnboxedPlainObject::class_;
|
||||
}
|
||||
|
||||
// Try to construct an UnboxedLayout for each of the preliminary objects,
|
||||
// provided they all match the template shape. If successful, converts the
|
||||
// preliminary objects and their group to the new unboxed representation.
|
||||
bool TryConvertToUnboxedLayout(JSContext* cx, AutoEnterAnalysis& enter,
|
||||
Shape* templateShape, ObjectGroup* group,
|
||||
PreliminaryObjectArray* objects);
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
|
Загрузка…
Ссылка в новой задаче