9e8d6b911cf24a5577fba5d2d19527bb05e1013d
[platform/upstream/coreclr.git] / src / jit / scopeinfo.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                                  ScopeInfo                                XX
9 XX                                                                           XX
10 XX   Classes to gather the Scope information from the local variable info.   XX
11 XX   Translates the given LocalVarTab from IL instruction offsets into       XX
12 XX   native code offsets.                                                    XX
13 XX                                                                           XX
14 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
15 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
16 */
17
18 /******************************************************************************
19  *                                  Debuggable code
20  *
21  *  We break up blocks at the start and end IL ranges of the local variables.
22  *  This is because IL offsets do not correspond exactly to native offsets
23  *  except at block boundaries. No basic-blocks are deleted (not even
24  *  unreachable), so there will not be any missing address-ranges, though the
25  *  blocks themselves may not be ordered. (Also, internal blocks may be added).
26  *  o At the start of each basic block, siBeginBlock() checks if any variables
27  *    are coming in scope, and adds an open scope to siOpenScopeList if needed.
28  *  o At the end of each basic block, siEndBlock() checks if any variables
29  *    are going out of scope and moves the open scope from siOpenScopeLast
30  *    to siScopeList.
31  *
32  *                                  Optimized code
33  *
34  *  We cannot break up the blocks as this will produce different code under
35  *  the debugger. Instead we try to do a best effort.
36  *  o At the start of each basic block, siBeginBlock() adds open scopes
37  *    corresponding to block->bbLiveIn to siOpenScopeList. Also siUpdate()
38  *    is called to close scopes for variables which are not live anymore.
39  *  o siEndBlock() closes scopes for any variables which go out of range
40  *    before bbCodeOffsEnd.
41  *  o siCloseAllOpenScopes() closes any open scopes after all the blocks.
42  *    This should only be needed if some basic block are deleted/out of order,
43  *    etc.
44  *  Also,
45  *  o At every assignment to a variable, siCheckVarScope() adds an open scope
46  *    for the variable being assigned to.
47  *  o UpdateLifeVar() calls siUpdate() which closes scopes for variables which
48  *    are not live anymore.
49  *
50  ******************************************************************************
51  */
52
53 #include "jitpch.h"
54 #ifdef _MSC_VER
55 #pragma hdrstop
56 #endif
57
58 #include "emit.h"
59 #include "codegen.h"
60
61 bool CodeGenInterface::siVarLoc::vlIsInReg(regNumber reg) const
62 {
63     switch (vlType)
64     {
65         case CodeGenInterface::VLT_REG:
66             return (vlReg.vlrReg == reg);
67         case CodeGenInterface::VLT_REG_REG:
68             return ((vlRegReg.vlrrReg1 == reg) || (vlRegReg.vlrrReg2 == reg));
69         case CodeGenInterface::VLT_REG_STK:
70             return (vlRegStk.vlrsReg == reg);
71         case CodeGenInterface::VLT_STK_REG:
72             return (vlStkReg.vlsrReg == reg);
73
74         case CodeGenInterface::VLT_STK:
75         case CodeGenInterface::VLT_STK2:
76         case CodeGenInterface::VLT_FPSTK:
77             return false;
78
79         default:
80             assert(!"Bad locType");
81             return false;
82     }
83 }
84
85 bool CodeGenInterface::siVarLoc::vlIsOnStk(regNumber reg, signed offset) const
86 {
87     regNumber actualReg;
88
89     switch (vlType)
90     {
91
92         case CodeGenInterface::VLT_REG_STK:
93             actualReg = vlRegStk.vlrsStk.vlrssBaseReg;
94             if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
95             {
96                 actualReg = REG_SPBASE;
97             }
98             return ((actualReg == reg) && (vlRegStk.vlrsStk.vlrssOffset == offset));
99         case CodeGenInterface::VLT_STK_REG:
100             actualReg = vlStkReg.vlsrStk.vlsrsBaseReg;
101             if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
102             {
103                 actualReg = REG_SPBASE;
104             }
105             return ((actualReg == reg) && (vlStkReg.vlsrStk.vlsrsOffset == offset));
106         case CodeGenInterface::VLT_STK:
107             actualReg = vlStk.vlsBaseReg;
108             if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
109             {
110                 actualReg = REG_SPBASE;
111             }
112             return ((actualReg == reg) && (vlStk.vlsOffset == offset));
113         case CodeGenInterface::VLT_STK2:
114             actualReg = vlStk2.vls2BaseReg;
115             if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
116             {
117                 actualReg = REG_SPBASE;
118             }
119             return ((actualReg == reg) && ((vlStk2.vls2Offset == offset) || (vlStk2.vls2Offset == (offset - 4))));
120
121         case CodeGenInterface::VLT_REG:
122         case CodeGenInterface::VLT_REG_FP:
123         case CodeGenInterface::VLT_REG_REG:
124         case CodeGenInterface::VLT_FPSTK:
125             return false;
126
127         default:
128             assert(!"Bad locType");
129             return false;
130     }
131 }
132
133 //------------------------------------------------------------------------
134 // Equals: Compares first reference and then values of the structures.
135 //
136 // Arguments:
137 //    lhs   - a "siVarLoc *" to compare.
138 //    rhs   - a "siVarLoc *" to compare.
139 //
140 // Notes:
141 //    Return true if both are nullptr.
142 //
143 // static
144 bool CodeGenInterface::siVarLoc::Equals(const siVarLoc* lhs, const siVarLoc* rhs)
145 {
146     if (lhs == rhs)
147     {
148         // Are both nullptr or the same reference
149         return true;
150     }
151     if ((lhs == nullptr) || (rhs == nullptr))
152     {
153         // Just one of them is a nullptr
154         return false;
155     }
156     if (lhs->vlType != rhs->vlType)
157     {
158         return false;
159     }
160     assert(lhs->vlType == rhs->vlType);
161     // If neither is nullptr, and are not the same reference, compare values
162     switch (lhs->vlType)
163     {
164         case VLT_STK:
165         case VLT_STK_BYREF:
166             return (lhs->vlStk.vlsBaseReg == rhs->vlStk.vlsBaseReg) && (lhs->vlStk.vlsOffset == rhs->vlStk.vlsOffset);
167
168         case VLT_STK2:
169             return (lhs->vlStk2.vls2BaseReg == rhs->vlStk2.vls2BaseReg) &&
170                    (lhs->vlStk2.vls2Offset == rhs->vlStk2.vls2Offset);
171
172         case VLT_REG:
173         case VLT_REG_FP:
174         case VLT_REG_BYREF:
175             return (lhs->vlReg.vlrReg == rhs->vlReg.vlrReg);
176
177         case VLT_REG_REG:
178             return (lhs->vlRegReg.vlrrReg1 == rhs->vlRegReg.vlrrReg1) &&
179                    (lhs->vlRegReg.vlrrReg2 == rhs->vlRegReg.vlrrReg2);
180
181         case VLT_REG_STK:
182             return (lhs->vlRegStk.vlrsReg == rhs->vlRegStk.vlrsReg) &&
183                    (lhs->vlRegStk.vlrsStk.vlrssBaseReg == rhs->vlRegStk.vlrsStk.vlrssBaseReg) &&
184                    (lhs->vlRegStk.vlrsStk.vlrssOffset == rhs->vlRegStk.vlrsStk.vlrssOffset);
185
186         case VLT_STK_REG:
187             return (lhs->vlStkReg.vlsrReg == rhs->vlStkReg.vlsrReg) &&
188                    (lhs->vlStkReg.vlsrStk.vlsrsBaseReg == rhs->vlStkReg.vlsrStk.vlsrsBaseReg) &&
189                    (lhs->vlStkReg.vlsrStk.vlsrsOffset == rhs->vlStkReg.vlsrStk.vlsrsOffset);
190
191         case VLT_FPSTK:
192             return (lhs->vlFPstk.vlfReg == rhs->vlFPstk.vlfReg);
193
194         case VLT_FIXED_VA:
195             return (lhs->vlFixedVarArg.vlfvOffset == rhs->vlFixedVarArg.vlfvOffset);
196
197         case VLT_COUNT:
198         case VLT_INVALID:
199             return true;
200
201         default:
202             unreached();
203     }
204 }
205
206 //------------------------------------------------------------------------
207 // siFillStackVarLoc: Fill "siVarLoc" struct indicating the stack position of the variable
208 // using "LclVarDsc" and "baseReg"/"offset".
209 //
210 // Arguments:
211 //    varDsc    - a "LclVarDsc *" to the variable it is desired to build the "siVarLoc".
212 //    varLoc    - a "siVarLoc &" to fill with the data of the "varDsc".
213 //    type      - a "var_types" which indicate the type of the variable.
214 //    baseReg   - a "regNumber" use as a base for the offset.
215 //    offset    - a signed amount of bytes distance from "baseReg" for the position of the variable.
216 //    isFramePointerUsed - a boolean variable
217 //
218 // Notes:
219 //    The "varLoc" argument is filled depending of the "type" argument but as a VLT_STK... variation.
220 //    "baseReg" and "offset" are used to indicate the position of the variable in the stack.
221 void CodeGenInterface::siVarLoc::siFillStackVarLoc(
222     const LclVarDsc* varDsc, var_types type, regNumber baseReg, int offset, bool isFramePointerUsed)
223 {
224     assert(offset != BAD_STK_OFFS);
225
226     switch (type)
227     {
228         case TYP_INT:
229         case TYP_REF:
230         case TYP_BYREF:
231         case TYP_FLOAT:
232         case TYP_STRUCT:
233         case TYP_BLK: // Needed because of the TYP_BLK stress mode
234 #ifdef FEATURE_SIMD
235         case TYP_SIMD8:
236         case TYP_SIMD12:
237         case TYP_SIMD16:
238         case TYP_SIMD32:
239 #endif
240 #ifdef _TARGET_64BIT_
241         case TYP_LONG:
242         case TYP_DOUBLE:
243 #endif // _TARGET_64BIT_
244 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
245             // In the AMD64 ABI we are supposed to pass a struct by reference when its
246             // size is not 1, 2, 4 or 8 bytes in size. During fgMorph, the compiler modifies
247             // the IR to comply with the ABI and therefore changes the type of the lclVar
248             // that holds the struct from TYP_STRUCT to TYP_BYREF but it gives us a hint that
249             // this is still a struct by setting the lvIsTemp flag.
250             // The same is true for ARM64 and structs > 16 bytes.
251             // (See Compiler::fgMarkImplicitByRefArgs in Morph.cpp for further detail)
252             // Now, the VM expects a special enum for these type of local vars: VLT_STK_BYREF
253             // to accomodate for this situation.
254             if (varDsc->lvType == TYP_BYREF && varDsc->lvIsTemp)
255             {
256                 assert(varDsc->lvIsParam);
257                 this->vlType = VLT_STK_BYREF;
258             }
259             else
260 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
261             {
262                 this->vlType = VLT_STK;
263             }
264             this->vlStk.vlsBaseReg = baseReg;
265             this->vlStk.vlsOffset  = offset;
266             if (!isFramePointerUsed && this->vlStk.vlsBaseReg == REG_SPBASE)
267             {
268                 this->vlStk.vlsBaseReg = (regNumber)ICorDebugInfo::REGNUM_AMBIENT_SP;
269             }
270             break;
271
272 #ifndef _TARGET_64BIT_
273         case TYP_LONG:
274         case TYP_DOUBLE:
275             this->vlType             = VLT_STK2;
276             this->vlStk2.vls2BaseReg = baseReg;
277             this->vlStk2.vls2Offset  = offset;
278             if (!isFramePointerUsed && this->vlStk2.vls2BaseReg == REG_SPBASE)
279             {
280                 this->vlStk2.vls2BaseReg = (regNumber)ICorDebugInfo::REGNUM_AMBIENT_SP;
281             }
282             break;
283 #endif // !_TARGET_64BIT_
284
285         default:
286             noway_assert(!"Invalid type");
287     }
288 }
289
290 //------------------------------------------------------------------------
291 // siFillRegisterVarLoc: Fill "siVarLoc" struct indicating the register position of the variable
292 // using "LclVarDsc" and "baseReg"/"offset" if it has a part in the stack (x64 bit float or long).
293 //
294 // Arguments:
295 //    varDsc    - a "LclVarDsc *" to the variable it is desired to build the "siVarLoc".
296 //    varLoc    - a "siVarLoc &" to fill with the data of the "varDsc".
297 //    type      - a "var_types" which indicate the type of the variable.
298 //    baseReg   - a "regNumber" use as a base for the offset.
299 //    offset    - a signed amount of bytes distance from "baseReg" for the position of the variable.
300 //    isFramePointerUsed    - a boolean indicating whether the current method sets up an
301 //    explicit stack frame or not.
302 //
303 // Notes:
304 //    The "varLoc" argument is filled depending of the "type" argument but as a VLT_REG... variation.
305 //    "baseReg" and "offset" are used .for not 64 bit and values that are splitted in two parts.
306 void CodeGenInterface::siVarLoc::siFillRegisterVarLoc(
307     const LclVarDsc* varDsc, var_types type, regNumber baseReg, int offset, bool isFramePointerUsed)
308 {
309     switch (type)
310     {
311         case TYP_INT:
312         case TYP_REF:
313         case TYP_BYREF:
314 #ifdef _TARGET_64BIT_
315         case TYP_LONG:
316 #endif // _TARGET_64BIT_
317             this->vlType       = VLT_REG;
318             this->vlReg.vlrReg = varDsc->lvRegNum;
319             break;
320
321 #ifndef _TARGET_64BIT_
322         case TYP_LONG:
323 #if !CPU_HAS_FP_SUPPORT
324         case TYP_DOUBLE:
325 #endif
326             if (varDsc->lvOtherReg != REG_STK)
327             {
328                 this->vlType            = VLT_REG_REG;
329                 this->vlRegReg.vlrrReg1 = varDsc->lvRegNum;
330                 this->vlRegReg.vlrrReg2 = varDsc->lvOtherReg;
331             }
332             else
333             {
334                 this->vlType                        = VLT_REG_STK;
335                 this->vlRegStk.vlrsReg              = varDsc->lvRegNum;
336                 this->vlRegStk.vlrsStk.vlrssBaseReg = baseReg;
337                 if (isFramePointerUsed && this->vlRegStk.vlrsStk.vlrssBaseReg == REG_SPBASE)
338                 {
339                     this->vlRegStk.vlrsStk.vlrssBaseReg = (regNumber)ICorDebugInfo::REGNUM_AMBIENT_SP;
340                 }
341                 this->vlRegStk.vlrsStk.vlrssOffset = offset + sizeof(int);
342             }
343             break;
344 #endif // !_TARGET_64BIT_
345
346 #ifdef _TARGET_64BIT_
347         case TYP_FLOAT:
348         case TYP_DOUBLE:
349             // TODO-AMD64-Bug: ndp\clr\src\inc\corinfo.h has a definition of RegNum that only goes up to R15,
350             // so no XMM registers can get debug information.
351             this->vlType       = VLT_REG_FP;
352             this->vlReg.vlrReg = varDsc->lvRegNum;
353             break;
354
355 #else // !_TARGET_64BIT_
356
357 #if CPU_HAS_FP_SUPPORT
358         case TYP_FLOAT:
359         case TYP_DOUBLE:
360             if (isFloatRegType(type))
361             {
362                 this->vlType         = VLT_FPSTK;
363                 this->vlFPstk.vlfReg = varDsc->lvRegNum;
364             }
365             break;
366 #endif // CPU_HAS_FP_SUPPORT
367
368 #endif // !_TARGET_64BIT_
369
370 #ifdef FEATURE_SIMD
371         case TYP_SIMD8:
372         case TYP_SIMD12:
373         case TYP_SIMD16:
374         case TYP_SIMD32:
375             this->vlType = VLT_REG_FP;
376
377             // TODO-AMD64-Bug: ndp\clr\src\inc\corinfo.h has a definition of RegNum that only goes up to R15,
378             // so no XMM registers can get debug information.
379             //
380             // Note: Need to initialize vlrReg field, otherwise during jit dump hitting an assert
381             // in eeDispVar() --> getRegName() that regNumber is valid.
382             this->vlReg.vlrReg = varDsc->lvRegNum;
383             break;
384 #endif // FEATURE_SIMD
385
386         default:
387             noway_assert(!"Invalid type");
388     }
389 }
390
391 //------------------------------------------------------------------------
392 // siVarLoc: Non-empty constructor of siVarLoc struct
393 // Arguments:
394 //    varDsc    - a "LclVarDsc *" to the variable it is desired to build the "siVarLoc".
395 //    baseReg   - a "regNumber" use as a base for the offset.
396 //    offset    - a signed amount of bytes distance from "baseReg" for the position of the variable.
397 //    isFramePointerUsed - a boolean variable
398 //
399 // Notes:
400 //    Called for every psiScope in "psiScopeList" codegen.h
401 CodeGenInterface::siVarLoc::siVarLoc(const LclVarDsc* varDsc, regNumber baseReg, int offset, bool isFramePointerUsed)
402 {
403     var_types type = genActualType(varDsc->TypeGet());
404
405     if (varDsc->lvIsInReg())
406     {
407         siFillRegisterVarLoc(varDsc, type, baseReg, offset, isFramePointerUsed);
408     }
409     else
410     {
411         siFillStackVarLoc(varDsc, type, baseReg, offset, isFramePointerUsed);
412     }
413 }
414
415 #ifdef USING_SCOPE_INFO
416 //------------------------------------------------------------------------
417 // getSiVarLoc: Returns a "siVarLoc" instance representing the place where the variable
418 // is given its description, "baseReg", and "offset" (if needed).
419 //
420 // Arguments:
421 //    varDsc    - a "LclVarDsc *" to the variable it is desired to build the "siVarLoc".
422 //    scope   - a "siScope" Scope info of the variable.
423 //
424 // Return Value:
425 //    A "siVarLoc" filled with the correct case struct fields for the variable, which could live
426 //    in a register, an stack position, or a combination of both.
427 //
428 // Notes:
429 //    Called for each siScope in siScopeList when "genSetScopeInfo".
430 CodeGenInterface::siVarLoc CodeGen::getSiVarLoc(const LclVarDsc* varDsc, const siScope* scope) const
431 {
432     // For stack vars, find the base register, and offset
433
434     regNumber baseReg;
435     signed    offset = varDsc->lvStkOffs;
436
437     if (!varDsc->lvFramePointerBased)
438     {
439         baseReg = REG_SPBASE;
440         offset += scope->scStackLevel;
441     }
442     else
443     {
444         baseReg = REG_FPBASE;
445     }
446
447     return CodeGenInterface::siVarLoc(varDsc, baseReg, offset, isFramePointerUsed());
448 }
449
450 //------------------------------------------------------------------------
451 // getSiVarLoc: Creates a "CodegenInterface::siVarLoc" instance from using the properties
452 // of the "psiScope" instance.
453 //
454 // Notes:
455 //    Called for every psiScope in "psiScopeList" codegen.h
456 CodeGenInterface::siVarLoc CodeGen::psiScope::getSiVarLoc() const
457 {
458     CodeGenInterface::siVarLoc varLoc;
459
460     if (scRegister)
461     {
462         varLoc.vlType       = VLT_REG;
463         varLoc.vlReg.vlrReg = (regNumber)u1.scRegNum;
464     }
465     else
466     {
467         varLoc.vlType           = VLT_STK;
468         varLoc.vlStk.vlsBaseReg = (regNumber)u2.scBaseReg;
469         varLoc.vlStk.vlsOffset  = u2.scOffset;
470     }
471
472     return varLoc;
473 }
474
475 /*============================================================================
476  *
477  *              Implementation for ScopeInfo
478  *
479  *
480  * Whenever a variable comes into scope, add it to the list.
481  * When a varDsc goes dead, end its previous scope entry, and make a new one
482  * which is unavailable.
483  * When a varDsc goes live, end its previous un-available entry (if any) and
484  * set its new entry as available.
485  *
486  *============================================================================
487  */
488
489 /*****************************************************************************
490  *                      siNewScope
491  *
492  * Creates a new scope and adds it to the Open scope list.
493  */
494
495 CodeGen::siScope* CodeGen::siNewScope(unsigned LVnum, unsigned varNum)
496 {
497     bool     tracked  = compiler->lvaTable[varNum].lvTracked;
498     unsigned varIndex = compiler->lvaTable[varNum].lvVarIndex;
499
500     if (tracked)
501     {
502         siEndTrackedScope(varIndex);
503     }
504
505     siScope* newScope = compiler->getAllocator(CMK_SiScope).allocate<siScope>(1);
506
507     newScope->scStartLoc.CaptureLocation(getEmitter());
508     assert(newScope->scStartLoc.Valid());
509
510     newScope->scEndLoc.Init();
511
512     newScope->scLVnum      = LVnum;
513     newScope->scVarNum     = varNum;
514     newScope->scNext       = nullptr;
515     newScope->scStackLevel = genStackLevel; // used only by stack vars
516
517     siOpenScopeLast->scNext = newScope;
518     newScope->scPrev        = siOpenScopeLast;
519     siOpenScopeLast         = newScope;
520
521     if (tracked)
522     {
523         siLatestTrackedScopes[varIndex] = newScope;
524     }
525
526     return newScope;
527 }
528
529 /*****************************************************************************
530  *                          siRemoveFromOpenScopeList
531  *
532  * Removes a scope from the open-scope list and puts it into the done-scope list
533  */
534
535 void CodeGen::siRemoveFromOpenScopeList(CodeGen::siScope* scope)
536 {
537     assert(scope);
538     assert(scope->scEndLoc.Valid());
539
540     // Remove from open-scope list
541
542     scope->scPrev->scNext = scope->scNext;
543     if (scope->scNext)
544     {
545         scope->scNext->scPrev = scope->scPrev;
546     }
547     else
548     {
549         siOpenScopeLast = scope->scPrev;
550     }
551
552     // Add to the finished scope list. (Try to) filter out scopes of length 0.
553
554     if (scope->scStartLoc != scope->scEndLoc)
555     {
556         siScopeLast->scNext = scope;
557         siScopeLast         = scope;
558         siScopeCnt++;
559     }
560 }
561
562 /*----------------------------------------------------------------------------
563  * These functions end scopes given different types of parameters
564  *----------------------------------------------------------------------------
565  */
566
567 /*****************************************************************************
568  * For tracked vars, we don't need to search for the scope in the list as we
569  * have a pointer to the open scopes of all tracked variables.
570  */
571
572 void CodeGen::siEndTrackedScope(unsigned varIndex)
573 {
574     siScope* scope = siLatestTrackedScopes[varIndex];
575     if (!scope)
576     {
577         return;
578     }
579
580     scope->scEndLoc.CaptureLocation(getEmitter());
581     assert(scope->scEndLoc.Valid());
582
583     siRemoveFromOpenScopeList(scope);
584
585     siLatestTrackedScopes[varIndex] = nullptr;
586 }
587
588 /*****************************************************************************
589  * If we don't know that the variable is tracked, this function handles both
590  * cases.
591  */
592
593 void CodeGen::siEndScope(unsigned varNum)
594 {
595     for (siScope* scope = siOpenScopeList.scNext; scope; scope = scope->scNext)
596     {
597         if (scope->scVarNum == varNum)
598         {
599             siEndScope(scope);
600             return;
601         }
602     }
603
604     JITDUMP("siEndScope: Failed to end scope for V%02u\n", varNum);
605
606     // At this point, we probably have a bad LocalVarTab
607     if (compiler->opts.compDbgCode)
608     {
609         JITDUMP("...checking var tab validity\n");
610
611         // Note the following assert is saying that we expect
612         // the VM supplied info to be invalid...
613         assert(!siVerifyLocalVarTab());
614
615         compiler->opts.compScopeInfo = false;
616     }
617 }
618
619 /*****************************************************************************
620  * If we have a handle to the siScope structure, we handle ending this scope
621  * differently than if we just had a variable number. This saves us searching
622  * the open-scope list again.
623  */
624
625 void CodeGen::siEndScope(siScope* scope)
626 {
627     scope->scEndLoc.CaptureLocation(getEmitter());
628     assert(scope->scEndLoc.Valid());
629
630     siRemoveFromOpenScopeList(scope);
631
632     LclVarDsc& lclVarDsc1 = compiler->lvaTable[scope->scVarNum];
633     if (lclVarDsc1.lvTracked)
634     {
635         siLatestTrackedScopes[lclVarDsc1.lvVarIndex] = nullptr;
636     }
637 }
638
639 /*****************************************************************************
640  *                      siVerifyLocalVarTab
641  *
642  * Checks the LocalVarTab for consistency. The VM may not have properly
643  * verified the LocalVariableTable.
644  */
645
646 #ifdef DEBUG
647
648 bool CodeGen::siVerifyLocalVarTab()
649 {
650     // No entries with overlapping lives should have the same slot.
651
652     for (unsigned i = 0; i < compiler->info.compVarScopesCount; i++)
653     {
654         for (unsigned j = i + 1; j < compiler->info.compVarScopesCount; j++)
655         {
656             unsigned slot1 = compiler->info.compVarScopes[i].vsdVarNum;
657             unsigned beg1  = compiler->info.compVarScopes[i].vsdLifeBeg;
658             unsigned end1  = compiler->info.compVarScopes[i].vsdLifeEnd;
659
660             unsigned slot2 = compiler->info.compVarScopes[j].vsdVarNum;
661             unsigned beg2  = compiler->info.compVarScopes[j].vsdLifeBeg;
662             unsigned end2  = compiler->info.compVarScopes[j].vsdLifeEnd;
663
664             if (slot1 == slot2 && (end1 > beg2 && beg1 < end2))
665             {
666                 return false;
667             }
668         }
669     }
670
671     return true;
672 }
673
674 #endif
675
676 /*============================================================================
677  *           INTERFACE (public) Functions for ScopeInfo
678  *============================================================================
679  */
680
681 void CodeGen::siInit()
682 {
683 #ifdef _TARGET_X86_
684     assert((unsigned)ICorDebugInfo::REGNUM_EAX == REG_EAX);
685     assert((unsigned)ICorDebugInfo::REGNUM_ECX == REG_ECX);
686     assert((unsigned)ICorDebugInfo::REGNUM_EDX == REG_EDX);
687     assert((unsigned)ICorDebugInfo::REGNUM_EBX == REG_EBX);
688     assert((unsigned)ICorDebugInfo::REGNUM_ESP == REG_ESP);
689     assert((unsigned)ICorDebugInfo::REGNUM_EBP == REG_EBP);
690     assert((unsigned)ICorDebugInfo::REGNUM_ESI == REG_ESI);
691     assert((unsigned)ICorDebugInfo::REGNUM_EDI == REG_EDI);
692 #endif
693
694     assert((unsigned)ICorDebugInfo::VLT_REG == CodeGenInterface::VLT_REG);
695     assert((unsigned)ICorDebugInfo::VLT_STK == CodeGenInterface::VLT_STK);
696     assert((unsigned)ICorDebugInfo::VLT_REG_REG == CodeGenInterface::VLT_REG_REG);
697     assert((unsigned)ICorDebugInfo::VLT_REG_STK == CodeGenInterface::VLT_REG_STK);
698     assert((unsigned)ICorDebugInfo::VLT_STK_REG == CodeGenInterface::VLT_STK_REG);
699     assert((unsigned)ICorDebugInfo::VLT_STK2 == CodeGenInterface::VLT_STK2);
700     assert((unsigned)ICorDebugInfo::VLT_FPSTK == CodeGenInterface::VLT_FPSTK);
701     assert((unsigned)ICorDebugInfo::VLT_FIXED_VA == CodeGenInterface::VLT_FIXED_VA);
702     assert((unsigned)ICorDebugInfo::VLT_COUNT == CodeGenInterface::VLT_COUNT);
703     assert((unsigned)ICorDebugInfo::VLT_INVALID == CodeGenInterface::VLT_INVALID);
704
705     /* ICorDebugInfo::VarLoc and siVarLoc should overlap exactly as we cast
706      * one to the other in eeSetLVinfo()
707      * Below is a "required but not sufficient" condition
708      */
709
710     assert(sizeof(ICorDebugInfo::VarLoc) == sizeof(CodeGenInterface::siVarLoc));
711
712     assert(compiler->opts.compScopeInfo);
713
714     siOpenScopeList.scNext = nullptr;
715     siOpenScopeLast        = &siOpenScopeList;
716     siScopeLast            = &siScopeList;
717
718     siScopeCnt = 0;
719
720     VarSetOps::AssignNoCopy(compiler, siLastLife, VarSetOps::MakeEmpty(compiler));
721     siLastEndOffs = 0;
722
723     if (compiler->info.compVarScopesCount == 0)
724     {
725         siLatestTrackedScopes = nullptr;
726     }
727     else
728     {
729 #if FEATURE_EH_FUNCLETS
730         siInFuncletRegion = false;
731 #endif // FEATURE_EH_FUNCLETS
732
733         unsigned scopeCount = compiler->lvaTrackedCount;
734
735         if (scopeCount == 0)
736         {
737             siLatestTrackedScopes = nullptr;
738         }
739         else
740         {
741             siLatestTrackedScopes = new (compiler->getAllocator(CMK_SiScope)) siScope* [scopeCount] {};
742         }
743
744         compiler->compResetScopeLists();
745     }
746 }
747
748 /*****************************************************************************
749  *                          siBeginBlock
750  *
751  * Called at the beginning of code-gen for a block. Checks if any scopes
752  * need to be opened.
753  */
754
755 void CodeGen::siBeginBlock(BasicBlock* block)
756 {
757     assert(block != nullptr);
758
759     if (!compiler->opts.compScopeInfo)
760     {
761         return;
762     }
763
764     if (compiler->info.compVarScopesCount == 0)
765     {
766         return;
767     }
768
769 #if FEATURE_EH_FUNCLETS
770     if (siInFuncletRegion)
771     {
772         return;
773     }
774
775     if (block->bbFlags & BBF_FUNCLET_BEG)
776     {
777         // For now, don't report any scopes in funclets. JIT64 doesn't.
778         siInFuncletRegion = true;
779
780         JITDUMP("Scope info: found beginning of funclet region at block " FMT_BB "; ignoring following blocks\n",
781                 block->bbNum);
782
783         return;
784     }
785 #endif // FEATURE_EH_FUNCLETS
786
787 #ifdef DEBUG
788     if (verbose)
789     {
790         printf("\nScope info: begin block " FMT_BB ", IL range ", block->bbNum);
791         block->dspBlockILRange();
792         printf("\n");
793     }
794 #endif // DEBUG
795
796     unsigned beginOffs = block->bbCodeOffs;
797
798     if (beginOffs == BAD_IL_OFFSET)
799     {
800         JITDUMP("Scope info: ignoring block beginning\n");
801         return;
802     }
803
804     // If we have tracked locals, use liveness to update the debug state.
805     //
806     // Note: we can improve on this some day -- if there are any tracked
807     // locals, untracked locals will fail to be reported.
808     if (compiler->lvaTrackedCount > 0)
809     {
810         // End scope of variables which are not live for this block
811         siUpdate();
812
813         // Check that vars which are live on entry have an open scope
814         VarSetOps::Iter iter(compiler, block->bbLiveIn);
815         unsigned        varIndex = 0;
816         while (iter.NextElem(&varIndex))
817         {
818             unsigned varNum = compiler->lvaTrackedToVarNum[varIndex];
819             // lvRefCnt may go down to 0 after liveness-analysis.
820             // So we need to check if this tracked variable is actually used.
821             if (!compiler->lvaTable[varNum].lvIsInReg() && !compiler->lvaTable[varNum].lvOnFrame)
822             {
823                 assert(compiler->lvaTable[varNum].lvRefCnt() == 0);
824                 continue;
825             }
826
827             siCheckVarScope(varNum, beginOffs);
828         }
829     }
830     else
831     {
832         // There aren't any tracked locals.
833         //
834         // For debuggable or minopts code, scopes can begin only on block boundaries.
835         // For other codegen modes (eg minopts/tier0) we currently won't report any
836         // untracked locals.
837         if (compiler->opts.OptimizationDisabled())
838         {
839             // Check if there are any scopes on the current block's start boundary.
840             VarScopeDsc* varScope = nullptr;
841
842 #if FEATURE_EH_FUNCLETS
843
844             // If we find a spot where the code offset isn't what we expect, because
845             // there is a gap, it might be because we've moved the funclets out of
846             // line. Catch up with the enter and exit scopes of the current block.
847             // Ignore the enter/exit scope changes of the missing scopes, which for
848             // funclets must be matched.
849             if (siLastEndOffs != beginOffs)
850             {
851                 assert(beginOffs > 0);
852                 assert(siLastEndOffs < beginOffs);
853
854                 JITDUMP("Scope info: found offset hole. lastOffs=%u, currOffs=%u\n", siLastEndOffs, beginOffs);
855
856                 // Skip enter scopes
857                 while ((varScope = compiler->compGetNextEnterScope(beginOffs - 1, true)) != nullptr)
858                 {
859                     /* do nothing */
860                     JITDUMP("Scope info: skipping enter scope, LVnum=%u\n", varScope->vsdLVnum);
861                 }
862
863                 // Skip exit scopes
864                 while ((varScope = compiler->compGetNextExitScope(beginOffs - 1, true)) != nullptr)
865                 {
866                     /* do nothing */
867                     JITDUMP("Scope info: skipping exit scope, LVnum=%u\n", varScope->vsdLVnum);
868                 }
869             }
870
871 #else // FEATURE_EH_FUNCLETS
872
873             if (siLastEndOffs != beginOffs)
874             {
875                 assert(siLastEndOffs < beginOffs);
876                 return;
877             }
878
879 #endif // FEATURE_EH_FUNCLETS
880
881             while ((varScope = compiler->compGetNextEnterScope(beginOffs)) != nullptr)
882             {
883                 LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varScope->vsdVarNum];
884
885                 // Only report locals that were referenced, if we're not doing debug codegen
886                 if (compiler->opts.compDbgCode || (lclVarDsc1->lvRefCnt() > 0))
887                 {
888                     // brace-matching editor workaround for following line: (
889                     JITDUMP("Scope info: opening scope, LVnum=%u [%03X..%03X)\n", varScope->vsdLVnum,
890                             varScope->vsdLifeBeg, varScope->vsdLifeEnd);
891
892                     siNewScope(varScope->vsdLVnum, varScope->vsdVarNum);
893
894 #ifdef DEBUG
895                     if (VERBOSE)
896                     {
897                         printf("Scope info: >> new scope, VarNum=%u, tracked? %s, VarIndex=%u, bbLiveIn=%s ",
898                                varScope->vsdVarNum, lclVarDsc1->lvTracked ? "yes" : "no", lclVarDsc1->lvVarIndex,
899                                VarSetOps::ToString(compiler, block->bbLiveIn));
900                         dumpConvertedVarSet(compiler, block->bbLiveIn);
901                         printf("\n");
902                     }
903                     assert(!lclVarDsc1->lvTracked ||
904                            VarSetOps::IsMember(compiler, block->bbLiveIn, lclVarDsc1->lvVarIndex));
905 #endif // DEBUG
906                 }
907                 else
908                 {
909                     JITDUMP("Skipping open scope for V%02u, unreferenced\n", varScope->vsdVarNum);
910                 }
911             }
912         }
913     }
914
915 #ifdef DEBUG
916     if (verbose)
917     {
918         siDispOpenScopes();
919     }
920 #endif
921 }
922
923 /*****************************************************************************
924  *                          siEndBlock
925  *
926  * Called at the end of code-gen for a block. Any closing scopes are marked
927  * as such. Note that if we are collecting LocalVar info, scopes can
928  * only begin or end at block boundaries for debuggable code.
929  */
930
931 void CodeGen::siEndBlock(BasicBlock* block)
932 {
933     assert(compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0));
934
935 #if FEATURE_EH_FUNCLETS
936     if (siInFuncletRegion)
937     {
938         return;
939     }
940 #endif // FEATURE_EH_FUNCLETS
941
942 #ifdef DEBUG
943     if (verbose)
944     {
945         printf("\nScope info: end block " FMT_BB ", IL range ", block->bbNum);
946         block->dspBlockILRange();
947         printf("\n");
948     }
949 #endif // DEBUG
950
951     unsigned endOffs = block->bbCodeOffsEnd;
952
953     if (endOffs == BAD_IL_OFFSET)
954     {
955         JITDUMP("Scope info: ignoring block end\n");
956         return;
957     }
958
959     // If non-debuggable code, find all scopes which end over this block
960     // and close them. For debuggable code, scopes will only end on block
961     // boundaries.
962
963     VarScopeDsc* varScope;
964     while ((varScope = compiler->compGetNextExitScope(endOffs, !compiler->opts.compDbgCode)) != nullptr)
965     {
966         // brace-matching editor workaround for following line: (
967         JITDUMP("Scope info: ending scope, LVnum=%u [%03X..%03X)\n", varScope->vsdLVnum, varScope->vsdLifeBeg,
968                 varScope->vsdLifeEnd);
969
970         unsigned   varNum     = varScope->vsdVarNum;
971         LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varNum];
972
973         assert(lclVarDsc1);
974
975         if (lclVarDsc1->lvTracked)
976         {
977             siEndTrackedScope(lclVarDsc1->lvVarIndex);
978         }
979         else
980         {
981             siEndScope(varNum);
982         }
983     }
984
985     siLastEndOffs = endOffs;
986
987 #ifdef DEBUG
988     if (verbose)
989     {
990         siDispOpenScopes();
991     }
992 #endif
993 }
994
995 //------------------------------------------------------------------------
996 // siUpdate: Closes the "ScopeInfo" of the tracked variables that has become dead.
997 //
998 // Notes:
999 //    Called at the start of basic blocks, and during code-gen of a block,
1000 //    for non-debuggable code, whenever the life of any tracked variable changes
1001 //    and the appropriate code has been generated. For debuggable code, variables are
1002 //    live over their entire scope, and so they go live or dead only on
1003 //    block boundaries.
1004 void CodeGen::siUpdate()
1005 {
1006     if (!compiler->opts.compScopeInfo)
1007     {
1008         return;
1009     }
1010
1011     if (compiler->opts.compDbgCode)
1012     {
1013         return;
1014     }
1015
1016     if (compiler->info.compVarScopesCount == 0)
1017     {
1018         return;
1019     }
1020
1021 #if FEATURE_EH_FUNCLETS
1022     if (siInFuncletRegion)
1023     {
1024         return;
1025     }
1026 #endif // FEATURE_EH_FUNCLETS
1027
1028     VARSET_TP killed(VarSetOps::Diff(compiler, siLastLife, compiler->compCurLife));
1029     assert(VarSetOps::IsSubset(compiler, killed, compiler->lvaTrackedVars));
1030
1031     VarSetOps::Iter iter(compiler, killed);
1032     unsigned        varIndex = 0;
1033     while (iter.NextElem(&varIndex))
1034     {
1035 #ifdef DEBUG
1036         unsigned   lclNum = compiler->lvaTrackedToVarNum[varIndex];
1037         LclVarDsc* lclVar = &compiler->lvaTable[lclNum];
1038         assert(lclVar->lvTracked);
1039 #endif
1040         siEndTrackedScope(varIndex);
1041     }
1042
1043     VarSetOps::Assign(compiler, siLastLife, compiler->compCurLife);
1044 }
1045
1046 /*****************************************************************************
1047  *                          siCheckVarScope
1048  *
1049  * For non-debuggable code, whenever we come across a GenTree which is an
1050  * assignment to a local variable, this function is called to check if the
1051  * variable has an open scope. Also, check if it has the correct LVnum.
1052  */
1053
1054 void CodeGen::siCheckVarScope(unsigned varNum, IL_OFFSET offs)
1055 {
1056     assert(compiler->opts.compScopeInfo && !compiler->opts.compDbgCode && (compiler->info.compVarScopesCount > 0));
1057
1058 #if FEATURE_EH_FUNCLETS
1059     if (siInFuncletRegion)
1060     {
1061         return;
1062     }
1063 #endif // FEATURE_EH_FUNCLETS
1064
1065     if (offs == BAD_IL_OFFSET)
1066     {
1067         return;
1068     }
1069
1070     siScope*   scope;
1071     LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varNum];
1072
1073     // If there is an open scope corresponding to varNum, find it
1074
1075     if (lclVarDsc1->lvTracked)
1076     {
1077         scope = siLatestTrackedScopes[lclVarDsc1->lvVarIndex];
1078     }
1079     else
1080     {
1081         for (scope = siOpenScopeList.scNext; scope; scope = scope->scNext)
1082         {
1083             if (scope->scVarNum == varNum)
1084             {
1085                 break;
1086             }
1087         }
1088     }
1089
1090     // Look up the compiler->info.compVarScopes[] to find the local var info for (varNum->lvSlotNum, offs)
1091     VarScopeDsc* varScope = compiler->compFindLocalVar(varNum, offs);
1092     if (varScope == nullptr)
1093     {
1094         return;
1095     }
1096
1097     // If the currently open scope does not have the correct LVnum, close it
1098     // and create a new scope with this new LVnum
1099
1100     if (scope)
1101     {
1102         if (scope->scLVnum != varScope->vsdLVnum)
1103         {
1104             siEndScope(scope);
1105             siNewScope(varScope->vsdLVnum, varScope->vsdVarNum);
1106         }
1107     }
1108     else
1109     {
1110         siNewScope(varScope->vsdLVnum, varScope->vsdVarNum);
1111     }
1112 }
1113
1114 /*****************************************************************************
1115  *                          siCloseAllOpenScopes
1116  *
1117  * For unreachable code, or optimized code with blocks reordered, there may be
1118  * scopes left open at the end. Simply close them.
1119  */
1120
1121 void CodeGen::siCloseAllOpenScopes()
1122 {
1123     assert(siOpenScopeList.scNext);
1124
1125     while (siOpenScopeList.scNext)
1126     {
1127         siEndScope(siOpenScopeList.scNext);
1128     }
1129 }
1130
1131 /*****************************************************************************
1132  *                          siDispOpenScopes
1133  *
1134  * Displays all the vars on the open-scope list
1135  */
1136
1137 #ifdef DEBUG
1138
1139 void CodeGen::siDispOpenScopes()
1140 {
1141     assert(compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0));
1142
1143     printf("Scope info: open scopes =\n");
1144
1145     if (siOpenScopeList.scNext == nullptr)
1146     {
1147         printf("   <none>\n");
1148     }
1149     else
1150     {
1151         for (siScope* scope = siOpenScopeList.scNext; scope != nullptr; scope = scope->scNext)
1152         {
1153             VarScopeDsc* localVars = compiler->info.compVarScopes;
1154
1155             for (unsigned i = 0; i < compiler->info.compVarScopesCount; i++, localVars++)
1156             {
1157                 if (localVars->vsdLVnum == scope->scLVnum)
1158                 {
1159                     const char* name = compiler->VarNameToStr(localVars->vsdName);
1160                     // brace-matching editor workaround for following line: (
1161                     printf("   %u (%s) [%03X..%03X)\n", localVars->vsdLVnum, name == nullptr ? "UNKNOWN" : name,
1162                            localVars->vsdLifeBeg, localVars->vsdLifeEnd);
1163                     break;
1164                 }
1165             }
1166         }
1167     }
1168 }
1169
1170 #endif // DEBUG
1171
1172 /*============================================================================
1173  *
1174  *              Implementation for PrologScopeInfo
1175  *
1176  *============================================================================
1177  */
1178
1179 /*****************************************************************************
1180  *                      psiNewPrologScope
1181  *
1182  * Creates a new scope and adds it to the Open scope list.
1183  */
1184
1185 CodeGen::psiScope* CodeGen::psiNewPrologScope(unsigned LVnum, unsigned slotNum)
1186 {
1187     psiScope* newScope = compiler->getAllocator(CMK_SiScope).allocate<psiScope>(1);
1188
1189     newScope->scStartLoc.CaptureLocation(getEmitter());
1190     assert(newScope->scStartLoc.Valid());
1191
1192     newScope->scEndLoc.Init();
1193
1194     newScope->scLVnum   = LVnum;
1195     newScope->scSlotNum = slotNum;
1196
1197     newScope->scNext         = nullptr;
1198     psiOpenScopeLast->scNext = newScope;
1199     newScope->scPrev         = psiOpenScopeLast;
1200     psiOpenScopeLast         = newScope;
1201
1202     return newScope;
1203 }
1204
1205 /*****************************************************************************
1206  *                          psiEndPrologScope
1207  *
1208  * Remove the scope from the Open-scope list and add it to the finished-scopes
1209  * list if its length is non-zero
1210  */
1211
1212 void CodeGen::psiEndPrologScope(psiScope* scope)
1213 {
1214     scope->scEndLoc.CaptureLocation(getEmitter());
1215     assert(scope->scEndLoc.Valid());
1216
1217     // Remove from open-scope list
1218     scope->scPrev->scNext = scope->scNext;
1219     if (scope->scNext)
1220     {
1221         scope->scNext->scPrev = scope->scPrev;
1222     }
1223     else
1224     {
1225         psiOpenScopeLast = scope->scPrev;
1226     }
1227
1228     // Add to the finished scope list.
1229     // If the length is zero, it means that the prolog is empty. In that case,
1230     // CodeGen::genSetScopeInfo will report the liveness of all arguments
1231     // as spanning the first instruction in the method, so that they can
1232     // at least be inspected on entry to the method.
1233     if (scope->scStartLoc != scope->scEndLoc || scope->scStartLoc.IsOffsetZero())
1234     {
1235         psiScopeLast->scNext = scope;
1236         psiScopeLast         = scope;
1237         psiScopeCnt++;
1238     }
1239 }
1240
1241 /*============================================================================
1242  *           INTERFACE (protected) Functions for PrologScopeInfo
1243  *============================================================================
1244  */
1245
1246 //------------------------------------------------------------------------
1247 // psSetScopeOffset: Set the offset of the newScope to the offset of the LslVar
1248 //
1249 // Arguments:
1250 //    'newScope'  the new scope object whose offset is to be set to the lclVarDsc offset.
1251 //    'lclVarDsc' is an op that will now be contained by its parent.
1252 //
1253 //
1254 void CodeGen::psSetScopeOffset(psiScope* newScope, LclVarDsc* lclVarDsc)
1255 {
1256     newScope->scRegister   = false;
1257     newScope->u2.scBaseReg = REG_SPBASE;
1258
1259 #ifdef _TARGET_AMD64_
1260     // scOffset = offset from caller SP - REGSIZE_BYTES
1261     // TODO-Cleanup - scOffset needs to be understood.  For now just matching with the existing definition.
1262     newScope->u2.scOffset =
1263         compiler->lvaToCallerSPRelativeOffset(lclVarDsc->lvStkOffs, lclVarDsc->lvFramePointerBased) + REGSIZE_BYTES;
1264 #else  // !_TARGET_AMD64_
1265     if (doubleAlignOrFramePointerUsed())
1266     {
1267         // REGSIZE_BYTES - for the pushed value of EBP
1268         newScope->u2.scOffset = lclVarDsc->lvStkOffs - REGSIZE_BYTES;
1269     }
1270     else
1271     {
1272         newScope->u2.scOffset = lclVarDsc->lvStkOffs - genTotalFrameSize();
1273     }
1274 #endif // !_TARGET_AMD64_
1275 }
1276
1277 /*============================================================================
1278 *           INTERFACE (public) Functions for PrologScopeInfo
1279 *============================================================================
1280 */
1281
1282 /*****************************************************************************
1283  *                          psiBegProlog
1284  *
1285  * Initializes the PrologScopeInfo, and creates open scopes for all the
1286  * parameters of the method.
1287  */
1288
1289 void CodeGen::psiBegProlog()
1290 {
1291     assert(compiler->compGeneratingProlog);
1292
1293     VarScopeDsc* varScope;
1294
1295     psiOpenScopeList.scNext = nullptr;
1296     psiOpenScopeLast        = &psiOpenScopeList;
1297     psiScopeLast            = &psiScopeList;
1298     psiScopeCnt             = 0;
1299
1300     compiler->compResetScopeLists();
1301
1302     while ((varScope = compiler->compGetNextEnterScope(0)) != nullptr)
1303     {
1304         LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varScope->vsdVarNum];
1305
1306         if (!lclVarDsc1->lvIsParam)
1307         {
1308             continue;
1309         }
1310
1311         psiScope* newScope = psiNewPrologScope(varScope->vsdLVnum, varScope->vsdVarNum);
1312
1313         if (lclVarDsc1->lvIsRegArg)
1314         {
1315             bool isStructHandled = false;
1316 #if defined(UNIX_AMD64_ABI)
1317             SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
1318             if (varTypeIsStruct(lclVarDsc1))
1319             {
1320                 CORINFO_CLASS_HANDLE typeHnd = lclVarDsc1->lvVerTypeInfo.GetClassHandle();
1321                 assert(typeHnd != nullptr);
1322                 compiler->eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
1323                 if (structDesc.passedInRegisters)
1324                 {
1325                     regNumber regNum      = REG_NA;
1326                     regNumber otherRegNum = REG_NA;
1327                     for (unsigned nCnt = 0; nCnt < structDesc.eightByteCount; nCnt++)
1328                     {
1329                         unsigned  len     = structDesc.eightByteSizes[nCnt];
1330                         var_types regType = TYP_UNDEF;
1331
1332                         if (nCnt == 0)
1333                         {
1334                             regNum = lclVarDsc1->lvArgReg;
1335                         }
1336                         else if (nCnt == 1)
1337                         {
1338                             otherRegNum = lclVarDsc1->lvOtherArgReg;
1339                         }
1340                         else
1341                         {
1342                             assert(false && "Invalid eightbyte number.");
1343                         }
1344
1345                         regType = compiler->GetEightByteType(structDesc, nCnt);
1346 #ifdef DEBUG
1347                         regType = compiler->mangleVarArgsType(regType);
1348                         assert(genMapRegNumToRegArgNum((nCnt == 0 ? regNum : otherRegNum), regType) != (unsigned)-1);
1349 #endif // DEBUG
1350                     }
1351
1352                     newScope->scRegister    = true;
1353                     newScope->u1.scRegNum   = (regNumberSmall)regNum;
1354                     newScope->u1.scOtherReg = (regNumberSmall)otherRegNum;
1355                 }
1356                 else
1357                 {
1358                     // Stack passed argument. Get the offset from the  caller's frame.
1359                     psSetScopeOffset(newScope, lclVarDsc1);
1360                 }
1361
1362                 isStructHandled = true;
1363             }
1364 #endif // !defined(UNIX_AMD64_ABI)
1365             if (!isStructHandled)
1366             {
1367 #ifdef DEBUG
1368                 var_types regType = compiler->mangleVarArgsType(lclVarDsc1->TypeGet());
1369                 if (lclVarDsc1->lvIsHfaRegArg())
1370                 {
1371                     regType = lclVarDsc1->GetHfaType();
1372                 }
1373                 assert(genMapRegNumToRegArgNum(lclVarDsc1->lvArgReg, regType) != (unsigned)-1);
1374 #endif // DEBUG
1375
1376                 newScope->scRegister  = true;
1377                 newScope->u1.scRegNum = (regNumberSmall)lclVarDsc1->lvArgReg;
1378             }
1379         }
1380         else
1381         {
1382             psSetScopeOffset(newScope, lclVarDsc1);
1383         }
1384     }
1385 }
1386
1387 /*****************************************************************************
1388  Enable this macro to get accurate prolog information for every instruction
1389  in the prolog. However, this is overkill as nobody steps through the
1390  disassembly of the prolog. Even if they do they will not expect rich debug info.
1391
1392  We still report all the arguments at the very start of the method so that
1393  the user can see the arguments at the very start of the method (offset=0).
1394
1395  Disabling this decreased the debug maps in mscorlib by 10% (01/2003)
1396  */
1397
1398 #if 0
1399 #define ACCURATE_PROLOG_DEBUG_INFO
1400 #endif
1401
1402 /*****************************************************************************
1403  *                          psiAdjustStackLevel
1404  *
1405  * When ESP changes, all scopes relative to ESP have to be updated.
1406  */
1407
1408 void CodeGen::psiAdjustStackLevel(unsigned size)
1409 {
1410     if (!compiler->opts.compScopeInfo || (compiler->info.compVarScopesCount == 0))
1411     {
1412         return;
1413     }
1414
1415     assert(compiler->compGeneratingProlog);
1416
1417 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1418
1419     psiScope* scope;
1420
1421     // walk the list backwards
1422     // Works as psiEndPrologScope does not change scPrev
1423     for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1424     {
1425         if (scope->scRegister)
1426         {
1427             assert(compiler->lvaTable[scope->scSlotNum].lvIsRegArg);
1428             continue;
1429         }
1430         assert(scope->u2.scBaseReg == REG_SPBASE);
1431
1432         psiScope* newScope     = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1433         newScope->scRegister   = false;
1434         newScope->u2.scBaseReg = REG_SPBASE;
1435         newScope->u2.scOffset  = scope->u2.scOffset + size;
1436
1437         psiEndPrologScope(scope);
1438     }
1439
1440 #endif // ACCURATE_PROLOG_DEBUG_INFO
1441 }
1442
1443 /*****************************************************************************
1444  *                          psiMoveESPtoEBP
1445  *
1446  * For EBP-frames, the parameters are accessed via ESP on entry to the function,
1447  * but via EBP right after a "mov ebp,esp" instruction
1448  */
1449
1450 void CodeGen::psiMoveESPtoEBP()
1451 {
1452     if (!compiler->opts.compScopeInfo || (compiler->info.compVarScopesCount == 0))
1453     {
1454         return;
1455     }
1456
1457     assert(compiler->compGeneratingProlog);
1458     assert(doubleAlignOrFramePointerUsed());
1459
1460 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1461
1462     psiScope* scope;
1463
1464     // walk the list backwards
1465     // Works as psiEndPrologScope does not change scPrev
1466     for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1467     {
1468         if (scope->scRegister)
1469         {
1470             assert(compiler->lvaTable[scope->scSlotNum].lvIsRegArg);
1471             continue;
1472         }
1473         assert(scope->u2.scBaseReg == REG_SPBASE);
1474
1475         psiScope* newScope     = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1476         newScope->scRegister   = false;
1477         newScope->u2.scBaseReg = REG_FPBASE;
1478         newScope->u2.scOffset  = scope->u2.scOffset;
1479
1480         psiEndPrologScope(scope);
1481     }
1482
1483 #endif // ACCURATE_PROLOG_DEBUG_INFO
1484 }
1485
1486 /*****************************************************************************
1487  *                          psiMoveToReg
1488  *
1489  * Called when a parameter is loaded into its assigned register from the stack,
1490  * or when parameters are moved around due to circular dependancy.
1491  * If reg != REG_NA, then the parameter is being moved into its assigned
1492  * register, else it may be being moved to a temp register.
1493  */
1494
1495 void CodeGen::psiMoveToReg(unsigned varNum, regNumber reg, regNumber otherReg)
1496 {
1497     assert(compiler->compGeneratingProlog);
1498
1499     if (!compiler->opts.compScopeInfo)
1500     {
1501         return;
1502     }
1503
1504     if (compiler->info.compVarScopesCount == 0)
1505     {
1506         return;
1507     }
1508
1509     assert((int)varNum >= 0); // It's not a spill temp number.
1510     assert(compiler->lvaTable[varNum].lvIsInReg());
1511
1512 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1513
1514     /* If reg!=REG_NA, the parameter is part of a cirular dependancy, and is
1515      * being moved through temp register "reg".
1516      * If reg==REG_NA, it is being moved to its assigned register.
1517      */
1518     if (reg == REG_NA)
1519     {
1520         // Grab the assigned registers.
1521
1522         reg      = compiler->lvaTable[varNum].lvRegNum;
1523         otherReg = compiler->lvaTable[varNum].lvOtherReg;
1524     }
1525
1526     psiScope* scope;
1527
1528     // walk the list backwards
1529     // Works as psiEndPrologScope does not change scPrev
1530     for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1531     {
1532         if (scope->scSlotNum != compiler->lvaTable[varNum].lvSlotNum)
1533             continue;
1534
1535         psiScope* newScope      = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1536         newScope->scRegister    = true;
1537         newScope->u1.scRegNum   = reg;
1538         newScope->u1.scOtherReg = otherReg;
1539
1540         psiEndPrologScope(scope);
1541         return;
1542     }
1543
1544     // May happen if a parameter does not have an entry in the LocalVarTab
1545     // But assert() just in case it is because of something else.
1546     assert(varNum == compiler->info.compRetBuffArg ||
1547            !"Parameter scope not found (Assert doesnt always indicate error)");
1548
1549 #endif // ACCURATE_PROLOG_DEBUG_INFO
1550 }
1551
1552 /*****************************************************************************
1553  *                      CodeGen::psiMoveToStack
1554  *
1555  * A incoming register-argument is being moved to its final home on the stack
1556  * (ie. all adjustments to {F/S}PBASE have been made
1557  */
1558
1559 void CodeGen::psiMoveToStack(unsigned varNum)
1560 {
1561     if (!compiler->opts.compScopeInfo || (compiler->info.compVarScopesCount == 0))
1562     {
1563         return;
1564     }
1565
1566     assert(compiler->compGeneratingProlog);
1567     assert(compiler->lvaTable[varNum].lvIsRegArg);
1568     assert(!compiler->lvaTable[varNum].lvRegister);
1569
1570 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1571
1572     psiScope* scope;
1573
1574     // walk the list backwards
1575     // Works as psiEndPrologScope does not change scPrev
1576     for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1577     {
1578         if (scope->scSlotNum != compiler->lvaTable[varNum].lvSlotNum)
1579             continue;
1580
1581         /* The param must be currently sitting in the register in which it
1582            was passed in */
1583         assert(scope->scRegister);
1584         assert(scope->u1.scRegNum == compiler->lvaTable[varNum].lvArgReg);
1585
1586         psiScope* newScope     = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1587         newScope->scRegister   = false;
1588         newScope->u2.scBaseReg = (compiler->lvaTable[varNum].lvFramePointerBased) ? REG_FPBASE : REG_SPBASE;
1589         newScope->u2.scOffset  = compiler->lvaTable[varNum].lvStkOffs;
1590
1591         psiEndPrologScope(scope);
1592         return;
1593     }
1594
1595     // May happen if a parameter does not have an entry in the LocalVarTab
1596     // But assert() just in case it is because of something else.
1597     assert(varNum == compiler->info.compRetBuffArg ||
1598            !"Parameter scope not found (Assert doesnt always indicate error)");
1599
1600 #endif // ACCURATE_PROLOG_DEBUG_INFO
1601 }
1602
1603 /*****************************************************************************
1604  *                          psiEndProlog
1605  */
1606
1607 void CodeGen::psiEndProlog()
1608 {
1609     assert(compiler->compGeneratingProlog);
1610     psiScope* scope;
1611
1612     for (scope = psiOpenScopeList.scNext; scope; scope = psiOpenScopeList.scNext)
1613     {
1614         psiEndPrologScope(scope);
1615     }
1616 }
1617 #endif // USING_SCOPE_INFO