~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/runtime/LocalVars.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (C) 2002-2010 Jeroen Frijters
 
3
 
 
4
  This software is provided 'as-is', without any express or implied
 
5
  warranty.  In no event will the authors be held liable for any damages
 
6
  arising from the use of this software.
 
7
 
 
8
  Permission is granted to anyone to use this software for any purpose,
 
9
  including commercial applications, and to alter it and redistribute it
 
10
  freely, subject to the following restrictions:
 
11
 
 
12
  1. The origin of this software must not be misrepresented; you must not
 
13
     claim that you wrote the original software. If you use this software
 
14
     in a product, an acknowledgment in the product documentation would be
 
15
     appreciated but is not required.
 
16
  2. Altered source versions must be plainly marked as such, and must not be
 
17
     misrepresented as being the original software.
 
18
  3. This notice may not be removed or altered from any source distribution.
 
19
 
 
20
  Jeroen Frijters
 
21
  jeroen@frijters.net
 
22
  
 
23
*/
 
24
using System;
 
25
using System.IO;
 
26
using System.Collections.Generic;
 
27
using System.Diagnostics;
 
28
#if STATIC_COMPILER
 
29
using IKVM.Reflection.Emit;
 
30
using Type = IKVM.Reflection.Type;
 
31
#else
 
32
using System.Reflection.Emit;
 
33
#endif
 
34
using IKVM.Internal;
 
35
using InstructionFlags = IKVM.Internal.ClassFile.Method.InstructionFlags;
 
36
using ExceptionTableEntry = IKVM.Internal.ClassFile.Method.ExceptionTableEntry;
 
37
 
 
38
sealed class LocalVar
 
39
{
 
40
        internal bool isArg;
 
41
        internal int local;
 
42
        internal TypeWrapper type;
 
43
        internal CodeEmitterLocal builder;
 
44
        // used to emit debugging info, only available if ClassLoaderWrapper.EmitDebugInfo is true
 
45
        internal string name;
 
46
        internal int start_pc;
 
47
        internal int end_pc;
 
48
}
 
49
 
 
50
struct LocalVarInfo
 
