1 /* Digital Mars DMDScript source code. 2 * Copyright (c) 2000-2002 by Chromium Communications 3 * D version Copyright (c) 2004-2010 by Digital Mars 4 * Distributed under the Boost Software License, Version 1.0. 5 * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 * written by Walter Bright 7 * http://www.digitalmars.com 8 * 9 * D2 port by Dmitry Olshansky 10 * 11 * DMDScript is implemented in the D Programming Language, 12 * http://www.digitalmars.com/d/ 13 * 14 * For a C++ implementation of DMDScript, including COM support, see 15 * http://www.digitalmars.com/dscript/cppscript.html 16 */ 17 18 19 module dmdscript.irstate; 20 21 import std.c.stdarg; 22 import std.c.stdlib; 23 import std.c..string; 24 import dmdscript.outbuffer; 25 import core.memory; 26 import core.stdc.stdio; 27 28 import std.stdio; 29 30 import dmdscript.script; 31 import dmdscript.statement; 32 import dmdscript.opcodes; 33 import dmdscript.ir; 34 import dmdscript.identifier; 35 36 // The state of the interpreter machine as seen by the code generator, not 37 // the interpreter. 38 39 struct IRstate 40 { 41 OutBuffer codebuf; // accumulate code here 42 Statement breakTarget; // current statement that 'break' applies to 43 Statement continueTarget; // current statement that 'continue' applies to 44 ScopeStatement scopeContext; // current ScopeStatement we're inside 45 uint[] fixups; 46 47 //void next(); // close out current Block, and start a new one 48 49 uint locali = 1; // leave location 0 as our "null" 50 uint nlocals = 1; 51 52 void ctor() 53 { 54 codebuf = new OutBuffer(); 55 } 56 57 void validate() 58 { 59 assert(codebuf.offset <= codebuf.data.length); 60 if(codebuf.data.length > codebuf.data.capacity) 61 printf("ptr %p, length %d, capacity %d\n", codebuf.data.ptr, codebuf.data.length, core.memory.GC.sizeOf(codebuf.data.ptr)); 62 assert(codebuf.data.length <= codebuf.data.capacity); 63 for(uint u = 0; u < codebuf.offset; ) 64 { 65 IR* code = cast(IR*)(codebuf.data.ptr + u); 66 assert(code.opcode < IRMAX); 67 u += IR.size(code.opcode) * 4; 68 } 69 } 70 71 /********************************** 72 * Allocate a block of local variables, and return an 73 * index to them. 74 */ 75 76 uint alloc(uint nlocals) 77 { 78 uint n; 79 80 n = locali; 81 locali += nlocals; 82 if(locali > this.nlocals) 83 this.nlocals = locali; 84 assert(n); 85 return n * INDEX_FACTOR; 86 } 87 88 /**************************************** 89 * Release this block of n locals starting at local. 90 */ 91 92 void release(uint local, uint n) 93 { 94 /+ 95 local /= INDEX_FACTOR; 96 if (local + n == locali) 97 locali = local; 98 +/ 99 } 100 101 uint mark() 102 { 103 return locali; 104 } 105 106 void release(uint i) 107 { 108 //locali = i; 109 } 110 111 static uint combine(uint loc, uint opcode) 112 { 113 return (loc << 16) | opcode; 114 } 115 116 /*************************************** 117 * Generate code. 118 */ 119 120 void gen0(Loc loc, uint opcode) 121 { 122 codebuf.write(combine(loc, opcode)); 123 } 124 125 void gen1(Loc loc, uint opcode, uint arg) 126 { 127 codebuf.reserve(2 * uint.sizeof); 128 version(all) 129 { 130 // Inline ourselves for speed (compiler doesn't do a good job) 131 uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset); 132 codebuf.offset += 2 * uint.sizeof; 133 data[0] = combine(loc, opcode); 134 data[1] = arg; 135 } 136 else 137 { 138 codebuf.write4n(combine(loc, opcode)); 139 codebuf.write4n(arg); 140 } 141 } 142 143 void gen2(Loc loc, uint opcode, uint arg1, uint arg2) 144 { 145 codebuf.reserve(3 * uint.sizeof); 146 version(all) 147 { 148 // Inline ourselves for speed (compiler doesn't do a good job) 149 uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset); 150 codebuf.offset += 3 * uint.sizeof; 151 data[0] = combine(loc, opcode); 152 data[1] = arg1; 153 data[2] = arg2; 154 } 155 else 156 { 157 codebuf.write4n(combine(loc, opcode)); 158 codebuf.write4n(arg1); 159 codebuf.write4n(arg2); 160 } 161 } 162 163 void gen3(Loc loc, uint opcode, uint arg1, uint arg2, uint arg3) 164 { 165 codebuf.reserve(4 * uint.sizeof); 166 version(all) 167 { 168 // Inline ourselves for speed (compiler doesn't do a good job) 169 uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset); 170 codebuf.offset += 4 * uint.sizeof; 171 data[0] = combine(loc, opcode); 172 data[1] = arg1; 173 data[2] = arg2; 174 data[3] = arg3; 175 } 176 else 177 { 178 codebuf.write4n(combine(loc, opcode)); 179 codebuf.write4n(arg1); 180 codebuf.write4n(arg2); 181 codebuf.write4n(arg3); 182 } 183 } 184 185 void gen4(Loc loc, uint opcode, uint arg1, uint arg2, uint arg3, uint arg4) 186 { 187 codebuf.reserve(5 * uint.sizeof); 188 version(all) 189 { 190 // Inline ourselves for speed (compiler doesn't do a good job) 191 uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset); 192 codebuf.offset += 5 * uint.sizeof; 193 data[0] = combine(loc, opcode); 194 data[1] = arg1; 195 data[2] = arg2; 196 data[3] = arg3; 197 data[4] = arg4; 198 } 199 else 200 { 201 codebuf.write4n(combine(loc, opcode)); 202 codebuf.write4n(arg1); 203 codebuf.write4n(arg2); 204 codebuf.write4n(arg3); 205 codebuf.write4n(arg4); 206 } 207 } 208 209 void gen(Loc loc, uint opcode, uint argc, ...) 210 { 211 codebuf.reserve((1 + argc) * uint.sizeof); 212 codebuf.write(combine(loc, opcode)); 213 for(uint i = 1; i <= argc; i++) 214 { 215 codebuf.write(va_arg!(uint)(_argptr)); 216 } 217 } 218 219 void pops(uint npops) 220 { 221 while(npops--) 222 gen0(0, IRpop); 223 } 224 225 /****************************** 226 * Get the current "instruction pointer" 227 */ 228 229 uint getIP() 230 { 231 if(!codebuf) 232 return 0; 233 return codebuf.offset / 4; 234 } 235 236 /****************************** 237 * Patch a value into the existing codebuf. 238 */ 239 240 void patchJmp(uint index, uint value) 241 { 242 assert((index + 1) * 4 < codebuf.offset); 243 (cast(uint *)(codebuf.data))[index + 1] = value - index; 244 } 245 246 /******************************* 247 * Add this IP to list of jump instructions to patch. 248 */ 249 250 void addFixup(uint index) 251 { 252 fixups ~= index; 253 } 254 255 /******************************* 256 * Go through the list of fixups and patch them. 257 */ 258 259 void doFixups() 260 { 261 uint i; 262 uint index; 263 uint value; 264 Statement s; 265 266 for(i = 0; i < fixups.length; i++) 267 { 268 index = fixups[i]; 269 assert((index + 1) * 4 < codebuf.offset); 270 s = (cast(Statement *)codebuf.data)[index + 1]; 271 value = s.getTarget(); 272 patchJmp(index, value); 273 } 274 } 275 276 277 void optimize() 278 { 279 // Determine the length of the code array 280 IR *c; 281 IR *c2; 282 IR *code; 283 uint length; 284 uint i; 285 286 code = cast(IR *)codebuf.data; 287 for(c = code; c.opcode != IRend; c += IR.size(c.opcode)) 288 { 289 } 290 length = c - code + 1; 291 292 // Allocate a bit vector for the array 293 byte[] b = new byte[length]; //TODO: that was a bit array, maybe should use std.container 294 295 // Set bit for each target of a jump 296 for(c = code; c.opcode != IRend; c += IR.size(c.opcode)) 297 { 298 switch(c.opcode) 299 { 300 case IRjf: 301 case IRjt: 302 case IRjfb: 303 case IRjtb: 304 case IRjmp: 305 case IRjlt: 306 case IRjle: 307 case IRjltc: 308 case IRjlec: 309 case IRtrycatch: 310 case IRtryfinally: 311 case IRnextscope: 312 case IRnext: 313 case IRnexts: 314 //writefln("set %d", (c - code) + (c + 1).offset); 315 b[(c - code) + (c + 1).offset] = true; 316 break; 317 default: 318 break; 319 } 320 } 321 322 // Allocate array of IR contents for locals. 323 IR*[] local; 324 IR*[] p1 = null; 325 326 // Allocate on stack for smaller arrays 327 IR** plocals; 328 if(nlocals < 128) 329 plocals = cast(IR * *)alloca(nlocals * local[0].sizeof); 330 331 if(plocals) 332 { 333 local = plocals[0 .. nlocals]; 334 local[] = null; 335 } 336 else 337 { 338 p1 = new IR *[nlocals]; 339 local = p1; 340 } 341 342 // Optimize 343 for(c = code; c.opcode != IRend; c += IR.size(c.opcode)) 344 { 345 uint offset = (c - code); 346 347 if(b[offset]) // if target of jump 348 { 349 // Reset contents of locals 350 local[] = null; 351 } 352 353 switch(c.opcode) 354 { 355 case IRnop: 356 break; 357 358 case IRnumber: 359 case IRstring: 360 case IRboolean: 361 local[(c + 1).index / INDEX_FACTOR] = c; 362 break; 363 364 case IRadd: 365 case IRsub: 366 case IRcle: 367 local[(c + 1).index / INDEX_FACTOR] = c; 368 break; 369 370 case IRputthis: 371 local[(c + 1).index / INDEX_FACTOR] = c; 372 goto Lreset; 373 374 case IRputscope: 375 local[(c + 1).index / INDEX_FACTOR] = c; 376 break; 377 378 case IRgetscope: 379 { 380 Identifier* cs = (c + 2).id; 381 IR *cimax = null; 382 for(i = nlocals; i--; ) 383 { 384 IR *ci = local[i]; 385 if(ci && 386 (ci.opcode == IRgetscope || ci.opcode == IRputscope) && 387 (ci + 2).id.value..string == cs.value..string 388 ) 389 { 390 if(cimax) 391 { 392 if(cimax < ci) 393 cimax = ci; // select most recent instruction 394 } 395 else 396 cimax = ci; 397 } 398 } 399 if(1 && cimax) 400 { 401 //writef("IRgetscope . IRmov %d, %d\n", (c + 1).index, (cimax + 1).index); 402 c.opcode = IRmov; 403 (c + 2).index = (cimax + 1).index; 404 local[(c + 1).index / INDEX_FACTOR] = cimax; 405 } 406 else 407 local[(c + 1).index / INDEX_FACTOR] = c; 408 break; 409 } 410 411 case IRnew: 412 local[(c + 1).index / INDEX_FACTOR] = c; 413 goto Lreset; 414 415 case IRcallscope: 416 case IRputcall: 417 case IRputcalls: 418 case IRputcallscope: 419 case IRputcallv: 420 case IRcallv: 421 local[(c + 1).index / INDEX_FACTOR] = c; 422 goto Lreset; 423 424 case IRmov: 425 local[(c + 1).index / INDEX_FACTOR] = local[(c + 2).index / INDEX_FACTOR]; 426 break; 427 428 case IRput: 429 case IRpostincscope: 430 case IRaddassscope: 431 goto Lreset; 432 433 case IRjf: 434 case IRjfb: 435 case IRjtb: 436 case IRjmp: 437 case IRjt: 438 case IRret: 439 case IRjlt: 440 case IRjle: 441 case IRjltc: 442 case IRjlec: 443 break; 444 445 default: 446 Lreset: 447 // Reset contents of locals 448 local[] = null; 449 break; 450 } 451 } 452 453 delete p1; 454 455 //return; 456 // Remove all IRnop's 457 for(c = code; c.opcode != IRend; ) 458 { 459 uint offset; 460 uint o; 461 uint c2off; 462 463 if(c.opcode == IRnop) 464 { 465 offset = (c - code); 466 for(c2 = code; c2.opcode != IRend; c2 += IR.size(c2.opcode)) 467 { 468 switch(c2.opcode) 469 { 470 case IRjf: 471 case IRjt: 472 case IRjfb: 473 case IRjtb: 474 case IRjmp: 475 case IRjlt: 476 case IRjle: 477 case IRjltc: 478 case IRjlec: 479 case IRnextscope: 480 case IRtryfinally: 481 case IRtrycatch: 482 c2off = c2 - code; 483 o = c2off + (c2 + 1).offset; 484 if(c2off <= offset && offset < o) 485 (c2 + 1).offset--; 486 else if(c2off > offset && o <= offset) 487 (c2 + 1).offset++; 488 break; 489 /+ 490 case IRtrycatch: 491 o = (c2 + 1).offset; 492 if (offset < o) 493 (c2 + 1).offset--; 494 break; 495 +/ 496 default: 497 continue; 498 } 499 } 500 501 length--; 502 memmove(c, c + 1, (length - offset) * uint.sizeof); 503 } 504 else 505 c += IR.size(c.opcode); 506 } 507 } 508 }