├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── WebAssembly.png ├── WebAssembly_uni.png ├── index.js ├── package.json ├── src ├── Reader.js ├── Writer.js ├── ast │ ├── ReadState.js │ ├── Reader.js │ ├── WriteState.js │ ├── Writer.js │ └── index.js ├── index.js ├── reflect │ ├── Assembly.js │ ├── BaseExport.js │ ├── Constant.js │ ├── DefaultExport.js │ ├── FunctionDeclaration.js │ ├── FunctionDefinition.js │ ├── FunctionImport.js │ ├── FunctionImportSignature.js │ ├── FunctionPointerElement.js │ ├── FunctionPointerTable.js │ ├── FunctionSignature.js │ ├── GlobalVariable.js │ ├── LocalVariable.js │ ├── RecordExport.js │ └── index.js ├── stmt │ ├── BaseExpr.js │ ├── BaseOperand.js │ ├── BaseStmt.js │ ├── ExprF32.js │ ├── ExprF64.js │ ├── ExprI32.js │ ├── ExprVoid.js │ ├── Stmt.js │ ├── StmtList.js │ ├── SwitchCase.js │ ├── behavior │ │ ├── BaseBehavior.js │ │ ├── BinaryBehavior.js │ │ ├── BlockBehavior.js │ │ ├── BranchBehavior.js │ │ ├── CallImportBehavior.js │ │ ├── CallIndirectBehavior.js │ │ ├── CallInternalBehavior.js │ │ ├── CommaBehavior.js │ │ ├── ConstantPoolBehavior.js │ │ ├── GetGlobalBehavior.js │ │ ├── GetLocalBehavior.js │ │ ├── LabelBehavior.js │ │ ├── LiteralBehavior.js │ │ ├── LoadBehavior.js │ │ ├── LoadWithOffsetBehavior.js │ │ ├── MultiaryBehavior.js │ │ ├── OpcodeOnlyBehavior.js │ │ ├── ReturnBehavior.js │ │ ├── SetGlobalBehavior.js │ │ ├── SetLocalBehavior.js │ │ ├── StmtListBehavior.js │ │ ├── StoreBehavior.js │ │ ├── StoreWithOffsetBehavior.js │ │ ├── SwitchBehavior.js │ │ ├── SwitchCaseMultipleBehavior.js │ │ ├── SwitchCaseNoneBehavior.js │ │ ├── SwitchCaseSingleBehavior.js │ │ ├── SwitchDefaultMultipleBehavior.js │ │ ├── SwitchDefaultNoneBehavior.js │ │ ├── SwitchDefaultSingleBehavior.js │ │ ├── UnaryBehavior.js │ │ └── index.js │ └── index.js ├── types.js ├── util.js └── util │ └── BufferQueue.js ├── tests ├── AngryBots-optimized.wasm ├── AngryBots.wasm ├── add-asm.js ├── add-test.js ├── add.wasm ├── assembler.js ├── fib-asm.js ├── fib.wasm └── test.js └── tools ├── externs ├── assert.js └── errors.js ├── opcodes-md-template.js ├── patch-cli.js └── unpack-cli.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | .idea/ 4 | raw/ 5 | v8.log 6 | tests/*.txt 7 | tests/AngryBotsPacked 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | .idea/ 4 | raw/ 5 | v8.log 6 | tests/*.txt 7 | tests/AngryBotsPacked 8 | 9 | WebAssembly.png 10 | WebAssembly_uni.png 11 | tests/*.wasm 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | - 0.12 5 | env: 6 | - VERBOSE=0 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

WebAssembly

2 | 3 | **WebAssembly** is a new, portable, size- and load-time-efficient format suitable for compilation to the web, designed 4 | in a collaborative afford under the umbrella of the W3C ([see](https://www.w3.org/community/webassembly/)). 5 | 6 | This package aims to provide tools for working with [WebAssembly](https://github.com/WebAssembly) binaries, providing 7 | interested developers with an easy way to experiment with the technology from within JavaScript itself. 8 | 9 | [![Build Status](https://travis-ci.org/dcodeIO/WebAssembly.svg)](https://travis-ci.org/dcodeIO/WebAssembly) 10 | 11 | Contents 12 | -------- 13 | 14 | * **[Type definitions](https://github.com/dcodeIO/WebAssembly/blob/master/src/types.js)**
15 | Relevant type and opcode definitions. 16 | 17 | * **[Reflection structure](https://github.com/dcodeIO/WebAssembly/tree/master/src/reflect)**
18 | Classes to represent the different sections of a WASM binary. 19 | 20 | * **[Statement types](https://github.com/dcodeIO/WebAssembly/tree/master/src/stmt)**
21 | Classes to represent the different statement and expression types. 22 | 23 | * **[Statement and expression behaviors](https://github.com/dcodeIO/WebAssembly/tree/master/src/stmt/behavior)**
24 | Classes describing the wire-format of any statement or expression in an easy to grasp way. 25 | 26 | * **[Reader](https://github.com/dcodeIO/WebAssembly/blob/master/src/Reader.js)**
27 | A streaming reader for disassembling WASM binaries into their respective reflection structure. 28 | 29 | * **[AstReader](https://github.com/dcodeIO/WebAssembly/blob/master/src/ast/Reader.js)**
30 | A streaming reader for disassembling function bodies into their respective AST. 31 | 32 | * **[Writer](https://github.com/dcodeIO/WebAssembly/blob/master/src/Writer.js)**
33 | A streaming writer for assembling WASM binaries from their respective reflection structure. 34 | 35 | * **[AstWriter](https://github.com/dcodeIO/WebAssembly/blob/master/src/ast/Writer.js)**
36 | A streaming writer for assembling function bodies from their respective AST. 37 | 38 | Compatibility 39 | ------------- 40 | For now this library aims to be compatible with what can be learned from the [polyfill prototype](https://github.com/WebAssembly/polyfill-prototype-1), 41 | but is written in plain JavaScript and does not contain any compiled code. 42 | 43 | While this package is built for the [node.js](https://nodejs.org/) platform, it *should* be trivial to also package it 44 | for browsers using [browserify](http://browserify.org). 45 | 46 | Please note that the [WebAssembly design](https://github.com/WebAssembly/design) is still in flux and that 47 | [binary encoding](https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md) and 48 | [AST semantics](https://github.com/WebAssembly/design/blob/master/AstSemantics.md) may change at any time. 49 | 50 | Usage 51 | ----- 52 | 53 | ##### Parsing a WASM binary including ASTs 54 | 55 | ```js 56 | var webassembly = require("webassembly"), 57 | Reader = webassembly.Reader; 58 | 59 | var reader = new Reader(); 60 | 61 | reader.on("functionDefinition", function(definition, index) { 62 | ... 63 | }); 64 | 65 | reader.on("end", function() { 66 | var myAssembly = reader.assembly; 67 | ... 68 | }); 69 | 70 | // Write your WASM data to it 71 | // - either manually: 72 | reader.write(wasmBinaryData); 73 | // - or pipe it: 74 | require("fs").createReadStream("wasmBinaryFile.wasm").pipe(reader); 75 | ``` 76 | 77 | ##### Just indexing a WASM binary, parsing ASTs on demand 78 | 79 | ```js 80 | var webassembly = require("webassembly"), 81 | Reader = webassembly.Reader, 82 | AstReader = webassembly.ast.Reader; 83 | 84 | var reader = new Reader({ 85 | skipAhead: true // Tells the AstReader not to generate statements, skipping ahead 86 | }); 87 | 88 | reader.on("end", function() { 89 | reader.assembly.functionDeclarations.forEach(function(declaration) { 90 | var definition = declaration.definition; 91 | ... 92 | 93 | // And create an AstReader from the definition manually, 94 | // piping in the relevant portion of bytes: 95 | var astReader = new AstReader(definition); 96 | astReader.on("ast", function(ast) { 97 | ... 98 | }); 99 | 100 | astReader.createReadStream("wasmBinaryFile.wasm", { 101 | start: definition.byteOffset, 102 | end: definition.byteOffset + definition.byteLength 103 | }).pipe(reader); 104 | }); 105 | }); 106 | 107 | ... 108 | ``` 109 | 110 | Documentation 111 | ------------- 112 | * [Binary Format](https://github.com/dcodeIO/WebAssembly/wiki/Binary-Format) 113 | * [Opcodes](https://github.com/dcodeIO/WebAssembly/wiki/Opcodes) 114 | * [Reader](https://github.com/dcodeIO/WebAssembly/wiki/Reader) 115 | 116 | Feel free to contribute! 117 | 118 | **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) - Logo derived from [W3C HTML5 Logos](http://www.w3.org/html/logo/) (CC A 3.0) 119 | -------------------------------------------------------------------------------- /WebAssembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcodeIO/WebAssembly-prototype/50e84e133a6e18b0ba0908eea241f836392ebde2/WebAssembly.png -------------------------------------------------------------------------------- /WebAssembly_uni.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcodeIO/WebAssembly-prototype/50e84e133a6e18b0ba0908eea241f836392ebde2/WebAssembly_uni.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | exports = require("./src"); 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webassembly", 3 | "description": "JavaScript tools for working with WebAssembly (WASM) binaries.", 4 | "author": "Daniel Wirtz ", 5 | "version": "0.9.0", 6 | "main": "src/index.js", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/dcodeIO/WebAssembly.git" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/dcodeIO/WebAssembly/issues" 13 | }, 14 | "homepage": "https://github.com/dcodeIO/WebAssembly", 15 | "keywords": [ 16 | "WebAssembly", 17 | "WASM", 18 | "AST", 19 | "parser" 20 | ], 21 | "dependencies": {}, 22 | "scripts": { 23 | "test": "node tests/test.js" 24 | }, 25 | "engines": { 26 | "node": ">=0.10" 27 | }, 28 | "license": "Apache License, Version 2.0" 29 | } 30 | -------------------------------------------------------------------------------- /src/ast/ReadState.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"), 2 | util = require("../util"); 3 | 4 | var ExprI32 = require("../stmt/ExprI32"), 5 | ExprF32 = require("../stmt/ExprF32"), 6 | ExprF64 = require("../stmt/ExprF64"), 7 | ExprVoid = require("../stmt/ExprVoid"), 8 | SwitchCase = require("../stmt/SwitchCase"), 9 | Stmt = require("../stmt/Stmt"); 10 | 11 | /** 12 | * AST read state. 13 | * @constructor 14 | * @param {!ast.Reader} reader 15 | * @param {number} popState 16 | * @exports ast.ReadState 17 | */ 18 | function ReadState(reader, popState) { 19 | 20 | /** 21 | * Reader reference. 22 | * @type {!ast.Reader} 23 | */ 24 | this.reader = reader; 25 | 26 | /** 27 | * Pop state. 28 | * @type {number} 29 | */ 30 | this.popState = popState; 31 | 32 | /** 33 | * Current type. 34 | * @type {number|undefined} 35 | * @private 36 | */ 37 | this._type = undefined; 38 | 39 | /** 40 | * Whether an imm is present. 41 | * @type {boolean} 42 | * @private 43 | */ 44 | this._withImm = false; 45 | 46 | /** 47 | * Current statement. 48 | * @type {!stmt.BaseStmt|undefined} 49 | * @private 50 | */ 51 | this._stmt = undefined; 52 | 53 | /** 54 | * States derived from the current operation. 55 | * @type {!Array.} 56 | * @private 57 | */ 58 | this._states = []; 59 | } 60 | 61 | module.exports = ReadState; 62 | 63 | var Reader = require("./Reader"); // cyclic 64 | 65 | /** 66 | * Prepares for the next read operation. 67 | * @param {number} type Wire type 68 | * @param {number} code 69 | * @param {number|null} imm 70 | */ 71 | ReadState.prototype.prepare = function(type, code, imm) { 72 | this._type = type; 73 | this._withImm = imm !== null; 74 | this._stmt = undefined; 75 | this._states = []; 76 | }; 77 | 78 | /** 79 | * Commits the current read operation. 80 | */ 81 | ReadState.prototype.commit = function() { 82 | this.reader.bufferQueue.advance(); 83 | if (!this.reader.skipAhead) { 84 | this.reader.emit("stmt", this._stmt); 85 | var parent = this.reader.stack[this.reader.stack.length - 1]; 86 | parent.add(this._stmt); 87 | } 88 | if (this._states.length > 0) { 89 | if (!this.reader.skipAhead) { 90 | this.reader.stack.push(this._stmt); 91 | this.reader.state.push(this.popState); 92 | } 93 | for (var i=this._states.length-1; i>=0; --i) 94 | this.reader.state.push(this._states[i]); 95 | } 96 | this.reset(); 97 | }; 98 | 99 | /** 100 | * Resets the internal state. 101 | */ 102 | ReadState.prototype.reset = function() { 103 | this._type = this._stmt = undefined; 104 | this._withImm = false; 105 | this._states = []; 106 | this.reader.bufferQueue.reset(); 107 | }; 108 | 109 | /** 110 | * Gets the current function's return type. 111 | * @returns {number} 112 | */ 113 | ReadState.prototype.rtype = function() { 114 | return this.reader.signature.returnType; 115 | }; 116 | 117 | /** 118 | * Reads the next unsigned byte. 119 | * @returns {number} 120 | */ 121 | ReadState.prototype.u8 = function() { 122 | return this.reader.bufferQueue.readUInt8(); 123 | }; 124 | 125 | /** 126 | * Reads the next unsigned varint. 127 | * @returns {number} 128 | */ 129 | ReadState.prototype.varint = function() { 130 | return this.reader.bufferQueue.readVarint(); 131 | }; 132 | 133 | /** 134 | * Reads the next signed varint. 135 | * @returns {number} 136 | */ 137 | ReadState.prototype.varint_s = function() { 138 | return this.reader.bufferQueue.readVarintSigned(); 139 | }; 140 | 141 | /** 142 | * Reads the next 32bit float. 143 | * @returns {number} 144 | */ 145 | ReadState.prototype.f32 = function() { 146 | return this.reader.bufferQueue.readFloatLE(); 147 | }; 148 | 149 | /** 150 | * Reads the next 64bit double. 151 | * @returns {number} 152 | */ 153 | ReadState.prototype.f64 = function() { 154 | return this.reader.bufferQueue.readDoubleLE(); 155 | }; 156 | 157 | /** 158 | * Creates a statement or expression with the specified code. 159 | * @param {number} code 160 | * @param {(number|!stmt.BaseOperand|!Array.)=} operands 161 | * @returns {!stmt.BaseStmt|undefined} 162 | */ 163 | ReadState.prototype.stmt = function(code, operands) { 164 | if (this.reader.skipAhead) 165 | return; 166 | switch (this._type) { 167 | case types.WireType.ExprI32: 168 | this._stmt = new ExprI32(code, operands); 169 | break; 170 | case types.WireType.ExprF32: 171 | this._stmt = new ExprF32(code, operands); 172 | break; 173 | case types.WireType.ExprF64: 174 | this._stmt = new ExprF64(code, operands); 175 | break; 176 | case types.WireType.ExprVoid: 177 | this._stmt = new ExprVoid(code, operands); 178 | break; 179 | case types.WireType.SwitchCase: 180 | this._stmt = new SwitchCase(code, operands); 181 | break; 182 | case types.WireType.Stmt: 183 | this._stmt = new Stmt(code, operands); 184 | break; 185 | default: 186 | throw Error("illegal WireType: "+this._type); 187 | 188 | } 189 | this._stmt.withImm = this._withImm; 190 | return this._stmt; 191 | }; 192 | 193 | /** 194 | * Creates a statement or expression with the specified code, converted to its counterpart without imm. 195 | * @param {number} code 196 | * @param {(number|!stmt.BaseOperand|!Array.)=} operands 197 | * @returns {!stmt.BaseStmt|boolean} `false` if there is no counterpart without imm 198 | */ 199 | ReadState.prototype.stmtWithoutImm = function(code, operands) { 200 | if ((code = types.codeWithoutImm(this._type, code)) < 0) 201 | throw Error("cannot convert "+types.WireTypeNames[this._type]+" code to non-imm counterpart: "+code); 202 | return this.stmt(code, operands); 203 | }; 204 | 205 | /** 206 | * Prepares to read the next statement or expression. 207 | * @param {number} wireType 208 | */ 209 | ReadState.prototype.read = function(wireType) { 210 | if (wireType === undefined) 211 | throw Error("meh"); 212 | this._states.push(wireType); 213 | }; 214 | 215 | /** 216 | * Gets the constant of matching type at the specified index. 217 | * @param {number} index 218 | * @returns {!reflect.Constant} 219 | */ 220 | ReadState.prototype.constant = function(index) { 221 | return this.reader.assembly.getConstant(this._type, index); 222 | }; 223 | 224 | /** 225 | * Gets the local variable at the specified index. 226 | * @param {number} index 227 | * @param {number=} type 228 | * @returns {!reflect.LocalVariable} 229 | */ 230 | ReadState.prototype.local = function(index, type) { 231 | var variable = this.reader.definition.getVariable(index); 232 | if (typeof type !== 'undefined' && variable.type !== type) 233 | throw Error("illegal local variable type: "+variable.type+" != "+type); 234 | return variable; 235 | }; 236 | 237 | /** 238 | * Gets the global variable at the specified index. 239 | * @param {number} index 240 | * @param {number=} type 241 | * @returns {!reflect.GlobalVariable} 242 | */ 243 | ReadState.prototype.global = function(index, type) { 244 | var variable = this.reader.assembly.getGlobalVariable(index); 245 | if (typeof type !== 'undefined' && variable.type !== type) 246 | throw Error("illegal global variable type: "+variable.type+" != "+type); 247 | return variable; 248 | }; 249 | 250 | /** 251 | * Gets the function declaration at the specified index. 252 | * @param {number} index 253 | * @returns {!reflect.FunctionDeclaration} 254 | */ 255 | ReadState.prototype.internal = function(index) { 256 | return this.reader.assembly.getFunctionDeclaration(index); 257 | }; 258 | 259 | /** 260 | * Gets the function pointer table at the specified index. 261 | * @param {number} index 262 | * @returns {!reflect.FunctionPointerTable} 263 | */ 264 | ReadState.prototype.indirect = function(index) { 265 | return this.reader.assembly.getFunctionPointerTable(index); 266 | }; 267 | 268 | /** 269 | * Gets the function import signature at the specified index. 270 | * @param {number} index 271 | * @returns {!reflect.FunctionImportSignature} 272 | */ 273 | ReadState.prototype.import = function(index) { 274 | return this.reader.assembly.getFunctionImportSignature(index); 275 | }; 276 | 277 | /** 278 | * Advances the buffer queue. 279 | */ 280 | ReadState.prototype.advance = function() { 281 | this.reader.bufferQueue.advance(); 282 | }; 283 | 284 | /** 285 | * Finishes the read state. 286 | */ 287 | ReadState.prototype.finish = function() { 288 | this.reset(); 289 | this.reader = null; 290 | }; 291 | -------------------------------------------------------------------------------- /src/ast/Reader.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Daniel Wirtz 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | var stream = require("stream"), 17 | util = require("../util"), 18 | types = require("../types"), 19 | stmt = require("../stmt/"); 20 | 21 | var ReadState = require("./ReadState"); 22 | 23 | var Constant = require("../reflect/Constant"), 24 | GlobalVariable = require("../reflect/GlobalVariable"), 25 | FunctionSignature = require("../reflect/FunctionSignature"), 26 | FunctionDeclaration = require("../reflect/FunctionDeclaration"), 27 | FunctionImport = require("../reflect/FunctionImport"), 28 | FunctionImportSignature = require("../reflect/FunctionImportSignature"), 29 | FunctionPointerTable = require("../reflect/FunctionPointerTable"), 30 | LocalVariable = require("../reflect/LocalVariable"); 31 | 32 | var BaseStmt = stmt.BaseStmt, 33 | StmtList = stmt.StmtList, 34 | Stmt = stmt.Stmt, 35 | SwitchCase = stmt.SwitchCase, 36 | ExprI32 = stmt.ExprI32, 37 | ExprF32 = stmt.ExprF32, 38 | ExprF64 = stmt.ExprF64, 39 | ExprVoid = stmt.ExprVoid; 40 | 41 | var verbose = 0; // For debugging 42 | 43 | /** 44 | * An abstract syntax tree reader. 45 | * @constructor 46 | * @param {!reflect.FunctionDefinition} functionDefinition 47 | * @param {!util.BufferQueue=} bufferQueue 48 | * @param {!Object.=} options 49 | * @exports ast.Reader 50 | */ 51 | function Reader(functionDefinition, bufferQueue, options) { 52 | stream.Writable.call(this, options); 53 | 54 | if (!(bufferQueue instanceof util.BufferQueue)) { 55 | options = bufferQueue; 56 | bufferQueue = undefined; 57 | } 58 | 59 | /** 60 | * Function definition. 61 | * @type {!reflect.FunctionDefinition} 62 | */ 63 | this.definition = functionDefinition; 64 | 65 | /** 66 | * Read buffer queue. 67 | * @type {!util.BufferQueue} 68 | */ 69 | this.bufferQueue = bufferQueue || new util.BufferQueue(); 70 | 71 | /** 72 | * State stack. 73 | * @type {!Array.} 74 | */ 75 | this.state = [Reader.State.StmtList]; 76 | 77 | /** 78 | * Processing stack. 79 | * @type {Array.} 80 | */ 81 | this.stack = []; // Expected to contain the root StmtList only when finished 82 | 83 | /** 84 | * Read state closure. 85 | * @type {!ast.ReadState} 86 | */ 87 | this.readState = new ReadState(this, Reader.State.Pop); 88 | 89 | /** 90 | * Whether to skip ahead, not parsing the AST in detail. 91 | * @type {boolean} 92 | */ 93 | this.skipAhead = !!(options && options.skipAhead); 94 | } 95 | 96 | module.exports = Reader; 97 | 98 | // Extends stream.Writable 99 | Reader.prototype = Object.create(stream.Writable.prototype); 100 | 101 | /** 102 | * Global offset. 103 | * @name ast.Reader#offset 104 | * @type {number} 105 | */ 106 | Object.defineProperty(Reader.prototype, "offset", { 107 | get: function() { 108 | return this.bufferQueue.offset; 109 | } 110 | }); 111 | 112 | /** 113 | * Function declaration. 114 | * @name ast.Reader#declaration 115 | * @type {!reflect.FunctionDeclaration} 116 | */ 117 | Object.defineProperty(Reader.prototype, "declaration", { 118 | get: function() { 119 | return this.definition.declaration; 120 | } 121 | }); 122 | 123 | /** 124 | * Function signature. 125 | * @name ast.Reader#signature 126 | * @type {!reflect.FunctionSignature} 127 | */ 128 | Object.defineProperty(Reader.prototype, "signature", { 129 | get: function() { 130 | return this.definition.declaration.signature; 131 | } 132 | }); 133 | 134 | /** 135 | * Assembly. 136 | * @name ast.Reader#assembly 137 | * @type {!reflect.Assembly} 138 | */ 139 | Object.defineProperty(Reader.prototype, "assembly", { 140 | get: function() { 141 | return this.definition.declaration.assembly; 142 | } 143 | }); 144 | 145 | /** 146 | * States. 147 | * @type {!Object.} 148 | * @const 149 | */ 150 | Reader.State = { 151 | ExprI32: types.WireType.ExprI32, 152 | ExprF32: types.WireType.ExprF32, 153 | ExprF64: types.WireType.ExprF64, 154 | ExprVoid: types.WireType.ExprVoid, 155 | SwitchCase: types.WireType.SwitchCase, 156 | Stmt: types.WireType.Stmt, 157 | StmtList: types.WireType.StmtList, 158 | Pop: types.WireTypeMax + 1 159 | }; 160 | 161 | Reader.prototype._write = function (chunk, encoding, callback) { 162 | if (this.state.length === 0) { // Already done or failed 163 | callback(Error("already ended")); 164 | return; 165 | } 166 | if (encoding) 167 | chunk = new Buffer(chunk, encoding); 168 | if (chunk.length === 0) { 169 | callback(); 170 | return; 171 | } 172 | this.bufferQueue.push(chunk); 173 | this._process(); 174 | callback(); 175 | }; 176 | 177 | Reader.prototype._process = function() { 178 | if (this.state.length === 0) 179 | return; 180 | do { 181 | if (this.state.length === 0) { // Done 182 | if (!this.skipAhead) { 183 | this.readState.finish(); 184 | if (this.stack.length !== 1) 185 | throw Error("illegal state: stack not cleared: "+this.stack.length); 186 | var stmtList = this.stack[0]; 187 | if (!(stmtList instanceof StmtList)) 188 | throw Error("illegal state: last stack item is not a StmtList: " + stmtList); 189 | if (stmtList.length > 0) { 190 | stmtList.forEach(function (stmt) { 191 | if (!(stmt instanceof BaseStmt)) 192 | throw Error("illegal state: StmtList contains non-Stmt: " + stmt); 193 | }); 194 | } 195 | this.emit("ast", stmtList); 196 | } 197 | this.emit("end"); 198 | return; 199 | } 200 | var state = this.state.pop(); 201 | if (verbose >= 2) 202 | console.log("state: "+state); 203 | try { 204 | switch (state) { 205 | case Reader.State.ExprI32: 206 | this._readExprI32(); 207 | break; 208 | case Reader.State.ExprF32: 209 | this._readExprF32(); 210 | break; 211 | case Reader.State.ExprF64: 212 | this._readExprF64(); 213 | break; 214 | case Reader.State.ExprVoid: 215 | this._readExprVoid(); 216 | break; 217 | case Reader.State.SwitchCase: 218 | this._readSwitchCase(); 219 | break; 220 | case Reader.State.Stmt: 221 | this._readStmt(); 222 | break; 223 | case Reader.State.StmtList: 224 | this._readStmtList(); 225 | break; 226 | case Reader.State.Pop: 227 | this.stack.pop(); 228 | break; 229 | default: 230 | throw Error("illegal state: " + state); 231 | } 232 | } catch (err) { 233 | if (err === util.BufferQueue.E_MORE) { 234 | this.state.push(state); // Wait for more 235 | return; 236 | } 237 | if (verbose >= 1) 238 | console.log(this.inspect()); 239 | this.emit("error", err); 240 | this.state = []; 241 | return; 242 | } finally { 243 | this.readState.reset(); 244 | } 245 | } while (true); 246 | }; 247 | 248 | Reader.prototype._readStmtList = function() { 249 | var size = this.readState.varint(); 250 | this.readState.advance(); 251 | if (!this.skipAhead) 252 | this.stack.push(new StmtList(size)); 253 | for (var i=0; i= 1) 270 | console.log("processing "+name+":" + types[name+"Names"][code] + " @ " + (this.offset-1).toString(16)); 271 | this.readState.prepare(wireType, code, null); 272 | clazz.determineBehavior(code, false).read(this.readState, code, null); 273 | } else { 274 | code = util.unpackWithImm(code); 275 | if (verbose >= 1) 276 | console.log("processing "+name+"WithImm:" + types[name+"WithImmNames"][code.code] + " @ " + (this.offset-1).toString(16)); 277 | this.readState.prepare(wireType, code.code, code.imm); 278 | clazz.determineBehavior(code.code, true).read(this.readState, code.code, code.imm); 279 | } 280 | this.readState.commit(); 281 | }; 282 | } 283 | 284 | Reader.prototype._readStmt = makeGenericRead(types.WireType.Stmt, Stmt, "Stmt"); 285 | Reader.prototype._readExprI32 = makeGenericRead(types.WireType.ExprI32, ExprI32, "I32"); 286 | Reader.prototype._readExprF32 = makeGenericRead(types.WireType.ExprF32, ExprF32, "F32"); 287 | Reader.prototype._readExprF64 = makeGenericRead(types.WireType.ExprF64, ExprF64, "F64"); 288 | Reader.prototype._readExprVoid = makeGenericRead(types.WireType.ExprVoid, ExprVoid, "Void"); 289 | Reader.prototype._readSwitchCase = makeGenericRead(types.WireType.SwitchCase, SwitchCase, "SwitchCase"); 290 | 291 | /** 292 | * Inspects a statement structure. 293 | * @param {!stmt.BaseStmt|!stmt.StmtList|number} stmt 294 | * @param {number=} depth 295 | * @returns {string} 296 | */ 297 | Reader.inspect = function(stmt, depth) { 298 | depth = depth || 0; 299 | var indent = ""; 300 | for (var i=0; i} 36 | * @private 37 | */ 38 | this._stack = []; 39 | } 40 | 41 | module.exports = WriteState; 42 | 43 | WriteState.prototype.prepare = function(type, stmt) { 44 | this._type = type; 45 | this._stmt = stmt; 46 | this._stack = []; 47 | }; 48 | 49 | WriteState.prototype.commit = function() { 50 | this.writer.bufferQueue.commit(); 51 | for (var i=this._stack.length-1; i>=0; --i) 52 | this.writer.stack.push(this._stack[i]); 53 | this.reset(); 54 | }; 55 | 56 | WriteState.prototype.reset = function() { 57 | this._type = this._stmt = undefined; 58 | this._stack = []; 59 | }; 60 | 61 | WriteState.prototype.rtype = function() { 62 | return this.writer.signature.returnType; 63 | }; 64 | 65 | WriteState.prototype.u8 = function(b) { 66 | this.writer.bufferQueue.writeUInt8(b); 67 | }; 68 | 69 | WriteState.prototype.code = function(code) { 70 | this.writer.bufferQueue.writeUInt8(code); 71 | }; 72 | 73 | WriteState.prototype.codeWithImm = function(code, imm) { 74 | if (imm < 0 || imm > types.OpWithImm_ImmMax || (code = types.codeWithImm(this._type, code)) < 0) 75 | return false; 76 | if (this.writer.preserveWithImm && !this._stmt.withImm) 77 | return false; 78 | this.writer.bufferQueue.writeUInt8(util.packWithImm(code, imm)); 79 | return true; 80 | }; 81 | 82 | WriteState.prototype.varint = function(value) { 83 | this.writer.bufferQueue.writeVarint(value); 84 | }; 85 | 86 | WriteState.prototype.varint_s = function(value) { 87 | this.writer.bufferQueue.writeVarintSigned(value); 88 | }; 89 | 90 | WriteState.prototype.f32 = function(value) { 91 | this.writer.bufferQueue.writeFloatLE(value); 92 | }; 93 | 94 | WriteState.prototype.f64 = function(value) { 95 | this.writer.bufferQueue.writeDoubleLE(value); 96 | }; 97 | 98 | WriteState.prototype.write = function(stmt) { 99 | this._stack.push(stmt); 100 | }; 101 | -------------------------------------------------------------------------------- /src/ast/Writer.js: -------------------------------------------------------------------------------- 1 | var stream = require("stream"), 2 | assert = require("assert"), 3 | types = require("../types"), 4 | util = require("../util"); 5 | 6 | var WriteState = require("./WriteState"), 7 | StmtList = require("../stmt/StmtList"), 8 | ExprI32 = require("../stmt/ExprI32"), 9 | ExprF32 = require("../stmt/ExprF32"), 10 | ExprF64 = require("../stmt/ExprF64"), 11 | ExprVoid = require("../stmt/ExprVoid"), 12 | SwitchCase = require("../stmt/SwitchCase"), 13 | Stmt = require("../stmt/Stmt"); 14 | 15 | var verbose = 0; // for debugging 16 | 17 | /** 18 | * An abstract syntax tree writer. 19 | * 20 | * The writer is created in paused mode. Call {@link ast.Writer#resume) to 21 | * begin writing the AST. 22 | * 23 | * @param {!reflect.FunctionDefinition} functionDefinition 24 | * @param {!util.BufferQueue=} bufferQueue 25 | * @param {!Object.=} options 26 | * @constructor 27 | * @extends stream.Readable 28 | * @exports ast.Writer 29 | */ 30 | function Writer(functionDefinition, bufferQueue, options) { 31 | assert(functionDefinition.ast instanceof StmtList, "definition must contain an AST"); 32 | 33 | stream.Readable.call(this, options); 34 | 35 | if (!(bufferQueue instanceof util.BufferQueue)) { 36 | options = bufferQueue; 37 | bufferQueue = undefined; 38 | } 39 | 40 | /** 41 | * Function definition. 42 | * @type {!reflect.FunctionDefinition} 43 | */ 44 | this.definition = functionDefinition; 45 | 46 | /** 47 | * Writer buffer queue. 48 | * @type {!util.BufferQueue} 49 | */ 50 | this.bufferQueue = bufferQueue || new util.BufferQueue(); 51 | 52 | /** 53 | * Statement stack. 54 | * @type {!Array.} 55 | */ 56 | this.stack = [functionDefinition.ast]; // StmtList 57 | 58 | /** 59 | * Write state. 60 | * @type {!ast.WriteState} 61 | */ 62 | this.writeState = new WriteState(this); 63 | 64 | /** 65 | * Whether opcodes with imm should be preserved. Relevant only when rewriting ASTs with the intend to preserve 66 | * their original (unoptimized) byte code, e.g. for comparison. 67 | * @type {boolean} 68 | */ 69 | this.preserveWithImm = !!(options && options.preserveWithImm); 70 | 71 | this.pause(); 72 | } 73 | 74 | module.exports = Writer; 75 | 76 | // Extends Readable 77 | Writer.prototype = Object.create(stream.Readable.prototype); 78 | 79 | /** 80 | * Function declaration. 81 | * @name ast.Writer#declaration 82 | * @type {!reflect.FunctionDeclaration} 83 | */ 84 | Object.defineProperty(Writer.prototype, "declaration", { 85 | get: function() { 86 | return this.definition.declaration; 87 | } 88 | }); 89 | 90 | /** 91 | * Function signature. 92 | * @name ast.Writer#signature 93 | * @type {!reflect.FunctionSignature} 94 | */ 95 | Object.defineProperty(Writer.prototype, "signature", { 96 | get: function() { 97 | return this.definition.declaration.signature; 98 | } 99 | }); 100 | 101 | /** 102 | * Assembly. 103 | * @name ast.Writer#assembly 104 | * @type {!reflect.Assembly} 105 | */ 106 | Object.defineProperty(Writer.prototype, "assembly", { 107 | get: function() { 108 | return this.definition.declaration.assembly; 109 | } 110 | }); 111 | 112 | /** 113 | * Global offset. 114 | * @name ast.Writer#offset 115 | * @type {number} 116 | */ 117 | Object.defineProperty(Writer.prototype, "offset", { 118 | get: function() { 119 | return this.bufferQueue.offset; 120 | } 121 | }); 122 | 123 | Writer.prototype._read = function(size) { 124 | if (this.stack.length === 0) 125 | throw Error("already done"); 126 | this.bufferQueue.push(new Buffer(size)); 127 | this._process(); 128 | }; 129 | 130 | Writer.prototype._process = function() { 131 | if (this.stack.length === 0) 132 | return; 133 | while (this.stack.length > 0) { 134 | var stmt = this.stack.pop(), 135 | state = stmt.type; 136 | this.emit("switchState", state, this.offset); 137 | try { 138 | switch (state) { 139 | case types.WireType.ExprI32: 140 | this._writeExprI32(stmt); 141 | break; 142 | case types.WireType.ExprF32: 143 | this._writeExprF32(stmt); 144 | break; 145 | case types.WireType.ExprF64: 146 | this._writeExprF64(stmt); 147 | break; 148 | case types.WireType.ExprVoid: 149 | this._writeExprVoid(stmt); 150 | break; 151 | case types.WireType.SwitchCase: 152 | this._writeSwitchCase(stmt); 153 | break; 154 | case types.WireType.Stmt: 155 | this._writeStmt(stmt); 156 | break; 157 | case types.WireType.StmtList: 158 | this._writeStmtList(stmt); 159 | break; 160 | default: 161 | throw Error("illegal wire type: " + stmt.type); 162 | } 163 | } catch (err) { 164 | if (err === util.BufferQueue.E_MORE) { 165 | this.stack.push(stmt); 166 | var buf = this.bufferQueue.reset().toBuffer(); 167 | this.push(buf); 168 | if (buf.length > 0) 169 | this.bufferQueue.clear(); 170 | return; // Wait for more 171 | } 172 | this.emit("error", err); 173 | this.stack = []; 174 | return; 175 | } 176 | } 177 | this.bufferQueue.commit(); 178 | this.push(this.bufferQueue.toBuffer()); 179 | this.bufferQueue.clear(); 180 | this.push(null); 181 | }; 182 | 183 | Writer.prototype._writeStmtList = function(stmtList) { 184 | this.bufferQueue 185 | .writeVarint(stmtList.length) 186 | .commit(); 187 | for (var i=stmtList.length-1; i>=0; --i) 188 | this.stack.push(stmtList[i]); 189 | }; 190 | 191 | function makeGenericWrite(wireType, clazz, name) { 192 | return function(stmt) { 193 | if (verbose >= 1) 194 | console.log("writing "+stmt+" @ "+this.offset.toString(16)); 195 | this.emit("stmt", stmt); 196 | this.writeState.prepare(wireType, stmt); 197 | stmt.behavior.write(this.writeState, stmt); 198 | this.writeState.commit(); 199 | } 200 | } 201 | 202 | Writer.prototype._writeExprI32 = makeGenericWrite(types.WireType.ExprI32, ExprI32, "I32"); 203 | Writer.prototype._writeExprF32 = makeGenericWrite(types.WireType.ExprF32, ExprF32, "F32"); 204 | Writer.prototype._writeExprF64 = makeGenericWrite(types.WireType.ExprF64, ExprF64, "F64"); 205 | Writer.prototype._writeExprVoid = makeGenericWrite(types.WireType.ExprVoid, ExprVoid, "Void"); 206 | Writer.prototype._writeSwitchCase = makeGenericWrite(types.WireType.SwitchCase, SwitchCase, "SwitchCase"); 207 | Writer.prototype._writeStmt = makeGenericWrite(types.WireType.Stmt, Stmt, "Stmt"); 208 | -------------------------------------------------------------------------------- /src/ast/index.js: -------------------------------------------------------------------------------- 1 | exports.Reader = require("./Reader"); 2 | exports.ReadState = require("./ReadState"); 3 | 4 | exports.Writer = require("./Writer"); 5 | exports.WriteState = require("./WriteState"); 6 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | exports.types = require("./types"); 2 | exports.util = require("./util"); 3 | exports.stmt = require("./stmt"); 4 | exports.reflect = require("./reflect"); 5 | exports.ast = require("./ast"); 6 | 7 | exports.Reader = require("./Reader"); 8 | exports.Writer = require("./Writer"); 9 | -------------------------------------------------------------------------------- /src/reflect/BaseExport.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Abstract base class of exports. 3 | * @constructor 4 | * @param {!Assembly} assembly 5 | * @exports reflect.BaseExport 6 | */ 7 | function BaseExport(assembly) { 8 | 9 | /** 10 | * Assembly reference. 11 | * @type {!reflect.Assembly} 12 | */ 13 | this.assembly = assembly; 14 | } 15 | 16 | module.exports = BaseExport; 17 | -------------------------------------------------------------------------------- /src/reflect/Constant.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"); 2 | 3 | var BaseOperand = require("../stmt/BaseOperand"); 4 | 5 | /** 6 | * A global constant. 7 | * @constructor 8 | * @param {!Assembly} assembly 9 | * @param {number} type 10 | * @param {number} value 11 | * @extends stmt.BaseOperand 12 | * @exports reflect.Constant 13 | */ 14 | function Constant(assembly, type, value) { 15 | BaseOperand.call(this); 16 | 17 | /** 18 | * Assembly reference. 19 | * @type {!Assembly} 20 | */ 21 | this.assembly = assembly; 22 | 23 | /** 24 | * Constant type. 25 | * @type {number} 26 | */ 27 | this.type = type; 28 | 29 | /** 30 | * Constant value. 31 | * @type {number} 32 | */ 33 | this.value = value; 34 | } 35 | 36 | module.exports = Constant; 37 | 38 | // Extends BaseOperand 39 | Constant.prototype = Object.create(BaseOperand.prototype); 40 | 41 | /** 42 | * Constant index in the constant pool of its respective type. 43 | * @name reflect.Constant#index 44 | * @type {number} 45 | */ 46 | Object.defineProperty(Constant.prototype, "index", { 47 | get: function() { 48 | switch (this.type) { 49 | case types.Type.I32: 50 | return this.assembly.constantsI32.indexOf(this); 51 | case types.Type.F32: 52 | return this.assembly.constantsF32.indexOf(this); 53 | case types.Type.F64: 54 | return this.assembly.constantsF64.indexOf(this); 55 | default: 56 | throw Error("illegal type: "+this.type); 57 | } 58 | } 59 | }); 60 | 61 | /** 62 | * Returns a string representation of this constant. 63 | * @returns {string} 64 | */ 65 | Constant.prototype.toString = function() { 66 | return "Constant"+types.TypeNames[this.type] 67 | + " value:"+this.value; 68 | }; 69 | -------------------------------------------------------------------------------- /src/reflect/DefaultExport.js: -------------------------------------------------------------------------------- 1 | var BaseExport = require("./BaseExport"), 2 | FunctionDeclaration = require("./FunctionDeclaration"); 3 | 4 | /** 5 | * A default export. 6 | * @constructor 7 | * @param {!Assembly} assembly 8 | * @param {number|!FunctionDeclaration} function_ 9 | * @extends BaseExport 10 | * @exports reflect.DefaultExport 11 | */ 12 | function DefaultExport(assembly, function_) { 13 | BaseExport.call(this, assembly); 14 | 15 | /** 16 | * Exported function. 17 | * @type {!reflect.FunctionDeclaration} 18 | */ 19 | this.function = function_ instanceof FunctionDeclaration 20 | ? function_ 21 | : this.assembly.getFunctionDeclaration(function_); 22 | } 23 | 24 | module.exports = DefaultExport; 25 | 26 | // Extends BaseExport 27 | DefaultExport.prototype = Object.create(BaseExport.prototype); 28 | 29 | /** 30 | * Returns a string representation of this export. 31 | * @returns {string} 32 | */ 33 | DefaultExport.prototype.toString = function() { 34 | return "DefaultExport " + this.function.toString(); 35 | }; 36 | -------------------------------------------------------------------------------- /src/reflect/FunctionDeclaration.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"), 2 | util = require("../util"); 3 | 4 | var FunctionSignature = require("./FunctionSignature"), 5 | BaseOperand = require("../stmt/BaseOperand"); 6 | 7 | /** 8 | * A function declaration. 9 | * @constructor 10 | * @param {!reflect.Assembly} assembly 11 | * @param {number|!reflect.FunctionSignature} signature 12 | * @extends stmt.BaseOperand 13 | * @exports reflect.FunctionDeclaration 14 | */ 15 | function FunctionDeclaration(assembly, signature) { 16 | BaseOperand.call(this); 17 | 18 | /** 19 | * Assembly reference. 20 | * @type {!reflect.Assembly} 21 | */ 22 | this.assembly = assembly; 23 | 24 | /** 25 | * Signature reference. 26 | * @type {!reflect.FunctionSignature} 27 | */ 28 | this.signature = signature instanceof FunctionSignature 29 | ? signature 30 | : assembly.getFunctionSignature(signature); 31 | 32 | /** 33 | * Function definition. 34 | * @type {reflect.FunctionDefinition} 35 | */ 36 | this.definition = null; // Assigned later on 37 | } 38 | 39 | module.exports = FunctionDeclaration; 40 | 41 | // Extends BaseOperand 42 | FunctionDeclaration.prototype = Object.create(BaseOperand.prototype); 43 | 44 | /** 45 | * Function declaration index. 46 | * @name reflect.FunctionDeclaration#index 47 | * @type {number} 48 | */ 49 | Object.defineProperty(FunctionDeclaration.prototype, "index", { 50 | get: function() { 51 | return this.assembly.functionDeclarations.indexOf(this); 52 | } 53 | }); 54 | 55 | /** 56 | * Indexed name. 57 | * @name reflect.FunctionDeclaration#name 58 | * @type {string} 59 | */ 60 | Object.defineProperty(FunctionDeclaration.prototype, "name", { 61 | get: function() { 62 | var func_name_base = this.assembly.functionImports.length + this.assembly.globalVariables.length; 63 | return this.assembly.globalName(func_name_base + this.index, "F"); 64 | } 65 | }); 66 | 67 | /** 68 | * Returns a string representation of this function declaration. 69 | * @returns {string} 70 | */ 71 | FunctionDeclaration.prototype.toString = function() { 72 | return "FunctionDeclaration " + this.name 73 | + " idx:" + this.index 74 | + " sig:" + this.signature.index; 75 | }; 76 | -------------------------------------------------------------------------------- /src/reflect/FunctionDefinition.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"), 2 | util = require("../util"); 3 | 4 | var FunctionSignature = require("./FunctionSignature"), 5 | BaseStmt = require("../stmt/BaseStmt"); 6 | 7 | /** 8 | * A function definition. 9 | * @constructor 10 | * @param {!reflect.FunctionDeclaration} declaration 11 | * @param {number} nI32vars 12 | * @param {number} nF32vars 13 | * @param {number} nF64vars 14 | * @param {number} byteOffset 15 | * @param {number=} byteLength 16 | * @exports reflect.FunctionDefinition 17 | */ 18 | function FunctionDefinition(declaration, nI32vars, nF32vars, nF64vars, byteOffset, byteLength) { 19 | 20 | /** 21 | * Function declaration reference. 22 | * @type {!reflect.FunctionDeclaration} 23 | */ 24 | this.declaration = declaration; 25 | 26 | /** 27 | * Local variables. 28 | * @type {!Array.} 29 | */ 30 | this.variables = new Array(declaration.signature.argumentTypes.length + nI32vars + nF32vars + nF64vars); 31 | var index = 0; 32 | declaration.signature.argumentTypes.forEach(function (type) { 33 | this.variables[index++] = new LocalVariable(this, type); 34 | }, this); 35 | for (var i = 0; i < nI32vars; ++i, ++index) 36 | this.variables[index] = new LocalVariable(this, types.Type.I32); 37 | for (i = 0; i < nF32vars; ++i, ++index) 38 | this.variables[index] = new LocalVariable(this, types.Type.F32); 39 | for (i = 0; i < nF64vars; ++i, ++index) 40 | this.variables[index] = new LocalVariable(this, types.Type.F64); 41 | 42 | /** 43 | * Byte offset of the function body. 44 | * @type {number} 45 | */ 46 | this.byteOffset = byteOffset || -1; 47 | 48 | /** 49 | * Byte length of the function body. 50 | * @type {number} 51 | */ 52 | this.byteLength = byteLength || -1; 53 | 54 | /** 55 | * Abstract syntax tree. 56 | * @type {stmt.StmtList} 57 | */ 58 | this.ast = null; 59 | } 60 | 61 | module.exports = FunctionDefinition; 62 | 63 | var LocalVariable = require("./LocalVariable"); // cyclic 64 | 65 | /** 66 | * Indexed internal function name. 67 | * @name reflect.FunctionDefinition#name 68 | * @type {string} 69 | */ 70 | Object.defineProperty(FunctionDefinition.prototype, "name", { 71 | get: function() { 72 | return this.declaration.name; 73 | } 74 | }); 75 | 76 | /** 77 | * Declaration index. 78 | * @name reflect.FunctionDefinition#index 79 | * @type {number} 80 | */ 81 | Object.defineProperty(FunctionDefinition.prototype, "index", { 82 | get: function() { 83 | return this.declaration.index; 84 | } 85 | }); 86 | 87 | /** 88 | * Returns a string representation of this function definition. 89 | * @returns {string} 90 | */ 91 | FunctionDefinition.prototype.toString = function() { 92 | return "FunctionDefinition " + this.name 93 | + " vars:" + this.variables.length 94 | + " decl:" + this.declaration.index; 95 | }; 96 | 97 | /** 98 | * Gets the variable at the specified index. 99 | * @param {number} index 100 | * @returns {!reflect.LocalVariable} 101 | */ 102 | FunctionDefinition.prototype.getVariable = function(index) { 103 | util.assertInteger("index", index, 0, this.variables.length-1); 104 | return this.variables[index]; 105 | }; 106 | 107 | function replace(ast, oldStmt, newStmt) { 108 | var stack = []; 109 | for (var i=ast.length-1; i>=0; --i) { 110 | stack.push(ast[i]); 111 | if (ast[i] === oldStmt) 112 | ast[i] = newStmt; 113 | } 114 | while (stack.length > 0) { 115 | var current = stack.pop(), k; 116 | for (i=0,k=current.operands.length; i=0; --i) 136 | stack.push(this.ast[i]); 137 | var n = 0; 138 | while (stack.length > 0) { 139 | var stmt = stack.pop(), 140 | behavior = stmt.behavior; 141 | if (typeof behavior.optimize === 'function') { 142 | var code = stmt.code, 143 | optimizedStmt = behavior.optimize(this, stmt); 144 | if (optimizedStmt !== stmt) { 145 | replace(this.ast, stmt, optimizedStmt); 146 | ++n; 147 | } else if (optimizedStmt.code !== code) 148 | ++n; 149 | } 150 | for (i=stmt.operands.length-1; i>=0; --i) { 151 | var operand = stmt.operands[i]; 152 | if (operand instanceof BaseStmt) 153 | stack.push(operand); 154 | } 155 | } 156 | return n; 157 | }; 158 | 159 | /** 160 | * Builds the function header in asm.js. 161 | * @param {bool=} pack 162 | * @returns {string} 163 | */ 164 | FunctionDefinition.prototype.asmHeader = function(pack) { 165 | var indent = pack ? "" : " ", 166 | ws = pack ? "" : " ", 167 | nl = pack ? "" : "\n"; 168 | var sb = []; 169 | sb.push("function ", this.name, "("); 170 | var args = this.declaration.signature.argumentTypes; 171 | var assembly = this.declaration.assembly; 172 | for (var i=0; i 0) 174 | sb.push(","); 175 | sb.push(assembly.localName(i)); 176 | } 177 | sb.push(")", ws, "{\n"); 178 | if (args.length > 0) { 179 | for (i = 0; i < args.length; ++i) { 180 | sb.push(indent, assembly.localName(i), ws, "=", ws); 181 | switch (args[i]) { 182 | case types.Type.I32: 183 | sb.push(assembly.localName(i), "|0;", nl); 184 | break; 185 | case types.Type.F32: 186 | sb.push(util.hotStdLibName(types.HotStdLib.FRound), "(", assembly.localName(i), ");", nl); 187 | break; 188 | case types.Type.F64: 189 | sb.push("+", assembly.localName(i), ";", nl); 190 | break; 191 | } 192 | } 193 | } 194 | if (this.variables.length > args.length) { 195 | sb.push(indent, "var "); 196 | for (i = args.length; i < this.variables.length; ++i) { 197 | var v = this.variables[i]; 198 | if (i > args.length) 199 | sb.push(",", nl, indent); 200 | sb.push(assembly.localName(i + args.length), ws, "=", ws); 201 | switch (v.type) { 202 | case types.Type.I32: 203 | sb.push("0"); 204 | break; 205 | case types.Type.F32: 206 | sb.push(util.hotStdLibName(types.HotStdLib.FRound), "(0)"); 207 | break; 208 | case types.Type.F64: 209 | sb.push("0."); 210 | } 211 | } 212 | sb.push(";"); 213 | } 214 | return sb.join(""); 215 | }; 216 | -------------------------------------------------------------------------------- /src/reflect/FunctionImport.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A function import. 3 | * @constructor 4 | * @param {!reflect.Assembly} assembly 5 | * @param {string} importName 6 | * @param {!Array.} importSignatures 7 | * @exports reflect.FunctionImport 8 | */ 9 | function FunctionImport(assembly, importName, importSignatures) { 10 | 11 | /** 12 | * Assembly reference. 13 | * @type {!reflect.Assembly} 14 | */ 15 | this.assembly = assembly; 16 | 17 | /** 18 | * Import name. 19 | * @type {string} 20 | */ 21 | this.importName = importName; 22 | 23 | /** 24 | * Function import signatures. 25 | * @type {!Array.} 26 | */ 27 | this.signatures = []; 28 | importSignatures.forEach(function(signature) { 29 | this.signatures.push( 30 | signature instanceof FunctionImportSignature 31 | ? signature 32 | : assembly.getFunctionImportSignature(signature) 33 | ); 34 | }, this); 35 | } 36 | 37 | module.exports = FunctionImport; 38 | 39 | var FunctionImportSignature = require("./FunctionImportSignature"); // cyclic 40 | 41 | /** 42 | * Function import index. 43 | * @name reflect.FunctionImport#index 44 | * @type {number} 45 | */ 46 | Object.defineProperty(FunctionImport.prototype, "index", { 47 | get: function() { 48 | return this.assembly.functionImports.indexOf(this); 49 | } 50 | }); 51 | 52 | /** 53 | * Indexed name. 54 | * @name reflect.FunctionImport#name 55 | * @type {number} 56 | */ 57 | Object.defineProperty(FunctionImport.prototype, "name", { 58 | get: function() { 59 | return this.assembly.globalName(this.index); 60 | } 61 | }); 62 | 63 | /** 64 | * Returns a string representation of this import. 65 | * @returns {string} 66 | */ 67 | FunctionImport.prototype.toString = function() { 68 | return "FunctionImport " + "foreign." + this.importName 69 | + " idx:" + this.index 70 | + " sigs:" + this.signatures.length; 71 | }; 72 | -------------------------------------------------------------------------------- /src/reflect/FunctionImportSignature.js: -------------------------------------------------------------------------------- 1 | var FunctionSignature = require("./FunctionSignature"), 2 | BaseOperand = require("../stmt/BaseOperand"); 3 | 4 | /** 5 | * A function import signature. 6 | * @constructor 7 | * @param {!reflect.Assembly} assembly 8 | * @param {number|!reflect.FunctionImport} functionImport 9 | * @param {number|!reflect.FunctionSignature} signature 10 | * @extends stmt.BaseOperand 11 | * @exports reflect.FunctionImportSignature 12 | */ 13 | function FunctionImportSignature(assembly, functionImport, signature) { 14 | 15 | /** 16 | * Assembly reference. 17 | * @type {!reflect.Assembly} 18 | */ 19 | this.assembly = assembly; 20 | 21 | /** 22 | * Function import. 23 | * @type {!reflect.FunctionImport} 24 | */ 25 | this.import = functionImport instanceof FunctionImport 26 | ? functionImport 27 | : assembly.getFunctionImport(functionImport); 28 | 29 | /** 30 | * Function signature. 31 | * @type {!reflect.FunctionSignature} 32 | */ 33 | this.signature = signature instanceof FunctionSignature 34 | ? signature 35 | : assembly.getFunctionSignature(signature); 36 | } 37 | 38 | module.exports = FunctionImportSignature; 39 | 40 | var FunctionImport = require("./FunctionImport"); // cyclic 41 | 42 | // Extends BaseOperand 43 | FunctionImportSignature.prototype = Object.create(BaseOperand.prototype); 44 | 45 | /** 46 | * Function import signature index. 47 | * @name reflect.FunctionImportSignature#index 48 | * @type {number} 49 | */ 50 | Object.defineProperty(FunctionImportSignature.prototype, "index", { 51 | get: function() { 52 | return this.assembly.functionImportSignatures.indexOf(this); 53 | } 54 | }); 55 | 56 | /** 57 | * Returns a string representation of this function import signature. 58 | * @returns {string} 59 | */ 60 | FunctionImportSignature.prototype.toString = function() { 61 | return "FunctionImportSignature " 62 | + " idx:" + this.index 63 | + " sig:" + this.signature.index 64 | + " imp:" + this.import.index; 65 | }; 66 | -------------------------------------------------------------------------------- /src/reflect/FunctionPointerElement.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A function pointer element. 3 | * @constructor 4 | * @param {!reflect.FunctionPointerTable} table 5 | * @param {number} value 6 | * @exports reflect.FunctionPointerElement 7 | */ 8 | function FunctionPointerElement(table, value) { 9 | 10 | /** 11 | * Function pointer table reference. 12 | * @type {!reflect.FunctionPointerTable} 13 | */ 14 | this.table = table; 15 | 16 | /** 17 | * Value. 18 | * @type {number} 19 | */ 20 | this.value = value; 21 | } 22 | 23 | module.exports = FunctionPointerElement; 24 | 25 | /** 26 | * Returns a string representation of this function pointer element. 27 | * @returns {string} 28 | */ 29 | FunctionPointerElement.prototype.toString = function() { 30 | return "FunctionPointerElement" 31 | + " tbl:" + this.table.index 32 | + " val:" + this.value; 33 | }; 34 | -------------------------------------------------------------------------------- /src/reflect/FunctionPointerTable.js: -------------------------------------------------------------------------------- 1 | var util = require("../util"); 2 | 3 | var FunctionSignature = require("./FunctionSignature"), 4 | FunctionPointerElement = require("./FunctionPointerElement"), 5 | BaseOperand = require("../stmt/BaseOperand"); 6 | 7 | /** 8 | * A function pointer table. 9 | * @constructor 10 | * @param {!reflect.Assembly} assembly 11 | * @param {number} index 12 | * @param {number|!reflect.FunctionSignature} signature 13 | * @param {!Array.} elements 14 | * @extends stmt.BaseOperand 15 | * @exports reflect.FunctionPointerTable 16 | */ 17 | function FunctionPointerTable(assembly, signature, elements) { 18 | BaseOperand.call(this); 19 | 20 | /** 21 | * Assembly reference. 22 | * @type {!reflect.Assembly} 23 | */ 24 | this.assembly = assembly; 25 | 26 | /** 27 | * Signature. 28 | * @type {!reflect.FunctionSignature} 29 | */ 30 | this.signature = signature instanceof FunctionSignature 31 | ? signature 32 | : assembly.getFunctionSignature(signature); 33 | 34 | /** 35 | * Elements. 36 | * @type {!Array.} 37 | */ 38 | this.elements = []; 39 | elements.forEach(function(element) { 40 | this.elements.push( 41 | element instanceof FunctionPointerElement 42 | ? element // usually not the case, but for completeness 43 | : new FunctionPointerElement(this, element) 44 | ); 45 | }, this); 46 | } 47 | 48 | module.exports = FunctionPointerTable; 49 | 50 | // Extends BaseOperand 51 | FunctionPointerTable.prototype = Object.create(BaseOperand.prototype); 52 | 53 | /** 54 | * Function pointer table index. 55 | * @name reflect.FunctionPointerTable#index 56 | * @type {number} 57 | */ 58 | Object.defineProperty(FunctionPointerTable.prototype, "index", { 59 | get: function() { 60 | return this.assembly.functionPointerTables.indexOf(this); 61 | } 62 | }); 63 | 64 | /** 65 | * Indexed name. 66 | * @name reflect.FunctionPointerTable#name 67 | * @type {string} 68 | */ 69 | Object.defineProperty(FunctionPointerTable.prototype, "name", { 70 | get: function() { 71 | var func_name_base = this.assembly.functionImports.length + this.assembly.globalVariables.length; 72 | var func_ptr_name_base = func_name_base + this.assembly.functionDeclarations.length; 73 | return this.assembly.globalName(func_ptr_name_base + this.index, "fptr"); 74 | } 75 | }); 76 | 77 | /** 78 | * Returns a string representation of this function pointer table. 79 | * @returns {string} 80 | */ 81 | FunctionPointerTable.prototype.toString = function() { 82 | return "FunctionPointerTable " + this.index.toString() + " " + this.signature.index + " " + this.elements.length; 83 | }; 84 | -------------------------------------------------------------------------------- /src/reflect/FunctionSignature.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"); 2 | 3 | /** 4 | * A function signature. 5 | * @constructor 6 | * @param {!reflect.Assembly} assembly 7 | * @param {number=} returnType 8 | * @param {!Array.=} argumentTypes 9 | * @exports reflect.FunctionSignature 10 | */ 11 | function FunctionSignature(assembly, returnType, argumentTypes) { 12 | 13 | /** 14 | * Assembly reference. 15 | * @type {!reflect.Assembly} 16 | */ 17 | this.assembly = assembly; 18 | 19 | /** 20 | * Return type. 21 | * @type {number} 22 | */ 23 | this.returnType = returnType; 24 | 25 | /** 26 | * Array of argument types. 27 | * @type {!Array.} 28 | */ 29 | this.argumentTypes = argumentTypes || []; 30 | 31 | /** 32 | * Index override used by {@link reflect.Assembly#optimize}. 33 | * @type {number} 34 | * @private 35 | */ 36 | this._indexOverride = -1; // FIXME 37 | } 38 | 39 | module.exports = FunctionSignature; 40 | 41 | /** 42 | * Function signature index. 43 | * @name reflect.FunctionSignature#index 44 | * @type {number} 45 | */ 46 | Object.defineProperty(FunctionSignature.prototype, "index", { 47 | get: function() { 48 | if (this._indexOverride >= 0) 49 | return this._indexOverride; 50 | return this.assembly.functionSignatures.indexOf(this); 51 | } 52 | }); 53 | 54 | /** 55 | * Returns a string representation of this signature. 56 | * @returns {string} 57 | */ 58 | FunctionSignature.prototype.toString = function() { 59 | var sb = []; 60 | sb.push("FunctionSignature idx:", this.index.toString(), " ", types.RTypeNames[this.returnType], "("); 61 | for (var i=0; i0) 63 | sb.push(","); 64 | sb.push(types.TypeNames[this.argumentTypes[i]]); 65 | } 66 | sb.push(")"); 67 | return sb.join(""); 68 | }; 69 | -------------------------------------------------------------------------------- /src/reflect/GlobalVariable.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"), 2 | util = require("../util"); 3 | 4 | var BaseOperand = require("../stmt/BaseOperand"); 5 | 6 | /** 7 | * A global variable. 8 | * @constructor 9 | * @param {!reflect.Assembly} assembly 10 | * @param {number} type 11 | * @param {string=} importName 12 | * @extends stmt.BaseOperand 13 | * @exports reflect.GlobalVariable 14 | */ 15 | function GlobalVariable(assembly, type, importName) { 16 | BaseOperand.call(this); 17 | 18 | /** 19 | * Assembly reference. 20 | * @type {!reflect.Assembly} 21 | */ 22 | this.assembly = assembly; 23 | 24 | /** 25 | * Variable type. 26 | * @type {number} 27 | */ 28 | this.type = type; 29 | 30 | /** 31 | * Import name if not zero. 32 | * @type {?string} 33 | */ 34 | this.importName = importName || null; 35 | } 36 | 37 | module.exports = GlobalVariable; 38 | 39 | // Extends BaseOperand 40 | GlobalVariable.prototype = Object.create(BaseOperand.prototype); 41 | 42 | /** 43 | * Global variable index. 44 | * @name reflect.GlobalVariable#index 45 | * @type {number} 46 | */ 47 | Object.defineProperty(GlobalVariable.prototype, "index", { 48 | get: function() { 49 | return this.assembly.globalVariables.indexOf(this); 50 | } 51 | }); 52 | 53 | /** 54 | * Indexed name. 55 | * @name reflect.GlobalVariable#name 56 | * @type {string} 57 | */ 58 | Object.defineProperty(GlobalVariable.prototype, "name", { 59 | get: function() { 60 | var num_func_imps = this.assembly.functionImports.length; 61 | return this.assembly.globalName(num_func_imps + this.index); 62 | } 63 | }); 64 | 65 | /** 66 | * Returns a string representation of this global variable. 67 | * @returns {string} 68 | */ 69 | GlobalVariable.prototype.toString = function() { 70 | return "GlobalVariable " + this.name 71 | + " idx:" + this.index 72 | + " type:" + types.TypeNames[this.type] 73 | + " val:" + (this.importName === null ? "0" : "foreign."+this.importName); 74 | }; 75 | -------------------------------------------------------------------------------- /src/reflect/LocalVariable.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"), 2 | util = require("../util"); 3 | 4 | var BaseOperand = require("../stmt/BaseOperand"); 5 | 6 | /** 7 | * A local variable. 8 | * @constructor 9 | * @param {number|!reflect.FunctionDefinition} functionDefinition 10 | * @param {number} type 11 | * @extends stmt.BaseOperand 12 | * @exports reflect.LocalVariable 13 | */ 14 | function LocalVariable(functionDefinition, type) { 15 | BaseOperand.call(this); 16 | 17 | /** 18 | * Function definition reference. 19 | * @type {!reflect.FunctionDefinition} 20 | */ 21 | this.functionDefinition = functionDefinition instanceof FunctionDefinition 22 | ? functionDefinition 23 | : this.assembly.getFunctionDefinition(functionDefinition); 24 | 25 | /** 26 | * Variable type. 27 | * @type {number} 28 | */ 29 | this.type = type; 30 | } 31 | 32 | module.exports = LocalVariable; 33 | 34 | var FunctionDefinition = require("./FunctionDefinition"); // cyclic 35 | 36 | // Extends BaseOperand 37 | LocalVariable.prototype = Object.create(BaseOperand.prototype); 38 | 39 | /** 40 | * Local variable index. 41 | * @name reflect.LocalVariable#index 42 | * @type {number} 43 | */ 44 | Object.defineProperty(LocalVariable.prototype, "index", { 45 | get: function() { 46 | return this.functionDefinition.variables.indexOf(this); 47 | } 48 | }); 49 | 50 | /** 51 | * Whether this local variable is a function argument or not. 52 | * @name reflect.LocalVariable#isArgument 53 | * @type {boolean} 54 | */ 55 | Object.defineProperty(LocalVariable.prototype, "isArgument", { 56 | get: function() { 57 | return this.index < this.functionDefinition.declaration.signature.argumentTypes.length; 58 | } 59 | }); 60 | 61 | /** 62 | * Indexed name. 63 | * @name reflect.LocalVariable#name 64 | * @type {string} 65 | */ 66 | Object.defineProperty(LocalVariable.prototype, "name", { 67 | get: function() { 68 | return this.functionDefinition.declaration.assembly.localName(this.index); 69 | } 70 | }); 71 | 72 | /** 73 | * Returns a string representation of this local variable. 74 | * @returns {string} 75 | */ 76 | LocalVariable.prototype.toString = function() { 77 | return "LocalVariable " + this.name 78 | + " idx:" +this.index 79 | + " type:" + types.TypeNames[this.type]; 80 | }; 81 | -------------------------------------------------------------------------------- /src/reflect/RecordExport.js: -------------------------------------------------------------------------------- 1 | var BaseExport = require("./BaseExport"), 2 | FunctionDeclaration = require("./FunctionDeclaration"); 3 | 4 | /** 5 | * A record export. 6 | * @constructor 7 | * @param {!reflect.Assembly} assembly 8 | * @param {!Object.=} functions 9 | * @extends reflect.BaseExport 10 | * @exports reflect.RecordExport 11 | */ 12 | function RecordExport(assembly, functions) { 13 | BaseExport.call(this, assembly); 14 | 15 | /** 16 | * Internal function indexes by exported name. 17 | * @type {!Object.} 18 | */ 19 | this.functions = {}; 20 | Object.keys(functions).forEach(function(name) { 21 | this.functions[name] = functions[name] instanceof FunctionDeclaration 22 | ? functions[name] 23 | : assembly.getFunctionDeclaration(functions[name]); 24 | }, this); 25 | } 26 | 27 | module.exports = RecordExport; 28 | 29 | // Extends BaseExport 30 | RecordExport.prototype = Object.create(BaseExport.prototype); 31 | 32 | /** 33 | * Returns a string representation of this export. 34 | * @returns {string} 35 | */ 36 | RecordExport.prototype.toString = function() { 37 | var sb = []; 38 | sb.push("RecordExport"); 39 | var names = Object.keys(this.functions); 40 | for (var i=0; i|number|!stmt.BaseOperand} operands 8 | * @abstract 9 | * @extends stmt.BaseStmt 10 | * @exports stmt.BaseExpr 11 | */ 12 | function BaseExpr(code, operands) { 13 | BaseStmt.call(this, code, operands); 14 | } 15 | 16 | module.exports = BaseExpr; 17 | 18 | BaseExpr.prototype = Object.create(BaseStmt.prototype); 19 | -------------------------------------------------------------------------------- /src/stmt/BaseOperand.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Base class of all operands but plain numbers. 3 | * @constructor 4 | * @exports stmt.BaseOperand 5 | */ 6 | function BaseOperand() { 7 | } 8 | 9 | module.exports = BaseOperand; 10 | -------------------------------------------------------------------------------- /src/stmt/BaseStmt.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"); 2 | 3 | var BaseOperand = require("./BaseOperand"); 4 | 5 | /** 6 | * Abstract base class of all statements. 7 | * @constructor 8 | * @param {number} code 9 | * @param {!Array.|number|!stmt.BaseOperand} operands 10 | * @abstract 11 | * @extends stmt.BaseOperand 12 | * @exports stmt.BaseStmt 13 | */ 14 | function BaseStmt(code, operands) { 15 | BaseOperand.call(this); 16 | 17 | /** 18 | * Parent statement or list. 19 | * @type {!stmt.BaseStmt|!stmt.StmtList|null} 20 | */ 21 | this.parent = null; 22 | 23 | /** 24 | * Opcode. 25 | * @type {number} 26 | */ 27 | this.code = code; 28 | 29 | /** 30 | * Operands. 31 | * @type {!Array.} 32 | */ 33 | this.operands = Array.isArray(operands) 34 | ? operands.slice() 35 | : typeof operands !== 'undefined' 36 | ? [operands] 37 | : []; 38 | 39 | /** 40 | * Whether this statement's opcode was originally packed with an imm. 41 | * @type {boolean} 42 | * @see {@link ast.Writer#preserveWithImm} 43 | */ 44 | this.withImm = false; 45 | } 46 | 47 | module.exports = BaseStmt; 48 | 49 | /* var ExprI32 = require("./ExprI32"), 50 | ExprF32 = require("./ExprF32"), 51 | ExprF64 = require("./ExprF64"), 52 | ExprVoid = require("./ExprVoid"), 53 | SwitchCase = require("./SwitchCase"), 54 | Stmt = require("./Stmt"); */ 55 | 56 | // Extends BaseOperand 57 | BaseStmt.prototype = Object.create(BaseOperand.prototype); 58 | 59 | /** 60 | * Wire type. 61 | * @name stmt.BaseExpr#type 62 | * @type {number} 63 | * @see {@link types.WireType} 64 | */ 65 | 66 | /** 67 | * Opcode with imm, if any. 68 | * @name stmt.BaseStmt#codeWithImm 69 | * @type {number} -1 if there is no counterpart 70 | */ 71 | 72 | /** 73 | * Behavior. 74 | * @name stmt.BaseStmt#behavior 75 | * @type {!stmt.behavior.BaseBehavior} 76 | */ 77 | 78 | /** 79 | * Gets the literal opcode name. 80 | * @name stmt.BaseStmt#name 81 | * @type {string} 82 | */ 83 | Object.defineProperty(BaseStmt.prototype, "name", { 84 | get: function() { 85 | switch (this.type) { 86 | case types.WireType.Stmt: 87 | return "Stmt:"+types.StmtNames[this.code]; 88 | case types.WireType.ExprI32: 89 | return "I32:"+types.I32Names[this.code]; 90 | case types.WireType.ExprF32: 91 | return "F32:"+types.F32Names[this.code]; 92 | case types.WireType.ExprF64: 93 | return "F64:"+types.F64Names[this.code]; 94 | case types.WireType.ExprVoid: 95 | return "Void:"+types.VoidNames[this.code]; 96 | case types.WireType.SwitchCase: 97 | return "SwitchCase:"+types.SwitchCaseNames[this.code]; 98 | default: 99 | throw Error("illegal statement type: "+this.type); 100 | } 101 | } 102 | }); 103 | 104 | /** 105 | * Adds another operand. 106 | * @param {number|!stmt.BaseOperand} operand 107 | */ 108 | BaseStmt.prototype.add = function(operand) { 109 | if (operand instanceof BaseStmt) 110 | operand.parent = this; 111 | this.operands.push(operand); 112 | }; 113 | 114 | /** 115 | * Returns a string representation of this statement. 116 | * @param {boolean=} shortFormat 117 | * @returns {string} 118 | */ 119 | BaseStmt.prototype.toString = function(shortFormat) { 120 | var sb = []; 121 | sb.push(this.name); 122 | if (shortFormat) 123 | sb.push("+", this.operands.length.toString()); 124 | else 125 | for (var i= 0, operand; i|number|!stmt.BaseOperand)=} operands 10 | * @constructor 11 | * @extends stmt.BaseExpr 12 | * @exports stmt.ExprF32 13 | */ 14 | function ExprF32(code, operands) { 15 | BaseExpr.call(this, code, operands); 16 | } 17 | 18 | module.exports = ExprF32; 19 | 20 | ExprF32.prototype = Object.create(BaseExpr.prototype); 21 | 22 | Object.defineProperty(ExprF32.prototype, "type", { 23 | get: function() { 24 | return types.WireType.ExprF32; 25 | } 26 | }); 27 | 28 | Object.defineProperty(ExprF32.prototype, "codeWithImm", { 29 | get: function() { 30 | return types.codeWithImm(types.RType.F32, this.code); 31 | } 32 | }); 33 | 34 | ExprF32.determineBehavior = function(code, withImm) { 35 | var Op; 36 | if (!withImm) { 37 | Op = types.F32; 38 | switch (code) { 39 | case Op.LitImm: 40 | return behavior.LiteralF32; 41 | case Op.LitPool: 42 | return behavior.ConstantF32; 43 | case Op.GetLoc: 44 | return behavior.GetLocalF32; 45 | case Op.GetGlo: 46 | return behavior.GetGlobalF32; 47 | case Op.SetLoc: 48 | return behavior.SetLocalF32; 49 | case Op.SetGlo: 50 | return behavior.SetGlobalF32; 51 | case Op.Load: 52 | return behavior.LoadF32; 53 | case Op.LoadOff: 54 | return behavior.LoadWithOffsetF32; 55 | case Op.Store: 56 | return behavior.StoreF32; 57 | case Op.StoreOff: 58 | return behavior.StoreWithOffsetF32; 59 | case Op.CallInt: 60 | return behavior.CallInternalF32; 61 | case Op.CallInd: 62 | return behavior.CallIndirectF32; 63 | case Op.Cond: 64 | return behavior.ConditionalF32; 65 | case Op.Comma: 66 | return behavior.CommaF32; 67 | case Op.FromS32: 68 | case Op.FromU32: 69 | return behavior.UnaryI32; 70 | case Op.FromF64: 71 | return behavior.UnaryF64; 72 | case Op.Neg: 73 | case Op.Abs: 74 | case Op.Ceil: 75 | case Op.Floor: 76 | case Op.Sqrt: 77 | return behavior.UnaryF32; 78 | case Op.Add: 79 | case Op.Sub: 80 | case Op.Mul: 81 | case Op.Div: 82 | return behavior.BinaryF32; 83 | default: 84 | throw Error("illegal F32 opcode: " + code); 85 | } 86 | } else { 87 | Op = types.F32WithImm; 88 | switch (code) { 89 | case Op.LitPool: 90 | return behavior.ConstantF32; 91 | case Op.GetLoc: 92 | return behavior.GetLocalF32; 93 | default: 94 | throw Error("illegal F32WithImm opcode: " + code); 95 | } 96 | } 97 | }; 98 | 99 | Object.defineProperty(ExprF32.prototype, "behavior", { 100 | get: function() { 101 | return ExprF32.determineBehavior(this.code); 102 | } 103 | }); 104 | -------------------------------------------------------------------------------- /src/stmt/ExprF64.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"), 2 | BaseExpr = require("./BaseExpr"), 3 | behavior = require("./behavior"); 4 | 5 | /** 6 | * A F64 expression. 7 | * @constructor 8 | * @param {number} code 9 | * @param {(!Array.|number|!stmt.BaseOperand)=} operands 10 | * @constructor 11 | * @extends stmt.BaseExpr 12 | * @exports stmt.ExprF64 13 | */ 14 | function ExprF64(code, operands) { 15 | BaseExpr.call(this, code, operands); 16 | } 17 | 18 | module.exports = ExprF64; 19 | 20 | ExprF64.prototype = Object.create(BaseExpr.prototype); 21 | 22 | Object.defineProperty(ExprF64.prototype, "type", { 23 | get: function() { 24 | return types.WireType.ExprF64; 25 | } 26 | }); 27 | 28 | Object.defineProperty(ExprF64.prototype, "codeWithImm", { 29 | get: function() { 30 | return types.codeWithImm(types.RType.F64, this.code); 31 | } 32 | }); 33 | 34 | ExprF64.determineBehavior = function(code, withImm) { 35 | var Op; 36 | if (!withImm) { 37 | Op = types.F64; 38 | switch (code) { 39 | case Op.LitImm: 40 | return behavior.LiteralF64; 41 | case Op.LitPool: 42 | return behavior.ConstantF64; 43 | case Op.GetLoc: 44 | return behavior.GetLocalF64; 45 | case Op.GetGlo: 46 | return behavior.GetGlobalF64; 47 | case Op.SetLoc: 48 | return behavior.SetLocalF64; 49 | case Op.SetGlo: 50 | return behavior.SetGlobalF64; 51 | case Op.Load: 52 | return behavior.LoadF64; 53 | case Op.LoadOff: 54 | return behavior.LoadWithOffsetF64; 55 | case Op.Store: 56 | return behavior.StoreF64; 57 | case Op.StoreOff: 58 | return behavior.StoreWithOffsetF64; 59 | case Op.CallInt: 60 | return behavior.CallInternalF64; 61 | case Op.CallImp: 62 | return behavior.CallImportF64; 63 | case Op.CallInd: 64 | return behavior.CallIndirectF64; 65 | case Op.Cond: 66 | return behavior.ConditionalF64; 67 | case Op.Comma: 68 | return behavior.CommaF64; 69 | case Op.FromS32: 70 | case Op.FromU32: 71 | return behavior.UnaryI32; 72 | case Op.FromF32: 73 | return behavior.UnaryF32; 74 | case Op.Neg: 75 | case Op.Abs: 76 | case Op.Ceil: 77 | case Op.Floor: 78 | case Op.Sqrt: 79 | case Op.Cos: 80 | case Op.Sin: 81 | case Op.Tan: 82 | case Op.ACos: 83 | case Op.ASin: 84 | case Op.ATan: 85 | case Op.Exp: 86 | case Op.Ln: 87 | return behavior.UnaryF64; 88 | case Op.Add: 89 | case Op.Sub: 90 | case Op.Mul: 91 | case Op.Div: 92 | case Op.Mod: 93 | case Op.ATan2: 94 | case Op.Pow: 95 | return behavior.BinaryF64; 96 | case Op.Min: 97 | case Op.Max: 98 | return behavior.MultiaryF64; 99 | default: 100 | throw Error("illegal F64 opcode: " + code); 101 | } 102 | } else { 103 | Op = types.F64WithImm; 104 | switch (code) { 105 | case Op.LitPool: 106 | return behavior.ConstantF64; 107 | case Op.GetLoc: 108 | return behavior.GetLocalF64; 109 | default: 110 | throw Error("illegal F64WithImm opcode: " + code); 111 | } 112 | } 113 | }; 114 | 115 | Object.defineProperty(ExprF64.prototype, "behavior", { 116 | get: function() { 117 | return ExprF64.determineBehavior(this.code); 118 | } 119 | }); 120 | -------------------------------------------------------------------------------- /src/stmt/ExprI32.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"), 2 | BaseExpr = require("./BaseExpr"), 3 | behavior = require("./behavior"); 4 | 5 | /** 6 | * An I32 expression. 7 | * @constructor 8 | * @param {number} code 9 | * @param {(!Array.|number|!stmt.BaseOperand)=} operands 10 | * @constructor 11 | * @extends stmt.BaseExpr 12 | * @exports stmt.ExprI32 13 | */ 14 | function ExprI32(code, operands) { 15 | BaseExpr.call(this, code, operands); 16 | } 17 | 18 | module.exports = ExprI32; 19 | 20 | ExprI32.prototype = Object.create(BaseExpr.prototype); 21 | 22 | Object.defineProperty(ExprI32.prototype, "type", { 23 | get: function() { 24 | return types.WireType.ExprI32; 25 | } 26 | }); 27 | 28 | Object.defineProperty(ExprI32.prototype, "codeWithImm", { 29 | get: function() { 30 | return types.codeWithImm(types.RType.I32, this.code); 31 | } 32 | }); 33 | 34 | ExprI32.determineBehavior = function(code, withImm) { 35 | var Op; 36 | if (!withImm) { 37 | Op = types.I32; 38 | switch (code) { 39 | case Op.LitImm: 40 | return behavior.LiteralI32; 41 | case Op.LitPool: 42 | return behavior.ConstantI32; 43 | case Op.GetLoc: 44 | return behavior.GetLocalI32; 45 | case Op.GetGlo: 46 | return behavior.GetGlobalI32; 47 | case Op.SetLoc: 48 | return behavior.SetLocalI32; 49 | case Op.SetGlo: 50 | return behavior.SetGlobalI32; 51 | case Op.SLoad8: 52 | case Op.ULoad8: 53 | case Op.SLoad16: 54 | case Op.ULoad16: 55 | case Op.Load32: 56 | return behavior.LoadI; 57 | case Op.SLoadOff8: 58 | case Op.ULoadOff8: 59 | case Op.SLoadOff16: 60 | case Op.ULoadOff16: 61 | case Op.LoadOff32: 62 | return behavior.LoadWithOffsetI; 63 | case Op.Store8: 64 | case Op.Store16: 65 | case Op.Store32: 66 | return behavior.StoreI; 67 | case Op.StoreOff8: 68 | case Op.StoreOff16: 69 | case Op.StoreOff32: 70 | return behavior.StoreWithOffsetI; 71 | case Op.CallInt: 72 | return behavior.CallInternalI32; 73 | case Op.CallImp: 74 | return behavior.CallImportI32; 75 | case Op.CallInd: 76 | return behavior.CallIndirectI32; 77 | case Op.Cond: 78 | return behavior.ConditionalI32; 79 | case Op.Comma: 80 | return behavior.CommaI32; 81 | case Op.FromF32: 82 | return behavior.UnaryF32; 83 | case Op.FromF64: 84 | return behavior.UnaryF64; 85 | case Op.Neg: 86 | case Op.BitNot: 87 | case Op.Clz: 88 | case Op.LogicNot: 89 | case Op.Abs: 90 | return behavior.UnaryI32; 91 | case Op.Add: 92 | case Op.Sub: 93 | case Op.Mul: 94 | case Op.SDiv: 95 | case Op.UDiv: 96 | case Op.SMod: 97 | case Op.UMod: 98 | case Op.BitOr: 99 | case Op.BitAnd: 100 | case Op.BitXor: 101 | case Op.Lsh: 102 | case Op.ArithRsh: 103 | case Op.LogicRsh: 104 | case Op.EqI32: 105 | case Op.NEqI32: 106 | case Op.SLeThI32: 107 | case Op.ULeThI32: 108 | case Op.SLeEqI32: 109 | case Op.ULeEqI32: 110 | case Op.SGrThI32: 111 | case Op.UGrThI32: 112 | case Op.SGrEqI32: 113 | case Op.UGrEqI32: 114 | return behavior.BinaryI32; 115 | case Op.EqF32: 116 | case Op.NEqF32: 117 | case Op.LeThF32: 118 | case Op.LeEqF32: 119 | case Op.GrThF32: 120 | case Op.GrEqF32: 121 | return behavior.BinaryF32; 122 | case Op.EqF64: 123 | case Op.NEqF64: 124 | case Op.LeThF64: 125 | case Op.LeEqF64: 126 | case Op.GrThF64: 127 | case Op.GrEqF64: 128 | return behavior.BinaryF64; 129 | case Op.SMin: 130 | case Op.UMin: 131 | case Op.SMax: 132 | case Op.UMax: 133 | return behavior.MultiaryI32; 134 | default: 135 | throw Error("illegal I32 opcode: " + code); 136 | } 137 | } else { 138 | Op = types.I32WithImm; 139 | switch (code) { 140 | case Op.LitPool: 141 | return behavior.ConstantI32; 142 | case Op.LitImm: 143 | return behavior.LiteralI32; 144 | case Op.GetLoc: 145 | return behavior.GetLocalI32; 146 | default: 147 | throw Error("illegal I32WithImm opcode: " + code); 148 | } 149 | } 150 | }; 151 | 152 | Object.defineProperty(ExprI32.prototype, "behavior", { 153 | get: function() { 154 | return ExprI32.determineBehavior(this.code); 155 | } 156 | }); 157 | -------------------------------------------------------------------------------- /src/stmt/ExprVoid.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"), 2 | BaseExpr = require("./BaseExpr"), 3 | behavior = require("./behavior"); 4 | 5 | /** 6 | * A void expression. 7 | * @constructor 8 | * @param {number} code 9 | * @param {(!Array.|number|!stmt.BaseOperand)=} operands 10 | * @constructor 11 | * @extends stmt.BaseExpr 12 | * @exports stmt.ExprVoid 13 | */ 14 | function ExprVoid(code, operands) { 15 | BaseExpr.call(this, code, operands); 16 | } 17 | 18 | module.exports = ExprVoid; 19 | 20 | ExprVoid.prototype = Object.create(BaseExpr.prototype); 21 | 22 | Object.defineProperty(ExprVoid.prototype, "type", { 23 | get: function() { 24 | return types.WireType.ExprVoid; 25 | } 26 | }); 27 | 28 | Object.defineProperty(ExprVoid.prototype, "codeWithImm", { 29 | get: function() { 30 | return -1; 31 | } 32 | }); 33 | 34 | ExprVoid.determineBehavior = function(code, withImm) { 35 | var Op; 36 | if (!withImm) { 37 | Op = types.Void; 38 | switch (code) { 39 | case Op.CallInt: 40 | return behavior.CallInternalVoid; 41 | case Op.CallImp: 42 | return behavior.CallImportVoid; 43 | case Op.CallInd: 44 | return behavior.CallIndirectVoid; 45 | default: 46 | throw Error("illegal Void opcode: " + code); 47 | } 48 | } else 49 | throw Error("illegal VoidWithImm opcode: " + code); 50 | }; 51 | 52 | Object.defineProperty(ExprVoid.prototype, "behavior", { 53 | get: function() { 54 | return ExprVoid.determineBehavior(this.code); 55 | } 56 | }); 57 | -------------------------------------------------------------------------------- /src/stmt/Stmt.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"), 2 | BaseStmt = require("./BaseStmt"), 3 | behavior = require("./behavior"); 4 | 5 | /** 6 | * A statement. 7 | * @constructor 8 | * @param {number} code 9 | * @param {(number|!BaseStmt|!Array)=} operands 10 | * @constructor 11 | * @extends stmt.BaseStmt 12 | * @exports stmt.Stmt 13 | */ 14 | function Stmt(code, operands) { 15 | BaseStmt.call(this, code, operands); 16 | } 17 | 18 | module.exports = Stmt; 19 | 20 | Stmt.prototype = Object.create(BaseStmt.prototype); 21 | 22 | Object.defineProperty(Stmt.prototype, "type", { 23 | get: function() { 24 | return types.WireType.Stmt; 25 | } 26 | }); 27 | 28 | Object.defineProperty(Stmt.prototype, "codeWithImm", { 29 | get: function() { 30 | switch (this.code) { 31 | case types.Stmt.SetLoc: 32 | return types.StmtWithImm.SetLoc; 33 | case types.Stmt.SetGlo: 34 | return types.StmtWithImm.SetGlo; 35 | default: 36 | return -1; 37 | } 38 | } 39 | }); 40 | 41 | Stmt.determineBehavior = function(code, withImm) { 42 | var Op; 43 | if (!withImm) { 44 | Op = types.Stmt; 45 | switch (code) { 46 | case Op.SetLoc: 47 | return behavior.SetLocal; 48 | case Op.SetGlo: 49 | return behavior.SetGlobal; 50 | case Op.I32Store8: 51 | case Op.I32Store16: 52 | case Op.I32Store32: 53 | return behavior.StoreI; 54 | case Op.I32StoreOff8: 55 | case Op.I32StoreOff16: 56 | case Op.I32StoreOff32: 57 | return behavior.StoreWithOffsetI; 58 | case Op.F32Store: 59 | return behavior.StoreF32; 60 | case Op.F32StoreOff: 61 | return behavior.StoreWithOffsetF32; 62 | case Op.F64Store: 63 | return behavior.StoreF64; 64 | case Op.F64StoreOff: 65 | return behavior.StoreWithOffsetF64; 66 | case Op.CallInt: 67 | return behavior.CallInternal; 68 | case Op.CallImp: 69 | return behavior.CallImport; 70 | case Op.CallInd: 71 | return behavior.CallIndirect; 72 | case Op.Ret: 73 | return behavior.Return; 74 | case Op.Block: 75 | return behavior.Block; 76 | case Op.IfThen: 77 | return behavior.IfThen; 78 | case Op.IfElse: 79 | return behavior.IfElse; 80 | case Op.While: 81 | return behavior.While; 82 | case Op.Do: 83 | return behavior.Do; 84 | case Op.Label: 85 | return behavior.Label; 86 | case Op.Break: 87 | return behavior.Break; 88 | case Op.Continue: 89 | return behavior.Continue; 90 | case Op.BreakLabel: 91 | return behavior.BreakLabel; 92 | case Op.ContinueLabel: 93 | return behavior.ContinueLabel; 94 | case Op.Switch: 95 | return behavior.Switch; 96 | default: 97 | throw Error("illegal Stmt opcode: " + code); 98 | } 99 | } else { 100 | Op = types.StmtWithImm; 101 | switch (code) { 102 | case Op.SetLoc: 103 | return behavior.SetLocal; 104 | case Op.SetGlo: 105 | return behavior.SetGlobal; 106 | default: 107 | throw Error("illegal StmtWithImm opcode: " + code); 108 | 109 | } 110 | } 111 | }; 112 | 113 | Object.defineProperty(Stmt.prototype, "behavior", { 114 | get: function() { 115 | return Stmt.determineBehavior(this.code, false); 116 | } 117 | }); 118 | -------------------------------------------------------------------------------- /src/stmt/StmtList.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"); 2 | 3 | /** 4 | * A list of statements. 5 | * @constructor 6 | * @param {number} size 7 | * @extends Array 8 | * @exports stmt.StmtList 9 | */ 10 | function StmtList(size) { 11 | Array.call(this, size); 12 | if (typeof size !== 'undefined') 13 | this.length = size; 14 | 15 | /** 16 | * Assembly offset. 17 | * @type {number} 18 | */ 19 | this.offset = 0; 20 | } 21 | 22 | module.exports = StmtList; 23 | 24 | // Extends Array 25 | StmtList.prototype = Object.create(Array.prototype); 26 | 27 | /** 28 | * Wire type. 29 | * @name stmt.StmtList#type 30 | * @type {number} 31 | */ 32 | Object.defineProperty(StmtList.prototype, "type", { 33 | get: function() { 34 | return types.WireType.StmtList; 35 | } 36 | }); 37 | 38 | /** 39 | * Adds a statement to the list. 40 | * @param {!stmt.BaseStmt} stmt 41 | */ 42 | StmtList.prototype.add = function(stmt) { 43 | if (this.offset >= this.length) 44 | throw Error("statement list overflow"); 45 | stmt.parent = this; 46 | this[this.offset++] = stmt; 47 | }; 48 | 49 | /** 50 | * Returns a string representation of this statement list. 51 | * @returns {string} 52 | */ 53 | StmtList.prototype.toString = function() { 54 | return "StmtList["+this.length+"]"; 55 | }; 56 | -------------------------------------------------------------------------------- /src/stmt/SwitchCase.js: -------------------------------------------------------------------------------- 1 | var types = require("../types"); 2 | 3 | var BaseStmt = require("./BaseStmt"), 4 | behavior = require("./behavior"); 5 | 6 | /** 7 | * A switch case statement. 8 | * @param {number} code 9 | * @param {(!BaseStmt|!Array)=} operands 10 | * @constructor 11 | * @extends stmt.BaseStmt 12 | * @exports stmt.SwitchCase 13 | */ 14 | function SwitchCase(code, operands) { 15 | BaseStmt.call(this, code, operands); 16 | } 17 | 18 | module.exports = SwitchCase; 19 | 20 | // Extends BaseStmt 21 | SwitchCase.prototype = Object.create(BaseStmt.prototype); 22 | 23 | Object.defineProperty(SwitchCase.prototype, "type", { 24 | get: function() { 25 | return types.WireType.SwitchCase; 26 | } 27 | }); 28 | 29 | Object.defineProperty(SwitchCase.prototype, "codeWithImm", { 30 | get: function() { 31 | return -1; 32 | } 33 | }); 34 | 35 | SwitchCase.determineBehavior = function(code, withImm) { 36 | var Op; 37 | if (!withImm) { 38 | Op = types.SwitchCase; 39 | switch (code) { 40 | case Op.Case0: 41 | return behavior.SwitchCase0; 42 | case Op.Case1: 43 | return behavior.SwitchCase1; 44 | case Op.CaseN: 45 | return behavior.SwitchCaseN; 46 | case Op.Default0: 47 | return behavior.SwitchDefault0; 48 | case Op.Default1: 49 | return behavior.SwitchDefault1; 50 | case Op.DefaultN: 51 | return behavior.SwitchDefaultN; 52 | default: 53 | throw Error("illegal SwitchCase opcode: " + code); 54 | } 55 | } else 56 | throw Error("illegal SwitchCaseWithImm opcode: " + code); 57 | }; 58 | 59 | Object.defineProperty(SwitchCase.prototype, "behavior", { 60 | get: function() { 61 | return SwitchCase.determineBehavior(this.code); 62 | } 63 | }); 64 | -------------------------------------------------------------------------------- /src/stmt/behavior/BaseBehavior.js: -------------------------------------------------------------------------------- 1 | var types = require("../../types"); 2 | 3 | /** 4 | * Abstract base class of all behaviors. 5 | * @constructor 6 | * @param {string} name 7 | * @param {string} description 8 | * @abstract 9 | * @exports stmt.behavior.BaseBehavior 10 | */ 11 | function BaseBehavior(name, description) { 12 | 13 | /** 14 | * Textual name. 15 | * @type {string} 16 | */ 17 | this.name = name; 18 | 19 | /** 20 | * Textual description. 21 | * @type {string} 22 | */ 23 | this.description = description; 24 | } 25 | 26 | module.exports = BaseBehavior; 27 | 28 | /** 29 | * A function capable of reading a statement with this behaviour. 30 | * @param {!ast.ReadState} s 31 | * @param {number} code 32 | * @param {number|null} imm 33 | */ 34 | BaseBehavior.prototype.read = function(s, code, imm) { 35 | throw Error("not implemented"); 36 | }; 37 | 38 | /** 39 | * A function capable of validating a statement with this behavior. 40 | * @param {!reflect.FunctionDefinition} definition 41 | * @param {!stmt.BaseStmt} stmt 42 | */ 43 | BaseBehavior.prototype.validate = function(definition, stmt) { 44 | throw Error("not implemented"); 45 | }; 46 | 47 | /** 48 | * A function capable of writing a statement with this behavior. 49 | * @param {!ast.WriteState} s 50 | * @param {!stmt.BaseStmt} stmt 51 | */ 52 | BaseBehavior.prototype.write = function(s, stmt) { 53 | throw Error("not implemented"); 54 | }; 55 | 56 | /** 57 | * An optional function capable of optimizing a statement with this behavior. 58 | * @type {function(!reflect.FunctionDefinition, !stmt.BaseStmt)|undefined} 59 | */ 60 | BaseBehavior.prototype.optimize; 61 | -------------------------------------------------------------------------------- /src/stmt/behavior/BinaryBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | BaseExpr = require("../BaseExpr"); 6 | 7 | /** 8 | * Binary behavior. 9 | * @param {string} name 10 | * @param {string} description 11 | * @param {number} type 12 | * @constructor 13 | * @extends stmt.behavior.BaseBehavior 14 | * @exports stmt.behavior.BinaryBehavior 15 | */ 16 | function BinaryBehavior(name, description, type) { 17 | BaseBehavior.call(this, name, description); 18 | 19 | /** 20 | * Wire type. 21 | * @type {number} 22 | */ 23 | this.type = type; 24 | } 25 | 26 | module.exports = BinaryBehavior; 27 | 28 | BinaryBehavior.prototype = Object.create(BaseBehavior.prototype); 29 | 30 | // opcode + Expr<*> left + Expr<*> right 31 | // Expr<*>, all without imm 32 | 33 | BinaryBehavior.prototype.read = function(s, code) { 34 | s.stmt(code); 35 | s.read(this.type); 36 | s.read(this.type); 37 | }; 38 | 39 | BinaryBehavior.prototype.validate = function(definition, stmt) { 40 | assert.strictEqual(stmt.operands.length, 2, this.name+" requires exactly 2 operands"); 41 | for (var i=0; i<2; ++i){ 42 | assert(stmt.operands[i] instanceof BaseExpr, this.name+" operand "+i+ " must be an expression"); 43 | assert.strictEqual(stmt.operands[i].type, this.type, this.name+" operand "+i+" expression must be "+types.RTypeNames[this.type]); 44 | } 45 | }; 46 | 47 | BinaryBehavior.prototype.write = function(s, stmt) { 48 | s.code(stmt.code); 49 | s.write(stmt.operands[0]); 50 | s.write(stmt.operands[1]); 51 | }; 52 | -------------------------------------------------------------------------------- /src/stmt/behavior/BlockBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | Stmt = require("../Stmt"); 6 | 7 | /** 8 | * Block behavior. 9 | * @param {string} name 10 | * @param {string} description 11 | * @constructor 12 | * @extends stmt.behavior.BaseBehavior 13 | * @exports stmt.behavior.BlockBehavior 14 | */ 15 | function BlockBehavior(name, description) { 16 | BaseBehavior.call(this, name, description); 17 | } 18 | 19 | module.exports = BlockBehavior; 20 | 21 | // Extends Behavior 22 | BlockBehavior.prototype = Object.create(BaseBehavior.prototype); 23 | 24 | // opcode + varint count + count * Stmt 25 | // Stmt only, without imm 26 | 27 | BlockBehavior.prototype.read = function(s, code) { 28 | var count = s.varint(); 29 | s.stmt(code); 30 | for (var i=0; i} types 13 | * @constructor 14 | * @extends stmt.behavior.BaseBehavior 15 | * @exports stmt.behavior.BranchBehavior 16 | */ 17 | function BranchBehavior(name, description, types) { 18 | BaseBehavior.call(this, name, description); 19 | 20 | /** 21 | * Wire types. 22 | * @type {!Array.} 23 | */ 24 | this.types = types; 25 | } 26 | 27 | module.exports = BranchBehavior; 28 | 29 | BranchBehavior.prototype = Object.create(BaseBehavior.prototype); 30 | 31 | // opcode + Expr value [...] 32 | // Expr<*>, all without imm 33 | 34 | BranchBehavior.prototype.read = function(s, code) { 35 | s.stmt(code); 36 | this.types.forEach(function(type) { 37 | s.read(type); 38 | }, this); 39 | }; 40 | 41 | BranchBehavior.prototype.validate = function(definition, stmt) { 42 | assert.strictEqual(stmt.operands.length, this.types.length, "Branch requires exactly "+this.types.length+" operands"); 43 | this.types.forEach(function(type, i) { 44 | if (type === null) 45 | assert(stmt.operands[i] instanceof Stmt, "Branch operand "+i+" must be a statement"); 46 | else { 47 | assert(stmt.operands[i] instanceof BaseExpr, "Branch operand "+i+ " must be an expression"); 48 | assert.strictEqual(stmt.operands[i].type, type, "Branch operand "+i+" expression must be "+types.RTypeNames[type]); 49 | } 50 | }, this); 51 | }; 52 | 53 | BranchBehavior.prototype.write = function(s, stmt) { 54 | s.code(stmt.code); 55 | stmt.operands.forEach(function(operand) { 56 | s.write(operand); 57 | }); 58 | }; 59 | -------------------------------------------------------------------------------- /src/stmt/behavior/CallImportBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | BaseExpr = require("../BaseExpr"), 6 | FunctionImportSignature = require("../../reflect/FunctionImportSignature"); 7 | 8 | /** 9 | * CallImport behavior. 10 | * @param {string} name 11 | * @param {string} description 12 | * @param {number} returnType 13 | * @constructor 14 | * @extends stmt.behavior.BaseBehavior 15 | * @exports stmt.behavior.CallImportBehavior 16 | */ 17 | function CallImportBehavior(name, description, returnType) { 18 | BaseBehavior.call(this, name, description); 19 | 20 | /** 21 | * Return type, if any. 22 | * @type {number} 23 | */ 24 | this.returnType = returnType; 25 | } 26 | 27 | module.exports = CallImportBehavior; 28 | 29 | // Extends Behavior 30 | CallImportBehavior.prototype = Object.create(BaseBehavior.prototype); 31 | 32 | // opcode + import function index + argument list as Expr 33 | // Stmt & Expr<*>, all without imm 34 | 35 | CallImportBehavior.prototype.read = function(s, code) { 36 | var functionImportSignature = s.import(s.varint()); 37 | s.stmt(code, [ functionImportSignature ]); 38 | functionImportSignature.signature.argumentTypes.forEach(function(type) { 39 | s.read(type); 40 | }, this); 41 | }; 42 | 43 | CallImportBehavior.prototype.validate = function(definition, stmt) { 44 | assert(stmt.operands.length >= 1, this.name+" requires at least 1 operand"); 45 | var func = stmt.operands[0]; 46 | assert(func instanceof FunctionImportSignature, this.name+" function (operand 0) must be a FunctionImportSignature"); 47 | assert.strictEqual(func.assembly, definition.declaration.assembly, this.name+" function (operand 0) must be part of this assembly"); 48 | assert.strictEqual(func.signature.returnType, this.returnType, this.name+" function (operand 0) return type must be "+types.RTypeNames[this.returnType]); 49 | assert.strictEqual(stmt.operands.length, 1+func.signature.argumentTypes.length, this.name+" requires exactly "+(1+func.signature.argumentTypes.length)+" operands"); 50 | func.signature.argumentTypes.forEach(function(type, i) { 51 | var expr = stmt.operands[1+i]; 52 | assert(expr instanceof BaseExpr, this.name+" argument "+i+" (operand "+(1+i)+") must be an expression"); 53 | assert.strictEqual(expr.type, type, this.name+" argument "+i+" (operand "+(1+i)+") expression must be "+types.RTypeNames[type]); 54 | }, this); 55 | }; 56 | 57 | CallImportBehavior.prototype.write = function(s, stmt) { 58 | s.code(stmt.code); 59 | s.varint(stmt.operands[0].index); 60 | for (var i=1; i element index + argument list as Expr 33 | // Stmt & Expr<*>, all without imm 34 | 35 | CallIndirectBehavior.prototype.read = function(s, code) { 36 | var functionPointerTable = s.indirect(s.varint()); 37 | s.stmt(code, [ functionPointerTable ]); 38 | s.read(types.WireType.ExprI32); 39 | functionPointerTable.signature.argumentTypes.forEach(function(type) { 40 | s.read(type); 41 | }, this); 42 | }; 43 | 44 | CallIndirectBehavior.prototype.validate = function(definition, stmt) { 45 | assert(stmt.operands.length >= 2, this.name+" requires at least 2 operands"); 46 | var func = stmt.operands[0]; 47 | assert(func instanceof FunctionPointerTable, this.name+" function (operand 0) must be a FunctionPointerTable"); 48 | assert.strictEqual(func.assembly, definition.declaration.assembly, this.name+" function (operand 0) must be part of this assembly"); 49 | assert.strictEqual(func.signature.returnType, this.returnType, this.name+" function (operand 0) return type must be "+types.RTypeNames[this.returnType]); 50 | assert.strictEqual(stmt.operands.length, 2+func.signature.argumentTypes.length, this.name+" requires exactly "+(2+func.signature.argumentTypes.length)+" operands"); 51 | var expr = stmt.operands[1]; 52 | assert(expr instanceof BaseExpr, this.name+" element index (operand 1) must be an expression"); 53 | assert.strictEqual(expr.type, types.RType.I32, this.name+" element index (operand 1) expression must be "+types.RTypeNames[types.RType.I32]); 54 | func.signature.argumentTypes.forEach(function(type, i) { 55 | var expr = stmt.operands[2+i]; 56 | assert(expr instanceof BaseExpr, this.name+" argument "+i+" (operand "+(2+i)+") must be an expression"); 57 | assert.strictEqual(expr.type, type, this.name+" argument "+i+" (operand "+(2+i)+") expression must be "+types.RTypeNames[type]); 58 | }, this); 59 | }; 60 | 61 | CallIndirectBehavior.prototype.write = function(s, stmt) { 62 | s.u8(stmt.code); 63 | s.varint(stmt.operands[0].index); 64 | s.write(stmt.operands[1]); 65 | for (var i=2; i 33 | // Stmt & Expr<*>, all without imm 34 | 35 | CallInternalBehavior.prototype.read = function(s, code) { 36 | var functionDeclaration = s.internal(s.varint()); 37 | s.stmt(code, [ functionDeclaration ]); 38 | functionDeclaration.signature.argumentTypes.forEach(function(type) { 39 | s.read(type); 40 | }, this); 41 | }; 42 | 43 | CallInternalBehavior.prototype.validate = function(definition, stmt) { 44 | assert(stmt.operands.length >= 1, this.name+" requires at least 1 operand"); 45 | var func = stmt.operands[0]; 46 | assert(func instanceof FunctionDeclaration, this.name+" function (operand 0) must be a FunctionDeclaration"); 47 | assert.strictEqual(func.assembly, definition.declaration.assembly, this.name+" function (operand 0) must be part of this assembly"); 48 | assert.strictEqual(func.declaration.signature.returnType, this.returnType, this.name+" function (operand 0) return type must be "+types.RTypeNames[this.returnType]); 49 | assert.strictEqual(stmt.operands.length, 1+func.signature.argumentTypes.length, this.name+" requires exactly "+(1+func.signature.argumentTypes.length)+" operands"); 50 | func.signature.argumentTypes.forEach(function(type, i) { 51 | var expr = stmt.operands[1+i]; 52 | assert(expr instanceof BaseExpr, this.name+" argument "+i+" (operand "+(1+i)+") must be an expression"); 53 | assert.strictEqual(expr.type, type, this.name+" argument "+i+" (operand "+(1+i)+") expression must be "+types.RTypeNames[type]); 54 | }, this); 55 | }; 56 | 57 | CallInternalBehavior.prototype.write = function(s, stmt) { 58 | s.code(stmt.code); 59 | s.varint(stmt.operands[0].index); 60 | for (var i=1; i left + Expr<*> right 32 | // Expr<*>, all without imm 33 | 34 | CommaBehavior.prototype.read = function(s, code) { 35 | var rtype = s.u8(); 36 | s.stmt(code); 37 | switch (rtype) { 38 | case types.RType.I32: 39 | case types.RType.F32: 40 | case types.RType.F64: 41 | case types.RType.Void: 42 | s.read(rtype); 43 | break; 44 | default: 45 | throw Error("illegal left hand return type: "+rtype); 46 | } 47 | s.read(this.returnType); 48 | }; 49 | 50 | CommaBehavior.prototype.validate = function(definition, stmt) { 51 | assert.strictEqual(stmt.operands.length, 2, this.name+" requires exactly 2 operands"); 52 | assert(stmt.operands[0] instanceof BaseExpr, this.name+" left (operand 0) must be an expression"); 53 | var right = stmt.operands[1]; 54 | assert(right instanceof BaseExpr, this.name+" right (operand 1) must be an expression"); 55 | assert.strictEqual(right.type, this.returnType, this.name+" right (operand 1) expression must be "+types.RTypeNames[this.returnType]); 56 | }; 57 | 58 | CommaBehavior.prototype.write = function(s, stmt) { 59 | s.code(stmt.code); 60 | s.u8(stmt.operands[0].type); 61 | s.write(stmt.operands[0]); 62 | s.write(stmt.operands[1]); 63 | }; 64 | -------------------------------------------------------------------------------- /src/stmt/behavior/ConstantPoolBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | Constant = require("../../reflect/Constant"); 6 | 7 | /** 8 | * ConstantPool behavior. 9 | * @param {string} name 10 | * @param {string} description 11 | * @param {number} type 12 | * @constructor 13 | * @extends stmt.behavior.BaseBehavior 14 | * @exports stmt.behavior.ConstantPoolBehavior 15 | */ 16 | function ConstantPoolBehavior(name, description, type) { 17 | BaseBehavior.call(this, name, description); 18 | 19 | /** 20 | * Constant type. 21 | * @type {number} 22 | */ 23 | this.type = type; 24 | } 25 | 26 | module.exports = ConstantPoolBehavior; 27 | 28 | // Extends Behavior 29 | ConstantPoolBehavior.prototype = Object.create(BaseBehavior.prototype); 30 | 31 | // opcode + constant index 32 | // Expr<*>, all with imm 33 | 34 | ConstantPoolBehavior.prototype.read = function(s, code, imm) { 35 | if (imm !== null) 36 | s.stmtWithoutImm(code, [ s.constant(imm) ]); 37 | else 38 | s.stmt(code, [ s.constant(s.varint()) ]); 39 | }; 40 | 41 | ConstantPoolBehavior.prototype.validate = function(definition, stmt) { 42 | assert.strictEqual(stmt.operands.length, 1, this.name+" requires exactly 1 operand"); 43 | var constant = stmt.operands[0]; 44 | assert(constant instanceof Constant, this+" constant (operand 0) must be a Constant"); 45 | assert.strictEqual(constant.assembly, definition.declaration.assembly, this.name+" constant (operand 0) must be part of this assembly"); 46 | assert.strictEqual(constant.type, this.type, this.name+" constant (operand 0) type must be "+types.RTypeNames[this.type]); 47 | }; 48 | 49 | ConstantPoolBehavior.prototype.write = function(s, stmt) { 50 | var index = stmt.operands[0].index; 51 | if (!s.codeWithImm(stmt.code, index)) { 52 | s.code(stmt.code); 53 | s.varint(index); 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /src/stmt/behavior/GetGlobalBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | GlobalVariable = require("../../reflect/GlobalVariable"); 6 | 7 | /** 8 | * GetGlobal behavior. 9 | * @param {string} name 10 | * @param {string} description 11 | * @param {number} type 12 | * @constructor 13 | * @extends stmt.behavior.BaseBehavior 14 | * @exports stmt.behavior.GetGlobalBehavior 15 | */ 16 | function GetGlobalBehavior(name, description, type) { 17 | BaseBehavior.call(this, name, description); 18 | 19 | /** 20 | * Global variable type. 21 | * @type {number} 22 | */ 23 | this.type = type; 24 | } 25 | 26 | module.exports = GetGlobalBehavior; 27 | 28 | // Extends Behavior 29 | GetGlobalBehavior.prototype = Object.create(BaseBehavior.prototype); 30 | 31 | // opcode + global variable index 32 | // Expr<*>, all without imm 33 | 34 | GetGlobalBehavior.prototype.read = function(s, code) { 35 | s.stmt(code, [ s.global(s.varint(), this.type) ]); 36 | }; 37 | 38 | GetGlobalBehavior.prototype.validate = function(definition, stmt) { 39 | assert.strictEqual(stmt.operands.length, 1, "GetGlobal requires exactly 1 operand"); 40 | var variable = stmt.operands[0]; 41 | assert(variable instanceof GlobalVariable, "GetGlobal variable (operand 0) must be a GlobalVariable"); 42 | assert.strictEqual(variable.definition.declaration.assembly, definition.definition.declaration.assembly, "GetGlobal variable (operand 0) must be part of this assembly"); 43 | assert.strictEqual(variable.type, this.type, "GetGlobal variable (operand 0) type must be "+types.RTypeNames[this.type]); 44 | }; 45 | 46 | GetGlobalBehavior.prototype.write = function(s, stmt) { 47 | s.code(stmt.code); 48 | s.varint(stmt.operands[0].index); 49 | }; 50 | -------------------------------------------------------------------------------- /src/stmt/behavior/GetLocalBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | LocalVariable = require("../../reflect/LocalVariable"); 6 | 7 | /** 8 | * GetLocal behavior. 9 | * @param {string} name 10 | * @param {string} description 11 | * @param {number} type 12 | * @constructor 13 | * @extends stmt.behavior.BaseBehavior 14 | * @exports stmt.behavior.GetLocalBehavior 15 | */ 16 | function GetLocalBehavior(name, description, type) { 17 | BaseBehavior.call(this, name, description); 18 | 19 | /** 20 | * Local variable type. 21 | * @type {number} 22 | */ 23 | this.type = type; 24 | } 25 | 26 | module.exports = GetLocalBehavior; 27 | 28 | // Extends Behavior 29 | GetLocalBehavior.prototype = Object.create(BaseBehavior.prototype); 30 | 31 | // opcode + local variable index 32 | // Expr<*>, all with imm 33 | 34 | GetLocalBehavior.prototype.read = function(s, code, imm) { 35 | if (imm !== null) 36 | s.stmtWithoutImm(code, [ s.local(imm, this.type) ]); 37 | else 38 | s.stmt(code, [ s.local(s.varint(), this.type) ]); 39 | }; 40 | 41 | GetLocalBehavior.prototype.validate = function(definition, stmt) { 42 | assert.strictEqual(stmt.operands.length, 1, "GetLocal requires exactly 1 operand"); 43 | var variable = stmt.operands[0]; 44 | assert(variable instanceof LocalVariable, "GetLocal variable (operand 0) must be a LocalVariable"); 45 | assert.strictEqual(variable.definition, definition, "GetLocal variable (operand 0) must be part of this definition"); 46 | assert.strictEqual(variable.type, this.type, "GetLocal variable (operand 0) type must be "+types.WireTypeNames[this.type]); 47 | }; 48 | 49 | GetLocalBehavior.prototype.write = function(s, stmt) { 50 | var index = stmt.operands[0].index; 51 | if (!s.codeWithImm(stmt.code, index)) { 52 | s.code(stmt.code); 53 | s.varint(index); 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /src/stmt/behavior/LabelBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | 3 | var BaseBehavior = require("./BaseBehavior"); 4 | 5 | /** 6 | * Label behavior. 7 | * @param {string} name 8 | * @param {string} description 9 | * @constructor 10 | * @extends stmt.behavior.BaseBehavior 11 | * @exports stmt.behavior.LabelBehavior 12 | */ 13 | function LabelBehavior(name, description) { 14 | BaseBehavior.call(this, name, description); 15 | } 16 | 17 | module.exports = LabelBehavior; 18 | 19 | // Extends Behavior 20 | LabelBehavior.prototype = Object.create(BaseBehavior.prototype); 21 | 22 | // opcode + label index 23 | // Stmt only, without imm 24 | 25 | LabelBehavior.prototype.read = function(s, code, imm) { 26 | s.stmt(code, [ s.varint() ]); 27 | }; 28 | 29 | LabelBehavior.prototype.validate = function(definition, stmt) { 30 | assert.strictEqual(stmt.operands.length, 1, "Label requires exactly 1 operands"); 31 | var label = stmt.operands[0]; 32 | assert(typeof label === 'number' && label%1 === 0 && label >= 0, "Label index (operand 0) must be a non-negative integer"); 33 | }; 34 | 35 | LabelBehavior.prototype.write = function(s, stmt) { 36 | s.code(stmt.code); 37 | s.varint(stmt.operands[0]); 38 | }; 39 | -------------------------------------------------------------------------------- /src/stmt/behavior/LiteralBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"); 5 | 6 | /** 7 | * Literal behavior. 8 | * @param {string} name 9 | * @param {string} description 10 | * @param {number} type 11 | * @constructor 12 | * @extends stmt.behavior.BaseBehavior 13 | * @exports stmt.behavior.LiteralBehavior 14 | */ 15 | function LiteralBehavior(name, description, type) { 16 | BaseBehavior.call(this, name, description); 17 | 18 | /** 19 | * Literal type. 20 | * @type {number} 21 | */ 22 | this.type = type; 23 | } 24 | 25 | module.exports = LiteralBehavior; 26 | 27 | // Extends Behavior 28 | LiteralBehavior.prototype = Object.create(BaseBehavior.prototype); 29 | 30 | // opcode + literal 31 | // Expr<*>, Expr with imm 32 | 33 | LiteralBehavior.prototype.read = function(s, code, imm) { 34 | if (this.type === types.Type.I32) { 35 | if (imm !== null) 36 | s.stmtWithoutImm(code, [ imm ]); 37 | else 38 | s.stmt(code, [ s.varint() ]); 39 | } else { 40 | var value; 41 | switch (this.type) { 42 | case types.Type.F32: 43 | value = s.f32(); 44 | break; 45 | case types.Type.F64: 46 | value = s.f64(); 47 | break; 48 | default: 49 | throw Error("unreachable"); 50 | } 51 | s.stmt(code, [ value ]); 52 | } 53 | }; 54 | 55 | LiteralBehavior.prototype.validate = function(definition, stmt) { 56 | assert.strictEqual(stmt.operands.length, 1, this.name+" requires exactly 1 operand"); 57 | var value = stmt.operands[0]; 58 | if (this.type === types.Type.I32) 59 | assert(typeof value === 'number' && value%1 === 0 && value >= 0, this.name+" value (operand 0) must be a non-negative integer"); 60 | else 61 | assert(typeof value === 'number', this.name+" value (operand 0) must be a number"); 62 | }; 63 | 64 | LiteralBehavior.prototype.write = function(s, stmt) { 65 | var value = stmt.operands[0]; 66 | if (this.type === types.Type.I32) { 67 | if (!s.codeWithImm(stmt.code, value)) { 68 | s.code(stmt.code); 69 | s.varint(value); 70 | } 71 | } else { 72 | s.code(stmt.code); 73 | switch (this.type) { 74 | case types.Type.F32: 75 | s.f32(value); 76 | break; 77 | case types.Type.F64: 78 | s.f64(value); 79 | break; 80 | default: 81 | throw Error("unreachable"); 82 | } 83 | } 84 | }; 85 | -------------------------------------------------------------------------------- /src/stmt/behavior/LoadBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | ExprI32 = require("../ExprI32"); 6 | 7 | /** 8 | * Load behavior. 9 | * @param {string} name 10 | * @param {string} description 11 | * @param {number} heapType 12 | * @constructor 13 | * @extends stmt.behavior.BaseBehavior 14 | * @exports stmt.behavior.LoadBehavior 15 | */ 16 | function LoadBehavior(name, description, heapType) { 17 | BaseBehavior.call(this, name, description); 18 | 19 | /** 20 | * Heap type. 21 | * @type {number} 22 | */ 23 | this.heapType = heapType; 24 | } 25 | 26 | module.exports = LoadBehavior; 27 | 28 | // Extends Behavior 29 | LoadBehavior.prototype = Object.create(BaseBehavior.prototype); 30 | 31 | // opcode + Expr heap index 32 | // Expr<*>, all without imm 33 | 34 | LoadBehavior.prototype.read = function(s, code) { 35 | s.stmt(code); 36 | s.read(types.WireType.ExprI32); 37 | }; 38 | 39 | LoadBehavior.prototype.validate = function(definition, stmt) { 40 | assert.strictEqual(stmt.operands.length, 1, "Load requires exactly 1 operand"); 41 | var index = stmt.operands[0]; 42 | assert(index instanceof ExprI32, "Load heap index (operand 0) must be an I32 expression"); 43 | }; 44 | 45 | LoadBehavior.prototype.write = function(s, stmt) { 46 | s.code(stmt.code); 47 | s.write(stmt.operands[0]); 48 | }; 49 | -------------------------------------------------------------------------------- /src/stmt/behavior/LoadWithOffsetBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | ExprI32 = require("../ExprI32"); 6 | 7 | /** 8 | * LoadWithOffset behavior. 9 | * @param {string} name 10 | * @param {string} description 11 | * @param {number} heapType 12 | * @constructor 13 | * @extends stmt.behavior.BaseBehavior 14 | * @exports stmt.behavior.LoadWithOffsetBehavior 15 | */ 16 | function LoadWithOffsetBehavior(name, description, heapType) { 17 | BaseBehavior.call(this, name, description); 18 | 19 | /** 20 | * Heap type. 21 | * @type {number} 22 | */ 23 | this.heapType = heapType; 24 | } 25 | 26 | module.exports = LoadWithOffsetBehavior; 27 | 28 | // Extends Behavior 29 | LoadWithOffsetBehavior.prototype = Object.create(BaseBehavior.prototype); 30 | 31 | // opcode + varint offset + Expr heap index 32 | // Expr<*>, all without imm 33 | 34 | LoadWithOffsetBehavior.prototype.read = function(s, code) { 35 | s.stmt(code, [ s.varint() ]); 36 | s.read(types.WireType.ExprI32); 37 | }; 38 | 39 | LoadWithOffsetBehavior.prototype.validate = function(definition, stmt) { 40 | assert.strictEqual(stmt.operands.length, 2, "LoadWithOffset requires exactly 2 operands"); 41 | var offset = stmt.operands[0]; 42 | assert(typeof offset === 'number' && offset%1 === 0 && offset >= 0, "LoadWithOffset offset (operand 0) must be a non-negative integer"); 43 | var index = stmt.operands[1]; 44 | assert(index instanceof ExprI32, "LoadWithOffset heap index (operand 1) must be an I32 expression"); 45 | }; 46 | 47 | LoadWithOffsetBehavior.prototype.write = function(s, stmt) { 48 | s.code(stmt.code); 49 | s.varint(stmt.operands[0]); 50 | s.write(stmt.operands[1]); 51 | }; 52 | -------------------------------------------------------------------------------- /src/stmt/behavior/MultiaryBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | BaseExpr = require("../BaseExpr"); 6 | 7 | /** 8 | * Multiary behavior. 9 | * @param {string} name 10 | * @param {string} description 11 | * @param {number} type 12 | * @constructor 13 | * @extends stmt.behavior.BaseBehavior 14 | * @exports stmt.behavior.MultiaryBehavior 15 | */ 16 | function MultiaryBehavior(name, description, type) { 17 | BaseBehavior.call(this, name, description); 18 | 19 | /** 20 | * Expression type. 21 | * @type {number} 22 | */ 23 | this.type = type; 24 | } 25 | 26 | module.exports = MultiaryBehavior; 27 | 28 | MultiaryBehavior.prototype = Object.create(BaseBehavior.prototype); 29 | 30 | // opcode + varint count + count * Expr<*> argument 31 | // Expr<*>, all without imm 32 | 33 | MultiaryBehavior.prototype.read = function(s, code) { 34 | var count = s.varint(); 35 | s.stmt(code); 36 | for (var i=0; i if function return type is not void ] 25 | // Stmt only, without imm 26 | 27 | ReturnBehavior.prototype.read = function(s, code, imm) { 28 | var rtype = s.rtype(); 29 | s.stmt(code); 30 | if (rtype !== types.RType.Void) 31 | s.read(rtype); 32 | }; 33 | 34 | ReturnBehavior.prototype.validate = function(definition, stmt) { 35 | var rtype = definition.declaration.signature.returnType; 36 | if (rtype === types.RType.Void) 37 | assert.strictEqual(stmt.operands.length, 0, this.name+" requires exactly 0 operands"); 38 | else { 39 | assert.strictEqual(stmt.operands.length, 1, this.name+" requires exactly 1 operand"); 40 | var expr = stmt.operands[0]; 41 | assert(expr instanceof BaseExpr, this.name+" return value (operand 0) must be an expression"); 42 | assert.strictEqual(expr.type, rtype, this.name+" return value (operand 0) expression must be "+types.RTypeNames[rtype]); 43 | } 44 | }; 45 | 46 | ReturnBehavior.prototype.write = function(s, stmt) { 47 | s.code(stmt.code); 48 | if (stmt.operands.length !== 0) 49 | s.write(stmt.operands[0]); 50 | }; 51 | -------------------------------------------------------------------------------- /src/stmt/behavior/SetGlobalBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"), 3 | util = require("../../util"); 4 | 5 | var BaseBehavior = require("./BaseBehavior"), 6 | GlobalVariable = require("../../reflect/GlobalVariable"), 7 | BaseExpr = require("../BaseExpr"), 8 | Stmt = require("../Stmt"); 9 | 10 | /** 11 | * SetGlobal behavior. 12 | * @param {string} name 13 | * @param {string} description 14 | * @param {number} type 15 | * @constructor 16 | * @extends stmt.behavior.BaseBehavior 17 | * @exports stmt.behavior.SetGlobalBehavior 18 | */ 19 | function SetGlobalBehavior(name, description, wireType) { 20 | BaseBehavior.call(this, name, description); 21 | 22 | /** 23 | * Wire type. 24 | * @type {number} 25 | */ 26 | this.wireType = wireType; 27 | } 28 | 29 | module.exports = SetGlobalBehavior; 30 | 31 | // Extends Behavior 32 | SetGlobalBehavior.prototype = Object.create(BaseBehavior.prototype); 33 | 34 | // opcode + varint global variable index + Expr value 35 | // Stmt & Expr<*>, Stmt with imm 36 | 37 | SetGlobalBehavior.prototype.read = function(s, code, imm) { 38 | var variable; 39 | if (imm !== null) 40 | s.stmtWithoutImm(code, [ variable = s.global(imm, this.wireType !== types.WireType.Stmt ? this.wireType : undefined) ]); 41 | else 42 | s.stmt(code, [ variable = s.global(s.varint(), this.wireType !== types.WireType.Stmt ? this.wireType : undefined) ]); 43 | s.read(this.wireType === types.WireType.Stmt ? variable.type : this.wireType); 44 | }; 45 | 46 | SetGlobalBehavior.prototype.validate = function(definition, stmt) { 47 | assert.strictEqual(stmt.operands.length, 2, "SetGlobal requires exactly 2 operands"); 48 | var variable = stmt.operands[0]; 49 | assert(variable instanceof GlobalVariable, "SetGlobal variable (operand 0) must be a GlobalVariable"); 50 | assert.strictEqual(variable.assembly, definition.declaration.assembly, "SetGlobal variable (operand 0) must be part of this assembly"); 51 | if (this.wireType !== types.WireType.Stmt) 52 | assert.strictEqual(variable.type, this.wireType, "SetGlobal variable (operand 0) must be "+types.TypeNames[this.wireType]); 53 | var expr = stmt.operands[1]; 54 | assert(expr instanceof BaseExpr, "SetGlobal value (operand 1) must be an expression"); 55 | assert.strictEqual(expr.type, variable.type, "SetGlobal value (operand 1) expression must be "+types.WireTypeNames[variable.type]); 56 | }; 57 | 58 | SetGlobalBehavior.prototype.write = function(s, stmt) { 59 | var index = stmt.operands[0].index; 60 | if (!s.codeWithImm(stmt.code, index)) { 61 | s.code(stmt.code); 62 | s.varint(index); 63 | } 64 | s.write(stmt.operands[1]); 65 | }; 66 | -------------------------------------------------------------------------------- /src/stmt/behavior/SetLocalBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | LocalVariable = require("../../reflect/LocalVariable"), 6 | BaseExpr = require("../BaseExpr"), 7 | Stmt = require("../Stmt"); 8 | 9 | /** 10 | * SetLocal behavior. 11 | * @param {string} name 12 | * @param {string} description 13 | * @param {number} wireType 14 | * @constructor 15 | * @extends stmt.behavior.BaseBehavior 16 | * @exports stmt.behavior.SetLocalBehavior 17 | */ 18 | function SetLocalBehavior(name, description, wireType) { 19 | BaseBehavior.call(this, name, description); 20 | 21 | /** 22 | * Expression return type, if an expression. 23 | * @type {number} 24 | */ 25 | this.wireType = wireType; 26 | } 27 | 28 | module.exports = SetLocalBehavior; 29 | 30 | // Extends Behavior 31 | SetLocalBehavior.prototype = Object.create(BaseBehavior.prototype); 32 | 33 | // opcode + varint local variable index + Expr value 34 | // Stmt & Expr<*>, Stmt with imm 35 | 36 | SetLocalBehavior.prototype.read = function(s, code, imm) { 37 | var variable; 38 | if (imm !== null) 39 | s.stmtWithoutImm(code, [ variable = s.local(imm, this.wireType !== types.WireType.Stmt ? this.wireType : undefined) ]); 40 | else 41 | s.stmt(code, [ variable = s.local(s.varint(), this.wireType !== types.WireType.Stmt ? this.wireType : undefined) ]); 42 | s.read(this.wireType === types.WireType.Stmt ? variable.type : this.wireType); 43 | }; 44 | 45 | SetLocalBehavior.prototype.validate = function(definition, stmt) { 46 | assert.strictEqual(stmt.operands.length, 2, "SetLocal requires exactly 2 operands"); 47 | var variable = stmt.operands[0]; 48 | assert(variable instanceof LocalVariable, "SetLocal variable (operand 0) must be a LocalVariable"); 49 | assert.strictEqual(variable.definition, definition, "SetLocal variable (operand 0) must be part of this definition"); 50 | if (this.wireType !== types.WireType.Stmt) 51 | assert.strictEqual(variable.type, this.wireType, "SetLocal variable (operand 0) must be "+types.TypeNames[this.returnType]); 52 | var expr = stmt.operands[1]; 53 | assert(expr instanceof BaseExpr, "SetLocal value (operand 1) must be an expression"); 54 | assert.strictEqual(expr.type, variable.type, "SetLocal value (operand 1) expression must be "+types.WireTypeNames[variable.type]); 55 | }; 56 | 57 | SetLocalBehavior.prototype.write = function(s, stmt) { 58 | var index = stmt.operands[0].index; 59 | if (!s.codeWithImm(stmt.code, index)) { 60 | s.code(stmt.code); 61 | s.varint(index); 62 | } 63 | s.write(stmt.operands[1]); 64 | }; 65 | -------------------------------------------------------------------------------- /src/stmt/behavior/StmtListBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | Stmt = require("../Stmt"); 6 | 7 | /** 8 | * StmtList behavior. 9 | * @param {string} name 10 | * @param {string} description 11 | * @constructor 12 | * @extends stmt.behavior.BaseBehavior 13 | * @exports stmt.behavior.StmtListBehavior 14 | */ 15 | function StmtListBehavior(name, description) { 16 | BaseBehavior.call(this, name, description); 17 | } 18 | 19 | module.exports = StmtListBehavior; 20 | 21 | // Extends BaseBehavior 22 | StmtListBehavior.prototype = Object.create(BaseBehavior.prototype); 23 | 24 | StmtListBehavior.prototype.read = function(s) { 25 | var count = s.varint(); 26 | 27 | }; -------------------------------------------------------------------------------- /src/stmt/behavior/StoreBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | BaseExpr = require("../BaseExpr"), 6 | ExprI32 = require("../ExprI32"); 7 | 8 | /** 9 | * Store behavior. 10 | * @param {string} name 11 | * @param {string} description 12 | * @param {number} heapType 13 | * @constructor 14 | * @extends stmt.behavior.BaseBehavior 15 | * @exports stmt.behavior.StoreBehavior 16 | */ 17 | function StoreBehavior(name, description, heapType) { 18 | BaseBehavior.call(this, name, description); 19 | 20 | /** 21 | * Heap type. 22 | * @type {number} 23 | */ 24 | this.heapType = heapType; 25 | } 26 | 27 | module.exports = StoreBehavior; 28 | 29 | // Extends Behavior 30 | StoreBehavior.prototype = Object.create(BaseBehavior.prototype); 31 | 32 | // opcode + Expr heap index + Expr value 33 | // Stmt & Expr<*>, all without imm 34 | 35 | StoreBehavior.prototype.read = function(s, code) { 36 | s.stmt(code); 37 | s.read(types.WireType.ExprI32); 38 | s.read(this.heapType); 39 | }; 40 | 41 | StoreBehavior.prototype.validate = function(definition, stmt) { 42 | assert.strictEqual(stmt.operands.length, 2, "Store requires exactly 2 operands"); 43 | var index = stmt.operands[0]; 44 | assert(index instanceof ExprI32, "Store heap index (operand 0) must be an I32 expression"); 45 | var value = stmt.operands[1]; 46 | assert(value instanceof BaseExpr, "Store value (operand 1) must be an expression"); 47 | assert.strictEqual(value.type, this.heapType, "Store value (operand 1) expression must be "+types.RTypeNames[this.heapType]); 48 | }; 49 | 50 | StoreBehavior.prototype.write = function(s, stmt) { 51 | s.code(stmt.code); 52 | s.write(stmt.operands[0]); 53 | s.write(stmt.operands[1]); 54 | }; 55 | -------------------------------------------------------------------------------- /src/stmt/behavior/StoreWithOffsetBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | BaseExpr = require("..//BaseExpr"), 6 | ExprI32 = require("../ExprI32"); 7 | 8 | /** 9 | * StoreWithOffset behavior. 10 | * @param {string} name 11 | * @param {string} description 12 | * @param {number} heapType 13 | * @constructor 14 | * @extends stmt.behavior.BaseBehavior 15 | * @exports stmt.behavior.StoreWithOffsetBehavior 16 | */ 17 | function StoreWithOffsetBehavior(name, description, heapType) { 18 | BaseBehavior.call(this, name, description); 19 | 20 | /** 21 | * Heap type. 22 | * @type {number} 23 | */ 24 | this.heapType = heapType; 25 | } 26 | 27 | module.exports = StoreWithOffsetBehavior; 28 | 29 | // Extends Behavior 30 | StoreWithOffsetBehavior.prototype = Object.create(BaseBehavior.prototype); 31 | 32 | // opcode + varint offset + Expr heap index + Expr value 33 | // Stmt & Expr<*>, all without imm 34 | 35 | StoreWithOffsetBehavior.prototype.read = function(s, code) { 36 | s.stmt(code, [ s.varint() ]); 37 | s.read(types.WireType.ExprI32); 38 | s.read(this.heapType); 39 | }; 40 | 41 | StoreWithOffsetBehavior.prototype.validate = function(definition, stmt) { 42 | assert.strictEqual(stmt.operands.length, 3, "StoreWithOffset requires exactly 3 operands"); 43 | var offset = stmt.operands[0]; 44 | assert(typeof offset === 'number' && offset%1 === 0 && offset >= 0, "StoreWithOffset offset (operand 0) must be a non-negative integer"); 45 | var index = stmt.operands[1]; 46 | assert(index instanceof ExprI32, "StoreWithOffset heap index (operand 1) must be an I32 expression"); 47 | var value = stmt.operands[2]; 48 | assert(value instanceof BaseExpr, "StoreWithOffset value (operand 2) must be an expression"); 49 | assert.strictEqual(value.type, this.heapType, "StoreWithOffset value (operand 1) expression must be "+types.TypeNames[this.heapType]); 50 | }; 51 | 52 | StoreWithOffsetBehavior.prototype.write = function(s, stmt) { 53 | s.code(stmt.code); 54 | s.varint(stmt.operands[0]); 55 | s.write(stmt.operands[1]); 56 | s.write(stmt.operands[2]); 57 | }; 58 | -------------------------------------------------------------------------------- /src/stmt/behavior/SwitchBehavior.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | types = require("../../types"); 3 | 4 | var BaseBehavior = require("./BaseBehavior"), 5 | ExprI32 = require("../ExprI32"), 6 | SwitchCase = require("../SwitchCase"); 7 | 8 | /** 9 | * Switch behavior. 10 | * @param {string} name 11 | * @param {string} description 12 | * @constructor 13 | * @extends stmt.behavior.BaseBehavior 14 | * @exports stmt.behavior.SwitchBehavior 15 | */ 16 | function SwitchBehavior(name, description) { 17 | BaseBehavior.call(this, name, description); 18 | } 19 | 20 | module.exports = SwitchBehavior; 21 | 22 | // Extends Behavior 23 | SwitchBehavior.prototype = Object.create(BaseBehavior.prototype); 24 | 25 | // opcode + number of cases + Expr condition + number of cases * SwitchCase 26 | // Stmt only, without imm 27 | 28 | SwitchBehavior.prototype.read = function(s, code) { 29 | var count = s.varint(); 30 | s.stmt(code); 31 | s.read(types.WireType.ExprI32); 32 | for (var i=0; i= 1, this.name+" requires at least 1 operand"); 37 | var label = stmt.operands[0]; 38 | assert(typeof label === 'number' && label%1 === 0, this.name+" label (operand 0) must be an integer"); 39 | for (var i=1; i argument 31 | // Expr<*>, all without imm 32 | 33 | UnaryBehavior.prototype.read = function(s, code) { 34 | s.stmt(code); 35 | s.read(this.type); 36 | }; 37 | 38 | UnaryBehavior.prototype.validate = function(definition, stmt) { 39 | assert.strictEqual(stmt.operands.length, 1, this.name+" requires exactly 1 operand"); 40 | assert(stmt.operands[0] instanceof BaseExpr, this.name+" operand 0 must be an expression"); 41 | assert.strictEqual(stmt.operands[0].type, this.type, this.name+" operand 0 expression must be "+types.TypeNames[this.type]); 42 | }; 43 | 44 | UnaryBehavior.prototype.write = function(s, stmt) { 45 | s.code(stmt.code); 46 | s.write(stmt.operands[0]); 47 | }; 48 | -------------------------------------------------------------------------------- /src/stmt/behavior/index.js: -------------------------------------------------------------------------------- 1 | var types = require("../../types"); 2 | 3 | /** 4 | * @namespace 5 | * @exports stmt.behavior 6 | */ 7 | var behavior = module.exports = {}; 8 | 9 | var BaseBehavior = behavior.BaseBehavior = require("./BaseBehavior"), 10 | GetLocalBehavior = behavior.GetLocalBehavior = require("./GetLocalBehavior"), 11 | GetGlobalBehavior = behavior.GetGlobalBehavior = require("./GetGlobalBehavior"), 12 | SetLocalBehavior = behavior.SetLocalBehavior = require("./SetLocalBehavior"), 13 | SetGlobalBehavior = behavior.SetGlobalBehavior = require("./SetGlobalBehavior"), 14 | LoadBehavior = behavior.LoadBehavior = require("./LoadBehavior"), 15 | StoreBehavior = behavior.StoreBehavior = require("./StoreBehavior"), 16 | LoadWithOffsetBehavior = behavior.LoadWithOffsetBehavior = require("./LoadWithOffsetBehavior"), 17 | StoreWithOffsetBehavior = behavior.StoreWithOffsetBehavior = require("./StoreWithOffsetBehavior"), 18 | BranchBehavior = behavior.BranchBehavior = require("./BranchBehavior"), 19 | OpcodeOnlyBehavior = behavior.OpcodeOnlyBehavior = require("./OpcodeOnlyBehavior"), 20 | LabelBehavior = behavior.LabelBehavior = require("./LabelBehavior"), 21 | ReturnBehavior = behavior.ReturnBehavior = require("./ReturnBehavior"), 22 | BlockBehavior = behavior.BlockBehavior = require("./BlockBehavior"), 23 | UnaryBehavior = behavior.UnaryBehavior = require("./UnaryBehavior"), 24 | BinaryBehavior = behavior.BinaryBehavior = require("./BinaryBehavior"), 25 | MultiaryBehavior = behavior.MultiaryBehavior = require("./MultiaryBehavior"), 26 | LiteralBehavior = behavior.LiteralBehavior = require("./LiteralBehavior"), 27 | ConstantPoolBehavior = behavior.ConstantPoolBehavior = require("./ConstantPoolBehavior"), 28 | CommaBehavior = behavior.CommaBehavior = require("./CommaBehavior"), 29 | CallInternalBehavior = behavior.CallInternalBehavior = require("./CallInternalBehavior"), 30 | CallImportBehavior = behavior.CallImportBehavior = require("./CallImportBehavior"), 31 | CallIndirectBehavior = behavior.CallIndirectBehavior = require("./CallIndirectBehavior"), 32 | SwitchBehavior = behavior.SwitchBehavior = require("./SwitchBehavior"), 33 | SwitchCaseNoneBehavior = behavior.SwitchNoneBehavior = require("./SwitchCaseNoneBehavior"), 34 | SwitchCaseSingleBehavior = behavior.SwitchCaseSingleBehavior = require("./SwitchCaseSingleBehavior"), 35 | SwitchCaseMultipleBehavior = behavior.SwitchCaseMultipleBehavior = require("./SwitchCaseMultipleBehavior"), 36 | SwitchDefaultNoneBehavior = behavior.SwitchDefaultNoneBehavior = require("./SwitchDefaultNoneBehavior"), 37 | SwitchDefaultSingleBehavior = behavior.SwitchDefaultSingleBehavior = require("./SwitchDefaultSingleBehavior"), 38 | SwitchDefaultMultipleBehavior = behavior.SwitchDefaultMultipleBehavior = require("./SwitchDefaultMultipleBehavior"); 39 | 40 | // Get local variable 41 | behavior.GetLocalI32 = new GetLocalBehavior("GetLocalI32", "opcode + local I32 variable index", types.Type.I32); 42 | behavior.GetLocalF32 = new GetLocalBehavior("GetLocalF32", "opcode + local F32 variable index", types.Type.F32); 43 | behavior.GetLocalF64 = new GetLocalBehavior("GetLocalF64", "opcode + local F64 variable index", types.Type.F64); 44 | 45 | // Set local variable 46 | behavior.SetLocal = new SetLocalBehavior("SetLocal", "opcode + local variable index + Expr", types.WireType.Stmt); 47 | behavior.SetLocalI32 = new SetLocalBehavior("SetLocalI32", "opcode + local I32 variable index + Expr", types.WireType.ExprI32); 48 | behavior.SetLocalF32 = new SetLocalBehavior("SetLocalF32", "opcode + local F32 variable index + Expr", types.WireType.ExprF32); 49 | behavior.SetLocalF64 = new SetLocalBehavior("SetLocalF64", "opcode + local F64 variable index + Expr", types.WireType.ExprF64); 50 | 51 | // Get global variable 52 | behavior.GetGlobalI32 = new GetGlobalBehavior("GetGlobalI32", "opcode + global I32 variable index", types.Type.I32); 53 | behavior.GetGlobalF32 = new GetGlobalBehavior("GetGlobalF32", "opcode + global F32 variable index", types.Type.F32); 54 | behavior.GetGlobalF64 = new GetGlobalBehavior("GetGlobalF64", "opcode + global F64 variable index", types.Type.F64); 55 | 56 | // Set global variable 57 | behavior.SetGlobal = new SetGlobalBehavior("SetGlobal", "opcode + global variable index + Expr", types.WireType.Stmt); 58 | behavior.SetGlobalI32 = new SetGlobalBehavior("SetGlobalI32", "opcode + global I32 variable index + Expr", types.WireType.ExprI32); 59 | behavior.SetGlobalF32 = new SetGlobalBehavior("SetGlobalF32", "opcode + global F32 variable index + Expr", types.WireType.ExprF32); 60 | behavior.SetGlobalF64 = new SetGlobalBehavior("SetGlobalF64", "opcode + global F64 variable index + Expr", types.WireType.ExprF64); 61 | 62 | // Store on heap 63 | behavior.StoreI = new StoreBehavior("StoreI", "opcode + Expr type-specific heap index + Expr value", types.Type.I32); 64 | behavior.StoreF32 = new StoreBehavior("StoreF32", "opcode + Expr F32 heap index + Expr value", types.Type.F32); 65 | behavior.StoreF64 = new StoreBehavior("StoreF64", "opcode + Expr F64 heap index + Expr value", types.Type.F64); 66 | 67 | // Load from heap 68 | behavior.LoadI = new LoadBehavior("LoadI", "opcode + Expr type-specific heap index", types.Type.I32); 69 | behavior.LoadF32 = new LoadBehavior("LoadF32", "opcode + Expr F32 heap index", types.Type.F32); 70 | behavior.LoadF64 = new LoadBehavior("LoadF64", "opcode + Expr F64 heap index", types.Type.F64); 71 | 72 | // Store on heap with specified offset 73 | behavior.StoreWithOffsetI = new StoreWithOffsetBehavior("StoreWithOffsetI", "opcode + Expr type-specific heap index + Expr heap offset + Expr value", types.WireType.ExprI32); 74 | behavior.StoreWithOffsetF32 = new StoreWithOffsetBehavior("StoreWithOffsetF32", "opcode + Expr F32 heap index + Expr heap offset + Expr value", types.WireType.ExprF32); 75 | behavior.StoreWithOffsetF64 = new StoreWithOffsetBehavior("StoreWithOffsetF64", "opcode + Expr F64 heap index + Expr heap offset + Expr value", types.WireType.ExprF64); 76 | 77 | // Load from heap with specified offset 78 | behavior.LoadWithOffsetI = new LoadWithOffsetBehavior("LoadWithOffsetI", "opcode + Expr type-specific heap index + Expr heap offset", types.Type.I32); 79 | behavior.LoadWithOffsetF32 = new LoadWithOffsetBehavior("LoadWithOffsetF32", "opcode + Expr F32 heap index + Expr heap offset", types.Type.F32); 80 | behavior.LoadWithOffsetF64 = new LoadWithOffsetBehavior("LoadWithOffsetF64", "opcode + Expr F64 heap index + Expr heap offset", types.Type.F64); 81 | 82 | // Control flow 83 | behavior.IfThen = new BranchBehavior("IfThen", "opcode + Expr condition + Stmt then", [types.WireType.ExprI32, types.WireType.Stmt]); 84 | behavior.IfElse = new BranchBehavior("IfElse", "opcode + Expr condition + Stmt then + Stmt else", [types.WireType.ExprI32, types.WireType.Stmt, types.WireType.Stmt]); 85 | behavior.While = new BranchBehavior("While", "opcode + Expr condition + Stmt body", [types.WireType.ExprI32, types.WireType.Stmt]); 86 | behavior.Do = new BranchBehavior("Do", "opcode + Stmt body + Expr condition", [types.WireType.Stmt, types.WireType.ExprI32]); 87 | behavior.Label = new BranchBehavior("Label", "opcode + Stmt body", [types.WireType.Stmt]); 88 | behavior.ConditionalI32 = new BranchBehavior("ConditionalI32", "opcode + Expr condition + Expr then + Expr else", [types.WireType.ExprI32, types.WireType.ExprI32, types.WireType.ExprI32]); 89 | behavior.ConditionalF32 = new BranchBehavior("ConditionalF32", "opcode + Expr condition + Expr then + Expr else", [types.WireType.ExprI32, types.WireType.ExprF32, types.WireType.ExprF32]); 90 | behavior.ConditionalF64 = new BranchBehavior("ConditionalF64", "opcode + Expr condition + Expr then + Expr else", [types.WireType.ExprI32, types.WireType.ExprF64, types.WireType.ExprF64]); 91 | behavior.Break = new OpcodeOnlyBehavior("Break", "opcode only"); 92 | behavior.Continue = new OpcodeOnlyBehavior("Continue", "opcode only"); 93 | behavior.BreakLabel = new LabelBehavior("BreakLabel", "opcode + label index"); 94 | behavior.ContinueLabel = new LabelBehavior("ContinueLabel", "opcode + label index"); 95 | behavior.Return = new ReturnBehavior("Return", "opcode [ + Expr if function return type is not void ]"); 96 | 97 | // Container 98 | behavior.Block = new BlockBehavior("Block", "opcode + varint count + count * Stmt"); 99 | 100 | // Unary operation 101 | behavior.UnaryI32 = new UnaryBehavior("UnaryI32", "opcode + Expr", types.WireType.ExprI32); 102 | behavior.UnaryF32 = new UnaryBehavior("UnaryF32", "opcode + Expr", types.WireType.ExprF32); 103 | behavior.UnaryF64 = new UnaryBehavior("UnaryF64", "opcode + Expr", types.WireType.ExprF64); 104 | 105 | // Binary operation 106 | behavior.BinaryI32 = new BinaryBehavior("BinaryI32", "opcode + Expr + Expr", types.WireType.ExprI32); 107 | behavior.BinaryF32 = new BinaryBehavior("BinaryF32", "opcode + Expr + Expr", types.WireType.ExprF32); 108 | behavior.BinaryF64 = new BinaryBehavior("BinaryF64", "opcode + Expr + Expr", types.WireType.ExprF64); 109 | 110 | // Multiary operation (variable number of arguments) 111 | behavior.MultiaryI32 = new MultiaryBehavior("MultiaryI32", "opcode + varint count + count * Expr", types.WireType.ExprI32); 112 | behavior.MultiaryF64 = new MultiaryBehavior("MultiaryF64", "opcode + varint count + count * Expr", types.WireType.ExprF64); 113 | 114 | // Literal value 115 | behavior.LiteralI32 = new LiteralBehavior("LiteralI32", "opcode + varint/imm value", types.Type.I32); 116 | behavior.LiteralF32 = new LiteralBehavior("LiteralF32", "opcode + float value", types.Type.F32); 117 | behavior.LiteralF64 = new LiteralBehavior("LiteralF64", "opcode + double value", types.Type.F64); 118 | 119 | // Constant value 120 | behavior.ConstantI32 = new ConstantPoolBehavior("ConstantI32", "opcode + I32 constant index", types.WireType.ExprI32); 121 | behavior.ConstantF32 = new ConstantPoolBehavior("ConstantF32", "opcode + F32 constant index", types.WireType.ExprF32); 122 | behavior.ConstantF64 = new ConstantPoolBehavior("ConstantF64", "opcode + F64 constant index", types.WireType.ExprF64); 123 | 124 | // Comma expression 125 | behavior.CommaI32 = new CommaBehavior("CommaI32", "opcode + byte return type + Expr + Expr", types.WireType.ExprI32); 126 | behavior.CommaF32 = new CommaBehavior("CommaF32", "opcode + byte return type + Expr + Expr", types.WireType.ExprF32); 127 | behavior.CommaF64 = new CommaBehavior("CommaF64", "opcode + byte return type + Expr + Expr", types.WireType.ExprF64); 128 | 129 | // Function call 130 | behavior.CallInternal = new CallInternalBehavior("CallInternal", "opcode + varint function declaration index + Expr for each argument", types.WireType.ExprVoid); 131 | behavior.CallImport = new CallImportBehavior("CallImport", "opcode + varint function import signature index + Expr for each argument", types.WireType.ExprVoid); 132 | behavior.CallIndirect = new CallIndirectBehavior("CallIndirect", "opcode + varint function pointer table index + Expr element index + Expr for each argument", types.WireType.ExprVoid); 133 | behavior.CallInternalI32 = new CallInternalBehavior("CallInternalI32", "opcode + varint function declaration index + Expr for each argument", types.WireType.ExprI32); 134 | behavior.CallImportI32 = new CallImportBehavior("CallImportI32", "opcode + varint function import signature index + Expr for each argument", types.WireType.ExprI32); 135 | behavior.CallIndirectI32 = new CallIndirectBehavior("CallIndirectI32", "opcode + varint function pointer table index + Expr element index + Expr for each argument", types.WireType.ExprI32); 136 | behavior.CallInternalF32 = new CallInternalBehavior("CallInternalF32", "opcode + varint function declaration index + Expr for each argument", types.WireType.ExprF32); 137 | behavior.CallIndirectF32 = new CallIndirectBehavior("CallIndirectF32", "opcode + varint function pointer table index + Expr element index + Expr for each argument", types.WireType.ExprF32); 138 | behavior.CallInternalF64 = new CallInternalBehavior("CallInternalF64", "opcode + varint function declaration index + Expr for each argument", types.WireType.ExprF64); 139 | behavior.CallImportF64 = new CallImportBehavior("CallImportF64", "opcode + varint function import signature index + Expr for each argument", types.WireType.ExprF64); 140 | behavior.CallIndirectF64 = new CallIndirectBehavior("CallIndirectF64", "opcode + varint function pointer table index + Expr element index + Expr for each argument", types.WireType.ExprF64); 141 | behavior.CallInternalVoid = new CallInternalBehavior("CallInternalVoid", "opcode + varint function declaration index + Expr for each argument", types.WireType.ExprVoid); 142 | behavior.CallImportVoid = new CallImportBehavior("CallImportVoid", "opcode + varint function import signature index + Expr for each argument", types.WireType.ExprVoid); 143 | behavior.CallIndirectVoid = new CallIndirectBehavior("CallIndirectVoid", "opcode + varint function pointer table index + Expr element index + Expr for each argument", types.WireType.ExprVoid); 144 | 145 | // Switch and switch cases 146 | behavior.Switch = new SwitchBehavior("Switch", "opcode + varint cases + cases * SwitchCase"); 147 | behavior.SwitchCase0 = new SwitchCaseNoneBehavior("SwitchCase0", "opcode + signed varint label"); 148 | behavior.SwitchCase1 = new SwitchCaseSingleBehavior("SwitchCase1", "opcode + signed varint label + Stmt"); 149 | behavior.SwitchCaseN = new SwitchCaseMultipleBehavior("SwitchCaseN", "opcode + signed varint label + varint count + count * Stmt"); 150 | behavior.SwitchDefault0 = new SwitchDefaultNoneBehavior("SwitchDefault0", "opcode only"); 151 | behavior.SwitchDefault1 = new SwitchDefaultSingleBehavior("SwitchDefault1", "opcode + Stmt"); 152 | behavior.SwitchDefaultN = new SwitchDefaultMultipleBehavior("SwitchDefaultN", "opcode + varint count + count * Stmt"); 153 | -------------------------------------------------------------------------------- /src/stmt/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace 3 | * @exports stmt 4 | */ 5 | var stmt = module.exports = {}; 6 | 7 | stmt.BaseStmt = require("./BaseStmt"); 8 | stmt.BaseOperand = require("./BaseOperand"); 9 | stmt.BaseExpr = require("./BaseExpr"); 10 | 11 | stmt.Stmt = require("./Stmt"); 12 | stmt.StmtList = require("./StmtList"); 13 | 14 | stmt.ExprI32 = require("./ExprI32"); 15 | stmt.ExprF32 = require("./ExprF32"); 16 | stmt.ExprF64 = require("./ExprF64"); 17 | stmt.ExprVoid = require("./ExprVoid"); 18 | 19 | stmt.SwitchCase = require("./SwitchCase"); 20 | 21 | stmt.behavior = require("./behavior"); 22 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | var types = require("./types"), 2 | assert = require("assert"); 3 | 4 | /** 5 | * Utility. 6 | * @namespace 7 | * @exports util 8 | */ 9 | var util = module.exports = {}; 10 | 11 | /** 12 | * @alias util.BufferQueue 13 | */ 14 | util.BufferQueue = require("./util/BufferQueue"); 15 | 16 | // ----- protocol ----- 17 | 18 | util.unpackWithImm = function(b) { 19 | if ((b & types.OpWithImm_Flag) === 0) 20 | return false; 21 | var op = (b >> types.OpWithImm_ImmBits) & types.OpWithImm_OpMax; 22 | var imm = b & types.OpWithImm_ImmMax; 23 | return { 24 | code: op, 25 | imm: imm 26 | }; 27 | }; 28 | 29 | util.packWithImm = function(code, imm) { 30 | return types.OpWithImm_Flag | ((code & types.OpWithImm_OpMax) << types.OpWithImm_ImmBits) | (imm & types.OpWithImm_ImmMax); 31 | }; 32 | 33 | util.calculateVarint = function(value) { 34 | value = value >>> 0; 35 | if (value < 1 << 7 ) return 1; 36 | else if (value < 1 << 14) return 2; 37 | else if (value < 1 << 21) return 3; 38 | else if (value < 1 << 28) return 4; 39 | else return 5; 40 | }; 41 | 42 | util.writeVarint = function(buffer, u32, offset) { 43 | var c = 1; 44 | u32 >>>= 0; 45 | while (u32 >= 1 << 7) 46 | buffer[offset++] = (u32 & 0x7f) | 0x80, 47 | u32 >>>= 7, 48 | ++c; 49 | buffer[offset] = u32; 50 | return c; 51 | }; 52 | 53 | /* util.readIfI32Lit = function(buffer, offset) { 54 | if (offset >= buffer.length) 55 | throw E_MORE; 56 | var off = offset; 57 | var b = buffer[off]; 58 | if (b & HasImmFlag) { 59 | var res = util.unpackWithImm(b); 60 | if (res.op === types.I32WithImm.LitImm) { 61 | off++; 62 | return { 63 | op: res.op, 64 | imm: res.imm, 65 | length: off - offset // 1 66 | }; 67 | } 68 | if (res.op === types.I32WithImm.LitPool) { 69 | off++; 70 | return { 71 | op: res.op, 72 | imm: res.imm, 73 | length: off - offset // 1 74 | }; 75 | } 76 | return false; 77 | } 78 | var vi; 79 | if (b === types.I32.LitImm) { 80 | off++; 81 | vi = this.readVarint(buffer, off); off += vi.length; 82 | return { 83 | op: b, 84 | imm: vi.value, 85 | length: off - offset 86 | }; 87 | } 88 | if (b === types.I32.LitPool) { 89 | off++; 90 | vi = this.readVarint(buffer, off); off += vi.length; 91 | return { 92 | op: b, 93 | imm: vi.value, 94 | length: off - offset 95 | } 96 | } 97 | return false; 98 | }; */ 99 | 100 | // ----- asm.js naming ----- 101 | 102 | // Identifier characters 103 | var IdenChars = [ 104 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 105 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 106 | '_', '$', 107 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 108 | ]; 109 | util.FirstCharRange = 26 * 2 + 2; 110 | util.FirstCharRangeMinusDollar = 26 * 2 + 1; 111 | util.NextCharRange = IdenChars.length; 112 | 113 | util.indexedName = function(range, i) { 114 | assert(IdenChars.length === 64, "assumed below"); 115 | if (i < range) 116 | return IdenChars[i]; 117 | i -= range; 118 | var name = []; 119 | if (i < range * 64) { 120 | name.push(IdenChars[i >> 6]); 121 | name.push(IdenChars[i & 0x3f]); 122 | 123 | // Instead of trying to catch every >2 letter keyword, just inject a _. 124 | assert(IdenChars[0x205>>6] === 'i' && IdenChars[0x205&0x3f] === 'f'); 125 | assert(IdenChars[0x20d>>6] === 'i' && IdenChars[0x20d&0x3f] === 'n'); 126 | assert(IdenChars[0x0ce>>6] === 'd' && IdenChars[0x0ce&0x3f] === 'o'); 127 | // Append _ if we would otherwise generate one of the two-letter keywords. 128 | if (range < util.NextCharRange && (i == 0x205 || i == 0x20d || i == 0x0ce)) 129 | name.push("_"); 130 | return name.join(""); 131 | } 132 | i -= range * 64; 133 | 134 | // Instead of trying to catch every >2 letter keyword, just inject a _. 135 | if (range < util.NextCharRange) 136 | name.push("_"); 137 | 138 | var len = 0; 139 | do { 140 | name.push(IdenChars[i & 0x3f]); 141 | len++; 142 | i = i >> 6; 143 | } while (i >= range * 64); 144 | name.push(IdenChars[i & 0x3f]); 145 | name.push(IdenChars[i >> 6]); 146 | len += 2; 147 | var a = name.slice(0, name.length - len); 148 | var b = name.slice(name.length - len); 149 | b.reverse(); 150 | name = a.concat(b); 151 | return name.join(""); 152 | }; 153 | 154 | util.localName = function(i) { 155 | return util.indexedName(util.FirstCharRangeMinusDollar, i + types.HotStdLibNames.length); 156 | }; 157 | 158 | util.globalName = function(i) { 159 | return '$' + util.indexedName(util.NextCharRange, i + types.StdLibNames.length); 160 | }; 161 | 162 | util.hotStdLibName = function(index) { 163 | assert(index >= 0 && index < types.HotStdLibNames.length); 164 | return String.fromCharCode(0x61 + index); 165 | }; 166 | 167 | util.stdLibName = function(index) { 168 | assert(index >= 0 && index < types.StdLibNames.length); 169 | return "$" + util.indexedName(util.FirstCharRange, index); 170 | }; 171 | 172 | var FNAME_RE = /^[a-zA-Z_\$][a-zA-Z0-9_\$]*$/; // FIXME 173 | 174 | util.isValidFName = function(value) { 175 | return !!(typeof value === 'string' && FNAME_RE.test(value)); 176 | }; 177 | 178 | // ----- inline assertions ----- 179 | 180 | util.assertInteger = function(name, value, min, max) { 181 | if (typeof value !== 'number' || value%1 !== 0) 182 | assert.fail(value, "integer", name+" must be an integer", "==="); 183 | if (typeof min === 'undefined' && typeof max === 'undefined') 184 | return; 185 | if (typeof max === 'undefined') 186 | max = min, min = 0; 187 | if (value < min || value > max) 188 | assert.fail(value, "["+min+","+max+"]", name+" out of bounds", "in"); 189 | }; 190 | 191 | util.assertRType = function(name, value) { 192 | util.assertInteger(name, value); 193 | if (!types.isValidRType(value)) 194 | assert.fail(value, types.RType, name+" must be a valid return type", "in"); 195 | }; 196 | 197 | util.assertType = function(name, value) { 198 | util.assertInteger(name, value); 199 | if (!types.isValidType(value)) 200 | assert.fail(value, util.values(types.Type), name+" must be a valid type", "in"); 201 | }; 202 | 203 | util.assertFName = function(name, value) { 204 | if (!util.isValidFName(value)) 205 | assert.fail(value, "function name", name+" must be a valid function name", "==="); 206 | }; 207 | 208 | // ----- general ----- 209 | 210 | util.values = function(obj) { 211 | var values = []; 212 | for (var i in obj) 213 | if (obj.hasOwnProperty(i)) 214 | values.push(obj[i]); 215 | return values; 216 | }; 217 | -------------------------------------------------------------------------------- /src/util/BufferQueue.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2015 Daniel Wirtz 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /** 18 | * A BufferQueue. 19 | * 20 | * Used to remove the need to slice or concatenate buffers and provides the 21 | * convenience of relative read operations and occasionally performed rollbacks. 22 | * 23 | * @constructor 24 | * @exports util.BufferQueue 25 | */ 26 | var BufferQueue = module.exports = function() { 27 | 28 | /** 29 | * Queued buffers. 30 | * @type {!Array.} 31 | */ 32 | this.buffers = []; 33 | 34 | /** 35 | * Global offset since start. 36 | * @type {number} 37 | */ 38 | this.offset = 0; 39 | 40 | /** 41 | * Current buffer index. 42 | * @type {number} 43 | */ 44 | this.bufferIndex = 0; 45 | 46 | /** 47 | * Current buffer offset. 48 | * @type {number} 49 | */ 50 | this.bufferOffset = 0; 51 | 52 | /** 53 | * Byte length of all queued buffers. 54 | * @type {number} 55 | */ 56 | this.bufferLength = 0; 57 | 58 | /** 59 | * Previous global offset. 60 | * @type {number} 61 | */ 62 | this.markedOffset = 0; 63 | 64 | /** 65 | * Previous buffer index. 66 | * @type {number} 67 | * @see {@link BufferQueue#reset} 68 | */ 69 | this.markedBufferIndex = 0; 70 | 71 | /** 72 | * Previous buffer offset. 73 | * @type {number} 74 | * @see {@link BufferQueue#reset} 75 | */ 76 | this.markedBufferOffset = 0; 77 | }; 78 | 79 | /** 80 | * Number of remaining readable bytes. 81 | * @name BufferQueue#remaining 82 | * @type {number} 83 | */ 84 | Object.defineProperty(BufferQueue.prototype, "remaining", { 85 | get: function() { 86 | if (this.buffers.length === 0) 87 | return 0; 88 | var len = this.bufferLength; 89 | for (var i=0; i 0) { 129 | this.bufferLength -= this.buffers.shift().length; 130 | this.bufferIndex--; 131 | } 132 | return this.commit(); 133 | }; 134 | 135 | /** 136 | * Resets the buffer queue to the last state. 137 | * @returns {!util.BufferQueue} 138 | */ 139 | BufferQueue.prototype.reset = function() { 140 | this.offset = this.markedOffset; 141 | this.bufferIndex = this.markedBufferIndex; 142 | this.bufferOffset = this.markedBufferOffset; 143 | return this; 144 | }; 145 | 146 | /** 147 | * Clears all buffers. 148 | * @param {boolean} resetOffset 149 | * @returns {!util.BufferQueue} 150 | */ 151 | BufferQueue.prototype.clear = function(resetOffset) { 152 | this.buffers = []; 153 | this.bufferLength = 0; 154 | this.bufferIndex = this.markedBufferIndex = 0; 155 | this.bufferOffset = this.markedBufferOffset = 0; 156 | if (resetOffset) 157 | this.offset = this.markedOffset = 0; 158 | return this; 159 | }; 160 | 161 | /** 162 | * Ensures that the specified number of bytes is readable. 163 | * @param {number} nBytes 164 | * @throws {BufferQueue.E_MORE} 165 | */ 166 | BufferQueue.prototype.ensure = function(nBytes) { 167 | if (this.remaining < nBytes) 168 | throw BufferQueue.E_MORE; 169 | }; 170 | 171 | /** 172 | * Reads an 8bit unsigned integer. 173 | * @returns {number} 174 | */ 175 | BufferQueue.prototype.readUInt8 = function() { 176 | if (this.bufferIndex >= this.buffers.length) 177 | throw BufferQueue.E_MORE; 178 | var buf = this.buffers[this.bufferIndex], 179 | u8 = buf[this.bufferOffset++]; 180 | this.offset++; 181 | if (this.bufferOffset >= buf.length) { 182 | this.bufferIndex++; 183 | this.bufferOffset = 0; 184 | } 185 | return u8; 186 | }; 187 | 188 | /** 189 | * Writes an 8bit unsigned integer. 190 | * @param {number} u8 191 | * @returns {!util.BufferQueue} 192 | */ 193 | BufferQueue.prototype.writeUInt8 = function(u8) { 194 | if (this.bufferIndex >= this.buffers.length) 195 | throw BufferQueue.E_MORE; 196 | var buf = this.buffers[this.bufferIndex]; 197 | buf[this.bufferOffset++] = u8; 198 | this.offset++; 199 | if (this.bufferOffset >= buf.length) { 200 | this.bufferIndex++; 201 | this.bufferOffset = 0; 202 | } 203 | return this; 204 | }; 205 | 206 | /** 207 | * Reads a little endian 32bit unsigned integer. 208 | * @returns {number} 209 | */ 210 | BufferQueue.prototype.readUInt32LE = function() { 211 | return (this.readUInt8() | (this.readUInt8() << 8) | (this.readUInt8() << 16) | (this.readUInt8() << 24)) >>> 0; 212 | }; 213 | 214 | /** 215 | * Writes a little endian 32bit unsigned integer. 216 | * @param {number} u32 217 | * @returns {!util.BufferQueue} 218 | */ 219 | BufferQueue.prototype.writeUInt32LE = function(u32) { 220 | u32 >>>= 0; 221 | return this.writeUInt8(u32) 222 | .writeUInt8(u32 >>> 8) 223 | .writeUInt8(u32 >>> 16) 224 | .writeUInt8(u32 >>> 24); 225 | }; 226 | 227 | /** 228 | * Reads an unsigned varint. 229 | * @returns {number} 230 | */ 231 | BufferQueue.prototype.readVarint = function() { 232 | if (this.buffers.length === 0) 233 | throw BufferQueue.E_MORE; 234 | var value = this.readUInt8(); 235 | if (value < 0x80) 236 | return value; 237 | value &= 0x7f; 238 | var c = 1; 239 | for (var shift = 7; true; shift += 7) { 240 | var b = this.readUInt8(); 241 | if (b < 0x80) 242 | return (value | (b << shift)) >>> 0; 243 | if (++c > 5) 244 | throw Error("illegal varint32: >5 bytes"); 245 | value = (value | ((b & 0x7f) << shift)) >>> 0; 246 | } 247 | }; 248 | 249 | /** 250 | * Writes an unsigned varint. 251 | * @param {number} u32 252 | * @returns {!util.BufferQueue} 253 | */ 254 | BufferQueue.prototype.writeVarint = function(u32) { 255 | u32 >>>= 0; 256 | if (u32) { 257 | for (; true; u32 >>>= 7) { 258 | if (u32 < 0x80) { 259 | this.writeUInt8(u32); 260 | return this; 261 | } 262 | this.writeUInt8(0x80 | (u32 & 0x7f)); 263 | } 264 | } else 265 | this.writeUInt8(0); 266 | return this; 267 | }; 268 | 269 | /** 270 | * Reads a signed varint. 271 | */ 272 | BufferQueue.prototype.readVarintSigned = function() { 273 | if (this.buffers.length === 0) 274 | throw BufferQueue.E_MORE; 275 | var value = this.readUInt8(); 276 | if (value < 0x80) 277 | return value << (32-7) >> (32-7); 278 | value &= 0x7f; 279 | var c = 1; 280 | for (var shift = 7; true; shift += 7) { 281 | var b = this.readUInt8(); 282 | if (b < 0x80) { 283 | value = (value | (b << shift)) >>> 0; 284 | var sign_extend = (32-7) - shift; 285 | if (sign_extend > 0) 286 | return (value|0) << sign_extend >> sign_extend; 287 | return value|0; 288 | } 289 | if (++c > 5) 290 | throw Error("illegal varint32: >5 bytes"); 291 | value = (value | ((b & 0x7f) << shift)) >>> 0; 292 | } 293 | }; 294 | 295 | /** 296 | * Writes a signed varint. 297 | * @param {number} s32 298 | * @returns {!util.BufferQueue} 299 | */ 300 | BufferQueue.prototype.writeVarintSigned = function(s32) { 301 | s32 |= 0; 302 | if (s32) { 303 | for (; true; s32 >>= 7) { 304 | if (-64 <= s32 && s32 < 64) { 305 | this.writeUInt8(s32 & 0x7f); 306 | return this; 307 | } 308 | this.writeUInt8(0x80 | (s32 & 0x7f)); 309 | } 310 | } else 311 | this.writeUInt8(0); 312 | return this; 313 | }; 314 | 315 | // ref: https://github.com/feross/ieee754 316 | BufferQueue.prototype._readFloat = function(isLE, mLen, nBytes) { 317 | var buffer = []; 318 | for (var i=0; i> 1, 324 | nBits = -7, 325 | d = isLE ? -1 : 1, 326 | s = buffer[i = isLE ? (nBytes - 1) : 0]; 327 | 328 | i += d; 329 | 330 | e = s & ((1 << (-nBits)) - 1); 331 | s >>= (-nBits); 332 | nBits += eLen; 333 | for (; nBits > 0; e = e * 256 + buffer[i], i += d, nBits -= 8) {} 334 | 335 | m = e & ((1 << (-nBits)) - 1); 336 | e >>= (-nBits); 337 | nBits += mLen; 338 | for (; nBits > 0; m = m * 256 + buffer[i], i += d, nBits -= 8) {} 339 | 340 | if (e === 0) 341 | e = 1 - eBias; 342 | else if (e === eMax) 343 | return m ? NaN : ((s ? -1 : 1) * Infinity); 344 | else { 345 | m = m + Math.pow(2, mLen); 346 | e = e - eBias; 347 | } 348 | return (s ? -1 : 1) * m * Math.pow(2, e - mLen); 349 | }; 350 | 351 | /** 352 | * Reads a little endian 32 bit float. 353 | * @returns {number} 354 | */ 355 | BufferQueue.prototype.readFloatLE = function() { 356 | return this._readFloat(true, 23, 4); 357 | }; 358 | 359 | /** 360 | * Reads a little endian 64 bit double. 361 | * @returns {number} 362 | */ 363 | BufferQueue.prototype.readDoubleLE = function() { 364 | return this._readFloat(true, 52, 8); 365 | }; 366 | 367 | // ref: https://github.com/feross/ieee754 368 | BufferQueue.prototype._writeFloat = function(value, isLE, mLen, nBytes) { 369 | var buffer = []; 370 | for (var i=0; i> 1; 376 | var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0); 377 | var i = isLE ? 0 : (nBytes - 1); 378 | var d = isLE ? 1 : -1; 379 | var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; 380 | 381 | value = Math.abs(value); 382 | 383 | if (isNaN(value) || value === Infinity) { 384 | m = isNaN(value) ? 1 : 0; 385 | e = eMax; 386 | } else { 387 | e = Math.floor(Math.log(value) / Math.LN2); 388 | if (value * (c = Math.pow(2, -e)) < 1) { 389 | e--; 390 | c *= 2; 391 | } 392 | if (e + eBias >= 1) { 393 | value += rt / c; 394 | } else { 395 | value += rt * Math.pow(2, 1 - eBias); 396 | } 397 | if (value * c >= 2) { 398 | e++; 399 | c /= 2; 400 | } 401 | 402 | if (e + eBias >= eMax) { 403 | m = 0; 404 | e = eMax; 405 | } else if (e + eBias >= 1) { 406 | m = (value * c - 1) * Math.pow(2, mLen); 407 | e = e + eBias; 408 | } else { 409 | m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); 410 | e = 0; 411 | } 412 | } 413 | 414 | for (; mLen >= 8; buffer[i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} 415 | 416 | e = (e << mLen) | m; 417 | eLen += mLen; 418 | for (; eLen > 0; buffer[i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} 419 | 420 | buffer[i - d] |= s * 128; 421 | for (i=0; i>> 0 < 3) { 9 | return 1|0; 10 | } 11 | l = $w(k-1)|0; 12 | m = $w(k-2)|0; 13 | return l + m; 14 | } 15 | 16 | return $w; 17 | } 18 | -------------------------------------------------------------------------------- /tests/fib.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcodeIO/WebAssembly-prototype/50e84e133a6e18b0ba0908eea241f836392ebde2/tests/fib.wasm -------------------------------------------------------------------------------- /tests/test.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"), 2 | path = require("path"), 3 | assert = require("assert"), 4 | pkg = require("../package.json"); 5 | 6 | var webassembly = require("../"), 7 | types = webassembly.types, 8 | Reader = webassembly.Reader, 9 | AstReader = webassembly.ast.Reader, 10 | Writer = webassembly.Writer, 11 | AstWriter = webassembly.ast.Writer, 12 | Assembly = webassembly.reflect.Assembly; 13 | 14 | var verbose = 1; 15 | 16 | if (typeof process.env.VERBOSE !== 'undefined') 17 | verbose = parseInt(process.env.VERBOSE, 10); 18 | 19 | var filename = "AngryBots.wasm"; 20 | var file = path.join(__dirname, filename), 21 | stats = fs.statSync(file); 22 | 23 | console.log("WebAssembly "+pkg.version+": Testing '"+filename+"' ...\n"); 24 | 25 | var reader = new Reader({ 26 | skipAhead: true 27 | }); 28 | 29 | if (verbose) { 30 | reader.on("switchState", function (prevState, newState, offset) { 31 | console.log("switch state " + prevState + "->" + newState + " @ " + offset.toString(16)); 32 | }); 33 | 34 | reader.on("header", function (size) { 35 | console.log("Precomputed size: " + size); 36 | }); 37 | 38 | reader.on("constants", function (nI32, nF32, nF64) { 39 | console.log("Constants: " + nI32 + "xI32, " + nF32 + "xF32, " + nF64 + "xF64"); 40 | }); 41 | 42 | reader.on("constant", function (constant) { 43 | console.log(constant.toString()); 44 | }); 45 | 46 | reader.on("constantsEnd", function () { 47 | console.log("End of constants"); 48 | }); 49 | 50 | reader.on("functionSignatures", function (nSigs) { 51 | console.log("Signatures: " + nSigs); 52 | }); 53 | 54 | reader.on("functionSignature", function (signature) { 55 | console.log(signature.toString()); 56 | }); 57 | 58 | reader.on("functionImports", function (nFunctionImports, nSignatures) { 59 | console.log("Function imports: " + nFunctionImports + " (" + nSignatures + " signatures)"); 60 | }); 61 | 62 | reader.on("functionImport", function (fimport) { 63 | console.log(fimport.toString()); 64 | }); 65 | 66 | reader.on("functionImportsEnd", function () { 67 | console.log("End of function imports"); 68 | }); 69 | 70 | reader.on("globalVariables", function (nI32zero, nF32zero, nF64zero, nI32import, nF32import, nF64import) { 71 | console.log("Global vars: " + [nI32zero, nF32zero, nF64zero, nI32import, nF32import, nF64import]); 72 | }); 73 | 74 | reader.on("globalVariable", function (variable) { 75 | console.log(variable.toString()); 76 | }); 77 | 78 | reader.on("globalVariablesEnd", function () { 79 | console.log("End of global variables"); 80 | }); 81 | 82 | reader.on("functionDeclarations", function (nDeclarations) { 83 | console.log("Function declarations: " + nDeclarations); 84 | }); 85 | 86 | reader.on("functionDeclaration", function (declaration) { 87 | console.log(declaration.toString()); 88 | }); 89 | 90 | reader.on("functionDeclarationsEnd", function () { 91 | console.log("End of function declarations"); 92 | }); 93 | 94 | reader.on("functionPointerTables", function (nTables) { 95 | console.log("Function pointer tables: " + nTables); 96 | }); 97 | 98 | reader.on("functionPointerTable", function (table) { 99 | console.log(table.toString()); 100 | }); 101 | 102 | reader.on("functionPointerTablesEnd", function () { 103 | console.log("End of function pointer tables"); 104 | }); 105 | 106 | reader.on("functionDefinitions", function (nDefinitions) { 107 | console.log("Function definitions: " + nDefinitions); 108 | }); 109 | 110 | reader.on("functionDefinition", function (definition) { 111 | console.log(definition.asmHeader() + "\n"); 112 | }); 113 | 114 | reader.on("functionDefinitionsEnd", function () { 115 | console.log("End of function definitions"); 116 | }); 117 | 118 | reader.on("export", function (exprt) { 119 | console.log("Export: " + exprt.toString()); 120 | }); 121 | } 122 | 123 | reader.on("end", function() { 124 | if (reader.offset !== stats.size) 125 | throw Error("reader offset != size: "+reader.offset+" != "+stats.size); 126 | console.log("Complete: "+reader.assembly.toString()+"\n"); 127 | 128 | if (verbose) 129 | console.log(reader.assembly.asmHeader(), "\n"); 130 | 131 | console.log("Validating assembly ..."); 132 | try { 133 | reader.assembly.validate(); 134 | } catch (err) { 135 | if (err instanceof assert.AssertionError) { 136 | console.log("actual: "+err.actual); 137 | console.log("expected: "+err.expected); 138 | } 139 | throw err; 140 | } 141 | console.log("Success\n"); 142 | validateAstOffsets(); 143 | }); 144 | 145 | console.log("Indexing assembly ..."); 146 | fs.createReadStream(file).pipe(reader); 147 | 148 | function validateAstOffsets() { 149 | console.log("Reading ASTs ..."); 150 | 151 | var assembly = reader.assembly; 152 | var stats = fs.statSync(file); 153 | var current = 0; 154 | 155 | function next() { 156 | if (current === assembly.functionDeclarations.length) { 157 | console.log("Complete: "+current+" ASTs\n"); 158 | validateAstRewrite(assembly); 159 | return; 160 | } 161 | var declaration = assembly.functionDeclarations[current++], 162 | definition = declaration.definition; 163 | var offset = definition.byteOffset, 164 | length = definition.byteLength, 165 | n = 0; 166 | if (length < 0) 167 | throw Error("length "+length+" < 0"); 168 | if (offset + length > stats.size) 169 | throw Error("offset + length "+(offset+length)+" > "+stats.size); 170 | if (verbose) 171 | console.log("Reading AST of "+definition+" @ "+definition.byteOffset.toString(16)); 172 | var astReader = new AstReader(definition); 173 | astReader.on("ast", function(ast) { 174 | if (verbose) 175 | console.log("AST read complete: "+n+" statements"); 176 | definition.ast = ast; 177 | }); 178 | astReader.on("stmt", function(stmt) { 179 | ++n; 180 | }); 181 | astReader.on("end", function() { 182 | next(); 183 | }); 184 | fs.createReadStream(file, { 185 | start: offset, 186 | end: offset + length 187 | }).pipe(astReader); 188 | } 189 | 190 | next(); 191 | } 192 | 193 | function validateAstRewrite(assembly) { 194 | console.log("Validating AST rewrite ..."); 195 | var contents = fs.readFileSync(file), 196 | current = 0; 197 | 198 | function next() { 199 | if (current >= assembly.functionDeclarations.length) { 200 | console.log("Success\n"); 201 | write(assembly); 202 | return; 203 | } 204 | var definition = assembly.functionDeclarations[current].definition, 205 | astContents = contents.slice(definition.byteOffset, definition.byteOffset + definition.byteLength); 206 | var writer = new AstWriter(definition, { preserveWithImm: true }), 207 | offset = 0, 208 | n = 0; 209 | if (verbose) 210 | console.log("Writing AST of "+definition); 211 | writer.on("data", function(chunk) { 212 | for (var i=0; i"+state+" @ "+offset.toString(16)); 252 | }); 253 | writer.on("data", function(chunk) { 254 | if (verbose && wi++%100 === 0) 255 | process.stdout.write("."); 256 | for (var i=0; i 23 | */ 24 | 25 | /** 26 | BEGIN_NODE_INCLUDE 27 | var assert = require('assert'); 28 | END_NODE_INCLUDE 29 | */ 30 | 31 | /** 32 | * @param {*} value 33 | * @param {string} message 34 | * @throws {assert.AssertionError} 35 | */ 36 | var assert = function(value, message) {}; 37 | 38 | /** 39 | * @param {{message: string, actual: *, expected: *, operator: string}} options 40 | * @constructor 41 | * @extends Error 42 | */ 43 | assert.AssertionError = function(options) {}; 44 | 45 | /** 46 | * @return {string} 47 | */ 48 | assert.AssertionError.prototype.toString = function() {}; 49 | 50 | /** 51 | * @param {*} value 52 | * @param {string=} message 53 | * @throws {assert.AssertionError} 54 | */ 55 | assert.ok = function(value, message) {}; 56 | 57 | /** 58 | * @param {*} actual 59 | * @param {*} expected 60 | * @param {string} message 61 | * @param {string} operator 62 | * @throws {assert.AssertionError} 63 | */ 64 | assert.fail = function(actual, expected, message, operator) {}; 65 | 66 | /** 67 | * @param {*} actual 68 | * @param {*} expected 69 | * @param {string=} message 70 | * @throws {assert.AssertionError} 71 | */ 72 | assert.equal = function(actual, expected, message) {}; 73 | 74 | /** 75 | * @param {*} actual 76 | * @param {*} expected 77 | * @param {string=} message 78 | * @throws {assert.AssertionError} 79 | */ 80 | assert.notEqual = function(actual, expected, message) {}; 81 | 82 | /** 83 | * @param {*} actual 84 | * @param {*} expected 85 | * @param {string=} message 86 | * @throws {assert.AssertionError} 87 | */ 88 | assert.deepEqual = function(actual, expected, message) {}; 89 | 90 | /** 91 | * @param {*} actual 92 | * @param {*} expected 93 | * @param {string=} message 94 | * @throws {assert.AssertionError} 95 | */ 96 | assert.notDeepEqual = function(actual, expected, message) {}; 97 | 98 | /** 99 | * @param {*} actual 100 | * @param {*} expected 101 | * @param {string=} message 102 | * @throws {assert.AssertionError} 103 | */ 104 | assert.strictEqual = function(actual, expected, message) {}; 105 | 106 | /** 107 | * @param {*} actual 108 | * @param {*} expected 109 | * @param {string=} message 110 | * @throws {assert.AssertionError} 111 | */ 112 | assert.notStrictEqual = function(actual, expected, message) {}; 113 | 114 | /** 115 | * @name assert.throws 116 | * @function 117 | * @param {function()} block 118 | * @param {Function|RegExp|function(*)} error 119 | * @param {string=} message 120 | * @throws {assert.AssertionError} 121 | */ 122 | // Error: .\assert.js:120: ERROR - Parse error. missing name after . operator 123 | // assert.throws = function(block, error, message) {}; 124 | 125 | /** 126 | * @param {function()} block 127 | * @param {Function|RegExp|function(*)} error 128 | * @param {string=} message 129 | * @throws {assert.AssertionError} 130 | */ 131 | assert.doesNotThrow = function(block, error, message) {}; 132 | 133 | /** 134 | * @param {*} value 135 | * @throws {assert.AssertionError} 136 | */ 137 | assert.ifError = function(value) {}; -------------------------------------------------------------------------------- /tools/externs/errors.js: -------------------------------------------------------------------------------- 1 | function Error(message) {} 2 | function TypeError(message) {} 3 | function RangeError(message) {} 4 | -------------------------------------------------------------------------------- /tools/opcodes-md-template.js: -------------------------------------------------------------------------------- 1 | var types = require("../src/types"), 2 | stmt = require("../src/stmt/"); 3 | 4 | var classes = { 5 | "Stmt": [ypes.Stmt, types.StmtWithImm, stmt.Stmt], 6 | "Expr": [types.I32, types.I32WithImm, stmt.ExprI32], 7 | "Expr": [types.F32, types.F32WithImm, stmt.ExprF32], 8 | "Expr": [types.F64, types.F64WithImm, stmt.ExprF64], 9 | "Expr": [types.Void, null, stmt.ExprVoid], 10 | "SwitchCase": [types.SwitchCase, null, stmt.SwitchCase] 11 | }; 12 | 13 | var md = []; 14 | 15 | function escapeHtml(s) { 16 | return s.replace(//g, ">") 18 | .replace(/"/g, """); 19 | } 20 | 21 | function codeTemplate(md, name, code, withImm, ctor) { 22 | md.push("| **", escapeHtml(name), "** | ", code.toString(10), " | "); 23 | var behavior = ctor.determineBehavior(code, withImm); 24 | md.push(escapeHtml(behavior.name), " | ", escapeHtml(behavior.description), "\n"); 25 | } 26 | 27 | Object.keys(classes).forEach(function (name) { 28 | md.push(escapeHtml(name), "\n-----\n\n"); 29 | var ctor = classes[name][2]; 30 | if (classes[name][0]) { 31 | md.push("### Opcode without Imm\n\n"); 32 | md.push("| Name | Code | Behavior | Description\n"); 33 | md.push("|------|------|----------|-------------\n"); 34 | Object.keys(classes[name][0]).forEach(function (codeName) { 35 | codeTemplate(md, codeName, classes[name][0][codeName], false, ctor); 36 | }); 37 | md.push("\n"); 38 | } 39 | if (classes[name][1]) { 40 | md.push("### Opcode with Imm\n\n"); 41 | md.push("| Name | Code | Behavior | Description\n"); 42 | md.push("|------|------|----------|-------------\n"); 43 | Object.keys(classes[name][1]).forEach(function (codeName) { 44 | codeTemplate(md, codeName, classes[name][1][codeName], true, ctor); 45 | }); 46 | md.push("\n"); 47 | } 48 | }); 49 | 50 | process.stdout.write(md.join(""), "utf8"); 51 | --------------------------------------------------------------------------------