Bug 996422 - Part 2: Split MIRType_Magic into one type for each magic constant. (r=jandem)

This commit is contained in:
Shu-yu Guo 2014-04-22 18:23:27 -07:00
parent 0529a14819
commit 32ae0307bf
11 changed files with 147 additions and 77 deletions

View File

@ -4047,7 +4047,7 @@ CodeGenerator::visitGetArgumentsObjectArg(LGetArgumentsObjectArg *lir)
#ifdef DEBUG
Label success;
masm.branchTestMagic(Assembler::NotEqual, out, &success);
masm.assumeUnreachable("Result from ArgumentObject shouldn't be MIRType_Magic.");
masm.assumeUnreachable("Result from ArgumentObject shouldn't be JSVAL_TYPE_MAGIC.");
masm.bind(&success);
#endif
return true;
@ -4066,7 +4066,7 @@ CodeGenerator::visitSetArgumentsObjectArg(LSetArgumentsObjectArg *lir)
#ifdef DEBUG
Label success;
masm.branchTestMagic(Assembler::NotEqual, argAddr, &success);
masm.assumeUnreachable("Result in ArgumentObject shouldn't be MIRType_Magic.");
masm.assumeUnreachable("Result in ArgumentObject shouldn't be JSVAL_TYPE_MAGIC.");
masm.bind(&success);
#endif
masm.storeValue(value, argAddr);

View File