51
{
 
52
        private readonly LocalVar[/*instructionIndex*/] localVars;
 
53
        private readonly LocalVar[/*instructionIndex*/][/*localIndex*/] invokespecialLocalVars;
 
54
        private readonly LocalVar[/*index*/] allLocalVars;
 
55
 
 
56
        internal LocalVarInfo(CodeInfo ma, ClassFile classFile, ClassFile.Method method, UntangledExceptionTable exceptions, MethodWrapper mw, ClassLoaderWrapper classLoader)
 
57
        {
 
58
                Dictionary<int, string>[] localStoreReaders = FindLocalVariables(ma, mw, classFile, method);
 
59
 
 
60
                // now that we've done the code flow analysis, we can do a liveness analysis on the local variables
 
61
                ClassFile.Method.Instruction[] instructions = method.Instructions;
 
62
                Dictionary<long, LocalVar> localByStoreSite = new Dictionary<long, LocalVar>();
 
63
                List<LocalVar> locals = new List<LocalVar>();
 
64
                for (int i = 0; i < localStoreReaders.Length; i++)
 
65
                {
 
66
                        if (localStoreReaders[i] != null)
 
67
                        {
 
68
                                VisitLocalLoads(ma, method, locals, localByStoreSite, localStoreReaders[i], i, classLoader.EmitDebugInfo);
 
69
                        }
 
70
                }
 
71
                Dictionary<LocalVar, LocalVar> forwarders = new Dictionary<LocalVar, LocalVar>();
 
72
                if (classLoader.EmitDebugInfo)
 
73
                {
 
74
                        InstructionFlags[] flags = MethodAnalyzer.ComputePartialReachability(ma, method.Instructions, exceptions, 0, false);
 
75
                        // if we're emitting debug info, we need to keep dead stores as well...
 
76
                        for (int i = 0; i < instructions.Length; i++)
 
77
                        {
 
78
                                if ((flags[i] & InstructionFlags.Reachable) != 0
 
79
                                        && IsStoreLocal(instructions[i].NormalizedOpCode))
 
80
                                {
 
81
                                        if (!localByStoreSite.ContainsKey(MakeKey(i, instructions[i].NormalizedArg1)))
 
82
                                        {
 
83
                                                LocalVar v = new LocalVar();
 
84
                                                v.local = instructions[i].NormalizedArg1;
 
85
                                                v.type = ma.GetStackTypeWrapper(i, 0);
 
86
                                                FindLvtEntry(v, method, i);
 
87
                                                locals.Add(v);
 
88
                                                localByStoreSite.Add(MakeKey(i, v.local), v);
 
89
                                        }
 
90
                                }
 
91
                        }
 
92
                        // to make the debugging experience better, we have to trust the
 
93
                        // LocalVariableTable (unless it's clearly bogus) and merge locals
 
94
                        // together that are the same according to the LVT
 
95
                        for (int i = 0; i < locals.Count - 1; i++)
 
96
                        {
 
97
                                for (int j = i + 1; j < locals.Count; j++)
 
98
                                {
 
99
                                        LocalVar v1 = (LocalVar)locals[i];
 
100
                                        LocalVar v2 = (LocalVar)locals[j];
 
101
                                        if (v1.name != null && v1.name == v2.name && v1.start_pc == v2.start_pc && v1.end_pc == v2.end_pc)
 
102
                                        {
 
103
                                                // we can only merge if the resulting type is valid (this protects against incorrect
 
104
                                                // LVT data, but is also needed for constructors, where the uninitialized this is a different
 
105
                                                // type from the initialized this)
 
106
                                                TypeWrapper tw = InstructionState.FindCommonBaseType(v1.type, v2.type);
 
107
                                                if (tw != VerifierTypeWrapper.Invalid)
 
108
                                                {
 
109
                                                        v1.isArg |= v2.isArg;
 
110
                                                        v1.type = tw;
 
111
                                                        forwarders.Add(v2, v1);
 
112
                                                        locals.RemoveAt(j);
 
113
                                                        j--;
 
114
                                                }
 
115
                                        }
 
116
                                }
 
117
                        }
 
118
                }
 
119
                else
 
120
                {
 
121
                        for (int i = 0; i < locals.Count - 1; i++)
 
122
                        {
 
123
                                for (int j = i + 1; j < locals.Count; j++)
 
124
                                {
 
125
                                        LocalVar v1 = (LocalVar)locals[i];
 
126
                                        LocalVar v2 = (LocalVar)locals[j];
 
127
                                        // if the two locals are the same, we merge them, this is a small
 
128
                                        // optimization, it should *not* be required for correctness.
 
129
                                        if (v1.local == v2.local && v1.type == v2.type)
 
130
                                        {
 
131
                                                v1.isArg |= v2.isArg;
 
132
                                                forwarders.Add(v2, v1);
 
133
                                                locals.RemoveAt(j);
 
134
                                                j--;
 
135
                                        }
 
136
                                }
 
137
                        }
 
138
                }
 
139
                invokespecialLocalVars = new LocalVar[instructions.Length][];
 
140
                localVars = new LocalVar[instructions.Length];
 
141
                for (int i = 0; i < localVars.Length; i++)
 
142
                {
 
143
                        LocalVar v = null;
 
144
                        if (localStoreReaders[i] != null)
 
145
                        {
 
146
                                Debug.Assert(IsLoadLocal(instructions[i].NormalizedOpCode));
 
147
                                // lame way to look up the local variable for a load
 
148
                                // (by indirecting through a corresponding store)
 
149
                                foreach (int store in localStoreReaders[i].Keys)
 
150
                                {
 
151
                                        v = localByStoreSite[MakeKey(store, instructions[i].NormalizedArg1)];
 
152
                                        break;
 
153
                                }
 
154
                        }
 
155
                        else
 
156
                        {
 
157
                                if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial)
 
158
                                {
 
159
                                        invokespecialLocalVars[i] = new LocalVar[method.MaxLocals];
 
160
                                        for (int j = 0; j < invokespecialLocalVars[i].Length; j++)
 
161
                                        {
 
162
                                                localByStoreSite.TryGetValue(MakeKey(i, j), out invokespecialLocalVars[i][j]);
 
163
                                        }
 
164
                                }
 
165
                                else
 
166
                                {
 
167
                                        localByStoreSite.TryGetValue(MakeKey(i, instructions[i].NormalizedArg1), out v);
 
168
                                }
 
169
                        }
 
170
                        if (v != null)
 
171
                        {
 
172
                                LocalVar fwd;
 
173
                                if (forwarders.TryGetValue(v, out fwd))
 
174
                                {
 
175
                                        v = fwd;
 
176
                                }
 
177
                                localVars[i] = v;
 
178
                        }
 
179
                }
 
180
                this.allLocalVars = locals.ToArray();
 
181
        }
 
