@awayfl/avm2
Version:
Virtual machine for executing AS3 code
594 lines (593 loc) • 17.1 kB
JavaScript
import { assert } from '@awayjs/graphics';
import { release } from '@awayfl/swf-loader';
var bytecodeNames = [
'',
'BKPT',
'NOP',
'THROW',
'GETSUPER',
'SETSUPER',
'DXNS',
'DXNSLATE',
'KILL',
'LABEL',
'LF32X4',
'SF32X4',
'IFNLT',
'IFNLE',
'IFNGT',
'IFNGE',
'JUMP',
'IFTRUE',
'IFFALSE',
'IFEQ',
'IFNE',
'IFLT',
'IFLE',
'IFGT',
'IFGE',
'IFSTRICTEQ',
'IFSTRICTNE',
'LOOKUPSWITCH',
'PUSHWITH',
'POPSCOPE',
'NEXTNAME',
'HASNEXT',
'PUSHNULL',
'PUSHUNDEFINED',
'PUSHFLOAT',
'NEXTVALUE',
'PUSHBYTE',
'PUSHSHORT',
'PUSHTRUE',
'PUSHFALSE',
'PUSHNAN',
'POP',
'DUP',
'SWAP',
'PUSHSTRING',
'PUSHINT',
'PUSHUINT',
'PUSHDOUBLE',
'PUSHSCOPE',
'PUSHNAMESPACE',
'HASNEXT2',
'UNUSED_33',
'UNUSED_34',
'LI8',
'LI16',
'LI32',
'LF32',
'LF64',
'SI8',
'SI16',
'SI32',
'SF32',
'SF64',
'UNUSED_3F',
'NEWFUNCTION',
'CALL',
'CONSTRUCT',
'CALLMETHOD',
'CALLSTATIC',
'CALLSUPER',
'CALLPROPERTY',
'RETURNVOID',
'RETURNVALUE',
'CONSTRUCTSUPER',
'CONSTRUCTPROP',
'CALLSUPERID',
'CALLPROPLEX',
'CALLINTERFACE',
'CALLSUPERVOID',
'CALLPROPVOID',
'SXI1',
'SXI8',
'SXI16',
'APPLYTYPE',
'PUSHFLOAT4',
'NEWOBJECT',
'NEWARRAY',
'NEWACTIVATION',
'NEWCLASS',
'GETDESCENDANTS',
'NEWCATCH',
'UNUSED_5B',
'UNUSED_5C',
'FINDPROPSTRICT',
'FINDPROPERTY',
'FINDDEF',
'GETLEX',
'SETPROPERTY',
'GETLOCAL',
'SETLOCAL',
'GETGLOBALSCOPE',
'GETSCOPEOBJECT',
'GETPROPERTY',
'GETOUTERSCOPE',
'INITPROPERTY',
'UNUSED_69',
'DELETEPROPERTY',
'UNUSED_6B',
'GETSLOT',
'SETSLOT',
'GETGLOBALSLOT',
'SETGLOBALSLOT',
'CONVERT_S',
'ESC_XELEM',
'ESC_XATTR',
'CONVERT_I',
'CONVERT_U',
'CONVERT_D',
'CONVERT_B',
'CONVERT_O',
'CHECKFILTER',
'CONVERT_F',
'UNPLUS',
'CONVERT_F4',
'BC_7C',
'BC_7D',
'BC_7E',
'BC_7F',
'COERCE',
'COERCE_B',
'COERCE_A',
'COERCE_I',
'COERCE_D',
'COERCE_S',
'ASTYPE',
'ASTYPELATE',
'COERCE_U',
'COERCE_O',
'UNUSED_8A',
'UNUSED_8B',
'UNUSED_8C',
'UNUSED_8D',
'UNUSED_8E',
'UNUSED_8F',
'NEGATE',
'INCREMENT',
'INCLOCAL',
'DECREMENT',
'DECLOCAL',
'TYPEOF',
'NOT',
'BITNOT',
'UNUSED_98',
'UNUSED_99',
'UNUSED_9A',
'UNUSED_9B',
'UNUSED_9C',
'UNUSED_9D',
'UNUSED_9E',
'UNUSED_9F',
'ADD',
'SUBTRACT',
'MULTIPLY',
'DIVIDE',
'MODULO',
'LSHIFT',
'RSHIFT',
'URSHIFT',
'BITAND',
'BITOR',
'BITXOR',
'EQUALS',
'STRICTEQUALS',
'LESSTHAN',
'LESSEQUALS',
'GREATERTHAN',
'GREATEREQUALS',
'INSTANCEOF',
'ISTYPE',
'ISTYPELATE',
'IN',
'UNUSED_B5',
'UNUSED_B6',
'UNUSED_B7',
'UNUSED_B8',
'UNUSED_B9',
'UNUSED_BA',
'UNUSED_BB',
'UNUSED_BC',
'UNUSED_BD',
'UNUSED_BE',
'UNUSED_BF',
'INCREMENT_I',
'DECREMENT_I',
'INCLOCAL_I',
'DECLOCAL_I',
'NEGATE_I',
'ADD_I',
'SUBTRACT_I',
'MULTIPLY_I',
'UNUSED_C8',
'UNUSED_C9',
'UNUSED_CA',
'UNUSED_CB',
'UNUSED_CC',
'UNUSED_CD',
'UNUSED_CE',
'UNUSED_CF',
'GETLOCAL0',
'GETLOCAL1',
'GETLOCAL2',
'GETLOCAL3',
'SETLOCAL0',
'SETLOCAL1',
'SETLOCAL2',
'SETLOCAL3',
'UNUSED_D8',
'UNUSED_D9',
'UNUSED_DA',
'UNUSED_DB',
'UNUSED_DC',
'UNUSED_DD',
'UNUSED_DE',
'UNUSED_DF',
'UNUSED_E0',
'UNUSED_E1',
'UNUSED_E2',
'UNUSED_E3',
'UNUSED_E4',
'UNUSED_E5',
'UNUSED_E6',
'UNUSED_E7',
'UNUSED_E8',
'UNUSED_E9',
'UNUSED_EA',
'UNUSED_EB',
'UNUSED_EC',
'INVALID',
'UNUSED_EE',
'DEBUG',
'DEBUGLINE',
'DEBUGFILE',
'BKPTLINE',
'TIMESTAMP',
'RESTARGC',
'RESTARG',
'UNUSED_F6',
'UNUSED_F7',
'UNUSED_F8',
'UNUSED_F9',
'UNUSED_FA',
'UNUSED_FB',
'UNUSED_FC',
'UNUSED_FD',
'UNUSED_FE',
'END'
];
export function getBytecodeName(bytecode) {
return release ? 'Bytecode: ' + bytecode : bytecodeNames[bytecode];
}
/**
* A array that maps from a bytecode value to the set of {@link OPFlags} for the corresponding instruction.
*/
export var BytecodeFlags = new Uint32Array(256);
export var BytecodeFormat = new Array(256);
function define(bytecode, format, flags) {
if (flags === void 0) { flags = 0; }
BytecodeFlags[bytecode] = flags;
BytecodeFormat[bytecode] = format;
}
/**
* Only call this before the compiler is used.
*/
export function defineBytecodes() {
define(1 /* Bytecode.BKPT */, '');
define(2 /* Bytecode.NOP */, '');
define(3 /* Bytecode.THROW */, '');
define(4 /* Bytecode.GETSUPER */, 'e');
define(5 /* Bytecode.SETSUPER */, 'e');
define(6 /* Bytecode.DXNS */, 'e');
define(7 /* Bytecode.DXNSLATE */, '');
define(8 /* Bytecode.KILL */, 'e');
define(9 /* Bytecode.LABEL */, '');
define(10 /* Bytecode.LF32X4 */, '');
define(11 /* Bytecode.SF32X4 */, '');
define(12 /* Bytecode.IFNLT */, 'd');
define(13 /* Bytecode.IFNLE */, 'd');
define(14 /* Bytecode.IFNGT */, 'd');
define(15 /* Bytecode.IFNGE */, 'd');
define(16 /* Bytecode.JUMP */, 'd');
define(17 /* Bytecode.IFTRUE */, 'd');
define(18 /* Bytecode.IFFALSE */, 'd');
define(19 /* Bytecode.IFEQ */, 'd');
define(20 /* Bytecode.IFNE */, 'd');
define(21 /* Bytecode.IFLT */, 'd');
define(22 /* Bytecode.IFLE */, 'd');
define(23 /* Bytecode.IFGT */, 'd');
define(24 /* Bytecode.IFGE */, 'd');
define(25 /* Bytecode.IFSTRICTEQ */, 'd');
define(26 /* Bytecode.IFSTRICTNE */, 'd');
define(27 /* Bytecode.LOOKUPSWITCH */, '');
define(28 /* Bytecode.PUSHWITH */, '');
define(29 /* Bytecode.POPSCOPE */, '');
define(30 /* Bytecode.NEXTNAME */, '');
define(31 /* Bytecode.HASNEXT */, '');
define(32 /* Bytecode.PUSHNULL */, '');
define(33 /* Bytecode.PUSHUNDEFINED */, '');
define(35 /* Bytecode.NEXTVALUE */, '');
define(36 /* Bytecode.PUSHBYTE */, 'b');
define(37 /* Bytecode.PUSHSHORT */, 'c');
define(38 /* Bytecode.PUSHTRUE */, '');
define(39 /* Bytecode.PUSHFALSE */, '');
define(40 /* Bytecode.PUSHNAN */, '');
define(41 /* Bytecode.POP */, '');
define(42 /* Bytecode.DUP */, '');
define(43 /* Bytecode.SWAP */, '');
define(44 /* Bytecode.PUSHSTRING */, 'e');
define(45 /* Bytecode.PUSHINT */, 'e');
define(46 /* Bytecode.PUSHUINT */, 'e');
define(47 /* Bytecode.PUSHDOUBLE */, 'e');
define(48 /* Bytecode.PUSHSCOPE */, '');
define(49 /* Bytecode.PUSHNAMESPACE */, 'e');
define(50 /* Bytecode.HASNEXT2 */, 'ee');
// define(Bytecode.UNDEFINED, "");
// define(Bytecode.UNDEFINED, "");
define(53 /* Bytecode.LI8 */, '');
define(54 /* Bytecode.LI16 */, '');
define(55 /* Bytecode.LI32 */, '');
define(56 /* Bytecode.LF32 */, '');
define(57 /* Bytecode.LF64 */, '');
define(58 /* Bytecode.SI8 */, '');
define(59 /* Bytecode.SI16 */, '');
define(60 /* Bytecode.SI32 */, '');
define(61 /* Bytecode.SF32 */, '');
define(62 /* Bytecode.SF64 */, '');
define(64 /* Bytecode.NEWFUNCTION */, 'e');
define(65 /* Bytecode.CALL */, 'e');
define(66 /* Bytecode.CONSTRUCT */, 'e');
define(67 /* Bytecode.CALLMETHOD */, 'ee');
define(68 /* Bytecode.CALLSTATIC */, 'ee');
define(69 /* Bytecode.CALLSUPER */, 'ee');
define(70 /* Bytecode.CALLPROPERTY */, 'ee');
define(71 /* Bytecode.RETURNVOID */, '');
define(72 /* Bytecode.RETURNVALUE */, '');
define(73 /* Bytecode.CONSTRUCTSUPER */, 'e');
define(74 /* Bytecode.CONSTRUCTPROP */, 'ee');
define(75 /* Bytecode.CALLSUPERID */, '');
define(76 /* Bytecode.CALLPROPLEX */, 'ee');
define(77 /* Bytecode.CALLINTERFACE */, '');
define(78 /* Bytecode.CALLSUPERVOID */, 'ee');
define(79 /* Bytecode.CALLPROPVOID */, 'ee');
define(80 /* Bytecode.SXI1 */, '');
define(81 /* Bytecode.SXI8 */, '');
define(82 /* Bytecode.SXI16 */, '');
define(83 /* Bytecode.APPLYTYPE */, 'e');
define(84 /* Bytecode.PUSHFLOAT4 */, '');
define(85 /* Bytecode.NEWOBJECT */, 'e');
define(86 /* Bytecode.NEWARRAY */, 'e');
define(87 /* Bytecode.NEWACTIVATION */, '');
define(88 /* Bytecode.NEWCLASS */, 'e');
define(89 /* Bytecode.GETDESCENDANTS */, 'e');
define(90 /* Bytecode.NEWCATCH */, 'e');
// define(Bytecode.UNDEFINED, "");
// define(Bytecode.UNDEFINED, "");
define(93 /* Bytecode.FINDPROPSTRICT */, 'e');
define(94 /* Bytecode.FINDPROPERTY */, 'e');
define(95 /* Bytecode.FINDDEF */, '');
define(96 /* Bytecode.GETLEX */, 'e');
define(97 /* Bytecode.SETPROPERTY */, 'e');
define(98 /* Bytecode.GETLOCAL */, 'e');
define(99 /* Bytecode.SETLOCAL */, 'e');
define(100 /* Bytecode.GETGLOBALSCOPE */, '');
define(101 /* Bytecode.GETSCOPEOBJECT */, 'e');
define(102 /* Bytecode.GETPROPERTY */, 'e');
define(103 /* Bytecode.GETOUTERSCOPE */, '');
define(104 /* Bytecode.INITPROPERTY */, 'e');
define(106 /* Bytecode.DELETEPROPERTY */, 'e');
define(108 /* Bytecode.GETSLOT */, 'e');
define(109 /* Bytecode.SETSLOT */, 'e');
define(110 /* Bytecode.GETGLOBALSLOT */, 'e');
define(111 /* Bytecode.SETGLOBALSLOT */, 'e');
define(112 /* Bytecode.CONVERT_S */, '');
define(113 /* Bytecode.ESC_XELEM */, '');
define(114 /* Bytecode.ESC_XATTR */, '');
define(115 /* Bytecode.CONVERT_I */, '');
define(116 /* Bytecode.CONVERT_U */, '');
define(117 /* Bytecode.CONVERT_D */, '');
define(118 /* Bytecode.CONVERT_B */, '');
define(119 /* Bytecode.CONVERT_O */, '');
define(120 /* Bytecode.CHECKFILTER */, '');
define(121 /* Bytecode.CONVERT_F */, '');
define(122 /* Bytecode.UNPLUS */, '');
define(123 /* Bytecode.CONVERT_F4 */, '');
define(128 /* Bytecode.COERCE */, 'e');
define(129 /* Bytecode.COERCE_B */, '');
define(130 /* Bytecode.COERCE_A */, '');
define(131 /* Bytecode.COERCE_I */, '');
define(132 /* Bytecode.COERCE_D */, '');
define(133 /* Bytecode.COERCE_S */, '');
define(134 /* Bytecode.ASTYPE */, 'e');
define(135 /* Bytecode.ASTYPELATE */, '');
define(136 /* Bytecode.COERCE_U */, '');
define(137 /* Bytecode.COERCE_O */, '');
define(144 /* Bytecode.NEGATE */, '');
define(145 /* Bytecode.INCREMENT */, '');
define(146 /* Bytecode.INCLOCAL */, 'e');
define(147 /* Bytecode.DECREMENT */, '');
define(148 /* Bytecode.DECLOCAL */, 'e');
define(149 /* Bytecode.TYPEOF */, '');
define(150 /* Bytecode.NOT */, '');
define(151 /* Bytecode.BITNOT */, '');
define(160 /* Bytecode.ADD */, '');
define(161 /* Bytecode.SUBTRACT */, '');
define(162 /* Bytecode.MULTIPLY */, '');
define(163 /* Bytecode.DIVIDE */, '');
define(164 /* Bytecode.MODULO */, '');
define(165 /* Bytecode.LSHIFT */, '');
define(166 /* Bytecode.RSHIFT */, '');
define(167 /* Bytecode.URSHIFT */, '');
define(168 /* Bytecode.BITAND */, '');
define(169 /* Bytecode.BITOR */, '');
define(170 /* Bytecode.BITXOR */, '');
define(171 /* Bytecode.EQUALS */, '');
define(172 /* Bytecode.STRICTEQUALS */, '');
define(173 /* Bytecode.LESSTHAN */, '');
define(174 /* Bytecode.LESSEQUALS */, '');
define(175 /* Bytecode.GREATERTHAN */, '');
define(176 /* Bytecode.GREATEREQUALS */, '');
define(177 /* Bytecode.INSTANCEOF */, '');
define(178 /* Bytecode.ISTYPE */, 'e');
define(179 /* Bytecode.ISTYPELATE */, '');
define(180 /* Bytecode.IN */, '');
define(192 /* Bytecode.INCREMENT_I */, '');
define(193 /* Bytecode.DECREMENT_I */, '');
define(194 /* Bytecode.INCLOCAL_I */, 'e');
define(195 /* Bytecode.DECLOCAL_I */, 'e');
define(196 /* Bytecode.NEGATE_I */, '');
define(197 /* Bytecode.ADD_I */, '');
define(198 /* Bytecode.SUBTRACT_I */, '');
define(199 /* Bytecode.MULTIPLY_I */, '');
define(208 /* Bytecode.GETLOCAL0 */, '');
define(209 /* Bytecode.GETLOCAL1 */, '');
define(210 /* Bytecode.GETLOCAL2 */, '');
define(211 /* Bytecode.GETLOCAL3 */, '');
define(212 /* Bytecode.SETLOCAL0 */, '');
define(213 /* Bytecode.SETLOCAL1 */, '');
define(214 /* Bytecode.SETLOCAL2 */, '');
define(215 /* Bytecode.SETLOCAL3 */, '');
define(237 /* Bytecode.INVALID */, '');
define(239 /* Bytecode.DEBUG */, 'aeae');
define(240 /* Bytecode.DEBUGLINE */, 'e');
define(241 /* Bytecode.DEBUGFILE */, 'e');
define(242 /* Bytecode.BKPTLINE */, 'e');
define(243 /* Bytecode.TIMESTAMP */, '');
// define(Bytecode.UNUSED_6B, "", Flags.NONE);
// define(Bytecode.UNUSED_DE, "", Flags.NONE);
// define(Bytecode.UNUSED_BB, "", Flags.NONE);
}
defineBytecodes();
var Bytes = /** @class */ (function () {
function Bytes() {
}
Bytes.u8 = function (code, i) {
return code[i];
};
Bytes.s32 = function (code, i) {
var result = code[i];
if (result & 0x80) {
result = result & 0x7f | code[i + 1] << 7;
if (result & 0x4000) {
result = result & 0x3fff | code[i + 2] << 14;
if (result & 0x200000) {
result = result & 0x1fffff | code[i + 3] << 21;
if (result & 0x10000000) {
result = result & 0x0fffffff | code[i + 4] << 28;
result = result & 0xffffffff;
}
}
}
}
return result;
};
Bytes.u32 = function (code, i) {
return Bytes.s32(code, i) >>> 0;
};
Bytes.u30 = function (code, i) {
return Bytes.u32(code, i);
};
Bytes.s32Length = function (code, i) {
var result = code[i];
if (result & 0x80) {
result = result & 0x7f | code[i + 1] << 7;
if (result & 0x4000) {
result = result & 0x3fff | code[i + 2] << 14;
if (result & 0x200000) {
result = result & 0x1fffff | code[i + 3] << 21;
if (result & 0x10000000) {
return 5;
}
return 4;
}
return 3;
}
return 2;
}
return 1;
};
return Bytes;
}());
export { Bytes };
function lengthAt(code, i) {
var l = 1;
var bytecode = code[i];
if (bytecode === 27 /* Bytecode.LOOKUPSWITCH */) {
l += 3; // Default offset.
var n = Bytes.u30(code, i + l) + 1; // Offsets
l += Bytes.s32Length(code, i + l);
l += n * 3;
return l;
}
var format = BytecodeFormat[bytecode];
if (format === '') {
return l;
}
assert(format, 'OP: ' + getBytecodeName(bytecode));
for (var j = 0; j < format.length; j++) {
var f = format[j].charCodeAt(0) - 97;
switch (f) {
case 0 /* Sizes.u08 */:
case 1 /* Sizes.s08 */:
l += 1;
continue;
case 3 /* Sizes.s24 */:
l += 3;
continue;
case 2 /* Sizes.s16 */:
case 4 /* Sizes.u30 */:
case 5 /* Sizes.u32 */:
l += Bytes.s32Length(code, i + l);
continue;
}
}
return l;
}
var BytecodeStream = /** @class */ (function () {
function BytecodeStream(code) {
this._code = code;
this.setBCI(0);
}
BytecodeStream.prototype.next = function () {
this.setBCI(this._nextBCI);
};
BytecodeStream.prototype.endBCI = function () {
return this._code.length;
};
Object.defineProperty(BytecodeStream.prototype, "nextBCI", {
get: function () {
return this._nextBCI;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BytecodeStream.prototype, "currentBCI", {
get: function () {
return this._currentBCI;
},
enumerable: false,
configurable: true
});
BytecodeStream.prototype.currentBytecode = function () {
return this._bytecode;
};
BytecodeStream.prototype.nextBC = function () {
return Bytes.u8(this._code, this._nextBCI);
};
BytecodeStream.prototype.setBCI = function (bci) {
this._currentBCI = bci;
if (this._currentBCI < this._code.length) {
this._bytecode = Bytes.u8(this._code, bci);
var l = lengthAt(this._code, bci);
this._nextBCI = bci + l;
}
else {
this._bytecode = 255 /* Bytecode.END */;
this._nextBCI = this._currentBCI;
}
};
return BytecodeStream;
}());
export { BytecodeStream };