1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/irstate.d, _irstate.d)
9  * Documentation: https://dlang.org/phobos/dmd_irstate.html
10  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/irstate.d
11  */
12 
13 module dmd.irstate;
14 
15 import dmd.root.array;
16 
17 import dmd.arraytypes;
18 import dmd.backend.type;
19 import dmd.dclass;
20 import dmd.dmodule;
21 import dmd.dsymbol;
22 import dmd.func;
23 import dmd.identifier;
24 import dmd.statement;
25 import dmd.globals;
26 import dmd.mtype;
27 
28 import dmd.backend.cc;
29 import dmd.backend.el;
30 
31 /****************************************
32  * Our label symbol, with vector to keep track of forward references.
33  */
34 
35 struct Label
36 {
37     block *lblock;      // The block to which the label is defined.
38     block *fwdrefs;     // The first use of the label before it is defined.
39 }
40 
41 /***********************************************************
42  */
43 struct IRState
44 {
45     IRState* prev;
46     Statement statement;
47     Module m;                       // module
48     private FuncDeclaration symbol; // function that code is being generate for
49     Identifier ident;
50     Symbol* shidden;                // hidden parameter to function
51     Symbol* sthis;                  // 'this' parameter to function (member and nested)
52     Symbol* sclosure;               // pointer to closure instance
53     Blockx* blx;
54     Dsymbols* deferToObj;           // array of Dsymbol's to run toObjFile(bool multiobj) on later
55     elem* ehidden;                  // transmit hidden pointer to CallExp::toElem()
56     Symbol* startaddress;
57     Array!(elem*)* varsInScope;     // variables that are in scope that will need destruction later
58     Label*[void*]* labels;          // table of labels used/declared in function
59     const Param* params;            // command line parameters
60     bool mayThrow;                  // the expression being evaluated may throw
61 
62     block* breakBlock;
63     block* contBlock;
64     block* switchBlock;
65     block* defaultBlock;
66     block* finallyBlock;
67 
68     this(IRState* irs, Statement s)
69     {
70         prev = irs;
71         statement = s;
72         if (irs)
73         {
74             m = irs.m;
75             shidden = irs.shidden;
76             sclosure = irs.sclosure;
77             sthis = irs.sthis;
78             blx = irs.blx;
79             deferToObj = irs.deferToObj;
80             varsInScope = irs.varsInScope;
81             labels = irs.labels;
82             params = irs.params;
83             mayThrow = irs.mayThrow;
84         }
85     }
86 
87     this(Module m, FuncDeclaration fd, Array!(elem*)* varsInScope, Dsymbols* deferToObj, Label*[void*]* labels,
88         const Param* params)
89     {
90         this.m = m;
91         this.symbol = fd;
92         this.varsInScope = varsInScope;
93         this.deferToObj = deferToObj;
94         this.labels = labels;
95         this.params = params;
96         mayThrow = global.params.useExceptions
97             && ClassDeclaration.throwable
98             && !(fd && fd.eh_none);
99     }
100 
101     /****
102      * Access labels AA from C++ code.
103      * Params:
104      *  s = key
105      * Returns:
106      *  pointer to value if it's there, null if not
107      */
108     Label** lookupLabel(Statement s)
109     {
110         return cast(void*)s in *labels;
111     }
112 
113     /****
114      * Access labels AA from C++ code.
115      * Params:
116      *  s = key
117      *  label = value
118      */
119     void insertLabel(Statement s, Label* label)
120     {
121         (*labels)[cast(void*)s] = label;
122     }
123 
124     block* getBreakBlock(Identifier ident)
125     {
126         IRState* bc;
127         if (ident)
128         {
129             Statement related = null;
130             block* ret = null;
131             for (bc = &this; bc; bc = bc.prev)
132             {
133                 // The label for a breakBlock may actually be some levels up (e.g.
134                 // on a try/finally wrapping a loop). We'll see if this breakBlock
135                 // is the one to return once we reach that outer statement (which
136                 // in many cases will be this same statement).
137                 if (bc.breakBlock)
138                 {
139                     related = bc.statement.getRelatedLabeled();
140                     ret = bc.breakBlock;
141                 }
142                 if (bc.statement == related && bc.prev.ident == ident)
143                     return ret;
144             }
145         }
146         else
147         {
148             for (bc = &this; bc; bc = bc.prev)
149             {
150                 if (bc.breakBlock)
151                     return bc.breakBlock;
152             }
153         }
154         return null;
155     }
156 
157     block* getContBlock(Identifier ident)
158     {
159         IRState* bc;
160         if (ident)
161         {
162             block* ret = null;
163             for (bc = &this; bc; bc = bc.prev)
164             {
165                 // The label for a contBlock may actually be some levels up (e.g.
166                 // on a try/finally wrapping a loop). We'll see if this contBlock
167                 // is the one to return once we reach that outer statement (which
168                 // in many cases will be this same statement).
169                 if (bc.contBlock)
170                 {
171                     ret = bc.contBlock;
172                 }
173                 if (bc.prev && bc.prev.ident == ident)
174                     return ret;
175             }
176         }
177         else
178         {
179             for (bc = &this; bc; bc = bc.prev)
180             {
181                 if (bc.contBlock)
182                     return bc.contBlock;
183             }
184         }
185         return null;
186     }
187 
188     block* getSwitchBlock()
189     {
190         IRState* bc;
191         for (bc = &this; bc; bc = bc.prev)
192         {
193             if (bc.switchBlock)
194                 return bc.switchBlock;
195         }
196         return null;
197     }
198 
199     block* getDefaultBlock()
200     {
201         IRState* bc;
202         for (bc = &this; bc; bc = bc.prev)
203         {
204             if (bc.defaultBlock)
205                 return bc.defaultBlock;
206         }
207         return null;
208     }
209 
210     block* getFinallyBlock()
211     {
212         IRState* bc;
213         for (bc = &this; bc; bc = bc.prev)
214         {
215             if (bc.finallyBlock)
216                 return bc.finallyBlock;
217         }
218         return null;
219     }
220 
221     FuncDeclaration getFunc()
222     {
223         for (auto bc = &this; 1; bc = bc.prev)
224         {
225             if (!bc.prev)
226                 return bc.symbol;
227         }
228     }
229 
230     /**********************
231      * Returns:
232      *    true if do array bounds checking for the current function
233      */
234     bool arrayBoundsCheck()
235     {
236         bool result;
237         final switch (global.params.useArrayBounds)
238         {
239         case CHECKENABLE.off:
240             result = false;
241             break;
242         case CHECKENABLE.on:
243             result = true;
244             break;
245         case CHECKENABLE.safeonly:
246             {
247                 result = false;
248                 FuncDeclaration fd = getFunc();
249                 if (fd)
250                 {
251                     Type t = fd.type;
252                     if (t.ty == Tfunction && (cast(TypeFunction)t).trust == TRUST.safe)
253                         result = true;
254                 }
255                 break;
256             }
257         case CHECKENABLE._default:
258             assert(0);
259         }
260         return result;
261     }
262 
263     /****************************
264      * Returns:
265      *  true if in a nothrow section of code
266      */
267     bool isNothrow()
268     {
269         return !mayThrow;
270     }
271 }
Suggestion Box / Bug Report