182
 
 
183
        private static void FindLvtEntry(LocalVar lv, ClassFile.Method method, int instructionIndex)
 
184
        {
 
185
                ClassFile.Method.LocalVariableTableEntry[] lvt = method.LocalVariableTableAttribute;
 
186
                if (lvt != null)
 
187
                {
 
188
                        int pc = method.Instructions[instructionIndex].PC;
 
189
                        int nextPC = method.Instructions[instructionIndex + 1].PC;
 
190
                        bool isStore = IsStoreLocal(method.Instructions[instructionIndex].NormalizedOpCode);
 
191
                        foreach (ClassFile.Method.LocalVariableTableEntry e in lvt)
 
192
                        {
 
193
                                // TODO validate the contents of the LVT entry
 
194
                                if (e.index == lv.local &&
 
195
                                        (e.start_pc <= pc || (e.start_pc == nextPC && isStore)) &&
 
196
                                        e.start_pc + e.length > pc)
 
197
                                {
 
198
                                        lv.name = e.name;
 
199
                                        lv.start_pc = e.start_pc;
 
200
                                        lv.end_pc = e.start_pc + e.length;
 
201
                                        break;
 
202
                                }
 
203
                        }
 
204
                }
 
205
        }
 
206
 
 
207
        // NOTE for dead stores, this returns null
 
208
        internal LocalVar GetLocalVar(int instructionIndex)
 
209
        {
 
210
                return localVars[instructionIndex];
 
211
        }
 
212
 
 
213
        internal LocalVar[] GetLocalVarsForInvokeSpecial(int instructionIndex)
 
214
        {
 
215
                return invokespecialLocalVars[instructionIndex];
 
216
        }
 
217
 
 
218
        internal LocalVar[] GetAllLocalVars()
 
219
        {
 
220
                return allLocalVars;
 
221
        }
 
222
 
 
223
        private static bool IsLoadLocal(NormalizedByteCode bc)
 
224
        {
 
225
                return bc == NormalizedByteCode.__aload ||
 
226
                        bc == NormalizedByteCode.__iload ||
 
227
                        bc == NormalizedByteCode.__lload ||
 
228
                        bc == NormalizedByteCode.__fload ||
 
229
                        bc == NormalizedByteCode.__dload ||
 
230
                        bc == NormalizedByteCode.__iinc ||
 
231
                        bc == NormalizedByteCode.__ret;
 
232
        }
 
233
 
 
234
        private static bool IsStoreLocal(NormalizedByteCode bc)
 
235
        {
 
236
                return bc == NormalizedByteCode.__astore ||
 
237
                        bc == NormalizedByteCode.__istore ||
 
238
                        bc == NormalizedByteCode.__lstore ||
 
239
                        bc == NormalizedByteCode.__fstore ||
 
240
                        bc == NormalizedByteCode.__dstore;
 
241
        }
 
242
 
 
243
        struct FindLocalVarState
 
