public static InstructionState operator +(InstructionState s1, InstructionState s2)
{
if (s1 == null)
{
return s2.Copy();
}
if (s1.stackSize != s2.stackSize || s1.stackEnd != s2.stackEnd)
{
throw new VerifyError(string.Format("Inconsistent stack height: {0} != {1}",
s1.stackSize + s1.stack.Length - s1.stackEnd,
s2.stackSize + s2.stack.Length - s2.stackEnd));
}
InstructionState s = s1.Copy();
s.changed = s1.changed;
for (int i = 0; i < s.stackSize; i++)
{
SimpleType type = s.stack[i];
SimpleType type2 = s2.stack[i];
if (type == type2)
{
// perfect match, nothing to do
}
else if (!type.IsPrimitive)
{
SimpleType baseType = InstructionState.FindCommonBaseType(type, type2);
if (baseType == SimpleType.Invalid)
{
if (SimpleType.IsRet(type) && SimpleType.IsRet(type2))
{
// if we never return from a subroutine, it is legal to merge to subroutine flows
// (this is from the Mauve test subr.pass.mergeok)
}
else
{
throw new VerifyError(string.Format("cannot merge {0} and {1}", type, type2));
}
}
if (type != baseType)
{
s.StackCopyOnWrite();
s.stack[i] = baseType;
s.changed = true;
}
}
else
{
throw new VerifyError(string.Format("cannot merge {0} and {1}", type, type2));
}
}
for (int i = 0; i < s.locals.Length; i++)
{
SimpleType type = s.locals[i];
SimpleType type2 = s2.locals[i];
SimpleType baseType = InstructionState.FindCommonBaseType(type, type2);
if (type != baseType)
{
s.LocalsCopyOnWrite();
s.locals[i] = baseType;
s.changed = true;
}
}
s.MergeSubroutineHelper(s2);
return s;
}