Fix reading Time zone rules using Julian days (#17672)
[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 genChangeLife() 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 Compiler::siVarLoc::vlIsInReg(regNumber reg)
62 {
63     switch (vlType)
64     {
65         case VLT_REG:
66             return (vlReg.vlrReg == reg);
67         case VLT_REG_REG:
68             return ((vlRegReg.vlrrReg1 == reg) || (vlRegReg.vlrrReg2 == reg));
69         case VLT_REG_STK:
70             return (vlRegStk.vlrsReg == reg);
71         case VLT_STK_REG:
72             return (vlStkReg.vlsrReg == reg);
73
74         case VLT_STK:
75         case VLT_STK2:
76         case VLT_FPSTK:
77             return false;
78
79         default:
80             assert(!"Bad locType");
81             return false;
82     }
83 }
84
85 bool Compiler::siVarLoc::vlIsOnStk(regNumber reg, signed offset)
86 {
87     regNumber actualReg;
88
89     switch (vlType)
90     {
91
92         case 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 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 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 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 VLT_REG:
122         case VLT_REG_FP:
123         case VLT_REG_REG:
124         case VLT_FPSTK:
125             return false;
126
127         default:
128             assert(!"Bad locType");
129             return false;
130     }
131 }
132
133 /*============================================================================
134  *
135  *              Implementation for ScopeInfo
136  *
137  *
138  * Whenever a variable comes into scope, add it to the list.
139  * When a varDsc goes dead, end its previous scope entry, and make a new one
140  * which is unavailable.
141  * When a varDsc goes live, end its previous un-available entry (if any) and
142  * set its new entry as available.
143  *
144  *============================================================================
145  */
146
147 /*****************************************************************************
148  *                      siNewScope
149  *
150  * Creates a new scope and adds it to the Open scope list.
151  */
152
153 CodeGen::siScope* CodeGen::siNewScope(unsigned LVnum, unsigned varNum)
154 {
155     bool     tracked  = compiler->lvaTable[varNum].lvTracked;
156     unsigned varIndex = compiler->lvaTable[varNum].lvVarIndex;
157
158     if (tracked)
159     {
160         siEndTrackedScope(varIndex);
161     }
162
163     siScope* newScope = (siScope*)compiler->compGetMem(sizeof(*newScope), CMK_SiScope);
164
165     newScope->scStartLoc.CaptureLocation(getEmitter());
166     assert(newScope->scStartLoc.Valid());
167
168     newScope->scEndLoc.Init();
169
170     newScope->scLVnum      = LVnum;
171     newScope->scVarNum     = varNum;
172     newScope->scNext       = nullptr;
173     newScope->scStackLevel = genStackLevel; // used only by stack vars
174
175     siOpenScopeLast->scNext = newScope;
176     newScope->scPrev        = siOpenScopeLast;
177     siOpenScopeLast         = newScope;
178
179     if (tracked)
180     {
181         siLatestTrackedScopes[varIndex] = newScope;
182     }
183
184     return newScope;
185 }
186
187 /*****************************************************************************
188  *                          siRemoveFromOpenScopeList
189  *
190  * Removes a scope from the open-scope list and puts it into the done-scope list
191  */
192
193 void CodeGen::siRemoveFromOpenScopeList(CodeGen::siScope* scope)
194 {
195     assert(scope);
196     assert(scope->scEndLoc.Valid());
197
198     // Remove from open-scope list
199
200     scope->scPrev->scNext = scope->scNext;
201     if (scope->scNext)
202     {
203         scope->scNext->scPrev = scope->scPrev;
204     }
205     else
206     {
207         siOpenScopeLast = scope->scPrev;
208     }
209
210     // Add to the finished scope list. (Try to) filter out scopes of length 0.
211
212     if (scope->scStartLoc != scope->scEndLoc)
213     {
214         siScopeLast->scNext = scope;
215         siScopeLast         = scope;
216         siScopeCnt++;
217     }
218 }
219
220 /*----------------------------------------------------------------------------
221  * These functions end scopes given different types of parameters
222  *----------------------------------------------------------------------------
223  */
224
225 /*****************************************************************************
226  * For tracked vars, we don't need to search for the scope in the list as we
227  * have a pointer to the open scopes of all tracked variables.
228  */
229
230 void CodeGen::siEndTrackedScope(unsigned varIndex)
231 {
232     siScope* scope = siLatestTrackedScopes[varIndex];
233     if (!scope)
234     {
235         return;
236     }
237
238     scope->scEndLoc.CaptureLocation(getEmitter());
239     assert(scope->scEndLoc.Valid());
240
241     siRemoveFromOpenScopeList(scope);
242
243     siLatestTrackedScopes[varIndex] = nullptr;
244 }
245
246 /*****************************************************************************
247  * If we don't know that the variable is tracked, this function handles both
248  * cases.
249  */
250
251 void CodeGen::siEndScope(unsigned varNum)
252 {
253     for (siScope* scope = siOpenScopeList.scNext; scope; scope = scope->scNext)
254     {
255         if (scope->scVarNum == varNum)
256         {
257             siEndScope(scope);
258             return;
259         }
260     }
261
262     // At this point, we probably have a bad LocalVarTab
263
264     if (compiler->opts.compDbgCode)
265     {
266         // LocalVarTab is good?? If we reached here implies that we are in a
267         // bad state, so pretend that we don't have any scope info.
268         assert(!siVerifyLocalVarTab());
269
270         compiler->opts.compScopeInfo = false;
271     }
272 }
273
274 /*****************************************************************************
275  * If we have a handle to the siScope structure, we handle ending this scope
276  * differently than if we just had a variable number. This saves us searching
277  * the open-scope list again.
278  */
279
280 void CodeGen::siEndScope(siScope* scope)
281 {
282     scope->scEndLoc.CaptureLocation(getEmitter());
283     assert(scope->scEndLoc.Valid());
284
285     siRemoveFromOpenScopeList(scope);
286
287     LclVarDsc& lclVarDsc1 = compiler->lvaTable[scope->scVarNum];
288     if (lclVarDsc1.lvTracked)
289     {
290         siLatestTrackedScopes[lclVarDsc1.lvVarIndex] = nullptr;
291     }
292 }
293
294 /*****************************************************************************
295  *                      siVerifyLocalVarTab
296  *
297  * Checks the LocalVarTab for consistency. The VM may not have properly
298  * verified the LocalVariableTable.
299  */
300
301 #ifdef DEBUG
302
303 bool CodeGen::siVerifyLocalVarTab()
304 {
305     // No entries with overlapping lives should have the same slot.
306
307     for (unsigned i = 0; i < compiler->info.compVarScopesCount; i++)
308     {
309         for (unsigned j = i + 1; j < compiler->info.compVarScopesCount; j++)
310         {
311             unsigned slot1 = compiler->info.compVarScopes[i].vsdVarNum;
312             unsigned beg1  = compiler->info.compVarScopes[i].vsdLifeBeg;
313             unsigned end1  = compiler->info.compVarScopes[i].vsdLifeEnd;
314
315             unsigned slot2 = compiler->info.compVarScopes[j].vsdVarNum;
316             unsigned beg2  = compiler->info.compVarScopes[j].vsdLifeBeg;
317             unsigned end2  = compiler->info.compVarScopes[j].vsdLifeEnd;
318
319             if (slot1 == slot2 && (end1 > beg2 && beg1 < end2))
320             {
321                 return false;
322             }
323         }
324     }
325
326     return true;
327 }
328
329 #endif
330
331 /*============================================================================
332  *           INTERFACE (public) Functions for ScopeInfo
333  *============================================================================
334  */
335
336 void CodeGen::siInit()
337 {
338 #ifdef _TARGET_X86_
339     assert((unsigned)ICorDebugInfo::REGNUM_EAX == REG_EAX);
340     assert((unsigned)ICorDebugInfo::REGNUM_ECX == REG_ECX);
341     assert((unsigned)ICorDebugInfo::REGNUM_EDX == REG_EDX);
342     assert((unsigned)ICorDebugInfo::REGNUM_EBX == REG_EBX);
343     assert((unsigned)ICorDebugInfo::REGNUM_ESP == REG_ESP);
344     assert((unsigned)ICorDebugInfo::REGNUM_EBP == REG_EBP);
345     assert((unsigned)ICorDebugInfo::REGNUM_ESI == REG_ESI);
346     assert((unsigned)ICorDebugInfo::REGNUM_EDI == REG_EDI);
347 #endif
348
349     assert((unsigned)ICorDebugInfo::VLT_REG == Compiler::VLT_REG);
350     assert((unsigned)ICorDebugInfo::VLT_STK == Compiler::VLT_STK);
351     assert((unsigned)ICorDebugInfo::VLT_REG_REG == Compiler::VLT_REG_REG);
352     assert((unsigned)ICorDebugInfo::VLT_REG_STK == Compiler::VLT_REG_STK);
353     assert((unsigned)ICorDebugInfo::VLT_STK_REG == Compiler::VLT_STK_REG);
354     assert((unsigned)ICorDebugInfo::VLT_STK2 == Compiler::VLT_STK2);
355     assert((unsigned)ICorDebugInfo::VLT_FPSTK == Compiler::VLT_FPSTK);
356     assert((unsigned)ICorDebugInfo::VLT_FIXED_VA == Compiler::VLT_FIXED_VA);
357     assert((unsigned)ICorDebugInfo::VLT_COUNT == Compiler::VLT_COUNT);
358     assert((unsigned)ICorDebugInfo::VLT_INVALID == Compiler::VLT_INVALID);
359
360     /* ICorDebugInfo::VarLoc and siVarLoc should overlap exactly as we cast
361      * one to the other in eeSetLVinfo()
362      * Below is a "required but not sufficient" condition
363      */
364
365     assert(sizeof(ICorDebugInfo::VarLoc) == sizeof(Compiler::siVarLoc));
366
367     assert(compiler->opts.compScopeInfo);
368
369     siOpenScopeList.scNext = nullptr;
370     siOpenScopeLast        = &siOpenScopeList;
371     siScopeLast            = &siScopeList;
372
373     siScopeCnt = 0;
374
375     VarSetOps::AssignNoCopy(compiler, siLastLife, VarSetOps::MakeEmpty(compiler));
376     siLastEndOffs = 0;
377
378     if (compiler->info.compVarScopesCount == 0)
379     {
380         return;
381     }
382
383 #if FEATURE_EH_FUNCLETS
384     siInFuncletRegion = false;
385 #endif // FEATURE_EH_FUNCLETS
386
387     for (unsigned i = 0; i < lclMAX_TRACKED; i++)
388     {
389         siLatestTrackedScopes[i] = nullptr;
390     }
391
392     compiler->compResetScopeLists();
393 }
394
395 /*****************************************************************************
396  *                          siBeginBlock
397  *
398  * Called at the beginning of code-gen for a block. Checks if any scopes
399  * need to be opened.
400  */
401
402 void CodeGen::siBeginBlock(BasicBlock* block)
403 {
404     assert(block != nullptr);
405
406     if (!compiler->opts.compScopeInfo)
407     {
408         return;
409     }
410
411     if (compiler->info.compVarScopesCount == 0)
412     {
413         return;
414     }
415
416 #if FEATURE_EH_FUNCLETS
417     if (siInFuncletRegion)
418     {
419         return;
420     }
421
422     if (block->bbFlags & BBF_FUNCLET_BEG)
423     {
424         // For now, don't report any scopes in funclets. JIT64 doesn't.
425         siInFuncletRegion = true;
426
427         JITDUMP("Scope info: found beginning of funclet region at block BB%02u; ignoring following blocks\n",
428                 block->bbNum);
429
430         return;
431     }
432 #endif // FEATURE_EH_FUNCLETS
433
434 #ifdef DEBUG
435     if (verbose)
436     {
437         printf("\nScope info: begin block BB%02u, IL range ", block->bbNum);
438         block->dspBlockILRange();
439         printf("\n");
440     }
441 #endif // DEBUG
442
443     unsigned beginOffs = block->bbCodeOffs;
444
445     if (beginOffs == BAD_IL_OFFSET)
446     {
447         JITDUMP("Scope info: ignoring block beginning\n");
448         return;
449     }
450
451     if (!compiler->opts.compDbgCode)
452     {
453         /* For non-debuggable code */
454
455         // End scope of variables which are not live for this block
456
457         siUpdate();
458
459         // Check that vars which are live on entry have an open scope
460
461         VarSetOps::Iter iter(compiler, block->bbLiveIn);
462         unsigned        varIndex = 0;
463         while (iter.NextElem(&varIndex))
464         {
465             unsigned varNum = compiler->lvaTrackedToVarNum[varIndex];
466             // lvRefCnt may go down to 0 after liveness-analysis.
467             // So we need to check if this tracked variable is actually used.
468             if (!compiler->lvaTable[varNum].lvIsInReg() && !compiler->lvaTable[varNum].lvOnFrame)
469             {
470                 assert(compiler->lvaTable[varNum].lvRefCnt == 0);
471                 continue;
472             }
473
474             siCheckVarScope(varNum, beginOffs);
475         }
476     }
477     else
478     {
479         // For debuggable code, scopes can begin only on block boundaries.
480         // Check if there are any scopes on the current block's start boundary.
481
482         VarScopeDsc* varScope;
483
484 #if FEATURE_EH_FUNCLETS
485
486         // If we find a spot where the code offset isn't what we expect, because
487         // there is a gap, it might be because we've moved the funclets out of
488         // line. Catch up with the enter and exit scopes of the current block.
489         // Ignore the enter/exit scope changes of the missing scopes, which for
490         // funclets must be matched.
491
492         if (siLastEndOffs != beginOffs)
493         {
494             assert(beginOffs > 0);
495             assert(siLastEndOffs < beginOffs);
496
497             JITDUMP("Scope info: found offset hole. lastOffs=%u, currOffs=%u\n", siLastEndOffs, beginOffs);
498
499             // Skip enter scopes
500             while ((varScope = compiler->compGetNextEnterScope(beginOffs - 1, true)) != nullptr)
501             {
502                 /* do nothing */
503                 JITDUMP("Scope info: skipping enter scope, LVnum=%u\n", varScope->vsdLVnum);
504             }
505
506             // Skip exit scopes
507             while ((varScope = compiler->compGetNextExitScope(beginOffs - 1, true)) != nullptr)
508             {
509                 /* do nothing */
510                 JITDUMP("Scope info: skipping exit scope, LVnum=%u\n", varScope->vsdLVnum);
511             }
512         }
513
514 #else // FEATURE_EH_FUNCLETS
515
516         if (siLastEndOffs != beginOffs)
517         {
518             assert(siLastEndOffs < beginOffs);
519             return;
520         }
521
522 #endif // FEATURE_EH_FUNCLETS
523
524         while ((varScope = compiler->compGetNextEnterScope(beginOffs)) != nullptr)
525         {
526             // brace-matching editor workaround for following line: (
527             JITDUMP("Scope info: opening scope, LVnum=%u [%03X..%03X)\n", varScope->vsdLVnum, varScope->vsdLifeBeg,
528                     varScope->vsdLifeEnd);
529
530             siNewScope(varScope->vsdLVnum, varScope->vsdVarNum);
531
532 #ifdef DEBUG
533             LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varScope->vsdVarNum];
534             if (VERBOSE)
535             {
536                 printf("Scope info: >> new scope, VarNum=%u, tracked? %s, VarIndex=%u, bbLiveIn=%s ",
537                        varScope->vsdVarNum, lclVarDsc1->lvTracked ? "yes" : "no", lclVarDsc1->lvVarIndex,
538                        VarSetOps::ToString(compiler, block->bbLiveIn));
539                 dumpConvertedVarSet(compiler, block->bbLiveIn);
540                 printf("\n");
541             }
542             assert(!lclVarDsc1->lvTracked || VarSetOps::IsMember(compiler, block->bbLiveIn, lclVarDsc1->lvVarIndex));
543 #endif // DEBUG
544         }
545     }
546
547 #ifdef DEBUG
548     if (verbose)
549     {
550         siDispOpenScopes();
551     }
552 #endif
553 }
554
555 /*****************************************************************************
556  *                          siEndBlock
557  *
558  * Called at the end of code-gen for a block. Any closing scopes are marked
559  * as such. Note that if we are collecting LocalVar info, scopes can
560  * only begin or end at block boundaries for debuggable code.
561  */
562
563 void CodeGen::siEndBlock(BasicBlock* block)
564 {
565     assert(compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0));
566
567 #if FEATURE_EH_FUNCLETS
568     if (siInFuncletRegion)
569     {
570         return;
571     }
572 #endif // FEATURE_EH_FUNCLETS
573
574 #ifdef DEBUG
575     if (verbose)
576     {
577         printf("\nScope info: end block BB%02u, IL range ", block->bbNum);
578         block->dspBlockILRange();
579         printf("\n");
580     }
581 #endif // DEBUG
582
583     unsigned endOffs = block->bbCodeOffsEnd;
584
585     if (endOffs == BAD_IL_OFFSET)
586     {
587         JITDUMP("Scope info: ignoring block end\n");
588         return;
589     }
590
591     // If non-debuggable code, find all scopes which end over this block
592     // and close them. For debuggable code, scopes will only end on block
593     // boundaries.
594
595     VarScopeDsc* varScope;
596     while ((varScope = compiler->compGetNextExitScope(endOffs, !compiler->opts.compDbgCode)) != nullptr)
597     {
598         // brace-matching editor workaround for following line: (
599         JITDUMP("Scope info: ending scope, LVnum=%u [%03X..%03X)\n", varScope->vsdLVnum, varScope->vsdLifeBeg,
600                 varScope->vsdLifeEnd);
601
602         unsigned   varNum     = varScope->vsdVarNum;
603         LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varNum];
604
605         assert(lclVarDsc1);
606
607         if (lclVarDsc1->lvTracked)
608         {
609             siEndTrackedScope(lclVarDsc1->lvVarIndex);
610         }
611         else
612         {
613             siEndScope(varNum);
614         }
615     }
616
617     siLastEndOffs = endOffs;
618
619 #ifdef DEBUG
620     if (verbose)
621     {
622         siDispOpenScopes();
623     }
624 #endif
625 }
626
627 /*****************************************************************************
628  *                          siUpdate
629  *
630  * Called at the start of basic blocks, and during code-gen of a block,
631  * for non-debuggable code, whenever the life of any tracked variable changes
632  * and the appropriate code has been generated. For debuggable code, variables are
633  * live over their entire scope, and so they go live or dead only on
634  * block boundaries.
635  */
636 void CodeGen::siUpdate()
637 {
638     if (!compiler->opts.compScopeInfo)
639     {
640         return;
641     }
642
643     if (compiler->opts.compDbgCode)
644     {
645         return;
646     }
647
648     if (compiler->info.compVarScopesCount == 0)
649     {
650         return;
651     }
652
653 #if FEATURE_EH_FUNCLETS
654     if (siInFuncletRegion)
655     {
656         return;
657     }
658 #endif // FEATURE_EH_FUNCLETS
659
660     VARSET_TP killed(VarSetOps::Diff(compiler, siLastLife, compiler->compCurLife));
661     assert(VarSetOps::IsSubset(compiler, killed, compiler->lvaTrackedVars));
662
663     VarSetOps::Iter iter(compiler, killed);
664     unsigned        varIndex = 0;
665     while (iter.NextElem(&varIndex))
666     {
667 #ifdef DEBUG
668         unsigned   lclNum = compiler->lvaTrackedToVarNum[varIndex];
669         LclVarDsc* lclVar = &compiler->lvaTable[lclNum];
670         assert(lclVar->lvTracked);
671 #endif
672
673         siScope* scope = siLatestTrackedScopes[varIndex];
674         siEndTrackedScope(varIndex);
675     }
676
677     VarSetOps::Assign(compiler, siLastLife, compiler->compCurLife);
678 }
679
680 /*****************************************************************************
681  *  In optimized code, we may not have access to gtLclVar.gtLclILoffs.
682  *  So there may be ambiguity as to which entry in compiler->info.compVarScopes
683  *  to use. We search the entire table and find the entry whose life
684  *  begins closest to the given offset.
685  */
686
687 /*****************************************************************************
688  *                          siCheckVarScope
689  *
690  * For non-debuggable code, whenever we come across a GenTree which is an
691  * assignment to a local variable, this function is called to check if the
692  * variable has an open scope. Also, check if it has the correct LVnum.
693  */
694
695 void CodeGen::siCheckVarScope(unsigned varNum, IL_OFFSET offs)
696 {
697     assert(compiler->opts.compScopeInfo && !compiler->opts.compDbgCode && (compiler->info.compVarScopesCount > 0));
698
699 #if FEATURE_EH_FUNCLETS
700     if (siInFuncletRegion)
701     {
702         return;
703     }
704 #endif // FEATURE_EH_FUNCLETS
705
706     if (offs == BAD_IL_OFFSET)
707     {
708         return;
709     }
710
711     siScope*   scope;
712     LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varNum];
713
714     // If there is an open scope corresponding to varNum, find it
715
716     if (lclVarDsc1->lvTracked)
717     {
718         scope = siLatestTrackedScopes[lclVarDsc1->lvVarIndex];
719     }
720     else
721     {
722         for (scope = siOpenScopeList.scNext; scope; scope = scope->scNext)
723         {
724             if (scope->scVarNum == varNum)
725             {
726                 break;
727             }
728         }
729     }
730
731     // Look up the compiler->info.compVarScopes[] to find the local var info for (varNum->lvSlotNum, offs)
732     VarScopeDsc* varScope = compiler->compFindLocalVar(varNum, offs);
733     if (varScope == nullptr)
734     {
735         return;
736     }
737
738     // If the currently open scope does not have the correct LVnum, close it
739     // and create a new scope with this new LVnum
740
741     if (scope)
742     {
743         if (scope->scLVnum != varScope->vsdLVnum)
744         {
745             siEndScope(scope);
746             siNewScope(varScope->vsdLVnum, varScope->vsdVarNum);
747         }
748     }
749     else
750     {
751         siNewScope(varScope->vsdLVnum, varScope->vsdVarNum);
752     }
753 }
754
755 /*****************************************************************************
756  *                          siCloseAllOpenScopes
757  *
758  * For unreachable code, or optimized code with blocks reordered, there may be
759  * scopes left open at the end. Simply close them.
760  */
761
762 void CodeGen::siCloseAllOpenScopes()
763 {
764     assert(siOpenScopeList.scNext);
765
766     while (siOpenScopeList.scNext)
767     {
768         siEndScope(siOpenScopeList.scNext);
769     }
770 }
771
772 /*****************************************************************************
773  *                          siDispOpenScopes
774  *
775  * Displays all the vars on the open-scope list
776  */
777
778 #ifdef DEBUG
779
780 void CodeGen::siDispOpenScopes()
781 {
782     assert(compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0));
783
784     printf("Scope info: open scopes =\n");
785
786     if (siOpenScopeList.scNext == nullptr)
787     {
788         printf("   <none>\n");
789     }
790     else
791     {
792         for (siScope* scope = siOpenScopeList.scNext; scope != nullptr; scope = scope->scNext)
793         {
794             VarScopeDsc* localVars = compiler->info.compVarScopes;
795
796             for (unsigned i = 0; i < compiler->info.compVarScopesCount; i++, localVars++)
797             {
798                 if (localVars->vsdLVnum == scope->scLVnum)
799                 {
800                     const char* name = compiler->VarNameToStr(localVars->vsdName);
801                     // brace-matching editor workaround for following line: (
802                     printf("   %u (%s) [%03X..%03X)\n", localVars->vsdLVnum, name == nullptr ? "UNKNOWN" : name,
803                            localVars->vsdLifeBeg, localVars->vsdLifeEnd);
804                     break;
805                 }
806             }
807         }
808     }
809 }
810
811 #endif // DEBUG
812
813 /*============================================================================
814  *
815  *              Implementation for PrologScopeInfo
816  *
817  *============================================================================
818  */
819
820 /*****************************************************************************
821  *                      psiNewPrologScope
822  *
823  * Creates a new scope and adds it to the Open scope list.
824  */
825
826 CodeGen::psiScope* CodeGen::psiNewPrologScope(unsigned LVnum, unsigned slotNum)
827 {
828     psiScope* newScope = (psiScope*)compiler->compGetMem(sizeof(*newScope), CMK_SiScope);
829
830     newScope->scStartLoc.CaptureLocation(getEmitter());
831     assert(newScope->scStartLoc.Valid());
832
833     newScope->scEndLoc.Init();
834
835     newScope->scLVnum   = LVnum;
836     newScope->scSlotNum = slotNum;
837
838     newScope->scNext         = nullptr;
839     psiOpenScopeLast->scNext = newScope;
840     newScope->scPrev         = psiOpenScopeLast;
841     psiOpenScopeLast         = newScope;
842
843     return newScope;
844 }
845
846 /*****************************************************************************
847  *                          psiEndPrologScope
848  *
849  * Remove the scope from the Open-scope list and add it to the finished-scopes
850  * list if its length is non-zero
851  */
852
853 void CodeGen::psiEndPrologScope(psiScope* scope)
854 {
855     scope->scEndLoc.CaptureLocation(getEmitter());
856     assert(scope->scEndLoc.Valid());
857
858     // Remove from open-scope list
859     scope->scPrev->scNext = scope->scNext;
860     if (scope->scNext)
861     {
862         scope->scNext->scPrev = scope->scPrev;
863     }
864     else
865     {
866         psiOpenScopeLast = scope->scPrev;
867     }
868
869     // Add to the finished scope list.
870     // If the length is zero, it means that the prolog is empty. In that case,
871     // CodeGen::genSetScopeInfo will report the liveness of all arguments
872     // as spanning the first instruction in the method, so that they can
873     // at least be inspected on entry to the method.
874     if (scope->scStartLoc != scope->scEndLoc || scope->scStartLoc.IsOffsetZero())
875     {
876         psiScopeLast->scNext = scope;
877         psiScopeLast         = scope;
878         psiScopeCnt++;
879     }
880 }
881
882 /*============================================================================
883  *           INTERFACE (protected) Functions for PrologScopeInfo
884  *============================================================================
885  */
886
887 //------------------------------------------------------------------------
888 // psSetScopeOffset: Set the offset of the newScope to the offset of the LslVar
889 //
890 // Arguments:
891 //    'newScope'  the new scope object whose offset is to be set to the lclVarDsc offset.
892 //    'lclVarDsc' is an op that will now be contained by its parent.
893 //
894 //
895 void CodeGen::psSetScopeOffset(psiScope* newScope, LclVarDsc* lclVarDsc)
896 {
897     newScope->scRegister   = false;
898     newScope->u2.scBaseReg = REG_SPBASE;
899
900 #ifdef _TARGET_AMD64_
901     // scOffset = offset from caller SP - REGSIZE_BYTES
902     // TODO-Cleanup - scOffset needs to be understood.  For now just matching with the existing definition.
903     newScope->u2.scOffset =
904         compiler->lvaToCallerSPRelativeOffset(lclVarDsc->lvStkOffs, lclVarDsc->lvFramePointerBased) + REGSIZE_BYTES;
905 #else  // !_TARGET_AMD64_
906     if (doubleAlignOrFramePointerUsed())
907     {
908         // REGSIZE_BYTES - for the pushed value of EBP
909         newScope->u2.scOffset = lclVarDsc->lvStkOffs - REGSIZE_BYTES;
910     }
911     else
912     {
913         newScope->u2.scOffset = lclVarDsc->lvStkOffs - genTotalFrameSize();
914     }
915 #endif // !_TARGET_AMD64_
916 }
917
918 /*============================================================================
919 *           INTERFACE (public) Functions for PrologScopeInfo
920 *============================================================================
921 */
922
923 /*****************************************************************************
924  *                          psiBegProlog
925  *
926  * Initializes the PrologScopeInfo, and creates open scopes for all the
927  * parameters of the method.
928  */
929
930 void CodeGen::psiBegProlog()
931 {
932     assert(compiler->compGeneratingProlog);
933
934     VarScopeDsc* varScope;
935
936     psiOpenScopeList.scNext = nullptr;
937     psiOpenScopeLast        = &psiOpenScopeList;
938     psiScopeLast            = &psiScopeList;
939     psiScopeCnt             = 0;
940
941     compiler->compResetScopeLists();
942
943     while ((varScope = compiler->compGetNextEnterScope(0)) != nullptr)
944     {
945         LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varScope->vsdVarNum];
946
947         if (!lclVarDsc1->lvIsParam)
948         {
949             continue;
950         }
951
952         psiScope* newScope = psiNewPrologScope(varScope->vsdLVnum, varScope->vsdVarNum);
953
954         if (lclVarDsc1->lvIsRegArg)
955         {
956             bool isStructHandled = false;
957 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
958             SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
959             if (varTypeIsStruct(lclVarDsc1))
960             {
961                 CORINFO_CLASS_HANDLE typeHnd = lclVarDsc1->lvVerTypeInfo.GetClassHandle();
962                 assert(typeHnd != nullptr);
963                 compiler->eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
964                 if (structDesc.passedInRegisters)
965                 {
966                     regNumber regNum      = REG_NA;
967                     regNumber otherRegNum = REG_NA;
968                     for (unsigned nCnt = 0; nCnt < structDesc.eightByteCount; nCnt++)
969                     {
970                         unsigned  len     = structDesc.eightByteSizes[nCnt];
971                         var_types regType = TYP_UNDEF;
972
973                         if (nCnt == 0)
974                         {
975                             regNum = lclVarDsc1->lvArgReg;
976                         }
977                         else if (nCnt == 1)
978                         {
979                             otherRegNum = lclVarDsc1->lvOtherArgReg;
980                         }
981                         else
982                         {
983                             assert(false && "Invalid eightbyte number.");
984                         }
985
986                         regType = compiler->GetEightByteType(structDesc, nCnt);
987 #ifdef DEBUG
988                         regType = compiler->mangleVarArgsType(regType);
989                         assert(genMapRegNumToRegArgNum((nCnt == 0 ? regNum : otherRegNum), regType) != (unsigned)-1);
990 #endif // DEBUG
991                     }
992
993                     newScope->scRegister    = true;
994                     newScope->u1.scRegNum   = (regNumberSmall)regNum;
995                     newScope->u1.scOtherReg = (regNumberSmall)otherRegNum;
996                 }
997                 else
998                 {
999                     // Stack passed argument. Get the offset from the  caller's frame.
1000                     psSetScopeOffset(newScope, lclVarDsc1);
1001                 }
1002
1003                 isStructHandled = true;
1004             }
1005 #endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1006             if (!isStructHandled)
1007             {
1008 #ifdef DEBUG
1009                 var_types regType = compiler->mangleVarArgsType(lclVarDsc1->TypeGet());
1010                 if (lclVarDsc1->lvIsHfaRegArg())
1011                 {
1012                     regType = lclVarDsc1->GetHfaType();
1013                 }
1014                 assert(genMapRegNumToRegArgNum(lclVarDsc1->lvArgReg, regType) != (unsigned)-1);
1015 #endif // DEBUG
1016
1017                 newScope->scRegister  = true;
1018                 newScope->u1.scRegNum = (regNumberSmall)lclVarDsc1->lvArgReg;
1019             }
1020         }
1021         else
1022         {
1023             psSetScopeOffset(newScope, lclVarDsc1);
1024         }
1025     }
1026 }
1027
1028 /*****************************************************************************
1029  Enable this macro to get accurate prolog information for every instruction
1030  in the prolog. However, this is overkill as nobody steps through the
1031  disassembly of the prolog. Even if they do they will not expect rich debug info.
1032
1033  We still report all the arguments at the very start of the method so that
1034  the user can see the arguments at the very start of the method (offset=0).
1035
1036  Disabling this decreased the debug maps in mscorlib by 10% (01/2003)
1037  */
1038
1039 #if 0
1040 #define ACCURATE_PROLOG_DEBUG_INFO
1041 #endif
1042
1043 /*****************************************************************************
1044  *                          psiAdjustStackLevel
1045  *
1046  * When ESP changes, all scopes relative to ESP have to be updated.
1047  */
1048
1049 void CodeGen::psiAdjustStackLevel(unsigned size)
1050 {
1051     if (!compiler->opts.compScopeInfo || (compiler->info.compVarScopesCount == 0))
1052     {
1053         return;
1054     }
1055
1056     assert(compiler->compGeneratingProlog);
1057
1058 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1059
1060     psiScope* scope;
1061
1062     // walk the list backwards
1063     // Works as psiEndPrologScope does not change scPrev
1064     for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1065     {
1066         if (scope->scRegister)
1067         {
1068             assert(compiler->lvaTable[scope->scSlotNum].lvIsRegArg);
1069             continue;
1070         }
1071         assert(scope->u2.scBaseReg == REG_SPBASE);
1072
1073         psiScope* newScope     = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1074         newScope->scRegister   = false;
1075         newScope->u2.scBaseReg = REG_SPBASE;
1076         newScope->u2.scOffset  = scope->u2.scOffset + size;
1077
1078         psiEndPrologScope(scope);
1079     }
1080
1081 #endif // ACCURATE_PROLOG_DEBUG_INFO
1082 }
1083
1084 /*****************************************************************************
1085  *                          psiMoveESPtoEBP
1086  *
1087  * For EBP-frames, the parameters are accessed via ESP on entry to the function,
1088  * but via EBP right after a "mov ebp,esp" instruction
1089  */
1090
1091 void CodeGen::psiMoveESPtoEBP()
1092 {
1093     if (!compiler->opts.compScopeInfo || (compiler->info.compVarScopesCount == 0))
1094     {
1095         return;
1096     }
1097
1098     assert(compiler->compGeneratingProlog);
1099     assert(doubleAlignOrFramePointerUsed());
1100
1101 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1102
1103     psiScope* scope;
1104
1105     // walk the list backwards
1106     // Works as psiEndPrologScope does not change scPrev
1107     for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1108     {
1109         if (scope->scRegister)
1110         {
1111             assert(compiler->lvaTable[scope->scSlotNum].lvIsRegArg);
1112             continue;
1113         }
1114         assert(scope->u2.scBaseReg == REG_SPBASE);
1115
1116         psiScope* newScope     = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1117         newScope->scRegister   = false;
1118         newScope->u2.scBaseReg = REG_FPBASE;
1119         newScope->u2.scOffset  = scope->u2.scOffset;
1120
1121         psiEndPrologScope(scope);
1122     }
1123
1124 #endif // ACCURATE_PROLOG_DEBUG_INFO
1125 }
1126
1127 /*****************************************************************************
1128  *                          psiMoveToReg
1129  *
1130  * Called when a parameter is loaded into its assigned register from the stack,
1131  * or when parameters are moved around due to circular dependancy.
1132  * If reg != REG_NA, then the parameter is being moved into its assigned
1133  * register, else it may be being moved to a temp register.
1134  */
1135
1136 void CodeGen::psiMoveToReg(unsigned varNum, regNumber reg, regNumber otherReg)
1137 {
1138     assert(compiler->compGeneratingProlog);
1139
1140     if (!compiler->opts.compScopeInfo)
1141     {
1142         return;
1143     }
1144
1145     if (compiler->info.compVarScopesCount == 0)
1146     {
1147         return;
1148     }
1149
1150     assert((int)varNum >= 0); // It's not a spill temp number.
1151     assert(compiler->lvaTable[varNum].lvIsInReg());
1152
1153 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1154
1155     /* If reg!=REG_NA, the parameter is part of a cirular dependancy, and is
1156      * being moved through temp register "reg".
1157      * If reg==REG_NA, it is being moved to its assigned register.
1158      */
1159     if (reg == REG_NA)
1160     {
1161         // Grab the assigned registers.
1162
1163         reg      = compiler->lvaTable[varNum].lvRegNum;
1164         otherReg = compiler->lvaTable[varNum].lvOtherReg;
1165     }
1166
1167     psiScope* scope;
1168
1169     // walk the list backwards
1170     // Works as psiEndPrologScope does not change scPrev
1171     for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1172     {
1173         if (scope->scSlotNum != compiler->lvaTable[varNum].lvSlotNum)
1174             continue;
1175
1176         psiScope* newScope      = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1177         newScope->scRegister    = true;
1178         newScope->u1.scRegNum   = reg;
1179         newScope->u1.scOtherReg = otherReg;
1180
1181         psiEndPrologScope(scope);
1182         return;
1183     }
1184
1185     // May happen if a parameter does not have an entry in the LocalVarTab
1186     // But assert() just in case it is because of something else.
1187     assert(varNum == compiler->info.compRetBuffArg ||
1188            !"Parameter scope not found (Assert doesnt always indicate error)");
1189
1190 #endif // ACCURATE_PROLOG_DEBUG_INFO
1191 }
1192
1193 /*****************************************************************************
1194  *                      CodeGen::psiMoveToStack
1195  *
1196  * A incoming register-argument is being moved to its final home on the stack
1197  * (ie. all adjustements to {F/S}PBASE have been made
1198  */
1199
1200 void CodeGen::psiMoveToStack(unsigned varNum)
1201 {
1202     if (!compiler->opts.compScopeInfo || (compiler->info.compVarScopesCount == 0))
1203     {
1204         return;
1205     }
1206
1207     assert(compiler->compGeneratingProlog);
1208     assert(compiler->lvaTable[varNum].lvIsRegArg);
1209     assert(!compiler->lvaTable[varNum].lvRegister);
1210
1211 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1212
1213     psiScope* scope;
1214
1215     // walk the list backwards
1216     // Works as psiEndPrologScope does not change scPrev
1217     for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1218     {
1219         if (scope->scSlotNum != compiler->lvaTable[varNum].lvSlotNum)
1220             continue;
1221
1222         /* The param must be currently sitting in the register in which it
1223            was passed in */
1224         assert(scope->scRegister);
1225         assert(scope->u1.scRegNum == compiler->lvaTable[varNum].lvArgReg);
1226
1227         psiScope* newScope     = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1228         newScope->scRegister   = false;
1229         newScope->u2.scBaseReg = (compiler->lvaTable[varNum].lvFramePointerBased) ? REG_FPBASE : REG_SPBASE;
1230         newScope->u2.scOffset  = compiler->lvaTable[varNum].lvStkOffs;
1231
1232         psiEndPrologScope(scope);
1233         return;
1234     }
1235
1236     // May happen if a parameter does not have an entry in the LocalVarTab
1237     // But assert() just in case it is because of something else.
1238     assert(varNum == compiler->info.compRetBuffArg ||
1239            !"Parameter scope not found (Assert doesnt always indicate error)");
1240
1241 #endif // ACCURATE_PROLOG_DEBUG_INFO
1242 }
1243
1244 /*****************************************************************************
1245  *                          psiEndProlog
1246  */
1247
1248 void CodeGen::psiEndProlog()
1249 {
1250     assert(compiler->compGeneratingProlog);
1251     psiScope* scope;
1252
1253     for (scope = psiOpenScopeList.scNext; scope; scope = psiOpenScopeList.scNext)
1254     {
1255         psiEndPrologScope(scope);
1256     }
1257 }