244
        {
 
245
                internal bool changed;
 
246
                internal FindLocalVarStoreSite[] sites;
 
247
 
 
248
                internal void Store(int instructionIndex, int localIndex)
 
249
                {
 
250
                        if (sites[localIndex].Count == 1 && sites[localIndex][0] == instructionIndex)
 
251
                        {
 
252
                                return;
 
253
                        }
 
254
                        sites = (FindLocalVarStoreSite[])sites.Clone();
 
255
                        sites[localIndex] = new FindLocalVarStoreSite();
 
256
                        sites[localIndex].Add(instructionIndex);
 
257
                }
 
258
 
 
259
                internal void Merge(FindLocalVarState state)
 
260
                {
 
261
                        if (sites == null)
 
262
                        {
 
263
                                sites = state.sites;
 
264
                                changed = true;
 
265
                        }
 
266
                        else
 
267
                        {
 
268
                                bool dirty = true;
 
269
                                for (int i = 0; i < sites.Length; i++)
 
270
                                {
 
271
                                        for (int j = 0; j < state.sites[i].Count; j++)
 
272
                                        {
 
273
                                                if (!sites[i].Contains(state.sites[i][j]))
 
274
                                                {
 
275
                                                        if (dirty)
 
276
                                                        {
 
277
                                                                dirty = false;
 
278
                                                                sites = (FindLocalVarStoreSite[])sites.Clone();
 
279
                                                        }
 
280
                                                        sites[i].Add(state.sites[i][j]);
 
281
                                                        changed = true;
 
282
                                                }
 
283
                                        }
 
284
                                }
 
285
                        }
 
286
                }
 
287
 
 
288
                internal FindLocalVarState Copy()
 
289
                {
 
290
                        FindLocalVarState copy = new FindLocalVarState();
 
291
                        copy.sites = sites;
 
292
                        return copy;
 
293
                }
 
294
 
 
295
                public override string ToString()
 
296
                {
 
297
                        System.Text.StringBuilder sb = new System.Text.StringBuilder();
 
298
                        if (sites != null)
 
299
                        {
 
300
                                foreach (FindLocalVarStoreSite site in sites)
 
301
                                {
 
302
                                        sb.Append('[');
 
303
                                        for (int i = 0; i < site.Count; i++)
 
304
                                        {
 
305
                                                sb.AppendFormat("{0}, ", site[i]);
 
306
                                        }
 
307
                                        sb.Append(']');
 
308
                                }
 
309
                        }
 
310
                        return sb.ToString();
 
311
                }
 
312
        }
 
313
 
 
314
        struct FindLocalVarStoreSite
 
315
        {
 
316
                private int[] data;
 
317
 
 
318
                internal bool Contains(int instructionIndex)
 
319
                {
 
320
                        if (data != null)
 
321
                        {
 
322
                                for (int i = 0; i < data.Length; i++)
 
323
                                {
 
324
                                        if (data[i] == instructionIndex)
 
325
                                        {
 
326
                                                return true;
 
327
                                        }
 
328
                                }
 
329
                        }
 
330
                        return false;
 
331
                }
 
332
 
 
333
                internal void Add(int instructionIndex)
 
334
                {
 
335
                        if (data == null)
 
336
                        {
 
337
                                data = new int[] { instructionIndex };
 
338
                        }
 
339
                        else
 
340
                        {
 
341
                                Array.Resize(ref data, data.Length + 1);
 
342
                                data[data.Length - 1] = instructionIndex;
 
343
                        }
 
344
                }
 
345
 
 
346
                internal int this[int index]
 
347
                {
 
348
                        get { return data[index]; }
 
349
                }
 
350
 
 
351
                internal int Count
 
352
                {
 
353
                        get { return data == null ? 0 : data.Length; }
 
354
                }
 
355
        }
 
356
 
 
357
        private static Dictionary<int, string>[] FindLocalVariables(CodeInfo codeInfo, MethodWrapper mw, ClassFile classFile, ClassFile.Method method)
 
358
        {
 
359
                FindLocalVarState[] state = new FindLocalVarState[method.Instructions.Length];
 
360
                state[0].changed = true;
 
361
                state[0].sites = new FindLocalVarStoreSite[method.MaxLocals];
 
362
                TypeWrapper[] parameters = mw.GetParameters();
 
363
                int argpos = 0;
 
364
                if (!mw.IsStatic)
 
365
                {
 
366
                        state[0].sites[argpos++].Add(-1);
 
367
                }
 
368
                for (int i = 0; i < parameters.Length; i++)
 
369
                {
 
370
                        state[0].sites[argpos++].Add(-1);
 
371
                        if (parameters[i].IsWidePrimitive)
 
372
                        {
 
373
                                argpos++;
 
374
                        }
 
375
                }
 
376
                return FindLocalVariablesImpl(codeInfo, classFile, method, state);
 
377
        }
 
378
 
 
379
        private static Dictionary<int, string>[] FindLocalVariablesImpl(CodeInfo codeInfo, ClassFile classFile, ClassFile.Method method, FindLocalVarState[] state)
 
380
        {
 
381
                ClassFile.Method.Instruction[] instructions = method.Instructions;
 
382
                ExceptionTableEntry[] exceptions = method.ExceptionTable;
 
383
                int maxLocals = method.MaxLocals;
 
384
                Dictionary<int, string>[] localStoreReaders = new Dictionary<int, string>[instructions.Length];
 
385
                bool done = false;
 
386
 
 
387
                while (!done)
 
388
                {
 
389
                        done = true;
 
390
                        for (int i = 0; i < instructions.Length; i++)
 
391
                        {
 
392
                                if (state[i].changed)
 
393
                                {
 
394
                                        done = false;
 
395
                                        state[i].changed = false;
 
396
 
 
397
                                        FindLocalVarState curr = state[i].Copy();
 
398
 
 
399
                                        for (int j = 0; j < exceptions.Length; j++)
 
400
                                        {
 
401
                                                if (exceptions[j].startIndex <= i && i < exceptions[j].endIndex)
 
402
                                                {
 
403
                                                        state[exceptions[j].handlerIndex].Merge(curr);
 
404
                                                }
 
405
                                        }
 
406
 
 
407
                                        if (IsLoadLocal(instructions[i].NormalizedOpCode)
 
408
                                                && (instructions[i].NormalizedOpCode != NormalizedByteCode.__aload || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i + 1, 0))))
 
409
                                        {
 
410
                                                if (localStoreReaders[i] == null)
 
411
                                                {
 
412
                                                        localStoreReaders[i] = new Dictionary<int, string>();
 
413
                                                }
 
414
                                                for (int j = 0; j < curr.sites[instructions[i].NormalizedArg1].Count; j++)
 
415
                                                {
 
416
                                                        localStoreReaders[i][curr.sites[instructions[i].NormalizedArg1][j]] = "";
 
417
                                                }
 
418
                                        }
 
419
 
 
420
                                        if (IsStoreLocal(instructions[i].NormalizedOpCode)
 
421
                                                && (instructions[i].NormalizedOpCode != NormalizedByteCode.__astore || !VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(i, 0))))
 
422
                                        {
 
423
                                                curr.Store(i, instructions[i].NormalizedArg1);
 
424
                                                // if this is a store at the end of an exception block,
 
425
                                                // we need to propagate the new state to the exception handler
 
426
                                                for (int j = 0; j < exceptions.Length; j++)
 
427
                                                {
 
428
                                                        if (exceptions[j].endIndex == i + 1)
 
429
                                                        {
 
430
                                                                state[exceptions[j].handlerIndex].Merge(curr);
 
431
                                                        }
 
432
                                                }
 
433
                                        }
 
434
 
 
435
                                        if (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial)
 
436
                                        {
 
437
                                                ClassFile.ConstantPoolItemMI cpi = classFile.GetMethodref(instructions[i].Arg1);
 
438
                                                if (ReferenceEquals(cpi.Name, StringConstants.INIT))
 
439
                                                {
 
440
                                                        TypeWrapper type = codeInfo.GetRawStackTypeWrapper(i, cpi.GetArgTypes().Length);
 
441
                                                        // after we've invoked the constructor, the uninitialized references
 
442
                                                        // are now initialized
 
443
                                                        if (type == VerifierTypeWrapper.UninitializedThis
 
444
                                                                || VerifierTypeWrapper.IsNew(type))
 
445
                                                        {
 
446
                                                                for (int j = 0; j < maxLocals; j++)
 
447
                                                                {
 
448
                                                                        if (codeInfo.GetLocalTypeWrapper(i, j) == type)
 
449
                                                                        {
 
450
                                                                                curr.Store(i, j);
 
451
                                                                        }
 
452
                                                                }
 
453
                                                        }
 
454
                                                }
 
455
                                        }
 
456
                                        else if (instructions[i].NormalizedOpCode == NormalizedByteCode.__goto_finally)
 
457
                                        {
 
458
                                                int handler = instructions[i].HandlerIndex;
 
459
 
 
460
                                                // Normally a store at the end of a try block doesn't affect the handler block,
 
461
                                                // but in the case of a finally handler it does, so we need to make sure that
 
462
                                                // we merge here in case the try block ended with a store.
 
463
                                                state[handler].Merge(curr);
 
464
 
 
465
                                                // Now we recursively analyse the handler and afterwards merge the endfault locations back to us
 
466
                                                FindLocalVarState[] handlerState = new FindLocalVarState[instructions.Length];
 
467
                                                handlerState[handler].changed = true;
 
468
                                                handlerState[handler].sites = new FindLocalVarStoreSite[maxLocals];
 
469
                                                FindLocalVariablesImpl(codeInfo, classFile, method, handlerState);
 
470
 
 
471
                                                // Merge back to the target of our __goto_finally
 
472
                                                for (int j = 0; j < handlerState.Length; j++)
 
473
                                                {
 
474
                                                        if (instructions[j].NormalizedOpCode == NormalizedByteCode.__athrow
 
475
                                                                && codeInfo.HasState(j)
 
476
                                                                && VerifierTypeWrapper.IsFaultBlockException(codeInfo.GetRawStackTypeWrapper(j, 0))
 
477
                                                                && ((VerifierTypeWrapper)codeInfo.GetRawStackTypeWrapper(j, 0)).Index == handler)
 
478
                                                        {
 
479
                                                                state[instructions[i].Arg1].Merge(handlerState[j]);
 
480
                                                        }
 
481
                                                }
 
482
                                        }
 
483
 
 
484
                                        switch (ByteCodeMetaData.GetFlowControl(instructions[i].NormalizedOpCode))
 
485
                                        {
 
486
                                                case ByteCodeFlowControl.Switch:
 
487
                                                        {
 
488
                                                                for (int j = 0; j < instructions[i].SwitchEntryCount; j++)
 
489
                                                                {
 
490
                                                                        state[instructions[i].GetSwitchTargetIndex(j)].Merge(curr);
 
491
                                                                }
 
492
                                                                state[instructions[i].DefaultTarget].Merge(curr);
 
493
                                                                break;
 
494
                                                        }
 
495
                                                case ByteCodeFlowControl.Branch:
 
496
                                                        state[instructions[i].TargetIndex].Merge(curr);
 
497
                                                        break;
 
498
                                                case ByteCodeFlowControl.CondBranch:
 
499
                                                        state[instructions[i].TargetIndex].Merge(curr);
 
500
                                                        state[i + 1].Merge(curr);
 
501
                                                        break;
 
502
                                                case ByteCodeFlowControl.Return:
 
503
                                                case ByteCodeFlowControl.Throw:
 
504
                                                        break;
 
505
                                                case ByteCodeFlowControl.Next:
 
506
                                                        state[i + 1].Merge(curr);
 
507
                                                        break;
 
508
                                                default:
 
509
                                                        throw new InvalidOperationException();
 
510
                                        }
 
511
                                }
 
