зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1000942 - Eliminate some unnecessary object type barriers. r=bhackett
This commit is contained in:
Родитель
8baaf89c87
Коммит
0181f313d3
|
@ -1728,7 +1728,7 @@ CodeGenerator::visitTypeBarrierV(LTypeBarrierV *lir)
|
|||
Register scratch = ToTempRegisterOrInvalid(lir->temp());
|
||||
|
||||
Label miss;
|
||||
masm.guardTypeSet(operand, lir->mir()->resultTypeSet(), scratch, &miss);
|
||||
masm.guardTypeSet(operand, lir->mir()->resultTypeSet(), lir->mir()->barrierKind(), scratch, &miss);
|
||||
if (!bailoutFrom(&miss, lir->snapshot()))
|
||||
return false;
|
||||
return true;
|
||||
|
@ -1737,6 +1737,8 @@ CodeGenerator::visitTypeBarrierV(LTypeBarrierV *lir)
|
|||
bool
|
||||
CodeGenerator::visitTypeBarrierO(LTypeBarrierO *lir)
|
||||
{
|
||||
MOZ_ASSERT(lir->mir()->barrierKind() != BarrierKind::TypeTagOnly);
|
||||
|
||||
Register obj = ToRegister(lir->object());
|
||||
Register scratch = ToTempRegisterOrInvalid(lir->temp());
|
||||
|
||||
|
@ -1754,7 +1756,7 @@ CodeGenerator::visitMonitorTypes(LMonitorTypes *lir)
|
|||
Register scratch = ToTempUnboxRegister(lir->temp());
|
||||
|
||||
Label matched, miss;
|
||||
masm.guardTypeSet(operand, lir->mir()->typeSet(), scratch, &miss);
|
||||
masm.guardTypeSet(operand, lir->mir()->typeSet(), lir->mir()->barrierKind(), scratch, &miss);
|
||||
if (!bailoutFrom(&miss, lir->snapshot()))
|
||||
return false;
|
||||
return true;
|
||||
|
@ -2710,7 +2712,7 @@ CodeGenerator::generateArgumentsChecks(bool bailout)
|
|||
// ... * sizeof(Value) - Scale by value size.
|
||||
// ArgToStackOffset(...) - Compute displacement within arg vector.
|
||||
int32_t offset = ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value));
|
||||
masm.guardTypeSet(Address(StackPointer, offset), types, temp, &miss);
|
||||
masm.guardTypeSet(Address(StackPointer, offset), types, BarrierKind::TypeSet, temp, &miss);
|
||||
}
|
||||
|
||||
if (miss.used()) {
|
||||
|
@ -3186,7 +3188,7 @@ CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
|
|||
if (mir->resultTypeSet() && !mir->resultTypeSet()->unknown()) {
|
||||
// We have a result TypeSet, assert this value is in it.
|
||||
Label miss, ok;
|
||||
masm.guardTypeSet(output, mir->resultTypeSet(), temp1, &miss);
|
||||
masm.guardTypeSet(output, mir->resultTypeSet(), BarrierKind::TypeSet, temp1, &miss);
|
||||
masm.jump(&ok);
|
||||
|
||||
masm.bind(&miss);
|
||||
|
|
|
@ -5049,7 +5049,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
|
|||
return false;
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return pushTypeBarrier(apply, types, true);
|
||||
return pushTypeBarrier(apply, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
// When inlining we have the arguments the function gets called with
|
||||
|
@ -5378,7 +5378,7 @@ IonBuilder::makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsit
|
|||
if (call->isCallDOMNative())
|
||||
return pushDOMTypeBarrier(call, types, call->getSingleTarget());
|
||||
|
||||
return pushTypeBarrier(call, types, true);
|
||||
return pushTypeBarrier(call, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -5426,7 +5426,7 @@ IonBuilder::jsop_eval(uint32_t argc)
|
|||
if (!string->mightBeType(MIRType_String)) {
|
||||
current->push(string);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return pushTypeBarrier(string, types, true);
|
||||
return pushTypeBarrier(string, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
current->pushSlot(info().thisSlot());
|
||||
|
@ -5465,7 +5465,7 @@ IonBuilder::jsop_eval(uint32_t argc)
|
|||
current->push(ins);
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return resumeAfter(ins) && pushTypeBarrier(ins, types, true);
|
||||
return resumeAfter(ins) && pushTypeBarrier(ins, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
return jsop_call(argc, /* constructing = */ false);
|
||||
|
@ -6274,7 +6274,7 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, Pr
|
|||
// instruction replaces the top of the stack.
|
||||
// (5) Lastly, a type barrier instruction replaces the top of the stack.
|
||||
bool
|
||||
IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, bool needsBarrier)
|
||||
IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, BarrierKind kind)
|
||||
{
|
||||
// Barriers are never needed for instructions whose result will not be used.
|
||||
if (BytecodeIsPopped(pc))
|
||||
|
@ -6286,7 +6286,7 @@ IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed,
|
|||
// must be a resume point capturing the original def, and resuming
|
||||
// to that point will explicitly monitor the new type.
|
||||
|
||||
if (!needsBarrier) {
|
||||
if (kind == BarrierKind::NoBarrier) {
|
||||
MDefinition *replace = ensureDefiniteType(def, observed->getKnownMIRType());
|
||||
if (replace != def) {
|
||||
current->pop();
|
||||
|
@ -6301,7 +6301,7 @@ IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed,
|
|||
|
||||
current->pop();
|
||||
|
||||
MInstruction *barrier = MTypeBarrier::New(alloc(), def, observed);
|
||||
MInstruction *barrier = MTypeBarrier::New(alloc(), def, observed, kind);
|
||||
current->add(barrier);
|
||||
|
||||
if (barrier->type() == MIRType_Undefined)
|
||||
|
@ -6342,7 +6342,8 @@ IonBuilder::pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *obser
|
|||
JS_ASSERT(barrier);
|
||||
}
|
||||
|
||||
return pushTypeBarrier(replace, observed, barrier);
|
||||
return pushTypeBarrier(replace, observed,
|
||||
barrier ? BarrierKind::TypeSet : BarrierKind::NoBarrier);
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
|
@ -6449,13 +6450,13 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
|
|||
}
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), staticType,
|
||||
name, types, /* updateObserved = */ true);
|
||||
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), staticType,
|
||||
name, types, /* updateObserved = */ true);
|
||||
|
||||
JSObject *singleton = types->getSingleton();
|
||||
|
||||
MIRType knownType = types->getKnownMIRType();
|
||||
if (!barrier) {
|
||||
if (barrier == BarrierKind::NoBarrier) {
|
||||
if (singleton) {
|
||||
// Try to inline a known constant value.
|
||||
if (testSingletonProperty(staticObject, name) == singleton)
|
||||
|
@ -6470,7 +6471,7 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
|
|||
MInstruction *obj = constant(ObjectValue(*staticObject));
|
||||
|
||||
MIRType rvalType = types->getKnownMIRType();
|
||||
if (barrier)
|
||||
if (barrier != BarrierKind::NoBarrier)
|
||||
rvalType = MIRType_Value;
|
||||
|
||||
return loadSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
|
||||
|
@ -6612,7 +6613,7 @@ IonBuilder::jsop_getname(PropertyName *name)
|
|||
return false;
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return pushTypeBarrier(ins, types, true);
|
||||
return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -6631,7 +6632,7 @@ IonBuilder::jsop_intrinsic(PropertyName *name)
|
|||
if (!resumeAfter(ins))
|
||||
return false;
|
||||
|
||||
return pushTypeBarrier(ins, types, true);
|
||||
return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
// Bake in the intrinsic. Make sure that TI agrees with us on the type.
|
||||
|
@ -6696,7 +6697,7 @@ IonBuilder::jsop_getelem()
|
|||
return false;
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return pushTypeBarrier(ins, types, true);
|
||||
return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
bool emitted = false;
|
||||
|
@ -6738,7 +6739,7 @@ IonBuilder::jsop_getelem()
|
|||
return false;
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return pushTypeBarrier(ins, types, true);
|
||||
return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -7004,7 +7005,7 @@ IonBuilder::pushDerivedTypedObject(bool *emitted,
|
|||
{
|
||||
derivedTypedObj->setResultTypeSet(observedTypes);
|
||||
} else {
|
||||
if (!pushTypeBarrier(derivedTypedObj, observedTypes, true))
|
||||
if (!pushTypeBarrier(derivedTypedObj, observedTypes, BarrierKind::TypeSet))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -7186,7 +7187,7 @@ IonBuilder::getElemTryArguments(bool *emitted, MDefinition *obj, MDefinition *in
|
|||
current->push(load);
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
if (!pushTypeBarrier(load, types, true))
|
||||
if (!pushTypeBarrier(load, types, BarrierKind::TypeSet))
|
||||
return false;
|
||||
|
||||
*emitted = true;
|
||||
|
@ -7255,18 +7256,19 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
|
|||
// Emit GetElementCache.
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj, nullptr, types);
|
||||
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj,
|
||||
nullptr, types);
|
||||
|
||||
// Always add a barrier if the index might be a string, so that the cache
|
||||
// can attach stubs for particular properties.
|
||||
if (index->mightBeType(MIRType_String))
|
||||
barrier = true;
|
||||
barrier = BarrierKind::TypeSet;
|
||||
|
||||
// See note about always needing a barrier in jsop_getprop.
|
||||
if (needsToMonitorMissingProperties(types))
|
||||
barrier = true;
|
||||
barrier = BarrierKind::TypeSet;
|
||||
|
||||
MInstruction *ins = MGetElementCache::New(alloc(), obj, index, barrier);
|
||||
MInstruction *ins = MGetElementCache::New(alloc(), obj, index, barrier != BarrierKind::NoBarrier);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
@ -7275,7 +7277,7 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
|
|||
return false;
|
||||
|
||||
// Spice up type information.
|
||||
if (index->type() == MIRType_Int32 && !barrier) {
|
||||
if (index->type() == MIRType_Int32 && barrier == BarrierKind::NoBarrier) {
|
||||
bool needHoleCheck = !ElementAccessIsPacked(constraints(), obj);
|
||||
MIRType knownType = GetElemKnownType(needHoleCheck, types);
|
||||
|
||||
|
@ -7302,7 +7304,8 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
|||
AddObjectsForPropertyRead(obj, nullptr, types);
|
||||
}
|
||||
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj, nullptr, types);
|
||||
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj,
|
||||
nullptr, types);
|
||||
bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj);
|
||||
|
||||
// Reads which are on holes in the object do not have to bail out if
|
||||
|
@ -7313,7 +7316,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
|||
!ElementAccessHasExtraIndexedProperty(constraints(), obj);
|
||||
|
||||
MIRType knownType = MIRType_Value;
|
||||
if (!barrier)
|
||||
if (barrier == BarrierKind::NoBarrier)
|
||||
knownType = GetElemKnownType(needsHoleCheck, types);
|
||||
|
||||
// Ensure index is an integer.
|
||||
|
@ -7341,7 +7344,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
|||
ExecutionMode executionMode = info().executionMode();
|
||||
bool loadDouble =
|
||||
executionMode == SequentialExecution &&
|
||||
!barrier &&
|
||||
barrier == BarrierKind::NoBarrier &&
|
||||
loopDepth_ &&
|
||||
!readOutOfBounds &&
|
||||
!needsHoleCheck &&
|
||||
|
@ -7392,7 +7395,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
|||
// NB: we have not added a MConvertElementsToDoubles MIR, so we
|
||||
// cannot *assume* the result is a double.
|
||||
if (executionMode == ParallelExecution &&
|
||||
barrier &&
|
||||
barrier != BarrierKind::NoBarrier &&
|
||||
types->getKnownMIRType() == MIRType_Int32 &&
|
||||
objTypes &&
|
||||
objTypes->convertDoubleElements(constraints()) == types::TemporaryTypeSet::AlwaysConvertToDoubles)
|
||||
|
@ -7402,7 +7405,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
|||
if (!types)
|
||||
return false;
|
||||
|
||||
barrier = false; // Don't need a barrier anymore
|
||||
barrier = BarrierKind::NoBarrier; // Don't need a barrier anymore
|
||||
}
|
||||
|
||||
if (knownType != MIRType_Value)
|
||||
|
@ -7561,7 +7564,7 @@ IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
|
|||
// observed (we've only read out-of-bounds values). Note that for
|
||||
// Uint32Array, we only check for int32: if allowDouble is false we
|
||||
// will bailout when we read a double.
|
||||
bool needsBarrier = true;
|
||||
BarrierKind barrier = BarrierKind::TypeSet;
|
||||
switch (arrayType) {
|
||||
case ScalarTypeDescr::TYPE_INT8:
|
||||
case ScalarTypeDescr::TYPE_UINT8:
|
||||
|
@ -7571,12 +7574,12 @@ IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
|
|||
case ScalarTypeDescr::TYPE_INT32:
|
||||
case ScalarTypeDescr::TYPE_UINT32:
|
||||
if (types->hasType(types::Type::Int32Type()))
|
||||
needsBarrier = false;
|
||||
barrier = BarrierKind::NoBarrier;
|
||||
break;
|
||||
case ScalarTypeDescr::TYPE_FLOAT32:
|
||||
case ScalarTypeDescr::TYPE_FLOAT64:
|
||||
if (allowDouble)
|
||||
needsBarrier = false;
|
||||
barrier = BarrierKind::NoBarrier;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Unknown typed array type");
|
||||
|
@ -7590,7 +7593,7 @@ IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
|
|||
current->add(load);
|
||||
current->push(load);
|
||||
|
||||
return pushTypeBarrier(load, types, needsBarrier);
|
||||
return pushTypeBarrier(load, types, barrier);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8494,7 +8497,7 @@ IonBuilder::invalidatedIdempotentCache()
|
|||
|
||||
bool
|
||||
IonBuilder::loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalType,
|
||||
bool barrier, types::TemporaryTypeSet *types)
|
||||
BarrierKind barrier, types::TemporaryTypeSet *types)
|
||||
{
|
||||
if (slot < nfixed) {
|
||||
MLoadFixedSlot *load = MLoadFixedSlot::New(alloc(), obj, slot);
|
||||
|
@ -8518,7 +8521,7 @@ IonBuilder::loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalT
|
|||
|
||||
bool
|
||||
IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
|
||||
bool barrier, types::TemporaryTypeSet *types)
|
||||
BarrierKind barrier, types::TemporaryTypeSet *types)
|
||||
{
|
||||
return loadSlot(obj, shape->slot(), shape->numFixedSlots(), rvalType, barrier, types);
|
||||
}
|
||||
|
@ -8568,8 +8571,8 @@ IonBuilder::jsop_getprop(PropertyName *name)
|
|||
return emitted;
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
|
||||
current->peek(-1), name, types);
|
||||
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
|
||||
current->peek(-1), name, types);
|
||||
|
||||
// Always use a call if we are performing analysis and
|
||||
// not actually emitting code, to simplify later analysis. Also skip deeper
|
||||
|
@ -8591,7 +8594,7 @@ IonBuilder::jsop_getprop(PropertyName *name)
|
|||
|
||||
current->pop();
|
||||
current->push(call);
|
||||
return resumeAfter(call) && pushTypeBarrier(call, types, true);
|
||||
return resumeAfter(call) && pushTypeBarrier(call, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
// Try to hardcode known constants.
|
||||
|
@ -8626,7 +8629,7 @@ IonBuilder::jsop_getprop(PropertyName *name)
|
|||
if (!resumeAfter(call))
|
||||
return false;
|
||||
|
||||
return pushTypeBarrier(call, types, true);
|
||||
return pushTypeBarrier(call, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -8765,7 +8768,7 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
|
|||
|
||||
bool
|
||||
IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
|
||||
bool barrier, types::TemporaryTypeSet *types)
|
||||
BarrierKind barrier, types::TemporaryTypeSet *types)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
types::HeapTypeSetKey property;
|
||||
|
@ -8781,7 +8784,7 @@ IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
|
|||
}
|
||||
|
||||
MLoadFixedSlot *fixed = MLoadFixedSlot::New(alloc(), useObj, property.maybeTypes()->definiteSlot());
|
||||
if (!barrier)
|
||||
if (barrier == BarrierKind::NoBarrier)
|
||||
fixed->setResultType(types->getKnownMIRType());
|
||||
|
||||
current->add(fixed);
|
||||
|
@ -8903,7 +8906,7 @@ CanInlinePropertyOpShapes(const BaselineInspector::ShapeVector &shapes)
|
|||
|
||||
bool
|
||||
IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name,
|
||||
bool barrier, types::TemporaryTypeSet *types)
|
||||
BarrierKind barrier, types::TemporaryTypeSet *types)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
if (current->peek(-1)->type() != MIRType_Object)
|
||||
|
@ -8917,7 +8920,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name,
|
|||
return true;
|
||||
|
||||
MIRType rvalType = types->getKnownMIRType();
|
||||
if (barrier || IsNullOrUndefined(rvalType))
|
||||
if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
|
||||
rvalType = MIRType_Value;
|
||||
|
||||
MDefinition *obj = current->pop();
|
||||
|
@ -8964,7 +8967,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name,
|
|||
|
||||
bool
|
||||
IonBuilder::getPropTryCache(bool *emitted, PropertyName *name,
|
||||
bool barrier, types::TemporaryTypeSet *types)
|
||||
BarrierKind barrier, types::TemporaryTypeSet *types)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
|
||||
|
@ -8981,18 +8984,19 @@ IonBuilder::getPropTryCache(bool *emitted, PropertyName *name,
|
|||
// Since getters have no guaranteed return values, we must barrier in order to be
|
||||
// able to attach stubs for them.
|
||||
if (inspector->hasSeenAccessedGetter(pc))
|
||||
barrier = true;
|
||||
barrier = BarrierKind::TypeSet;
|
||||
|
||||
if (needsToMonitorMissingProperties(types))
|
||||
barrier = true;
|
||||
barrier = BarrierKind::TypeSet;
|
||||
|
||||
// Caches can read values from prototypes, so update the barrier to
|
||||
// reflect such possible values.
|
||||
if (!barrier)
|
||||
if (barrier == BarrierKind::NoBarrier)
|
||||
barrier = PropertyReadOnPrototypeNeedsTypeBarrier(constraints(), obj, name, types);
|
||||
|
||||
current->pop();
|
||||
MGetPropertyCache *load = MGetPropertyCache::New(alloc(), obj, name, barrier);
|
||||
MGetPropertyCache *load = MGetPropertyCache::New(alloc(), obj, name,
|
||||
barrier != BarrierKind::NoBarrier);
|
||||
|
||||
// Try to mark the cache as idempotent.
|
||||
//
|
||||
|
@ -9019,7 +9023,7 @@ IonBuilder::getPropTryCache(bool *emitted, PropertyName *name,
|
|||
return false;
|
||||
|
||||
MIRType rvalType = types->getKnownMIRType();
|
||||
if (barrier || IsNullOrUndefined(rvalType))
|
||||
if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
|
||||
rvalType = MIRType_Value;
|
||||
load->setResultType(rvalType);
|
||||
|
||||
|
@ -9863,7 +9867,7 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
|
|||
current->push(load);
|
||||
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return pushTypeBarrier(load, types, true);
|
||||
return pushTypeBarrier(load, types, BarrierKind::TypeSet);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -343,7 +343,7 @@ class IonBuilder : public MIRGenerator
|
|||
|
||||
// Add a guard which ensure that the set of type which goes through this
|
||||
// generated code correspond to the observed types for the bytecode.
|
||||
bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, bool needBarrier);
|
||||
bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, BarrierKind kind);
|
||||
|
||||
// As pushTypeBarrier, but will compute the needBarrier boolean itself based
|
||||
// on observed and the JSFunction that we're planning to call. The
|
||||
|
@ -380,9 +380,9 @@ class IonBuilder : public MIRGenerator
|
|||
|
||||
bool hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall);
|
||||
bool loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalType,
|
||||
bool barrier, types::TemporaryTypeSet *types);
|
||||
BarrierKind barrier, types::TemporaryTypeSet *types);
|
||||
bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
|
||||
bool barrier, types::TemporaryTypeSet *types);
|
||||
BarrierKind barrier, types::TemporaryTypeSet *types);
|
||||
bool storeSlot(MDefinition *obj, size_t slot, size_t nfixed,
|
||||
MDefinition *value, bool needsBarrier,
|
||||
MIRType slotType = MIRType_None);
|
||||
|
@ -394,11 +394,11 @@ class IonBuilder : public MIRGenerator
|
|||
bool getPropTryConstant(bool *emitted, PropertyName *name,
|
||||
types::TemporaryTypeSet *types);
|
||||
bool getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
|
||||
bool barrier, types::TemporaryTypeSet *types);
|
||||
BarrierKind barrier, types::TemporaryTypeSet *types);
|
||||
bool getPropTryCommonGetter(bool *emitted, PropertyName *name,
|
||||
types::TemporaryTypeSet *types);
|
||||
bool getPropTryInlineAccess(bool *emitted, PropertyName *name,
|
||||
bool barrier, types::TemporaryTypeSet *types);
|
||||
BarrierKind barrier, types::TemporaryTypeSet *types);
|
||||
bool getPropTryTypedObject(bool *emitted, PropertyName *name,
|
||||
types::TemporaryTypeSet *resultTypes);
|
||||
bool getPropTryScalarPropOfTypedObject(bool *emitted,
|
||||
|
@ -411,7 +411,7 @@ class IonBuilder : public MIRGenerator
|
|||
size_t fieldIndex,
|
||||
types::TemporaryTypeSet *resultTypes);
|
||||
bool getPropTryCache(bool *emitted, PropertyName *name,
|
||||
bool barrier, types::TemporaryTypeSet *types);
|
||||
BarrierKind barrier, types::TemporaryTypeSet *types);
|
||||
bool needsToMonitorMissingProperties(types::TemporaryTypeSet *types);
|
||||
|
||||
// jsop_setprop() helpers.
|
||||
|
|
|
@ -1969,7 +1969,7 @@ GenerateSetSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
|
|||
Register scratchReg = object;
|
||||
masm.push(scratchReg);
|
||||
|
||||
masm.guardTypeSet(valReg, propTypes, scratchReg, &barrierFailure);
|
||||
masm.guardTypeSet(valReg, propTypes, BarrierKind::TypeSet, scratchReg, &barrierFailure);
|
||||
masm.pop(object);
|
||||
}
|
||||
}
|
||||
|
@ -2521,7 +2521,7 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
|
|||
JS_ASSERT(!propTypes->unknown());
|
||||
|
||||
Register scratchReg = object;
|
||||
masm.guardTypeSet(valReg, propTypes, scratchReg, &failuresPopObject);
|
||||
masm.guardTypeSet(valReg, propTypes, BarrierKind::TypeSet, scratchReg, &failuresPopObject);
|
||||
masm.loadPtr(Address(StackPointer, 0), object);
|
||||
}
|
||||
|
||||
|
|
|
@ -69,9 +69,10 @@ class TypeWrapper {
|
|||
} /* anonymous namespace */
|
||||
|
||||
template <typename Source, typename TypeSet> void
|
||||
MacroAssembler::guardTypeSet(const Source &address, const TypeSet *types,
|
||||
MacroAssembler::guardTypeSet(const Source &address, const TypeSet *types, BarrierKind kind,
|
||||
Register scratch, Label *miss)
|
||||
{
|
||||
JS_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
|
||||
JS_ASSERT(!types->unknown());
|
||||
|
||||
Label matched;
|
||||
|
@ -126,8 +127,10 @@ MacroAssembler::guardTypeSet(const Source &address, const TypeSet *types,
|
|||
// Test specific objects.
|
||||
JS_ASSERT(scratch != InvalidReg);
|
||||
branchTestObject(NotEqual, tag, miss);
|
||||
Register obj = extractObject(address, scratch);
|
||||
guardObjectType(obj, types, scratch, miss);
|
||||
if (kind != BarrierKind::TypeTagOnly) {
|
||||
Register obj = extractObject(address, scratch);
|
||||
guardObjectType(obj, types, scratch, miss);
|
||||
}
|
||||
|
||||
bind(&matched);
|
||||
}
|
||||
|
@ -203,30 +206,30 @@ MacroAssembler::guardType(const Source &address, types::Type type,
|
|||
Register scratch, Label *miss)
|
||||
{
|
||||
TypeWrapper wrapper(type);
|
||||
guardTypeSet(address, &wrapper, scratch, miss);
|
||||
guardTypeSet(address, &wrapper, BarrierKind::TypeSet, scratch, miss);
|
||||
}
|
||||
|
||||
template void MacroAssembler::guardTypeSet(const Address &address, const types::TemporaryTypeSet *types,
|
||||
Register scratch, Label *miss);
|
||||
BarrierKind kind, Register scratch, Label *miss);
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::TemporaryTypeSet *types,
|
||||
Register scratch, Label *miss);
|
||||
BarrierKind kind, Register scratch, Label *miss);
|
||||
|
||||
template void MacroAssembler::guardTypeSet(const Address &address, const types::HeapTypeSet *types,
|
||||
Register scratch, Label *miss);
|
||||
BarrierKind kind, Register scratch, Label *miss);
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::HeapTypeSet *types,
|
||||
Register scratch, Label *miss);
|
||||
BarrierKind kind, Register scratch, Label *miss);
|
||||
template void MacroAssembler::guardTypeSet(const TypedOrValueRegister ®, const types::HeapTypeSet *types,
|
||||
Register scratch, Label *miss);
|
||||
BarrierKind kind, Register scratch, Label *miss);
|
||||
|
||||
template void MacroAssembler::guardTypeSet(const Address &address, const types::TypeSet *types,
|
||||
Register scratch, Label *miss);
|
||||
BarrierKind kind, Register scratch, Label *miss);
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::TypeSet *types,
|
||||
Register scratch, Label *miss);
|
||||
BarrierKind kind, Register scratch, Label *miss);
|
||||
|
||||
template void MacroAssembler::guardTypeSet(const Address &address, const TypeWrapper *types,
|
||||
Register scratch, Label *miss);
|
||||
BarrierKind kind, Register scratch, Label *miss);
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const TypeWrapper *types,
|
||||
Register scratch, Label *miss);
|
||||
BarrierKind kind, Register scratch, Label *miss);
|
||||
|
||||
template void MacroAssembler::guardObjectType(Register obj, const types::TemporaryTypeSet *types,
|
||||
Register scratch, Label *miss);
|
||||
|
|
|
@ -300,7 +300,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
// Emits a test of a value against all types in a TypeSet. A scratch
|
||||
// register is required.
|
||||
template <typename Source, typename TypeSet>
|
||||
void guardTypeSet(const Source &address, const TypeSet *types, Register scratch, Label *miss);
|
||||
void guardTypeSet(const Source &address, const TypeSet *types, BarrierKind kind, Register scratch, Label *miss);
|
||||
template <typename TypeSet>
|
||||
void guardObjectType(Register obj, const TypeSet *types, Register scratch, Label *miss);
|
||||
template <typename Source>
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef jit_IonTypes_h
|
||||
#define jit_IonTypes_h
|
||||
|
||||
#include "mozilla/TypedEnum.h"
|
||||
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "js/Value.h"
|
||||
|
@ -324,6 +326,19 @@ enum ABIFunctionType
|
|||
(ArgType_General << (ArgType_Shift * 2))
|
||||
};
|
||||
|
||||
MOZ_BEGIN_ENUM_CLASS(BarrierKind, uint32_t)
|
||||
// No barrier is needed.
|
||||
NoBarrier,
|
||||
|
||||
// The barrier only has to check the value's type tag is in the TypeSet.
|
||||
// Specific object types don't have to be checked.
|
||||
TypeTagOnly,
|
||||
|
||||
// Check if the value is in the TypeSet, including the object type if it's
|
||||
// an object.
|
||||
TypeSet
|
||||
MOZ_END_ENUM_CLASS(BarrierKind)
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -2303,7 +2303,8 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
|
|||
}
|
||||
|
||||
// Handle typebarrier with specific TypeObject/SingleObjects.
|
||||
if (inputType == MIRType_Object && !types->hasType(types::Type::AnyObjectType()))
|
||||
if (inputType == MIRType_Object && !types->hasType(types::Type::AnyObjectType()) &&
|
||||
ins->barrierKind() != BarrierKind::TypeTagOnly)
|
||||
{
|
||||
LDefinition tmp = needTemp ? temp() : LDefinition::BogusTemp();
|
||||
LTypeBarrierO *barrier = new(alloc()) LTypeBarrierO(useRegister(ins->getOperand(0)), tmp);
|
||||
|
|
|
@ -385,9 +385,9 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
|
|||
bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED);
|
||||
bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
|
||||
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
|
||||
callInfo.thisArg(), nullptr, returnTypes);
|
||||
if (barrier)
|
||||
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
|
||||
callInfo.thisArg(), nullptr, returnTypes);
|
||||
if (barrier != BarrierKind::NoBarrier)
|
||||
returnType = MIRType_Value;
|
||||
|
||||
MArrayPopShift *ins = MArrayPopShift::New(alloc(), callInfo.thisArg(), mode,
|
||||
|
@ -1231,7 +1231,7 @@ IonBuilder::inlineRegExpExec(CallInfo &callInfo)
|
|||
if (!resumeAfter(exec))
|
||||
return InliningStatus_Error;
|
||||
|
||||
if (!pushTypeBarrier(exec, getInlineReturnTypeSet(), true))
|
||||
if (!pushTypeBarrier(exec, getInlineReturnTypeSet(), BarrierKind::TypeSet))
|
||||
return InliningStatus_Error;
|
||||
|
||||
return InliningStatus_Inlined;
|
||||
|
@ -1782,7 +1782,7 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo &callInfo)
|
|||
current->push(load);
|
||||
|
||||
// We don't track reserved slot types, so always emit a barrier.
|
||||
if (!pushTypeBarrier(load, getInlineReturnTypeSet(), true))
|
||||
if (!pushTypeBarrier(load, getInlineReturnTypeSet(), BarrierKind::TypeSet))
|
||||
return InliningStatus_Error;
|
||||
|
||||
return InliningStatus_Inlined;
|
||||
|
|
|
@ -3089,7 +3089,7 @@ jit::DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinit
|
|||
return elementType;
|
||||
}
|
||||
|
||||
static bool
|
||||
static BarrierKind
|
||||
PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints,
|
||||
types::TypeObjectKey *object, PropertyName *name,
|
||||
types::TypeSet *observed)
|
||||
|
@ -3105,13 +3105,20 @@ PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints,
|
|||
if (object->unknownProperties() || observed->empty() ||
|
||||
object->clasp()->isProxy())
|
||||
{
|
||||
return true;
|
||||
return BarrierKind::TypeSet;
|
||||
}
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
types::HeapTypeSetKey property = object->property(id);
|
||||
if (property.maybeTypes() && !TypeSetIncludes(observed, MIRType_Value, property.maybeTypes()))
|
||||
return true;
|
||||
if (property.maybeTypes()) {
|
||||
if (!TypeSetIncludes(observed, MIRType_Value, property.maybeTypes())) {
|
||||
// If all possible objects have been observed, we don't have to
|
||||
// guard on the specific object types.
|
||||
if (property.maybeTypes()->objectsAreSubset(observed))
|
||||
return BarrierKind::TypeTagOnly;
|
||||
return BarrierKind::TypeSet;
|
||||
}
|
||||
}
|
||||
|
||||
// Type information for global objects is not required to reflect the
|
||||
// initial 'undefined' value for properties, in particular global
|
||||
|
@ -3121,15 +3128,15 @@ PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints,
|
|||
if (name && types::CanHaveEmptyPropertyTypesForOwnProperty(obj) &&
|
||||
(!property.maybeTypes() || property.maybeTypes()->empty()))
|
||||
{
|
||||
return true;
|
||||
return BarrierKind::TypeSet;
|
||||
}
|
||||
}
|
||||
|
||||
property.freeze(constraints);
|
||||
return false;
|
||||
return BarrierKind::NoBarrier;
|
||||
}
|
||||
|
||||
bool
|
||||
BarrierKind
|
||||
jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
types::TypeObjectKey *object, PropertyName *name,
|
||||
|
@ -3177,45 +3184,55 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
|
|||
return PropertyReadNeedsTypeBarrier(constraints, object, name, observed);
|
||||
}
|
||||
|
||||
bool
|
||||
BarrierKind
|
||||
jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name,
|
||||
types::TemporaryTypeSet *observed)
|
||||
{
|
||||
if (observed->unknown())
|
||||
return false;
|
||||
return BarrierKind::NoBarrier;
|
||||
|
||||
types::TypeSet *types = obj->resultTypeSet();
|
||||
if (!types || types->unknownObject())
|
||||
return true;
|
||||
return BarrierKind::TypeSet;
|
||||
|
||||
BarrierKind res = BarrierKind::NoBarrier;
|
||||
|
||||
bool updateObserved = types->getObjectCount() == 1;
|
||||
for (size_t i = 0; i < types->getObjectCount(); i++) {
|
||||
types::TypeObjectKey *object = types->getObject(i);
|
||||
if (object) {
|
||||
if (PropertyReadNeedsTypeBarrier(propertycx, constraints, object, name,
|
||||
observed, updateObserved))
|
||||
{
|
||||
return true;
|
||||
BarrierKind kind = PropertyReadNeedsTypeBarrier(propertycx, constraints, object, name,
|
||||
observed, updateObserved);
|
||||
if (kind == BarrierKind::TypeSet)
|
||||
return BarrierKind::TypeSet;
|
||||
|
||||
if (kind == BarrierKind::TypeTagOnly) {
|
||||
MOZ_ASSERT(res == BarrierKind::NoBarrier || res == BarrierKind::TypeTagOnly);
|
||||
res = BarrierKind::TypeTagOnly;
|
||||
} else {
|
||||
MOZ_ASSERT(kind == BarrierKind::NoBarrier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
BarrierKind
|
||||
jit::PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name,
|
||||
types::TemporaryTypeSet *observed)
|
||||
{
|
||||
if (observed->unknown())
|
||||
return false;
|
||||
return BarrierKind::NoBarrier;
|
||||
|
||||
types::TypeSet *types = obj->resultTypeSet();
|
||||
if (!types || types->unknownObject())
|
||||
return true;
|
||||
return BarrierKind::TypeSet;
|
||||
|
||||
BarrierKind res = BarrierKind::NoBarrier;
|
||||
|
||||
for (size_t i = 0; i < types->getObjectCount(); i++) {
|
||||
types::TypeObjectKey *object = types->getObject(i);
|
||||
|
@ -3223,16 +3240,24 @@ jit::PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *cons
|
|||
continue;
|
||||
while (true) {
|
||||
if (!object->hasTenuredProto())
|
||||
return true;
|
||||
return BarrierKind::TypeSet;
|
||||
if (!object->proto().isObject())
|
||||
break;
|
||||
object = types::TypeObjectKey::get(object->proto().toObject());
|
||||
if (PropertyReadNeedsTypeBarrier(constraints, object, name, observed))
|
||||
return true;
|
||||
BarrierKind kind = PropertyReadNeedsTypeBarrier(constraints, object, name, observed);
|
||||
if (kind == BarrierKind::TypeSet)
|
||||
return BarrierKind::TypeSet;
|
||||
|
||||
if (kind == BarrierKind::TypeTagOnly) {
|
||||
MOZ_ASSERT(res == BarrierKind::NoBarrier || res == BarrierKind::TypeTagOnly);
|
||||
res = BarrierKind::TypeTagOnly;
|
||||
} else {
|
||||
MOZ_ASSERT(kind == BarrierKind::NoBarrier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3382,7 +3407,13 @@ TryAddTypeBarrierForWrite(TempAllocator &alloc, types::CompilerConstraintList *c
|
|||
if (!types)
|
||||
return false;
|
||||
|
||||
MInstruction *ins = MMonitorTypes::New(alloc, *pvalue, types);
|
||||
// If all possible objects can be stored without a barrier, we don't have to
|
||||
// guard on the specific object types.
|
||||
BarrierKind kind = BarrierKind::TypeSet;
|
||||
if ((*pvalue)->resultTypeSet() && (*pvalue)->resultTypeSet()->objectsAreSubset(types))
|
||||
kind = BarrierKind::TypeTagOnly;
|
||||
|
||||
MInstruction *ins = MMonitorTypes::New(alloc, *pvalue, types, kind);
|
||||
current->add(ins);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -9070,10 +9070,15 @@ class MTypeBarrier
|
|||
: public MUnaryInstruction,
|
||||
public TypeBarrierPolicy
|
||||
{
|
||||
MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types)
|
||||
: MUnaryInstruction(def)
|
||||
BarrierKind barrierKind_;
|
||||
|
||||
MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types, BarrierKind kind)
|
||||
: MUnaryInstruction(def),
|
||||
barrierKind_(kind)
|
||||
{
|
||||
JS_ASSERT(!types->unknown());
|
||||
MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
|
||||
|
||||
MOZ_ASSERT(!types->unknown());
|
||||
setResultType(types->getKnownMIRType());
|
||||
setResultTypeSet(types);
|
||||
|
||||
|
@ -9084,8 +9089,9 @@ class MTypeBarrier
|
|||
public:
|
||||
INSTRUCTION_HEADER(TypeBarrier)
|
||||
|
||||
static MTypeBarrier *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) {
|
||||
return new(alloc) MTypeBarrier(def, types);
|
||||
static MTypeBarrier *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types,
|
||||
BarrierKind kind = BarrierKind::TypeSet) {
|
||||
return new(alloc) MTypeBarrier(def, types, kind);
|
||||
}
|
||||
|
||||
void printOpcode(FILE *fp) const;
|
||||
|
@ -9103,6 +9109,9 @@ class MTypeBarrier
|
|||
virtual bool neverHoist() const {
|
||||
return resultTypeSet()->empty();
|
||||
}
|
||||
BarrierKind barrierKind() const {
|
||||
return barrierKind_;
|
||||
}
|
||||
|
||||
bool alwaysBails() const {
|
||||
// If mirtype of input doesn't agree with mirtype of barrier,
|
||||
|
@ -9122,20 +9131,25 @@ class MTypeBarrier
|
|||
class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
|
||||
{
|
||||
const types::TemporaryTypeSet *typeSet_;
|
||||
BarrierKind barrierKind_;
|
||||
|
||||
MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types)
|
||||
MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types, BarrierKind kind)
|
||||
: MUnaryInstruction(def),
|
||||
typeSet_(types)
|
||||
typeSet_(types),
|
||||
barrierKind_(kind)
|
||||
{
|
||||
MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
|
||||
|
||||
setGuard();
|
||||
JS_ASSERT(!types->unknown());
|
||||
MOZ_ASSERT(!types->unknown());
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(MonitorTypes)
|
||||
|
||||
static MMonitorTypes *New(TempAllocator &alloc, MDefinition *def, const types::TemporaryTypeSet *types) {
|
||||
return new(alloc) MMonitorTypes(def, types);
|
||||
static MMonitorTypes *New(TempAllocator &alloc, MDefinition *def, const types::TemporaryTypeSet *types,
|
||||
BarrierKind kind) {
|
||||
return new(alloc) MMonitorTypes(def, types, kind);
|
||||
}
|
||||
|
||||
TypePolicy *typePolicy() {
|
||||
|
@ -9145,6 +9159,10 @@ class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
|
|||
const types::TemporaryTypeSet *typeSet() const {
|
||||
return typeSet_;
|
||||
}
|
||||
BarrierKind barrierKind() const {
|
||||
return barrierKind_;
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
@ -10094,17 +10112,17 @@ bool ElementAccessIsPacked(types::CompilerConstraintList *constraints, MDefiniti
|
|||
bool ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj);
|
||||
MIRType DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinition *obj);
|
||||
bool PropertyReadNeedsTypeBarrier(JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
types::TypeObjectKey *object, PropertyName *name,
|
||||
types::TemporaryTypeSet *observed, bool updateObserved);
|
||||
bool PropertyReadNeedsTypeBarrier(JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name,
|
||||
types::TemporaryTypeSet *observed);
|
||||
bool PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name,
|
||||
types::TemporaryTypeSet *observed);
|
||||
BarrierKind PropertyReadNeedsTypeBarrier(JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
types::TypeObjectKey *object, PropertyName *name,
|
||||
types::TemporaryTypeSet *observed, bool updateObserved);
|
||||
BarrierKind PropertyReadNeedsTypeBarrier(JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name,
|
||||
types::TemporaryTypeSet *observed);
|
||||
BarrierKind PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name,
|
||||
types::TemporaryTypeSet *observed);
|
||||
bool PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name);
|
||||
void AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
|
||||
|
|
|
@ -351,6 +351,26 @@ TypeSet::mightBeMIRType(jit::MIRType type)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TypeSet::objectsAreSubset(TypeSet *other)
|
||||
{
|
||||
if (other->unknownObject())
|
||||
return true;
|
||||
|
||||
if (unknownObject())
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < getObjectCount(); i++) {
|
||||
TypeObjectKey *obj = getObject(i);
|
||||
if (!obj)
|
||||
continue;
|
||||
if (!other->hasType(Type::ObjectType(obj)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TypeSet::isSubset(TypeSet *other)
|
||||
{
|
||||
|
|
|
@ -584,6 +584,12 @@ class TypeSet
|
|||
*/
|
||||
bool isSubset(TypeSet *other);
|
||||
|
||||
/*
|
||||
* Get whether the objects in this TypeSet are a subset of the objects
|
||||
* in other.
|
||||
*/
|
||||
bool objectsAreSubset(TypeSet *other);
|
||||
|
||||
/* Forward all types in this set to the specified constraint. */
|
||||
bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче