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 }