Mercurial > projects > dmdscript-tango
view dmdscript_tango/irstate.d @ 3:8363a4bf6a8f
rename package: dmdscript to dmdscript_tango
author | saaadel |
---|---|
date | Sun, 24 Jan 2010 18:33:05 +0200 |
parents | 55c2951c07be |
children |
line wrap: on
line source
/* Digital Mars DMDScript source code. * Copyright (c) 2000-2002 by Chromium Communications * D version Copyright (c) 2004-2006 by Digital Mars * All Rights Reserved * written by Walter Bright * www.digitalmars.com * Use at your own risk. There is no warranty, express or implied. * License for redistribution is by the GNU General Public License in gpl.txt. * * A binary, non-exclusive license for commercial use can be * purchased from www.digitalmars.com/dscript/buy.html. * * DMDScript is implemented in the D Programming Language, * www.digitalmars.com/d/ * * For a C++ implementation of DMDScript, including COM support, * see www.digitalmars.com/dscript/cppscript.html. */ module dmdscript_tango.irstate; import std.c.stdarg; import std.c.stdlib; import std.c.string; import std.outbuffer; import std.gc; import dmdscript_tango.script; import dmdscript_tango.statement; import dmdscript_tango.opcodes; import dmdscript_tango.ir; import dmdscript_tango.identifier; // The state of the interpreter machine as seen by the code generator, not // the interpreter. struct IRstate { OutBuffer codebuf; // accumulate code here Statement breakTarget; // current statement that 'break' applies to Statement continueTarget; // current statement that 'continue' applies to ScopeStatement scopeContext; // current ScopeStatement we're inside uint[] fixups; //void next(); // close out current Block, and start a new one uint locali = 1; // leave location 0 as our "null" uint nlocals = 1; void ctor() { codebuf = new OutBuffer(); } void validate() { assert(codebuf.offset <= codebuf.data.length); if (codebuf.data.length > std.gc.capacity(codebuf.data.ptr)) printf("ptr %p, length %d, capacity %d\n", codebuf.data.ptr, codebuf.data.length, std.gc.capacity(codebuf.data.ptr)); assert(codebuf.data.length <= std.gc.capacity(codebuf.data.ptr)); for (uint u = 0; u < codebuf.offset;) { IR* code = cast(IR*)(codebuf.data.ptr + u); assert(code.opcode < IRMAX); u += IR.size(code.opcode) * 4; } } /********************************** * Allocate a block of local variables, and return an * index to them. */ uint alloc(uint nlocals) { uint n; n = locali; locali += nlocals; if (locali > this.nlocals) this.nlocals = locali; assert(n); return n * INDEX_FACTOR; } /**************************************** * Release this block of n locals starting at local. */ void release(uint local, uint n) { /+ local /= INDEX_FACTOR; if (local + n == locali) locali = local; +/ } uint mark() { return locali; } void release(uint i) { //locali = i; } static uint combine(uint loc, uint opcode) { return (loc << 16) | opcode; } /*************************************** * Generate code. */ void gen0(Loc loc, uint opcode) { codebuf.write(combine(loc, opcode)); } void gen1(Loc loc, uint opcode, uint arg) { codebuf.reserve(2 * uint.sizeof); version (all) { // Inline ourselves for speed (compiler doesn't do a good job) uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset); codebuf.offset += 2 * uint.sizeof; data[0] = combine(loc, opcode); data[1] = arg; } else { codebuf.write4n(combine(loc, opcode)); codebuf.write4n(arg); } } void gen2(Loc loc, uint opcode, uint arg1, uint arg2) { codebuf.reserve(3 * uint.sizeof); version (all) { // Inline ourselves for speed (compiler doesn't do a good job) uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset); codebuf.offset += 3 * uint.sizeof; data[0] = combine(loc, opcode); data[1] = arg1; data[2] = arg2; } else { codebuf.write4n(combine(loc, opcode)); codebuf.write4n(arg1); codebuf.write4n(arg2); } } void gen3(Loc loc, uint opcode, uint arg1, uint arg2, uint arg3) { codebuf.reserve(4 * uint.sizeof); version (all) { // Inline ourselves for speed (compiler doesn't do a good job) uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset); codebuf.offset += 4 * uint.sizeof; data[0] = combine(loc, opcode); data[1] = arg1; data[2] = arg2; data[3] = arg3; } else { codebuf.write4n(combine(loc, opcode)); codebuf.write4n(arg1); codebuf.write4n(arg2); codebuf.write4n(arg3); } } void gen4(Loc loc, uint opcode, uint arg1, uint arg2, uint arg3, uint arg4) { codebuf.reserve(5 * uint.sizeof); version (all) { // Inline ourselves for speed (compiler doesn't do a good job) uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset); codebuf.offset += 5 * uint.sizeof; data[0] = combine(loc, opcode); data[1] = arg1; data[2] = arg2; data[3] = arg3; data[4] = arg4; } else { codebuf.write4n(combine(loc, opcode)); codebuf.write4n(arg1); codebuf.write4n(arg2); codebuf.write4n(arg3); codebuf.write4n(arg4); } } void gen(Loc loc, uint opcode, uint argc, ...) { codebuf.reserve((1 + argc) * uint.sizeof); codebuf.write(combine(loc, opcode)); for (uint i = 1; i <= argc; i++) { codebuf.write(va_arg!(uint)(_argptr)); } } void pops(uint npops) { while (npops--) gen0(0, IRpop); } /****************************** * Get the current "instruction pointer" */ uint getIP() { if (!codebuf) return 0; return codebuf.offset / 4; } /****************************** * Patch a value into the existing codebuf. */ void patchJmp(uint index, uint value) { assert((index + 1) * 4 < codebuf.offset); (cast(uint *)(codebuf.data))[index + 1] = value - index; } /******************************* * Add this IP to list of jump instructions to patch. */ void addFixup(uint index) { fixups ~= index; } /******************************* * Go through the list of fixups and patch them. */ void doFixups() { uint i; uint index; uint value; Statement s; for (i = 0; i < fixups.length; i++) { index = fixups[i]; assert((index + 1) * 4 < codebuf.offset); s = (cast(Statement *)codebuf.data)[index + 1]; value = s.getTarget(); patchJmp(index, value); } } void optimize() { // Determine the length of the code array IR *c; IR *c2; IR *code; uint length; uint i; code = cast(IR *) codebuf.data; for (c = code; c.opcode != IRend; c += IR.size(c.opcode)) { } length = c - code + 1; // Allocate a bit vector for the array bit[] b = new bit[length]; // Set bit for each target of a jump for (c = code; c.opcode != IRend; c += IR.size(c.opcode)) { switch (c.opcode) { case IRjf: case IRjt: case IRjfb: case IRjtb: case IRjmp: case IRjlt: case IRjle: case IRjltc: case IRjlec: case IRtrycatch: case IRtryfinally: //writef("set %d\n", (c - code) + (c + 1).offset); b[(c - code) + (c + 1).offset] = true; break; default: break; } } // Allocate array of IR contents for locals. IR*[] local; IR*[] p1 = null; // Allocate on stack for smaller arrays IR** plocals; if (nlocals < 128) plocals = cast(IR **)alloca(nlocals * local[0].sizeof); if (plocals) { local = plocals[0 .. nlocals]; local[] = null; } else { p1 = new IR*[nlocals]; local = p1; } // Optimize for (c = code; c.opcode != IRend; c += IR.size(c.opcode)) { uint offset = (c - code); if (b[offset]) // if target of jump { // Reset contents of locals local[] = null; } switch (c.opcode) { case IRnop: break; case IRnumber: case IRstring: case IRboolean: local[(c + 1).index / INDEX_FACTOR] = c; break; case IRadd: case IRsub: case IRcle: local[(c + 1).index / INDEX_FACTOR] = c; break; case IRputthis: local[(c + 1).index / INDEX_FACTOR] = c; goto Lreset; case IRputscope: local[(c + 1).index / INDEX_FACTOR] = c; break; case IRgetscope: { Identifier* cs = (c + 2).id; IR *cimax = null; for (i = nlocals; i--; ) { IR *ci = local[i]; if (ci && (ci.opcode == IRgetscope || ci.opcode == IRputscope) && (ci + 2).id.value.string == cs.value.string ) { if (cimax) { if (cimax < ci) cimax = ci; // select most recent instruction } else cimax = ci; } } if (1 && cimax) { //writef("IRgetscope . IRmov %d, %d\n", (c + 1).index, (cimax + 1).index); c.opcode = IRmov; (c + 2).index = (cimax + 1).index; local[(c + 1).index / INDEX_FACTOR] = cimax; } else local[(c + 1).index / INDEX_FACTOR] = c; break; } case IRnew: local[(c + 1).index / INDEX_FACTOR] = c; goto Lreset; case IRcallscope: case IRputcall: case IRputcalls: case IRputcallscope: case IRputcallv: case IRcallv: local[(c + 1).index / INDEX_FACTOR] = c; goto Lreset; case IRmov: local[(c + 1).index / INDEX_FACTOR] = local[(c + 2).index / INDEX_FACTOR]; break; case IRput: case IRpostincscope: case IRaddassscope: goto Lreset; case IRjf: case IRjfb: case IRjtb: case IRjmp: case IRjt: case IRret: case IRjlt: case IRjle: case IRjltc: case IRjlec: break; default: Lreset: // Reset contents of locals local[] = null; break; } } delete p1; //return; // Remove all IRnop's for (c = code; c.opcode != IRend; ) { uint offset; uint o; uint c2off; if (c.opcode == IRnop) { offset = (c - code); for (c2 = code; c2.opcode != IRend; c2 += IR.size(c2.opcode)) { switch (c2.opcode) { case IRjf: case IRjt: case IRjfb: case IRjtb: case IRjmp: case IRjlt: case IRjle: case IRjltc: case IRjlec: case IRnextscope: case IRtryfinally: case IRtrycatch: c2off = c2 - code; o = c2off + (c2 + 1).offset; if (c2off <= offset && offset < o) (c2 + 1).offset--; else if (c2off > offset && o <= offset) (c2 + 1).offset++; break; /+ case IRtrycatch: o = (c2 + 1).offset; if (offset < o) (c2 + 1).offset--; break; +/ default: continue; } } length--; memmove(c, c + 1, (length - offset) * uint.sizeof); } else c += IR.size(c.opcode); } } }