512
                        }
 
513
                }
 
514
                return localStoreReaders;
 
515
        }
 
516
 
 
517
        private static void VisitLocalLoads(CodeInfo codeInfo, ClassFile.Method method, List<LocalVar> locals, Dictionary<long, LocalVar> localByStoreSite, Dictionary<int, string> storeSites, int instructionIndex, bool debug)
 
518
        {
 
519
                Debug.Assert(IsLoadLocal(method.Instructions[instructionIndex].NormalizedOpCode));
 
520
                LocalVar local = null;
 
521
                TypeWrapper type = VerifierTypeWrapper.Null;
 
522
                int localIndex = method.Instructions[instructionIndex].NormalizedArg1;
 
523
                bool isArg = false;
 
524
                foreach (int store in storeSites.Keys)
 
525
                {
 
526
                        if (store == -1)
 
527
                        {
 
528
                                // it's a method argument, it has no initial store, but the type is simply the parameter type
 
529
                                type = InstructionState.FindCommonBaseType(type, codeInfo.GetLocalTypeWrapper(0, localIndex));
 
530
                                isArg = true;
 
531
                        }
 
532
                        else
 
533
                        {
 
534
                                if (method.Instructions[store].NormalizedOpCode == NormalizedByteCode.__invokespecial)
 
535
                                {
 
536
                                        type = InstructionState.FindCommonBaseType(type, codeInfo.GetLocalTypeWrapper(store + 1, localIndex));
 
537
                                }
 
538
                                else if (method.Instructions[store].NormalizedOpCode == NormalizedByteCode.__static_error)
 
539
                                {
 
540
                                        // it's an __invokespecial that turned into a __static_error
 
541
                                        // (since a __static_error doesn't continue, we don't need to set type)
 
542
                                }
 
543
                                else
 
544
                                {
 
545
                                        Debug.Assert(IsStoreLocal(method.Instructions[store].NormalizedOpCode));
 
546
                                        type = InstructionState.FindCommonBaseType(type, codeInfo.GetStackTypeWrapper(store, 0));
 
547
                                }
 
548
                        }
 
549
                        // we can't have an invalid type, because that would have failed verification earlier
 
550
                        Debug.Assert(type != VerifierTypeWrapper.Invalid);
 
551
 
 
552
                        LocalVar l;
 
553
                        if (localByStoreSite.TryGetValue(MakeKey(store, localIndex), out l))
 
554
                        {
 
555
                                if (local == null)
 
556
                                {
 
557
                                        local = l;
 
558
                                }
 
559
                                else if (local != l)
 
560
                                {
 
561
                                        // If we've already defined a LocalVar and we find another one, then we merge them
 
562
                                        // together.
 
563
                                        // This happens for the following code fragment:
 
564
                                        //
 
565
                                        // int i = -1;
 
566
                                        // try { i = 0; for(; ; ) System.out.println(i); } catch(Exception x) {}
 
567
                                        // try { i = 0; for(; ; ) System.out.println(i); } catch(Exception x) {}
 
568
                                        // System.out.println(i);
 
569
                                        //
 
570
                                        local = MergeLocals(locals, localByStoreSite, local, l);
 
571
                                }
 
572
                        }
 
573
                }
 
574
                if (local == null)
 
575
                {
 
576
                        local = new LocalVar();
 
577
                        local.local = localIndex;
 
578
                        if (VerifierTypeWrapper.IsThis(type))
 
579
                        {
 
580
                                local.type = ((VerifierTypeWrapper)type).UnderlyingType;
 
581
                        }
 
582
                        else
 
583
                        {
 
584
                                local.type = type;
 
585
                        }
 
586
                        local.isArg = isArg;
 
587
                        if (debug)
 
588
                        {
 
589
                                FindLvtEntry(local, method, instructionIndex);
 
590
                        }
 
591
                        locals.Add(local);
 
592
                }
 
593
                else
 
594
                {
 
595
                        local.isArg |= isArg;
 
596
                        local.type = InstructionState.FindCommonBaseType(local.type, type);
 
597
                        Debug.Assert(local.type != VerifierTypeWrapper.Invalid);
 
598
                }
 
599
                foreach (int store in storeSites.Keys)
 
600
                {
 
601
                        LocalVar v;
 
602
                        if (!localByStoreSite.TryGetValue(MakeKey(store, localIndex), out v))
 
603
                        {
 
604
                                localByStoreSite[MakeKey(store, localIndex)] = local;
 
605
                        }
 
606
                        else if (v != local)
 
607
                        {
 
608
                                local = MergeLocals(locals, localByStoreSite, local, v);
 
609
                        }
 
610
                }
 
611
        }
 
