Bug 1000942 - Eliminate some unnecessary object type barriers. r=bhackett

This commit is contained in:
Jan de Mooij 2014-04-29 08:54:46 +02:00
Родитель 8baaf89c87
Коммит 0181f313d3
13 изменённых файлов: 225 добавлений и 125 удалений

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

@ -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 &reg, 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);