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<LispList<Edge<CFGBlock, EdgeTag>>>> contextLookup,
299 LispList<Edge<CFGBlock, EdgeTag>> context)
301 DecoratorHelper.Push (this);
303 UnderlyingCFG.Print (tw, printer, contextLookup, context);
305 DecoratorHelper.Pop ();
310 #region Implementation of IStackInfo
311 bool IStackInfo.IsCallOnThis (APC pc)
313 if (this.recursion_guard)
315 return LocalStackMap (pc.Block.Subroutine).IsCallOnThis (pc);
319 #region Implementation of IStackContext<Field,Method>
320 public int StackDepth (APC pc)
322 return GlobalStackDepth (pc);
326 #region Implementation of IMethodContext<Field,Method>
327 Method IMethodContext.CurrentMethod
329 get { return this.il_decoder.ContextProvider.MethodContext.CurrentMethod; }
332 ICFG IMethodContext.CFG
337 public IEnumerable<Field> Modifies (Method method)
339 return this.il_decoder.ContextProvider.MethodContext.Modifies (method);
342 public IEnumerable<Method> AffectedGetters (Field field)
344 return this.il_decoder.ContextProvider.MethodContext.AffectedGetters (field);
348 #region Implementation of IExpressionILVisitor<APC,Type,Dummy,Dummy,StackInfo,StackInfo>
349 public StackInfo Binary (APC pc, BinaryOperator op, Dummy dest, Dummy operand1, Dummy operand2, StackInfo data)
351 return data.Pop (2).Push ();
354 public StackInfo Isinst (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
359 public StackInfo LoadNull (APC pc, Dummy dest, StackInfo polarity)
361 return polarity.Push ();
364 public StackInfo LoadConst (APC pc, TypeNode type, object constant, Dummy dest, StackInfo data)
369 public StackInfo Sizeof (APC pc, TypeNode type, Dummy dest, StackInfo data)
374 public StackInfo Unary (APC pc, UnaryOperator op, bool unsigned, Dummy dest, Dummy source, StackInfo data)
376 return data.Pop (1).Push ();
380 #region Implementation of ISyntheticILVisitor<APC,Method,Field,Type,Dummy,Dummy,StackInfo,StackInfo>
381 public StackInfo Entry (APC pc, Method method, StackInfo data)
386 public StackInfo Assume (APC pc, EdgeTag tag, Dummy condition, StackInfo data)
391 public StackInfo Assert (APC pc, EdgeTag tag, Dummy condition, StackInfo data)
396 public StackInfo BeginOld (APC pc, APC matchingEnd, StackInfo data)
398 return new StackInfo (OldStartDepth (pc.Block.Subroutine), 4);
402 public StackInfo EndOld (APC pc, APC matchingBegin, TypeNode type, Dummy dest, Dummy source, StackInfo data)
404 return new StackInfo (this.stack_depth_mirror_for_end_old [matchingBegin] + 1, 4);
407 public StackInfo LoadStack (APC pc, int offset, Dummy dest, Dummy source, bool isOld, StackInfo data)
409 return data.Push (data [offset]);
412 public StackInfo LoadStackAddress (APC pc, int offset, Dummy dest, Dummy source, TypeNode type, bool isOld, StackInfo data)
417 public StackInfo LoadResult (APC pc, TypeNode type, Dummy dest, Dummy source, StackInfo data)
423 #region Implementation of IILVisitor<APC,Local,Parameter,Method,Field,Type,Dummy,Dummy,StackInfo,StackInfo>
424 public StackInfo Arglist (APC pc, Dummy dest, StackInfo data)
429 public StackInfo Branch (APC pc, APC target, bool leavesExceptionBlock, StackInfo data)
434 public StackInfo BranchCond (APC pc, APC target, BranchOperator bop, Dummy value1, Dummy value2, StackInfo data)
439 public StackInfo BranchTrue (APC pc, APC target, Dummy cond, StackInfo data)
444 public StackInfo BranchFalse (APC pc, APC target, Dummy cond, StackInfo data)
449 public StackInfo Break (APC pc, StackInfo data)
454 public StackInfo Call<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, Dummy dest, ArgList args, StackInfo data)
455 where TypeList : IIndexable<TypeNode>
456 where ArgList : IIndexable<Dummy>
458 int count = MetaDataProvider.Parameters (method).Count + (extraVarargs == null ? 0 : extraVarargs.Count);
459 if (!MetaDataProvider.IsStatic (method)) {
460 if (data.IsThis (count))
461 this.stack_depth_mirror_for_end_old.AddCallOnThis (pc);
464 data = data.Pop (count);
465 if (MetaDataProvider.IsVoidMethod (method))
470 public StackInfo Calli<TypeList, ArgList> (APC pc, TypeNode returnType, TypeList argTypes, bool instance, Dummy dest, Dummy functionPointer, ArgList args, StackInfo data)
471 where TypeList : IIndexable<TypeNode>
472 where ArgList : IIndexable<Dummy>
477 int slots = count + (argTypes == null ? 0 : argTypes.Count);
479 if (MetaDataProvider.IsVoid (returnType))
484 public StackInfo CheckFinite (APC pc, Dummy dest, Dummy source, StackInfo data)
489 public StackInfo CopyBlock (APC pc, Dummy destAddress, Dummy srcAddress, Dummy len, StackInfo data)
494 public StackInfo EndFilter (APC pc, Dummy decision, StackInfo data)
499 public StackInfo EndFinally (APC pc, StackInfo data)
501 return new StackInfo (0, 0);
504 public StackInfo Jmp (APC pc, Method method, StackInfo data)
506 return new StackInfo (0, 0);
509 public StackInfo LoadArg (APC pc, Parameter argument, bool isOld, Dummy dest, StackInfo data)
511 if (!MetaDataProvider.IsStatic (MetaDataProvider.DeclaringMethod (argument)) && MetaDataProvider.ParameterIndex (argument) == 0)
512 return data.PushThis ();
517 public StackInfo LoadArgAddress (APC pc, Parameter argument, bool isOld, Dummy dest, StackInfo data)
522 public StackInfo LoadLocal (APC pc, Local local, Dummy dest, StackInfo data)
527 public StackInfo LoadLocalAddress (APC pc, Local local, Dummy dest, StackInfo data)
532 public StackInfo Nop (APC pc, StackInfo data)
537 public StackInfo Pop (APC pc, Dummy source, StackInfo data)
542 public StackInfo Return (APC pc, Dummy source, StackInfo data)
547 public StackInfo StoreArg (APC pc, Parameter argument, Dummy source, StackInfo data)
552 public StackInfo StoreLocal (APC pc, Local local, Dummy source, StackInfo data)
557 public StackInfo Switch (APC pc, TypeNode type, IEnumerable<Pair<object, APC>> cases, Dummy value, StackInfo data)
562 public StackInfo Box (APC pc, TypeNode type, Dummy dest, Dummy source, StackInfo data)
564 return data.Pop (1).Push ();
567 public StackInfo ConstrainedCallvirt<TypeList, ArgList> (APC pc, Method method, TypeNode constraint, TypeList extraVarargs, Dummy dest, ArgList args, StackInfo data)
568 where TypeList : IIndexable<TypeNode>
569 where ArgList : IIndexable<Dummy>
571 int paramsCount = MetaDataProvider.Parameters (method).Count + (extraVarargs == null ? 0 : extraVarargs.Count);
572 if (!MetaDataProvider.IsStatic (method)) {
573 if (data.IsThis (paramsCount))
574 this.stack_depth_mirror_for_end_old.AddCallOnThis (pc);
578 data = data.Pop (paramsCount);
579 if (MetaDataProvider.IsVoid (MetaDataProvider.ReturnType (method)))
585 public StackInfo CastClass (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
590 public StackInfo CopyObj (APC pc, TypeNode type, Dummy destPtr, Dummy sourcePtr, StackInfo data)
595 public StackInfo Initobj (APC pc, TypeNode type, Dummy ptr, StackInfo data)
600 public StackInfo LoadElement (APC pc, TypeNode type, Dummy dest, Dummy array, Dummy index, StackInfo data)
602 return data.Pop (2).Push ();
605 public StackInfo LoadField (APC pc, Field field, Dummy dest, Dummy obj, StackInfo data)
607 return data.Pop (1).Push ();
610 public StackInfo LoadFieldAddress (APC pc, Field field, Dummy dest, Dummy obj, StackInfo data)
612 return data.Pop (1).Push ();
615 public StackInfo LoadLength (APC pc, Dummy dest, Dummy array, StackInfo data)
617 return data.Pop (1).Push ();
620 public StackInfo LoadStaticField (APC pc, Field field, Dummy dest, StackInfo data)
625 public StackInfo LoadStaticFieldAddress (APC pc, Field field, Dummy dest, StackInfo data)
630 public StackInfo LoadTypeToken (APC pc, TypeNode type, Dummy dest, StackInfo data)
635 public StackInfo LoadFieldToken (APC pc, Field type, Dummy dest, StackInfo data)
640 public StackInfo LoadMethodToken (APC pc, Method type, Dummy dest, StackInfo data)
645 public StackInfo NewArray<ArgList> (APC pc, TypeNode type, Dummy dest, ArgList lengths, StackInfo data) where ArgList : IIndexable<Dummy>
647 return data.Pop (lengths.Count).Push ();
650 public StackInfo NewObj<ArgList> (APC pc, Method ctor, Dummy dest, ArgList args, StackInfo data) where ArgList : IIndexable<Dummy>
652 int paramsCount = MetaDataProvider.Parameters (ctor).Count;
653 return data.Pop (paramsCount).Push ();
656 public StackInfo MkRefAny (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
661 public StackInfo RefAnyType (APC pc, Dummy dest, Dummy source, StackInfo data)
663 return data.Pop (1).Push ();
666 public StackInfo RefAnyVal (APC pc, TypeNode type, Dummy dest, Dummy source, StackInfo data)
668 return data.Pop (1).Push ();
671 public StackInfo Rethrow (APC pc, StackInfo data)
673 return new StackInfo (0, 0);
676 public StackInfo StoreElement (APC pc, TypeNode type, Dummy array, Dummy index, Dummy value, StackInfo data)
681 public StackInfo StoreField (APC pc, Field field, Dummy obj, Dummy value, StackInfo data)
686 public StackInfo StoreStaticField (APC pc, Field field, Dummy value, StackInfo data)
691 public StackInfo Throw (APC pc, Dummy exception, StackInfo data)
693 return new StackInfo (0, 0);
696 public StackInfo Unbox (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
698 return data.Pop (1).Push ();
701 public StackInfo UnboxAny (APC pc, TypeNode type, Dummy dest, Dummy obj, StackInfo data)
703 return data.Pop (1).Push ();