@ -442,6 +442,22 @@ class TypeAnalyzer
static MIRType
GuessPhiType(MPhi *phi, bool *hasInputsWithEmptyTypes)
{
#ifdef DEBUG
// Check that different magic constants aren't flowing together.
MIRType magicType = MIRType_None;
for (size_t i = 0; i < phi->numOperands(); i++) {
MDefinition *in = phi->getOperand(i);
if (in->type() == MIRType_MagicOptimizedArguments ||
in->type() == MIRType_MagicHole ||
in->type() == MIRType_MagicIsConstructing)
{
if (magicType == MIRType_None)
magicType = in->type();
MOZ_ASSERT(magicType == in->type());
}
}
#endif
*hasInputsWithEmptyTypes = false;
MIRType type = MIRType_None;
@ -714,7 +730,7 @@ TypeAnalyzer::replaceRedundantPhi(MPhi *phi)
case MIRType_Null:
v = NullValue();
break;
case MIRType_Magic:
case MIRType_MagicOptimizedArguments:
v = MagicValue(JS_OPTIMIZED_ARGUMENTS);
break;
default:
@ -737,7 +753,10 @@ TypeAnalyzer::insertConversions()
return false;
for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd();) {
if (phi->type() <= MIRType_Null || phi->type() == MIRType_Magic) {
if (phi->type() == MIRType_Undefined ||
phi->type() == MIRType_Null ||
phi->type() == MIRType_MagicOptimizedArguments)
{
replaceRedundantPhi(*phi);
phi = block->discardPhiAt(phi);
} else {

View File

@ -1031,7 +1031,7 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction **def_,
def = barrier;
} else if (type == MIRType_Null ||
type == MIRType_Undefined ||
type == MIRType_Magic)
type == MIRType_MagicOptimizedArguments)
{
// No unbox instruction will be added below, so check the type by
// adding a type barrier for a singleton type set.
@ -1077,7 +1077,7 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction **def_,
break;
}
case MIRType_Magic:
case MIRType_MagicOptimizedArguments:
JS_ASSERT(lazyArguments_);
osrBlock->rewriteSlot(slot, lazyArguments_);
def = lazyArguments_;
@ -4943,14 +4943,14 @@ IonBuilder::jsop_funapply(uint32_t argc)
// to be either definitely |arguments| or definitely not |arguments|.
MDefinition *argument = current->peek(-1);
if (script()->argumentsHasVarBinding() &&
argument->mightBeType(MIRType_Magic) &&
argument->type() != MIRType_Magic)
argument->mightBeType(MIRType_MagicOptimizedArguments) &&
argument->type() != MIRType_MagicOptimizedArguments)
{
return abort("fun.apply with MaybeArguments");
}
// Fallback to regular call if arg 2 is not definitely |arguments|.
if (argument->type() != MIRType_Magic) {
if (argument->type() != MIRType_MagicOptimizedArguments) {
CallInfo callInfo(alloc(), false);
if (!callInfo.init(current, argc))
return false;
@ -5531,7 +5531,7 @@ IonBuilder::jsop_initelem_array()
// to them during initialization.
bool needStub = false;
types::TypeObjectKey *initializer = obj->resultTypeSet()->getObject(0);
if (value->isConstant() && value->toConstant()->value().isMagic(JS_ELEMENTS_HOLE)) {
if (value->type() == MIRType_MagicHole) {
if (!initializer->hasFlags(constraints(), types::OBJECT_FLAG_NON_PACKED))
needStub = true;
} else if (!initializer->unknownProperties()) {
@ -6462,7 +6462,7 @@ jit::TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *input
case MIRType_Double:
case MIRType_Float32:
case MIRType_String:
case MIRType_Magic:
case MIRType_MagicOptimizedArguments:
return types->hasType(types::Type::PrimitiveType(ValueTypeFromMIRType(input)));
case MIRType_Object:
@ -6677,7 +6677,7 @@ IonBuilder::jsop_getelem()
if (!getElemTryArgumentsInlined(&emitted, obj, index) || emitted)
return emitted;
if (script()->argumentsHasVarBinding() && obj->mightBeType(MIRType_Magic))
if (script()->argumentsHasVarBinding() && obj->mightBeType(MIRType_MagicOptimizedArguments))
return abort("Type is not definitely lazy arguments.");
if (!getElemTryCache(&emitted, obj, index) || emitted)
@ -7113,7 +7113,7 @@ IonBuilder::getElemTryArguments(bool *emitted, MDefinition *obj, MDefinition *in
if (inliningDepth_ > 0)
return true;
if (obj->type() != MIRType_Magic)
if (obj->type() != MIRType_MagicOptimizedArguments)
return true;
// Emit GetFrameArgument.
@ -7156,7 +7156,7 @@ IonBuilder::getElemTryArgumentsInlined(bool *emitted, MDefinition *obj, MDefinit
if (inliningDepth_ == 0)
return true;
if (obj->type() != MIRType_Magic)
if (obj->type() != MIRType_MagicOptimizedArguments)
return true;
// Emit inlined arguments.
@ -7573,7 +7573,7 @@ IonBuilder::jsop_setelem()
if (!setElemTryArguments(&emitted, object, index, value) || emitted)
return emitted;
if (script()->argumentsHasVarBinding() && object->mightBeType(MIRType_Magic))
if (script()->argumentsHasVarBinding() && object->mightBeType(MIRType_MagicOptimizedArguments))
return abort("Type is not definitely lazy arguments.");
if (!setElemTryCache(&emitted, object, index, value) || emitted)
@ -7784,7 +7784,7 @@ IonBuilder::setElemTryArguments(bool *emitted, MDefinition *object,
{
JS_ASSERT(*emitted == false);
if (object->type() != MIRType_Magic)
if (object->type() != MIRType_MagicOptimizedArguments)
return true;
// Arguments are not supported yet.
@ -8588,9 +8588,12 @@ bool
IonBuilder::getPropTryArgumentsLength(bool *emitted)
{
JS_ASSERT(*emitted == false);
if (current->peek(-1)->type() != MIRType_Magic) {
if (script()->argumentsHasVarBinding() && current->peek(-1)->mightBeType(MIRType_Magic))
if (current->peek(-1)->type() != MIRType_MagicOptimizedArguments) {
if (script()->argumentsHasVarBinding() &&
current->peek(-1)->mightBeType(MIRType_MagicOptimizedArguments))
{
return abort("Type is not definitely lazy arguments.");
}
return true;
}
if (JSOp(*pc) != JSOP_LENGTH)

View File

@ -127,12 +127,16 @@ class MacroAssembler : public MacroAssemblerSpecific
JS_ASSERT(isInitialized());
MIRType mirType = MIRType_None;
if (type_.isPrimitive())
mirType = MIRTypeFromValueType(type_.primitive());
else if (type_.isAnyObject())
if (type_.isPrimitive()) {
if (type_.isMagicArguments())
mirType = MIRType_MagicOptimizedArguments;
else
mirType = MIRTypeFromValueType(type_.primitive());
} else if (type_.isAnyObject()) {
mirType = MIRType_Object;
else
} else {
MOZ_ASSUME_UNREACHABLE("Unknown conversion to mirtype");
}
if (mirType == MIRType_Double)
masm.branchTestNumber(cond(), reg(), jump());
@ -332,14 +336,16 @@ class MacroAssembler : public MacroAssemblerSpecific
template <typename Value>
void branchTestMIRType(Condition cond, const Value &val, MIRType type, Label *label) {
switch (type) {
case MIRType_Null: return branchTestNull(cond, val, label);
case MIRType_Undefined: return branchTestUndefined(cond, val, label);
case MIRType_Boolean: return branchTestBoolean(cond, val, label);
case MIRType_Int32: return branchTestInt32(cond, val, label);
case MIRType_String: return branchTestString(cond, val, label);
case MIRType_Object: return branchTestObject(cond, val, label);
case MIRType_Double: return branchTestDouble(cond, val, label);
case MIRType_Magic: return branchTestMagic(cond, val, label);
case MIRType_Null: return branchTestNull(cond, val, label);
case MIRType_Undefined: return branchTestUndefined(cond, val, label);
case MIRType_Boolean: return branchTestBoolean(cond, val, label);
case MIRType_Int32: return branchTestInt32(cond, val, label);
case MIRType_String: return branchTestString(cond, val, label);
case MIRType_Object: return branchTestObject(cond, val, label);
case MIRType_Double: return branchTestDouble(cond, val, label);
case MIRType_MagicOptimizedArguments: // Fall through.
case MIRType_MagicIsConstructing:
case MIRType_MagicHole: return branchTestMagic(cond, val, label);
default:
MOZ_ASSUME_UNREACHABLE("Bad MIRType");
}

View File

@ -70,7 +70,7 @@ BailoutKindString(BailoutKind kind)
}
}
static const uint32_t ELEMENT_TYPE_BITS = 4;
static const uint32_t ELEMENT_TYPE_BITS = 5;
static const uint32_t ELEMENT_TYPE_SHIFT = 0;
static const uint32_t ELEMENT_TYPE_MASK = (1 << ELEMENT_TYPE_BITS) - 1;
static const uint32_t VECTOR_SCALE_BITS = 2;
@ -90,14 +90,16 @@ enum MIRType
MIRType_Float32,
MIRType_String,
MIRType_Object,
MIRType_Magic,
MIRType_MagicOptimizedArguments, // JS_OPTIMIZED_ARGUMENTS magic value.
MIRType_MagicHole, // JS_ELEMENTS_HOLE magic value.
MIRType_MagicIsConstructing, // JS_IS_CONSTRUCTING magic value.
MIRType_Value,
MIRType_None, // Invalid, used as a placeholder.
MIRType_Slots, // A slots vector
MIRType_Elements, // An elements vector
MIRType_Pointer, // An opaque pointer that receives no special treatment
MIRType_Shape, // A Shape pointer.
MIRType_ForkJoinContext, // js::ForkJoinContext*
MIRType_None, // Invalid, used as a placeholder.
MIRType_Slots, // A slots vector
MIRType_Elements, // An elements vector
MIRType_Pointer, // An opaque pointer that receives no special treatment
MIRType_Shape, // A Shape pointer.
MIRType_ForkJoinContext, // js::ForkJoinContext*
MIRType_Last = MIRType_ForkJoinContext,
MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT),
MIRType_Int32x4 = MIRType_Int32 | (2 << VECTOR_SCALE_SHIFT),
@ -120,6 +122,8 @@ VectorSize(MIRType type)
static inline MIRType
MIRTypeFromValueType(JSValueType type)
{
// This function does not deal with magic types. Magic constants should be
// filtered out in MIRTypeFromValue.
switch (type) {
case JSVAL_TYPE_DOUBLE:
return MIRType_Double;
@ -135,8 +139,6 @@ MIRTypeFromValueType(JSValueType type)
return MIRType_Null;
case JSVAL_TYPE_OBJECT:
return MIRType_Object;
case JSVAL_TYPE_MAGIC:
return MIRType_Magic;
case JSVAL_TYPE_UNKNOWN:
return MIRType_Value;
default:
@ -161,7 +163,9 @@ ValueTypeFromMIRType(MIRType type)
return JSVAL_TYPE_DOUBLE;
case MIRType_String:
return JSVAL_TYPE_STRING;
case MIRType_Magic:
case MIRType_MagicOptimizedArguments:
case MIRType_MagicHole:
case MIRType_MagicIsConstructing:
return JSVAL_TYPE_MAGIC;
default:
JS_ASSERT(type == MIRType_Object);
@ -195,8 +199,12 @@ StringFromMIRType(MIRType type)
return "String";
case MIRType_Object:
return "Object";
case MIRType_Magic:
return "Magic";
case MIRType_MagicOptimizedArguments:
return "MagicOptimizedArguments";
case MIRType_MagicHole:
return "MagicHole";
case MIRType_MagicIsConstructing:
return "MagicIsConstructing";
case MIRType_Value:
return "Value";
case MIRType_None:

View File

@ -548,8 +548,14 @@ MConstant::printOpcode(FILE *fp) const
case MIRType_String:
fprintf(fp, "string %p", (void *)value().toString());
break;
case MIRType_Magic:
fprintf(fp, "magic");
case MIRType_MagicOptimizedArguments:
fprintf(fp, "magic lazyargs");
break;
case MIRType_MagicHole:
fprintf(fp, "magic hole");
break;
case MIRType_MagicIsConstructing:
fprintf(fp, "magic is-constructing");
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected type");
@ -1695,7 +1701,9 @@ KnownNonStringPrimitive(MDefinition *op)
{
return !op->mightBeType(MIRType_Object)
&& !op->mightBeType(MIRType_String)
&& !op->mightBeType(MIRType_Magic);
&& !op->mightBeType(MIRType_MagicOptimizedArguments)
&& !op->mightBeType(MIRType_MagicHole)
&& !op->mightBeType(MIRType_MagicIsConstructing);
}
void
@ -1819,7 +1827,9 @@ ObjectOrSimplePrimitive(MDefinition *op)
return !op->mightBeType(MIRType_String)
&& !op->mightBeType(MIRType_Double)
&& !op->mightBeType(MIRType_Float32)
&& !op->mightBeType(MIRType_Magic);
&& !op->mightBeType(MIRType_MagicOptimizedArguments)
&& !op->mightBeType(MIRType_MagicHole)
&& !op->mightBeType(MIRType_MagicIsConstructing);
}
static bool

View File

@ -42,6 +42,18 @@ MIRType MIRTypeFromValue(const js::Value &vp)
{
if (vp.isDouble())
return MIRType_Double;
if (vp.isMagic()) {
switch (vp.whyMagic()) {
case JS_OPTIMIZED_ARGUMENTS:
return MIRType_MagicOptimizedArguments;
case JS_ELEMENTS_HOLE:
return MIRType_MagicHole;
case JS_IS_CONSTRUCTING:
return MIRType_MagicIsConstructing;
default:
MOZ_ASSERT(!"Unexpected magic constant");
}
}
return MIRTypeFromValueType(vp.extractNonDoubleType());
}
@ -455,7 +467,7 @@ class MDefinition : public MNode
bool emptyResultTypeSet() const;
bool mightBeType(MIRType type) const {
JS_ASSERT(type != MIRType_Value);
MOZ_ASSERT(type != MIRType_Value);
if (type == this->type())
return true;

View File

@ -293,8 +293,9 @@ TypeBarrierPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
if (inputType == MIRType_Value) {
JS_ASSERT(outputType != MIRType_Value);
// We can't unbox a value to null/undefined. So keep output also a value.
if (IsNullOrUndefined(outputType) || outputType == MIRType_Magic) {
// We can't unbox a value to null/undefined/lazyargs. So keep output
// also a value.
if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
JS_ASSERT(ins->defUseCount() == 0);
ins->setResultType(MIRType_Value);
return true;

View File

@ -193,7 +193,7 @@ CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resume
}
break;
}
case MIRType_Magic:
case MIRType_MagicOptimizedArguments:
{
uint32_t index;
if (!graph.addConstantToPool(MagicValue(JS_OPTIMIZED_ARGUMENTS), &index))

View File

@ -310,29 +310,6 @@ TemporaryTypeSet::TemporaryTypeSet(Type type)
}
}
static inline TypeFlags
PrimitiveMIRType(jit::MIRType type)
{
switch (type) {
case jit::MIRType_Undefined:
return TYPE_FLAG_UNDEFINED;
case jit::MIRType_Null:
return TYPE_FLAG_NULL;
case jit::MIRType_Boolean:
return TYPE_FLAG_BOOLEAN;
case jit::MIRType_Int32:
return TYPE_FLAG_INT32;
case jit::MIRType_Double:
return TYPE_FLAG_DOUBLE;
case jit::MIRType_String:
return TYPE_FLAG_STRING;
case jit::MIRType_Magic:
return TYPE_FLAG_LAZYARGS;
default:
MOZ_ASSUME_UNREACHABLE("Bad MIR type");
}
}
bool
TypeSet::mightBeMIRType(jit::MIRType type)
{
@ -342,7 +319,37 @@ TypeSet::mightBeMIRType(jit::MIRType type)
if (type == jit::MIRType_Object)
return unknownObject() || baseObjectCount() != 0;
return baseFlags() & PrimitiveMIRType(type);
switch (type) {
case jit::MIRType_Undefined:
return baseFlags() & TYPE_FLAG_UNDEFINED;
case jit::MIRType_Null:
return baseFlags() & TYPE_FLAG_NULL;
case jit::MIRType_Boolean:
return baseFlags() & TYPE_FLAG_BOOLEAN;
case jit::MIRType_Int32:
return baseFlags() & TYPE_FLAG_INT32;
case jit::MIRType_Float32: // Fall through, there's no JSVAL for Float32.
case jit::MIRType_Double:
return baseFlags() & TYPE_FLAG_DOUBLE;
case jit::MIRType_String:
return baseFlags() & TYPE_FLAG_STRING;
case jit::MIRType_MagicOptimizedArguments:
return baseFlags() & TYPE_FLAG_LAZYARGS;
case jit::MIRType_MagicHole:
case jit::MIRType_MagicIsConstructing:
// These magic constants do not escape to script and are not observed
// in the type sets.
//
// The reason we can return false here is subtle: if Ion is asking the
// type set if it has seen such a magic constant, then the MIR in
// question is the most generic type, MIRType_Value. A magic constant
// could only be emitted by a MIR of MIRType_Value if that MIR is a
// phi, and we check that different magic constants do not flow to the
// same join point in GuessPhiType.
return false;
default:
MOZ_ASSUME_UNREACHABLE("Bad MIR type");
}
}
bool
@ -1182,7 +1189,7 @@ GetMIRTypeFromTypeFlags(TypeFlags flags)
case TYPE_FLAG_STRING:
return jit::MIRType_String;
case TYPE_FLAG_LAZYARGS:
return jit::MIRType_Magic;
return jit::MIRType_MagicOptimizedArguments;
case TYPE_FLAG_ANYOBJECT:
return jit::MIRType_Object;
default:

View File

@ -224,6 +224,10 @@ class Type
return (JSValueType) data;
}
bool isMagicArguments() const {
return primitive() == JSVAL_TYPE_MAGIC;
}
bool isSomeObject() const {
return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
}
@ -657,7 +661,7 @@ class TemporaryTypeSet : public TypeSet
/* Get any type tag which all values in this set must have. */
jit::MIRType getKnownMIRType();
bool isMagicArguments() { return getKnownMIRType() == jit::MIRType_Magic; }
bool isMagicArguments() { return getKnownMIRType() == jit::MIRType_MagicOptimizedArguments; }
/* Whether this value may be an object. */
bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }