示例#1
0
        public IntSet Union(IntSet other, BoolRef changed)
        {
            var res = new IntSet(Math.Max(n, other.n));

            for (var i = 0; i < Math.Min(v.Length, other.v.Length); i++)
            {
                var origv = v[i];
                res.v[i] = v[i] | other.v[i];
                if (res.v[i] != origv)
                {
                    changed.Set();
                }
            }
            if (v.Length < other.v.Length)
            {
                for (var i = v.Length; i < other.v.Length; i++)
                {
                    res.v[i] = other.v[i];
                    if (other.v[i] != 0u)
                    {
                        changed.Set();
                    }
                }
            }
            else
            {
                for (var i = other.v.Length; i < v.Length; i++)
                {
                    res.v[i] = v[i];
                }
            }
            return(res);
        }
示例#2
0
        public ReadWriteDomain Lub(ReadWriteDomain other, BoolRef changed)
        {
            switch (Value)
            {
            case ReadWriteEnum.None:
                if (other.Value != ReadWriteEnum.None)
                {
                    changed.Set();
                    return(other);
                }
                else
                {
                    return(this);
                }

            case ReadWriteEnum.Read:
                if (other.Value == ReadWriteEnum.ReadWrite)
                {
                    changed.Set();
                    return(other);
                }
                else
                {
                    return(this);
                }

            case ReadWriteEnum.ReadWrite:
                return(this);

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
示例#3
0
 public ControlFlow Lub(ControlFlow other, BoolRef changed)
 {
     if (Value == other.Value || Value == ControlFlowEnum.Any)
     {
         return(this);
     }
     else
     {
         changed.Set();
         return(Top);
     }
 }
示例#4
0
 public BooleanDomain Lub(BooleanDomain other, BoolRef changed)
 {
     if (!Value && other.Value)
     {
         changed.Set();
         return(Top);
     }
     else
     {
         return(this);
     }
 }
示例#5
0
        public IntPowersetDomain Lub(IntPowersetDomain other, BoolRef changed)
        {
            var thisChanged = new BoolRef();
            var members     = Members.Union(other.Members, thisChanged);

            if (thisChanged.Value)
            {
                changed.Set();
                return(new IntPowersetDomain(members));
            }
            else
            {
                return(this);
            }
        }
示例#6
0
        public ReadWriteVectorDomain Lub(ReadWriteVectorDomain other, BoolRef changed)
        {
            var thisChanged = new BoolRef();
            var isRead      = IsRead.Union(other.IsRead, thisChanged);
            var isWrite     = IsWrite.Union(other.IsWrite, thisChanged);

            if (thisChanged.Value)
            {
                changed.Set();
                return(new ReadWriteVectorDomain(isRead, isWrite));
            }
            else
            {
                return(this);
            }
        }
示例#7
0
 public EvalTimes Lub(EvalTimes other, BoolRef changed)
 {
     if (Value == other.Value || Value == EvalTimesEnum.Any || other.Value == EvalTimesEnum.Once)
     {
         return(this);
     }
     else if (other.Value == EvalTimesEnum.Any || Value == EvalTimesEnum.Once)
     {
         changed.Set();
         return(other);
     }
     else
     {
         changed.Set();
         return(Top);
     }
 }
示例#8
0
 public DroppedDomain <T> Lub(DroppedDomain <T> other, BoolRef changed)
 {
     if (IsTop)
     {
         return(Top);
     }
     else if (other.IsTop)
     {
         changed.Set();
         return(Top);
     }
     else
     {
         var value = Value.Lub(other.Value, changed);
         return(value == null ? null : new DroppedDomain <T>(value));
     }
 }
示例#9
0
        public DiscreteDomain <T> Lub(DiscreteDomain <T> other, BoolRef changed)
        {
            switch (Flag)
            {
            case DiscreteEnum.None:
                if (other.Flag == DiscreteEnum.None)
                {
                    return(this);
                }
                else
                {
                    changed.Set();
                    return(other);
                }

            case DiscreteEnum.Specific:
                if (other.Flag == DiscreteEnum.None)
                {
                    return(this);
                }
                else if (other.Flag == DiscreteEnum.Specific)
                {
                    if (Value.Equals(other.Value))
                    {
                        return(this);
                    }
                    else
                    {
                        return(null);
                    }
                }
                else
                {
                    changed.Set();
                    return(other);
                }

            case DiscreteEnum.Any:
                return(this);

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
示例#10
0
 public void UnionInPlace(IntSet other, BoolRef changed)
 {
     k = -1;
     n = Math.Max(n, other.n);
     if (v.Length < other.v.Length)
     {
         var newv = new uint[other.v.Length];
         other.v.CopyTo(newv, 0);
         for (var i = 0; i < v.Length; i++)
         {
             var origv = newv[i];
             newv[i] |= v[i];
             if (newv[i] != origv)
             {
                 changed.Set();
             }
         }
         for (var i = v.Length; i < other.v.Length; i++)
         {
             if (newv[i] != 0u)
             {
                 changed.Set();
             }
         }
         v = newv;
     }
     else
     {
         for (var i = 0; i < other.v.Length; i++)
         {
             var origv = v[i];
             v[i] |= other.v[i];
             if (v[i] != origv)
             {
                 changed.Set();
             }
         }
     }
 }
示例#11
0
        public VectorDomain <T> Lub(VectorDomain <T> other, BoolRef changed)
        {
            if (Elements.Count != other.Elements.Count)
            {
                return(null);
            }
            var res = default(Seq <T>);

            for (var i = 0; i < Elements.Count; i++)
            {
                var thisChanged = new BoolRef();
                var elem        = Elements[i].Lub(other.Elements[i], thisChanged);
                if (elem == null)
                {
                    return(null);
                }
                if (thisChanged.Value && res == null)
                {
                    changed.Set();
                    res = new Seq <T>(Elements.Count);
                    for (var j = 0; j < i; j++)
                    {
                        res.Add(Elements[i]);
                    }
                }
                if (res != null)
                {
                    res[i] = elem;
                }
            }
            if (res == null)
            {
                return(this);
            }
            else
            {
                return(new VectorDomain <T>(res));
            }
        }
示例#12
0
        public void Unify(RootEnvironment rootEnv, StackEntryState other, BoolRef changed)
        {
            var type = Type.Lub(rootEnv, other.Type, changed);

            var upperBound = default(TypeRef);
            if (UpperBound != null && other.UpperBound != null)
                upperBound = UpperBound.Glb(rootEnv, other.UpperBound, changed);
            else if (other.UpperBound != null)
            {
                upperBound = other.UpperBound;
                changed.Set();
            }
            else
                upperBound = UpperBound;

            if (upperBound != null && !type.IsAssignableTo(rootEnv, upperBound))
                throw new InvalidOperationException("stack entries are not unifiable");

            var pointsTo = PointsTo.Lub(other.PointsTo, changed);

            UpperBound = upperBound;
            Type = type;
            PointsTo = pointsTo;
        }
示例#13
0
 public void PropogateBackwards(ArgsLocalsState other, ArgLocal argLocal, int index, bool isAlive, BoolRef changed)
 {
     var newArgsAlive = other.argsAlive.Clone();
     var newLocalsAlive = other.localsAlive.Clone();
     if (index >= 0)
     {
         switch (argLocal)
         {
             case ArgLocal.Arg:
                 newArgsAlive[index] = isAlive;
                 break;
             case ArgLocal.Local:
                 newLocalsAlive[index] = isAlive;
                 break;
             default:
                 throw new ArgumentOutOfRangeException("argLocal");
         }
     }
     argsAlive.UnionInPlace(newArgsAlive, changed);
     localsAlive.UnionInPlace(newLocalsAlive, changed);
 }
示例#14
0
 public void ReadPointer(ArgsLocalsState other, PointsTo pointsTo, BoolRef changed)
 {
     var newArgsAlive = other.argsAlive.Clone();
     foreach (var argIndex in pointsTo.Args.Members)
         newArgsAlive[argIndex] = true;
     argsAlive.UnionInPlace(newArgsAlive, changed);
     var newLocalsAlive = other.localsAlive.Clone();
     foreach (var localIndex in pointsTo.Locals.Members)
         newLocalsAlive[localIndex] = true;
     localsAlive.UnionInPlace(newLocalsAlive, changed);
 }
示例#15
0
        // ----------------------------------------------------------------------
        // Exceptional transitions
        // ----------------------------------------------------------------------

        // Exceptional control flow may take this source machine state to other target machine state.
        // Account for forward and backward propogation of non-stack related state.
        public void SourceToTargetTransition(MachineState other, BoolRef changed)
        {
            innerState.Value.ArgsLocalsState.SourceToTargetTransition(other.innerState.Value.ArgsLocalsState, changed);
        }
示例#16
0
 // This and other must always be the same state. Throw if no lub. Otherwise return true if this state changed.
 public void Unify(MachineState other, BoolRef changed)
 {
     if (RootEnv != other.RootEnv)
         throw new InvalidOperationException("states must share same environment");
     if (nArgs != other.nArgs || nLocals != other.nLocals)
         throw new InvalidOperationException("states must have the same number of arguments and locals");
     innerState.Unify(other.innerState, (l, r, c) => l.Unify(RootEnv, r, c), changed);
 }
示例#17
0
 private void UnifyAfterState(MachineState state, int offset, BoolRef changed)
 {
     var existing = default(MachineState);
     if (offsetToAfterState.TryGetValue(offset, out existing))
         existing.Unify(state, changed);
     else
     {
         offsetToAfterState.Add(offset, state);
         changed.Set();
     }
 }
示例#18
0
 private MachineState ForwardBlock(InstructionContext context, MachineState initState, BoolRef changed)
 {
     if (context.HasBody)
     {
         var state = initState;
         for (var i = 0; i < context.Block.Body.Count; i++)
         {
             var offset = context.Block.Body[i].Offset;
             if (state == null)
             {
                 // Has an earlier instruction transferred control to here?
                 if (!offsetToBeforeState.TryGetValue(offset, out state))
                 {
                     // CLR spec requires that an instruction only reached by back jumps, and the entry of
                     // a try block, has an empty entry stack. We initially assume no pointers are
                     // stored in arguments or locals.
                     state = new MachineState(methEnv, method.ValueParameters.Count, method.Locals.Count);
                     offsetToBeforeState.Add(offset, state);
                     changed.Set();
                 }
             }
             else
                 // Current instruction cannot be a try
                 UnifyBeforeState(state, offset, changed);
             context.Block.Body[i].BeforeState = state; // not necessarialy final
             state = ForwardInstruction(context, i, state, changed);
             if (!context.Block.Body[i].IsStructural)
                 UnifyAfterState(state, offset, changed);
             context.Block.Body[i].AfterState = state; // not necessarialy final
             if (context.Block.Body[i].NeverReturns)
                 state = null;
         }
         if (state != null)
             throw new InvalidOperationException("fell off of end of instructions");
         return context.Block.Body[context.Block.Body.Count - 1].AfterState;
     }
     else
         return initState;
 }
示例#19
0
        // ----------------------------------------------------------------------
        // Backward propogation of args and locals liveness
        // (we clone and mutate the existing args and locals state)
        // ----------------------------------------------------------------------

        // Ensure any argument or local which is alive in nextState is alive in this state. Return true if this state changed.
        public void PropogateBackwards(MachineState nextState, BoolRef changed)
        {
            innerState.Value.ArgsLocalsState.PropogateBackwards(nextState.innerState.Value.ArgsLocalsState, default(ArgLocal), -1, false, changed);
        }
示例#20
0
        // ----------------------------------------------------------------------
        // Entry point
        // ----------------------------------------------------------------------

        public void Infer()
        {
            var instructions = method.Instructions(methEnv.Global);
            var rootContext = new InstructionContext(null, -1, instructions);
            var initState = new MachineState(methEnv, method.ValueParameters.Count, method.Locals.Count);
            var effectiveTransitions = new Set<SourceTarget>();

            AddEffectiveBlockTransitions(effectiveTransitions, rootContext);
            if (tracer != null)
                tracer.Trace
                    ("Effective transitions",
                     w2 =>
                         {
                             foreach (var st in effectiveTransitions)
                             {
                                 st.Append(w2);
                                 w2.EndLine();
                             }
                         });

            var changed = new BoolRef();
            var i = 0;
            do
            {
                changed.Clear();
                ForwardBlock(rootContext, initState, changed);
                BackwardBlock(rootContext, changed);

                foreach (var st in effectiveTransitions)
                {
                    var sourceState = st.Source.BeforeState;
                    var targetState = default(MachineState);
                    if (!offsetToBeforeState.TryGetValue(st.Target, out targetState))
                        throw new InvalidOperationException("no state for target offset");
                    sourceState.SourceToTargetTransition(targetState, changed);
                }

                if (tracer != null)
                {
                    if (changed.Value)
                        tracer.Trace("After machine state inference iteration " + i++, instructions.Append);
                    else
                        tracer.AppendLine("Fixed point after iteration " + i);
                }
            }
            while (changed.Value);
        }
示例#21
0
 public void SourceToTargetTransition(ArgsLocalsState other, BoolRef changed)
 {
     // Any pointers in source are pointers in target
     foreach (var kv in argLocalToPointsTo)
     {
         var pt = default(PointsTo);
         if (!kv.Value.IsBottom)
         {
             if (other.argLocalToPointsTo.TryGetValue(kv.Key, out pt))
                 other.argLocalToPointsTo[kv.Key] = pt.Lub(kv.Value, changed);
             else
             {
                 changed.Set();
                 other.argLocalToPointsTo.Add(kv.Key, kv.Value);
             }
         }
     }
     // Anything alive in target is alive in source
     argsAlive.UnionInPlace(other.argsAlive, changed);
     localsAlive.UnionInPlace(other.localsAlive, changed);
 }
示例#22
0
 public void PeekBoxedType(int n, TypeRef expType, BoolRef changed)
 {
     var type = PeekType(n);
     var s = type.Style(RootEnv);
     if (s is NullTypeStyle)
     {
         // No-op.
         // Will fail at runtime, but still ok.
         // If stack entry is generalized, it must go directly to Object.
     }
     else if (s is ReferenceTypeStyle)
     {
         if (s is ObjectTypeStyle)
             // This stack entry can never be refined away from object
             return;
         if (!(s is BoxTypeStyle))
             // Parameter types not allowed
             throw new InvalidOperationException("stack entry is not object or a boxed type");
         if (expType.Style(RootEnv) is NullableTypeStyle)
             // Account for null -> no-value coercion
             expType = expType.Arguments[0];
         expType = expType.ToRunTimeType(RootEnv,false);
         if (!type.Arguments[0].IsEquivalentTo(RootEnv, expType))
             throw new InvalidOperationException("boxed element type is not equivalent to expected type");
         // Box types are NOT invariant, so need to impose upper bound
         SetUpperBound(n, RootEnv.Global.BoxTypeConstructorRef.ApplyTo(expType), changed);
     }
     else
         // Parameter types not allowed
         throw new InvalidOperationException("stack entry is not object or a boxed type");
 }
示例#23
0
 public TypeRef PeekExpectedType(int n, TypeRef expType, BoolRef changed)
 {
     SetUpperBound(n, expType, changed);
     return innerState.Value.Stack[n].Type;
 }
示例#24
0
        // ----------------------------------------------------------------------
        // Stack type constraints
        // ----------------------------------------------------------------------

        private void SetUpperBound(int n, TypeRef type, BoolRef changed)
        {
            if (n >= Depth)
                throw new InvalidOperationException("stack is too shallow");
            innerState.Value.Stack[n].SetUpperBound(RootEnv, type.ToRunTimeType(RootEnv,true), changed);
        }
示例#25
0
 public void Unify(ArgsLocalsState other, BoolRef changed)
 {
     foreach (var kv in other.argLocalToPointsTo)
     {
         var pt = default(PointsTo);
         if (!kv.Value.IsBottom)
         {
             if (argLocalToPointsTo.TryGetValue(kv.Key, out pt))
                 argLocalToPointsTo[kv.Key] = pt.Lub(kv.Value, changed);
             else
             {
                 changed.Set();
                 argLocalToPointsTo.Add(kv.Key, kv.Value);
             }
         }
     }
     argsAlive.UnionInPlace(other.argsAlive, changed);
     localsAlive.UnionInPlace(other.localsAlive, changed);
 }
示例#26
0
        // ----------------------------------------------------------------------
        // Back propogation
        // ----------------------------------------------------------------------

        // Refine given before machine state account for backwards flow from after machine state.
        // Only propogates liveness, thus we only need to look for read/writes of arguments and locals,
        // either directly (via ldarg/starg/ldloc/stloc) or indirectly (via ldind/ldobj/cpobj).
        public void BackwardInstruction(InstructionContext context, int index, MachineState beforeState, MachineState afterState, BoolRef changed)
        {
            var instruction = context.Block.Body[index];
            switch (instruction.Flavor)
            {
            case InstructionFlavor.Misc:
                {
                    var misci = (MiscInstruction)instruction;
                    switch (misci.Op)
                    {
                    case MiscOp.LdindRef:
                        beforeState.ReadPointer(afterState, beforeState.PeekPointsTo(0), changed);
                        return;
                    case MiscOp.StindRef:
                        // May have overwritten an arg or local, but don't know exactly which one, so must
                        // be conservative and leave everything alive
                        break;
                    case MiscOp.Nop:
                    case MiscOp.Break:
                    case MiscOp.Dup:
                    case MiscOp.Pop:
                    case MiscOp.Ldnull:
                    case MiscOp.Ckfinite:
                    case MiscOp.Throw:
                    case MiscOp.Rethrow:
                    case MiscOp.LdelemRef:
                    case MiscOp.StelemRef:
                    case MiscOp.Ldlen:
                    case MiscOp.Ret:
                    case MiscOp.RetVal:
                    case MiscOp.Endfilter:
                    case MiscOp.Endfinally:
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    break;
                }
            case InstructionFlavor.ArgLocal:
                {
                    var sli = (ArgLocalInstruction)instruction;
                    switch (sli.Op)
                    {
                    case ArgLocalOp.Ld:
                        beforeState.ReadArgLocal(afterState, sli.ArgLocal, sli.Index, changed);
                        return;
                    case ArgLocalOp.Lda:
                        // Assume pointer we are creating is read from, and to be conservative don't
                        // assume it is written to.
                        beforeState.ReadArgLocal(afterState, sli.ArgLocal, sli.Index, changed);   
                        break;
                    case ArgLocalOp.St:
                        beforeState.WriteArgLocal(afterState, sli.ArgLocal, sli.Index, changed);
                        return;
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    break;
                }
            case InstructionFlavor.Type:
                {
                    var typei = (TypeInstruction)instruction;
                    switch (typei.Op)
                    {
                    case TypeOp.Ldobj:
                        beforeState.ReadPointer(afterState, beforeState.PeekPointsTo(0), changed);
                        return;
                    case TypeOp.Stobj:
                        // As above, can't be sure which args or locals will be written to
                        break;
                    case TypeOp.Cpobj:
                        // As above, can't be sure which args or locals will be written to
                        // But can handle read safely
                        beforeState.ReadPointer(afterState, beforeState.PeekPointsTo(0), changed);
                        return;
                    case TypeOp.Newarr:
                    case TypeOp.Initobj:
                    case TypeOp.Castclass:
                    case TypeOp.Isinst:
                    case TypeOp.Box:
                    case TypeOp.Unbox:
                    case TypeOp.UnboxAny:
                    case TypeOp.Ldtoken:
                    case TypeOp.Ldelem:
                    case TypeOp.Stelem:
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    break;
                }
            case InstructionFlavor.Try:
                {
                    var tryi = (TryInstruction)instruction;
                    var tryContext = new TryBodyInstructionContext(context, index, tryi.Body);
                    BackwardBlock(tryContext, changed);
                    for (var j = 0; j < tryi.Handlers.Count; j++)
                    {
                        var h = tryi.Handlers[j];
                        var handlerContext = new TryHandlerInstructionContext(context, index, h.Body, j);
                        BackwardBlock(handlerContext, changed);
                    }
                    return;
                }
            case InstructionFlavor.Method:
                {
                    var methi = (MethodInstruction)instruction;
                    switch (methi.Op)
                    {
                    case MethodOp.Call:
                    case MethodOp.Newobj:
                        {
                            // Assume any pointers passed to call are read from
                            var sig = (CST.MethodSignature)methi.Method.ExternalSignature;
                            var skippedArgs = (methi.Op == MethodOp.Newobj ? 1 : 0);
                            var passedArgs = sig.Parameters.Count - skippedArgs;
                            for (var i = passedArgs - 1; i >= 0; i--)
                            {
                                if (sig.Parameters[skippedArgs + i].Style(methEnv) is CST.ManagedPointerTypeStyle)
                                    beforeState.ReadPointer
                                        (afterState, beforeState.PeekPointsTo(passedArgs - 1 - i), changed);
                            }
                            // Also assume call does not write to any pointers, thus everything remains
                            // alive across call. Ie just fallthough.
                            break;
                        }
                    case MethodOp.Ldftn:
                    case MethodOp.Ldtoken:
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    break;
                }
            case InstructionFlavor.Unsupported:
            case InstructionFlavor.Field:
            case InstructionFlavor.Branch:
            case InstructionFlavor.Switch:
            case InstructionFlavor.Compare:
            case InstructionFlavor.LdElemAddr:
            case InstructionFlavor.LdInt32:
            case InstructionFlavor.LdInt64:
            case InstructionFlavor.LdSingle:
            case InstructionFlavor.LdDouble:
            case InstructionFlavor.LdString:
            case InstructionFlavor.Arith:
            case InstructionFlavor.Conv:
            case InstructionFlavor.IfThenElsePseudo:
            case InstructionFlavor.ShortCircuitingPseudo:
            case InstructionFlavor.StructuralSwitchPseudo:
            case InstructionFlavor.LoopPseudo:
            case InstructionFlavor.WhileDoPseudo:
            case InstructionFlavor.DoWhilePseudo:
            case InstructionFlavor.LoopControlPseudo:
                break;
            default:
                throw new ArgumentOutOfRangeException();
            }
            // By default, anything alive in after state must be alive in before state.
            beforeState.PropogateBackwards(afterState, changed);
        }
示例#27
0
 public void ReadArgLocal(MachineState nextState, ArgLocal argLocal, int index, BoolRef changed)
 {
     innerState.Value.ArgsLocalsState.PropogateBackwards(nextState.innerState.Value.ArgsLocalsState, argLocal, index, true, changed);
 }
示例#28
0
        // ----------------------------------------------------------------------
        // Forward propogation
        // ----------------------------------------------------------------------

        // Return machine state after performing given instruction on entry machine state.
        // Propogates stack shapes and args/locals points-to
        private MachineState ForwardInstruction(InstructionContext context, int index, MachineState state, BoolRef changed)
        {
            var instruction = context.Block.Body[index];
            switch (instruction.Flavor)
            {
            case InstructionFlavor.Unsupported:
                throw new InvalidOperationException("unsupported opcode");
            case InstructionFlavor.Misc:
                {
                    var misci = (MiscInstruction)instruction;
                    switch (misci.Op)
                    {
                    case MiscOp.Nop:
                    case MiscOp.Break:
                        return state;
                    case MiscOp.Dup:
                        return state.Push(state.Peek(0));
                    case MiscOp.Pop:
                        return state.Pop(1);
                    case MiscOp.Ldnull:
                        return state.PushType(global.NullRef, BottomPT);
                    case MiscOp.Ckfinite:
                        state.PeekExpectedType(0, global.DoubleRef, changed);
                        // Assume the instruction can "peek" at top of stack, thus no need for pop/push.
                        return state;
                    case MiscOp.Throw:
                        state.PeekReferenceType(0);
                        return state.DiscardStack();
                    case MiscOp.Rethrow:
                        return state.DiscardStack();
                    case MiscOp.LdindRef:
                        {
                            var elemType = state.PeekPointerToReferenceType(0);
                            return state.PopPushType(1, elemType, BottomPT);
                        }
                    case MiscOp.StindRef:
                        {
                            var expElemType = state.PeekPointerToReferenceType(1);
                            state.PeekExpectedType(0, expElemType, changed);
                            return state.Pop(2);
                        }
                    case MiscOp.LdelemRef:
                        {
                            state.PeekIndexType(0);
                            // WARNING: Type may not be final
                            var elemType = state.PeekArrayOfReferenceType(1);
                            return state.PopPushType(2, elemType, BottomPT);
                        }
                    case MiscOp.StelemRef:
                        state.PeekReferenceType(0);
                        state.PeekIndexType(1);
                        state.PeekArrayOfReferenceType(2);
                        // Since the value type and array element type may be independently generalized,
                        // it is pointless to check that the first is assignable to the second.
                        // Instead this check is done at runtime.
                        return state.Pop(3);
                    case MiscOp.Ldlen:
                        state.PeekArrayOfAnyType(0);
                        return state.PopPushType(1, global.IntNativeRef, BottomPT);
                    case MiscOp.Ret:
                        {
                            if (state.Depth != 0)
                                throw new InvalidOperationException("stack should be empty");
                            return state; // empty
                        }
                    case MiscOp.RetVal:
                        {
                            state.PeekExpectedType(0, method.Result.Type, changed);
                            var newState = state.Pop(1);
                            if (newState.Depth != 0)
                                throw new InvalidOperationException("stack should be empty");
                            return newState; // empty
                        }
                    case MiscOp.Endfilter:
                        {
                            state.PeekExpectedType(0, global.Int32Ref, changed);
                            var newState = state.Pop(1);
                            if (newState.Depth != 0)
                                throw new InvalidOperationException("stack should be empty");
                            return newState; // empty
                        }
                    case MiscOp.Endfinally:
                        {
                            // Control could transfer to an outer finally/fault block, or to the target
                            // of a leave instruction. However these transitions are delt with separately.
                            return state.DiscardStack();
                        }
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            case InstructionFlavor.Branch:
                {
                    var bri = (BranchInstruction)instruction;
                    switch (bri.Op)
                    {
                    case BranchOp.Br:
                        UnifyBeforeState(state, bri.Target, changed);
                        return state;
                    case BranchOp.Brtrue:
                        {
                            // WARNING: Type may not be final
                            // NOTE: May capture skolemized types
                            bri.Type = state.PeekIntegerOrObjectOrPointerType(0, false);
                            var newState = state.Pop(1);
                            UnifyBeforeState(newState, bri.Target, changed);
                            return newState;
                        }
                    case BranchOp.Brfalse:
                        {
                            // WARNING: Type may not be final
                            // NOTE: May capture skolemized types
                            bri.Type = state.PeekIntegerOrObjectOrPointerType(0, true);
                            var newState = state.Pop(1);
                            UnifyBeforeState(newState, bri.Target, changed);
                            return newState;
                        }
                    case BranchOp.Breq:
                    case BranchOp.Brne:
                        {
                            // WARNING: Type may not be final
                            // NOTE: May capture skolemized types
                            bri.Type = state.Peek2ComparableTypes(0, true);
                            var newState = state.Pop(2);
                            UnifyBeforeState(newState, bri.Target, changed);
                            return newState;
                        }
                    case BranchOp.Leave:
                        {
                            // Control could transfer via finally blocks instead of directly to the leave target.
                            // Propogate only that the stack must be empty at target. Remaining machine state
                            // is dealt with separately.
                            UnifyBeforeState
                                (new MachineState(methEnv, method.ValueParameters.Count, method.Locals.Count),
                                 bri.Target,
                                 changed);
                            return state.DiscardStack();
                        }
                    case BranchOp.BrLt:
                    case BranchOp.BrLe:
                    case BranchOp.BrGt:
                    case BranchOp.BrGe:
                        {
                            // WARNING: Type may not be final
                            // NOTE: May capture skolemized types
                            bri.Type = state.Peek2ComparableTypes(0, false);
                            var newState = state.Pop(2);
                            UnifyBeforeState(newState, bri.Target, changed);
                            return newState;
                        }
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            case InstructionFlavor.Switch:
                {
                    var switchi = (SwitchInstruction)instruction;
                    state.PeekExpectedType(0, global.Int32Ref, changed);
                    var newState = state.Pop(1);
                    for (var i = 0; i < switchi.CaseTargets.Count; i++)
                        UnifyBeforeState(newState, switchi.CaseTargets[i], changed);
                    return newState;
                }
            case InstructionFlavor.Compare:
                {
                    var cmpi = (CompareInstruction)instruction;
                    // WARNING: Capured type may not be final
                    // NOTE: May capture skolemized types
                    switch (cmpi.Op)
                    {
                    case CompareOp.Ceq:
                    case CompareOp.CnePseudo:
                        cmpi.Type = state.Peek2ComparableTypes(0, true);
                        return state.PopPushType(2, global.Int32Ref, BottomPT);
                    case CompareOp.Clt:
                    case CompareOp.Cgt:
                    case CompareOp.CgePseudo:
                    case CompareOp.ClePseudo:
                        cmpi.Type = state.Peek2ComparableTypes(0, false);
                        return state.PopPushType(2, global.Int32Ref, BottomPT);
                    case CompareOp.CtruePseudo:
                    case CompareOp.CfalsePseudo:
                        cmpi.Type = state.PeekIntegerOrObjectOrPointerType(0, true);
                        return state.PopPushType(1, global.Int32Ref, BottomPT);
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            case InstructionFlavor.ArgLocal:
                {
                    var argi = (ArgLocalInstruction)instruction;
                    var type = method.ArgLocalType(argi.ArgLocal, argi.Index);
                    switch (argi.Op)
                    {
                    case ArgLocalOp.Ld:
                        return state.PushType(type, state.ArgLocalPointsTo(argi.ArgLocal, argi.Index));
                    case ArgLocalOp.Lda:
                        return state.PushType(methEnv.Global.ManagedPointerTypeConstructorRef.ApplyTo(type), ArgLocalPT(argi.ArgLocal, argi.Index));
                    case ArgLocalOp.St:
                        {
                            state.PeekExpectedType(0, type, changed);
                            var pointsTo = state.PeekPointsTo(0);
                            if (!pointsTo.IsBottom)
                            {
                                if (!(type.Style(methEnv) is ManagedPointerTypeStyle))
                                    throw new InvalidOperationException
                                        ("stack indicates pointer, but parameter or local type does not");
                                if (pointsTo.PointsOutsideOfHeap)
                                    throw new InvalidOperationException("arguments cannot point outside of the heap");
                            }
                            return state.PopAddArgLocalPointsTo(1, argi.ArgLocal, argi.Index, pointsTo);
                        }
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            case InstructionFlavor.Field:
                {
                    var fieldi = (FieldInstruction)instruction;
                    var fieldEnv = fieldi.Field.Enter(methEnv);
                    var fieldType = fieldEnv.SubstituteType(fieldEnv.Field.FieldType);
                    switch (fieldi.Op)
                    {
                    case FieldOp.Ldfld:
                        if (fieldi.IsStatic)
                            return state.PushType(fieldType, BottomPT);
                        else
                        {
                            fieldi.IsViaPointer = state.PeekDereferencableExpectedType
                                (0, fieldi.Field.DefiningType, true, changed);
                            return state.PopPushType(1, fieldType, BottomPT);
                        }
                    case FieldOp.Ldflda:
                        if (fieldi.IsStatic)
                            return state.PushType(methEnv.Global.ManagedPointerTypeConstructorRef.ApplyTo(fieldType), HeapPT);
                        else
                        {
                            // Underlying type cannot be a struct, otherwise would have a pointer into
                            // the stack
                            fieldi.IsViaPointer = state.PeekDereferencableExpectedType
                                (0, fieldi.Field.DefiningType, false, changed);
                            return state.PopPushType
                                (1, methEnv.Global.ManagedPointerTypeConstructorRef.ApplyTo(fieldType), HeapPT);
                        }
                    case FieldOp.Stfld:
                        if (fieldi.IsStatic)
                        {
                            state.PeekExpectedType(0, fieldType, changed);
                            return state.Pop(1);
                        }
                        else
                        {
                            state.PeekExpectedType(0, fieldType, changed);
                            fieldi.IsViaPointer = state.PeekDereferencableExpectedType
                                (1, fieldi.Field.DefiningType, false, changed);
                            return state.Pop(2);
                        }
                    case FieldOp.Ldtoken:
                        return state.PushType(global.RuntimeFieldHandleRef, BottomPT);
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            case InstructionFlavor.Method:
                {
                    var methi = (MethodInstruction)instruction;
                    var sig = (CST.MethodSignature)methi.Method.ExternalSignature;
                    switch (methi.Op)
                    {
                    case MethodOp.Call:
                        {
                            for (var i = sig.Parameters.Count - 1; i >= 1; i--)
                                state.PeekExpectedType(sig.Parameters.Count - 1 - i, sig.Parameters[i], changed);
                            if (methi.Constrained != null)
                            {
                                if (!methi.IsVirtual || methi.Method.IsStatic)
                                    throw new InvalidOperationException
                                        ("constrained only valid on virtual calls to instance methods");
                                var thisType = sig.Parameters[0];
                                var constrainedPtr = methEnv.Global.ManagedPointerTypeConstructorRef.ApplyTo(methi.Constrained);
                                var constrainedBox = methEnv.Global.BoxTypeConstructorRef.ApplyTo(methi.Constrained);
                                var cs = methi.Constrained.Style(methEnv);
                                if (cs is ValueTypeStyle)
                                {
                                    if (thisType.Style(methEnv) is ManagedPointerTypeStyle)
                                    {
                                        // We pass the argument pointer as is
                                        if (!methi.Constrained.IsAssignableTo(methEnv, thisType.Arguments[0]))
                                            throw new InvalidOperationException
                                                ("constrained type is not assignable to method's first argument type");
                                    }
                                    else
                                    {
                                        // *Case 1* Morally we deref the argument pointer and box the contents,
                                        // but since no supertype of a value type may mutate the underlying value,
                                        // we don't need to take a copy of the value when boxing, so in practice
                                        // this is a no-op
                                        if (!constrainedBox.IsAssignableTo(methEnv, thisType))
                                            throw new InvalidOperationException
                                                ("constrained type is not assignable to method's first argument type");
                                    }
                                }
                                else if (cs is ReferenceTypeStyle)
                                {
                                    // *Case 2* We dereference the pointer and pass the object reference
                                    if (!methi.Constrained.IsAssignableTo(methEnv, thisType))
                                        throw new InvalidOperationException
                                            ("constrained type is not assignable to method's first argument type");
                                }
                                else if (cs is ParameterTypeStyle)
                                {
                                    // Since we are calling an instance method, we know the first argument cannot be
                                    // a "naked" type parameter, but is either a class or an interface.
                                    // We must decide between cases 1 and 2 above at runtime, but checking as
                                    // per case 1 is sufficient now.
                                    // NOTE: As for box/classcast/isinst below, if the parameter is
                                    // instantiated to a reference type then the type box type is considered
                                    // equivalent to the underyling reference type.
                                    if (!constrainedBox.IsAssignableTo(methEnv, thisType))
                                        throw new InvalidOperationException
                                            ("constrained type is not assignable to method's first argument type");
                                }
                                else
                                    throw new InvalidOperationException
                                        ("constrained must be value, reference or parameter type");

                                state.PeekExpectedType(sig.Parameters.Count - 1, constrainedPtr, changed);
                            }
                            else if (sig.Parameters.Count > 0)
                                state.PeekExpectedType(sig.Parameters.Count - 1, sig.Parameters[0], changed);
                            if (sig.Result == null)
                                return state.Pop(sig.Parameters.Count);
                            else
                                return state.PopPushType(sig.Parameters.Count, sig.Result, BottomPT);
                        }
                    case MethodOp.Ldftn:
                        {
                            // NOTE: Verified CLR allows only the two "blessed" sequences:
                            //   dup; ldvirtftn; newobj <delegate ctor>
                            //   ldftn; newobj <delegate ctor>
                            // It is thus possible to check the delegate will capture an instance which
                            // implements the loaded method. However, we don't check that here.
                            if (methi.IsVirtual)
                            {
                                if (methi.Method.IsStatic)
                                    throw new InvalidOperationException("cannot ldvirtftn of a static method");
                                var objectType = default(TypeRef);
                                if (sig.Parameters[0].Style(methEnv) is ManagedPointerTypeStyle)
                                    // Object should be a box
                                    objectType = methEnv.Global.BoxTypeConstructorRef.ApplyTo(sig.Parameters[0].Arguments[0]);
                                else
                                    // Object should match parameter
                                    objectType = sig.Parameters[0];
                                state.PeekExpectedType(0, objectType, changed);
                                return state.PopPushType(1, sig.WithoutThis().ToCodePointer(methEnv.Global), BottomPT);
                            }
                            else
                            {
                                if (methi.Method.IsStatic)
                                    return state.PushType(sig.ToCodePointer(methEnv.Global), BottomPT);
                                else
                                    return state.PushType(sig.WithoutThis().ToCodePointer(methEnv.Global), BottomPT);
                            }
                        }
                    case MethodOp.Newobj:
                        {
                            if (methi.Method.IsStatic || sig.Result != null)
                                throw new InvalidOperationException("not a constructor");
                            for (var i = sig.Parameters.Count - 1; i >= 1; i--)
                                state.PeekExpectedType(sig.Parameters.Count - 1 - i, sig.Parameters[i], changed);
                            // First argument to constructor is created by runtime. If definining type is
                            // a value type, first argument will be a pointer, but result left on stack
                            // will be the value itself.
                            return state.PopPushType(sig.Parameters.Count - 1, methi.Method.DefiningType, BottomPT);
                        }
                    case MethodOp.Ldtoken:
                        return state.PushType(global.RuntimeMethodHandleRef, BottomPT);
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            case InstructionFlavor.Type:
                {
                    var typei = (TypeInstruction)instruction;
                    switch (typei.Op)
                    {
                    case TypeOp.Ldobj:
                        state.PeekReadPointerType(0, typei.Type);
                        return state.PopPushType(1, typei.Type, BottomPT);
                    case TypeOp.Stobj:
                        state.PeekExpectedType(0, typei.Type, changed);
                        state.PeekWritePointerType(1, typei.Type);
                        return state.Pop(2);
                    case TypeOp.Cpobj:
                        state.PeekReadPointerType(0, typei.Type);
                        state.PeekWritePointerType(1, typei.Type);
                        return state.Pop(2);
                    case TypeOp.Newarr:
                        state.PeekIndexType(0);
                        return state.PopPushType(1, methEnv.Global.ArrayTypeConstructorRef.ApplyTo(typei.Type), BottomPT);
                    case TypeOp.Initobj:
                        state.PeekWritePointerType(0, typei.Type);
                        return state.Pop(1);
                    case TypeOp.Castclass:
                    case TypeOp.Isinst:
                    case TypeOp.Box:
                        {
                            var resultType = default(TypeRef);
                            var s = typei.Type.Style(methEnv);
                            if (s is NullableTypeStyle)
                                resultType = methEnv.Global.BoxTypeConstructorRef.ApplyTo(typei.Type.Arguments[0]);
                            else if (s is ValueTypeStyle)
                                resultType = methEnv.Global.BoxTypeConstructorRef.ApplyTo(typei.Type);
                            else if (s is ReferenceTypeStyle)
                                resultType = typei.Type;
                            else if (s is ParameterTypeStyle)
                                // NOTE: As for constrained call above, if type parameter is instantitated to
                                // a ref type, then this box type is considered equivalent to the
                                // underlying reference type.
                                resultType = methEnv.Global.BoxTypeConstructorRef.ApplyTo(typei.Type);
                            else
                                throw new InvalidOperationException
                                    ("can only box/cast to reference, value or parameter type");
                            if (typei.Op == TypeOp.Box)
                                state.PeekExpectedType(0, typei.Type, changed);
                            else
                                state.PeekReferenceType(0);
                            return state.PopPushType(1, resultType, BottomPT);
                        }
                    case TypeOp.Unbox:
                        if (!(typei.Type.Style(methEnv) is ValueTypeStyle))
                            // Parameter types are not allowed
                            throw new InvalidOperationException("type must be a value type");
                        state.PeekBoxedType(0, typei.Type, changed);
                        return state.PopPushType(1, methEnv.Global.ManagedPointerTypeConstructorRef.ApplyTo(typei.Type), HeapPT);
                    case TypeOp.UnboxAny:
                        {
                            var s = typei.Type.Style(methEnv);
                            if (s is ValueTypeStyle)
                                state.PeekBoxedType(0, typei.Type, changed);
                            else if (!(s is ReferenceTypeStyle) && !(s is ParameterTypeStyle))
                                throw new InvalidOperationException("type must be value, reference or parameter type");
                            return state.PopPushType(1, typei.Type, BottomPT);
                        }
                    case TypeOp.Ldtoken:
                        return state.PushType(global.RuntimeTypeHandleRef, BottomPT);
                    case TypeOp.Ldelem:
                        state.PeekIndexType(0);
                        state.PeekReadArrayType(1, typei.Type, false);
                        return state.PopPushType(2, typei.Type, BottomPT);
                    case TypeOp.Stelem:
                        state.PeekExpectedType(0, typei.Type, changed);
                        state.PeekIndexType(1);
                        state.PeekWriteArrayType(2, typei.Type);
                        return state.Pop(3);
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            case InstructionFlavor.LdElemAddr:
                {
                    var ldelemai = (LdElemAddrInstruction)instruction;
                    state.PeekIndexType(0);
                    // WARNING: May prematurely fail for non-readonly loads
                    state.PeekReadArrayType(1, ldelemai.Type, !ldelemai.IsReadonly);
                    return state.PopPushType(2, methEnv.Global.ManagedPointerTypeConstructorRef.ApplyTo(ldelemai.Type), HeapPT);
                }
            case InstructionFlavor.LdInt32:
                return state.PushType(global.Int32Ref, BottomPT);
            case InstructionFlavor.LdInt64:
                return state.PushType(global.Int64Ref, BottomPT);
            case InstructionFlavor.LdSingle:
                return state.PushType(global.DoubleRef, BottomPT);
            case InstructionFlavor.LdDouble:
                return state.PushType(global.DoubleRef, BottomPT);
            case InstructionFlavor.LdString:
                return state.PushType(global.StringRef, BottomPT);
            case InstructionFlavor.Arith:
                {
                    var arithi = (ArithInstruction)instruction;
                    switch (arithi.Op)
                    {
                    case ArithOp.Add:
                    case ArithOp.Sub:
                    case ArithOp.Mul:
                    case ArithOp.Div:
                    case ArithOp.Rem:
                        // NOTE: May capture skolemized types
                        arithi.Type = state.Peek2NumberTypes(0, true);
                        return state.PopPushType(2, arithi.Type, BottomPT);
                    case ArithOp.Neg:
                        // NOTE: May capture skolemized types
                        arithi.Type = state.PeekNumberType(0, true);
                        // Changing underlying value, so pop/push explicitly
                        return state.PopPushType(1, arithi.Type, BottomPT);
                    case ArithOp.BitAnd:
                    case ArithOp.BitOr:
                    case ArithOp.BitXor:
                        // NOTE: May capture skolemized types
                        arithi.Type = state.Peek2NumberTypes(0, false);
                        return state.PopPushType(2, arithi.Type, BottomPT);
                    case ArithOp.BitNot:
                        // NOTE: May capture skolemized types
                        arithi.Type = state.PeekNumberType(0, false);
                        // Changing underlying value, so pop/push explicitly
                        return state.PopPushType(1, arithi.Type, BottomPT);
                    case ArithOp.Shl:
                    case ArithOp.Shr:
                        state.PeekExpectedType(0, global.Int32Ref, changed);
                        // NOTE: May capture skolemized types
                        arithi.Type = state.PeekNumberType(1, false);
                        // Changing underlying value, so pop/push explicitly
                        return state.PopPushType(2, arithi.Type, BottomPT);
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            case InstructionFlavor.Conv:
                {
                    var convi = (ConvInstruction)instruction;
                    var mustBeInteger = (!convi.WithOverflow && convi.IsSourceUnsigned &&
                                         convi.TargetNumberFlavor == NumberFlavor.Double);
                    // NOTE: May capture skolemized types
                    convi.SourceType = state.PeekNumberType(0, !mustBeInteger);
                    return state.PopPushType(1, TypeRef.NumberFrom(methEnv.Global, convi.TargetNumberFlavor), BottomPT);
                }
            case InstructionFlavor.Try:
                {
                    var tryi = (TryInstruction)instruction;
                    // Isolation:
                    //  - There is no way for the current stack shape to influence or be influenced by
                    //    inference of the try, since the current stack shape must be empty.
                    //  - There is no way for the try to influence the result stack shape, since it must be
                    //    empty.
                    //  - However pointers in arguments and locals may propogate into and out of try body
                    //    via exceptional transitions. The latter are delt with separately.
                    if (state.Depth != 0)
                        throw new InvalidOperationException("stack should be empty");
                    var newState = ForwardBlock
                        (new TryBodyInstructionContext(context, index, tryi.Body), state, changed);
                    for (var j = 0; j < tryi.Handlers.Count; j++)
                    {
                        var h = tryi.Handlers[j];
                        var handlerContext = new TryHandlerInstructionContext(context, index, h.Body, j);
                        var initHandlerState = new MachineState
                            (methEnv, method.ValueParameters.Count, method.Locals.Count);
                        switch (h.Flavor)
                        {
                        case HandlerFlavor.Catch:
                            {
                                var catchh = (CatchTryInstructionHandler)h;
                                ForwardBlock(handlerContext, initHandlerState.PushType(catchh.Type, BottomPT), changed);
                                break;
                            }
                        case HandlerFlavor.Filter:
                            throw new NotSupportedException("filter handler blocks");
                        case HandlerFlavor.Fault:
                        case HandlerFlavor.Finally:
                            ForwardBlock(handlerContext, initHandlerState, changed);
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }
                    return newState;
                }
            case InstructionFlavor.IfThenElsePseudo:
            case InstructionFlavor.ShortCircuitingPseudo:
            case InstructionFlavor.StructuralSwitchPseudo:
            case InstructionFlavor.LoopPseudo:
            case InstructionFlavor.WhileDoPseudo:
            case InstructionFlavor.DoWhilePseudo:
            case InstructionFlavor.LoopControlPseudo:
                throw new InvalidOperationException("no machine state inference for psuedo-instructions");
            default:
                throw new ArgumentOutOfRangeException();
            }
        }
示例#29
0
 public void ReadPointer(MachineState nextState, PointsTo pointsTo, BoolRef changed)
 {
     innerState.Value.ArgsLocalsState.ReadPointer(nextState.innerState.Value.ArgsLocalsState, pointsTo, changed);
 }
示例#30
0
 public void SetUpperBound(RootEnvironment rootEnv, TypeRef type, BoolRef changed)
 {
     var s = type.Style(rootEnv);
     if (s is ValueTypeStyle || s is PointerTypeStyle || s is CodePointerTypeStyle)
     {
         // These types are only assignable to themselves, so no need to remember
         // the upper bound, just check it
         if (!Type.IsAssignableTo(rootEnv, type))
         {
             if (s is UnmanagedPointerTypeStyle)
                 throw new InvalidOperationException("unmanaged pointer");
             else
                 throw new InvalidOperationException("stack entry cannot be generalized");
         }
     }
     else
     {
         var upperBound = UpperBound == null ? type : UpperBound.Glb(rootEnv, type, changed);
         if (!Type.IsAssignableTo(rootEnv, upperBound))
             throw new InvalidOperationException("stack entry cannot be generalized");
         if (!upperBound.IsEquivalentTo(rootEnv, rootEnv.Global.ObjectRef))
         {
             if (UpperBound == null)
                 changed.Set();
             UpperBound = upperBound;
         }
     }
 }
示例#31
0
        public void Unify(RootEnvironment rootEnv, InnerMachineState other, BoolRef changed)
        {
            if (Stack.Count != other.Stack.Count)
                throw new InvalidOperationException("stacks must have the same depth");

            for (var i = 0; i < Stack.Count; i++)
                Stack[i].Unify(rootEnv, other.Stack[i], changed);

            if (Ids != null || other.Ids != null)
                throw new InvalidOperationException("stack slot identifiers cannot be unified");

            ArgsLocalsState.Unify(other.ArgsLocalsState, changed);
        }
示例#32
0
 public bool PeekDereferencableExpectedType(int n, TypeRef expType, bool canBeStruct, BoolRef changed)
 {
     expType = expType.ToRunTimeType(RootEnv,false);
     var type = PeekType(n);
     var s = type.Style(RootEnv);
     if (s is NullTypeStyle)
     {
         // Stack entry will remain a referece type (and thus never a pointer).
         // 'null' can be statically dereferenced if we are expecting a reference type, though
         // of course this will cause a null reference exception at runtime
         if (!(expType.Style(RootEnv) is ReferenceTypeStyle))
             throw new InvalidOperationException("expected type is not a referece type");
         // Stack type cannot be refined above expected reference type
         SetUpperBound(n, expType, changed);
         // Not dereferencing a pointer
         return false;
     }
     else if (s is UnmanagedPointerTypeStyle)
         throw new InvalidOperationException("unmananaged pointer");
     else if (s is ManagedPointerTypeStyle)
     {
         // Stack entry will remain a pointer of this type, so no need to impose upper bound
         if (!type.Arguments[0].IsAssignableTo(RootEnv, expType))
             throw new InvalidOperationException
                 ("managed pointer element type is not assignable to expected type");
         // Dereferencing a pointer
         return true;
     }
     else
     {
         // If stack entry is a value type it will remain a value type, so test is stable under generalization
         if (!canBeStruct && s is ValueTypeStyle)
             throw new InvalidOperationException
                 ("stack entry is a value type, but value types cannot be the target of field pointers");
         // Values and objects can be dereferenced if they are compatible with expected type
         // Parameter types are not allowed
         if (!(s is ReferenceTypeStyle) && !(s is ValueTypeStyle))
             throw new InvalidOperationException("stack entry is not a value or reference type");
         // Stack type cannot be refined above expected type
         SetUpperBound(n, expType, changed);
         // Not dereferencing a pointer
         return false;
     }
 }
示例#33
0
 public void BackwardBlock(InstructionContext context, BoolRef changed)
 {
     for (var i = context.Block.Body.Count - 1; i >= 0; i--)
         BackwardInstruction(context, i, context.Block.Body[i].BeforeState, context.Block.Body[i].AfterState, changed);
 }