UNPKG

@awayfl/avm2

Version:

Virtual machine for executing AS3 code

859 lines (858 loc) 34.6 kB
import { Bytecode } from '../Bytecode'; import { Instruction } from './Instruction'; import { Settings } from '../Settings'; /** * Propogade stack for calculation real stack size for every instruction */ export function propagateStack(position, stack, q) { var v = stack; var l = q.length; var minStack = stack; for (var i = 0; i < l; i++) { if (q[i].position >= position) { if (q[i].stack >= 0) return minStack; q[i].stack = v; v += q[i].delta; if (v < minStack) minStack = v; for (var j = 0; j < q[i].refs.length; j++) { var s = propagateStack(q[i].refs[j], v, q); if (s < minStack) minStack = s; } if (q[i].terminal) return minStack; } } return minStack; } /** * Like as propogadeStack, only for scope */ export function propagateScope(position, scope, q) { var v = scope; var l = q.length; for (var i = 0; i < l; i++) { if (q[i].position >= position) { if (q[i].scope >= 0) return; q[i].scope = v; v += q[i].deltaScope; for (var j = 0; j < q[i].refs.length; j++) { propagateScope(q[i].refs[j], v, q); } if (q[i].terminal) return; } } } export function propogateTree(q, jumps) { var branches = {}; var condNodes = []; branches[0] = 0; var l = q.length; for (var i = 1; i < l; i++) { var inst = q[i]; if (jumps.indexOf(inst.position) > -1) { branches[inst.position] = i; } if (inst.name >= Bytecode.IFNLT && inst.name <= Bytecode.LOOKUPSWITCH) { condNodes.push(inst); } } for (var _i = 0, condNodes_1 = condNodes; _i < condNodes_1.length; _i++) { var c = condNodes_1[_i]; if (c.name === Bytecode.LOOKUPSWITCH) { var params = c.params; c.childs = []; for (var i = 0; i < params.length - 1; i++) { c.childs.push(branches[i]); } continue; } if (c.name === Bytecode.JUMP) { c.childs = [branches[c.params[0]]]; continue; } c.childs.push(branches[c.params[0]]); } } function u30(state) { var code = state.code; var i = state.index; var u = code[i++]; if (u & 0x80) { u = u & 0x7f | code[i++] << 7; if (u & 0x4000) { u = u & 0x3fff | code[i++] << 14; if (u & 0x200000) { u = u & 0x1fffff | code[i++] << 21; if (u & 0x10000000) { u = u & 0x0fffffff | code[i++] << 28; u = u & 0xffffffff; } } } } state.index = i; return u >>> 0; } function mn(state) { var index = u30(state); var name = state.abc.getMultiname(index); var mnResult = state.currentMn; mnResult[0] = index; if (name.isRuntimeName() || name.isRuntimeNamespace()) { mnResult[1] = 256; mnResult[2] = name.isRuntimeName() && name.isRuntimeNamespace() ? -2 : -1; return mnResult; } mnResult[1] = 0; mnResult[2] = 0; return mnResult; } function s24(state) { var code = state.code; var i = state.index; var u = code[i++] | (code[i++] << 8) | (code[i++] << 16); u = (u << 8) >> 8; state.index = i; return u; } function s8(state) { return (state.code[state.index++] << 24) >> 24; } /** * Analyzing instruction set from method info * @param methodInfo */ export function analyze(methodInfo) { var abc = methodInfo.abc; var body = methodInfo.getBody(); var code = body.code; var q = []; var state = { index: 0, abc: abc, code: code, currentMn: [0, 0, 0] }; var type = 0; var lastType = 0; var requireScope = false; for (; state.index < code.length;) { var oldi = state.index; var z = code[state.index++]; var last = Settings.OPTIMISE_ON_IR ? q[q.length - 1] : null; var ins = void 0; switch (z) { case Bytecode.NOP: ins = (new Instruction(oldi, z)); break; case Bytecode.LABEL: ins = (new Instruction(oldi, z)); break; case Bytecode.DXNSLATE: ins = (new Instruction(oldi, z, 0, -1)); break; case Bytecode.DEBUGFILE: case Bytecode.DEBUGLINE: ins = (new Instruction(oldi, z, u30(state))); break; case Bytecode.DEBUG: ins = (new Instruction(oldi, z, [s8(state), u30(state), s8(state), u30(state)])); break; case Bytecode.THROW: ins = (new Instruction(oldi, z, null, -1, 0, true)); break; case Bytecode.PUSHSCOPE: ins = (new Instruction(oldi, z, null, -1, 1)); ins.returnTypeId = lastType = ++type; break; case Bytecode.PUSHWITH: ins = (new Instruction(oldi, z, null, -1, 1)); break; case Bytecode.POPSCOPE: ins = (new Instruction(oldi, z, null, 0, -1)); break; case Bytecode.GETSCOPEOBJECT: ins = (new Instruction(oldi, z, s8(state), 1, 0)); ins.returnTypeId = lastType = ++type; requireScope = true; break; case Bytecode.GETGLOBALSCOPE: ins = (new Instruction(oldi, z, null, 1)); ins.returnTypeId = lastType = ++type; requireScope = true; break; case Bytecode.GETSLOT: ins = (new Instruction(oldi, z, u30(state), 0)); ins.returnTypeId = lastType = ++type; break; case Bytecode.SETSLOT: ins = (new Instruction(oldi, z, u30(state), -2)); break; case Bytecode.NEXTNAME: ins = (new Instruction(oldi, z, null, -1)); ins.returnTypeId = lastType = ++type; break; case Bytecode.NEXTVALUE: ins = (new Instruction(oldi, z, null, -1)); ins.returnTypeId = lastType = ++type; break; case Bytecode.HASNEXT: ins = (new Instruction(oldi, z, null, -1)); ins.returnTypeId = lastType = -2 /* PRIMITIVE_TYPE.BOOL */; break; case Bytecode.HASNEXT2: ins = (new Instruction(oldi, z, [u30(state), u30(state)], 1)); ins.returnTypeId = lastType = -2 /* PRIMITIVE_TYPE.BOOL */; break; case Bytecode.IN: ins = (new Instruction(oldi, z, null, -1)); ins.returnTypeId = lastType = -2 /* PRIMITIVE_TYPE.BOOL */; break; case Bytecode.DUP: ins = (new Instruction(oldi, z, null, 1)); ins.returnTypeId = lastType = type; if (last) { switch (last.name) { case Bytecode.PUSHTRUE: case Bytecode.PUSHFALSE: case Bytecode.PUSHNAN: case Bytecode.PUSHINT: case Bytecode.PUSHDOUBLE: case Bytecode.PUSHBYTE: case Bytecode.PUSHFLOAT: case Bytecode.PUSHSTRING: case Bytecode.PUSHNULL: { ins.name = last.name; ins.params = last.params; ins.comment = 'IR: DUP changed to PUSH*, reason: prevent optimisation'; } } } break; case Bytecode.POP: { ins = (new Instruction(oldi, z, null, -1)); ins.returnTypeId = lastType = type; // if (last && last.name === Bytecode.CALLPROPERTY) { last.name = Bytecode.CALLPROPVOID; last.comment = 'IR: Optimised from "CALLPROPERTY", reason: POP STACK'; } break; } case Bytecode.SWAP: ins = (new Instruction(oldi, z, null, 0)); break; case Bytecode.PUSHTRUE: ins = (new Instruction(oldi, z, null, 1)); ins.returnTypeId = lastType = -2 /* PRIMITIVE_TYPE.BOOL */; break; case Bytecode.PUSHFALSE: ins = (new Instruction(oldi, z, null, 1)); ins.returnTypeId = lastType = -2 /* PRIMITIVE_TYPE.BOOL */; break; case Bytecode.PUSHBYTE: ins = (new Instruction(oldi, z, s8(state), 1)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.PUSHSHORT: ins = (new Instruction(oldi, z, u30(state) << 16 >> 16, 1)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.PUSHINT: ins = (new Instruction(oldi, z, u30(state), 1)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.PUSHUINT: ins = (new Instruction(oldi, z, u30(state), 1)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.PUSHDOUBLE: ins = (new Instruction(oldi, z, u30(state), 1)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.PUSHNAN: ins = (new Instruction(oldi, z, null, 1)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.PUSHNULL: ins = (new Instruction(oldi, z, null, 1)); ins.returnTypeId = lastType = -6 /* PRIMITIVE_TYPE.NULL */; break; case Bytecode.PUSHUNDEFINED: ins = (new Instruction(oldi, z, null, 1)); ins.returnTypeId = lastType = -5 /* PRIMITIVE_TYPE.UNDEF */; break; case Bytecode.PUSHSTRING: ins = (new Instruction(oldi, z, u30(state), 1)); ins.returnTypeId = lastType = -4 /* PRIMITIVE_TYPE.STRING */; break; case Bytecode.IFEQ: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, -2, 0, false, [i + j])); break; } case Bytecode.IFNE: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, -2, 0, false, [i + j])); break; } case Bytecode.IFSTRICTEQ: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, -2, 0, false, [i + j])); break; } case Bytecode.IFSTRICTNE: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, -2, 0, false, [i + j])); break; } case Bytecode.IFGT: case Bytecode.IFNLE: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, -2, 0, false, [i + j])); break; } case Bytecode.IFGE: case Bytecode.IFNLT: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, -2, 0, false, [i + j])); break; } case Bytecode.IFLT: case Bytecode.IFNGE: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, -2, 0, false, [i + j])); break; } case Bytecode.IFLE: case Bytecode.IFNGT: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, -2, 0, false, [i + j])); break; } case Bytecode.IFTRUE: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, -1, 0, false, [i + j])); break; } case Bytecode.IFFALSE: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, -1, 0, false, [i + j])); break; } case Bytecode.LOOKUPSWITCH: { var offset = oldi + s24(state); var cases = u30(state); var table = [offset]; for (var j = 0; j <= cases; j++) table.push(oldi + s24(state)); ins = (new Instruction(oldi, z, table, -1, 0, true, table)); break; } case Bytecode.JUMP: { var j = s24(state); var i = state.index; ins = (new Instruction(oldi, z, i + j, 0, 0, true, [i + j])); break; } case Bytecode.RETURNVALUE: ins = (new Instruction(oldi, z, null, -1, 0, true)); break; case Bytecode.RETURNVOID: ins = (new Instruction(oldi, z, null, 0, 0, true)); break; case Bytecode.NOT: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = lastType = -2 /* PRIMITIVE_TYPE.BOOL */; break; case Bytecode.BITNOT: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.NEGATE: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.INCREMENT: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.DECREMENT: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.INCLOCAL: case Bytecode.DECLOCAL: ins = (new Instruction(oldi, z, u30(state), 0)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.INCREMENT_I: case Bytecode.DECREMENT_I: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.INCLOCAL_I: case Bytecode.DECLOCAL_I: ins = (new Instruction(oldi, z, u30(state), 0)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.NEGATE_I: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.ADD_I: case Bytecode.SUBTRACT_I: case Bytecode.MULTIPLY_I: case Bytecode.ADD: case Bytecode.SUBTRACT: case Bytecode.MULTIPLY: case Bytecode.DIVIDE: case Bytecode.MODULO: case Bytecode.LSHIFT: case Bytecode.RSHIFT: case Bytecode.URSHIFT: case Bytecode.BITAND: case Bytecode.BITOR: case Bytecode.BITXOR: ins = (new Instruction(oldi, z, null, -1)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; case Bytecode.EQUALS: case Bytecode.STRICTEQUALS: case Bytecode.GREATERTHAN: case Bytecode.GREATEREQUALS: case Bytecode.LESSTHAN: case Bytecode.LESSEQUALS: ins = (new Instruction(oldi, z, null, -1)); ins.returnTypeId = lastType = -2 /* PRIMITIVE_TYPE.BOOL */; break; case Bytecode.TYPEOF: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = lastType = ++type; break; case Bytecode.INSTANCEOF: { ins = (new Instruction(oldi, z, null, -1)); ins.returnTypeId = lastType = -2 /* PRIMITIVE_TYPE.BOOL */; break; } case Bytecode.ISTYPE: { var _a = mn(state), index = _a[0], d = _a[2]; ins = (new Instruction(oldi, z, index, 0 + d)); ins.returnTypeId = lastType = -2 /* PRIMITIVE_TYPE.BOOL */; requireScope = true; break; } case Bytecode.ISTYPELATE: ins = (new Instruction(oldi, z, null, -1)); ins.returnTypeId = lastType = -2 /* PRIMITIVE_TYPE.BOOL */; requireScope = true; break; case Bytecode.ASTYPELATE: ins = (new Instruction(oldi, z, null, -1)); break; case Bytecode.ASTYPE: { var _b = mn(state), index = _b[0], d = _b[2]; ins = (new Instruction(oldi, z, index, 0 + d)); requireScope = true; break; } case Bytecode.CALL: { var argnum = u30(state); ins = (new Instruction(oldi, z, argnum, -argnum - 1)); requireScope = true; break; } case Bytecode.CONSTRUCT: { var argnum = u30(state); ins = (new Instruction(oldi, z, argnum, -argnum)); ins.returnTypeId = lastType = ++type; break; } case Bytecode.CALLPROPERTY: { var _c = mn(state), index = _c[0], dyn = _c[1], d = _c[2]; var argnum = u30(state); ins = (new Instruction(oldi, z + dyn, [argnum, index], -argnum + d)); ins.returnTypeId = lastType = ++type; requireScope = requireScope || dyn !== 0; break; } case Bytecode.CALLPROPLEX: { var _d = mn(state), index = _d[0], dyn = _d[1], d = _d[2]; var argnum = u30(state); ins = (new Instruction(oldi, z + dyn, [argnum, index], -argnum + d)); ins.returnTypeId = lastType = ++type; requireScope = requireScope || dyn !== 0; break; } case Bytecode.CALLPROPVOID: { var _e = mn(state), index = _e[0], dyn = _e[1], d = _e[2]; var argnum = u30(state); ins = (new Instruction(oldi, z + dyn, [argnum, index], -(argnum + 1) + d)); break; } case Bytecode.APPLYTYPE: { var argnum = u30(state); ins = (new Instruction(oldi, z, argnum, -argnum)); ins.returnTypeId = lastType = type; break; } case Bytecode.FINDPROPSTRICT: { var _f = mn(state), index = _f[0], dyn = _f[1], d = _f[2]; ins = (new Instruction(oldi, z + dyn, index, 1 + d)); ins.returnTypeId = lastType = ++type; requireScope = true; break; } case Bytecode.FINDPROPERTY: { var _g = mn(state), index = _g[0], dyn = _g[1], d = _g[2]; ins = (new Instruction(oldi, z + dyn, index, 1 + d)); ins.returnTypeId = lastType = ++type; requireScope = true; break; } case Bytecode.NEWFUNCTION: ins = (new Instruction(oldi, z, u30(state), 1)); ins.returnTypeId = lastType = ++type; requireScope = true; break; case Bytecode.NEWCLASS: ins = (new Instruction(oldi, z, u30(state), 0)); ins.returnTypeId = lastType = ++type; requireScope = true; break; case Bytecode.GETDESCENDANTS: ins = (new Instruction(oldi, z, u30(state), 0)); ins.returnTypeId = lastType = ++type; break; case Bytecode.NEWARRAY: { var argnum = u30(state); ins = (new Instruction(oldi, z, argnum, -argnum + 1)); ins.returnTypeId = lastType = ++type; break; } case Bytecode.NEWOBJECT: { var argnum = u30(state); ins = (new Instruction(oldi, z, argnum, -2 * argnum + 1)); ins.returnTypeId = lastType = ++type; break; } case Bytecode.NEWACTIVATION: ins = (new Instruction(oldi, z, null, 1)); ins.returnTypeId = lastType = ++type; requireScope = true; break; case Bytecode.NEWCATCH: ins = (new Instruction(oldi, z, u30(state), 1)); requireScope = true; break; case Bytecode.CONSTRUCTSUPER: { var argnum = u30(state); ins = (new Instruction(oldi, z, argnum, -(argnum + 1))); break; } case Bytecode.CALLSUPER: { var _h = mn(state), index = _h[0], dyn = _h[1], d = _h[2]; var argnum = u30(state); ins = (new Instruction(oldi, z + dyn, [argnum, index], -argnum + d)); break; } case Bytecode.CALLSUPERVOID: { var _j = mn(state), index = _j[0], dyn = _j[1], d = _j[2]; var argnum = u30(state); ins = (new Instruction(oldi, z + dyn, [argnum, index], -(argnum + 1) + d)); break; } case Bytecode.CONSTRUCTPROP: { var _k = mn(state), index = _k[0], dyn = _k[1], d = _k[2]; var argnum = u30(state); ins = (new Instruction(oldi, z + dyn, [argnum, index], -argnum + d)); ins.returnTypeId = lastType = ++type; break; } case Bytecode.GETPROPERTY: { var _l = mn(state), index = _l[0], dyn = _l[1], d = _l[2]; ins = (new Instruction(oldi, Bytecode.GETPROPERTY + dyn, index, 0 + d)); ins.returnTypeId = lastType = ++type; break; } // we collapse 2 operation to one, but this is can prevent optimisations case Bytecode.INITPROPERTY: case Bytecode.SETPROPERTY: { var _m = mn(state), index = _m[0], dyn = _m[1], d = _m[2]; ins = (new Instruction(oldi, Bytecode.SETPROPERTY + dyn, index, -2 + d)); break; } case Bytecode.DELETEPROPERTY: { var _o = mn(state), index = _o[0], dyn = _o[1], d = _o[2]; ins = (new Instruction(oldi, z + dyn, index, 0 + d)); break; } case Bytecode.GETSUPER: { var _p = mn(state), index = _p[0], dyn = _p[1], d = _p[2]; ins = (new Instruction(oldi, z + dyn, index, 0 + d)); ins.returnTypeId = lastType = ++type; break; } case Bytecode.SETSUPER: { var _q = mn(state), index = _q[0], dyn = _q[1], d = _q[2]; ins = (new Instruction(oldi, z + dyn, index, -2 + d)); break; } case Bytecode.COERCE: { var _r = mn(state), index = _r[0], dyn = _r[1], d = _r[2]; ins = (new Instruction(oldi, z + dyn, index, 0 + d)); ins.returnTypeId = lastType; // construct prop was called with same MN that used for coerce, redundant if (last && last.name === Bytecode.CONSTRUCTPROP && last.params[1] === index) { ins.returnTypeId = -1 /* PRIMITIVE_TYPE.VOID */; ins.name = Bytecode.LABEL; ins.comment = 'IR: Drop coerce, reason: redundant'; break; } requireScope = true; break; } case Bytecode.COERCE_A: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = lastType; break; case Bytecode.COERCE_S: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = -4 /* PRIMITIVE_TYPE.STRING */; break; case Bytecode.CONVERT_D: { ins = (new Instruction(oldi, z, null, 0)); if (last) { switch (last.name) { case Bytecode.PUSHINT: case Bytecode.PUSHFLOAT: case Bytecode.PUSHDOUBLE: case Bytecode.ADD_I: case Bytecode.INCREMENT: case Bytecode.DECREMENT: case Bytecode.DECREMENT_I: case Bytecode.INCREMENT_I: { ins.name = Bytecode.LABEL; ins.comment = 'IR: CONVERT_D removed, reason: arguments strictly number'; break; } } } break; } case Bytecode.CONVERT_B: { ins = (new Instruction(oldi, z, null, 0)); if (last) { switch (last.name) { case Bytecode.EQUALS: case Bytecode.STRICTEQUALS: case Bytecode.GREATERTHAN: case Bytecode.GREATEREQUALS: case Bytecode.LESSTHAN: case Bytecode.LESSEQUALS: case Bytecode.NOT: { ins.name = Bytecode.LABEL; ins.comment = 'IR: CONVERT_B removed, reason: arguments strictly boolean'; break; } } } break; } case Bytecode.ESC_XATTR: case Bytecode.ESC_XELEM: case Bytecode.CONVERT_I: case Bytecode.CONVERT_U: case Bytecode.CONVERT_S: case Bytecode.CONVERT_O: ins = (new Instruction(oldi, z, null, 0)); break; case Bytecode.CHECKFILTER: ins = (new Instruction(oldi, z, null, 0)); break; case Bytecode.GETLOCAL: ins = (new Instruction(oldi, Bytecode.GETLOCAL, u30(state), 1)); ins.returnTypeId = lastType; break; case Bytecode.GETLOCAL0: ins = (new Instruction(oldi, Bytecode.GETLOCAL, 0, 1)); ins.returnTypeId = lastType; break; case Bytecode.GETLOCAL1: ins = (new Instruction(oldi, Bytecode.GETLOCAL, 1, 1)); ins.returnTypeId = lastType; break; case Bytecode.GETLOCAL2: ins = (new Instruction(oldi, Bytecode.GETLOCAL, 2, 1)); ins.returnTypeId = lastType; break; case Bytecode.GETLOCAL3: ins = (new Instruction(oldi, Bytecode.GETLOCAL, 3, 1)); ins.returnTypeId = lastType; break; case Bytecode.SETLOCAL: ins = (new Instruction(oldi, Bytecode.SETLOCAL, u30(state), -1)); ins.returnTypeId = lastType; break; case Bytecode.SETLOCAL0: ins = (new Instruction(oldi, Bytecode.SETLOCAL, 0, -1)); ins.returnTypeId = lastType; break; case Bytecode.SETLOCAL1: ins = (new Instruction(oldi, Bytecode.SETLOCAL, 1, -1)); ins.returnTypeId = lastType; break; case Bytecode.SETLOCAL2: ins = (new Instruction(oldi, Bytecode.SETLOCAL, 2, -1)); ins.returnTypeId = lastType; break; case Bytecode.SETLOCAL3: ins = (new Instruction(oldi, Bytecode.SETLOCAL, 3, -1)); ins.returnTypeId = lastType; break; case Bytecode.KILL: ins = (new Instruction(oldi, z, u30(state), 0)); ins.name = Bytecode.LABEL; ins.comment = 'IR: KILL removed, reason: prevent optimisation'; break; case Bytecode.GETLEX: { var _s = mn(state), index = _s[0], dyn = _s[1], d = _s[2]; ins = (new Instruction(oldi, z + dyn, index, 1 + d)); ins.returnTypeId = lastType = ++type; requireScope = true; break; } //http://docs.redtamarin.com/0.4.1T124/avm2/intrinsics/memory/package.html#si32() case Bytecode.SI8: case Bytecode.SI16: case Bytecode.SI32: case Bytecode.SF32: case Bytecode.SF64: ins = (new Instruction(oldi, z, null, -2)); break; //http://docs.redtamarin.com/0.4.1T124/avm2/intrinsics/memory/package.html#li32() case Bytecode.LI8: case Bytecode.LI16: case Bytecode.LI32: case Bytecode.LF32: case Bytecode.LF64: ins = (new Instruction(oldi, z, null, 0)); ins.returnTypeId = lastType = -3 /* PRIMITIVE_TYPE.NUMBER */; break; default: { var c = code[state.index - 1]; return { error: { message: "UNKNOWN BYTECODE ".concat(c.toString(16), " ").concat(Bytecode[c], " at ").concat(oldi), reason: "unknow_bytecode" /* COMPILATION_FAIL_REASON.UNKNOW_BYTECODE */, } }; } } q.push(ins); } var minStack = propagateStack(0, 0, q); if (requireScope) { propagateScope(0, 0, q); } else { var scopeIndexes = []; for (var i = 0; i < q.length; i++) { if (q[i].name === Bytecode.PUSHSCOPE) { scopeIndexes.push(i); } } for (var _i = 0, scopeIndexes_1 = scopeIndexes; _i < scopeIndexes_1.length; _i++) { var i = scopeIndexes_1[_i]; // we remove 3 commands, because push scope shift stack before var comment = new Instruction(0, Bytecode.LABEL); comment.comment = 'IR: PUSHSCOPE removed, reason: unused'; q.splice(i - 1, 2, comment); } } var jumps = [0]; for (var i = 0; i < q.length; i++) { for (var j = 0; j < q[i].refs.length; j++) { jumps.push(q[i].refs[j]); } } var catchStart; var catchEnd; if (body.catchBlocks.length) { // collect try-catch blocks sorted by their start-position catchStart = {}; // collect try-catch blocks sorted by their end-position catchEnd = {}; for (var i = 0; i < body.catchBlocks.length; i++) { var block = body.catchBlocks[i]; //let stack = 0; var start = -1; var end = -1; var scope = 0; for (var c = 0; c < q.length; c++) { var pos = q[c].position; if (pos >= block.start) { start = pos; break; } // propogade it // stack = q[c].stack; if (!Settings.NO_PROPAGATE_SCOPES_FOR_TRY) scope = q[c].scope; } for (var c = q.length - 1; c >= 0; c--) { var pos = q[c].position; if (pos <= block.end) { end = pos; break; } } if (!catchStart[start]) catchStart[start] = []; catchStart[start].push(block); if (!catchEnd[end]) catchEnd[end] = []; catchEnd[end].push(block); // make sure that the target-instruction for the catch is propagated and set as target // using the stack value of the start-instruction does seem to do the trick // and this broadcast bug, if breakpoints is exist // IMPORTANT! Catch block push error on top of stack // this is why stack should start from 1 instead of 0 var s = propagateStack(block.target, 1, q); if (s < minStack) minStack = s; // IMPORTANT! SCOPE SHOULD BE PROPOGADED TOO propagateScope(block.target, scope, q); jumps.push(block.target); } } propogateTree(q, jumps); var error = minStack < 0 ? { message: 'Stack underrun while preprocess, stack:' + minStack, reason: "underrun" /* COMPILATION_FAIL_REASON.UNDERRUN */ } : null; return { set: q, jumps: jumps, catchStart: catchStart, catchEnd: catchEnd, error: error }; }