2 // StackDepthProvider.cs
5 // Alexander Chebaturkin (chebaturkin@gmail.com)
7 // Copyright (C) 2011 Alexander Chebaturkin
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
32 using Mono.CodeContracts.Static.AST;
33 using Mono.CodeContracts.Static.AST.Visitors;
34 using Mono.CodeContracts.Static.ControlFlow;
35 using Mono.CodeContracts.Static.DataStructures;
36 using Mono.CodeContracts.Static.Providers;
38 namespace Mono.CodeContracts.Static.Analysis.StackAnalysis {
39 class StackDepthProvider<TContext> : IILVisitor<APC, Dummy, Dummy, StackInfo, StackInfo>,
40 IILDecoder<APC, int, int, IStackContextProvider, Dummy>,
41 IStackContextProvider, IStackContext,
44 IStackInfo where TContext : IMethodContextProvider {
45 private readonly IILDecoder<APC, Dummy, Dummy, TContext, Dummy> il_decoder;
46 private int cached_subroutine;
47 private APCMap<int> local_stack_depth_cache;
48 private APCMap<int> stack_depth_mirror_for_end_old;
49 private bool recursion_guard;
51 public StackDepthProvider (IILDecoder<APC, Dummy, Dummy, TContext, Dummy> ilDecoder,
52 IMetaDataProvider metaDataProvider)
54 this.il_decoder = ilDecoder;
55 MetaDataProvider = metaDataProvider;
58 #region Implementation of IILDecoder<APC,Local,Parameter,Method,Field,Type,int,int,IStackContextProvider<Field,Method>,Dummy>
59 public TResult ForwardDecode<TData, TResult, TVisitor> (APC pc, TVisitor visitor, TData data)
60 where TVisitor : IILVisitor<APC, int, int, TData, TResult>
62 if (pc.Index != 0 || pc.SubroutineContext != null || pc.Block != pc.Block.Subroutine.Exit || !pc.Block.Subroutine.IsMethod)
63 return this.il_decoder.ForwardDecode<TData, TResult, StackDecoder<TContext, TData, TResult, TVisitor>> (pc, new StackDecoder<TContext, TData, TResult, TVisitor> (this, visitor), data);
64 if (!pc.Block.Subroutine.HasReturnValue)
65 return visitor.Return (pc, -1, data);
67 int source = GlobalStackDepth (pc) - 1;
68 return visitor.Return (pc, source, data);
71 public bool IsUnreachable (APC pc)
76 public Dummy EdgeData (APC @from, APC to)
82 public IMetaDataProvider MetaDataProvider { get; private set; }
84 private ICFG UnderlyingCFG
86 get { return this.il_decoder.ContextProvider.MethodContext.CFG; }
89 #region IILDecoder<APC,int,int,IStackContextProvider,Dummy> Members
90 public IStackContextProvider ContextProvider
96 #region IStackContextProvider Members
97 public IStackContext StackContext
102 public IMethodContext MethodContext
108 public int GlobalStackDepth (APC pc)
110 int num = LocalStackDepth (pc);
112 if (pc.SubroutineContext == null || !pc.Block.Subroutine.HasContextDependentStackDepth)
115 CFGBlock block = pc.SubroutineContext.Head.From;
116 return num + GlobalStackDepth (APC.ForEnd (block, pc.SubroutineContext.Tail));
119 public int LocalStackDepth (APC pc)
121 return LocalStackMap (pc.Block.Subroutine) [pc];
124 private int OldStartDepth (Subroutine subroutine)
126 Method method = ((IMethodInfo) subroutine).Method;
127 int count = MetaDataProvider.Parameters (method).Count;
128 if (!MetaDataProvider.IsConstructor (method) && !MetaDataProvider.IsStatic (method))
133 private APCMap<int> LocalStackMap (Subroutine subroutine)
135 if (this.local_stack_depth_cache == null || this.cached_subroutine != subroutine.Id) {
136 this.local_stack_depth_cache = GetStackDepthMap (subroutine);
137 this.cached_subroutine = subroutine.Id;
139 return this.local_stack_depth_cache;
142 private APCMap<int> GetStackDepthMap (Subroutine subroutine)
145 var key = new TypedKey ("stackDepthKey");
146 if (!subroutine.TryGetValue (key, out result)) {
147 result = ComputeStackDepthMap (subroutine);
148 subroutine.Add (key, result);
153 private APCMap<int> ComputeStackDepthMap (Subroutine subroutine)
155 var startDepths = new Dictionary<int, StackInfo> (subroutine.BlockCount);
156 APCMap<int> apcMap = this.stack_depth_mirror_for_end_old = new APCMap<int> (subroutine);
158 foreach (CFGBlock block in subroutine.Blocks) {
160 if (!startDepths.TryGetValue (block.Index, out stackInfo))
161 stackInfo = ComputeBlockStartDepth (block);
162 foreach (APC apc in block.APCs ()) {
163 apcMap.Add (apc, stackInfo.Depth);
164 stackInfo = this.il_decoder.ForwardDecode<StackInfo, StackInfo, IILVisitor<APC, Dummy, Dummy, StackInfo, StackInfo>> (apc, this, stackInfo);
166 if (!apcMap.ContainsKey (block.Last))
167 apcMap.Add (block.Last, stackInfo.Depth);
168 foreach (CFGBlock successor in subroutine.SuccessorBlocks (block)) {
169 bool oldRecursionGuard = this.recursion_guard;
170 this.recursion_guard = true;
172 bool isExceptionHandlerEdge;
173 foreach (var info in subroutine.EdgeSubroutinesOuterToInner (block, successor, out isExceptionHandlerEdge, null).AsEnumerable ())
174 stackInfo.Adjust (info.Value.StackDelta);
176 this.recursion_guard = oldRecursionGuard;
178 AddStartDepth (startDepths, successor, stackInfo);
184 private StackInfo ComputeBlockStartDepth (CFGBlock block)
186 if (block.Subroutine.IsCatchFilterHeader (block))
187 return new StackInfo (1, 2);
188 return new StackInfo (0, 4);
191 private void AddStartDepth (Dictionary<int, StackInfo> dict, CFGBlock block, StackInfo stackDepth)
194 if (dict.TryGetValue (block.Index, out stackInfo))
196 dict.Add (block.Index, stackDepth.Clone ());
199 #region Implementation of ICFG
202 get { return UnderlyingCFG.Entry; }
205 APC ICFG.EntryAfterRequires
207 get { return UnderlyingCFG.EntryAfterRequires; }
212 get { return UnderlyingCFG.NormalExit; }
215 APC ICFG.ExceptionExit
217 get { return UnderlyingCFG.ExceptionExit; }
220 Subroutine ICFG.Subroutine
222 get { return UnderlyingCFG.Subroutine; }
225 APC ICFG.Next (APC pc)
228 if (((ICFG) this).HasSingleSuccessor (pc, out singleSuccessor))
229 return singleSuccessor;
233 bool ICFG.HasSingleSuccessor (APC pc, out APC successor)
235 DecoratorHelper.Push (this);
237 return UnderlyingCFG.HasSingleSuccessor (pc, out successor);
239 DecoratorHelper.Pop ();
243 bool ICFG.HasSinglePredecessor (APC pc, out APC predecessor)
245 DecoratorHelper.Push (this);
247 return UnderlyingCFG.HasSinglePredecessor (pc, out predecessor);
249 DecoratorHelper.Pop ();
253 IEnumerable<APC> ICFG.Successors (APC pc)
255 DecoratorHelper.Push (this);
257 return UnderlyingCFG.Successors (pc);
259 DecoratorHelper.Pop ();
263 IEnumerable<APC> ICFG.Predecessors (APC pc)
265 DecoratorHelper.Push (this);
267 return UnderlyingCFG.Predecessors (pc);
269 DecoratorHelper.Pop ();
273 bool ICFG.IsJoinPoint (APC pc)
275 return UnderlyingCFG.IsJoinPoint (pc);
278 bool ICFG.IsSplitPoint (APC pc)
280 return UnderlyingCFG.IsSplitPoint (pc);
283 bool ICFG.IsBlockStart (APC pc)
285 return UnderlyingCFG.IsBlockStart (pc);
288 bool ICFG.IsBlockEnd (APC pc)
290 return UnderlyingCFG.IsBlockEnd (pc);
293 IILDecoder<APC, Dummy, Dummy, IMethodContextProvider, Dummy> ICFG.GetDecoder (IMetaDataProvider metaDataProvider)
295 return UnderlyingCFG.GetDecoder (metaDataProvider);
298 void ICFG.Print (TextWriter tw, ILPrinter<APC> printer, Func<CFGBlock, IEnumerable<Sequence<Edge<CFGBlock, EdgeTag>>>> contextLookup,
299 Sequence<Edge<CFGBlock, EdgeTag>> context)
301 DecoratorHelper.Push (this);
303 UnderlyingCFG.Print (tw, printer, contextLookup, context);
305 DecoratorHelper.Pop ();
309 public bool IsForwardBackEdge (APC @from, APC to)
311 return this.UnderlyingCFG.IsForwardBackEdge (from, to);
314 public APC Post (APC pc)
316 return UnderlyingCFG.Post (pc);
321 #region Implementation of IStackInfo
322 bool IStackInfo.IsCallOnThis (APC pc)
324 if (this.recursion_guard)
326 return LocalStackMap (pc.Block.Subroutine).IsCallOnThis (pc);
330 #region Implementation of IStackContext<Field,Method>
331 public int StackDepth (APC pc)
333 return GlobalStackDepth (pc);
337 #region Implementation of IMethodContext<Field,Method>
338 Method IMethodContext.CurrentMethod
340 get { return this.il_decoder.ContextProvider.MethodContext.CurrentMethod; }
343 ICFG IMethodContext.CFG
348 public IEnumerable<Field> Modifies (Method method)
350 return this.il_decoder.ContextProvider.MethodContext.Modifies (method);
353 public IEnumerable<Method> AffectedGetters (Field field)
355 return this.il_decoder.ContextProvider.MethodContext.AffectedGetters (field);
359 #region Implementation of IExpressionILVisitor<APC,Type,Dummy,Dummy,StackInfo,StackInfo>
360 public StackInfo Binary (APC pc, BinaryOperator op, Dummy dest, Dummy operand1, Dummy operand2, StackInfo data)
362 return data.Pop (2).Push ();
365 public StackInfo Isinst (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
370 public StackInfo LoadNull (APC pc, Dummy dest, StackInfo polarity)
372 return polarity.Push ();
375 public StackInfo LoadConst (APC pc, TypeNode type, object constant, Dummy dest, StackInfo data)
380 public StackInfo Sizeof (APC pc, TypeNode type, Dummy dest, StackInfo data)
385 public StackInfo Unary (APC pc, UnaryOperator op, bool unsigned, Dummy dest, Dummy source, StackInfo data)
387 return data.Pop (1).Push ();
391 #region Implementation of ISyntheticILVisitor<APC,Method,Field,Type,Dummy,Dummy,StackInfo,StackInfo>
392 public StackInfo Entry (APC pc, Method method, StackInfo data)
397 public StackInfo Assume (APC pc, EdgeTag tag, Dummy condition, StackInfo data)
402 public StackInfo Assert (APC pc, EdgeTag tag, Dummy condition, StackInfo data)
407 public StackInfo BeginOld (APC pc, APC matchingEnd, StackInfo data)
409 return new StackInfo (OldStartDepth (pc.Block.Subroutine), 4);
413 public StackInfo EndOld (APC pc, APC matchingBegin, TypeNode type, Dummy dest, Dummy source, StackInfo data)
415 return new StackInfo (this.stack_depth_mirror_for_end_old [matchingBegin] + 1, 4);
418 public StackInfo LoadStack (APC pc, int offset, Dummy dest, Dummy source, bool isOld, StackInfo data)
420 return data.Push (data [offset]);
423 public StackInfo LoadStackAddress (APC pc, int offset, Dummy dest, Dummy source, TypeNode type, bool isOld, StackInfo data)
428 public StackInfo LoadResult (APC pc, TypeNode type, Dummy dest, Dummy source, StackInfo data)
434 #region Implementation of IILVisitor<APC,Local,Parameter,Method,Field,Type,Dummy,Dummy,StackInfo,StackInfo>
435 public StackInfo Arglist (APC pc, Dummy dest, StackInfo data)
440 public StackInfo Branch (APC pc, APC target, bool leavesExceptionBlock, StackInfo data)
445 public StackInfo BranchCond (APC pc, APC target, BranchOperator bop, Dummy value1, Dummy value2, StackInfo data)
450 public StackInfo BranchTrue (APC pc, APC target, Dummy cond, StackInfo data)
455 public StackInfo BranchFalse (APC pc, APC target, Dummy cond, StackInfo data)
460 public StackInfo Break (APC pc, StackInfo data)
465 public StackInfo Call<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, StackInfo data)
466 where TypeList : IIndexable<TypeNode>
467 where ArgList : IIndexable<Dummy>
469 int count = MetaDataProvider.Parameters (method).Count + (extraVarargs == null ? 0 : extraVarargs.Count);
470 if (!MetaDataProvider.IsStatic (method)) {
471 if (data.IsThis (count))
472 this.stack_depth_mirror_for_end_old.AddCallOnThis (pc);
475 data = data.Pop (count);
476 if (MetaDataProvider.IsVoidMethod (method))
481 public StackInfo Calli<TypeList, ArgList> (APC pc, TypeNode returnType, TypeList argTypes, bool instance, Dummy dest, Dummy functionPointer, ArgList args, StackInfo data)
482 where TypeList : IIndexable<TypeNode>
483 where ArgList : IIndexable<Dummy>
488 int slots = count + (argTypes == null ? 0 : argTypes.Count);
490 if (MetaDataProvider.IsVoid (returnType))
495 public StackInfo CheckFinite (APC pc, Dummy dest, Dummy source, StackInfo data)
500 public StackInfo CopyBlock (APC pc, Dummy destAddress, Dummy srcAddress, Dummy len, StackInfo data)
505 public StackInfo EndFilter (APC pc, Dummy decision, StackInfo data)
510 public StackInfo EndFinally (APC pc, StackInfo data)
512 return new StackInfo (0, 0);
515 public StackInfo Jmp (APC pc, Method method, StackInfo data)
517 return new StackInfo (0, 0);
520 public StackInfo LoadArg (APC pc, Parameter argument, bool isOld, Dummy dest, StackInfo data)
522 if (!MetaDataProvider.IsStatic (MetaDataProvider.DeclaringMethod (argument)) && MetaDataProvider.ParameterIndex (argument) == 0)
523 return data.PushThis ();
528 public StackInfo LoadArgAddress (APC pc, Parameter argument, bool isOld, Dummy dest, StackInfo data)
533 public StackInfo LoadLocal (APC pc, Local local, Dummy dest, StackInfo data)
538 public StackInfo LoadLocalAddress (APC pc, Local local, Dummy dest, StackInfo data)
543 public StackInfo Nop (APC pc, StackInfo data)
548 public StackInfo Pop (APC pc, Dummy source, StackInfo data)
553 public StackInfo Return (APC pc, Dummy source, StackInfo data)
558 public StackInfo StoreArg (APC pc, Parameter argument, Dummy source, StackInfo data)
563 public StackInfo StoreLocal (APC pc, Local local, Dummy source, StackInfo data)
568 public StackInfo Switch (APC pc, TypeNode type, IEnumerable<Pair<object, APC>> cases, Dummy value, StackInfo data)
573 public StackInfo Box (APC pc, TypeNode type, Dummy dest, Dummy source, StackInfo data)
575 return data.Pop (1).Push ();
578 public StackInfo ConstrainedCallvirt<TypeList, ArgList> (APC pc, Method method, TypeNode constraint, TypeList extraVarargs, Dummy dest, ArgList args, StackInfo data)
579 where TypeList : IIndexable<TypeNode>
580 where ArgList : IIndexable<Dummy>
582 int paramsCount = MetaDataProvider.Parameters (method).Count + (extraVarargs == null ? 0 : extraVarargs.Count);
583 if (!MetaDataProvider.IsStatic (method)) {
584 if (data.IsThis (paramsCount))
585 this.stack_depth_mirror_for_end_old.AddCallOnThis (pc);
589 data = data.Pop (paramsCount);
590 if (MetaDataProvider.IsVoid (MetaDataProvider.ReturnType (method)))
596 public StackInfo CastClass (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
601 public StackInfo CopyObj (APC pc, TypeNode type, Dummy destPtr, Dummy sourcePtr, StackInfo data)
606 public StackInfo Initobj (APC pc, TypeNode type, Dummy ptr, StackInfo data)
611 public StackInfo LoadElement (APC pc, TypeNode type, Dummy dest, Dummy array, Dummy index, StackInfo data)
613 return data.Pop (2).Push ();
616 public StackInfo LoadField (APC pc, Field field, Dummy dest, Dummy obj, StackInfo data)
618 return data.Pop (1).Push ();
621 public StackInfo LoadFieldAddress (APC pc, Field field, Dummy dest, Dummy obj, StackInfo data)
623 return data.Pop (1).Push ();
626 public StackInfo LoadLength (APC pc, Dummy dest, Dummy array, StackInfo data)
628 return data.Pop (1).Push ();
631 public StackInfo LoadStaticField (APC pc, Field field, Dummy dest, StackInfo data)
636 public StackInfo LoadStaticFieldAddress (APC pc, Field field, Dummy dest, StackInfo data)
641 public StackInfo LoadTypeToken (APC pc, TypeNode type, Dummy dest, StackInfo data)
646 public StackInfo LoadFieldToken (APC pc, Field type, Dummy dest, StackInfo data)
651 public StackInfo LoadMethodToken (APC pc, Method type, Dummy dest, StackInfo data)
656 public StackInfo NewArray<ArgList> (APC pc, TypeNode type, Dummy dest, ArgList lengths, StackInfo data) where ArgList : IIndexable<Dummy>
658 return data.Pop (lengths.Count).Push ();
661 public StackInfo NewObj<ArgList> (APC pc, Method ctor, Dummy dest, ArgList args, StackInfo data) where ArgList : IIndexable<Dummy>
663 int paramsCount = MetaDataProvider.Parameters (ctor).Count;
664 return data.Pop (paramsCount).Push ();
667 public StackInfo MkRefAny (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
672 public StackInfo RefAnyType (APC pc, Dummy dest, Dummy source, StackInfo data)
674 return data.Pop (1).Push ();
677 public StackInfo RefAnyVal (APC pc, TypeNode type, Dummy dest, Dummy source, StackInfo data)
679 return data.Pop (1).Push ();
682 public StackInfo Rethrow (APC pc, StackInfo data)
684 return new StackInfo (0, 0);
687 public StackInfo StoreElement (APC pc, TypeNode type, Dummy array, Dummy index, Dummy value, StackInfo data)
692 public StackInfo StoreField (APC pc, Field field, Dummy obj, Dummy value, StackInfo data)
697 public StackInfo StoreStaticField (APC pc, Field field, Dummy value, StackInfo data)
702 public StackInfo Throw (APC pc, Dummy exception, StackInfo data)
704 return new StackInfo (0, 0);
707 public StackInfo Unbox (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
709 return data.Pop (1).Push ();
712 public StackInfo UnboxAny (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
714 return data.Pop (1).Push ();