612
 
 
613
        private static long MakeKey(int i, int j)
 
614
        {
 
615
                return (((long)(uint)i) << 32) + (uint)j;
 
616
        }
 
617
 
 
618
        private static LocalVar MergeLocals(List<LocalVar> locals, Dictionary<long, LocalVar> localByStoreSite, LocalVar l1, LocalVar l2)
 
619
        {
 
620
                Debug.Assert(l1 != l2);
 
621
                Debug.Assert(l1.local == l2.local);
 
622
                for (int i = 0; i < locals.Count; i++)
 
623
                {
 
624
                        if (locals[i] == l2)
 
625
                        {
 
626
                                locals.RemoveAt(i);
 
627
                                i--;
 
628
                        }
 
629
                }
 
630
                Dictionary<long, LocalVar> temp = new Dictionary<long, LocalVar>(localByStoreSite);
 
631
                localByStoreSite.Clear();
 
632
                foreach (KeyValuePair<long, LocalVar> kv in temp)
 
633
                {
 
634
                        localByStoreSite[kv.Key] = kv.Value == l2 ? l1 : kv.Value;
 
635
                }
 
636
                l1.isArg |= l2.isArg;
 
637
                l1.type = InstructionState.FindCommonBaseType(l1.type, l2.type);
 
638
                Debug.Assert(l1.type != VerifierTypeWrapper.Invalid);
 
639
                return l1;
 
640
        }
 
641
}