Repository: irelance/jsc-decompile-mozjs-34 Branch: master Commit: 44ffa1b0bb5f Files: 17 Total size: 127.4 KB Directory structure: gitextract_il3n6s28/ ├── .gitignore ├── composer.json ├── readme.md ├── run.php ├── scan.php └── src/ ├── Constant.php ├── Context.php ├── Decompile.php ├── Helper/ │ ├── Operation.php │ ├── Reveal.php │ └── Stack.php └── Xdr/ ├── Atom.php ├── Common.php ├── ObjectXdr.php ├── Operation.php ├── Scope.php └── Script.php ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ js/ compile libmozglue.dylib libmozjs-52.dylib .idea/ /vendor/ composer.lock ================================================ FILE: composer.json ================================================ { "name": "irelance/jsc-decompile-mozjs-34", "license": "proprietary", "type": "project", "authors": [ { "name": "irelance", "email": "heirelance@163.com" } ], "autoload": { "psr-4": { "Irelance\\Mozjs34\\": "src" } }, "require": { "php": ">=7.0.0" } } ================================================ FILE: readme.md ================================================ # 1.Summary This project is a javascript bytecode decoder for mozilla spider-monkey version 34. This version may decompile jsc file compile by cocos-2dx. It would not work for different version of Mozilla spider-monkey (without shell of course), for its opcode defined different for each version. Maybe no longer update, but still a good example to understand how javascript virtual machine work (though different engine has different implement). Is this project can just decompile "34" version only and why? Well, the truth is may decompile near 34 version before bytecode file structure change. Js engine may change the file struct for support new language feather, performance optimization, code refactoring, ... But think of most change is just to add ```section```(concept come of executable binary file) and add ```operation``` instead of change struct. So this project just try to decompile without check magic code. At least, scan.php will work at most time. # 2.Usage ## 2.1.Install PHP and Composer If you are familiar with php, you can skip this part. install php7.0 (still work in php7.4) ``` # ubuntu $ sudo apt install php7.0 # mac $ brew install php7.0 # windows # just google an binary one ``` install composer >see https://getcomposer.org/download/ install this project ``` $ cd path/to/project # no dependences, just auto generate the autoload $ composer install ``` ## 2.2.decompile *.jsc file ``` $ cd /path/to/this/project $ php run.php /path/to/your.jsc > /path/to/decompile.txt #if this didn't work, you can also try below command to get the bitcode $ php scan.php /path/to/your.jsc > /path/to/scan.txt ``` ## 2.3. print more info with scan.php Just remove the slashes in scan.php # 3. How to guess the bytecode version | magic code | version | | --- | --- | | 2C C0 73 B9 | 33 | | 28 C0 73 B9 | 34 | | 25 C0 73 B9 | 35 | | 04 C0 73 B9 | 36 | | FC BF 73 B9 | 37 | | F4 BF 73 B9 | 38 | | D1 BF 73 B9 | 39 | | C3 BF 73 B9 | 40 | | B7 BF 73 B9 | 41 | | B3 BF 73 B9 | 42 | | AB BF 73 B9 | 43 | | A0 BF 73 B9 | 44 | | 95 BF 73 B9 | 45 | | 88 BF 73 B9 | 46 | | 81 BF 73 B9 | 47 | Yes, change happens >= 48. bytecodeVer(int) change to buildId(string). And buildId is very like an useragent of browser. # 4.Besides This project is not complete yet. - A Fatal Bug was found when decompile with a deep context Decompile result is not a runable file. Some local variables are auto generate, for the compiler discards local variables. ================================================ FILE: run.php ================================================ run(); //$decompile->runResult(); $contexts = $decompile->getContexts(); foreach ($contexts as $index => $context) { //if ($index==0) { echo '==================================' . $index . '==================================S', CLIENT_EOL; /* @var \Irelance\Mozjs34\Context $context */ $context->printProperties([ //'Summaries', //'Atoms', //'Operations', 'Argv', 'Content', //'Nodes', //'Consts', //'Objects', //'Regexps', //'TryNote', //'ScopeNote', ]); echo '==========================================================================E', CLIENT_EOL; //} } ================================================ FILE: scan.php ================================================ run(); //$decompile->runResult(); $contexts = $decompile->getContexts(); foreach ($contexts as $index => $context) { //if ($index==0) { echo '==================================' . $index . '==================================S', CLIENT_EOL; /* @var \Irelance\Mozjs34\Context $context */ $context->printProperties([ //'Summaries', 'Atoms', 'Operations', 'Argv', //'Content', 'Nodes', 'Consts', //'Objects', 'Regexps', //'TryNote', //'ScopeNote', ]); echo '==========================================================================E', CLIENT_EOL; //} } ================================================ FILE: src/Constant.php ================================================ "); } define('JSID_TYPE_STRING', 0x0); define('JSID_TYPE_INT', 0x1); define('JSID_TYPE_VOID', 0x2); define('JSID_TYPE_SYMBOL', 0x4); define('JSID_TYPE_MASK', 0x7); define("js_undefined_str", "undefined"); define("js_typeof_str", "typeof"); define("js_void_str", "void"); define("js_null_str", "null"); define("js_false_str", "false"); define("js_true_str", "true"); define("js_throw_str", "throw"); define("js_in_str", "in"); define("js_instanceof_str", "instanceof"); define("js_this_str", "this"); define("js_new_str", "new"); class Constant { const _ConstTag = [ 'SCRIPT_INT', 'SCRIPT_DOUBLE', 'SCRIPT_ATOM', 'SCRIPT_TRUE', 'SCRIPT_FALSE', 'SCRIPT_NULL', 'SCRIPT_OBJECT', 'SCRIPT_VOID', 'SCRIPT_HOLE', ]; const _Class = [ 'CK_BlockObject', 'CK_WithObject', 'CK_JSFunction', 'CK_JSObject' ]; const _ScriptBits = [ 'NoScriptRval', 'SavedCallerFun', 'Strict', 'ContainsDynamicNameAccess', 'FunHasExtensibleScope', 'FunNeedsDeclEnvObject', 'FunHasAnyAliasedFormal', 'ArgumentsHasVarBinding', 'NeedsArgsObj', 'IsGeneratorExp', 'IsLegacyGenerator', 'IsStarGenerator', 'OwnSource', 'ExplicitUseStrict', 'SelfHosted', 'IsCompileAndGo', 'HasSingleton', 'TreatAsRunOnce', 'HasLazyScript' ]; const _FirstWordFlag = [ 'HasAtom' => 0x1, 'IsStarGenerator' => 0x2, 'IsLazy' => 0x4, 'HasSingletonType' => 0x8 ]; const _Opcode = [ 0 => ['op' => 'JSOP_NOP', 'val' => 0, 'name' => "nop", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 1 => ['op' => 'JSOP_UNDEFINED', 'val' => 1, 'name' => js_undefined_str, 'image' => "", 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 2 => ['op' => 'JSOP_UNUSED2', 'val' => 2, 'name' => "unused2", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 0, 'format' => ['JOF_BYTE']], 3 => ['op' => 'JSOP_ENTERWITH', 'val' => 3, 'name' => "enterwith", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 0, 'format' => ['JOF_OBJECT']], 4 => ['op' => 'JSOP_LEAVEWITH', 'val' => 4, 'name' => "leavewith", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 5 => ['op' => 'JSOP_RETURN', 'val' => 5, 'name' => "return", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 0, 'format' => ['JOF_BYTE']], 6 => ['op' => 'JSOP_GOTO', 'val' => 6, 'name' => "goto", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 0, 'format' => ['JOF_JUMP']], 7 => ['op' => 'JSOP_IFEQ', 'val' => 7, 'name' => "ifeq", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 0, 'format' => ['JOF_JUMP', 'JOF_DETECTING']], 8 => ['op' => 'JSOP_IFNE', 'val' => 8, 'name' => "ifne", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 0, 'format' => ['JOF_JUMP']], 9 => ['op' => 'JSOP_ARGUMENTS', 'val' => 9, 'name' => "arguments", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 10 => ['op' => 'JSOP_SWAP', 'val' => 10, 'name' => "swap", 'image' => NULL, 'len' => 1, 'use' => 2, 'def' => 2, 'format' => ['JOF_BYTE']], 11 => ['op' => 'JSOP_POPN', 'val' => 11, 'name' => "popn", 'image' => NULL, 'len' => 3, 'use' => -1, 'def' => 0, 'format' => ['JOF_UINT16']], 12 => ['op' => 'JSOP_DUP', 'val' => 12, 'name' => "dup", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 2, 'format' => ['JOF_BYTE']], 13 => ['op' => 'JSOP_DUP2', 'val' => 13, 'name' => "dup2", 'image' => NULL, 'len' => 1, 'use' => 2, 'def' => 4, 'format' => ['JOF_BYTE']], 14 => ['op' => 'JSOP_SETCONST', 'val' => 14, 'name' => "setconst", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME', 'JOF_SET']], 15 => ['op' => 'JSOP_BITOR', 'val' => 15, 'name' => "bitor", 'image' => "|", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 16 => ['op' => 'JSOP_BITXOR', 'val' => 16, 'name' => "bitxor", 'image' => "^", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 17 => ['op' => 'JSOP_BITAND', 'val' => 17, 'name' => "bitand", 'image' => "&", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 18 => ['op' => 'JSOP_EQ', 'val' => 18, 'name' => "eq", 'image' => "==", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH', 'JOF_DETECTING']], 19 => ['op' => 'JSOP_NE', 'val' => 19, 'name' => "ne", 'image' => "!=", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH', 'JOF_DETECTING']], 20 => ['op' => 'JSOP_LT', 'val' => 20, 'name' => "lt", 'image' => "<", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 21 => ['op' => 'JSOP_LE', 'val' => 21, 'name' => "le", 'image' => "<=", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 22 => ['op' => 'JSOP_GT', 'val' => 22, 'name' => "gt", 'image' => ">", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 23 => ['op' => 'JSOP_GE', 'val' => 23, 'name' => "ge", 'image' => ">=", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 24 => ['op' => 'JSOP_LSH', 'val' => 24, 'name' => "lsh", 'image' => "<<", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 25 => ['op' => 'JSOP_RSH', 'val' => 25, 'name' => "rsh", 'image' => ">>", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 26 => ['op' => 'JSOP_URSH', 'val' => 26, 'name' => "ursh", 'image' => ">>>", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 27 => ['op' => 'JSOP_ADD', 'val' => 27, 'name' => "add", 'image' => "+", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 28 => ['op' => 'JSOP_SUB', 'val' => 28, 'name' => "sub", 'image' => "-", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 29 => ['op' => 'JSOP_MUL', 'val' => 29, 'name' => "mul", 'image' => "*", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 30 => ['op' => 'JSOP_DIV', 'val' => 30, 'name' => "div", 'image' => "/", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 31 => ['op' => 'JSOP_MOD', 'val' => 31, 'name' => "mod", 'image' => "%", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_ARITH']], 32 => ['op' => 'JSOP_NOT', 'val' => 32, 'name' => "not", 'image' => "!", 'len' => 1, 'use' => 1, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ARITH', 'JOF_DETECTING']], 33 => ['op' => 'JSOP_BITNOT', 'val' => 33, 'name' => "bitnot", 'image' => "~", 'len' => 1, 'use' => 1, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ARITH']], 34 => ['op' => 'JSOP_NEG', 'val' => 34, 'name' => "neg", 'image' => "- ", 'len' => 1, 'use' => 1, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ARITH']], 35 => ['op' => 'JSOP_POS', 'val' => 35, 'name' => "pos", 'image' => "+ ", 'len' => 1, 'use' => 1, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ARITH']], 36 => ['op' => 'JSOP_DELNAME', 'val' => 36, 'name' => "delname", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME']], 37 => ['op' => 'JSOP_DELPROP', 'val' => 37, 'name' => "delprop", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_PROP']], 38 => ['op' => 'JSOP_DELELEM', 'val' => 38, 'name' => "delelem", 'image' => NULL, 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ELEM']], 39 => ['op' => 'JSOP_TYPEOF', 'val' => 39, 'name' => js_typeof_str, 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_DETECTING']], 40 => ['op' => 'JSOP_VOID', 'val' => 40, 'name' => js_void_str, 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 1, 'format' => ['JOF_BYTE']], 41 => ['op' => 'JSOP_SPREADCALL', 'val' => 41, 'name' => "spreadcall", 'image' => NULL, 'len' => 1, 'use' => 3, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_INVOKE', 'JOF_TYPESET']], 42 => ['op' => 'JSOP_SPREADNEW', 'val' => 42, 'name' => "spreadnew", 'image' => NULL, 'len' => 1, 'use' => 3, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_INVOKE', 'JOF_TYPESET']], 43 => ['op' => 'JSOP_SPREADEVAL', 'val' => 43, 'name' => "spreadeval", 'image' => NULL, 'len' => 1, 'use' => 3, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_INVOKE', 'JOF_TYPESET']], 44 => ['op' => 'JSOP_DUPAT', 'val' => 44, 'name' => "dupat", 'image' => NULL, 'len' => 4, 'use' => 0, 'def' => 1, 'format' => ['JOF_UINT24']], 45 => ['op' => 'JSOP_UNUSED45', 'val' => 45, 'name' => "unused45", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 46 => ['op' => 'JSOP_UNUSED46', 'val' => 46, 'name' => "unused46", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 47 => ['op' => 'JSOP_UNUSED47', 'val' => 47, 'name' => "unused47", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 48 => ['op' => 'JSOP_UNUSED48', 'val' => 48, 'name' => "unused48", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 49 => ['op' => 'JSOP_UNUSED49', 'val' => 49, 'name' => "unused49", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 50 => ['op' => 'JSOP_UNUSED50', 'val' => 50, 'name' => "unused50", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 51 => ['op' => 'JSOP_UNUSED51', 'val' => 51, 'name' => "unused51", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 52 => ['op' => 'JSOP_UNUSED52', 'val' => 52, 'name' => "unused52", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 53 => ['op' => 'JSOP_GETPROP', 'val' => 53, 'name' => "getprop", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_PROP', 'JOF_TYPESET', 'JOF_TMPSLOT3']], 54 => ['op' => 'JSOP_SETPROP', 'val' => 54, 'name' => "setprop", 'image' => NULL, 'len' => 5, 'use' => 2, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_PROP', 'JOF_SET', 'JOF_DETECTING']], 55 => ['op' => 'JSOP_GETELEM', 'val' => 55, 'name' => "getelem", 'image' => NULL, 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ELEM', 'JOF_TYPESET', 'JOF_LEFTASSOC']], 56 => ['op' => 'JSOP_SETELEM', 'val' => 56, 'name' => "setelem", 'image' => NULL, 'len' => 1, 'use' => 3, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ELEM', 'JOF_SET', 'JOF_DETECTING']], 57 => ['op' => 'JSOP_UNUSED57', 'val' => 57, 'name' => "unused57", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 58 => ['op' => 'JSOP_CALL', 'val' => 58, 'name' => "call", 'image' => NULL, 'len' => 3, 'use' => -1, 'def' => 1, 'format' => ['JOF_UINT16', 'JOF_INVOKE', 'JOF_TYPESET']], 59 => ['op' => 'JSOP_NAME', 'val' => 59, 'name' => "name", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME', 'JOF_TYPESET']], 60 => ['op' => 'JSOP_DOUBLE', 'val' => 60, 'name' => "double", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_DOUBLE']], 61 => ['op' => 'JSOP_STRING', 'val' => 61, 'name' => "string", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_ATOM']], 62 => ['op' => 'JSOP_ZERO', 'val' => 62, 'name' => "zero", 'image' => "0", 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 63 => ['op' => 'JSOP_ONE', 'val' => 63, 'name' => "one", 'image' => "1", 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 64 => ['op' => 'JSOP_NULL', 'val' => 64, 'name' => js_null_str, 'image' => js_null_str, 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 65 => ['op' => 'JSOP_THIS', 'val' => 65, 'name' => js_this_str, 'image' => js_this_str, 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 66 => ['op' => 'JSOP_FALSE', 'val' => 66, 'name' => js_false_str, 'image' => js_false_str, 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 67 => ['op' => 'JSOP_TRUE', 'val' => 67, 'name' => js_true_str, 'image' => js_true_str, 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 68 => ['op' => 'JSOP_OR', 'val' => 68, 'name' => "or", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 1, 'format' => ['JOF_JUMP', 'JOF_DETECTING', 'JOF_LEFTASSOC']], 69 => ['op' => 'JSOP_AND', 'val' => 69, 'name' => "and", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 1, 'format' => ['JOF_JUMP', 'JOF_DETECTING', 'JOF_LEFTASSOC']], 70 => ['op' => 'JSOP_TABLESWITCH', 'val' => 70, 'name' => "tableswitch", 'image' => NULL, 'len' => -1, 'use' => 1, 'def' => 0, 'format' => ['JOF_TABLESWITCH', 'JOF_DETECTING']], 71 => ['op' => 'JSOP_RUNONCE', 'val' => 71, 'name' => "runonce", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 72 => ['op' => 'JSOP_STRICTEQ', 'val' => 72, 'name' => "stricteq", 'image' => "===", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_DETECTING', 'JOF_LEFTASSOC', 'JOF_ARITH']], 73 => ['op' => 'JSOP_STRICTNE', 'val' => 73, 'name' => "strictne", 'image' => "!==", 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_DETECTING', 'JOF_LEFTASSOC', 'JOF_ARITH']], 74 => ['op' => 'JSOP_SETCALL', 'val' => 74, 'name' => "setcall", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 75 => ['op' => 'JSOP_ITER', 'val' => 75, 'name' => "iter", 'image' => NULL, 'len' => 2, 'use' => 1, 'def' => 1, 'format' => ['JOF_UINT8']], 76 => ['op' => 'JSOP_MOREITER', 'val' => 76, 'name' => "moreiter", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 2, 'format' => ['JOF_BYTE']], 77 => ['op' => 'JSOP_ITERNEXT', 'val' => 77, 'name' => "iternext", 'image' => "", 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 78 => ['op' => 'JSOP_ENDITER', 'val' => 78, 'name' => "enditer", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 0, 'format' => ['JOF_BYTE']], 79 => ['op' => 'JSOP_FUNAPPLY', 'val' => 79, 'name' => "funapply", 'image' => NULL, 'len' => 3, 'use' => -1, 'def' => 1, 'format' => ['JOF_UINT16', 'JOF_INVOKE', 'JOF_TYPESET']], 80 => ['op' => 'JSOP_OBJECT', 'val' => 80, 'name' => "object", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_OBJECT']], 81 => ['op' => 'JSOP_POP', 'val' => 81, 'name' => "pop", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 0, 'format' => ['JOF_BYTE']], 82 => ['op' => 'JSOP_NEW', 'val' => 82, 'name' => js_new_str, 'image' => NULL, 'len' => 3, 'use' => -1, 'def' => 1, 'format' => ['JOF_UINT16', 'JOF_INVOKE', 'JOF_TYPESET']], 83 => ['op' => 'JSOP_UNUSED83', 'val' => 83, 'name' => "unused83", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 84 => ['op' => 'JSOP_GETARG', 'val' => 84, 'name' => "getarg", 'image' => NULL, 'len' => 3, 'use' => 0, 'def' => 1, 'format' => ['JOF_QARG', 'JOF_NAME']], 85 => ['op' => 'JSOP_SETARG', 'val' => 85, 'name' => "setarg", 'image' => NULL, 'len' => 3, 'use' => 1, 'def' => 1, 'format' => ['JOF_QARG', 'JOF_NAME', 'JOF_SET']], 86 => ['op' => 'JSOP_GETLOCAL', 'val' => 86, 'name' => "getlocal", 'image' => NULL, 'len' => 4, 'use' => 0, 'def' => 1, 'format' => ['JOF_LOCAL', 'JOF_NAME']], 87 => ['op' => 'JSOP_SETLOCAL', 'val' => 87, 'name' => "setlocal", 'image' => NULL, 'len' => 4, 'use' => 1, 'def' => 1, 'format' => ['JOF_LOCAL', 'JOF_NAME', 'JOF_SET', 'JOF_DETECTING']], 88 => ['op' => 'JSOP_UINT16', 'val' => 88, 'name' => "uint16", 'image' => NULL, 'len' => 3, 'use' => 0, 'def' => 1, 'format' => ['JOF_UINT16']], 89 => ['op' => 'JSOP_NEWINIT', 'val' => 89, 'name' => "newinit", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_UINT8']], 90 => ['op' => 'JSOP_NEWARRAY', 'val' => 90, 'name' => "newarray", 'image' => NULL, 'len' => 4, 'use' => 0, 'def' => 1, 'format' => ['JOF_UINT24']], 91 => ['op' => 'JSOP_NEWOBJECT', 'val' => 91, 'name' => "newobject", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_OBJECT']], 92 => ['op' => 'JSOP_ENDINIT', 'val' => 92, 'name' => "endinit", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 93 => ['op' => 'JSOP_INITPROP', 'val' => 93, 'name' => "initprop", 'image' => NULL, 'len' => 5, 'use' => 2, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_PROP', 'JOF_SET', 'JOF_DETECTING']], 94 => ['op' => 'JSOP_INITELEM', 'val' => 94, 'name' => "initelem", 'image' => NULL, 'len' => 1, 'use' => 3, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ELEM', 'JOF_SET', 'JOF_DETECTING']], 95 => ['op' => 'JSOP_INITELEM_INC', 'val' => 95, 'name' => "initelem_inc", 'image' => NULL, 'len' => 1, 'use' => 3, 'def' => 2, 'format' => ['JOF_BYTE', 'JOF_ELEM', 'JOF_SET']], 96 => ['op' => 'JSOP_INITELEM_ARRAY', 'val' => 96, 'name' => "initelem_array", 'image' => NULL, 'len' => 4, 'use' => 2, 'def' => 1, 'format' => ['JOF_UINT24', 'JOF_ELEM', 'JOF_SET', 'JOF_DETECTING']], 97 => ['op' => 'JSOP_INITPROP_GETTER', 'val' => 97, 'name' => "initprop_getter", 'image' => NULL, 'len' => 5, 'use' => 2, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_PROP', 'JOF_SET', 'JOF_DETECTING']], 98 => ['op' => 'JSOP_INITPROP_SETTER', 'val' => 98, 'name' => "initprop_setter", 'image' => NULL, 'len' => 5, 'use' => 2, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_PROP', 'JOF_SET', 'JOF_DETECTING']], 99 => ['op' => 'JSOP_INITELEM_GETTER', 'val' => 99, 'name' => "initelem_getter", 'image' => NULL, 'len' => 1, 'use' => 3, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ELEM', 'JOF_SET', 'JOF_DETECTING']], 100 => ['op' => 'JSOP_INITELEM_SETTER', 'val' => 100, 'name' => "initelem_setter", 'image' => NULL, 'len' => 1, 'use' => 3, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ELEM', 'JOF_SET', 'JOF_DETECTING']], 101 => ['op' => 'JSOP_CALLSITEOBJ', 'val' => 101, 'name' => "callsiteobj", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_OBJECT']], 102 => ['op' => 'JSOP_NEWARRAY_COPYONWRITE', 'val' => 102, 'name' => "newarray_copyonwrite", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_OBJECT']], 103 => ['op' => 'JSOP_UNUSED103', 'val' => 103, 'name' => "unused103", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 104 => ['op' => 'JSOP_UNUSED104', 'val' => 104, 'name' => "unused104", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 105 => ['op' => 'JSOP_UNUSED105', 'val' => 105, 'name' => "unused105", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 106 => ['op' => 'JSOP_LABEL', 'val' => 106, 'name' => "label", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 0, 'format' => ['JOF_JUMP']], 107 => ['op' => 'JSOP_UNUSED107', 'val' => 107, 'name' => "unused107", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 108 => ['op' => 'JSOP_FUNCALL', 'val' => 108, 'name' => "funcall", 'image' => NULL, 'len' => 3, 'use' => -1, 'def' => 1, 'format' => ['JOF_UINT16', 'JOF_INVOKE', 'JOF_TYPESET']], 109 => ['op' => 'JSOP_LOOPHEAD', 'val' => 109, 'name' => "loophead", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 110 => ['op' => 'JSOP_BINDNAME', 'val' => 110, 'name' => "bindname", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME', 'JOF_SET']], 111 => ['op' => 'JSOP_SETNAME', 'val' => 111, 'name' => "setname", 'image' => NULL, 'len' => 5, 'use' => 2, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME', 'JOF_SET', 'JOF_DETECTING']], 112 => ['op' => 'JSOP_THROW', 'val' => 112, 'name' => js_throw_str, 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 0, 'format' => ['JOF_BYTE']], 113 => ['op' => 'JSOP_IN', 'val' => 113, 'name' => js_in_str, 'image' => js_in_str, 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC']], 114 => ['op' => 'JSOP_INSTANCEOF', 'val' => 114, 'name' => js_instanceof_str, 'image' => js_instanceof_str, 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_LEFTASSOC', 'JOF_TMPSLOT']], 115 => ['op' => 'JSOP_DEBUGGER', 'val' => 115, 'name' => "debugger", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 116 => ['op' => 'JSOP_GOSUB', 'val' => 116, 'name' => "gosub", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 0, 'format' => ['JOF_JUMP']], 117 => ['op' => 'JSOP_RETSUB', 'val' => 117, 'name' => "retsub", 'image' => NULL, 'len' => 1, 'use' => 2, 'def' => 0, 'format' => ['JOF_BYTE']], 118 => ['op' => 'JSOP_EXCEPTION', 'val' => 118, 'name' => "exception", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 119 => ['op' => 'JSOP_LINENO', 'val' => 119, 'name' => "lineno", 'image' => NULL, 'len' => 3, 'use' => 0, 'def' => 0, 'format' => ['JOF_UINT16']], 120 => ['op' => 'JSOP_CONDSWITCH', 'val' => 120, 'name' => "condswitch", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 121 => ['op' => 'JSOP_CASE', 'val' => 121, 'name' => "case", 'image' => NULL, 'len' => 5, 'use' => 2, 'def' => 1, 'format' => ['JOF_JUMP']], 122 => ['op' => 'JSOP_DEFAULT', 'val' => 122, 'name' => "default", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 0, 'format' => ['JOF_JUMP']], 123 => ['op' => 'JSOP_EVAL', 'val' => 123, 'name' => "eval", 'image' => NULL, 'len' => 3, 'use' => -1, 'def' => 1, 'format' => ['JOF_UINT16', 'JOF_INVOKE', 'JOF_TYPESET']], 124 => ['op' => 'JSOP_UNUSED124', 'val' => 124, 'name' => "unused124", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 125 => ['op' => 'JSOP_UNUSED125', 'val' => 125, 'name' => "unused125", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 126 => ['op' => 'JSOP_UNUSED126', 'val' => 126, 'name' => "unused126", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 127 => ['op' => 'JSOP_DEFFUN', 'val' => 127, 'name' => "deffun", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 0, 'format' => ['JOF_OBJECT']], 128 => ['op' => 'JSOP_DEFCONST', 'val' => 128, 'name' => "defconst", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 0, 'format' => ['JOF_ATOM']], 129 => ['op' => 'JSOP_DEFVAR', 'val' => 129, 'name' => "defvar", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 0, 'format' => ['JOF_ATOM']], 130 => ['op' => 'JSOP_LAMBDA', 'val' => 130, 'name' => "lambda", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_OBJECT']], 131 => ['op' => 'JSOP_LAMBDA_ARROW', 'val' => 131, 'name' => "lambda_arrow", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 1, 'format' => ['JOF_OBJECT']], 132 => ['op' => 'JSOP_CALLEE', 'val' => 132, 'name' => "callee", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 133 => ['op' => 'JSOP_PICK', 'val' => 133, 'name' => "pick", 'image' => NULL, 'len' => 2, 'use' => 0, 'def' => 0, 'format' => ['JOF_UINT8', 'JOF_TMPSLOT2']], 134 => ['op' => 'JSOP_TRY', 'val' => 134, 'name' => "try", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 135 => ['op' => 'JSOP_FINALLY', 'val' => 135, 'name' => "finally", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 2, 'format' => ['JOF_BYTE']], 136 => ['op' => 'JSOP_GETALIASEDVAR', 'val' => 136, 'name' => "getaliasedvar", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_SCOPECOORD', 'JOF_NAME', 'JOF_TYPESET']], 137 => ['op' => 'JSOP_SETALIASEDVAR', 'val' => 137, 'name' => "setaliasedvar", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 1, 'format' => ['JOF_SCOPECOORD', 'JOF_NAME', 'JOF_SET', 'JOF_DETECTING']], 138 => ['op' => 'JSOP_UNUSED138', 'val' => 138, 'name' => "unused138", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 139 => ['op' => 'JSOP_UNUSED139', 'val' => 139, 'name' => "unused139", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 140 => ['op' => 'JSOP_UNUSED140', 'val' => 140, 'name' => "unused140", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 141 => ['op' => 'JSOP_UNUSED141', 'val' => 141, 'name' => "unused141", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 142 => ['op' => 'JSOP_UNUSED142', 'val' => 142, 'name' => "unused142", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 143 => ['op' => 'JSOP_GETINTRINSIC', 'val' => 143, 'name' => "getintrinsic", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME', 'JOF_TYPESET']], 144 => ['op' => 'JSOP_SETINTRINSIC', 'val' => 144, 'name' => "setintrinsic", 'image' => NULL, 'len' => 5, 'use' => 2, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME', 'JOF_SET', 'JOF_DETECTING']], 145 => ['op' => 'JSOP_BINDINTRINSIC', 'val' => 145, 'name' => "bindintrinsic", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME', 'JOF_SET']], 146 => ['op' => 'JSOP_UNUSED146', 'val' => 146, 'name' => "unused146", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 147 => ['op' => 'JSOP_UNUSED147', 'val' => 147, 'name' => "unused147", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 148 => ['op' => 'JSOP_UNUSED148', 'val' => 148, 'name' => "unused148", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 149 => ['op' => 'JSOP_BACKPATCH', 'val' => 149, 'name' => "backpatch", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 0, 'format' => ['JOF_JUMP']], 150 => ['op' => 'JSOP_UNUSED150', 'val' => 150, 'name' => "unused150", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 151 => ['op' => 'JSOP_THROWING', 'val' => 151, 'name' => "throwing", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 0, 'format' => ['JOF_BYTE']], 152 => ['op' => 'JSOP_SETRVAL', 'val' => 152, 'name' => "setrval", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 0, 'format' => ['JOF_BYTE']], 153 => ['op' => 'JSOP_RETRVAL', 'val' => 153, 'name' => "retrval", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 154 => ['op' => 'JSOP_GETGNAME', 'val' => 154, 'name' => "getgname", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME', 'JOF_TYPESET', 'JOF_GNAME']], 155 => ['op' => 'JSOP_SETGNAME', 'val' => 155, 'name' => "setgname", 'image' => NULL, 'len' => 5, 'use' => 2, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME', 'JOF_SET', 'JOF_DETECTING', 'JOF_GNAME']], 156 => ['op' => 'JSOP_UNUSED156', 'val' => 156, 'name' => "unused156", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 157 => ['op' => 'JSOP_UNUSED157', 'val' => 157, 'name' => "unused157", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 158 => ['op' => 'JSOP_UNUSED158', 'val' => 158, 'name' => "unused158", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 159 => ['op' => 'JSOP_UNUSED159', 'val' => 159, 'name' => "unused159", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 160 => ['op' => 'JSOP_REGEXP', 'val' => 160, 'name' => "regexp", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_REGEXP']], 161 => ['op' => 'JSOP_UNUSED161', 'val' => 161, 'name' => "unused161", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 162 => ['op' => 'JSOP_UNUSED162', 'val' => 162, 'name' => "unused162", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 163 => ['op' => 'JSOP_UNUSED163', 'val' => 163, 'name' => "unused163", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 164 => ['op' => 'JSOP_UNUSED164', 'val' => 164, 'name' => "unused164", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 165 => ['op' => 'JSOP_UNUSED165', 'val' => 165, 'name' => "unused165", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 166 => ['op' => 'JSOP_UNUSED166', 'val' => 166, 'name' => "unused166", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 167 => ['op' => 'JSOP_UNUSED167', 'val' => 167, 'name' => "unused167", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 168 => ['op' => 'JSOP_UNUSED168', 'val' => 168, 'name' => "unused168", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 169 => ['op' => 'JSOP_UNUSED169', 'val' => 169, 'name' => "unused169", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 170 => ['op' => 'JSOP_UNUSED170', 'val' => 170, 'name' => "unused170", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 171 => ['op' => 'JSOP_UNUSED171', 'val' => 171, 'name' => "unused171", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 172 => ['op' => 'JSOP_UNUSED172', 'val' => 172, 'name' => "unused172", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 173 => ['op' => 'JSOP_UNUSED173', 'val' => 173, 'name' => "unused173", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 174 => ['op' => 'JSOP_UNUSED174', 'val' => 174, 'name' => "unused174", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 175 => ['op' => 'JSOP_UNUSED175', 'val' => 175, 'name' => "unused175", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 176 => ['op' => 'JSOP_UNUSED176', 'val' => 176, 'name' => "unused176", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 177 => ['op' => 'JSOP_UNUSED177', 'val' => 177, 'name' => "unused177", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 178 => ['op' => 'JSOP_UNUSED178', 'val' => 178, 'name' => "unused178", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 179 => ['op' => 'JSOP_UNUSED179', 'val' => 179, 'name' => "unused179", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 180 => ['op' => 'JSOP_UNUSED180', 'val' => 180, 'name' => "unused180", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 181 => ['op' => 'JSOP_UNUSED181', 'val' => 181, 'name' => "unused181", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 182 => ['op' => 'JSOP_UNUSED182', 'val' => 182, 'name' => "unused182", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 183 => ['op' => 'JSOP_UNUSED183', 'val' => 183, 'name' => "unused183", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 184 => ['op' => 'JSOP_CALLPROP', 'val' => 184, 'name' => "callprop", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_PROP', 'JOF_TYPESET', 'JOF_TMPSLOT3']], 185 => ['op' => 'JSOP_UNUSED185', 'val' => 185, 'name' => "unused185", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 186 => ['op' => 'JSOP_UNUSED186', 'val' => 186, 'name' => "unused186", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 187 => ['op' => 'JSOP_UNUSED187', 'val' => 187, 'name' => "unused187", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 188 => ['op' => 'JSOP_UINT24', 'val' => 188, 'name' => "uint24", 'image' => NULL, 'len' => 4, 'use' => 0, 'def' => 1, 'format' => ['JOF_UINT24']], 189 => ['op' => 'JSOP_UNUSED189', 'val' => 189, 'name' => "unused189", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 190 => ['op' => 'JSOP_UNUSED190', 'val' => 190, 'name' => "unused190", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 191 => ['op' => 'JSOP_UNUSED191', 'val' => 191, 'name' => "unused191", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 192 => ['op' => 'JSOP_UNUSED192', 'val' => 192, 'name' => "unused192", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 193 => ['op' => 'JSOP_CALLELEM', 'val' => 193, 'name' => "callelem", 'image' => NULL, 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_ELEM', 'JOF_TYPESET', 'JOF_LEFTASSOC']], 194 => ['op' => 'JSOP_MUTATEPROTO', 'val' => 194, 'name' => "mutateproto", 'image' => NULL, 'len' => 1, 'use' => 2, 'def' => 1, 'format' => ['JOF_BYTE']], 195 => ['op' => 'JSOP_GETXPROP', 'val' => 195, 'name' => "getxprop", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_PROP', 'JOF_TYPESET']], 196 => ['op' => 'JSOP_UNUSED196', 'val' => 196, 'name' => "unused196", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 197 => ['op' => 'JSOP_TYPEOFEXPR', 'val' => 197, 'name' => "typeofexpr", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_DETECTING']], 198 => ['op' => 'JSOP_PUSHBLOCKSCOPE', 'val' => 198, 'name' => "pushblockscope", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 0, 'format' => ['JOF_OBJECT']], 199 => ['op' => 'JSOP_POPBLOCKSCOPE', 'val' => 199, 'name' => "popblockscope", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 200 => ['op' => 'JSOP_DEBUGLEAVEBLOCK', 'val' => 200, 'name' => "debugleaveblock", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 201 => ['op' => 'JSOP_UNUSED201', 'val' => 201, 'name' => "unused201", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 202 => ['op' => 'JSOP_GENERATOR', 'val' => 202, 'name' => "generator", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 203 => ['op' => 'JSOP_YIELD', 'val' => 203, 'name' => "yield", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 1, 'format' => ['JOF_BYTE']], 204 => ['op' => 'JSOP_ARRAYPUSH', 'val' => 204, 'name' => "arraypush", 'image' => NULL, 'len' => 1, 'use' => 2, 'def' => 0, 'format' => ['JOF_BYTE']], 205 => ['op' => 'JSOP_UNUSED205', 'val' => 205, 'name' => "unused205", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 206 => ['op' => 'JSOP_UNUSED206', 'val' => 206, 'name' => "unused206", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 207 => ['op' => 'JSOP_UNUSED207', 'val' => 207, 'name' => "unused207", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 208 => ['op' => 'JSOP_UNUSED208', 'val' => 208, 'name' => "unused208", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 209 => ['op' => 'JSOP_UNUSED209', 'val' => 209, 'name' => "unused209", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 210 => ['op' => 'JSOP_UNUSED210', 'val' => 210, 'name' => "unused210", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 211 => ['op' => 'JSOP_UNUSED211', 'val' => 211, 'name' => "unused211", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 212 => ['op' => 'JSOP_UNUSED212', 'val' => 212, 'name' => "unused212", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 213 => ['op' => 'JSOP_UNUSED213', 'val' => 213, 'name' => "unused213", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 214 => ['op' => 'JSOP_BINDGNAME', 'val' => 214, 'name' => "bindgname", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_NAME', 'JOF_SET', 'JOF_GNAME']], 215 => ['op' => 'JSOP_INT8', 'val' => 215, 'name' => "int8", 'image' => NULL, 'len' => 2, 'use' => 0, 'def' => 1, 'format' => ['JOF_INT8']], 216 => ['op' => 'JSOP_INT32', 'val' => 216, 'name' => "int32", 'image' => NULL, 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_INT32']], 217 => ['op' => 'JSOP_LENGTH', 'val' => 217, 'name' => "length", 'image' => NULL, 'len' => 5, 'use' => 1, 'def' => 1, 'format' => ['JOF_ATOM', 'JOF_PROP', 'JOF_TYPESET', 'JOF_TMPSLOT3']], 218 => ['op' => 'JSOP_HOLE', 'val' => 218, 'name' => "hole", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE']], 219 => ['op' => 'JSOP_UNUSED219', 'val' => 219, 'name' => "unused219", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 220 => ['op' => 'JSOP_UNUSED220', 'val' => 220, 'name' => "unused220", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 221 => ['op' => 'JSOP_UNUSED221', 'val' => 221, 'name' => "unused221", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 222 => ['op' => 'JSOP_UNUSED222', 'val' => 222, 'name' => "unused222", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 223 => ['op' => 'JSOP_UNUSED223', 'val' => 223, 'name' => "unused223", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 0, 'format' => ['JOF_BYTE']], 224 => ['op' => 'JSOP_REST', 'val' => 224, 'name' => "rest", 'image' => NULL, 'len' => 1, 'use' => 0, 'def' => 1, 'format' => ['JOF_BYTE', 'JOF_TYPESET']], 225 => ['op' => 'JSOP_TOID', 'val' => 225, 'name' => "toid", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 1, 'format' => ['JOF_BYTE']], 226 => ['op' => 'JSOP_IMPLICITTHIS', 'val' => 226, 'name' => "implicitthis", 'image' => "", 'len' => 5, 'use' => 0, 'def' => 1, 'format' => ['JOF_ATOM']], 227 => ['op' => 'JSOP_LOOPENTRY', 'val' => 227, 'name' => "loopentry", 'image' => NULL, 'len' => 2, 'use' => 0, 'def' => 0, 'format' => ['JOF_UINT8']], 228 => ['op' => 'JSOP_TOSTRING', 'val' => 228, 'name' => "tostring", 'image' => NULL, 'len' => 1, 'use' => 1, 'def' => 1, 'format' => ['JOF_BYTE']], ]; } ================================================ FILE: src/Context.php ================================================ argvs[] = $value; } public function addSummary($key, $value) { if (isset($this->summaries[$key])) { return false; } $this->summaries[$key] = $value; return true; } public function addOperation($parserIndex, array $operation) { $this->operations[$parserIndex] = $operation; } public function addNode($node) { $this->nodes[] = $node; } public function addAtom($atom) { $this->atoms[] = $atom; } public function addConst($const) { $this->consts[] = $const; } public function addObject($classKind, array $extra) { $this->objects[] = array_merge($extra, ['classKind' => $classKind]); } public function addRegexp($source, $flagsword) { $this->regexps[] = [ 'source' => $source, 'flagsword' => $flagsword, ]; } public function addTryNote($kind, $stackDepth, $start, $length) { $this->tryNotes[] = ['kind' => $kind, 'stackDepth' => $stackDepth, 'start' => $start, 'length' => $length]; } public function addScopeNote($index, $start, $length, $parent) { $this->scopeNotes[$index] = ['parent' => $parent, 'start' => $start, 'length' => $length]; } public function addHasLazyScript($packedFields) { $this->hasLazyScript = $packedFields; } public function getSummary($key) { return $this->summaries[$key]; } /** * @param $stack Stack|array */ public function pushStack($stack) { if (is_array($stack)) { $stack = new Stack($stack); } array_push($this->stack, $stack); } /** * @return Stack */ public function popStack() { return array_pop($this->stack); } protected $storageScript = []; public function writeScript($parserIndex, $string, $offset = 0) { $this->storageScript[$parserIndex * 2 + $offset] = ['value' => $string]; } public function appendScript($parserIndex, $string, $offset = 0) { if (!isset($this->storageScript[$parserIndex * 2 + $offset])) { $this->writeScript($parserIndex, $string, $offset); return; } $this->storageScript[$parserIndex * 2 + $offset]['value'] .= $string; } public function getScript($parserIndex, $offset = 0) { if (!isset($this->storageScript[$parserIndex * 2 + $offset])) { return ['value' => '']; } return $this->storageScript[$parserIndex * 2 + $offset]; } public function dropScript($parserIndex, $offset = 0) { if (isset($this->storageScript[$parserIndex * 2 + $offset])) { unset($this->storageScript[$parserIndex * 2 + $offset]); } } } ================================================ FILE: src/Decompile.php ================================================ fp = fopen($filename, 'rb'); $this->init(); } public function __destruct() { fclose($this->fp); } public function init() { $i = 0; while (!feof($this->fp)) { $c = fgetc($this->fp); $this->bytecodes[$i] = ord($c); $i++; } $this->bytecodeLength = count($this->bytecodes); } protected function parserVersion() { $this->parseIndex = 0; $bytecodeVer = $this->todec(); return $bytecodeVer; } public function run() { $this->parserVersion(); $this->XDRScript(); } public function runResult() { echo '----------------ByteCode---------------', CLIENT_EOL; echo 'file size :', $this->bytecodeLength, CLIENT_EOL; echo 'parse size :', 1 + $this->parseIndex, CLIENT_EOL; echo '---------------------------------------', CLIENT_EOL; } public function getContexts() { return $this->contexts; } protected $localVariable = []; public function setLocalVariable($index, $value) { $this->localVariable[$index] = $value; } public function getLocalVariable($index) { if (!isset($this->localVariable[$index])) { return new Stack(['parserIndex' => 0, 'type' => 'undefined', 'value' => 'undefined']); } return $this->localVariable[$index]; } protected $aliasedVariable = []; public function setAliasedVariable($hops, $slot, $value) { if (!isset($this->aliasedVariable[$hops])) { $this->aliasedVariable[$hops] = []; } $this->aliasedVariable[$hops][$slot] = $value; } public function getAliasedVariable($hops, $slot) { if (!isset($this->aliasedVariable[$hops][$slot])) { return new Stack(['parserIndex' => 0, 'type' => 'undefined', 'value' => 'undefined']); } return $this->aliasedVariable[$hops][$slot]; } protected $globalVariable = []; public function setGlobalVariable($key, $value) { $this->globalVariable[$key] = $value; } public function getGlobalVariable($key) { if (!isset($this->localVariable[$key])) { return new Stack(['parserIndex' => 0, 'type' => 'undefined', 'name' => $key, 'value' => $key]); } return $this->globalVariable[$key]; } } ================================================ FILE: src/Helper/Operation.php ================================================ operations[$goto])) { return false; } $nextOperation = $this->operations[$goto]; } return $nextOperation; } public function getNextOperation($operation) { $nextIndex = $operation['parserIndex'] + $operation['length']; if (!isset($this->operations[$nextIndex])) { return false; } return $this->operations[$nextIndex]; } public function revealOperations($start, $end, $conditons = [], $isCover = true) { $operationKeys = array_keys($this->operations); $operationKeysFlip = array_flip($operationKeys); $start = $operationKeysFlip[$start]; $end = $operationKeysFlip[$end]; for ($i = $start; $i < $end; $i++) { $operation = $this->operations[$operationKeys[$i]]; if (!$operation['isCover']) { if ($this->isDebug) { echo '[', $operationKeys[$i], ']', $operation['name'], json_encode($operation['params']), ' pop: ', $operation['pop'], ' push: ', $operation['push'], ' byte: ', $operation['length'], CLIENT_EOL; } $this->revealOperation($operation, $conditons); $this->operations[$operationKeys[$i]]['isCover'] = $isCover; } } } protected function hasOperation($start, $end, $name) { $operationKeys = array_keys($this->operations); $operationKeysFlip = array_flip($operationKeys); $start = $operationKeysFlip[$start]; $end = $operationKeysFlip[$end]; for ($i = $start + 1; $i < $end; $i++) { $operation = $this->operations[$operationKeys[$i]]; if ($operation['name'] == $name) { return true; } } return false; } protected function findFirstOperation($name, $start = null, $end = null) { if (is_string($name)) { $name = [$name]; } $operationKeys = array_keys($this->operations); $operationKeysFlip = array_flip($operationKeys); $start = is_null($start) ? 0 : $operationKeysFlip[$start]; $end = is_null($end) ? count($operationKeys) : $operationKeysFlip[$end]; for ($i = $start; $i < $end; $i++) { $operation = $this->operations[$operationKeys[$i]]; if (in_array($operation['name'], $name)) { return $operation; } } return false; } public function revealOperation($operation, $conditons = []) { switch ($operation['name']) { case 'JSOP_RETRVAL': case 'JSOP_ENDINIT': case 'JSOP_NOP': break; case 'JSOP_RETURN': $value = $this->getLogicValue($operation, $this->popStack()); $this->writeScript($operation['parserIndex'], 'return ' . $value . ';'); break; //change stack case 'JSOP_POP': case 'JSOP_SETRVAL': $rVal = $this->popStack(); if ($rVal && $script = $rVal->getScript()) { $this->writeScript($operation['parserIndex'], $script . ';'); } break; case 'JSOP_POPN': $n = $operation['params']['n']; for ($i = 0; $i < $n; $i++) { $this->popStack(); } break; case 'JSOP_DUP': $val = $this->popStack(); $this->pushStack($val); $this->pushStack($val); break; case 'JSOP_DUP2': $val1 = $this->popStack(); $val2 = $this->popStack(); $this->pushStack($val2); $this->pushStack($val1); $this->pushStack($val2); $this->pushStack($val1); break; case 'JSOP_DUPAT': $number = $operation['params']['n']; $temp = []; for ($i = 0; $i < $number; $i++) { $temp[$i] = $this->popStack(); } for ($i = $number - 1; $i >= 0; $i--) { $this->pushStack($temp[$i]); } $this->pushStack($temp[$number - 1]); break; case 'JSOP_PICK': $number = $operation['params']['n']; $temp = []; for ($i = 0; $i < $number; $i++) { $temp[$i] = $this->popStack(); } $nTh = $this->popStack(); for ($i = $number - 1; $i >= 0; $i--) { $this->pushStack($temp[$i]); } $this->pushStack($nTh); break; case 'JSOP_SWAP':// v1, v2 => v2, v1 $val1 = $this->popStack(); $val2 = $this->popStack(); $this->pushStack($val1); $this->pushStack($val2); break; //control goto case 'JSOP_GOTO': if (!empty($conditons)) { if (isset($conditons['type']) && $conditons['type'] == 'switch') { $gotoIndex = $operation['parserIndex'] + $operation['params']['offset']; if ($gotoIndex >= $conditons['defaultIndex']) { $this->writeScript($operation['parserIndex'], 'break;'); $this->writeScript($gotoIndex, '}', +1); return; } } } $this->_getBranchContinue($operation) || $this->_getBranchBreak($operation); break; //control branch case 'JSOP_IFEQ': $value = $this->getLogicValue($operation, $this->popStack()); //storage stack for k=x?a:b $stackCopy = serialize($this->stack); $this->appendScript($operation['parserIndex'], 'if(' . $value . '){'); if ($operation['params']['offset'] > 0) { $elseStart = $this->gotoNextOperation($operation); $this->revealOperations($operation['parserIndex'] + $operation['length'], $elseStart['parserIndex']); $gotoOperation = $this->_getBranchGoto($operation); while ($this->_getBranchContinue($gotoOperation) || $this->_getBranchBreak($gotoOperation)) { $gotoOperation = $this->findFirstOperation('JSOP_GOTO', $gotoOperation['parserIndex'] + $gotoOperation['length']); if (!$gotoOperation) { break; } } $hasNextOperation = false; $nextOperationIndex = false; if ($gotoOperation) { $hasNextOperation = $gotoOperation['name']; $nextOperationIndex = $gotoOperation['parserIndex']; if ($elseIfOperation = $this->findFirstOperation( 'JSOP_IFEQ', $gotoOperation['parserIndex'], $gotoOperation['parserIndex'] + $gotoOperation['params']['offset'] ) ) { $hasNextOperation = $elseIfOperation['name']; $nextOperationIndex = $elseIfOperation['parserIndex']; } } switch ($hasNextOperation) { case 'JSOP_IFEQ': $this->writeScript($nextOperationIndex, '} else '); break; case 'JSOP_GOTO': $this->writeScript($nextOperationIndex, '} else {'); default: $this->appendScript($operation['parserIndex'] + $operation['params']['offset'], '}', +1); break; } $oldCount = count(unserialize($stackCopy)); $newCount = count($this->stack); if ($oldCount != $newCount) { if (($newCount - $oldCount) != 1) { exit("[error] JSOP_IFEQ Unknown Type"); } $this->dropScript($nextOperationIndex); $this->dropScript($operation['parserIndex']); $this->dropScript($operation['parserIndex'] + $operation['params']['offset'], +1); if (!$gotoOperation) { exit("[error] JSOP_IFEQ No Goto "); } $setIndex = $gotoOperation['parserIndex'] + $gotoOperation['params']['offset']; $setOperation = $this->operations[$setIndex]; switch ($setOperation['name']) { case 'JSOP_SETELEM': case 'JSOP_SETNAME': case 'JSOP_SETCONST': case 'JSOP_SETPROP': case 'JSOP_INITPROP': $endOperation = $this->getNextOperation($setOperation); break; default://todo find all ending operation $endOperation = $this->findFirstOperation( ['JSOP_SETRVAL', 'JSOP_GOTO', 'JSOP_POP', 'JSOP_RETURN', 'JSOP_IFEQ', 'JSOP_IFNE', ], $setIndex ); break; } if (!$endOperation) { exit("[error] JSOP_IFEQ Unknown endOperation " . $operation['parserIndex']); } $this->revealOperations($setIndex, $endOperation['parserIndex'], [], false); $left = $this->popStack(); $this->stack = unserialize($stackCopy); $this->revealOperations($gotoOperation['parserIndex'] + 5, $endOperation['parserIndex']); $right = $this->popStack(); $this->pushStack(['type' => 'script', 'script' => $value . '?' . $left->getScript() . ':' . $right->getScript()]); return; } } break; case 'JSOP_TABLESWITCH': //case type is int $val = $this->popStack(); $this->writeScript($operation['parserIndex'], 'switch(' . $val->getValue() . '){'); $caseCurrent = $operation['params']['low']; $contents = []; foreach ($operation['params']['offset'] as $offset) { if ($offset) { $contentIndex = $operation['parserIndex'] + $offset; if (!isset($contents[$contentIndex])) { $contents[$contentIndex] = []; } $contents[$contentIndex][] = ['value' => 'case ' . $caseCurrent . ':']; } $caseCurrent++; } $defaultIndex = $operation['parserIndex'] + $operation['params']['len']; $this->_renderSwitch($contents, $defaultIndex); break; //control branch switch case type is mix case 'JSOP_CONDSWITCH': $name = $this->popStack(); $this->writeScript($operation['parserIndex'], 'switch(' . $name->getValue() . '){'); $this->pushStack(['type' => 'switch', 'value' => []]); break; case 'JSOP_CASE': $val = $this->popStack(); $switch = $this->popStack(); $contentIndex = $operation['parserIndex'] + $operation['params']['offset']; if (!isset($switch->value[$contentIndex])) { $switch->value[$contentIndex] = []; } $switch->value[$contentIndex][] = ['value' => 'case ' . $val->getValue() . ':']; $this->pushStack($switch); break; case 'JSOP_DEFAULT': $switch = $this->popStack(); $this->_renderSwitch($switch->value, $operation['parserIndex'] + $operation['params']['offset']); break; //control loop case 'JSOP_IFNE': $value = $this->getLogicValue($operation, $this->popStack()); $this->writeScript($operation['parserIndex'], 'if(' . $value . ')'); break; case 'JSOP_LOOPHEAD': $gotoOperation = $this->_getLoopGoto($operation); $isDo = !$gotoOperation; if ($isDo) { $this->writeScript($operation['parserIndex'], 'do{', -1); $entryOperation = $this->operations[$operation['parserIndex'] + $operation['length']]; $ifOperation = $entryOperation; do { $ifOperation = $this->_getLoopLogic($ifOperation); } while ($this->operations[$ifOperation['parserIndex'] + $ifOperation['params']['offset']]['parserIndex'] != $operation['parserIndex']); } else { $entryOperation = $this->operations[$gotoOperation['parserIndex'] + $gotoOperation['params']['offset']]; $ifOperation = $this->_getLoopLogic($entryOperation); } $this->revealOperations($entryOperation['parserIndex'], $ifOperation['parserIndex'] + $ifOperation['length']); $this->revealOperations($operation['parserIndex'] + $operation['length'], $entryOperation['parserIndex']); if ($isDo) { $this->writeScript( $ifOperation['parserIndex'], str_replace('if(', '} while(', $this->getScript($ifOperation['parserIndex'])['value']) ); } else { $this->writeScript( $operation['parserIndex'], str_replace('if(', 'while(', $this->getScript($ifOperation['parserIndex'])['value']) . '{', -1 ); $this->writeScript($ifOperation['parserIndex'], '}'); } break; case 'JSOP_LOOPENTRY': break; //For-In Statement case 'JSOP_ITER': $val = $this->popStack(); $this->pushStack($val); break; case 'JSOP_ITERNEXT': $this->pushStack(['type' => 'script', 'name' => '_iternext']); break; case 'JSOP_MOREITER': $val = $this->popStack(); $this->pushStack([]); $this->pushStack(['type' => 'script', 'script' => $val->getValue() . ' has _iternext']); break; case 'JSOP_ENDITER': $val = $this->popStack(); break; //math case 'JSOP_BITNOT': case 'JSOP_NEG': $value = $this->getLogicValue($operation, $this->popStack()); $this->pushStack(['script' => '(' . $operation['image'] . $value . ')', 'type' => 'script']); break; case 'JSOP_POS': break; //math case 'JSOP_ADD': case 'JSOP_SUB': case 'JSOP_MUL': case 'JSOP_DIV': case 'JSOP_MOD': case 'JSOP_BITOR': case 'JSOP_BITXOR': case 'JSOP_BITAND': case 'JSOP_RSH': case 'JSOP_LSH': case 'JSOP_URSH': //logic case 'JSOP_EQ': case 'JSOP_NE': case 'JSOP_LT': case 'JSOP_LE': case 'JSOP_GT': case 'JSOP_GE': case 'JSOP_STRICTEQ': case 'JSOP_STRICTNE': case 'JSOP_IN': $right = $this->popStack(); $rVal = $right->getValue(); $left = $this->popStack(); $lVal = $left->getValue(); if ($left->type == 'logic') { $lVal = $this->_combineLogicByParserIndex($left->operation['parserIndex']); } if ($right->type == 'logic') { $rVal = $this->_combineLogicByParserIndex($right->operation['parserIndex']); } $this->pushStack(['script' => '(' . $lVal . ' ' . $operation['image'] . ' ' . $rVal . ')', 'type' => 'script']); break; case 'JSOP_OR': $script = $this->popStack(); $gotoIndex = $operation['parserIndex'] + $operation['params']['offset']; $this->logicStacks[$operation['parserIndex']] = ['type' => 'or', 'goto' => $gotoIndex, 'value' => $script->getValue()]; $this->pushStack(['type' => 'logic', 'operation' => $operation]); break; case 'JSOP_AND': $script = $this->popStack(); $gotoIndex = $operation['parserIndex'] + $operation['params']['offset']; $this->logicStacks[$operation['parserIndex']] = ['type' => 'and', 'goto' => $gotoIndex, 'value' => $script->getValue()]; $this->pushStack(['type' => 'logic', 'operation' => $operation]); break; case 'JSOP_NOT': $script = $this->popStack(); $this->logicStacks[$operation['parserIndex']] = ['type' => 'not', 'value' => $script->getValue()]; $this->pushStack(['type' => 'logic', 'operation' => $operation]); break; //typeof case 'JSOP_TYPEOF': case 'JSOP_TYPEOFEXPR': $name = $this->popStack(); $this->pushStack(['script' => 'typeof ' . $name->getValue(), 'type' => 'script']); break; //instanceof case 'JSOP_INSTANCEOF': $rVal = $this->popStack(); $lVal = $this->popStack(); $this->pushStack(['script' => $lVal->getValue() . ' instanceof ' . $rVal->getValue(), 'type' => 'script']); break; //Function case 'JSOP_NEW': case 'JSOP_FUNAPPLY'://apply case 'JSOP_FUNCALL'://call case 'JSOP_EVAL'://eval case 'JSOP_CALL': $_argc = $operation['params']['argc']; $_argv = []; for ($i = 0; $i < $_argc; $i++) { $_argv[] = $this->popStack(); } $_this = $this->popStack(); $_callee = $this->popStack(); $write = ''; if (!empty($this->logicStacks)) { $write .= $this->_combineLogicByGotoIndex($operation['parserIndex'] + $operation['length']); } if ($operation['name'] == 'JSOP_NEW') { $write = 'new '; } $write .= $_callee->name ? $_callee->name : ('(' . $_callee->getScript() . ')'); $write .= '('; if ($_argc) { for ($i = $_argc - 1; $i >= 0; $i--) { //$argv = $_argv[$i]->getScript() ? $_argv[$i]->getScript() : $_argv[$i]->name;//todo $argv = $_argv[$i]->getValue(); $write .= $argv . ','; } $write = substr($write, 0, strlen($write) - 1); } $write .= ')'; $this->pushStack(['type' => 'script', 'script' => $write]); break; //Object case 'JSOP_NEWINIT': $this->pushStack(['value' => [], 'type' => 'object']); break; case 'JSOP_INITPROP': $name = $this->atoms[$operation['params']['nameIndex']]; $val = $this->popStack(); $array = $this->popStack(); $array->value[$name] = $val; $this->pushStack($array); break; case 'JSOP_DELPROP': $obj = $this->popStack(); $this->pushStack(['type' => 'script', 'script' => 'delete ' . $obj->getValue() . '.' . $this->atoms[$operation['params']['nameIndex']]]); break; case 'JSOP_SETPROP': $value = $this->getLogicValue($operation, $this->popStack()); $name = $this->popStack(); $this->pushStack(['type' => 'script', 'script' => $name->getValue() . '.' . $this->atoms[$operation['params']['nameIndex']] . '=' . $value]); break; case 'JSOP_GETPROP': case 'JSOP_CALLPROP': $obj = $this->popStack(); $this->pushStack(['name' => $obj->getValue() . '.' . $this->atoms[$operation['params']['nameIndex']]]); break; case 'JSOP_INITELEM': case 'JSOP_INITELEM_INC': $val = $this->popStack(); $name = $this->popStack(); $array = $this->popStack(); $array->value[$name->getValue()] = $val; $this->pushStack($array); break; case 'JSOP_DELELEM': $propval = $this->popStack(); $obj = $this->popStack(); $this->pushStack(['type' => 'script', 'script' => 'delete ' . $obj->getValue() . '[' . $propval->getValue() . ']']); break; case 'JSOP_SETELEM': $value = $this->getLogicValue($operation, $this->popStack()); $propval = $this->popStack(); $obj = $this->popStack(); $this->pushStack(['type' => 'script', 'script' => $obj->getValue() . '[' . $propval->getValue() . ']=' . $value]); break; case 'JSOP_GETELEM': case 'JSOP_CALLELEM': $propval = $this->popStack(); $obj = $this->popStack(); $this->pushStack(['name' => $obj->getValue() . '[' . $propval->getValue() . ']']); break; //Array case 'JSOP_NEWARRAY': $this->pushStack(['value' => [], 'type' => 'array']); break; case 'JSOP_INITELEM_ARRAY': $val = $this->popStack(); $array = $this->popStack(); $array->value[] = $val; $this->pushStack($array); break; case 'JSOP_LENGTH': $name = $this->popStack(); $this->pushStack(['type' => 'script', 'script' => $name->getValue() . '.length']); break; //压入变量 case 'JSOP_NAME': case 'JSOP_BINDNAME': case 'JSOP_IMPLICITTHIS': $this->pushStack(['name' => $this->atoms[$operation['params']['nameIndex']]]); break; //定义变量 case 'JSOP_DEFVAR': $this->writeScript($operation['parserIndex'], 'var ' . $this->atoms[$operation['params']['nameIndex']] . ';'); break; case 'JSOP_DEFCONST': $this->writeScript($operation['parserIndex'], 'const ' . $this->atoms[$operation['params']['nameIndex']] . ';'); break; case 'JSOP_DEFFUN': $object = $this->objects[$operation['params']['funcIndex']]; $this->writeScript($operation['parserIndex'], 'function ' . $object['name'] . '( __ARGV_' . $object['contextIndex'] . '__ ){ __FUNC_' . $object['contextIndex'] . '__ }'); break; //定义常量 ['isJson'=>false,'value'=>'xxxx'] case 'JSOP_TRUE': $this->pushStack(['value' => 'true', 'type' => 'boolean']); break; case 'JSOP_FALSE': $this->pushStack(['value' => 'false', 'type' => 'boolean']); break; case 'JSOP_NULL': $this->pushStack(['value' => 'null', 'type' => 'null']); break; case 'JSOP_VOID': $val = $this->popStack(); case 'JSOP_UNDEFINED': $this->pushStack(['value' => 'undefined', 'type' => 'undefined']); break; case 'JSOP_ZERO': $this->pushStack(['value' => 0, 'type' => 'number']); break; case 'JSOP_ONE': $this->pushStack(['value' => 1, 'type' => 'number']); break; case 'JSOP_INT8': case 'JSOP_UINT16': case 'JSOP_UINT24': case 'JSOP_INT32': $this->pushStack(['value' => $operation['params']['val'], 'type' => 'number']); break; case 'JSOP_DOUBLE': $this->pushStack(['value' => $this->consts[$operation['params']['constIndex']]['value'], 'type' => 'number']); break; case 'JSOP_STRING': $this->pushStack(['value' => $this->atoms[$operation['params']['atomIndex']], 'type' => 'string']); break; case 'JSOP_REGEXP': $this->pushStack(['value' => '/' . $this->regexps[$operation['params']['regexpIndex']]['source'] . '/', 'type' => 'regexp']); break; case 'JSOP_OBJECT'://todo $object = $this->objects[$operation['params']['objectIndex']]; $value = []; foreach ($object['initialized'] as $k => $v) { $type = 'undefined'; switch ($v['type']) { case 'SCRIPT_INT': case 'SCRIPT_DOUBLE': $type = 'number'; break; case 'SCRIPT_ATOM': $type = 'string'; break; case 'SCRIPT_TRUE': case 'SCRIPT_FALSE': $type = 'boolean'; break; case 'SCRIPT_NULL': $type = 'null'; break; case 'SCRIPT_OBJECT'://todo maybe function $type = 'object'; break; //case 'SCRIPT_VOID': //case 'SCRIPT_HOLE': } $value[$k] = new Stack(['value' => $v['value'], 'type' => $type]); } $this->pushStack(['value' => $value, 'type' => 1 == $object['isArray'] ? 'array' : 'object']); break; case 'JSOP_LAMBDA_ARROW': $_this = $this->popStack(); $object = $this->objects[$operation['params']['funcIndex']]; $this->pushStack(['value' => $object['contextIndex'], 'type' => 'function']); break; case 'JSOP_LAMBDA': $object = $this->objects[$operation['params']['funcIndex']]; $this->pushStack(['value' => $object['contextIndex'], 'type' => 'function']); break; //赋值 case 'JSOP_SETNAME': $value = $this->getLogicValue($operation, $this->popStack()); $name = $this->popStack(); $name->value = $value; $name->script = $name->getValue() . ' = ' . $value; $name->type = 'script'; $this->pushStack($name); break; case 'JSOP_SETCONST': $value = $this->getLogicValue($operation, $this->popStack()); $name = $this->atoms[$operation['params']['nameIndex']]; $this->pushStack([ 'type' => 'script', 'name' => $name->value, 'value' => $value, 'script' => $name->value . ' = ' . $value, ]); break; //delete case 'JSOP_DELNAME': $this->pushStack(['type' => 'script', 'script' => 'delete ' . $this->atoms[$operation['params']['nameIndex']]]); break; //todo list //Other case 'JSOP_TOSTRING': $val = $this->popStack(); $this->pushStack([]); break; case 'JSOP_LINENO': break; //With Statement case 'JSOP_ENTERWITH': $val = $this->popStack(); break; case 'JSOP_LEAVEWITH': break; //Arguments case 'JSOP_CALLEE': $this->pushStack([]); break; case 'JSOP_ARGUMENTS': $this->pushStack(['name' => 'arguments']); break; case 'JSOP_REST': $this->pushStack(['name' => 'rest']); break; case 'JSOP_SETARG': $val = $this->popStack(); $this->pushStack([ 'type' => 'script', 'name' => $this->argvs[$operation['params']['argno']], 'script' => $this->argvs[$operation['params']['argno']] . ' = ' . $val->getValue(), ]); break; case 'JSOP_GETARG': $this->pushStack(['name' => $this->argvs[$operation['params']['argno']]]); break; //Array case 'JSOP_NEWARRAY_COPYONWRITE': $this->pushStack([]); break; case 'JSOP_HOLE': $this->pushStack([]); break; case 'JSOP_ARRAYPUSH': $val = $this->popStack(); $array = $this->popStack(); break; //Object case 'JSOP_TOID': $val = $this->popStack(); $this->pushStack([]); break; case 'JSOP_MUTATEPROTO': $val = $this->popStack(); $val = $this->popStack(); $this->pushStack([]); break; case 'JSOP_GETXPROP': $val = $this->popStack(); $this->pushStack([]); break; case 'JSOP_CALLSITEOBJ': $this->pushStack([]); break; case 'JSOP_INITPROP_GETTER': $val = $this->popStack(); $val = $this->popStack(); $this->pushStack([]); break; case 'JSOP_INITPROP_SETTER': $val = $this->popStack(); $val = $this->popStack(); $this->pushStack([]); break; case 'JSOP_INITELEM_GETTER': $val = $this->popStack(); $val = $this->popStack(); $val = $this->popStack(); $this->pushStack([]); break; case 'JSOP_INITELEM_SETTER': $val = $this->popStack(); $val = $this->popStack(); $val = $this->popStack(); $this->pushStack([]); break; case 'JSOP_NEWOBJECT': $this->pushStack(['value' => [], 'type' => 'object']); break; //This case 'JSOP_THIS': $this->pushStack(['name' => 'this']); break; //Function case 'JSOP_SETCALL': break; case 'JSOP_RUNONCE': break; case 'JSOP_SPREADCALL': $val = $this->popStack(); $val = $this->popStack(); $val = $this->popStack(); $this->pushStack([]); break; case 'JSOP_SPREADNEW': $val = $this->popStack(); $val = $this->popStack(); $val = $this->popStack(); $this->pushStack([]); break; case 'JSOP_SPREADEVAL': $val = $this->popStack(); $val = $this->popStack(); $val = $this->popStack(); $this->pushStack([]); break; //Free Variables case 'JSOP_BINDGNAME': case 'JSOP_GETGNAME'://todo check if this different from local, for just access variable name $key = $this->atoms[$operation['params']['nameIndex']]; $this->pushStack($this->decompile->getGlobalVariable($key)); break; case 'JSOP_SETGNAME': $value = $this->popStack(); $bind = $this->popStack(); $key = $this->atoms[$operation['params']['nameIndex']]; $globalVar = [ 'type' => 'script', 'name' => $key, 'value' => $value, 'script' => $key . '=' . $value->getValue(), ]; $this->decompile->setLocalVariable($key, $globalVar); $this->pushStack($globalVar); break; //Local Variables case 'JSOP_GETLOCAL'://todo $localno = $operation['params']['localno']; $this->pushStack($this->decompile->getLocalVariable($localno)); break; case 'JSOP_SETLOCAL'://todo $raw = $this->popStack(); $value = $raw->name ?: $this->getLogicValue($operation, $raw); $localno = $operation['params']['localno']; $name = '_local' . $localno; $localVar = [ 'type' => 'script', 'name' => $name, 'value' => $value, 'script' => $name . '=' . $value, ]; $this->decompile->setLocalVariable($localno, $localVar); $this->pushStack($localVar); break; //Generator case 'JSOP_GENERATOR': break; case 'JSOP_YIELD': $val = $this->popStack(); $this->pushStack(['type' => 'script', 'value' => 'yield ' . $val->getValue()]); break; //Aliased Variables case 'JSOP_GETALIASEDVAR'://todo $aliasedVar = $this->decompile->getAliasedVariable($operation['params']['hops'], $operation['params']['slot']); $this->pushStack($aliasedVar); break; case 'JSOP_SETALIASEDVAR'://todo $value = $this->getLogicValue($operation, $this->popStack()); $aliasedVar = ['type' => 'aliasedVar', 'name' => '_aliased' . rand(1000, 9999)]; $this->decompile->setAliasedVariable($operation['params']['hops'], $operation['params']['slot'], $aliasedVar); $this->pushStack(['type' => 'script', 'name' => $aliasedVar['name'], 'script' => $aliasedVar['name'] . '=' . $value]); break; //Exception Handling case 'JSOP_TRY': $this->writeScript($operation['parserIndex'], 'try{'); break; case 'JSOP_THROW': $val = $this->popStack(); $this->writeScript($operation['parserIndex'], 'throw ' . $val->getValue()); break; case 'JSOP_GOSUB': break; case 'JSOP_EXCEPTION': $exception = ['type' => 'exception', 'value' => '@error']; $this->writeScript($operation['parserIndex'], '}catch(' . $exception['value'] . '){'); $this->pushStack($exception); break; case 'JSOP_DEBUGLEAVEBLOCK': $this->writeScript($operation['parserIndex'], '} '); break; case 'JSOP_FINALLY': $this->writeScript($operation['parserIndex'], 'finally{ '); $this->pushStack([]); $this->pushStack([]); break; case 'JSOP_RETSUB': $this->writeScript($operation['parserIndex'], '}'); $val = $this->popStack(); $val = $this->popStack(); break; //todo case 'JSOP_DEBUGGER': break; case 'JSOP_THROWING': $val = $this->popStack(); break; //Block-local Scope case 'JSOP_POPBLOCKSCOPE': break; case 'JSOP_PUSHBLOCKSCOPE': break; //Jumps case 'JSOP_BACKPATCH': break; case 'JSOP_LABEL': break; //Intrinsics case 'JSOP_BINDINTRINSIC': $this->pushStack([]); break; case 'JSOP_GETINTRINSIC': $this->pushStack([]); break; case 'JSOP_SETINTRINSIC': $val = $this->popStack(); $val = $this->popStack(); $this->pushStack([]); break; } } protected function _renderSwitch($contents, $defaultIndex) { $contentEndings = array_keys($contents); $contentEndings[] = $defaultIndex; $i = 1; foreach ($contents as $start => $content) { $caseWrite = ''; foreach ($content as $case) { $caseWrite .= $case['value']; } $this->writeScript($start, $caseWrite, -1); $this->revealOperations($start, $contentEndings[$i], ['type' => 'switch', 'defaultIndex' => $defaultIndex,]); $i++; } $this->writeScript($defaultIndex, 'default:'); } protected function getLogicValue($operation, Stack $val) { $value = $val->getValue(); if (!empty($this->logicStacks)) { $value = $this->_combineLogicByGotoIndex($operation['parserIndex'] + $operation['length']) . $value; } return $value; } protected function _getLoopGoto($operation) { $gotoIndex = $operation['parserIndex'] - 5; if (!isset($this->operations[$gotoIndex])) { return false; } $gotoOperation = $this->operations[$gotoIndex]; if ($gotoOperation['name'] !== 'JSOP_GOTO') { return false; } return $gotoOperation; } protected function _getLoopLogic($entry) { $if = $entry; do { $if = $this->findFirstOperation( ['JSOP_IFNE', 'JSOP_IFEQ'], $if['parserIndex'] + $if['length'] ); if (!$if) { return false; } } while ($if['params']['offset'] > 0); return $if; } protected function _getBranchGoto($operation) { $gotoIndex = $operation['parserIndex'] + $operation['params']['offset'] - 5; if (!isset($this->operations[$gotoIndex])) { return false; } $gotoOperation = $this->operations[$gotoIndex]; if ($gotoOperation['name'] !== 'JSOP_GOTO') { return false; } return $gotoOperation; } protected function _getBranchBreak($goto) { if ($goto['params']['offset'] > 0) { if ($this->hasOperation($goto['parserIndex'], $goto['parserIndex'] + $goto['params']['offset'], 'JSOP_LOOPENTRY')) { $this->writeScript($goto['parserIndex'], 'break;'); return true; } } return false; } protected function _getBranchContinue($goto) { if ($goto['params']['offset'] < 0) { $nextOperation = $this->gotoNextOperation($goto); if ($nextOperation['name'] == 'JSOP_LOOPENTRY') { $this->writeScript($goto['parserIndex'], 'continue;'); return true; } } return false; } protected function _combineLogic() { ksort($this->logicStacks); while (count($this->logicStacks) > 1) { $this->_combineLogicUnit(); } $result = array_pop($this->logicStacks); switch ($result['type']) { case 'not': $result['value'] = '!(' . $result['value'] . ')'; break; case 'and': $result['value'] = $result['value'] . '&&'; break; case 'or': $result['value'] = $result['value'] . '||'; break; } return $result['value']; } protected function _getLogicScript($stack) { $value = ''; $isNot = $stack['type'] == 'not'; if ($isNot) { $value .= '!('; } $value .= $stack['value']; if ($isNot) { $value .= ')'; } switch ($stack['type']) { case 'and': $value .= ' && '; break; case 'or': $value .= ' || '; break; } return $value; } protected function _combineLogicUnit() { $logicStackKeys = array_keys($this->logicStacks); $logicStackKeysCount = count($logicStackKeys); $tree = ['type' => 'script']; for ($i = 0; $i < $logicStackKeysCount; $i++) { $logicStack = $this->logicStacks[$logicStackKeys[$i]]; if (is_null($logicStack['value'])) { $preStack = $this->logicStacks[$logicStackKeys[$i - 1]]; $this->logicStacks[$logicStackKeys[$i]]['value'] = $preStack['type'] == 'not' ? ('!(' . $preStack['value'] . ')') : $preStack['value']; unset($this->logicStacks[$logicStackKeys[$i - 1]]); } elseif (!isset($logicStackKeys[$i + 1])) {//if last one $preStack = $this->logicStacks[$logicStackKeys[$i - 1]]; $value = $this->_getLogicScript($preStack) . $this->_getLogicScript($logicStack); $this->logicStacks[$logicStackKeys[$i - 1]] = ['value' => $value, 'type' => 'script']; unset($this->logicStacks[$logicStackKeys[$i]]); } elseif (!isset($logicStack['goto'])) { continue; } elseif ($logicStackKeys[$i + 1] == $logicStack['goto']) { $nextLogicStack = $this->logicStacks[$logicStackKeys[$i + 1]]; $isNot = $nextLogicStack['type'] == 'not' ? '!' : ''; switch ($logicStack['type']) { case 'and': $tree['value'] = $isNot . '(' . $logicStack['value'] . ' && ' . $nextLogicStack['value'] . ')'; break; case 'or': $tree['value'] = $isNot . '(' . $logicStack['value'] . ' || ' . $nextLogicStack['value'] . ')'; break; case 'script': $tree['value'] = $logicStack['value'] . $nextLogicStack['value']; break; } if (isset($nextLogicStack['goto'])) { $tree['goto'] = $nextLogicStack['goto']; $tree['type'] = $nextLogicStack['type']; } unset($this->logicStacks[$logicStackKeys[$i]]); $this->logicStacks[$logicStackKeys[$i + 1]] = $tree; break; } } } protected function _combineLogicByGotoIndex($index) { krsort($this->logicStacks); $executeFlag = true; $execute = []; $storage = []; foreach ($this->logicStacks as $key => $value) { if (isset($value['goto']) && $value['goto'] > $index) { $executeFlag = false; } if ($executeFlag) { $execute[$key] = $value; } else { $storage[$key] = $value; } } $result = ''; if (!empty($execute)) { $this->logicStacks = $execute; $result = $this->_combineLogic(); } $this->logicStacks = $storage; return $result; } protected function _combineLogicByParserIndex($index) { ksort($this->logicStacks); $executeFlag = true; $execute = []; $storage = []; foreach ($this->logicStacks as $key => $value) { if ($key > $index) { $executeFlag = false; } if ($executeFlag) { $execute[$key] = $value; } else { $storage[$key] = $value; } } $result = ''; if (!empty($execute)) { $this->logicStacks = $execute; $result = $this->_combineLogic(); } $this->logicStacks = $storage; return $result; } } ================================================ FILE: src/Helper/Reveal.php ================================================ summaries)) { echo '---------------Summaries---------------', CLIENT_EOL; foreach ($this->summaries as $key => $value) { echo $key, ' : ', $value, CLIENT_EOL; } echo '---------------------------------------', CLIENT_EOL; } } public function printOperations() { echo '---------------Operations--------------', CLIENT_EOL; foreach ($this->operations as $key => $operation) { $op = Constant::_Opcode[$operation['id']]; echo '[', $key, ']', $op['op'], json_encode($operation['params']), ' pop: ', $operation['pop'], ' push: ', $operation['push'], ' byte: ', $operation['length'], CLIENT_EOL; } echo '---------------------------------------', CLIENT_EOL; } public function printNodes() { echo '-----------------Nodes-----------------', CLIENT_EOL; echo implode(', ', $this->nodes), CLIENT_EOL; echo '---------------------------------------', CLIENT_EOL; } public function printAtoms() { if (count($this->atoms)) { echo '-----------------Atoms-----------------', CLIENT_EOL; foreach ($this->atoms as $key => $value) { echo $key, ' : ', $value, CLIENT_EOL; } echo '---------------------------------------', CLIENT_EOL; } } public function printConsts() { if (count($this->consts)) { echo '-----------------Consts----------------', CLIENT_EOL; foreach ($this->consts as $key => $const) { echo $key, ' : [', $const['type'], ']', $const['value'], CLIENT_EOL; } echo '---------------------------------------', CLIENT_EOL; } } public function printObjects() { if (count($this->objects)) { echo '-----------------Objects---------------', CLIENT_EOL; foreach ($this->objects as $object) { echo json_encode($object), CLIENT_EOL; } echo '---------------------------------------', CLIENT_EOL; } } public function printRegexps() { if (count($this->regexps)) { echo '-----------------Regexps---------------', CLIENT_EOL; foreach ($this->regexps as $regexp) { echo $regexp['source'], CLIENT_EOL; } echo '---------------------------------------', CLIENT_EOL; } } public function printTryNote() { if (count($this->tryNotes)) { echo '-----------------Objects---------------', CLIENT_EOL; foreach ($this->tryNotes as $tryNote) { echo json_encode($tryNote), CLIENT_EOL; } echo '---------------------------------------', CLIENT_EOL; } } public function printScopeNote() { if (count($this->scopeNotes)) { echo '---------------ScopeNotes---------------', CLIENT_EOL; foreach ($this->scopeNotes as $id => $scopeNote) { echo $id, ' : ', json_encode($scopeNote), CLIENT_EOL; } echo '---------------------------------------', CLIENT_EOL; } } public function printProperties(array $types) { foreach ($types as $type) { $call = 'print' . $type; if (method_exists($this, $call)) { $this->$call(); } } } public function printContent() { foreach ($this->operations as $key => $operation) { if (!$this->operations[$key]['isCover']) { if ($this->isDebug) { echo $key, CLIENT_EOL; } $this->revealOperation($operation); $this->operations[$key]['isCover'] = true; } } ksort($this->storageScript); $scriptKeys = array_keys($this->storageScript); $scriptKeysCount = count($scriptKeys); echo '----------------Content----------------', CLIENT_EOL; for ($i = 0; $i < $scriptKeysCount; $i++) { $script = $this->storageScript[$scriptKeys[$i]]; if ($this->isDebug) { echo '[', $scriptKeys[$i] / 2, ']', $script['value'], CLIENT_EOL; } else { echo $script['value'], CLIENT_EOL; } } echo '---------------------------------------', CLIENT_EOL; } public function printArgv() { echo '------------------Argv------------------', CLIENT_EOL; echo implode(',', $this->argvs), CLIENT_EOL; echo '---------------------------------------', CLIENT_EOL; } } ================================================ FILE: src/Helper/Stack.php ================================================ $value) { $this->$prop = $value; } } public function getValue() { if ($this->name) { return $this->name; } return $this->getScript(); } public function getScript() { if ($this->script) { return $this->script; } $this->script = self::renderBase($this); return $this->script; } public static function renderBase(self $input) { switch ($input->type) { case 'script': return $input->script; case 'function': return 'function () { __FUNC_' . $input->value . '__ }'; case 'string': return '"' . $input->value . '"'; case 'object': return self::renderObject($input->value); case 'array': return self::renderArray($input->value); case 'number': case 'boolean': case 'null': case 'undefined': case 'regexp': } return $input->value; } public static function renderArray($array) { $result = '['; foreach ($array as $item) { $result .= $item->getValue() . ','; } $resultLen = strlen($result); if ($resultLen>1) { $result = substr($result, 0, $resultLen - 1); } $result .= ']'; return $result; } public static function renderObject($object) { $result = '{'; foreach ($object as $key => $value) { $result .= $key . ':'; $result .= $value->getValue() . ','; } $resultLen = strlen($result); if ($resultLen>1) { $result = substr($result, 0, $resultLen - 1); } $result .= '}'; return $result; } } ================================================ FILE: src/Xdr/Atom.php ================================================ parseIndex + $length; $atom = ''; for (; $this->parseIndex < $end; $this->parseIndex++) { $atom .= chr($this->bytecodes[$this->parseIndex]); } return $atom; } protected function getTwoByteChar() { $char = '\u' . dechex($this->bytecodes[$this->parseIndex + 1]) . dechex($this->bytecodes[$this->parseIndex]); $this->parseIndex += 2; return $char; } protected function getTwoByteChars($length) { $atom = ''; for ($i = 0; $i < $length; $i++) { $atom .= $this->getTwoByteChar(); } return json_decode('"' . $atom . '"'); } public function XDRAtom() { $lengthAndEncoding = $this->todec(); $hasLatin1Chars = $lengthAndEncoding & 1; $length = $lengthAndEncoding >> 1; if ($hasLatin1Chars) { $atom = $this->getLatin1Chars($length); } else { $atom = $this->getTwoByteChars($length); } return $atom; } } ================================================ FILE: src/Xdr/Common.php ================================================ parseIndex + $length; $result = ''; for (; $this->parseIndex < $end; $this->parseIndex++) { $result .= sprintf('%02s', dechex($this->bytecodes[$this->parseIndex])); } return $result; } protected function getCString() { $result = ''; while ($this->bytecodes[$this->parseIndex]) { $result .= chr($this->bytecodes[$this->parseIndex]); $this->parseIndex++; } $this->parseIndex++; return $result; } protected function todec($length = 4)//length include start { return $this->littleEndian2Dec($length); } protected function littleEndian2Dec($length) { $result = ''; for ($i = $this->parseIndex + $length - 1; $i >= $this->parseIndex; $i--) { $result .= sprintf('%02s', dechex($this->bytecodes[$i])); } $this->parseIndex += $length; return hexdec($result); } protected function bigEndian2Dec($length) { $end = $this->parseIndex + $length; $result = ''; for (; $this->parseIndex < $end; $this->parseIndex++) { $result .= sprintf('%02s', dechex($this->bytecodes[$this->parseIndex])); } return hexdec($result); } protected function uInt32ToInt32($num) { return unpack('l', pack('L', $num))[1]; } protected function uIntToInt($num, $bit) { $half = 1 << ($bit - 1); if ($num <= $half) { return $num; } $max = (1 << $bit) - 1; return -(($num - 1) ^ $max); } public function xdrConst() { $type = $this->todec(); $const = [ 'type' => Constant::_ConstTag[$type], ]; switch ($type) { case 0: $const['value'] = $this->todec(); break; case 1: $value = unpack('d', pack('H*', $this->getRawHex(8))); $const['value'] = $value[1]; break; case 2: $const['value'] = $this->XDRAtom(); break; case 3: $const['value'] = true; break; case 4: $const['value'] = false; break; case 5: $const['value'] = null; break; case 6: $object = $this->xdrCK_JSObject(); $const['value'] = "__OBJECT__"; $const['extra'] = $object; break; case 7: $const['value'] = "__VOID__"; break; case 8: $const['value'] = "__HOLE__"; break; default: $const['value'] = "__ERROR__"; break; } return $const; } public function XDRInterpretedFunction() { $result = ['name' => '']; $firstword = $this->todec(); if ($firstword & Constant::_FirstWordFlag['HasAtom']) { $result['name'] = $this->XDRAtom(); } $flagsword = $this->todec(); if ($firstword & Constant::_FirstWordFlag['IsLazy']) { $this->XDRLazyScript(); $result['type'] = 'lazy'; } else { $result['type'] = 'block'; $result['contextIndex'] = $this->XDRScript()->index; } return $result; } public function XDRLazyFreeVariables() { //for 0 -> numFreeVariables //$atom=$this->XDRAtom(); } public function XDRLazyScript() { //XDRLazyScript $begin = $this->todec(); $end = $this->todec(); $lineno = $this->todec(); $column = $this->todec(); $packedFields = $this->todec(8); $this->XDRLazyFreeVariables(); } } ================================================ FILE: src/Xdr/ObjectXdr.php ================================================ $result(); } protected function xdrCK_Not() { return []; } protected function xdrCK_BlockObject() { $result = [ 'enclosingStaticScopeIndex' => $this->todec(), 'count' => $this->todec(), 'offset' => $this->todec(), 'atoms' => [], ]; for ($i = 0; $i < $result['count']; $i++) { $result['atoms'][] = [ 'atom' => $this->XDRAtom(), 'aliased' => $this->todec(), ]; } return $result; } protected function xdrCK_WithObject() { return [ 'enclosingStaticScopeIndex' => $this->todec(), ]; } protected function xdrCK_JSFunction() { return array_merge([ 'funEnclosingScopeIndex' => $funEnclosingScopeIndex = $this->todec(), ],$this->XDRInterpretedFunction()); } public function xdrCK_JSObject() { $result = []; $result['isArray'] = $isArray = $this->todec(); $this->todec();//isArray ? length : kind $result['capacity'] = $capacity = $this->todec(); $initialized = $this->todec(); $result['initialized'] = []; for ($i = 0; $i < $initialized; $i++) { $result['initialized'][] = $tmpValue = $this->xdrConst(); } $nslot = $this->todec(); $result['nslot'] = []; for ($i = 0; $i < $nslot; $i++) { $idType = $this->todec(); if ($idType == JSID_TYPE_STRING) { $key = $this->XDRAtom(); } else { $key = $this->todec(); } $val = $this->xdrConst(); $result['nslot'][$key] = $val; } $isSingletonTyped = $this->todec(); $frozen = $this->todec(); if ($isArray) { $copyOnWrite = $this->todec(); } return $result; } } ================================================ FILE: src/Xdr/Operation.php ================================================ bytecodes[$this->parseIndex]]; $result = [ 'id' => $op['val'], 'name' => $op['op'], 'parserIndex' => $this->parseIndex, 'params' => [], 'length' => $op['len'], 'image' => $op['image'], 'push' => $op['def'], 'pop' => $op['use'], 'isCover' => false, ]; $this->parseIndex++; switch ($op['op']) { case 'JSOP_ENTERWITH': $result['params']['staticWithIndex'] = $this->bigEndian2Dec(4); break; case 'JSOP_GOTO': case 'JSOP_IFEQ': case 'JSOP_IFNE': case 'JSOP_OR': case 'JSOP_AND': case 'JSOP_LABEL': case 'JSOP_GOSUB': case 'JSOP_CASE': case 'JSOP_DEFAULT': case 'JSOP_BACKPATCH': $result['params']['offset'] = $this->uInt32ToInt32($this->bigEndian2Dec(4)); break; case 'JSOP_CALL': case 'JSOP_FUNAPPLY': case 'JSOP_NEW': case 'JSOP_FUNCALL': case 'JSOP_EVAL': $result['params']['argc'] = $this->bigEndian2Dec(2); break; case 'JSOP_GETARG': case 'JSOP_SETARG': $result['params']['argno'] = $this->bigEndian2Dec(2); break; case 'JSOP_PICK': $result['params']['n'] = $this->bigEndian2Dec(1); break; case 'JSOP_POPN': $result['params']['n'] = $this->bigEndian2Dec(2); break; case 'JSOP_DUPAT': $result['params']['n'] = $this->bigEndian2Dec(3); break; case 'JSOP_SETCONST': case 'JSOP_DELNAME': case 'JSOP_DELPROP': case 'JSOP_GETPROP': case 'JSOP_SETPROP': case 'JSOP_INITPROP': case 'JSOP_NAME': case 'JSOP_INITPROP_GETTER': case 'JSOP_INITPROP_SETTER': case 'JSOP_BINDNAME': case 'JSOP_SETNAME': case 'JSOP_DEFCONST': case 'JSOP_DEFVAR': case 'JSOP_GETINTRINSIC': case 'JSOP_SETINTRINSIC': case 'JSOP_BINDINTRINSIC': case 'JSOP_GETGNAME': case 'JSOP_SETGNAME': case 'JSOP_CALLPROP': case 'JSOP_GETXPROP': case 'JSOP_BINDGNAME': case 'JSOP_LENGTH': case 'JSOP_IMPLICITTHIS': $result['params']['nameIndex'] = $this->bigEndian2Dec(4); break; case 'JSOP_DOUBLE': $result['params']['constIndex'] = $this->bigEndian2Dec(4); break; case 'JSOP_STRING': $result['params']['atomIndex'] = $this->bigEndian2Dec(4); break; case 'JSOP_OBJECT': case 'JSOP_CALLSITEOBJ': case 'JSOP_NEWARRAY_COPYONWRITE': $result['params']['objectIndex'] = $this->bigEndian2Dec(4); break; case 'JSOP_DEFFUN': case 'JSOP_LAMBDA': case 'JSOP_LAMBDA_ARROW': $result['params']['funcIndex'] = $this->bigEndian2Dec(4); break; case 'JSOP_REGEXP': $result['params']['regexpIndex'] = $this->bigEndian2Dec(4); break; case 'JSOP_PUSHBLOCKSCOPE': $result['params']['staticBlockObjectIndex'] = $this->bigEndian2Dec(4); break; case 'JSOP_TABLESWITCH': $result['params']['len'] = $this->uInt32ToInt32($this->bigEndian2Dec(4)); $result['params']['low'] = $this->uInt32ToInt32($this->bigEndian2Dec(4)); $result['params']['high'] = $this->uInt32ToInt32($this->bigEndian2Dec(4)); $result['params']['offset'] = []; $end = $result['params']['high'] - $result['params']['low']; for ($i = 0; $i <= $end; $i++) { $result['params']['offset'][$i] = $this->uInt32ToInt32($this->bigEndian2Dec(4)); } break; case 'JSOP_ITER': $result['params']['flags'] = $this->bigEndian2Dec(1); break; case 'JSOP_GETLOCAL'://todo uint32_t localno but op len is 4 case 'JSOP_SETLOCAL'://todo uint32_t localno but op len is 4 $result['params']['localno'] = $this->bigEndian2Dec(3); break; case 'JSOP_INT8': $result['params']['val'] = $this->uIntToInt($this->bigEndian2Dec(1), 8); break; case 'JSOP_UINT16': $result['params']['val'] = $this->bigEndian2Dec(2); break; case 'JSOP_UINT24': $result['params']['val'] = $this->bigEndian2Dec(3); break; case 'JSOP_INT32': $result['params']['val'] = $this->uInt32ToInt32($this->bigEndian2Dec(4)); break; case 'JSOP_NEWINIT': $result['params']['kind'] = $this->bigEndian2Dec(1); $result['params']['extra'] = $this->bigEndian2Dec(3); break; case 'JSOP_NEWARRAY': $result['params']['length'] = $this->bigEndian2Dec(3); break; case 'JSOP_NEWOBJECT': $result['params']['baseobjIndex'] = $this->bigEndian2Dec(4); break; case 'JSOP_INITELEM_ARRAY': $result['params']['index'] = $this->bigEndian2Dec(3); break; case 'JSOP_LINENO': $result['params']['lineno'] = $this->bigEndian2Dec(2); break; case 'JSOP_GETALIASEDVAR': case 'JSOP_SETALIASEDVAR': $result['params']['hops'] = $this->bigEndian2Dec(1); $result['params']['slot'] = $this->bigEndian2Dec(3); break; case 'JSOP_LOOPENTRY': $result['params']['BITFIELD'] = $this->bigEndian2Dec(1); $result['params']['depth'] = $result['params']['BITFIELD'] - 128; break; } return $result; } } ================================================ FILE: src/Xdr/Scope.php ================================================ todec(); $result = []; for ($i = 0; $i < $length; $i++) { $u8 = $this->todec(1); $hasAtom = $u8 >> 1; if ($hasAtom) { $result[] = $this->XDRAtom(); } } return $result; } public function xdrScopeExtra($scopeKind) { $result = 'xdr'; switch ($scopeKind) { case 'Function': $result .= 'Function'; break; case 'FunctionBodyVar': case 'ParameterExpressionVar': $result .= 'Var'; break; case 'Lexical': case 'SimpleCatch': case 'Catch': case 'NamedLambda': case 'StrictNamedLambda': $result .= 'Lexical'; break; case 'With': $result .= 'With'; break; case 'Eval': case 'StrictEval': $result .= 'Eval'; break; case 'Global': case 'NonSyntactic': $result .= 'Global'; break; case 'Module': default: $result .= 'Not'; } return $this->$result(); } protected function xdrNot() { return []; } protected function xdrWith() { return []; } protected function xdrLexical() { return [ 'bindingNames' => $this->XDRSizedBindingNames(), 'constStart' => $this->todec(), 'firstFrameSlot' => $this->todec(), 'nextFrameSlot' => $this->todec() ]; } protected function xdrFunction() { return [ 'bindingNames' => $this->XDRSizedBindingNames(), 'needsEnvironment' => $this->todec(1), 'hasParameterExprs' => $this->todec(1), 'nonPositionalFormalStart' => $this->todec(2), 'varStart' => $this->todec(2), 'nextFrameSlot' => $this->todec(), ]; } protected function xdrVar() { return [ 'bindingNames' => $this->XDRSizedBindingNames(), 'needsEnvironment' => $this->todec(1), 'firstFrameSlot' => $this->todec(), 'nextFrameSlot' => $this->todec() ]; } protected function xdrGlobal() { return [ 'bindingNames' => $this->XDRSizedBindingNames(), 'letStart' => $this->todec(), 'constStart' => $this->todec(), ]; } protected function xdrEval() { return [ 'bindingNames' => $this->XDRSizedBindingNames(), 'length' => $this->todec(), ]; } } ================================================ FILE: src/Xdr/Script.php ================================================ todec(2); $context->addSummary('nargs', $nargs); $context->addSummary('nblocklocals', $this->todec(2)); $nvars = $this->todec(); $context->addSummary('nvars', $nvars); $context->addSummary('length', $this->todec()); $context->addSummary('prologLength', $this->todec()); $context->addSummary('version', $this->todec()); $context->addSummary('natoms', $this->todec()); $context->addSummary('nsrcnotes', $this->todec()); $context->addSummary('nconsts', $this->todec()); $context->addSummary('nobjects', $this->todec()); $context->addSummary('nregexps', $this->todec()); $context->addSummary('ntrynotes', $this->todec()); $context->addSummary('nblockscopes', $this->todec()); $context->addSummary('nTypeSets', $this->todec()); $context->addSummary('funLength', $this->todec()); $scriptBit = $this->todec(); $context->addSummary('scriptBits', $scriptBit); $scriptBits = array_flip(Constant::_ScriptBits); if ($scriptBit & (1 << $scriptBits['OwnSource'])) { $context->addSummary('hasSource', $this->todec(1)); $context->addSummary('retrievable', $this->todec(1)); if($context->getSummary('hasSource') && !$context->getSummary('retirevable')) { $context->addSummary('sourceLength', $this->todec()); $context->addSummary('sourcecompressedLength', $this->todec()); $context->addSummary('argumentsNotIncluded', $this->todec(1)); $context->addSummary( 'sourceBytes', $this->getRawHex( $context->getSummary('sourcecompressedLength') ? $context->getSummary('sourcecompressedLength') : $context->getSummary('sourceLength') * 2 ) ); } $context->addSummary('hasSourceMap', $this->todec(1)); if($context->getSummary('hasSourceMap')) { $context->addSummary('sourceMapURLLen', $this->todec()); $context->addSummary('sourceMapURL', $this->getRawHex($context->getSummary('sourceMapURLLen') * 2)); } $context->addSummary('haveDisplayURL', $this->todec(1)); if($context->getSummary('haveDisplayURL')) { $context->addSummary('displayURLLen', $this->todec()); $context->addSummary('displayURL', $this->getRawHex($context->getSummary('displayURLLen'))); } $context->addSummary('haveFilename', $this->todec(1)); if($context->getSummary('haveFilename')) { $context->addSummary('buildPath', $this->getCString()); } } $nameCount = $nargs + $nvars; for ($i = 0; $i < $nameCount; $i++) { $atom = $this->XDRAtom(); $context->addArgv($atom); } for ($i = 0; $i < $nameCount; $i++) { $u8 = $this->todec(1); } $context->addSummary('sourceStart_', $this->todec()); $context->addSummary('sourceEnd_', $this->todec()); $context->addSummary('lineno', $this->todec()); $context->addSummary('column', $this->todec()); $context->addSummary('nslots', $this->todec()); $context->addSummary('staticLevel', $this->todec()); } protected function parserScript(Context $context) { $end = $this->parseIndex + $context->getSummary('length'); for (; $this->parseIndex < $end;) { $context->addOperation($this->parseIndex, $this->parserOperation()); } $this->parseIndex = $end; } protected function parserSrcNodes(Context $context) { $end = $this->parseIndex + $context->getSummary('nsrcnotes'); for (; $this->parseIndex < $end; $this->parseIndex++) { $context->addNode($this->bytecodes[$this->parseIndex]); } } protected function parserAtoms(Context $context) { if ($natoms = $context->getSummary('natoms')) { for ($i = 0; $i < $natoms; $i++) { $context->addAtom($this->XDRAtom()); } } } protected function parseConsts(Context $context) { if ($nconsts = $context->getSummary('nconsts')) { for ($i = 0; $i < $nconsts; $i++) { $context->addConst($this->xdrConst()); } } } protected function parserObject(Context $context) { $context->addObject( $classKind = Constant::_Class[$this->todec()], $extra = $this->xdrObjectExtra($classKind) ); } protected function parserObjects(Context $context) { if ($nobjects = $context->getSummary('nobjects')) { for ($i = 0; $i < $nobjects; $i++) { $this->parserObject($context); } } } protected function parserRegexps(Context $context) { if ($nregexps = $context->getSummary('nregexps')) { for ($i = 0; $i < $nregexps; $i++) { $context->addRegexp( $source = $this->XDRAtom(), $flagsword = $this->todec() ); } } } protected function parserTryNotes(Context $context) { if ($ntrynotes = $context->getSummary('ntrynotes')) { for ($i = 0; $i < $ntrynotes; $i++) { $context->addTryNote( $kind = $this->todec(1), $stackDepth = $this->todec(), $start = $this->todec(), $length = $this->todec() ); } } } protected function parserScopeNotes(Context $context) { if ($nscopeNotes = $context->getSummary('nblockscopes')) { for ($i = 0; $i < $nscopeNotes; $i++) { $context->addScopeNote( $index = $this->todec(), $start = $this->todec(), $length = $this->todec(), $parent = $this->todec() ); } } } protected function parserHasLazyScript(Context $context) { $scriptBits = array_flip(Constant::_ScriptBits); $HasLazyScript = $scriptBits['HasLazyScript']; if ($context->getSummary('scriptBits') & (1 << $HasLazyScript)) { $packedFields = $this->todec(8); $context->addHasLazyScript($packedFields); $this->XDRLazyFreeVariables(); } } public function XDRScript() { $context = new Context(); $index = count($this->contexts); $this->contexts[] = $context; $context->index = $index; $this->parseScriptIndex = $index; $context->decompile = $this; $this->parserHeader($context);//header storage the base info of a context, if jsc compile with no setSourceIsLazy(true), raw source save here $this->parserScript($context);//get the operations and parse to script (maybe not good enough to parse here) $this->parserSrcNodes($context); $this->parserAtoms($context);//this section save strings $this->parseConsts($context); $this->parserObjects($context);//this section save local simple objects $this->parserRegexps($context); $this->parserTryNotes($context); $this->parserScopeNotes($context);//this section save block scope info $this->parserHasLazyScript($context); return $context; } }