├── .gitignore ├── .travis.yml ├── Contributing.md ├── LICENSE ├── README.md ├── src └── wasm │ ├── asm-wasm-builder.cc │ ├── asm-wasm-builder.h │ ├── ast-decoder.cc │ ├── ast-decoder.h │ ├── decoder.h │ ├── encoder.cc │ ├── encoder.h │ ├── module-decoder.cc │ ├── module-decoder.h │ ├── wasm-compiler.cc │ ├── wasm-compiler.h │ ├── wasm-js.cc │ ├── wasm-js.h │ ├── wasm-linkage.cc │ ├── wasm-macro-gen.h │ ├── wasm-module.cc │ ├── wasm-module.h │ ├── wasm-opcodes.cc │ ├── wasm-opcodes.h │ ├── wasm-result.cc │ ├── wasm-result.h │ └── wasm.gyp ├── test ├── cctest │ └── wasm │ │ ├── test-run-wasm-module.cc │ │ ├── test-run-wasm.cc │ │ ├── test-signatures.h │ │ └── wasm.gyp ├── mjsunit │ └── wasm │ │ ├── asm-wasm.js │ │ ├── calls.js │ │ ├── compile-run-basic.js │ │ ├── divrem-trap.js │ │ ├── ffi-error.js │ │ ├── ffi.js │ │ ├── indirect-calls.js │ │ ├── instantiate-module-basic.js │ │ ├── module-memory.js │ │ ├── params.js │ │ ├── stackwalk.js │ │ ├── unreachable.js │ │ ├── verify-function-basic-errors.js │ │ ├── verify-function-simple.js │ │ ├── verify-module-basic-errors.js │ │ ├── wasm-constants.js │ │ └── wasm-object-api.js └── unittests │ └── wasm │ ├── ast-decoder-unittest.cc │ ├── encoder-unittest.cc │ ├── module-decoder-unittest.cc │ ├── wasm-macro-gen-unittest.cc │ └── wasm.gyp └── travis ├── build-and-test.sh └── install-dependencies.sh /.gitignore: -------------------------------------------------------------------------------- 1 | depot_tools 2 | v8 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c++ 2 | 3 | sudo: off 4 | 5 | install: ./travis/install-dependencies.sh 6 | 7 | script: 8 | - ./travis/build-and-test.sh 9 | 10 | compiler: 11 | - clang 12 | 13 | os: 14 | - linux 15 | - osx 16 | -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to WebAssembly 2 | 3 | Interested in participating? Please follow 4 | [the same contributing guidelines as the design repository][]. 5 | 6 | [the same contributing guidelines as the design repository]: https://github.com/WebAssembly/design/blob/master/Contributing.md 7 | 8 | Also, please be sure to read [the README.md](README.md) for this repository. 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This license applies to all parts of V8 that are not externally 2 | maintained libraries. The externally maintained libraries used by V8 3 | are: 4 | 5 | - PCRE test suite, located in 6 | test/mjsunit/third_party/regexp-pcre/regexp-pcre.js. This is based on the 7 | test suite from PCRE-7.3, which is copyrighted by the University 8 | of Cambridge and Google, Inc. The copyright notice and license 9 | are embedded in regexp-pcre.js. 10 | 11 | - Layout tests, located in test/mjsunit/third_party/object-keys. These are 12 | based on layout tests from webkit.org which are copyrighted by 13 | Apple Computer, Inc. and released under a 3-clause BSD license. 14 | 15 | - Strongtalk assembler, the basis of the files assembler-arm-inl.h, 16 | assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h, 17 | assembler-ia32.cc, assembler-ia32.h, assembler-x64-inl.h, 18 | assembler-x64.cc, assembler-x64.h, assembler-mips-inl.h, 19 | assembler-mips.cc, assembler-mips.h, assembler.cc and assembler.h. 20 | This code is copyrighted by Sun Microsystems Inc. and released 21 | under a 3-clause BSD license. 22 | 23 | - Valgrind client API header, located at third_party/valgrind/valgrind.h 24 | This is release under the BSD license. 25 | 26 | These libraries have their own licenses; we recommend you read them, 27 | as their terms may differ from the terms below. 28 | 29 | Further license information can be found in LICENSE files located in 30 | sub-directories. 31 | 32 | Copyright 2014, the V8 project authors. All rights reserved. 33 | Redistribution and use in source and binary forms, with or without 34 | modification, are permitted provided that the following conditions are 35 | met: 36 | 37 | * Redistributions of source code must retain the above copyright 38 | notice, this list of conditions and the following disclaimer. 39 | * Redistributions in binary form must reproduce the above 40 | copyright notice, this list of conditions and the following 41 | disclaimer in the documentation and/or other materials provided 42 | with the distribution. 43 | * Neither the name of Google Inc. nor the names of its 44 | contributors may be used to endorse or promote products derived 45 | from this software without specific prior written permission. 46 | 47 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 48 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 49 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 50 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 51 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 52 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 53 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 54 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 55 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 56 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 57 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # The code of this project has been moved into the
[V8 repository](https://github.com/v8/v8). 4 | 5 | ## WebAssembly V8 Native Prototype 6 | 7 | This repository contains additional source code needed to build a prototype 8 | implementation of WebAssembly incorporated into V8. 9 | 10 | To build: 11 | 12 | * Install depot_tools: 13 | http://dev.chromium.org/developers/how-tos/install-depot-tools 14 | * Checkout this prototype: 15 | ``` 16 | git clone https://github.com/WebAssembly/v8-native-prototype.git 17 | ``` 18 | * Checkout V8: 19 | ``` 20 | mkdir v8 21 | cd v8 22 | fetch v8 23 | cd v8 24 | ``` 25 | * Add symlinks to prototype from v8: 26 | ``` 27 | ln -fs $PWD/../../v8-native-prototype third_party/wasm 28 | ln -fs $PWD/../../v8-native-prototype test/mjsunit/wasm 29 | ``` 30 | * make x64.debug wasm=on 31 | -------------------------------------------------------------------------------- /src/wasm/asm-wasm-builder.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_ASM_WASM_BUILDER_H_ 6 | #define V8_WASM_ASM_WASM_BUILDER_H_ 7 | 8 | #include "src/allocation.h" 9 | #include "src/zone.h" 10 | #include "src/wasm/encoder.h" 11 | 12 | namespace v8 { 13 | namespace internal { 14 | 15 | class FunctionLiteral; 16 | 17 | namespace wasm { 18 | 19 | class AsmWasmBuilder { 20 | public: 21 | explicit AsmWasmBuilder(Isolate* isolate, Zone* zone, FunctionLiteral* root); 22 | WasmModuleIndex* Run(); 23 | 24 | private: 25 | Isolate* isolate_; 26 | Zone* zone_; 27 | FunctionLiteral* literal_; 28 | }; 29 | } 30 | } 31 | } 32 | 33 | #endif // V8_WASM_ASM_WASM_BUILDER_H_ 34 | -------------------------------------------------------------------------------- /src/wasm/ast-decoder.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_AST_DECODER_H_ 6 | #define V8_WASM_AST_DECODER_H_ 7 | 8 | #include "src/signature.h" 9 | #include "src/wasm/wasm-opcodes.h" 10 | #include "src/wasm/wasm-result.h" 11 | 12 | namespace v8 { 13 | namespace internal { 14 | 15 | namespace compiler { // external declarations from compiler. 16 | class WasmGraphBuilder; 17 | } 18 | 19 | namespace wasm { 20 | 21 | typedef compiler::WasmGraphBuilder TFBuilder; 22 | struct ModuleEnv; // forward declaration of module interface. 23 | 24 | // Interface the function environment during decoding, include the signature 25 | // and number of locals. 26 | struct FunctionEnv { 27 | ModuleEnv* module; // module environment 28 | FunctionSig* sig; // signature of this function 29 | uint32_t local_int32_count; // number of int32 locals 30 | uint32_t local_int64_count; // number of int64 locals 31 | uint32_t local_float32_count; // number of float32 locals 32 | uint32_t local_float64_count; // number of float64 locals 33 | uint32_t total_locals; // sum of parameters and all locals 34 | 35 | bool IsValidLocal(uint32_t index) { return index < total_locals; } 36 | uint32_t GetLocalCount() { return total_locals; } 37 | LocalType GetLocalType(uint32_t index) { 38 | if (index < sig->parameter_count()) return sig->GetParam(index); 39 | index -= sig->parameter_count(); 40 | if (index < local_int32_count) return kAstI32; 41 | index -= local_int32_count; 42 | if (index < local_int64_count) return kAstI64; 43 | index -= local_int64_count; 44 | if (index < local_float32_count) return kAstF32; 45 | index -= local_float32_count; 46 | if (index < local_float64_count) return kAstF64; 47 | return kAstStmt; 48 | } 49 | 50 | void AddLocals(LocalType type, uint32_t count) { 51 | switch (type) { 52 | case kAstI32: 53 | local_int32_count += count; 54 | break; 55 | case kAstI64: 56 | local_int64_count += count; 57 | break; 58 | case kAstF32: 59 | local_float32_count += count; 60 | break; 61 | case kAstF64: 62 | local_float64_count += count; 63 | break; 64 | default: 65 | UNREACHABLE(); 66 | } 67 | total_locals += count; 68 | DCHECK(total_locals == 69 | (sig->parameter_count() + local_int32_count + local_int64_count + 70 | local_float32_count + local_float64_count)); 71 | } 72 | 73 | void SumLocals() { 74 | total_locals = static_cast(sig->parameter_count()) + 75 | local_int32_count + local_int64_count + local_float32_count + 76 | local_float64_count; 77 | } 78 | }; 79 | 80 | struct Tree; 81 | typedef Result TreeResult; 82 | 83 | std::ostream& operator<<(std::ostream& os, const Tree& tree); 84 | 85 | TreeResult VerifyWasmCode(FunctionEnv* env, const byte* base, const byte* start, 86 | const byte* end); 87 | TreeResult BuildTFGraph(TFBuilder* builder, FunctionEnv* env, const byte* base, 88 | const byte* start, const byte* end); 89 | 90 | inline TreeResult VerifyWasmCode(FunctionEnv* env, const byte* start, 91 | const byte* end) { 92 | return VerifyWasmCode(env, nullptr, start, end); 93 | } 94 | 95 | inline TreeResult BuildTFGraph(TFBuilder* builder, FunctionEnv* env, 96 | const byte* start, const byte* end) { 97 | return BuildTFGraph(builder, env, nullptr, start, end); 98 | } 99 | 100 | enum ReadUnsignedLEB128ErrorCode { kNoError, kInvalidLEB128, kMissingLEB128 }; 101 | 102 | ReadUnsignedLEB128ErrorCode ReadUnsignedLEB128Operand(const byte*, const byte*, 103 | int*, uint32_t*); 104 | 105 | // Computes the length of the opcode at the given address. 106 | int OpcodeLength(const byte* pc); 107 | 108 | // Computes the arity (number of sub-nodes) of the opcode at the given address. 109 | int OpcodeArity(FunctionEnv* env, const byte* pc); 110 | } 111 | } 112 | } 113 | 114 | #endif // V8_WASM_AST_DECODER_H_ 115 | -------------------------------------------------------------------------------- /src/wasm/decoder.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_DECODER_H_ 6 | #define V8_WASM_DECODER_H_ 7 | 8 | #include "src/signature.h" 9 | #include "src/zone-containers.h" 10 | #include "src/base/smart-pointers.h" 11 | #include "src/wasm/wasm-result.h" 12 | #include "src/flags.h" 13 | 14 | namespace v8 { 15 | namespace internal { 16 | namespace wasm { 17 | 18 | #if DEBUG 19 | #define TRACE(...) \ 20 | do { \ 21 | if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 22 | } while (false) 23 | #else 24 | #define TRACE(...) 25 | #endif 26 | 27 | // A helper utility to decode bytes, integers, fields, varints, etc, from 28 | // a buffer of bytes. 29 | class Decoder { 30 | public: 31 | Decoder(const byte* start, const byte* end) 32 | : start_(start), 33 | pc_(start), 34 | limit_(end), 35 | error_pc_(nullptr), 36 | error_pt_(nullptr) {} 37 | 38 | virtual ~Decoder() {} 39 | 40 | // Reads a 8-bit unsigned integer (byte) and advances {pc_}. 41 | uint8_t u8(const char* name = nullptr) { 42 | TRACE(" +%d %-20s: ", static_cast(pc_ - start_), 43 | name ? name : "uint8_t"); 44 | if (checkAvailable(1)) { 45 | byte val = *(pc_++); 46 | TRACE("%02x = %d\n", val, val); 47 | return val; 48 | } else { 49 | error("expected 1 byte, but fell off end"); 50 | return traceOffEnd(); 51 | } 52 | } 53 | 54 | // Reads a 16-bit unsigned integer (little endian) and advances {pc_}. 55 | uint16_t u16(const char* name = nullptr) { 56 | TRACE(" +%d %-20s: ", static_cast(pc_ - start_), 57 | name ? name : "uint16_t"); 58 | if (checkAvailable(2)) { 59 | #ifdef V8_TARGET_LITTLE_ENDIAN 60 | byte b0 = pc_[0]; 61 | byte b1 = pc_[1]; 62 | #else 63 | byte b1 = pc_[0]; 64 | byte b0 = pc_[1]; 65 | #endif 66 | uint16_t val = static_cast(b1 << 8) | b0; 67 | TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val); 68 | pc_ += 2; 69 | return val; 70 | } else { 71 | error("expected 2 bytes, but fell off end"); 72 | return traceOffEnd(); 73 | } 74 | } 75 | 76 | // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}. 77 | uint32_t u32(const char* name = nullptr) { 78 | TRACE(" +%d %-20s: ", static_cast(pc_ - start_), 79 | name ? name : "uint32_t"); 80 | if (checkAvailable(4)) { 81 | #ifdef V8_TARGET_LITTLE_ENDIAN 82 | byte b0 = pc_[0]; 83 | byte b1 = pc_[1]; 84 | byte b2 = pc_[2]; 85 | byte b3 = pc_[3]; 86 | #else 87 | byte b3 = pc_[0]; 88 | byte b2 = pc_[1]; 89 | byte b1 = pc_[2]; 90 | byte b0 = pc_[3]; 91 | #endif 92 | uint32_t val = static_cast(b3 << 24) | 93 | static_cast(b2 << 16) | 94 | static_cast(b1 << 8) | b0; 95 | TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val); 96 | pc_ += 4; 97 | return val; 98 | } else { 99 | error("expected 4 bytes, but fell off end"); 100 | return traceOffEnd(); 101 | } 102 | } 103 | 104 | // Reads a LEB128 variable-length 32-bit integer and advances {pc_}. 105 | uint32_t u32v(int* length, const char* name = nullptr) { 106 | TRACE(" +%d %-20s: ", static_cast(pc_ - start_), 107 | name ? name : "varint"); 108 | 109 | if (!checkAvailable(1)) { 110 | error("expected at least 1 byte, but fell off end"); 111 | return traceOffEnd(); 112 | } 113 | 114 | const byte* pos = pc_; 115 | const byte* end = pc_ + 5; 116 | if (end > limit_) end = limit_; 117 | 118 | uint32_t result = 0; 119 | int shift = 0; 120 | byte b = 0; 121 | while (pc_ < end) { 122 | b = *pc_++; 123 | TRACE("%02x ", b); 124 | result = result | ((b & 0x7F) << shift); 125 | if ((b & 0x80) == 0) break; 126 | shift += 7; 127 | } 128 | 129 | *length = static_cast(pc_ - pos); 130 | if (pc_ == end && (b & 0x80)) { 131 | error(pc_ - 1, "varint too large"); 132 | } else { 133 | TRACE("= %u\n", result); 134 | } 135 | return result; 136 | } 137 | 138 | // Check that at least {size} bytes exist between {pc_} and {limit_}. 139 | bool checkAvailable(int size) { 140 | if (pc_ < start_ || (pc_ + size) > limit_) { 141 | error(pc_, nullptr, "expected %d bytes, fell off end", size); 142 | return false; 143 | } else { 144 | return true; 145 | } 146 | } 147 | 148 | void error(const char* msg) { error(pc_, nullptr, msg); } 149 | 150 | void error(const byte* pc, const char* msg) { error(pc, nullptr, msg); } 151 | 152 | // Sets internal error state. 153 | void error(const byte* pc, const byte* pt, const char* format, ...) { 154 | if (ok()) { 155 | #if DEBUG 156 | if (FLAG_wasm_break_on_decoder_error) { 157 | base::OS::DebugBreak(); 158 | } 159 | #endif 160 | const int kMaxErrorMsg = 256; 161 | char* buffer = new char[kMaxErrorMsg]; 162 | va_list arguments; 163 | va_start(arguments, format); 164 | base::OS::VSNPrintF(buffer, kMaxErrorMsg - 1, format, arguments); 165 | va_end(arguments); 166 | error_msg_.Reset(buffer); 167 | error_pc_ = pc; 168 | error_pt_ = pt; 169 | onFirstError(); 170 | } 171 | } 172 | 173 | // Behavior triggered on first error, overridden in subclasses. 174 | virtual void onFirstError() {} 175 | 176 | // Debugging helper to print bytes up to the end. 177 | template 178 | T traceOffEnd() { 179 | T t = 0; 180 | for (const byte* ptr = pc_; ptr < limit_; ptr++) { 181 | TRACE("%02x ", *ptr); 182 | } 183 | TRACE("\n"); 184 | pc_ = limit_; 185 | return t; 186 | } 187 | 188 | // Converts the given value to a {Result}, copying the error if necessary. 189 | template 190 | Result toResult(T val) { 191 | Result result; 192 | if (error_pc_) { 193 | result.error_code = kError; 194 | result.start = start_; 195 | result.error_pc = error_pc_; 196 | result.error_pt = error_pt_; 197 | result.error_msg = error_msg_; 198 | error_msg_.Reset(nullptr); 199 | } else { 200 | result.error_code = kSuccess; 201 | result.val = val; 202 | } 203 | return result; 204 | } 205 | 206 | // Resets the boundaries of this decoder. 207 | void Reset(const byte* start, const byte* end) { 208 | start_ = start; 209 | pc_ = start; 210 | limit_ = end; 211 | error_pc_ = nullptr; 212 | error_pt_ = nullptr; 213 | error_msg_.Reset(nullptr); 214 | } 215 | 216 | bool ok() const { return error_pc_ == nullptr; } 217 | bool failed() const { return error_pc_ != nullptr; } 218 | 219 | protected: 220 | const byte* start_; 221 | const byte* pc_; 222 | const byte* limit_; 223 | const byte* error_pc_; 224 | const byte* error_pt_; 225 | base::SmartArrayPointer error_msg_; 226 | }; 227 | 228 | #undef TRACE 229 | } 230 | } 231 | } 232 | 233 | #endif // V8_WASM_DECODER_H_ 234 | -------------------------------------------------------------------------------- /src/wasm/encoder.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "src/signature.h" 6 | 7 | #include "src/v8.h" 8 | #include "src/handles.h" 9 | #include "src/zone-containers.h" 10 | 11 | #include "src/wasm/ast-decoder.h" 12 | #include "src/wasm/encoder.h" 13 | #include "src/wasm/wasm-module.h" 14 | #include "src/wasm/wasm-opcodes.h" 15 | 16 | #include "src/v8memory.h" 17 | 18 | namespace v8 { 19 | namespace internal { 20 | namespace wasm { 21 | 22 | /*TODO: add error cases for adding too many locals, too many functions and bad 23 | indices in body */ 24 | 25 | namespace { 26 | void EmitUint8(byte** b, uint8_t x) { 27 | Memory::uint8_at(*b) = x; 28 | *b += 1; 29 | } 30 | 31 | void EmitUint16(byte** b, uint16_t x) { 32 | Memory::uint16_at(*b) = x; 33 | *b += 2; 34 | } 35 | 36 | void EmitUint32(byte** b, uint32_t x) { 37 | Memory::uint32_at(*b) = x; 38 | *b += 4; 39 | } 40 | 41 | void EmitVarInt(byte** b, size_t val) { 42 | while (true) { 43 | size_t next = val >> 7; 44 | byte out = static_cast(val & 0x7f); 45 | if (next) { 46 | *((*b)++) = 0x80 | out; 47 | val = next; 48 | } else { 49 | *((*b)++) = out; 50 | break; 51 | } 52 | } 53 | } 54 | } 55 | 56 | struct WasmFunctionBuilder::Type { 57 | bool param_; 58 | LocalType type_; 59 | }; 60 | 61 | WasmFunctionBuilder::WasmFunctionBuilder(Zone* zone, 62 | const unsigned char* name, 63 | int name_length) 64 | : return_type_(kAstI32), 65 | locals_(zone), 66 | exported_(0), 67 | external_(0), 68 | body_(zone), 69 | local_indices_(zone), 70 | name_(zone) { 71 | if (name_length > 0) { 72 | for (int i = 0; i < name_length; i++) { 73 | name_.push_back(*(name + i)); 74 | } 75 | name_.push_back('\0'); 76 | } 77 | } 78 | 79 | uint16_t WasmFunctionBuilder::AddParam(LocalType type) { 80 | return AddVar(type, true); 81 | } 82 | 83 | uint16_t WasmFunctionBuilder::AddLocal(LocalType type) { 84 | return AddVar(type, false); 85 | } 86 | 87 | uint16_t WasmFunctionBuilder::AddVar(LocalType type, bool param) { 88 | locals_.push_back({param, type}); 89 | return static_cast(locals_.size() - 1); 90 | } 91 | 92 | void WasmFunctionBuilder::ReturnType(LocalType type) { return_type_ = type; } 93 | 94 | void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) { 95 | EmitCode(code, code_size, NULL, 0); 96 | } 97 | 98 | void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size, 99 | const uint32_t* local_indices, 100 | uint32_t indices_size) { 101 | size_t size = body_.size(); 102 | for (size_t i = 0; i < code_size; i++) { 103 | body_.push_back(code[i]); 104 | } 105 | for (size_t i = 0; i < indices_size; i++) { 106 | local_indices_.push_back(local_indices[i] + static_cast(size)); 107 | } 108 | } 109 | 110 | void WasmFunctionBuilder::Emit(WasmOpcode opcode) { 111 | body_.push_back(static_cast(opcode)); 112 | } 113 | 114 | void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) { 115 | body_.push_back(static_cast(opcode)); 116 | body_.push_back(immediate); 117 | } 118 | 119 | void WasmFunctionBuilder::EmitWithLocal(WasmOpcode opcode) { 120 | body_.push_back(static_cast(opcode)); 121 | local_indices_.push_back(static_cast(body_.size()) - 1); 122 | } 123 | 124 | uint32_t WasmFunctionBuilder::EmitEditableImmediate(const byte immediate) { 125 | body_.push_back(immediate); 126 | return static_cast(body_.size()) - 1; 127 | } 128 | 129 | void WasmFunctionBuilder::EditImmediate(uint32_t offset, const byte immediate) { 130 | DCHECK(offset < body_.size()); 131 | body_[offset] = immediate; 132 | } 133 | 134 | void WasmFunctionBuilder::Exported(uint8_t flag) { exported_ = flag; } 135 | 136 | void WasmFunctionBuilder::External(uint8_t flag) { external_ = flag; } 137 | 138 | WasmFunctionEncoder* WasmFunctionBuilder::Build(Zone* zone, 139 | WasmModuleBuilder* mb) const { 140 | WasmFunctionEncoder* e = 141 | new (zone) WasmFunctionEncoder(zone, return_type_, exported_, external_); 142 | auto var_index = new uint16_t[locals_.size()]; 143 | IndexVars(e, var_index); 144 | const byte* start = body_.data(); 145 | const byte* end = start + body_.size(); 146 | size_t local_index = 0; 147 | for (size_t i = 0; i < body_.size();) { 148 | if (local_index < local_indices_.size() && 149 | i == local_indices_[local_index]) { 150 | int length = 0; 151 | uint32_t index; 152 | ReadUnsignedLEB128Operand(start + i, end, &length, &index); 153 | uint16_t new_index = var_index[index]; 154 | const std::vector& index_vec = UnsignedLEB128From(new_index); 155 | for (size_t j = 0; j < index_vec.size(); j++) { 156 | e->body_.push_back(index_vec.at(j)); 157 | } 158 | i += length; 159 | local_index++; 160 | } else { 161 | e->body_.push_back(*(start + i)); 162 | i++; 163 | } 164 | } 165 | FunctionSig::Builder sig(zone, return_type_ == kAstStmt ? 0 : 1, 166 | e->params_.size()); 167 | if (return_type_ != kAstStmt) { 168 | sig.AddReturn(static_cast(return_type_)); 169 | } 170 | for (size_t i = 0; i < e->params_.size(); i++) { 171 | sig.AddParam(static_cast(e->params_[i])); 172 | } 173 | e->signature_index_ = mb->AddSignature(sig.Build()); 174 | delete[] var_index; 175 | e->name_.insert(e->name_.begin(), name_.begin(), name_.end()); 176 | return e; 177 | } 178 | 179 | void WasmFunctionBuilder::IndexVars(WasmFunctionEncoder* e, 180 | uint16_t* var_index) const { 181 | uint16_t param = 0; 182 | uint16_t int32 = 0; 183 | uint16_t int64 = 0; 184 | uint16_t float32 = 0; 185 | uint16_t float64 = 0; 186 | for (size_t i = 0; i < locals_.size(); i++) { 187 | if (locals_.at(i).param_) { 188 | param++; 189 | } else if (locals_.at(i).type_ == kAstI32) { 190 | int32++; 191 | } else if (locals_.at(i).type_ == kAstI64) { 192 | int64++; 193 | } else if (locals_.at(i).type_ == kAstF32) { 194 | float32++; 195 | } else if (locals_.at(i).type_ == kAstF64) { 196 | float64++; 197 | } 198 | } 199 | e->local_int32_count_ = int32; 200 | e->local_int64_count_ = int64; 201 | e->local_float32_count_ = float32; 202 | e->local_float64_count_ = float64; 203 | float64 = param + int32 + int64 + float32; 204 | float32 = param + int32 + int64; 205 | int64 = param + int32; 206 | int32 = param; 207 | param = 0; 208 | for (size_t i = 0; i < locals_.size(); i++) { 209 | if (locals_.at(i).param_) { 210 | e->params_.push_back(locals_.at(i).type_); 211 | var_index[i] = param++; 212 | } else if (locals_.at(i).type_ == kAstI32) { 213 | var_index[i] = int32++; 214 | } else if (locals_.at(i).type_ == kAstI64) { 215 | var_index[i] = int64++; 216 | } else if (locals_.at(i).type_ == kAstF32) { 217 | var_index[i] = float32++; 218 | } else if (locals_.at(i).type_ == kAstF64) { 219 | var_index[i] = float64++; 220 | } 221 | } 222 | } 223 | 224 | WasmFunctionEncoder::WasmFunctionEncoder(Zone* zone, LocalType return_type, 225 | bool exported, bool external) 226 | : params_(zone), exported_(exported), external_(external), body_(zone), 227 | name_(zone) {} 228 | 229 | uint32_t WasmFunctionEncoder::HeaderSize() const { 230 | uint32_t size = 3; 231 | if (HasLocals()) size += 8; 232 | if (!external_) size += 2; 233 | if (HasName()) size += 4; 234 | return size; 235 | } 236 | 237 | uint32_t WasmFunctionEncoder::BodySize(void) const { 238 | return external_ ? 0 : static_cast(body_.size()); 239 | } 240 | 241 | uint32_t WasmFunctionEncoder::NameSize() const { 242 | return exported_ ? static_cast(name_.size()) : 0; 243 | } 244 | 245 | void WasmFunctionEncoder::Serialize(byte* buffer, byte** header, 246 | byte** body) const { 247 | uint8_t decl_bits = (exported_ ? kDeclFunctionExport : 0) | 248 | (external_ ? kDeclFunctionImport : 0) | 249 | (HasLocals() ? kDeclFunctionLocals : 0) | 250 | (HasName() ? kDeclFunctionName : 0); 251 | 252 | EmitUint8(header, decl_bits); 253 | EmitUint16(header, signature_index_); 254 | 255 | if (HasName()) { 256 | uint32_t name_offset = static_cast(*body - buffer); 257 | EmitUint32(header, name_offset); 258 | std::memcpy(*body, name_.data(), name_.size()); 259 | (*body) += name_.size(); 260 | } 261 | 262 | if (HasLocals()) { 263 | EmitUint16(header, local_int32_count_); 264 | EmitUint16(header, local_int64_count_); 265 | EmitUint16(header, local_float32_count_); 266 | EmitUint16(header, local_float64_count_); 267 | } 268 | 269 | if (!external_) { 270 | EmitUint16(header, static_cast(body_.size())); 271 | std::memcpy(*header, body_.data(), body_.size()); 272 | (*header) += body_.size(); 273 | } 274 | } 275 | 276 | WasmDataSegmentEncoder::WasmDataSegmentEncoder(Zone* zone, const byte* data, 277 | uint32_t size, uint32_t dest) 278 | : data_(zone), dest_(dest) { 279 | for (size_t i = 0; i < size; i++) { 280 | data_.push_back(data[i]); 281 | } 282 | } 283 | 284 | uint32_t WasmDataSegmentEncoder::HeaderSize() const { 285 | static const int kDataSegmentSize = 13; 286 | return kDataSegmentSize; 287 | } 288 | 289 | uint32_t WasmDataSegmentEncoder::BodySize() const { 290 | return static_cast(data_.size()); 291 | } 292 | 293 | void WasmDataSegmentEncoder::Serialize(byte* buffer, byte** header, 294 | byte** body) const { 295 | uint32_t body_offset = static_cast(*body - buffer); 296 | EmitUint32(header, dest_); 297 | EmitUint32(header, body_offset); 298 | EmitUint32(header, static_cast(data_.size())); 299 | EmitUint8(header, 1); // init 300 | 301 | std::memcpy(*body, data_.data(), data_.size()); 302 | (*body) += data_.size(); 303 | } 304 | 305 | WasmModuleBuilder::WasmModuleBuilder(Zone* zone) 306 | : zone_(zone), 307 | signatures_(zone), 308 | functions_(zone), 309 | data_segments_(zone), 310 | indirect_functions_(zone), 311 | globals_(zone), 312 | signature_map_(zone) {} 313 | 314 | uint16_t WasmModuleBuilder::AddFunction(const unsigned char* name, 315 | int name_length) { 316 | functions_.push_back(new (zone_) WasmFunctionBuilder(zone_, name, 317 | name_length)); 318 | return static_cast(functions_.size() - 1); 319 | } 320 | 321 | WasmFunctionBuilder* WasmModuleBuilder::FunctionAt(size_t index) { 322 | if (functions_.size() > index) { 323 | return functions_.at(index); 324 | } else { 325 | return nullptr; 326 | } 327 | } 328 | 329 | void WasmModuleBuilder::AddDataSegment(WasmDataSegmentEncoder* data) { 330 | data_segments_.push_back(data); 331 | } 332 | 333 | int WasmModuleBuilder::CompareFunctionSigs::operator()(FunctionSig* a, 334 | FunctionSig* b) { 335 | if (a->return_count() < b->return_count()) return -1; 336 | if (a->return_count() > b->return_count()) return 1; 337 | if (a->parameter_count() < b->parameter_count()) return -1; 338 | if (a->parameter_count() > b->parameter_count()) return 1; 339 | for (size_t r = 0; r < a->return_count(); r++) { 340 | if (a->GetReturn(r) < b->GetReturn(r)) return -1; 341 | if (a->GetReturn(r) > b->GetReturn(r)) return 1; 342 | } 343 | for (size_t p = 0; p < a->parameter_count(); p++) { 344 | if (a->GetParam(p) < b->GetParam(p)) return -1; 345 | if (a->GetParam(p) > b->GetParam(p)) return 1; 346 | } 347 | return 0; 348 | } 349 | 350 | uint16_t WasmModuleBuilder::AddSignature(FunctionSig* sig) { 351 | SignatureMap::iterator pos = signature_map_.find(sig); 352 | if (pos != signature_map_.end()) { 353 | return pos->second; 354 | } else { 355 | uint16_t index = static_cast(signatures_.size()); 356 | signature_map_[sig] = index; 357 | signatures_.push_back(sig); 358 | return index; 359 | } 360 | } 361 | 362 | void WasmModuleBuilder::AddIndirectFunction(uint16_t index) { 363 | indirect_functions_.push_back(index); 364 | } 365 | 366 | WasmModuleWriter* WasmModuleBuilder::Build(Zone* zone) { 367 | WasmModuleWriter* writer = new (zone) WasmModuleWriter(zone); 368 | for (auto function : functions_) { 369 | writer->functions_.push_back(function->Build(zone, this)); 370 | } 371 | for (auto segment : data_segments_) { 372 | writer->data_segments_.push_back(segment); 373 | } 374 | for (auto sig : signatures_) { 375 | writer->signatures_.push_back(sig); 376 | } 377 | for (auto index : indirect_functions_) { 378 | writer->indirect_functions_.push_back(index); 379 | } 380 | for (auto global : globals_) { 381 | writer->globals_.push_back(global); 382 | } 383 | return writer; 384 | } 385 | 386 | uint32_t WasmModuleBuilder::AddGlobal(MachineType type, bool exported) { 387 | globals_.push_back(std::make_pair(type, exported)); 388 | return static_cast(globals_.size() - 1); 389 | } 390 | 391 | WasmModuleWriter::WasmModuleWriter(Zone* zone) 392 | : functions_(zone), 393 | data_segments_(zone), 394 | signatures_(zone), 395 | indirect_functions_(zone), 396 | globals_(zone) {} 397 | 398 | struct Sizes { 399 | size_t header_size; 400 | size_t body_size; 401 | 402 | size_t total() { return header_size + body_size; } 403 | 404 | void Add(size_t header, size_t body) { 405 | header_size += header; 406 | body_size += body; 407 | } 408 | 409 | void AddSection(size_t size) { 410 | if (size > 0) { 411 | Add(1, 0); 412 | while (size > 0) { 413 | Add(1, 0); 414 | size = size >> 7; 415 | } 416 | } 417 | } 418 | }; 419 | 420 | WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { 421 | Sizes sizes = {0, 0}; 422 | 423 | sizes.Add(1, 0); 424 | sizes.Add(kDeclMemorySize, 0); 425 | 426 | sizes.AddSection(signatures_.size()); 427 | for (auto sig : signatures_) { 428 | sizes.Add(2 + sig->parameter_count(), 0); 429 | } 430 | 431 | sizes.AddSection(globals_.size()); 432 | if (globals_.size() > 0) { 433 | sizes.Add(kDeclGlobalSize * globals_.size(), 0); 434 | } 435 | 436 | sizes.AddSection(functions_.size()); 437 | for (auto function : functions_) { 438 | sizes.Add(function->HeaderSize() + function->BodySize(), 439 | function->NameSize()); 440 | } 441 | 442 | sizes.AddSection(data_segments_.size()); 443 | for (auto segment : data_segments_) { 444 | sizes.Add(segment->HeaderSize(), segment->BodySize()); 445 | } 446 | 447 | sizes.AddSection(indirect_functions_.size()); 448 | sizes.Add(2 * static_cast(indirect_functions_.size()), 0); 449 | 450 | if (sizes.body_size > 0) sizes.Add(1, 0); 451 | 452 | ZoneVector buffer_vector(sizes.total(), zone); 453 | byte* buffer = buffer_vector.data(); 454 | byte* header = buffer; 455 | byte* body = buffer + sizes.header_size; 456 | 457 | // -- emit memory declaration ------------------------------------------------ 458 | EmitUint8(&header, kDeclMemory); 459 | EmitUint8(&header, 16); // min memory size 460 | EmitUint8(&header, 16); // max memory size 461 | EmitUint8(&header, 0); // memory export 462 | 463 | // -- emit globals ----------------------------------------------------------- 464 | if (globals_.size() > 0) { 465 | EmitUint8(&header, kDeclGlobals); 466 | EmitVarInt(&header, globals_.size()); 467 | 468 | for (auto global : globals_) { 469 | EmitUint32(&header, 0); 470 | EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first)); 471 | EmitUint8(&header, global.second); 472 | } 473 | } 474 | 475 | // -- emit signatures -------------------------------------------------------- 476 | if (signatures_.size() > 0) { 477 | EmitUint8(&header, kDeclSignatures); 478 | EmitVarInt(&header, signatures_.size()); 479 | 480 | for (FunctionSig* sig : signatures_) { 481 | EmitUint8(&header, static_cast(sig->parameter_count())); 482 | if (sig->return_count() > 0) { 483 | EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetReturn())); 484 | } else { 485 | EmitUint8(&header, kLocalVoid); 486 | } 487 | for (size_t j = 0; j < sig->parameter_count(); j++) { 488 | EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j))); 489 | } 490 | } 491 | } 492 | 493 | // -- emit functions --------------------------------------------------------- 494 | if (functions_.size() > 0) { 495 | EmitUint8(&header, kDeclFunctions); 496 | EmitVarInt(&header, functions_.size()); 497 | 498 | for (auto func : functions_) { 499 | func->Serialize(buffer, &header, &body); 500 | } 501 | } 502 | 503 | // -- emit data segments ----------------------------------------------------- 504 | if (data_segments_.size() > 0) { 505 | EmitUint8(&header, kDeclDataSegments); 506 | EmitVarInt(&header, data_segments_.size()); 507 | 508 | for (auto segment : data_segments_) { 509 | segment->Serialize(buffer, &header, &body); 510 | } 511 | } 512 | 513 | // -- emit function table ---------------------------------------------------- 514 | if (indirect_functions_.size() > 0) { 515 | EmitUint8(&header, kDeclFunctionTable); 516 | EmitVarInt(&header, indirect_functions_.size()); 517 | 518 | for (auto index : indirect_functions_) { 519 | EmitUint16(&header, index); 520 | } 521 | } 522 | 523 | if (sizes.body_size > 0) EmitUint8(&header, kDeclEnd); 524 | 525 | return new (zone) WasmModuleIndex(buffer, buffer + sizes.total()); 526 | } 527 | 528 | std::vector UnsignedLEB128From(uint32_t result) { 529 | std::vector output; 530 | uint8_t next = 0; 531 | int shift = 0; 532 | do { 533 | next = static_cast(result >> shift); 534 | if (((result >> shift) & 0xFFFFFF80) != 0) { 535 | next = next | 0x80; 536 | } 537 | output.push_back(next); 538 | shift += 7; 539 | } while ((next & 0x80) != 0); 540 | return output; 541 | } 542 | } 543 | } 544 | } 545 | -------------------------------------------------------------------------------- /src/wasm/encoder.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_ENCODER_H_ 6 | #define V8_WASM_ENCODER_H_ 7 | 8 | #include "src/signature.h" 9 | #include "src/zone-containers.h" 10 | 11 | #include "src/base/smart-pointers.h" 12 | 13 | #include "src/wasm/wasm-module.h" 14 | #include "src/wasm/wasm-opcodes.h" 15 | #include "src/wasm/wasm-result.h" 16 | 17 | namespace v8 { 18 | namespace internal { 19 | namespace wasm { 20 | 21 | class WasmModuleBuilder; 22 | 23 | class WasmFunctionEncoder : public ZoneObject { 24 | public: 25 | uint32_t HeaderSize() const; 26 | uint32_t BodySize() const; 27 | uint32_t NameSize() const; 28 | void Serialize(byte* buffer, byte** header, byte** body) const; 29 | 30 | private: 31 | WasmFunctionEncoder(Zone* zone, LocalType return_type, bool exported, 32 | bool external); 33 | friend class WasmFunctionBuilder; 34 | uint16_t signature_index_; 35 | ZoneVector params_; 36 | uint16_t local_int32_count_; 37 | uint16_t local_int64_count_; 38 | uint16_t local_float32_count_; 39 | uint16_t local_float64_count_; 40 | bool exported_; 41 | bool external_; 42 | ZoneVector body_; 43 | ZoneVector name_; 44 | 45 | bool HasLocals() const { 46 | return (local_int32_count_ + local_int64_count_ + local_float32_count_ + 47 | local_float64_count_) > 0; 48 | } 49 | 50 | bool HasName() const { 51 | return exported_ && name_.size() > 0; 52 | } 53 | }; 54 | 55 | class WasmFunctionBuilder : public ZoneObject { 56 | public: 57 | uint16_t AddParam(LocalType type); 58 | uint16_t AddLocal(LocalType type); 59 | void ReturnType(LocalType type); 60 | void EmitCode(const byte* code, uint32_t code_size); 61 | void EmitCode(const byte* code, uint32_t code_size, 62 | const uint32_t* local_indices, uint32_t indices_size); 63 | void Emit(WasmOpcode opcode); 64 | void EmitWithU8(WasmOpcode opcode, const byte immediate); 65 | void EmitWithLocal(WasmOpcode opcode); 66 | uint32_t EmitEditableImmediate(const byte immediate); 67 | void EditImmediate(uint32_t offset, const byte immediate); 68 | void Exported(uint8_t flag); 69 | void External(uint8_t flag); 70 | WasmFunctionEncoder* Build(Zone* zone, WasmModuleBuilder* mb) const; 71 | 72 | private: 73 | WasmFunctionBuilder(Zone* zone, const unsigned char* name, int name_length); 74 | friend class WasmModuleBuilder; 75 | LocalType return_type_; 76 | struct Type; 77 | ZoneVector locals_; 78 | uint8_t exported_; 79 | uint8_t external_; 80 | ZoneVector body_; 81 | ZoneVector local_indices_; 82 | ZoneVector name_; 83 | uint16_t AddVar(LocalType type, bool param); 84 | void IndexVars(WasmFunctionEncoder* e, uint16_t* var_index) const; 85 | }; 86 | 87 | class WasmDataSegmentEncoder : public ZoneObject { 88 | public: 89 | WasmDataSegmentEncoder(Zone* zone, const byte* data, uint32_t size, 90 | uint32_t dest); 91 | uint32_t HeaderSize() const; 92 | uint32_t BodySize() const; 93 | void Serialize(byte* buffer, byte** header, byte** body) const; 94 | 95 | private: 96 | ZoneVector data_; 97 | uint32_t dest_; 98 | }; 99 | 100 | class WasmModuleIndex : public ZoneObject { 101 | public: 102 | const byte* Begin() const { return begin_; } 103 | const byte* End() const { return end_; } 104 | 105 | private: 106 | friend class WasmModuleWriter; 107 | WasmModuleIndex(const byte* begin, const byte* end) 108 | : begin_(begin), end_(end) {} 109 | const byte* begin_; 110 | const byte* end_; 111 | }; 112 | 113 | class WasmModuleWriter : public ZoneObject { 114 | public: 115 | WasmModuleIndex* WriteTo(Zone* zone) const; 116 | 117 | private: 118 | friend class WasmModuleBuilder; 119 | WasmModuleWriter(Zone* zone); 120 | ZoneVector functions_; 121 | ZoneVector data_segments_; 122 | ZoneVector signatures_; 123 | ZoneVector indirect_functions_; 124 | ZoneVector> globals_; 125 | }; 126 | 127 | class WasmModuleBuilder : public ZoneObject { 128 | public: 129 | WasmModuleBuilder(Zone* zone); 130 | uint16_t AddFunction(const unsigned char* name = NULL, int name_length = 0); 131 | uint32_t AddGlobal(MachineType type, bool exported); 132 | WasmFunctionBuilder* FunctionAt(size_t index); 133 | void AddDataSegment(WasmDataSegmentEncoder* data); 134 | uint16_t AddSignature(FunctionSig* sig); 135 | void AddIndirectFunction(uint16_t index); 136 | WasmModuleWriter* Build(Zone* zone); 137 | 138 | private: 139 | struct CompareFunctionSigs { 140 | int operator()(FunctionSig* a, FunctionSig* b); 141 | }; 142 | typedef ZoneMap SignatureMap; 143 | 144 | Zone* zone_; 145 | ZoneVector signatures_; 146 | ZoneVector functions_; 147 | ZoneVector data_segments_; 148 | ZoneVector indirect_functions_; 149 | ZoneVector> globals_; 150 | SignatureMap signature_map_; 151 | }; 152 | 153 | std::vector UnsignedLEB128From(uint32_t result); 154 | } 155 | } 156 | } 157 | 158 | #endif // V8_WASM_ENCODER_H_ 159 | -------------------------------------------------------------------------------- /src/wasm/module-decoder.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_MODULE_DECODER_H_ 6 | #define V8_WASM_MODULE_DECODER_H_ 7 | 8 | #include "src/wasm/ast-decoder.h" 9 | #include "src/wasm/wasm-module.h" 10 | 11 | namespace v8 { 12 | namespace internal { 13 | namespace wasm { 14 | // Decodes the bytes of a WASM module between {module_start} and {module_end}. 15 | ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone, 16 | const byte* module_start, const byte* module_end, 17 | bool verify_functions, bool asm_js); 18 | 19 | // Exposed for testing. Decodes a single function signature, allocating it 20 | // in the given zone. Returns {nullptr} upon failure. 21 | FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start, 22 | const byte* end); 23 | 24 | // Decodes the bytes of a WASM function between 25 | // {function_start} and {function_end}. 26 | FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone, ModuleEnv* env, 27 | const byte* function_start, 28 | const byte* function_end); 29 | } 30 | } 31 | } 32 | 33 | #endif // V8_WASM_MODULE_DECODER_H_ 34 | -------------------------------------------------------------------------------- /src/wasm/wasm-compiler.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_TF_BUILDER_H_ 6 | #define V8_WASM_TF_BUILDER_H_ 7 | 8 | #include "src/zone.h" 9 | 10 | #include "src/wasm/wasm-opcodes.h" 11 | 12 | namespace v8 { 13 | namespace internal { 14 | 15 | namespace compiler { 16 | // Forward declarations for some compiler data structures. 17 | class Node; 18 | class JSGraph; 19 | } 20 | 21 | namespace wasm { 22 | // Forward declarations for some WASM data structures. 23 | struct ModuleEnv; 24 | struct WasmFunction; 25 | class ErrorThrower; 26 | 27 | // Expose {Node} and {Graph} opaquely as {wasm::TFNode} and {wasm::TFGraph}. 28 | typedef compiler::Node TFNode; 29 | typedef compiler::JSGraph TFGraph; 30 | } 31 | 32 | namespace compiler { 33 | // Compiles a single function, producing a code object. 34 | Handle CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate, 35 | wasm::ModuleEnv* module_env, 36 | const wasm::WasmFunction& function, int index); 37 | 38 | // Wraps a JS function, producing a code object that can be called from WASM. 39 | Handle CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module, 40 | Handle function, 41 | uint32_t index); 42 | 43 | // Wraps a given wasm code object, producing a JSFunction that can be called 44 | // from JavaScript. 45 | Handle CompileJSToWasmWrapper(Isolate* isolate, 46 | wasm::ModuleEnv* module, 47 | Handle name, 48 | Handle wasm_code, 49 | uint32_t index); 50 | 51 | // Abstracts details of building TurboFan graph nodes for WASM to separate 52 | // the WASM decoder from the internal details of TurboFan. 53 | class WasmTrapHelper; 54 | class WasmGraphBuilder { 55 | public: 56 | WasmGraphBuilder(Zone* z, JSGraph* g); 57 | 58 | Node** Buffer(size_t count) { 59 | if (count > cur_bufsize) { 60 | size_t new_size = count + cur_bufsize + 5; 61 | cur_buffer = 62 | reinterpret_cast(zone->New(new_size * sizeof(Node*))); 63 | cur_bufsize = new_size; 64 | } 65 | return cur_buffer; 66 | } 67 | 68 | //----------------------------------------------------------------------- 69 | // Operations independent of {control} or {effect}. 70 | //----------------------------------------------------------------------- 71 | Node* Error(); 72 | Node* Start(unsigned params); 73 | Node* Param(unsigned index, wasm::LocalType type); 74 | Node* Loop(Node* entry); 75 | Node* Terminate(Node* effect, Node* control); 76 | Node* Merge(unsigned count, Node** controls); 77 | Node* Phi(wasm::LocalType type, unsigned count, Node** vals, Node* control); 78 | Node* EffectPhi(unsigned count, Node** effects, Node* control); 79 | Node* Int32Constant(int32_t value); 80 | Node* Int64Constant(int64_t value); 81 | Node* Float32Constant(float value); 82 | Node* Float64Constant(double value); 83 | Node* Constant(Handle value); 84 | Node* Binop(wasm::WasmOpcode opcode, Node* left, Node* right); 85 | Node* Unop(wasm::WasmOpcode opcode, Node* input); 86 | unsigned InputCount(Node* node); 87 | bool IsPhiWithMerge(Node* phi, Node* merge); 88 | void AppendToMerge(Node* merge, Node* from); 89 | void AppendToPhi(Node* merge, Node* phi, Node* from); 90 | 91 | //----------------------------------------------------------------------- 92 | // Operations that read and/or write {control} and {effect}. 93 | //----------------------------------------------------------------------- 94 | Node* Branch(Node* cond, Node** true_node, Node** false_node); 95 | Node* Switch(unsigned count, Node* key); 96 | Node* IfValue(int32_t value, Node* sw); 97 | Node* IfDefault(Node* sw); 98 | Node* Return(unsigned count, Node** vals); 99 | Node* ReturnVoid(); 100 | Node* Unreachable(); 101 | 102 | Node* CallDirect(uint32_t index, Node** args); 103 | Node* CallIndirect(uint32_t index, Node** args); 104 | void BuildJSToWasmWrapper(Handle wasm_code, wasm::FunctionSig* sig); 105 | void BuildWasmToJSWrapper(Handle function, 106 | wasm::FunctionSig* sig); 107 | Node* ToJS(Node* node, Node* context, wasm::LocalType type); 108 | Node* FromJS(Node* node, Node* context, wasm::LocalType type); 109 | Node* Invert(Node* node); 110 | Node* FunctionTable(); 111 | 112 | //----------------------------------------------------------------------- 113 | // Operations that concern the linear memory. 114 | //----------------------------------------------------------------------- 115 | Node* MemSize(uint32_t offset); 116 | Node* LoadGlobal(uint32_t index); 117 | Node* StoreGlobal(uint32_t index, Node* val); 118 | Node* LoadMem(wasm::LocalType type, MachineType memtype, Node* index, 119 | uint32_t offset); 120 | Node* StoreMem(MachineType type, Node* index, uint32_t offset, Node* val); 121 | 122 | static void PrintDebugName(Node* node); 123 | 124 | Node* Control() { return *control; } 125 | Node* Effect() { return *effect; } 126 | 127 | void set_module(wasm::ModuleEnv* env) { this->module = env; } 128 | 129 | void set_control_ptr(Node** control) { this->control = control; } 130 | 131 | void set_effect_ptr(Node** effect) { this->effect = effect; } 132 | 133 | private: 134 | static const int kDefaultBufferSize = 16; 135 | friend class WasmTrapHelper; 136 | 137 | Zone* zone; 138 | JSGraph* graph; 139 | wasm::ModuleEnv* module; 140 | Node* mem_buffer; 141 | Node* mem_size; 142 | Node* function_table; 143 | Node** control; 144 | Node** effect; 145 | Node** cur_buffer; 146 | size_t cur_bufsize; 147 | Node* def_buffer[kDefaultBufferSize]; 148 | 149 | WasmTrapHelper* trap; 150 | 151 | // Internal helper methods. 152 | Node* String(const char* string); 153 | Node* MemBuffer(uint32_t offset); 154 | void BoundsCheckMem(MachineType memtype, Node* index, uint32_t offset); 155 | 156 | Node* BuildWasmCall(wasm::FunctionSig* sig, Node** args); 157 | Node* BuildF32CopySign(Node* left, Node* right); 158 | Node* BuildF64CopySign(Node* left, Node* right); 159 | Node* BuildI32Ctz(Node* input); 160 | Node* BuildI32Popcnt(Node* input); 161 | Node* BuildI64Ctz(Node* input); 162 | Node* BuildI64Popcnt(Node* input); 163 | 164 | Node** Realloc(Node** buffer, size_t count) { 165 | Node** buf = Buffer(count); 166 | if (buf != buffer) memcpy(buf, buffer, count * sizeof(Node*)); 167 | return buf; 168 | } 169 | }; 170 | } 171 | } 172 | } // namespace v8::internal::wasm 173 | 174 | #endif // V8_WASM_TF_BUILDER_H_ 175 | -------------------------------------------------------------------------------- /src/wasm/wasm-js.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "src/api-natives.h" 6 | #include "src/api.h" 7 | #include "src/assert-scope.h" 8 | #include "src/ast/ast.h" 9 | #include "src/ast/scopes.h" 10 | #include "src/factory.h" 11 | #include "src/handles.h" 12 | #include "src/isolate.h" 13 | #include "src/objects.h" 14 | #include "src/parsing/parser.h" 15 | #include "src/typing-asm.h" 16 | 17 | #include "src/wasm/asm-wasm-builder.h" 18 | #include "src/wasm/encoder.h" 19 | #include "src/wasm/wasm-js.h" 20 | #include "src/wasm/wasm-module.h" 21 | #include "src/wasm/module-decoder.h" 22 | #include "src/wasm/wasm-result.h" 23 | 24 | typedef uint8_t byte; 25 | 26 | using v8::internal::wasm::ErrorThrower; 27 | 28 | namespace v8 { 29 | 30 | namespace { 31 | struct RawBuffer { 32 | const byte* start; 33 | const byte* end; 34 | size_t size() { return static_cast(end - start); } 35 | }; 36 | 37 | RawBuffer GetRawBufferArgument( 38 | ErrorThrower& thrower, const v8::FunctionCallbackInfo& args) { 39 | if (args.Length() < 1 || !args[0]->IsArrayBuffer()) { 40 | thrower.Error("Argument 0 must be an array buffer"); 41 | return {nullptr, nullptr}; 42 | } 43 | Local buffer = Local::Cast(args[0]); 44 | ArrayBuffer::Contents contents = 45 | buffer->IsExternal() ? buffer->GetContents() : buffer->Externalize(); 46 | 47 | // TODO(titzer): allow offsets into buffers, views, etc. 48 | 49 | const byte* start = reinterpret_cast(contents.Data()); 50 | const byte* end = start + contents.ByteLength(); 51 | 52 | if (start == nullptr) { 53 | thrower.Error("ArrayBuffer argument is empty"); 54 | } 55 | return {start, end}; 56 | } 57 | 58 | void VerifyModule(const v8::FunctionCallbackInfo& args) { 59 | HandleScope scope(args.GetIsolate()); 60 | i::Isolate* isolate = reinterpret_cast(args.GetIsolate()); 61 | ErrorThrower thrower(isolate, "WASM.verifyModule()"); 62 | 63 | RawBuffer buffer = GetRawBufferArgument(thrower, args); 64 | if (thrower.error()) return; 65 | 66 | i::Zone zone; 67 | internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule( 68 | isolate, &zone, buffer.start, buffer.end, true, false); 69 | 70 | if (result.failed()) { 71 | thrower.Failed("", result); 72 | } 73 | 74 | if (result.val) delete result.val; 75 | } 76 | 77 | void VerifyFunction(const v8::FunctionCallbackInfo& args) { 78 | HandleScope scope(args.GetIsolate()); 79 | i::Isolate* isolate = reinterpret_cast(args.GetIsolate()); 80 | ErrorThrower thrower(isolate, "WASM.verifyFunction()"); 81 | 82 | // TODO(titzer): no need to externalize to get the bytes for verification. 83 | RawBuffer buffer = GetRawBufferArgument(thrower, args); 84 | if (thrower.error()) return; 85 | 86 | internal::wasm::FunctionResult result; 87 | { 88 | // Verification of a single function shouldn't allocate. 89 | i::DisallowHeapAllocation no_allocation; 90 | i::Zone zone; 91 | result = internal::wasm::DecodeWasmFunction(isolate, &zone, nullptr, 92 | buffer.start, buffer.end); 93 | } 94 | 95 | if (result.failed()) { 96 | thrower.Failed("", result); 97 | } 98 | 99 | if (result.val) delete result.val; 100 | } 101 | 102 | void CompileRun(const v8::FunctionCallbackInfo& args) { 103 | HandleScope scope(args.GetIsolate()); 104 | i::Isolate* isolate = reinterpret_cast(args.GetIsolate()); 105 | ErrorThrower thrower(isolate, "WASM.compileRun()"); 106 | 107 | RawBuffer buffer = GetRawBufferArgument(thrower, args); 108 | if (thrower.error()) return; 109 | 110 | // Decode and pre-verify the functions before compiling and running. 111 | i::Zone zone; 112 | internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule( 113 | isolate, &zone, buffer.start, buffer.end, true, false); 114 | 115 | if (result.failed()) { 116 | thrower.Failed("", result); 117 | } else { 118 | // Success. Compile and run! 119 | int32_t retval = i::wasm::CompileAndRunWasmModule(isolate, result.val); 120 | args.GetReturnValue().Set(retval); 121 | } 122 | 123 | if (result.val) delete result.val; 124 | } 125 | 126 | v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(i::ParseInfo* info) { 127 | info->set_global(); 128 | info->set_lazy(false); 129 | info->set_allow_lazy_parsing(false); 130 | info->set_toplevel(true); 131 | 132 | CHECK(i::Compiler::ParseAndAnalyze(info)); 133 | info->set_literal( 134 | info->scope()->declarations()->at(0)->AsFunctionDeclaration()->fun()); 135 | 136 | v8::internal::AsmTyper typer(info->isolate(), info->zone(), *(info->script()), 137 | info->literal()); 138 | if (!typer.Validate()) { 139 | return NULL; 140 | } 141 | 142 | auto module = 143 | v8::internal::wasm::AsmWasmBuilder(info->isolate(), info->zone(), 144 | info->literal()) 145 | .Run(); 146 | return module; 147 | } 148 | 149 | void AsmCompileRun(const v8::FunctionCallbackInfo& args) { 150 | HandleScope scope(args.GetIsolate()); 151 | i::Isolate* isolate = reinterpret_cast(args.GetIsolate()); 152 | ErrorThrower thrower(isolate, "WASM.asmCompileRun()"); 153 | 154 | if (args.Length() != 1) { 155 | thrower.Error("Invalid argument count"); 156 | return; 157 | } 158 | if (!args[0]->IsString()) { 159 | thrower.Error("Invalid argument count"); 160 | return; 161 | } 162 | 163 | i::Factory* factory = isolate->factory(); 164 | i::Zone zone; 165 | Local source = Local::Cast(args[0]); 166 | i::Handle script = factory->NewScript(Utils::OpenHandle(*source)); 167 | i::ParseInfo info(&zone, script); 168 | 169 | auto module = TranslateAsmModule(&info); 170 | if (module == NULL) { 171 | thrower.Error("Asm.js validation failed"); 172 | return; 173 | } 174 | 175 | int32_t result = v8::internal::wasm::CompileAndRunWasmModule( 176 | isolate, module->Begin(), module->End(), true); 177 | args.GetReturnValue().Set(result); 178 | } 179 | 180 | // TODO(aseemgarg): deal with arraybuffer and foreign functions 181 | void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo& args) { 182 | HandleScope scope(args.GetIsolate()); 183 | i::Isolate* isolate = reinterpret_cast(args.GetIsolate()); 184 | ErrorThrower thrower(isolate, "WASM.instantiateModuleFromAsm()"); 185 | 186 | if (args.Length() != 1) { 187 | thrower.Error("Invalid argument count"); 188 | return; 189 | } 190 | if (!args[0]->IsString()) { 191 | thrower.Error("Invalid argument count"); 192 | return; 193 | } 194 | 195 | i::Factory* factory = isolate->factory(); 196 | i::Zone zone; 197 | Local source = Local::Cast(args[0]); 198 | i::Handle script = factory->NewScript(Utils::OpenHandle(*source)); 199 | i::ParseInfo info(&zone, script); 200 | 201 | auto module = TranslateAsmModule(&info); 202 | if (module == NULL) { 203 | thrower.Error("Asm.js validation failed"); 204 | return; 205 | } 206 | 207 | i::Handle memory = i::Handle::null(); 208 | internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule( 209 | isolate, &zone, module->Begin(), module->End(), false, false); 210 | 211 | if (result.failed()) { 212 | thrower.Failed("", result); 213 | } else { 214 | // Success. Instantiate the module and return the object. 215 | i::Handle ffi = i::Handle::null(); 216 | 217 | i::MaybeHandle object = 218 | result.val->Instantiate(isolate, ffi, memory); 219 | 220 | if (!object.is_null()) { 221 | args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked())); 222 | } 223 | } 224 | 225 | if (result.val) delete result.val; 226 | } 227 | 228 | void InstantiateModule(const v8::FunctionCallbackInfo& args) { 229 | HandleScope scope(args.GetIsolate()); 230 | i::Isolate* isolate = reinterpret_cast(args.GetIsolate()); 231 | ErrorThrower thrower(isolate, "WASM.instantiateModule()"); 232 | 233 | RawBuffer buffer = GetRawBufferArgument(thrower, args); 234 | if (buffer.start == nullptr) return; 235 | 236 | i::Handle memory = i::Handle::null(); 237 | if (args.Length() > 2 && args[2]->IsArrayBuffer()) { 238 | Local obj = Local::Cast(args[2]); 239 | i::Handle mem_obj = v8::Utils::OpenHandle(*obj); 240 | memory = i::Handle(i::JSArrayBuffer::cast(*mem_obj)); 241 | i::Isolate* isolate = memory->GetIsolate(); 242 | memory->set_is_external(true); 243 | isolate->heap()->UnregisterArrayBuffer(*memory); 244 | } 245 | 246 | // Decode but avoid a redundant pass over function bodies for verification. 247 | // Verification will happen during compilation. 248 | i::Zone zone; 249 | internal::wasm::ModuleResult result = internal::wasm::DecodeWasmModule( 250 | isolate, &zone, buffer.start, buffer.end, false, false); 251 | 252 | if (result.failed()) { 253 | thrower.Failed("", result); 254 | } else { 255 | // Success. Instantiate the module and return the object. 256 | i::Handle ffi = i::Handle::null(); 257 | if (args.Length() > 1 && args[1]->IsObject()) { 258 | Local obj = Local::Cast(args[1]); 259 | ffi = i::Handle::cast(v8::Utils::OpenHandle(*obj)); 260 | } 261 | 262 | i::MaybeHandle object = 263 | result.val->Instantiate(isolate, ffi, memory); 264 | 265 | if (!object.is_null()) { 266 | args.GetReturnValue().Set(v8::Utils::ToLocal(object.ToHandleChecked())); 267 | } 268 | } 269 | 270 | if (result.val) delete result.val; 271 | } 272 | } 273 | 274 | // TODO(titzer): we use the API to create the function template because the 275 | // internal guts are too ugly to replicate here. 276 | static i::Handle NewTemplate(i::Isolate* i_isolate, 277 | FunctionCallback func) { 278 | Isolate* isolate = reinterpret_cast(i_isolate); 279 | Local local = FunctionTemplate::New(isolate, func); 280 | return v8::Utils::OpenHandle(*local); 281 | } 282 | 283 | namespace internal { 284 | static Handle v8_str(Isolate* isolate, const char* str) { 285 | return isolate->factory()->NewStringFromAsciiChecked(str); 286 | } 287 | 288 | static void InstallFunc(Isolate* isolate, Handle object, 289 | const char* str, FunctionCallback func) { 290 | Handle name = v8_str(isolate, str); 291 | Handle temp = NewTemplate(isolate, func); 292 | Handle function = 293 | ApiNatives::InstantiateFunction(temp).ToHandleChecked(); 294 | PropertyAttributes attributes = 295 | static_cast(DONT_DELETE | READ_ONLY); 296 | JSObject::AddProperty(object, name, function, attributes); 297 | } 298 | 299 | void WasmJs::Install(Isolate* isolate, Handle global) { 300 | // Bind the WASM object. 301 | Factory* factory = isolate->factory(); 302 | Handle name = v8_str(isolate, "WASM"); 303 | Handle cons = factory->NewFunction(name); 304 | JSFunction::SetInstancePrototype( 305 | cons, Handle(global->native_context()->initial_object_prototype(), 306 | isolate)); 307 | cons->shared()->set_instance_class_name(*name); 308 | Handle wasm_object = factory->NewJSObject(cons, TENURED); 309 | PropertyAttributes attributes = static_cast(DONT_ENUM); 310 | JSObject::AddProperty(global, name, wasm_object, attributes); 311 | 312 | // Install functions on the WASM object. 313 | InstallFunc(isolate, wasm_object, "instantiateModule", InstantiateModule); 314 | InstallFunc(isolate, wasm_object, "verifyModule", VerifyModule); 315 | InstallFunc(isolate, wasm_object, "verifyFunction", VerifyFunction); 316 | InstallFunc(isolate, wasm_object, "compileRun", CompileRun); 317 | InstallFunc(isolate, wasm_object, "asmCompileRun", AsmCompileRun); 318 | InstallFunc(isolate, wasm_object, "instantiateModuleFromAsm", 319 | InstantiateModuleFromAsm); 320 | } 321 | } // namespace internal 322 | } // namespace v8 323 | -------------------------------------------------------------------------------- /src/wasm/wasm-js.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_JS_H_ 6 | #define V8_WASM_JS_H_ 7 | 8 | #ifndef V8_SHARED 9 | #include "src/allocation.h" 10 | #include "src/hashmap.h" 11 | #include "src/v8.h" 12 | #else 13 | #include "include/v8.h" 14 | #include "src/base/compiler-specific.h" 15 | #endif // !V8_SHARED 16 | 17 | namespace v8 { 18 | namespace internal { 19 | // Exposes a WASM API to JavaScript through the V8 API. 20 | class WasmJs { 21 | public: 22 | static void Install(Isolate* isolate, Handle global_object); 23 | }; 24 | } 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/wasm/wasm-linkage.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "src/assembler.h" 6 | #include "src/macro-assembler.h" 7 | 8 | #include "src/wasm/wasm-module.h" 9 | 10 | #include "src/compiler/linkage.h" 11 | 12 | #include "src/zone.h" 13 | 14 | namespace v8 { 15 | namespace internal { 16 | namespace wasm { 17 | 18 | using compiler::LocationSignature; 19 | using compiler::CallDescriptor; 20 | using compiler::LinkageLocation; 21 | 22 | namespace { 23 | MachineType MachineTypeFor(LocalType type) { 24 | switch (type) { 25 | case kAstI32: 26 | return MachineType::Int32(); 27 | case kAstI64: 28 | return MachineType::Int64(); 29 | case kAstF64: 30 | return MachineType::Float64(); 31 | case kAstF32: 32 | return MachineType::Float32(); 33 | default: 34 | UNREACHABLE(); 35 | return MachineType::AnyTagged(); 36 | } 37 | } 38 | 39 | // Platform-specific configuration for C calling convention. 40 | LinkageLocation regloc(Register reg) { 41 | return LinkageLocation::ForRegister(reg.code()); 42 | } 43 | 44 | LinkageLocation regloc(DoubleRegister reg) { 45 | return LinkageLocation::ForRegister(reg.code()); 46 | } 47 | 48 | LinkageLocation stackloc(int i) { 49 | return LinkageLocation::ForCallerFrameSlot(i); 50 | } 51 | 52 | #if V8_TARGET_ARCH_IA32 53 | // =========================================================================== 54 | // == ia32 =================================================================== 55 | // =========================================================================== 56 | #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi, edi 57 | #define GP_RETURN_REGISTERS eax, edx 58 | #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6 59 | #define FP_RETURN_REGISTERS xmm1, xmm2 60 | 61 | #elif V8_TARGET_ARCH_X64 62 | // =========================================================================== 63 | // == x64 ==================================================================== 64 | // =========================================================================== 65 | #define GP_PARAM_REGISTERS rax, rdx, rcx, rbx, rsi, rdi 66 | #define GP_RETURN_REGISTERS rax, rdx 67 | #define FP_PARAM_REGISTERS xmm1, xmm2, xmm3, xmm4, xmm5, xmm6 68 | #define FP_RETURN_REGISTERS xmm1, xmm2 69 | 70 | #elif V8_TARGET_ARCH_X87 71 | // =========================================================================== 72 | // == x87 ==================================================================== 73 | // =========================================================================== 74 | #define GP_PARAM_REGISTERS eax, edx, ecx, ebx, esi, edi 75 | #define GP_RETURN_REGISTERS eax, edx 76 | 77 | #elif V8_TARGET_ARCH_ARM 78 | // =========================================================================== 79 | // == arm ==================================================================== 80 | // =========================================================================== 81 | #define GP_PARAM_REGISTERS r0, r1, r2, r3 82 | #define GP_RETURN_REGISTERS r0, r1 83 | #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7 84 | #define FP_RETURN_REGISTERS d0, d1 85 | 86 | #elif V8_TARGET_ARCH_ARM64 87 | // =========================================================================== 88 | // == arm64 ==================================================================== 89 | // =========================================================================== 90 | #define GP_PARAM_REGISTERS x0, x1, x2, x3, x4, x5, x6, x7 91 | #define GP_RETURN_REGISTERS x0, x1 92 | #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7 93 | #define FP_RETURN_REGISTERS d0, d1 94 | 95 | #elif V8_TARGET_ARCH_MIPS 96 | // =========================================================================== 97 | // == mips =================================================================== 98 | // =========================================================================== 99 | #define GP_PARAM_REGISTERS a0, a1, a2, a3 100 | #define GP_RETURN_REGISTERS v0, v1 101 | #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14 102 | #define FP_RETURN_REGISTERS f2, f4 103 | 104 | #elif V8_TARGET_ARCH_MIPS64 105 | // =========================================================================== 106 | // == mips64 ================================================================= 107 | // =========================================================================== 108 | #define GP_PARAM_REGISTERS a0, a1, a2, a3, a4, a5, a6, a7 109 | #define GP_RETURN_REGISTERS v0, v1 110 | #define FP_PARAM_REGISTERS f2, f4, f6, f8, f10, f12, f14 111 | #define FP_RETURN_REGISTERS f2, f4 112 | 113 | #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 114 | // =========================================================================== 115 | // == ppc & ppc64 ============================================================ 116 | // =========================================================================== 117 | #define GP_PARAM_REGISTERS r3, r4, r5, r6, r7, r8, r9, r10 118 | #define GP_RETURN_REGISTERS r3, r4 119 | #define FP_PARAM_REGISTERS d0, d1, d2, d3, d4, d5, d6, d7 120 | #define FP_RETURN_REGISTERS d0, d1 121 | 122 | #else 123 | // =========================================================================== 124 | // == unknown ================================================================ 125 | // =========================================================================== 126 | // Don't define anything. We'll just always use the stack. 127 | #endif 128 | 129 | // Helper for allocating either an GP or FP reg, or the next stack slot. 130 | struct Allocator { 131 | Allocator(const Register* gp, int gpc, const DoubleRegister* fp, int fpc) 132 | : gp_count(gpc), 133 | gp_offset(0), 134 | gp_regs(gp), 135 | fp_count(fpc), 136 | fp_offset(0), 137 | fp_regs(fp), 138 | stack_offset(0) {} 139 | 140 | int gp_count; 141 | int gp_offset; 142 | const Register* gp_regs; 143 | 144 | int fp_count; 145 | int fp_offset; 146 | const DoubleRegister* fp_regs; 147 | 148 | int stack_offset; 149 | 150 | LinkageLocation Next(LocalType type) { 151 | if (IsFloatingPoint(type)) { 152 | // Allocate a floating point register/stack location. 153 | if (fp_offset < fp_count) { 154 | return regloc(fp_regs[fp_offset++]); 155 | } else { 156 | int offset = -1 - stack_offset; 157 | stack_offset += Words(type); 158 | return stackloc(offset); 159 | } 160 | } else { 161 | // Allocate a general purpose register/stack location. 162 | if (gp_offset < gp_count) { 163 | return regloc(gp_regs[gp_offset++]); 164 | } else { 165 | int offset = -1 - stack_offset; 166 | stack_offset += Words(type); 167 | return stackloc(offset); 168 | } 169 | } 170 | } 171 | bool IsFloatingPoint(LocalType type) { 172 | return type == kAstF32 || type == kAstF64; 173 | } 174 | int Words(LocalType type) { 175 | if (kPointerSize < 8 && (type == kAstI64 || type == kAstF64)) { 176 | return 2; 177 | } 178 | return 1; 179 | } 180 | }; 181 | } // namespace 182 | 183 | // General code uses the above configuration data. 184 | CallDescriptor* ModuleEnv::GetWasmCallDescriptor(Zone* zone, 185 | FunctionSig* fsig) { 186 | MachineSignature::Builder msig(zone, fsig->return_count(), 187 | fsig->parameter_count()); 188 | LocationSignature::Builder locations(zone, fsig->return_count(), 189 | fsig->parameter_count()); 190 | 191 | #ifdef GP_RETURN_REGISTERS 192 | static const Register kGPReturnRegisters[] = {GP_RETURN_REGISTERS}; 193 | static const int kGPReturnRegistersCount = 194 | static_cast(arraysize(kGPReturnRegisters)); 195 | #else 196 | static const Register* kGPReturnRegisters = nullptr; 197 | static const int kGPReturnRegistersCount = 0; 198 | #endif 199 | 200 | #ifdef FP_RETURN_REGISTERS 201 | static const DoubleRegister kFPReturnRegisters[] = {FP_RETURN_REGISTERS}; 202 | static const int kFPReturnRegistersCount = 203 | static_cast(arraysize(kFPReturnRegisters)); 204 | #else 205 | static const DoubleRegister* kFPReturnRegisters = nullptr; 206 | static const int kFPReturnRegistersCount = 0; 207 | #endif 208 | 209 | Allocator rets(kGPReturnRegisters, kGPReturnRegistersCount, 210 | kFPReturnRegisters, kFPReturnRegistersCount); 211 | 212 | // Add return location(s). 213 | const int return_count = static_cast(locations.return_count_); 214 | for (int i = 0; i < return_count; i++) { 215 | LocalType ret = fsig->GetReturn(i); 216 | msig.AddReturn(MachineTypeFor(ret)); 217 | locations.AddReturn(rets.Next(ret)); 218 | } 219 | 220 | #ifdef GP_PARAM_REGISTERS 221 | static const Register kGPParamRegisters[] = {GP_PARAM_REGISTERS}; 222 | static const int kGPParamRegistersCount = 223 | static_cast(arraysize(kGPParamRegisters)); 224 | #else 225 | static const Register* kGPParamRegisters = nullptr; 226 | static const int kGPParamRegistersCount = 0; 227 | #endif 228 | 229 | #ifdef FP_PARAM_REGISTERS 230 | static const DoubleRegister kFPParamRegisters[] = {FP_PARAM_REGISTERS}; 231 | static const int kFPParamRegistersCount = 232 | static_cast(arraysize(kFPParamRegisters)); 233 | #else 234 | static const DoubleRegister* kFPParamRegisters = nullptr; 235 | static const int kFPParamRegistersCount = 0; 236 | #endif 237 | 238 | Allocator params(kGPParamRegisters, kGPParamRegistersCount, kFPParamRegisters, 239 | kFPParamRegistersCount); 240 | 241 | // Add register and/or stack parameter(s). 242 | const int parameter_count = static_cast(fsig->parameter_count()); 243 | for (int i = 0; i < parameter_count; i++) { 244 | LocalType param = fsig->GetParam(i); 245 | msig.AddParam(MachineTypeFor(param)); 246 | locations.AddParam(params.Next(param)); 247 | } 248 | 249 | const RegList kCalleeSaveRegisters = 0; 250 | const RegList kCalleeSaveFPRegisters = 0; 251 | 252 | // The target for WASM calls is always a code object. 253 | MachineType target_type = MachineType::AnyTagged(); 254 | LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); 255 | return new (zone) CallDescriptor( // -- 256 | CallDescriptor::kCallCodeObject, // kind 257 | target_type, // target MachineType 258 | target_loc, // target location 259 | msig.Build(), // machine_sig 260 | locations.Build(), // location_sig 261 | params.stack_offset, // stack_parameter_count 262 | compiler::Operator::kNoProperties, // properties 263 | kCalleeSaveRegisters, // callee-saved registers 264 | kCalleeSaveFPRegisters, // callee-saved fp regs 265 | CallDescriptor::kUseNativeStack, // flags 266 | "c-call"); 267 | } 268 | } 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /src/wasm/wasm-macro-gen.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_MACRO_GEN_H_ 6 | #define V8_WASM_MACRO_GEN_H_ 7 | 8 | #include "src/wasm/wasm-opcodes.h" 9 | 10 | // Convenience macros for building Wasm bytecode directly into a byte array. 11 | 12 | //------------------------------------------------------------------------------ 13 | // Control. 14 | //------------------------------------------------------------------------------ 15 | #define WASM_NOP kExprNop 16 | 17 | #define WASM_BLOCK(count, ...) kExprBlock, static_cast(count), __VA_ARGS__ 18 | #define WASM_INFINITE_LOOP kExprLoop, 1, kExprBr, 0, kExprNop 19 | #define WASM_LOOP(count, ...) kExprLoop, static_cast(count), __VA_ARGS__ 20 | #define WASM_IF(cond, tstmt) kExprIf, cond, tstmt 21 | #define WASM_IF_ELSE(cond, tstmt, fstmt) kExprIfElse, cond, tstmt, fstmt 22 | #define WASM_SELECT(cond, tval, fval) kExprSelect, cond, tval, fval 23 | #define WASM_BR(depth) kExprBr, static_cast(depth), kExprNop 24 | #define WASM_BR_IF(depth, cond) \ 25 | kExprBrIf, static_cast(depth), cond, kExprNop 26 | #define WASM_BRV(depth, val) kExprBr, static_cast(depth), val 27 | #define WASM_BRV_IF(depth, cond, val) \ 28 | kExprBrIf, static_cast(depth), cond, val 29 | #define WASM_BREAK(depth) kExprBr, static_cast(depth + 1), kExprNop 30 | #define WASM_CONTINUE(depth) kExprBr, static_cast(depth), kExprNop 31 | #define WASM_BREAKV(depth, val) kExprBr, static_cast(depth + 1), val 32 | #define WASM_RETURN0 kExprReturn 33 | #define WASM_RETURN(...) kExprReturn, __VA_ARGS__ 34 | #define WASM_UNREACHABLE kExprUnreachable 35 | 36 | #define WASM_TABLESWITCH_OP(case_count, table_count, ...) \ 37 | kExprTableSwitch, static_cast(case_count), \ 38 | static_cast(case_count >> 8), static_cast(table_count), \ 39 | static_cast(table_count >> 8), __VA_ARGS__ 40 | 41 | #define WASM_TABLESWITCH_BODY0(key) key 42 | 43 | #define WASM_TABLESWITCH_BODY(key, ...) key, __VA_ARGS__ 44 | 45 | #define WASM_CASE(x) static_cast(x), static_cast(x >> 8) 46 | #define WASM_CASE_BR(x) static_cast(x), static_cast(0x80 | (x) >> 8) 47 | 48 | //------------------------------------------------------------------------------ 49 | // Misc expressions. 50 | //------------------------------------------------------------------------------ 51 | #define WASM_ID(...) __VA_ARGS__ 52 | #define WASM_ZERO kExprI8Const, 0 53 | #define WASM_ONE kExprI8Const, 1 54 | #define WASM_I8(val) kExprI8Const, static_cast(val) 55 | #define WASM_I32(val) \ 56 | kExprI32Const, static_cast(val), static_cast(val >> 8), \ 57 | static_cast(val >> 16), static_cast(val >> 24) 58 | #define WASM_I64(val) \ 59 | kExprI64Const, static_cast(static_cast(val)), \ 60 | static_cast(static_cast(val) >> 8), \ 61 | static_cast(static_cast(val) >> 16), \ 62 | static_cast(static_cast(val) >> 24), \ 63 | static_cast(static_cast(val) >> 32), \ 64 | static_cast(static_cast(val) >> 40), \ 65 | static_cast(static_cast(val) >> 48), \ 66 | static_cast(static_cast(val) >> 56) 67 | #define WASM_F32(val) \ 68 | kExprF32Const, \ 69 | static_cast(bit_cast(static_cast(val))), \ 70 | static_cast(bit_cast(static_cast(val)) >> 8), \ 71 | static_cast(bit_cast(static_cast(val)) >> 16), \ 72 | static_cast(bit_cast(static_cast(val)) >> 24) 73 | #define WASM_F64(val) \ 74 | kExprF64Const, static_cast(bit_cast(val)), \ 75 | static_cast(bit_cast(val) >> 8), \ 76 | static_cast(bit_cast(val) >> 16), \ 77 | static_cast(bit_cast(val) >> 24), \ 78 | static_cast(bit_cast(val) >> 32), \ 79 | static_cast(bit_cast(val) >> 40), \ 80 | static_cast(bit_cast(val) >> 48), \ 81 | static_cast(bit_cast(val) >> 56) 82 | #define WASM_GET_LOCAL(index) kExprGetLocal, static_cast(index) 83 | #define WASM_SET_LOCAL(index, val) kExprSetLocal, static_cast(index), val 84 | #define WASM_LOAD_GLOBAL(index) kExprLoadGlobal, static_cast(index) 85 | #define WASM_STORE_GLOBAL(index, val) \ 86 | kExprStoreGlobal, static_cast(index), val 87 | #define WASM_LOAD_MEM(type, index) \ 88 | static_cast( \ 89 | v8::internal::wasm::WasmOpcodes::LoadStoreOpcodeOf(type, false)), \ 90 | v8::internal::wasm::WasmOpcodes::LoadStoreAccessOf(false), index 91 | #define WASM_STORE_MEM(type, index, val) \ 92 | static_cast( \ 93 | v8::internal::wasm::WasmOpcodes::LoadStoreOpcodeOf(type, true)), \ 94 | v8::internal::wasm::WasmOpcodes::LoadStoreAccessOf(false), index, val 95 | #define WASM_LOAD_MEM_OFFSET(type, offset, index) \ 96 | static_cast( \ 97 | v8::internal::wasm::WasmOpcodes::LoadStoreOpcodeOf(type, false)), \ 98 | v8::internal::wasm::WasmOpcodes::LoadStoreAccessOf(true), \ 99 | static_cast(offset), index 100 | #define WASM_STORE_MEM_OFFSET(type, offset, index, val) \ 101 | static_cast( \ 102 | v8::internal::wasm::WasmOpcodes::LoadStoreOpcodeOf(type, true)), \ 103 | v8::internal::wasm::WasmOpcodes::LoadStoreAccessOf(true), \ 104 | static_cast(offset), index, val 105 | #define WASM_CALL_FUNCTION(index, ...) \ 106 | kExprCallFunction, static_cast(index), __VA_ARGS__ 107 | #define WASM_CALL_INDIRECT(index, func, ...) \ 108 | kExprCallIndirect, static_cast(index), func, __VA_ARGS__ 109 | #define WASM_CALL_FUNCTION0(index) kExprCallFunction, static_cast(index) 110 | #define WASM_CALL_INDIRECT0(index, func) \ 111 | kExprCallIndirect, static_cast(index), func 112 | #define WASM_NOT(x) kExprBoolNot, x 113 | 114 | //------------------------------------------------------------------------------ 115 | // Constructs that are composed of multiple bytecodes. 116 | //------------------------------------------------------------------------------ 117 | #define WASM_WHILE(x, y) kExprLoop, 1, kExprIf, x, kExprBr, 0, y 118 | #define WASM_INC_LOCAL(index) \ 119 | kExprSetLocal, static_cast(index), kExprI32Add, kExprGetLocal, \ 120 | static_cast(index), kExprI8Const, 1 121 | #define WASM_INC_LOCAL_BY(index, count) \ 122 | kExprSetLocal, static_cast(index), kExprI32Add, kExprGetLocal, \ 123 | static_cast(index), kExprI8Const, static_cast(count) 124 | 125 | #define WASM_UNOP(opcode, x) static_cast(opcode), x 126 | #define WASM_BINOP(opcode, x, y) static_cast(opcode), x, y 127 | 128 | //------------------------------------------------------------------------------ 129 | // Int32 operations 130 | //------------------------------------------------------------------------------ 131 | #define WASM_I32_ADD(x, y) kExprI32Add, x, y 132 | #define WASM_I32_SUB(x, y) kExprI32Sub, x, y 133 | #define WASM_I32_MUL(x, y) kExprI32Mul, x, y 134 | #define WASM_I32_DIVS(x, y) kExprI32DivS, x, y 135 | #define WASM_I32_DIVU(x, y) kExprI32DivU, x, y 136 | #define WASM_I32_REMS(x, y) kExprI32RemS, x, y 137 | #define WASM_I32_REMU(x, y) kExprI32RemU, x, y 138 | #define WASM_I32_AND(x, y) kExprI32And, x, y 139 | #define WASM_I32_IOR(x, y) kExprI32Ior, x, y 140 | #define WASM_I32_XOR(x, y) kExprI32Xor, x, y 141 | #define WASM_I32_SHL(x, y) kExprI32Shl, x, y 142 | #define WASM_I32_SHR(x, y) kExprI32ShrU, x, y 143 | #define WASM_I32_SAR(x, y) kExprI32ShrS, x, y 144 | #define WASM_I32_EQ(x, y) kExprI32Eq, x, y 145 | #define WASM_I32_NE(x, y) kExprI32Ne, x, y 146 | #define WASM_I32_LTS(x, y) kExprI32LtS, x, y 147 | #define WASM_I32_LES(x, y) kExprI32LeS, x, y 148 | #define WASM_I32_LTU(x, y) kExprI32LtU, x, y 149 | #define WASM_I32_LEU(x, y) kExprI32LeU, x, y 150 | #define WASM_I32_GTS(x, y) kExprI32GtS, x, y 151 | #define WASM_I32_GES(x, y) kExprI32GeS, x, y 152 | #define WASM_I32_GTU(x, y) kExprI32GtU, x, y 153 | #define WASM_I32_GEU(x, y) kExprI32GeU, x, y 154 | #define WASM_I32_CLZ(x) kExprI32Clz, x 155 | #define WASM_I32_CTZ(x) kExprI32Ctz, x 156 | #define WASM_I32_POPCNT(x) kExprI32Popcnt, x 157 | 158 | //------------------------------------------------------------------------------ 159 | // Int64 operations 160 | //------------------------------------------------------------------------------ 161 | #define WASM_I64_ADD(x, y) kExprI64Add, x, y 162 | #define WASM_I64_SUB(x, y) kExprI64Sub, x, y 163 | #define WASM_I64_MUL(x, y) kExprI64Mul, x, y 164 | #define WASM_I64_DIVS(x, y) kExprI64DivS, x, y 165 | #define WASM_I64_DIVU(x, y) kExprI64DivU, x, y 166 | #define WASM_I64_REMS(x, y) kExprI64RemS, x, y 167 | #define WASM_I64_REMU(x, y) kExprI64RemU, x, y 168 | #define WASM_I64_AND(x, y) kExprI64And, x, y 169 | #define WASM_I64_IOR(x, y) kExprI64Ior, x, y 170 | #define WASM_I64_XOR(x, y) kExprI64Xor, x, y 171 | #define WASM_I64_SHL(x, y) kExprI64Shl, x, y 172 | #define WASM_I64_SHR(x, y) kExprI64ShrU, x, y 173 | #define WASM_I64_SAR(x, y) kExprI64ShrS, x, y 174 | #define WASM_I64_EQ(x, y) kExprI64Eq, x, y 175 | #define WASM_I64_NE(x, y) kExprI64Ne, x, y 176 | #define WASM_I64_LTS(x, y) kExprI64LtS, x, y 177 | #define WASM_I64_LES(x, y) kExprI64LeS, x, y 178 | #define WASM_I64_LTU(x, y) kExprI64LtU, x, y 179 | #define WASM_I64_LEU(x, y) kExprI64LeU, x, y 180 | #define WASM_I64_GTS(x, y) kExprI64GtS, x, y 181 | #define WASM_I64_GES(x, y) kExprI64GeS, x, y 182 | #define WASM_I64_GTU(x, y) kExprI64GtU, x, y 183 | #define WASM_I64_GEU(x, y) kExprI64GeU, x, y 184 | #define WASM_I64_CLZ(x) kExprI64Clz, x 185 | #define WASM_I64_CTZ(x) kExprI64Ctz, x 186 | #define WASM_I64_POPCNT(x) kExprI64Popcnt, x 187 | 188 | //------------------------------------------------------------------------------ 189 | // Float32 operations 190 | //------------------------------------------------------------------------------ 191 | #define WASM_F32_ADD(x, y) kExprF32Add, x, y 192 | #define WASM_F32_SUB(x, y) kExprF32Sub, x, y 193 | #define WASM_F32_MUL(x, y) kExprF32Mul, x, y 194 | #define WASM_F32_DIV(x, y) kExprF32Div, x, y 195 | #define WASM_F32_MIN(x, y) kExprF32Min, x, y 196 | #define WASM_F32_MAX(x, y) kExprF32Max, x, y 197 | #define WASM_F32_ABS(x) kExprF32Abs, x 198 | #define WASM_F32_NEG(x) kExprF32Neg, x 199 | #define WASM_F32_COPYSIGN(x, y) kExprF32CopySign, x, y 200 | #define WASM_F32_CEIL(x) kExprF32Ceil, x 201 | #define WASM_F32_FLOOR(x) kExprF32Floor, x 202 | #define WASM_F32_TRUNC(x) kExprF32Trunc, x 203 | #define WASM_F32_NEARESTINT(x) kExprF32NearestInt, x 204 | #define WASM_F32_SQRT(x) kExprF32Sqrt, x 205 | #define WASM_F32_EQ(x, y) kExprF32Eq, x, y 206 | #define WASM_F32_NE(x, y) kExprF32Ne, x, y 207 | #define WASM_F32_LT(x, y) kExprF32Lt, x, y 208 | #define WASM_F32_LE(x, y) kExprF32Le, x, y 209 | #define WASM_F32_GT(x, y) kExprF32Gt, x, y 210 | #define WASM_F32_GE(x, y) kExprF32Ge, x, y 211 | 212 | //------------------------------------------------------------------------------ 213 | // Float64 operations 214 | //------------------------------------------------------------------------------ 215 | #define WASM_F64_ADD(x, y) kExprF64Add, x, y 216 | #define WASM_F64_SUB(x, y) kExprF64Sub, x, y 217 | #define WASM_F64_MUL(x, y) kExprF64Mul, x, y 218 | #define WASM_F64_DIV(x, y) kExprF64Div, x, y 219 | #define WASM_F64_MIN(x, y) kExprF64Min, x, y 220 | #define WASM_F64_MAX(x, y) kExprF64Max, x, y 221 | #define WASM_F64_ABS(x) kExprF64Abs, x 222 | #define WASM_F64_NEG(x) kExprF64Neg, x 223 | #define WASM_F64_COPYSIGN(x, y) kExprF64CopySign, x, y 224 | #define WASM_F64_CEIL(x) kExprF64Ceil, x 225 | #define WASM_F64_FLOOR(x) kExprF64Floor, x 226 | #define WASM_F64_TRUNC(x) kExprF64Trunc, x 227 | #define WASM_F64_NEARESTINT(x) kExprF64NearestInt, x 228 | #define WASM_F64_SQRT(x) kExprF64Sqrt, x 229 | #define WASM_F64_EQ(x, y) kExprF64Eq, x, y 230 | #define WASM_F64_NE(x, y) kExprF64Ne, x, y 231 | #define WASM_F64_LT(x, y) kExprF64Lt, x, y 232 | #define WASM_F64_LE(x, y) kExprF64Le, x, y 233 | #define WASM_F64_GT(x, y) kExprF64Gt, x, y 234 | #define WASM_F64_GE(x, y) kExprF64Ge, x, y 235 | 236 | //------------------------------------------------------------------------------ 237 | // Type conversions. 238 | //------------------------------------------------------------------------------ 239 | #define WASM_I32_SCONVERT_F32(x) kExprI32SConvertF32, x 240 | #define WASM_I32_SCONVERT_F64(x) kExprI32SConvertF64, x 241 | #define WASM_I32_UCONVERT_F32(x) kExprI32UConvertF32, x 242 | #define WASM_I32_UCONVERT_F64(x) kExprI32UConvertF64, x 243 | #define WASM_I32_CONVERT_I64(x) kExprI32ConvertI64, x 244 | #define WASM_I64_SCONVERT_F32(x) kExprI64SConvertF32, x 245 | #define WASM_I64_SCONVERT_F64(x) kExprI64SConvertF64, x 246 | #define WASM_I64_UCONVERT_F32(x) kExprI64UConvertF32, x 247 | #define WASM_I64_UCONVERT_F64(x) kExprI64UConvertF64, x 248 | #define WASM_I64_SCONVERT_I32(x) kExprI64SConvertI32, x 249 | #define WASM_I64_UCONVERT_I32(x) kExprI64UConvertI32, x 250 | #define WASM_F32_SCONVERT_I32(x) kExprF32SConvertI32, x 251 | #define WASM_F32_UCONVERT_I32(x) kExprF32UConvertI32, x 252 | #define WASM_F32_SCONVERT_I64(x) kExprF32SConvertI64, x 253 | #define WASM_F32_UCONVERT_I64(x) kExprF32UConvertI64, x 254 | #define WASM_F32_CONVERT_F64(x) kExprF32ConvertF64, x 255 | #define WASM_F32_REINTERPRET_I32(x) kExprF32ReinterpretI32, x 256 | #define WASM_F64_SCONVERT_I32(x) kExprF64SConvertI32, x 257 | #define WASM_F64_UCONVERT_I32(x) kExprF64UConvertI32, x 258 | #define WASM_F64_SCONVERT_I64(x) kExprF64SConvertI64, x 259 | #define WASM_F64_UCONVERT_I64(x) kExprF64UConvertI64, x 260 | #define WASM_F64_CONVERT_F32(x) kExprF64ConvertF32, x 261 | #define WASM_F64_REINTERPRET_I64(x) kExprF64ReinterpretI64, x 262 | #define WASM_I32_REINTERPRET_F32(x) kExprI32ReinterpretF32, x 263 | #define WASM_I64_REINTERPRET_F64(x) kExprI64ReinterpretF64, x 264 | 265 | #endif // V8_WASM_MACRO_GEN_H_ 266 | -------------------------------------------------------------------------------- /src/wasm/wasm-module.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_MODULE_H_ 6 | #define V8_WASM_MODULE_H_ 7 | 8 | #include "wasm-opcodes.h" 9 | #include "wasm-result.h" 10 | 11 | #include "src/api.h" 12 | #include "src/handles.h" 13 | 14 | namespace v8 { 15 | namespace internal { 16 | 17 | namespace compiler { 18 | class CallDescriptor; 19 | } 20 | 21 | namespace wasm { 22 | const size_t kMaxModuleSize = 1024 * 1024 * 1024; 23 | const size_t kMaxFunctionSize = 128 * 1024; 24 | const size_t kMaxStringSize = 256; 25 | 26 | enum WasmSectionDeclCode { 27 | kDeclMemory = 0x00, 28 | kDeclSignatures = 0x01, 29 | kDeclFunctions = 0x02, 30 | kDeclGlobals = 0x03, 31 | kDeclDataSegments = 0x04, 32 | kDeclFunctionTable = 0x05, 33 | kDeclEnd = 0x06, 34 | }; 35 | 36 | static const int kMaxModuleSectionCode = 6; 37 | 38 | enum WasmFunctionDeclBit { 39 | kDeclFunctionName = 0x01, 40 | kDeclFunctionImport = 0x02, 41 | kDeclFunctionLocals = 0x04, 42 | kDeclFunctionExport = 0x08 43 | }; 44 | 45 | // Constants for fixed-size elements within a module. 46 | static const size_t kDeclMemorySize = 3; 47 | static const size_t kDeclGlobalSize = 6; 48 | static const size_t kDeclDataSegmentSize = 13; 49 | 50 | // Static representation of a wasm function. 51 | struct WasmFunction { 52 | FunctionSig* sig; // signature of the function. 53 | uint16_t sig_index; // index into the signature table. 54 | uint32_t name_offset; // offset in the module bytes of the name, if any. 55 | uint32_t code_start_offset; // offset in the module bytes of code start. 56 | uint32_t code_end_offset; // offset in the module bytes of code end. 57 | uint16_t local_int32_count; // number of int32 local variables. 58 | uint16_t local_int64_count; // number of int64 local variables. 59 | uint16_t local_float32_count; // number of float32 local variables. 60 | uint16_t local_float64_count; // number of float64 local variables. 61 | bool exported; // true if this function is exported. 62 | bool external; // true if this function is externally supplied. 63 | }; 64 | 65 | struct ModuleEnv; // forward declaration of decoder interface. 66 | 67 | // Static representation of a wasm global variable. 68 | struct WasmGlobal { 69 | uint32_t name_offset; // offset in the module bytes of the name, if any. 70 | MachineType type; // type of the global. 71 | uint32_t offset; // offset from beginning of globals area. 72 | bool exported; // true if this global is exported. 73 | }; 74 | 75 | // Static representation of a wasm data segment. 76 | struct WasmDataSegment { 77 | uint32_t dest_addr; // destination memory address of the data. 78 | uint32_t source_offset; // start offset in the module bytes. 79 | uint32_t source_size; // end offset in the module bytes. 80 | bool init; // true if loaded upon instantiation. 81 | }; 82 | 83 | // Static representation of a module. 84 | struct WasmModule { 85 | static const uint8_t kMinMemSize = 12; // Minimum memory size = 4kb 86 | static const uint8_t kMaxMemSize = 30; // Maximum memory size = 1gb 87 | 88 | Isolate* shared_isolate; // isolate for storing shared code. 89 | const byte* module_start; // starting address for the module bytes. 90 | const byte* module_end; // end address for the module bytes. 91 | uint8_t min_mem_size_log2; // minimum size of the memory (log base 2). 92 | uint8_t max_mem_size_log2; // maximum size of the memory (log base 2). 93 | bool mem_export; // true if the memory is exported. 94 | bool mem_external; // true if the memory is external. 95 | 96 | std::vector* globals; // globals in this module. 97 | std::vector* signatures; // signatures in this module. 98 | std::vector* functions; // functions in this module. 99 | std::vector* data_segments; // data segments in this module. 100 | std::vector* function_table; // function table. 101 | 102 | // Get a pointer to a string stored in the module bytes representing a name. 103 | const char* GetName(uint32_t offset) { 104 | CHECK(BoundsCheck(offset, offset + 1)); 105 | if (offset == 0) return ""; // no name. 106 | return reinterpret_cast(module_start + offset); 107 | } 108 | 109 | // Checks the given offset range is contained within the module bytes. 110 | bool BoundsCheck(uint32_t start, uint32_t end) { 111 | size_t size = module_end - module_start; 112 | return start < size && end < size; 113 | } 114 | 115 | // Creates a new instantiation of the module in the given isolate. 116 | MaybeHandle Instantiate(Isolate* isolate, Handle ffi, 117 | Handle memory); 118 | }; 119 | 120 | // forward declaration. 121 | class WasmLinker; 122 | 123 | // Interface provided to the decoder/graph builder which contains only 124 | // minimal information about the globals, functions, and function tables. 125 | struct ModuleEnv { 126 | uintptr_t globals_area; // address of the globals area. 127 | uintptr_t mem_start; // address of the start of linear memory. 128 | uintptr_t mem_end; // address of the end of linear memory. 129 | 130 | WasmModule* module; 131 | WasmLinker* linker; 132 | std::vector>* function_code; 133 | Handle function_table; 134 | Handle memory; 135 | Handle context; 136 | bool asm_js; // true if the module originated from asm.js. 137 | 138 | bool IsValidGlobal(uint32_t index) { 139 | return module && index < module->globals->size(); 140 | } 141 | bool IsValidFunction(uint32_t index) { 142 | return module && index < module->functions->size(); 143 | } 144 | bool IsValidSignature(uint32_t index) { 145 | return module && index < module->signatures->size(); 146 | } 147 | MachineType GetGlobalType(uint32_t index) { 148 | DCHECK(IsValidGlobal(index)); 149 | return module->globals->at(index).type; 150 | } 151 | FunctionSig* GetFunctionSignature(uint32_t index) { 152 | DCHECK(IsValidFunction(index)); 153 | return module->functions->at(index).sig; 154 | } 155 | FunctionSig* GetSignature(uint32_t index) { 156 | DCHECK(IsValidSignature(index)); 157 | return module->signatures->at(index); 158 | } 159 | size_t FunctionTableSize() { 160 | return module ? module->function_table->size() : 0; 161 | } 162 | 163 | Handle GetFunctionCode(uint32_t index); 164 | Handle GetFunctionTable(); 165 | 166 | compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone, FunctionSig* sig); 167 | compiler::CallDescriptor* GetCallDescriptor(Zone* zone, uint32_t index); 168 | }; 169 | 170 | std::ostream& operator<<(std::ostream& os, const WasmModule& module); 171 | std::ostream& operator<<(std::ostream& os, const WasmFunction& function); 172 | 173 | typedef Result ModuleResult; 174 | typedef Result FunctionResult; 175 | 176 | // For testing. Decode, verify, and run the last exported function in the 177 | // given encoded module. 178 | int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start, 179 | const byte* module_end, bool asm_js = false); 180 | 181 | // For testing. Decode, verify, and run the last exported function in the 182 | // given decoded module. 183 | int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module); 184 | } 185 | } 186 | } 187 | 188 | #endif // V8_WASM_MODULE_H_ 189 | -------------------------------------------------------------------------------- /src/wasm/wasm-opcodes.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "src/wasm/wasm-opcodes.h" 6 | #include "src/signature.h" 7 | 8 | namespace v8 { 9 | namespace internal { 10 | namespace wasm { 11 | 12 | typedef Signature FunctionSig; 13 | 14 | const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) { 15 | switch (opcode) { 16 | #define DECLARE_NAME_CASE(name, opcode, sig) \ 17 | case kExpr##name: \ 18 | return "Expr" #name; 19 | FOREACH_OPCODE(DECLARE_NAME_CASE) 20 | #undef DECLARE_NAME_CASE 21 | default: 22 | break; 23 | } 24 | return "Unknown"; 25 | } 26 | 27 | #define DECLARE_SIG_ENUM(name, ...) kSigEnum_##name, 28 | 29 | enum WasmOpcodeSig { FOREACH_SIGNATURE(DECLARE_SIG_ENUM) }; 30 | 31 | // TODO(titzer): not static-initializer safe. Wrap in LazyInstance. 32 | #define DECLARE_SIG(name, ...) \ 33 | static LocalType kTypes_##name[] = {__VA_ARGS__}; \ 34 | static const FunctionSig kSig_##name( \ 35 | 1, static_cast(arraysize(kTypes_##name)) - 1, kTypes_##name); 36 | 37 | FOREACH_SIGNATURE(DECLARE_SIG) 38 | 39 | #define DECLARE_SIG_ENTRY(name, ...) &kSig_##name, 40 | 41 | static const FunctionSig* kSimpleExprSigs[] = { 42 | nullptr, FOREACH_SIGNATURE(DECLARE_SIG_ENTRY)}; 43 | 44 | static byte kSimpleExprSigTable[256]; 45 | 46 | // Initialize the signature table. 47 | static void InitSigTable() { 48 | #define SET_SIG_TABLE(name, opcode, sig) \ 49 | kSimpleExprSigTable[opcode] = static_cast(kSigEnum_##sig) + 1; 50 | FOREACH_SIMPLE_OPCODE(SET_SIG_TABLE); 51 | #undef SET_SIG_TABLE 52 | } 53 | 54 | FunctionSig* WasmOpcodes::Signature(WasmOpcode opcode) { 55 | // TODO(titzer): use LazyInstance to make this thread safe. 56 | if (kSimpleExprSigTable[kExprI32Add] == 0) InitSigTable(); 57 | return const_cast( 58 | kSimpleExprSigs[kSimpleExprSigTable[static_cast(opcode)]]); 59 | } 60 | 61 | // TODO(titzer): pull WASM_64 up to a common header. 62 | #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 63 | #define WASM_64 1 64 | #else 65 | #define WASM_64 0 66 | #endif 67 | 68 | bool WasmOpcodes::IsSupported(WasmOpcode opcode) { 69 | switch (opcode) { 70 | #if !WASM_64 71 | // Opcodes not supported on 32-bit platforms. 72 | case kExprI64Add: 73 | case kExprI64Sub: 74 | case kExprI64Mul: 75 | case kExprI64DivS: 76 | case kExprI64DivU: 77 | case kExprI64RemS: 78 | case kExprI64RemU: 79 | case kExprI64And: 80 | case kExprI64Ior: 81 | case kExprI64Xor: 82 | case kExprI64Shl: 83 | case kExprI64ShrU: 84 | case kExprI64ShrS: 85 | case kExprI64Eq: 86 | case kExprI64Ne: 87 | case kExprI64LtS: 88 | case kExprI64LeS: 89 | case kExprI64LtU: 90 | case kExprI64LeU: 91 | case kExprI64GtS: 92 | case kExprI64GeS: 93 | case kExprI64GtU: 94 | case kExprI64GeU: 95 | 96 | case kExprI32ConvertI64: 97 | case kExprI64SConvertI32: 98 | case kExprI64UConvertI32: 99 | 100 | case kExprF64ReinterpretI64: 101 | case kExprI64ReinterpretF64: 102 | 103 | case kExprI64Clz: 104 | case kExprI64Ctz: 105 | case kExprI64Popcnt: 106 | 107 | case kExprF32SConvertI64: 108 | case kExprF32UConvertI64: 109 | case kExprF64SConvertI64: 110 | case kExprF64UConvertI64: 111 | 112 | #endif 113 | 114 | case kExprI64SConvertF32: 115 | case kExprI64SConvertF64: 116 | case kExprI64UConvertF32: 117 | case kExprI64UConvertF64: 118 | return false; 119 | default: 120 | return true; 121 | } 122 | } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/wasm/wasm-opcodes.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_OPCODES_H_ 6 | #define V8_WASM_OPCODES_H_ 7 | 8 | #include "src/signature.h" 9 | #include "src/machine-type.h" 10 | 11 | namespace v8 { 12 | namespace internal { 13 | namespace wasm { 14 | 15 | // Binary encoding of local types. 16 | enum LocalTypeCode { 17 | kLocalVoid = 0, 18 | kLocalI32 = 1, 19 | kLocalI64 = 2, 20 | kLocalF32 = 3, 21 | kLocalF64 = 4 22 | }; 23 | 24 | // Binary encoding of memory types. 25 | enum MemTypeCode { 26 | kMemI8 = 0, 27 | kMemU8 = 1, 28 | kMemI16 = 2, 29 | kMemU16 = 3, 30 | kMemI32 = 4, 31 | kMemU32 = 5, 32 | kMemI64 = 6, 33 | kMemU64 = 7, 34 | kMemF32 = 8, 35 | kMemF64 = 9 36 | }; 37 | 38 | // We reuse the internal machine type to represent WebAssembly AST types. 39 | // A typedef improves readability without adding a whole new type system. 40 | typedef MachineRepresentation LocalType; 41 | const LocalType kAstStmt = MachineRepresentation::kNone; 42 | const LocalType kAstI32 = MachineRepresentation::kWord32; 43 | const LocalType kAstI64 = MachineRepresentation::kWord64; 44 | const LocalType kAstF32 = MachineRepresentation::kFloat32; 45 | const LocalType kAstF64 = MachineRepresentation::kFloat64; 46 | // We use kTagged here because kNone is already used by kAstStmt. 47 | const LocalType kAstEnd = MachineRepresentation::kTagged; 48 | 49 | // Functionality related to encoding memory accesses. 50 | struct MemoryAccess { 51 | // Atomicity annotations for access to the memory and globals. 52 | enum Atomicity { 53 | kNone = 0, // non-atomic 54 | kSequential = 1, // sequential consistency 55 | kAcquire = 2, // acquire semantics 56 | kRelease = 3 // release semantics 57 | }; 58 | 59 | // Alignment annotations for memory accesses. 60 | enum Alignment { kAligned = 0, kUnaligned = 1 }; 61 | 62 | // Bitfields for the various annotations for memory accesses. 63 | typedef BitField AlignmentField; 64 | typedef BitField AtomicityField; 65 | typedef BitField OffsetField; 66 | }; 67 | 68 | typedef Signature FunctionSig; 69 | 70 | // Control expressions and blocks. 71 | #define FOREACH_CONTROL_OPCODE(V) \ 72 | V(Nop, 0x00, _) \ 73 | V(Block, 0x01, _) \ 74 | V(Loop, 0x02, _) \ 75 | V(If, 0x03, _) \ 76 | V(IfElse, 0x04, _) \ 77 | V(Select, 0x05, _) \ 78 | V(Br, 0x06, _) \ 79 | V(BrIf, 0x07, _) \ 80 | V(TableSwitch, 0x08, _) \ 81 | V(Return, 0x14, _) \ 82 | V(Unreachable, 0x15, _) 83 | // TODO(titzer): numbering 84 | 85 | // Constants, locals, globals, and calls. 86 | #define FOREACH_MISC_OPCODE(V) \ 87 | V(I8Const, 0x09, _) \ 88 | V(I32Const, 0x0a, _) \ 89 | V(I64Const, 0x0b, _) \ 90 | V(F64Const, 0x0c, _) \ 91 | V(F32Const, 0x0d, _) \ 92 | V(GetLocal, 0x0e, _) \ 93 | V(SetLocal, 0x0f, _) \ 94 | V(LoadGlobal, 0x10, _) \ 95 | V(StoreGlobal, 0x11, _) \ 96 | V(CallFunction, 0x12, _) \ 97 | V(CallIndirect, 0x13, _) 98 | 99 | // Load memory expressions. 100 | #define FOREACH_LOAD_MEM_OPCODE(V) \ 101 | V(I32LoadMem8S, 0x20, i_i) \ 102 | V(I32LoadMem8U, 0x21, i_i) \ 103 | V(I32LoadMem16S, 0x22, i_i) \ 104 | V(I32LoadMem16U, 0x23, i_i) \ 105 | V(I64LoadMem8S, 0x24, l_i) \ 106 | V(I64LoadMem8U, 0x25, l_i) \ 107 | V(I64LoadMem16S, 0x26, l_i) \ 108 | V(I64LoadMem16U, 0x27, l_i) \ 109 | V(I64LoadMem32S, 0x28, l_i) \ 110 | V(I64LoadMem32U, 0x29, l_i) \ 111 | V(I32LoadMem, 0x2a, i_i) \ 112 | V(I64LoadMem, 0x2b, l_i) \ 113 | V(F32LoadMem, 0x2c, f_i) \ 114 | V(F64LoadMem, 0x2d, d_i) 115 | 116 | // Store memory expressions. 117 | #define FOREACH_STORE_MEM_OPCODE(V) \ 118 | V(I32StoreMem8, 0x2e, i_ii) \ 119 | V(I32StoreMem16, 0x2f, i_ii) \ 120 | V(I64StoreMem8, 0x30, l_il) \ 121 | V(I64StoreMem16, 0x31, l_il) \ 122 | V(I64StoreMem32, 0x32, l_il) \ 123 | V(I32StoreMem, 0x33, i_ii) \ 124 | V(I64StoreMem, 0x34, l_il) \ 125 | V(F32StoreMem, 0x35, f_if) \ 126 | V(F64StoreMem, 0x36, d_id) 127 | 128 | // Load memory expressions. 129 | #define FOREACH_MISC_MEM_OPCODE(V) \ 130 | V(MemorySize, 0x3b, i_v) \ 131 | V(GrowMemory, 0x39, i_i) 132 | 133 | // Expressions with signatures. 134 | #define FOREACH_SIMPLE_OPCODE(V) \ 135 | V(I32Add, 0x40, i_ii) \ 136 | V(I32Sub, 0x41, i_ii) \ 137 | V(I32Mul, 0x42, i_ii) \ 138 | V(I32DivS, 0x43, i_ii) \ 139 | V(I32DivU, 0x44, i_ii) \ 140 | V(I32RemS, 0x45, i_ii) \ 141 | V(I32RemU, 0x46, i_ii) \ 142 | V(I32And, 0x47, i_ii) \ 143 | V(I32Ior, 0x48, i_ii) \ 144 | V(I32Xor, 0x49, i_ii) \ 145 | V(I32Shl, 0x4a, i_ii) \ 146 | V(I32ShrU, 0x4b, i_ii) \ 147 | V(I32ShrS, 0x4c, i_ii) \ 148 | V(I32Eq, 0x4d, i_ii) \ 149 | V(I32Ne, 0x4e, i_ii) \ 150 | V(I32LtS, 0x4f, i_ii) \ 151 | V(I32LeS, 0x50, i_ii) \ 152 | V(I32LtU, 0x51, i_ii) \ 153 | V(I32LeU, 0x52, i_ii) \ 154 | V(I32GtS, 0x53, i_ii) \ 155 | V(I32GeS, 0x54, i_ii) \ 156 | V(I32GtU, 0x55, i_ii) \ 157 | V(I32GeU, 0x56, i_ii) \ 158 | V(I32Clz, 0x57, i_i) \ 159 | V(I32Ctz, 0x58, i_i) \ 160 | V(I32Popcnt, 0x59, i_i) \ 161 | V(BoolNot, 0x5a, i_i) \ 162 | V(I64Add, 0x5b, l_ll) \ 163 | V(I64Sub, 0x5c, l_ll) \ 164 | V(I64Mul, 0x5d, l_ll) \ 165 | V(I64DivS, 0x5e, l_ll) \ 166 | V(I64DivU, 0x5f, l_ll) \ 167 | V(I64RemS, 0x60, l_ll) \ 168 | V(I64RemU, 0x61, l_ll) \ 169 | V(I64And, 0x62, l_ll) \ 170 | V(I64Ior, 0x63, l_ll) \ 171 | V(I64Xor, 0x64, l_ll) \ 172 | V(I64Shl, 0x65, l_ll) \ 173 | V(I64ShrU, 0x66, l_ll) \ 174 | V(I64ShrS, 0x67, l_ll) \ 175 | V(I64Eq, 0x68, i_ll) \ 176 | V(I64Ne, 0x69, i_ll) \ 177 | V(I64LtS, 0x6a, i_ll) \ 178 | V(I64LeS, 0x6b, i_ll) \ 179 | V(I64LtU, 0x6c, i_ll) \ 180 | V(I64LeU, 0x6d, i_ll) \ 181 | V(I64GtS, 0x6e, i_ll) \ 182 | V(I64GeS, 0x6f, i_ll) \ 183 | V(I64GtU, 0x70, i_ll) \ 184 | V(I64GeU, 0x71, i_ll) \ 185 | V(I64Clz, 0x72, l_l) \ 186 | V(I64Ctz, 0x73, l_l) \ 187 | V(I64Popcnt, 0x74, l_l) \ 188 | V(F32Add, 0x75, f_ff) \ 189 | V(F32Sub, 0x76, f_ff) \ 190 | V(F32Mul, 0x77, f_ff) \ 191 | V(F32Div, 0x78, f_ff) \ 192 | V(F32Min, 0x79, f_ff) \ 193 | V(F32Max, 0x7a, f_ff) \ 194 | V(F32Abs, 0x7b, f_f) \ 195 | V(F32Neg, 0x7c, f_f) \ 196 | V(F32CopySign, 0x7d, f_ff) \ 197 | V(F32Ceil, 0x7e, f_f) \ 198 | V(F32Floor, 0x7f, f_f) \ 199 | V(F32Trunc, 0x80, f_f) \ 200 | V(F32NearestInt, 0x81, f_f) \ 201 | V(F32Sqrt, 0x82, f_f) \ 202 | V(F32Eq, 0x83, i_ff) \ 203 | V(F32Ne, 0x84, i_ff) \ 204 | V(F32Lt, 0x85, i_ff) \ 205 | V(F32Le, 0x86, i_ff) \ 206 | V(F32Gt, 0x87, i_ff) \ 207 | V(F32Ge, 0x88, i_ff) \ 208 | V(F64Add, 0x89, d_dd) \ 209 | V(F64Sub, 0x8a, d_dd) \ 210 | V(F64Mul, 0x8b, d_dd) \ 211 | V(F64Div, 0x8c, d_dd) \ 212 | V(F64Min, 0x8d, d_dd) \ 213 | V(F64Max, 0x8e, d_dd) \ 214 | V(F64Abs, 0x8f, d_d) \ 215 | V(F64Neg, 0x90, d_d) \ 216 | V(F64CopySign, 0x91, d_dd) \ 217 | V(F64Ceil, 0x92, d_d) \ 218 | V(F64Floor, 0x93, d_d) \ 219 | V(F64Trunc, 0x94, d_d) \ 220 | V(F64NearestInt, 0x95, d_d) \ 221 | V(F64Sqrt, 0x96, d_d) \ 222 | V(F64Eq, 0x97, i_dd) \ 223 | V(F64Ne, 0x98, i_dd) \ 224 | V(F64Lt, 0x99, i_dd) \ 225 | V(F64Le, 0x9a, i_dd) \ 226 | V(F64Gt, 0x9b, i_dd) \ 227 | V(F64Ge, 0x9c, i_dd) \ 228 | V(I32SConvertF32, 0x9d, i_f) \ 229 | V(I32SConvertF64, 0x9e, i_d) \ 230 | V(I32UConvertF32, 0x9f, i_f) \ 231 | V(I32UConvertF64, 0xa0, i_d) \ 232 | V(I32ConvertI64, 0xa1, i_l) \ 233 | V(I64SConvertF32, 0xa2, l_f) \ 234 | V(I64SConvertF64, 0xa3, l_d) \ 235 | V(I64UConvertF32, 0xa4, l_f) \ 236 | V(I64UConvertF64, 0xa5, l_d) \ 237 | V(I64SConvertI32, 0xa6, l_i) \ 238 | V(I64UConvertI32, 0xa7, l_i) \ 239 | V(F32SConvertI32, 0xa8, f_i) \ 240 | V(F32UConvertI32, 0xa9, f_i) \ 241 | V(F32SConvertI64, 0xaa, f_l) \ 242 | V(F32UConvertI64, 0xab, f_l) \ 243 | V(F32ConvertF64, 0xac, f_d) \ 244 | V(F32ReinterpretI32, 0xad, f_i) \ 245 | V(F64SConvertI32, 0xae, d_i) \ 246 | V(F64UConvertI32, 0xaf, d_i) \ 247 | V(F64SConvertI64, 0xb0, d_l) \ 248 | V(F64UConvertI64, 0xb1, d_l) \ 249 | V(F64ConvertF32, 0xb2, d_f) \ 250 | V(F64ReinterpretI64, 0xb3, d_l) \ 251 | V(I32ReinterpretF32, 0xb4, i_f) \ 252 | V(I64ReinterpretF64, 0xb5, l_d) 253 | 254 | // All opcodes. 255 | #define FOREACH_OPCODE(V) \ 256 | FOREACH_CONTROL_OPCODE(V) \ 257 | FOREACH_MISC_OPCODE(V) \ 258 | FOREACH_SIMPLE_OPCODE(V) \ 259 | FOREACH_STORE_MEM_OPCODE(V) \ 260 | FOREACH_LOAD_MEM_OPCODE(V) \ 261 | FOREACH_MISC_MEM_OPCODE(V) 262 | 263 | // All signatures. 264 | #define FOREACH_SIGNATURE(V) \ 265 | V(i_ii, kAstI32, kAstI32, kAstI32) \ 266 | V(i_i, kAstI32, kAstI32) \ 267 | V(i_v, kAstI32) \ 268 | V(i_ff, kAstI32, kAstF32, kAstF32) \ 269 | V(i_f, kAstI32, kAstF32) \ 270 | V(i_dd, kAstI32, kAstF64, kAstF64) \ 271 | V(i_d, kAstI32, kAstF64) \ 272 | V(i_l, kAstI32, kAstI64) \ 273 | V(l_ll, kAstI64, kAstI64, kAstI64) \ 274 | V(i_ll, kAstI32, kAstI64, kAstI64) \ 275 | V(l_l, kAstI64, kAstI64) \ 276 | V(l_i, kAstI64, kAstI32) \ 277 | V(l_f, kAstI64, kAstF32) \ 278 | V(l_d, kAstI64, kAstF64) \ 279 | V(f_ff, kAstF32, kAstF32, kAstF32) \ 280 | V(f_f, kAstF32, kAstF32) \ 281 | V(f_d, kAstF32, kAstF64) \ 282 | V(f_i, kAstF32, kAstI32) \ 283 | V(f_l, kAstF32, kAstI64) \ 284 | V(d_dd, kAstF64, kAstF64, kAstF64) \ 285 | V(d_d, kAstF64, kAstF64) \ 286 | V(d_f, kAstF64, kAstF32) \ 287 | V(d_i, kAstF64, kAstI32) \ 288 | V(d_l, kAstF64, kAstI64) \ 289 | V(d_id, kAstF64, kAstI32, kAstF64) \ 290 | V(f_if, kAstF32, kAstI32, kAstF32) \ 291 | V(l_il, kAstI64, kAstI32, kAstI64) 292 | 293 | enum WasmOpcode { 294 | // Declare expression opcodes. 295 | #define DECLARE_NAMED_ENUM(name, opcode, sig) kExpr##name = opcode, 296 | FOREACH_OPCODE(DECLARE_NAMED_ENUM) 297 | #undef DECLARE_NAMED_ENUM 298 | }; 299 | 300 | // A collection of opcode-related static methods. 301 | class WasmOpcodes { 302 | public: 303 | static bool IsSupported(WasmOpcode opcode); 304 | static const char* OpcodeName(WasmOpcode opcode); 305 | static FunctionSig* Signature(WasmOpcode opcode); 306 | 307 | static byte MemSize(MachineType type) { 308 | return 1 << ElementSizeLog2Of(type.representation()); 309 | } 310 | 311 | static LocalTypeCode LocalTypeCodeFor(LocalType type) { 312 | switch (type) { 313 | case kAstI32: 314 | return kLocalI32; 315 | case kAstI64: 316 | return kLocalI64; 317 | case kAstF32: 318 | return kLocalF32; 319 | case kAstF64: 320 | return kLocalF64; 321 | case kAstStmt: 322 | return kLocalVoid; 323 | default: 324 | UNREACHABLE(); 325 | return kLocalVoid; 326 | } 327 | } 328 | 329 | static MemTypeCode MemTypeCodeFor(MachineType type) { 330 | if (type == MachineType::Int8()) { 331 | return kMemI8; 332 | } else if (type == MachineType::Uint8()) { 333 | return kMemU8; 334 | } else if (type == MachineType::Int16()) { 335 | return kMemI16; 336 | } else if (type == MachineType::Uint16()) { 337 | return kMemU16; 338 | } else if (type == MachineType::Int32()) { 339 | return kMemI32; 340 | } else if (type == MachineType::Uint32()) { 341 | return kMemU32; 342 | } else if (type == MachineType::Int64()) { 343 | return kMemI64; 344 | } else if (type == MachineType::Uint64()) { 345 | return kMemU64; 346 | } else if (type == MachineType::Float32()) { 347 | return kMemF32; 348 | } else if (type == MachineType::Float64()) { 349 | return kMemF64; 350 | } else { 351 | UNREACHABLE(); 352 | return kMemI32; 353 | } 354 | } 355 | 356 | static MachineType MachineTypeFor(LocalType type) { 357 | switch (type) { 358 | case kAstI32: 359 | return MachineType::Int32(); 360 | case kAstI64: 361 | return MachineType::Int64(); 362 | case kAstF32: 363 | return MachineType::Float32(); 364 | case kAstF64: 365 | return MachineType::Float64(); 366 | case kAstStmt: 367 | return MachineType::None(); 368 | default: 369 | UNREACHABLE(); 370 | return MachineType::None(); 371 | } 372 | } 373 | 374 | static LocalType LocalTypeFor(MachineType type) { 375 | if (type == MachineType::Int8()) { 376 | return kAstI32; 377 | } else if (type == MachineType::Uint8()) { 378 | return kAstI32; 379 | } else if (type == MachineType::Int16()) { 380 | return kAstI32; 381 | } else if (type == MachineType::Uint16()) { 382 | return kAstI32; 383 | } else if (type == MachineType::Int32()) { 384 | return kAstI32; 385 | } else if (type == MachineType::Uint32()) { 386 | return kAstI32; 387 | } else if (type == MachineType::Int64()) { 388 | return kAstI64; 389 | } else if (type == MachineType::Uint64()) { 390 | return kAstI64; 391 | } else if (type == MachineType::Float32()) { 392 | return kAstF32; 393 | } else if (type == MachineType::Float64()) { 394 | return kAstF64; 395 | } else { 396 | UNREACHABLE(); 397 | return kAstI32; 398 | } 399 | } 400 | 401 | // TODO(titzer): remove this method 402 | static WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) { 403 | if (type == MachineType::Int8()) { 404 | return store ? kExprI32StoreMem8 : kExprI32LoadMem8S; 405 | } else if (type == MachineType::Uint8()) { 406 | return store ? kExprI32StoreMem8 : kExprI32LoadMem8U; 407 | } else if (type == MachineType::Int16()) { 408 | return store ? kExprI32StoreMem16 : kExprI32LoadMem16S; 409 | } else if (type == MachineType::Uint16()) { 410 | return store ? kExprI32StoreMem16 : kExprI32LoadMem16U; 411 | } else if (type == MachineType::Int32()) { 412 | return store ? kExprI32StoreMem : kExprI32LoadMem; 413 | } else if (type == MachineType::Uint32()) { 414 | return store ? kExprI32StoreMem : kExprI32LoadMem; 415 | } else if (type == MachineType::Int64()) { 416 | return store ? kExprI64StoreMem : kExprI64LoadMem; 417 | } else if (type == MachineType::Uint64()) { 418 | return store ? kExprI64StoreMem : kExprI64LoadMem; 419 | } else if (type == MachineType::Float32()) { 420 | return store ? kExprF32StoreMem : kExprF32LoadMem; 421 | } else if (type == MachineType::Float64()) { 422 | return store ? kExprF64StoreMem : kExprF64LoadMem; 423 | } else { 424 | UNREACHABLE(); 425 | return kExprNop; 426 | } 427 | } 428 | 429 | static byte LoadStoreAccessOf(bool with_offset) { 430 | return MemoryAccess::OffsetField::encode(with_offset); 431 | } 432 | 433 | static char ShortNameOf(LocalType type) { 434 | switch (type) { 435 | case kAstI32: 436 | return 'i'; 437 | case kAstI64: 438 | return 'l'; 439 | case kAstF32: 440 | return 'f'; 441 | case kAstF64: 442 | return 'd'; 443 | case kAstStmt: 444 | return 'v'; 445 | case kAstEnd: 446 | return 'x'; 447 | default: 448 | UNREACHABLE(); 449 | return '?'; 450 | } 451 | } 452 | 453 | static const char* TypeName(LocalType type) { 454 | switch (type) { 455 | case kAstI32: 456 | return "i32"; 457 | case kAstI64: 458 | return "i64"; 459 | case kAstF32: 460 | return "f32"; 461 | case kAstF64: 462 | return "f64"; 463 | case kAstStmt: 464 | return ""; 465 | case kAstEnd: 466 | return ""; 467 | default: 468 | return ""; 469 | } 470 | } 471 | }; 472 | } 473 | } 474 | } 475 | 476 | #endif // V8_WASM_OPCODES_H_ 477 | -------------------------------------------------------------------------------- /src/wasm/wasm-result.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "src/wasm/wasm-result.h" 6 | 7 | #include "src/factory.h" 8 | #include "src/heap/heap.h" 9 | #include "src/isolate.h" 10 | #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! 11 | #include "src/objects.h" 12 | 13 | #include "src/base/platform/platform.h" 14 | 15 | namespace v8 { 16 | namespace internal { 17 | namespace wasm { 18 | 19 | std::ostream& operator<<(std::ostream& os, const ErrorCode& error_code) { 20 | switch (error_code) { 21 | case kSuccess: 22 | os << "Success"; 23 | break; 24 | default: // TODO(titzer): render error codes 25 | os << "Error"; 26 | break; 27 | } 28 | return os; 29 | } 30 | 31 | void ErrorThrower::Error(const char* format, ...) { 32 | if (error_) return; // only report the first error. 33 | error_ = true; 34 | char buffer[256]; 35 | 36 | va_list arguments; 37 | va_start(arguments, format); 38 | base::OS::VSNPrintF(buffer, 255, format, arguments); 39 | va_end(arguments); 40 | 41 | std::ostringstream str; 42 | if (context_ != nullptr) { 43 | str << context_ << ": "; 44 | } 45 | str << buffer; 46 | 47 | isolate_->ScheduleThrow( 48 | *isolate_->factory()->NewStringFromAsciiChecked(str.str().c_str())); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/wasm/wasm-result.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef V8_WASM_RESULT_H_ 6 | #define V8_WASM_RESULT_H_ 7 | 8 | #include "src/v8.h" 9 | 10 | #include "src/base/smart-pointers.h" 11 | 12 | namespace v8 { 13 | namespace internal { 14 | 15 | class Isolate; 16 | 17 | namespace wasm { 18 | 19 | // Error codes for programmatic checking of the decoder's verification. 20 | enum ErrorCode { 21 | kSuccess, 22 | kError, // TODO(titzer): remove me 23 | kOutOfMemory, // decoder ran out of memory 24 | kEndOfCode, // end of code reached prematurely 25 | kInvalidOpcode, // found invalid opcode 26 | kUnreachableCode, // found unreachable code 27 | kImproperContinue, // improperly nested continue 28 | kImproperBreak, // improperly nested break 29 | kReturnCount, // return count mismatch 30 | kTypeError, // type mismatch 31 | kInvalidLocalIndex, // invalid local 32 | kInvalidGlobalIndex, // invalid global 33 | kInvalidFunctionIndex, // invalid function 34 | kInvalidMemType // invalid memory type 35 | }; 36 | 37 | // The overall result of decoding a function or a module. 38 | template 39 | struct Result { 40 | Result() 41 | : val(nullptr), error_code(kSuccess), start(nullptr), error_pc(nullptr) { 42 | error_msg.Reset(nullptr); 43 | } 44 | 45 | T val; 46 | ErrorCode error_code; 47 | const byte* start; 48 | const byte* error_pc; 49 | const byte* error_pt; 50 | base::SmartArrayPointer error_msg; 51 | 52 | bool ok() const { return error_code == kSuccess; } 53 | bool failed() const { return error_code != kSuccess; } 54 | 55 | template 56 | void CopyFrom(Result& that) { 57 | error_code = that.error_code; 58 | start = that.start; 59 | error_pc = that.error_pc; 60 | error_pt = that.error_pt; 61 | error_msg = that.error_msg; 62 | } 63 | }; 64 | 65 | template 66 | std::ostream& operator<<(std::ostream& os, const Result& result) { 67 | os << "Result = "; 68 | if (result.ok()) { 69 | if (result.val != nullptr) { 70 | os << *result.val; 71 | } else { 72 | os << "success (no value)"; 73 | } 74 | } else if (result.error_msg.get() != nullptr) { 75 | ptrdiff_t offset = result.error_pc - result.start; 76 | if (offset < 0) { 77 | os << result.error_msg.get() << " @" << offset; 78 | } else { 79 | os << result.error_msg.get() << " @+" << offset; 80 | } 81 | } else { 82 | os << result.error_code; 83 | } 84 | os << std::endl; 85 | return os; 86 | } 87 | 88 | std::ostream& operator<<(std::ostream& os, const ErrorCode& error_code); 89 | 90 | // A helper for generating error messages that bubble up to JS exceptions. 91 | class ErrorThrower { 92 | public: 93 | ErrorThrower(Isolate* isolate, const char* context) 94 | : isolate_(isolate), context_(context), error_(false) {} 95 | 96 | void Error(const char* fmt, ...); 97 | 98 | template 99 | void Failed(const char* error, Result& result) { 100 | std::ostringstream str; 101 | str << error << result; 102 | return Error(str.str().c_str()); 103 | } 104 | 105 | bool error() const { return error_; } 106 | 107 | private: 108 | Isolate* isolate_; 109 | const char* context_; 110 | bool error_; 111 | }; 112 | } 113 | } 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /src/wasm/wasm.gyp: -------------------------------------------------------------------------------- 1 | # Copyright 2015 the V8 project authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style license that can be 3 | # found in the LICENSE file. 4 | 5 | { 6 | 'targets': [ 7 | { 8 | 'target_name': 'wasm', 9 | 'toolsets': ['target', 'host'], 10 | 'type': 'none', 11 | # A list of additional sources and options to be injected into: 12 | # tools/gyp/v8.gyp:v8_base 13 | 'direct_dependent_settings': { 14 | 'include_dirs': ['../..'], 15 | 'sources': [ 16 | 'asm-wasm-builder.cc', 17 | 'asm-wasm-builder.h', 18 | 'ast-decoder.cc', 19 | 'ast-decoder.h', 20 | 'decoder.h', 21 | 'encoder.cc', 22 | 'encoder.h', 23 | 'module-decoder.cc', 24 | 'module-decoder.h', 25 | 'wasm-compiler.h', 26 | 'wasm-compiler.cc', 27 | 'wasm-js.cc', 28 | 'wasm-js.h', 29 | 'wasm-linkage.cc', 30 | 'wasm-macro-gen.h', 31 | 'wasm-module.cc', 32 | 'wasm-module.h', 33 | 'wasm-opcodes.cc', 34 | 'wasm-opcodes.h', 35 | 'wasm-result.cc', 36 | 'wasm-result.h', 37 | ], 38 | }, 39 | }, 40 | ], 41 | } 42 | -------------------------------------------------------------------------------- /test/cctest/wasm/test-run-wasm-module.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include 6 | #include 7 | 8 | #include "src/wasm/encoder.h" 9 | #include "src/wasm/wasm-macro-gen.h" 10 | #include "src/wasm/wasm-module.h" 11 | #include "src/wasm/wasm-opcodes.h" 12 | 13 | #include "test/cctest/cctest.h" 14 | 15 | using namespace v8::base; 16 | using namespace v8::internal; 17 | using namespace v8::internal::compiler; 18 | using namespace v8::internal::wasm; 19 | 20 | 21 | namespace { 22 | void TestModule(WasmModuleIndex* module, int32_t expected_result) { 23 | Isolate* isolate = CcTest::InitIsolateOnce(); 24 | int32_t result = 25 | CompileAndRunWasmModule(isolate, module->Begin(), module->End()); 26 | CHECK_EQ(expected_result, result); 27 | } 28 | } // namespace 29 | 30 | 31 | // A raw test that skips the WasmModuleBuilder. 32 | TEST(Run_WasmModule_CallAdd_rev) { 33 | static const byte data[] = { 34 | // sig#0 ------------------------------------------ 35 | kDeclSignatures, 2, 36 | 0, kLocalI32, // void -> int 37 | 2, kLocalI32, kLocalI32, kLocalI32, // int,int -> int 38 | // func#0 (main) ---------------------------------- 39 | kDeclFunctions, 2, 40 | kDeclFunctionExport, 41 | 0, 0, // sig index 42 | 6, 0, // body size 43 | kExprCallFunction, 1, // -- 44 | kExprI8Const, 77, // -- 45 | kExprI8Const, 22, // -- 46 | // func#1 ----------------------------------------- 47 | 0, // no name, not exported 48 | 1, 0, // sig index 49 | 5, 0, // body size 50 | kExprI32Add, // -- 51 | kExprGetLocal, 0, // -- 52 | kExprGetLocal, 1, // -- 53 | }; 54 | 55 | Isolate* isolate = CcTest::InitIsolateOnce(); 56 | int32_t result = 57 | CompileAndRunWasmModule(isolate, data, data + arraysize(data)); 58 | CHECK_EQ(99, result); 59 | } 60 | 61 | 62 | TEST(Run_WasmModule_Return114) { 63 | static const int32_t kReturnValue = 114; 64 | Zone zone; 65 | WasmModuleBuilder* builder = new(&zone) WasmModuleBuilder(&zone); 66 | uint16_t f_index = builder->AddFunction(); 67 | WasmFunctionBuilder* f = builder->FunctionAt(f_index); 68 | f->ReturnType(kAstI32); 69 | f->Exported(1); 70 | byte code[] = {WASM_I8(kReturnValue)}; 71 | f->EmitCode(code, sizeof(code)); 72 | WasmModuleWriter* writer = builder->Build(&zone); 73 | TestModule(writer->WriteTo(&zone), kReturnValue); 74 | } 75 | 76 | 77 | TEST(Run_WasmModule_CallAdd) { 78 | Zone zone; 79 | WasmModuleBuilder* builder = new(&zone) WasmModuleBuilder(&zone); 80 | uint16_t f1_index = builder->AddFunction(); 81 | WasmFunctionBuilder* f = builder->FunctionAt(f1_index); 82 | f->ReturnType(kAstI32); 83 | uint16_t param1 = f->AddParam(kAstI32); 84 | uint16_t param2 = f->AddParam(kAstI32); 85 | byte code1[] = { 86 | WASM_I32_ADD(WASM_GET_LOCAL(param1), WASM_GET_LOCAL(param2))}; 87 | uint32_t local_indices1[] = {2, 4}; 88 | f->EmitCode(code1, sizeof(code1), local_indices1, sizeof(local_indices1)/4); 89 | uint16_t f2_index = builder->AddFunction(); 90 | f = builder->FunctionAt(f2_index); 91 | f->ReturnType(kAstI32); 92 | f->Exported(1); 93 | byte code2[] = { 94 | WASM_CALL_FUNCTION(f1_index, WASM_I8(77), WASM_I8(22))}; 95 | f->EmitCode(code2, sizeof(code2)); 96 | WasmModuleWriter* writer = builder->Build(&zone); 97 | TestModule(writer->WriteTo(&zone), 99); 98 | } 99 | 100 | 101 | TEST(Run_WasmModule_ReadLoadedDataSegment) { 102 | static const byte kDataSegmentDest0 = 12; 103 | Zone zone; 104 | WasmModuleBuilder* builder = new(&zone) WasmModuleBuilder(&zone); 105 | uint16_t f_index = builder->AddFunction(); 106 | WasmFunctionBuilder* f = builder->FunctionAt(f_index); 107 | f->ReturnType(kAstI32); 108 | f->Exported(1); 109 | byte code[] = { 110 | WASM_LOAD_MEM(MachineType::Int32(), WASM_I8(kDataSegmentDest0))}; 111 | f->EmitCode(code, sizeof(code)); 112 | byte data[] = {0xaa, 0xbb, 0xcc, 0xdd}; 113 | builder->AddDataSegment( 114 | new(&zone) WasmDataSegmentEncoder( 115 | &zone, data, sizeof(data), kDataSegmentDest0)); 116 | WasmModuleWriter* writer = builder->Build(&zone); 117 | TestModule(writer->WriteTo(&zone), 0xddccbbaa); 118 | } 119 | 120 | 121 | TEST(Run_WasmModule_CheckMemoryIsZero) { 122 | static const int kCheckSize = 16 * 1024; 123 | Zone zone; 124 | WasmModuleBuilder* builder = new(&zone) WasmModuleBuilder(&zone); 125 | uint16_t f_index = builder->AddFunction(); 126 | WasmFunctionBuilder* f = builder->FunctionAt(f_index); 127 | f->ReturnType(kAstI32); 128 | uint16_t localIndex = f->AddLocal(kAstI32); 129 | f->Exported(1); 130 | byte code[] = { 131 | WASM_BLOCK(2, 132 | WASM_WHILE( 133 | WASM_I32_LTS(WASM_GET_LOCAL(localIndex), WASM_I32(kCheckSize)), 134 | WASM_IF_ELSE(WASM_LOAD_MEM(MachineType::Int32(), 135 | WASM_GET_LOCAL(localIndex)), 136 | WASM_BRV(2, WASM_I8(-1)), 137 | WASM_INC_LOCAL_BY(localIndex, 4))), 138 | WASM_I8(11))}; 139 | uint32_t local_indices[] = {7, 19, 25, 28}; 140 | f->EmitCode(code, sizeof(code), local_indices, sizeof(local_indices)/4); 141 | WasmModuleWriter* writer = builder->Build(&zone); 142 | TestModule(writer->WriteTo(&zone), 11); 143 | } 144 | 145 | 146 | TEST(Run_WasmModule_CallMain_recursive) { 147 | Zone zone; 148 | WasmModuleBuilder* builder = new(&zone) WasmModuleBuilder(&zone); 149 | uint16_t f_index = builder->AddFunction(); 150 | WasmFunctionBuilder* f = builder->FunctionAt(f_index); 151 | f->ReturnType(kAstI32); 152 | uint16_t localIndex = f->AddLocal(kAstI32); 153 | f->Exported(1); 154 | byte code[] = { 155 | WASM_BLOCK( 156 | 2, 157 | WASM_SET_LOCAL(localIndex, WASM_LOAD_MEM(MachineType::Int32(), 158 | WASM_ZERO)), 159 | WASM_IF_ELSE(WASM_I32_LTS(WASM_GET_LOCAL(localIndex), WASM_I8(5)), 160 | WASM_BLOCK(2, 161 | WASM_STORE_MEM(MachineType::Int32(), 162 | WASM_ZERO, WASM_INC_LOCAL(localIndex)), 163 | WASM_BRV(1, WASM_CALL_FUNCTION0(0))), 164 | WASM_BRV(0, WASM_I8(55)))) 165 | }; 166 | uint32_t local_indices[] = {3, 11, 21, 24}; 167 | f->EmitCode(code, sizeof(code), local_indices, sizeof(local_indices)/4); 168 | WasmModuleWriter* writer = builder->Build(&zone); 169 | TestModule(writer->WriteTo(&zone), 55); 170 | } 171 | 172 | 173 | TEST(Run_WasmModule_Global) { 174 | Zone zone; 175 | WasmModuleBuilder* builder = new(&zone) WasmModuleBuilder(&zone); 176 | uint32_t global1 = builder->AddGlobal(MachineType::Int32(), 0); 177 | uint32_t global2 = builder->AddGlobal(MachineType::Int32(), 0); 178 | uint16_t f1_index = builder->AddFunction(); 179 | WasmFunctionBuilder* f = builder->FunctionAt(f1_index); 180 | f->ReturnType(kAstI32); 181 | byte code1[] = { 182 | WASM_I32_ADD(WASM_LOAD_GLOBAL(global1), WASM_LOAD_GLOBAL(global2))}; 183 | f->EmitCode(code1, sizeof(code1)); 184 | uint16_t f2_index = builder->AddFunction(); 185 | f = builder->FunctionAt(f2_index); 186 | f->ReturnType(kAstI32); 187 | f->Exported(1); 188 | byte code2[] = { 189 | WASM_STORE_GLOBAL(global1, WASM_I32(56)), 190 | WASM_STORE_GLOBAL(global2, WASM_I32(41)), 191 | WASM_RETURN(WASM_CALL_FUNCTION0(f1_index))}; 192 | f->EmitCode(code2, sizeof(code2)); 193 | WasmModuleWriter* writer = builder->Build(&zone); 194 | TestModule(writer->WriteTo(&zone), 97); 195 | } 196 | -------------------------------------------------------------------------------- /test/cctest/wasm/test-signatures.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef TEST_SIGNATURES_H 6 | #define TEST_SIGNATURES_H 7 | 8 | #include "src/signature.h" 9 | #include "src/wasm/wasm-opcodes.h" 10 | 11 | namespace v8 { 12 | namespace internal { 13 | namespace wasm { 14 | 15 | typedef Signature FunctionSig; 16 | 17 | // A helper class with many useful signatures in order to simplify tests. 18 | class TestSignatures { 19 | public: 20 | TestSignatures() 21 | : sig_i_v(1, 0, kIntTypes4), 22 | sig_i_i(1, 1, kIntTypes4), 23 | sig_i_ii(1, 2, kIntTypes4), 24 | sig_i_iii(1, 3, kIntTypes4), 25 | sig_i_f(1, 1, kIntFloatTypes4), 26 | sig_i_ff(1, 2, kIntFloatTypes4), 27 | sig_i_d(1, 1, kIntDoubleTypes4), 28 | sig_i_dd(1, 2, kIntDoubleTypes4), 29 | sig_l_v(1, 0, kLongTypes4), 30 | sig_l_l(1, 1, kLongTypes4), 31 | sig_l_ll(1, 2, kLongTypes4), 32 | sig_i_ll(1, 2, kIntLongTypes4), 33 | sig_f_ff(1, 2, kFloatTypes4), 34 | sig_d_dd(1, 2, kDoubleTypes4), 35 | sig_v_v(0, 0, kIntTypes4), 36 | sig_v_i(0, 1, kIntTypes4), 37 | sig_v_ii(0, 2, kIntTypes4), 38 | sig_v_iii(0, 3, kIntTypes4) { 39 | // I used C++ and you won't believe what happened next.... 40 | for (int i = 0; i < 4; i++) kIntTypes4[i] = kAstI32; 41 | for (int i = 0; i < 4; i++) kLongTypes4[i] = kAstI64; 42 | for (int i = 0; i < 4; i++) kFloatTypes4[i] = kAstF32; 43 | for (int i = 0; i < 4; i++) kDoubleTypes4[i] = kAstF64; 44 | for (int i = 0; i < 4; i++) kIntLongTypes4[i] = kAstI64; 45 | for (int i = 0; i < 4; i++) kIntFloatTypes4[i] = kAstF32; 46 | for (int i = 0; i < 4; i++) kIntDoubleTypes4[i] = kAstF64; 47 | kIntLongTypes4[0] = kAstI32; 48 | kIntFloatTypes4[0] = kAstI32; 49 | kIntDoubleTypes4[0] = kAstI32; 50 | } 51 | 52 | FunctionSig* i_v() { return &sig_i_v; } 53 | FunctionSig* i_i() { return &sig_i_i; } 54 | FunctionSig* i_ii() { return &sig_i_ii; } 55 | FunctionSig* i_iii() { return &sig_i_iii; } 56 | 57 | FunctionSig* i_f() { return &sig_i_f; } 58 | FunctionSig* i_ff() { return &sig_i_ff; } 59 | FunctionSig* i_d() { return &sig_i_d; } 60 | FunctionSig* i_dd() { return &sig_i_dd; } 61 | 62 | FunctionSig* l_v() { return &sig_l_v; } 63 | FunctionSig* l_l() { return &sig_l_l; } 64 | FunctionSig* l_ll() { return &sig_l_ll; } 65 | FunctionSig* i_ll() { return &sig_i_ll; } 66 | 67 | FunctionSig* f_ff() { return &sig_f_ff; } 68 | FunctionSig* d_dd() { return &sig_d_dd; } 69 | 70 | FunctionSig* v_v() { return &sig_v_v; } 71 | FunctionSig* v_i() { return &sig_v_i; } 72 | FunctionSig* v_ii() { return &sig_v_ii; } 73 | FunctionSig* v_iii() { return &sig_v_iii; } 74 | 75 | private: 76 | LocalType kIntTypes4[4]; 77 | LocalType kLongTypes4[4]; 78 | LocalType kFloatTypes4[4]; 79 | LocalType kDoubleTypes4[4]; 80 | LocalType kIntLongTypes4[4]; 81 | LocalType kIntFloatTypes4[4]; 82 | LocalType kIntDoubleTypes4[4]; 83 | 84 | FunctionSig sig_i_v; 85 | FunctionSig sig_i_i; 86 | FunctionSig sig_i_ii; 87 | FunctionSig sig_i_iii; 88 | 89 | FunctionSig sig_i_f; 90 | FunctionSig sig_i_ff; 91 | FunctionSig sig_i_d; 92 | FunctionSig sig_i_dd; 93 | 94 | FunctionSig sig_l_v; 95 | FunctionSig sig_l_l; 96 | FunctionSig sig_l_ll; 97 | FunctionSig sig_i_ll; 98 | 99 | FunctionSig sig_f_ff; 100 | FunctionSig sig_d_dd; 101 | 102 | FunctionSig sig_v_v; 103 | FunctionSig sig_v_i; 104 | FunctionSig sig_v_ii; 105 | FunctionSig sig_v_iii; 106 | }; 107 | } 108 | } 109 | } 110 | 111 | #endif // TEST_SIGNATURES_H 112 | -------------------------------------------------------------------------------- /test/cctest/wasm/wasm.gyp: -------------------------------------------------------------------------------- 1 | # Copyright 2015 the V8 project authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style license that can be 3 | # found in the LICENSE file. 4 | 5 | { 6 | 'targets': [ 7 | { 8 | 'target_name': 'wasm_cctest', 9 | 'type': 'none', 10 | # A list of additional sources and options to be injected into: 11 | # test/cctest/cctest.gyp:cctest 12 | 'direct_dependent_settings': { 13 | 'include_dirs': ['../../..'], 14 | 'sources': [ 15 | 'test-run-wasm.cc', 16 | 'test-run-wasm-module.cc', 17 | ], 18 | }, 19 | }, 20 | ], 21 | } 22 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/asm-wasm.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | function IntTest() { 6 | "use asm"; 7 | function sum(a, b) { 8 | a = a|0; 9 | b = b|0; 10 | var c = (b + 1)|0 11 | return (a + c + 1)|0; 12 | } 13 | 14 | function caller() { 15 | return sum(77,22) | 0; 16 | } 17 | 18 | return {caller: caller}; 19 | } 20 | 21 | assertEquals(101, WASM.asmCompileRun(IntTest.toString())); 22 | 23 | function Float64Test() { 24 | "use asm"; 25 | function sum(a, b) { 26 | a = +a; 27 | b = +b; 28 | return +(a + b); 29 | } 30 | 31 | function caller() { 32 | var a = +sum(70.1,10.2); 33 | var ret = 0|0; 34 | if (a == 80.3) { 35 | ret = 1|0; 36 | } else { 37 | ret = 0|0; 38 | } 39 | return ret|0; 40 | } 41 | 42 | return {caller: caller}; 43 | } 44 | 45 | assertEquals(1, WASM.asmCompileRun(Float64Test.toString())); 46 | 47 | function BadModule() { 48 | "use asm"; 49 | function caller(a, b) { 50 | a = a|0; 51 | b = b+0; 52 | var c = (b + 1)|0 53 | return (a + c + 1)|0; 54 | } 55 | 56 | function caller() { 57 | return call(1, 2)|0; 58 | } 59 | 60 | return {caller: caller}; 61 | } 62 | 63 | assertThrows(function() { 64 | WASM.asmCompileRun(BadModule.toString()) 65 | }); 66 | 67 | function TestReturnInBlock() { 68 | "use asm"; 69 | 70 | function caller() { 71 | if(1) { 72 | { 73 | { 74 | return 1; 75 | } 76 | } 77 | } 78 | return 0; 79 | } 80 | 81 | return {caller: caller}; 82 | } 83 | 84 | assertEquals(1, WASM.asmCompileRun(TestReturnInBlock.toString())); 85 | 86 | function TestWhileSimple() { 87 | "use asm"; 88 | 89 | function caller() { 90 | var x = 0; 91 | while(x < 5) { 92 | x = (x + 1)|0; 93 | } 94 | return x|0; 95 | } 96 | 97 | return {caller: caller}; 98 | } 99 | 100 | assertEquals(5, WASM.asmCompileRun(TestWhileSimple.toString())); 101 | 102 | function TestWhileWithoutBraces() { 103 | "use asm"; 104 | 105 | function caller() { 106 | var x = 0; 107 | while(x <= 3) 108 | x = (x + 1)|0; 109 | return x|0; 110 | } 111 | 112 | return {caller: caller}; 113 | } 114 | 115 | assertEquals(4, WASM.asmCompileRun(TestWhileWithoutBraces.toString())); 116 | 117 | function TestReturnInWhile() { 118 | "use asm"; 119 | 120 | function caller() { 121 | var x = 0; 122 | while(x < 10) { 123 | x = (x + 6)|0; 124 | return x|0; 125 | } 126 | return x|0; 127 | } 128 | 129 | return {caller: caller}; 130 | } 131 | 132 | assertEquals(6, WASM.asmCompileRun(TestReturnInWhile.toString())); 133 | 134 | function TestReturnInWhileWithoutBraces() { 135 | "use asm"; 136 | 137 | function caller() { 138 | var x = 0; 139 | while(x < 5) 140 | return 7; 141 | return x|0; 142 | } 143 | 144 | return {caller: caller}; 145 | } 146 | 147 | assertEquals(7, WASM.asmCompileRun(TestReturnInWhileWithoutBraces.toString())); 148 | 149 | function TestBreakInWhile() { 150 | "use asm"; 151 | 152 | function caller() { 153 | while(1) { 154 | break; 155 | } 156 | return 8; 157 | } 158 | 159 | return {caller: caller}; 160 | } 161 | 162 | assertEquals(8, WASM.asmCompileRun(TestBreakInWhile.toString())); 163 | 164 | function TestBreakInNestedWhile() { 165 | "use asm"; 166 | 167 | function caller() { 168 | var x = 1.0; 169 | while(x < 1.5) { 170 | while(1) 171 | break; 172 | x = +(x + 0.25); 173 | } 174 | var ret = 0; 175 | if (x == 1.5) { 176 | ret = 9; 177 | } 178 | return ret|0; 179 | } 180 | 181 | return {caller: caller}; 182 | } 183 | 184 | assertEquals(9, WASM.asmCompileRun(TestBreakInNestedWhile.toString())); 185 | 186 | function TestBreakInBlock() { 187 | "use asm"; 188 | 189 | function caller() { 190 | var x = 0; 191 | abc: { 192 | x = 10; 193 | if (x == 10) { 194 | break abc; 195 | } 196 | x = 20; 197 | } 198 | return x|0; 199 | } 200 | 201 | return {caller: caller}; 202 | } 203 | 204 | assertEquals(10, WASM.asmCompileRun(TestBreakInBlock.toString())); 205 | 206 | function TestBreakInNamedWhile() { 207 | "use asm"; 208 | 209 | function caller() { 210 | var x = 0; 211 | outer: while (1) { 212 | x = (x + 1)|0; 213 | while (x == 11) { 214 | break outer; 215 | } 216 | } 217 | return x|0; 218 | } 219 | 220 | return {caller: caller}; 221 | } 222 | 223 | assertEquals(11, WASM.asmCompileRun(TestBreakInNamedWhile.toString())); 224 | 225 | function TestContinue() { 226 | "use asm"; 227 | 228 | function caller() { 229 | var x = 5; 230 | var ret = 0; 231 | while (x >= 0) { 232 | x = (x - 1)|0; 233 | if (x == 2) { 234 | continue; 235 | } 236 | ret = (ret - 1)|0; 237 | } 238 | return ret|0; 239 | } 240 | 241 | return {caller: caller}; 242 | } 243 | 244 | assertEquals(-5, WASM.asmCompileRun(TestContinue.toString())); 245 | 246 | function TestContinueInNamedWhile() { 247 | "use asm"; 248 | 249 | function caller() { 250 | var x = 5; 251 | var y = 0; 252 | var ret = 0; 253 | outer: while (x > 0) { 254 | x = (x - 1)|0; 255 | y = 0; 256 | while (y < 5) { 257 | if (x == 3) { 258 | continue outer; 259 | } 260 | ret = (ret + 1)|0; 261 | y = (y + 1)|0; 262 | } 263 | } 264 | return ret|0; 265 | } 266 | 267 | return {caller: caller}; 268 | } 269 | 270 | assertEquals(20, WASM.asmCompileRun(TestContinueInNamedWhile.toString())); 271 | 272 | function TestNot() { 273 | "use asm"; 274 | 275 | function caller() { 276 | var a = !(2 > 3); 277 | return a | 0; 278 | } 279 | 280 | return {caller:caller}; 281 | } 282 | 283 | assertEquals(1, WASM.asmCompileRun(TestNot.toString())); 284 | 285 | function TestNotEquals() { 286 | "use asm"; 287 | 288 | function caller() { 289 | var a = 3; 290 | if (a != 2) { 291 | return 21; 292 | } 293 | return 0; 294 | } 295 | 296 | return {caller:caller}; 297 | } 298 | 299 | assertEquals(21, WASM.asmCompileRun(TestNotEquals.toString())); 300 | 301 | function TestUnsignedComparison() { 302 | "use asm"; 303 | 304 | function caller() { 305 | var a = 0xffffffff; 306 | if ((a>>>0) > (0>>>0)) { 307 | return 22; 308 | } 309 | return 0; 310 | } 311 | 312 | return {caller:caller}; 313 | } 314 | 315 | assertEquals(22, WASM.asmCompileRun(TestUnsignedComparison.toString())); 316 | 317 | function TestMixedAdd() { 318 | "use asm"; 319 | 320 | function caller() { 321 | var a = 0x80000000; 322 | var b = 0x7fffffff; 323 | var c = 0; 324 | c = ((a>>>0) + b)|0; 325 | if ((c >>> 0) > (0>>>0)) { 326 | if (c < 0) { 327 | return 23; 328 | } 329 | } 330 | return 0; 331 | } 332 | 333 | return {caller:caller}; 334 | } 335 | 336 | assertEquals(23, WASM.asmCompileRun(TestMixedAdd.toString())); 337 | 338 | function TestInt32HeapAccess(stdlib, foreign, buffer) { 339 | "use asm"; 340 | 341 | var m = new stdlib.Int32Array(buffer); 342 | function caller() { 343 | var i = 4; 344 | 345 | m[0] = (i + 1) | 0; 346 | m[i >> 2] = ((m[0]|0) + 1) | 0; 347 | m[2] = ((m[i >> 2]|0) + 1) | 0; 348 | return m[2] | 0; 349 | } 350 | 351 | return {caller: caller}; 352 | } 353 | 354 | assertEquals(7, WASM.asmCompileRun(TestInt32HeapAccess.toString())); 355 | 356 | function TestHeapAccessIntTypes() { 357 | var types = [ 358 | ['Int8Array', '>> 0'], 359 | ['Uint8Array', '>> 0'], 360 | ['Int16Array', '>> 1'], 361 | ['Uint16Array', '>> 1'], 362 | ['Int32Array', '>> 2'], 363 | ['Uint32Array', '>> 2'], 364 | ]; 365 | for (var i = 0; i < types.length; i++) { 366 | var code = TestInt32HeapAccess.toString(); 367 | code = code.replace('Int32Array', types[i][0]); 368 | code = code.replace(/>> 2/g, types[i][1]); 369 | assertEquals(7, WASM.asmCompileRun(code)); 370 | } 371 | } 372 | 373 | TestHeapAccessIntTypes(); 374 | 375 | function TestFloatHeapAccess(stdlib, foreign, buffer) { 376 | "use asm"; 377 | 378 | var f32 = new stdlib.Float32Array(buffer); 379 | var f64 = new stdlib.Float64Array(buffer); 380 | var fround = stdlib.Math.fround; 381 | function caller() { 382 | var i = 8; 383 | var j = 8; 384 | var v = 6.0; 385 | 386 | // TODO(bradnelson): Add float32 when asm-wasm supports it. 387 | f64[2] = v + 1.0; 388 | f64[i >> 3] = +f64[2] + 1.0; 389 | f64[j >> 3] = +f64[j >> 3] + 1.0; 390 | i = +f64[i >> 3] == 9.0; 391 | return i|0; 392 | } 393 | 394 | return {caller: caller}; 395 | } 396 | 397 | assertEquals(1, WASM.asmCompileRun(TestFloatHeapAccess.toString())); 398 | 399 | function TestConvertI32() { 400 | "use asm"; 401 | 402 | function caller() { 403 | var a = 1.5; 404 | if ((~~(a + a)) == 3) { 405 | return 24; 406 | } 407 | return 0; 408 | } 409 | 410 | return {caller:caller}; 411 | } 412 | 413 | assertEquals(24, WASM.asmCompileRun(TestConvertI32.toString())); 414 | 415 | function TestConvertF64FromInt() { 416 | "use asm"; 417 | 418 | function caller() { 419 | var a = 1; 420 | if ((+(a + a)) > 1.5) { 421 | return 25; 422 | } 423 | return 0; 424 | } 425 | 426 | return {caller:caller}; 427 | } 428 | 429 | assertEquals(25, WASM.asmCompileRun(TestConvertF64FromInt.toString())); 430 | 431 | function TestConvertF64FromUnsigned() { 432 | "use asm"; 433 | 434 | function caller() { 435 | var a = 0xffffffff; 436 | if ((+(a>>>0)) > 0.0) { 437 | if((+a) < 0.0) { 438 | return 26; 439 | } 440 | } 441 | return 0; 442 | } 443 | 444 | return {caller:caller}; 445 | } 446 | 447 | assertEquals(26, WASM.asmCompileRun(TestConvertF64FromUnsigned.toString())); 448 | 449 | function TestModInt() { 450 | "use asm"; 451 | 452 | function caller() { 453 | var a = -83; 454 | var b = 28; 455 | return ((a|0)%(b|0))|0; 456 | } 457 | 458 | return {caller:caller}; 459 | } 460 | 461 | assertEquals(-27, WASM.asmCompileRun(TestModInt.toString())); 462 | 463 | function TestModUnsignedInt() { 464 | "use asm"; 465 | 466 | function caller() { 467 | var a = 0x80000000; //2147483648 468 | var b = 10; 469 | return ((a>>>0)%(b>>>0))|0; 470 | } 471 | 472 | return {caller:caller}; 473 | } 474 | 475 | assertEquals(8, WASM.asmCompileRun(TestModUnsignedInt.toString())); 476 | 477 | function TestModDouble() { 478 | "use asm"; 479 | 480 | function caller() { 481 | var a = 5.25; 482 | var b = 2.5; 483 | if (a%b == 0.25) { 484 | return 28; 485 | } 486 | return 0; 487 | } 488 | 489 | return {caller:caller}; 490 | } 491 | 492 | assertEquals(28, WASM.asmCompileRun(TestModDouble.toString())); 493 | 494 | /* 495 | TODO: Fix parsing of negative doubles 496 | Fix code to use trunc instead of casts 497 | function TestModDoubleNegative() { 498 | "use asm"; 499 | 500 | function caller() { 501 | var a = -34359738368.25; 502 | var b = 2.5; 503 | if (a%b == -0.75) { 504 | return 28; 505 | } 506 | return 0; 507 | } 508 | 509 | return {caller:caller}; 510 | } 511 | 512 | assertEquals(28, WASM.asmCompileRun(TestModDoubleNegative.toString())); 513 | */ 514 | 515 | function TestNamedFunctions() { 516 | "use asm"; 517 | 518 | var a = 0.0; 519 | var b = 0.0; 520 | 521 | function add() { 522 | return +(a + b); 523 | } 524 | 525 | function init() { 526 | a = 43.25; 527 | b = 34.25; 528 | } 529 | 530 | return {init:init, 531 | add:add}; 532 | } 533 | 534 | var module = WASM.instantiateModuleFromAsm(TestNamedFunctions.toString()); 535 | module.init(); 536 | assertEquals(77.5, module.add()); 537 | 538 | function TestGlobalsWithInit() { 539 | "use asm"; 540 | 541 | var a = 43.25; 542 | var b = 34.25; 543 | 544 | function add() { 545 | return +(a + b); 546 | } 547 | 548 | return {add:add}; 549 | } 550 | 551 | var module = WASM.instantiateModuleFromAsm(TestGlobalsWithInit.toString()); 552 | module.__init__(); 553 | assertEquals(77.5, module.add()); 554 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/calls.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | load("test/mjsunit/wasm/wasm-constants.js"); 6 | 7 | var module = (function () { 8 | var kBodySize = 5; 9 | var kNameOffset = 21 + kBodySize + 1; 10 | 11 | return WASM.instantiateModule(bytes( 12 | // -- memory 13 | kDeclMemory, 14 | 12, 12, 1, 15 | // -- signatures 16 | kDeclSignatures, 1, 17 | 2, kAstI32, kAstI32, kAstI32, // int, int -> int 18 | // -- functions 19 | kDeclFunctions, 1, 20 | kDeclFunctionName | kDeclFunctionExport, 21 | 0, 0, 22 | kNameOffset, 0, 0, 0, // name offset 23 | kBodySize, 0, 24 | // -- body 25 | kExprI32Sub, // -- 26 | kExprGetLocal, 0, // -- 27 | kExprGetLocal, 1, // -- 28 | kDeclEnd, 29 | 's', 'u', 'b', 0 // name 30 | )); 31 | })(); 32 | 33 | // Check the module exists. 34 | assertFalse(module === undefined); 35 | assertFalse(module === null); 36 | assertFalse(module === 0); 37 | assertEquals("object", typeof module); 38 | 39 | // Check the memory is an ArrayBuffer. 40 | var mem = module.memory; 41 | assertFalse(mem === undefined); 42 | assertFalse(mem === null); 43 | assertFalse(mem === 0); 44 | assertEquals("object", typeof mem); 45 | assertTrue(mem instanceof ArrayBuffer); 46 | for (var i = 0; i < 4; i++) { 47 | module.memory = 0; // should be ignored 48 | assertEquals(mem, module.memory); 49 | } 50 | 51 | assertEquals(4096, module.memory.byteLength); 52 | 53 | // Check the properties of the sub function. 54 | assertEquals("function", typeof module.sub); 55 | 56 | assertEquals(-55, module.sub(33, 88)); 57 | assertEquals(-55555, module.sub(33333, 88888)); 58 | assertEquals(-5555555, module.sub(3333333, 8888888)); 59 | 60 | 61 | var module = (function() { 62 | var kBodySize = 1; 63 | var kNameOffset2 = 19 + kBodySize + 1; 64 | 65 | return WASM.instantiateModule(bytes( 66 | // -- memory 67 | kDeclMemory, 68 | 12, 12, 1, 69 | // -- signatures 70 | kDeclSignatures, 1, 71 | 0, kAstStmt, // signature: void -> void 72 | // -- functions 73 | kDeclFunctions, 1, 74 | kDeclFunctionName | kDeclFunctionExport, 75 | 0, 0, // signature index 76 | kNameOffset2, 0, 0, 0, // name offset 77 | kBodySize, 0, 78 | kExprNop, // body 79 | kDeclEnd, 80 | 'n', 'o', 'p', 0 // name 81 | )); 82 | })(); 83 | 84 | // Check the module exists. 85 | assertFalse(module === undefined); 86 | assertFalse(module === null); 87 | assertFalse(module === 0); 88 | assertEquals("object", typeof module); 89 | 90 | // Check the memory is an ArrayBuffer. 91 | var mem = module.memory; 92 | assertFalse(mem === undefined); 93 | assertFalse(mem === null); 94 | assertFalse(mem === 0); 95 | assertEquals("object", typeof mem); 96 | assertTrue(mem instanceof ArrayBuffer); 97 | for (var i = 0; i < 4; i++) { 98 | module.memory = 0; // should be ignored 99 | assertEquals(mem, module.memory); 100 | } 101 | 102 | assertEquals(4096, module.memory.byteLength); 103 | 104 | // Check the properties of the sub function. 105 | assertFalse(module.nop === undefined); 106 | assertFalse(module.nop === null); 107 | assertFalse(module.nop === 0); 108 | assertEquals("function", typeof module.nop); 109 | 110 | assertEquals(undefined, module.nop()); 111 | 112 | (function testLt() { 113 | var kBodySize = 5; 114 | var kNameOffset = 21 + kBodySize + 1; 115 | 116 | var data = bytes( 117 | // -- memory 118 | kDeclMemory, 119 | 12, 12, 1, 120 | // -- signatures 121 | kDeclSignatures, 1, 122 | 2, kAstI32, kAstF64, kAstF64, // (f64,f64)->int 123 | // -- functions 124 | kDeclFunctions, 1, 125 | kDeclFunctionName | kDeclFunctionExport, 126 | 0, 0, // signature index 127 | kNameOffset, 0, 0, 0, // name offset 128 | kBodySize, 0, 129 | // -- body 130 | kExprF64Lt, // -- 131 | kExprGetLocal, 0, // -- 132 | kExprGetLocal, 1, // -- 133 | kDeclEnd, 134 | 'f', 'l', 't', 0 // name 135 | ); 136 | 137 | var module = WASM.instantiateModule(data); 138 | 139 | assertEquals("function", typeof module.flt); 140 | assertEquals(1, module.flt(-2, -1)); 141 | assertEquals(0, module.flt(7.3, 7.1)); 142 | assertEquals(1, module.flt(7.1, 7.3)); 143 | })(); 144 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/compile-run-basic.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | load("test/mjsunit/wasm/wasm-constants.js"); 6 | 7 | var kReturnValue = 97; 8 | 9 | var kBodySize = 2; 10 | var kNameOffset = 15 + kBodySize + 1; 11 | 12 | var data = bytes( 13 | // -- signatures 14 | kDeclSignatures, 1, 15 | 0, kAstI32, // signature: void -> int 16 | // -- main function 17 | kDeclFunctions, 1, 18 | kDeclFunctionName | kDeclFunctionExport, 19 | 0, 0, // signature index 20 | kNameOffset, 0, 0, 0, // name offset 21 | kBodySize, 0, // body size 22 | // -- body 23 | kExprI8Const, // -- 24 | kReturnValue, // -- 25 | kDeclEnd, 26 | 'm', 'a', 'i', 'n', 0 // name 27 | ); 28 | 29 | assertEquals(kReturnValue, WASM.compileRun(data)); 30 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/divrem-trap.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Flags: --expose-gc --allow-natives-syntax 6 | 7 | load("test/mjsunit/wasm/wasm-constants.js"); 8 | 9 | function assertTraps(code, msg) { 10 | var threwException = true; 11 | try { 12 | if (typeof code === 'function') { 13 | code(); 14 | } else { 15 | eval(code); 16 | } 17 | threwException = false; 18 | } catch (e) { 19 | if (typeof type_opt === 'function') { 20 | assertInstanceof(e, type_opt); 21 | } 22 | if (arguments.length >= 3) { 23 | assertEquals(e.type, cause_opt); 24 | } 25 | // Success. 26 | return; 27 | } 28 | throw new MjsUnitAssertionError("Did not throw exception"); 29 | } 30 | 31 | 32 | function makeDivRem(opcode) { 33 | var kBodySize = 5; 34 | var kNameMainOffset = 6 + 11 + kBodySize + 1; 35 | 36 | var data = bytes( 37 | // signatures 38 | kDeclSignatures, 1, 39 | 2, kAstI32, kAstI32, kAstI32, // (int,int) -> int 40 | // -- main function 41 | kDeclFunctions, 1, 42 | kDeclFunctionName | kDeclFunctionExport, 43 | 0, 0, 44 | kNameMainOffset, 0, 0, 0, // name offset 45 | kBodySize, 0, 46 | // main body 47 | opcode, // -- 48 | kExprGetLocal, 0, // -- 49 | kExprGetLocal, 1, // -- 50 | // names 51 | kDeclEnd, 52 | 'm', 'a', 'i', 'n', 0 // -- 53 | ); 54 | 55 | var module = WASM.instantiateModule(data); 56 | 57 | assertEquals("function", typeof module.main); 58 | 59 | return module.main; 60 | } 61 | 62 | var divs = makeDivRem(kExprI32DivS); 63 | var divu = makeDivRem(kExprI32DivU); 64 | 65 | assertEquals( 33, divs( 333, 10)); 66 | assertEquals(-33, divs(-336, 10)); 67 | 68 | assertEquals( 44, divu( 445, 10)); 69 | assertEquals(429496685, divu(-446, 10)); 70 | 71 | assertTraps(kTrapDivByZero, "divs(100, 0);"); 72 | assertTraps(kTrapDivByZero, "divs(-1009, 0);"); 73 | 74 | assertTraps(kTrapDivByZero, "divu(200, 0);"); 75 | assertTraps(kTrapDivByZero, "divu(-2009, 0);"); 76 | 77 | assertTraps(kTrapDivUnrepresentable, "divs(0x80000000, -1)"); 78 | assertEquals(0, divu(0x80000000, -1)); 79 | 80 | 81 | var rems = makeDivRem(kExprI32RemS); 82 | var remu = makeDivRem(kExprI32RemU); 83 | 84 | assertEquals( 3, rems( 333, 10)); 85 | assertEquals(-6, rems(-336, 10)); 86 | 87 | assertEquals( 5, remu( 445, 10)); 88 | assertEquals( 3, remu(-443, 10)); 89 | 90 | assertTraps(kTrapRemByZero, "rems(100, 0);"); 91 | assertTraps(kTrapRemByZero, "rems(-1009, 0);"); 92 | 93 | assertTraps(kTrapRemByZero, "remu(200, 0);"); 94 | assertTraps(kTrapRemByZero, "remu(-2009, 0);"); 95 | 96 | assertEquals(-2147483648, remu(0x80000000, -1)); 97 | assertEquals(0, rems(0x80000000, -1)); 98 | 99 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/ffi-error.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | load("test/mjsunit/wasm/wasm-constants.js"); 6 | 7 | function testCallFFI(ffi) { 8 | var kBodySize = 6; 9 | var kNameAddOffset = 28 + kBodySize + 1; 10 | var kNameMainOffset = kNameAddOffset + 4; 11 | 12 | var data = bytes( 13 | kDeclMemory, 14 | 12, 12, 1, // memory 15 | // -- signatures 16 | kDeclSignatures, 1, 17 | 2, kAstI32, kAstF64, kAstF64, // (f64,f64)->int 18 | // -- foreign function 19 | kDeclFunctions, 2, 20 | kDeclFunctionName | kDeclFunctionImport, 21 | 0, 0, // signature index 22 | kNameAddOffset, 0, 0, 0, // name offset 23 | // -- main function 24 | kDeclFunctionName | kDeclFunctionExport, 25 | 0, 0, // signature index 26 | kNameMainOffset, 0, 0, 0, // name offset 27 | kBodySize, 0, 28 | // main body 29 | kExprCallFunction, 0, // -- 30 | kExprGetLocal, 0, // -- 31 | kExprGetLocal, 1, // -- 32 | // names 33 | kDeclEnd, 34 | 'f', 'u', 'n', 0, // -- 35 | 'm', 'a', 'i', 'n', 0 // -- 36 | ); 37 | 38 | print("instantiate FFI"); 39 | var module = WASM.instantiateModule(data, ffi); 40 | } 41 | 42 | // everything is good. 43 | (function() { 44 | var ffi = new Object(); 45 | ffi.fun = function(a, b) { print(a, b); } 46 | testCallFFI(ffi); 47 | })(); 48 | 49 | 50 | // FFI object should be an object. 51 | assertThrows(function() { 52 | var ffi = 0; 53 | testCallFFI(ffi); 54 | }); 55 | 56 | 57 | // FFI object should have a "fun" property. 58 | assertThrows(function() { 59 | var ffi = new Object(); 60 | testCallFFI(ffi); 61 | }); 62 | 63 | 64 | // "fun" should be a JS function. 65 | assertThrows(function() { 66 | var ffi = new Object(); 67 | ffi.fun = new Object(); 68 | testCallFFI(ffi); 69 | }); 70 | 71 | 72 | // "fun" should be a JS function. 73 | assertThrows(function() { 74 | var ffi = new Object(); 75 | ffi.fun = 0; 76 | testCallFFI(ffi); 77 | }); 78 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/ffi.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | load("test/mjsunit/wasm/wasm-constants.js"); 6 | 7 | function testCallFFI(func, check) { 8 | var kBodySize = 6; 9 | var kNameFunOffset = 24 + kBodySize + 1; 10 | var kNameMainOffset = kNameFunOffset + 4; 11 | 12 | var ffi = new Object(); 13 | ffi.fun = func; 14 | 15 | var data = bytes( 16 | // signatures 17 | kDeclSignatures, 1, 18 | 2, kAstI32, kAstF64, kAstF64, // (f64,f64) -> int 19 | // -- foreign function 20 | kDeclFunctions, 2, 21 | kDeclFunctionName | kDeclFunctionImport, 22 | 0, 0, 23 | kNameFunOffset, 0, 0, 0, // name offset 24 | // -- main function 25 | kDeclFunctionName | kDeclFunctionExport, 26 | 0, 0, 27 | kNameMainOffset, 0, 0, 0, // name offset 28 | kBodySize, 0, 29 | // main body 30 | kExprCallFunction, 0, // -- 31 | kExprGetLocal, 0, // -- 32 | kExprGetLocal, 1, // -- 33 | // names 34 | kDeclEnd, 35 | 'f', 'u', 'n', 0, // -- 36 | 'm', 'a', 'i', 'n', 0 // -- 37 | ); 38 | 39 | var module = WASM.instantiateModule(data, ffi); 40 | 41 | assertEquals("function", typeof module.main); 42 | 43 | for (var i = 0; i < 100000; i += 10003) { 44 | var a = 22.5 + i, b = 10.5 + i; 45 | var r = module.main(a, b); 46 | check(r, a, b); 47 | } 48 | } 49 | 50 | var global = (function() { return this; })(); 51 | var params = [-99, -99, -99, -99]; 52 | var was_called = false; 53 | var length = -1; 54 | 55 | function FOREIGN_SUB(a, b) { 56 | print("FOREIGN_SUB(" + a + ", " + b + ")"); 57 | was_called = true; 58 | params[0] = this; 59 | params[1] = a; 60 | params[2] = b; 61 | return (a - b) | 0; 62 | } 63 | 64 | function check_FOREIGN_SUB(r, a, b) { 65 | assertEquals(a - b | 0, r); 66 | assertTrue(was_called); 67 | // assertEquals(global, params[0]); // sloppy mode 68 | assertEquals(a, params[1]); 69 | assertEquals(b, params[2]); 70 | was_called = false; 71 | } 72 | 73 | testCallFFI(FOREIGN_SUB, check_FOREIGN_SUB); 74 | 75 | 76 | function FOREIGN_ABCD(a, b, c, d) { 77 | print("FOREIGN_ABCD(" + a + ", " + b + ", " + c + ", " + d + ")"); 78 | was_called = true; 79 | params[0] = this; 80 | params[1] = a; 81 | params[2] = b; 82 | params[3] = c; 83 | params[4] = d; 84 | return (a * b * 6) | 0; 85 | } 86 | 87 | function check_FOREIGN_ABCD(r, a, b) { 88 | assertEquals((a * b * 6) | 0, r); 89 | assertTrue(was_called); 90 | // assertEquals(global, params[0]); // sloppy mode. 91 | assertEquals(a, params[1]); 92 | assertEquals(b, params[2]); 93 | assertEquals(undefined, params[3]); 94 | assertEquals(undefined, params[4]); 95 | was_called = false; 96 | } 97 | 98 | testCallFFI(FOREIGN_ABCD, check_FOREIGN_ABCD); 99 | 100 | function FOREIGN_ARGUMENTS0() { 101 | print("FOREIGN_ARGUMENTS0"); 102 | was_called = true; 103 | length = arguments.length; 104 | for (var i = 0; i < arguments.length; i++) { 105 | params[i] = arguments[i]; 106 | } 107 | return (arguments[0] * arguments[1] * 7) | 0; 108 | } 109 | 110 | function FOREIGN_ARGUMENTS1(a) { 111 | print("FOREIGN_ARGUMENTS1", a); 112 | was_called = true; 113 | length = arguments.length; 114 | for (var i = 0; i < arguments.length; i++) { 115 | params[i] = arguments[i]; 116 | } 117 | return (arguments[0] * arguments[1] * 7) | 0; 118 | } 119 | 120 | function FOREIGN_ARGUMENTS2(a, b) { 121 | print("FOREIGN_ARGUMENTS2", a, b); 122 | was_called = true; 123 | length = arguments.length; 124 | for (var i = 0; i < arguments.length; i++) { 125 | params[i] = arguments[i]; 126 | } 127 | return (a * b * 7) | 0; 128 | } 129 | 130 | function FOREIGN_ARGUMENTS3(a, b, c) { 131 | print("FOREIGN_ARGUMENTS3", a, b, c); 132 | was_called = true; 133 | length = arguments.length; 134 | for (var i = 0; i < arguments.length; i++) { 135 | params[i] = arguments[i]; 136 | } 137 | return (a * b * 7) | 0; 138 | } 139 | 140 | function FOREIGN_ARGUMENTS4(a, b, c, d) { 141 | print("FOREIGN_ARGUMENTS4", a, b, c, d); 142 | was_called = true; 143 | length = arguments.length; 144 | for (var i = 0; i < arguments.length; i++) { 145 | params[i] = arguments[i]; 146 | } 147 | return (a * b * 7) | 0; 148 | } 149 | 150 | function check_FOREIGN_ARGUMENTS(r, a, b) { 151 | assertEquals((a * b * 7) | 0, r); 152 | assertTrue(was_called); 153 | assertEquals(2, length); 154 | assertEquals(a, params[0]); 155 | assertEquals(b, params[1]); 156 | was_called = false; 157 | } 158 | 159 | // Check a bunch of uses of the arguments object. 160 | testCallFFI(FOREIGN_ARGUMENTS0, check_FOREIGN_ARGUMENTS); 161 | testCallFFI(FOREIGN_ARGUMENTS1, check_FOREIGN_ARGUMENTS); 162 | testCallFFI(FOREIGN_ARGUMENTS2, check_FOREIGN_ARGUMENTS); 163 | testCallFFI(FOREIGN_ARGUMENTS3, check_FOREIGN_ARGUMENTS); 164 | testCallFFI(FOREIGN_ARGUMENTS4, check_FOREIGN_ARGUMENTS); 165 | 166 | function returnValue(val) { 167 | return function(a, b) { 168 | print("RETURN_VALUE ", val); 169 | return val; 170 | } 171 | } 172 | 173 | 174 | function checkReturn(expected) { 175 | return function(r, a, b) { assertEquals(expected, r); } 176 | } 177 | 178 | // Check that returning weird values doesn't crash 179 | testCallFFI(returnValue(undefined), checkReturn(0)); 180 | testCallFFI(returnValue(null), checkReturn(0)); 181 | testCallFFI(returnValue("0"), checkReturn(0)); 182 | testCallFFI(returnValue("-77"), checkReturn(-77)); 183 | 184 | var objWithValueOf = {valueOf: function() { return 198; }} 185 | 186 | testCallFFI(returnValue(objWithValueOf), checkReturn(198)); 187 | 188 | 189 | function testCallBinopVoid(type, func, check) { 190 | var kBodySize = 10; 191 | var kNameFunOffset = 28 + kBodySize + 1; 192 | var kNameMainOffset = kNameFunOffset + 4; 193 | 194 | var ffi = new Object(); 195 | 196 | var passed_length = -1; 197 | var passed_a = -1; 198 | var passed_b = -1; 199 | var args_a = -1; 200 | var args_b = -1; 201 | 202 | ffi.fun = function(a, b) { 203 | passed_length = arguments.length; 204 | passed_a = a; 205 | passed_b = b; 206 | args_a = arguments[0]; 207 | args_b = arguments[1]; 208 | } 209 | 210 | var data = bytes( 211 | // -- signatures 212 | kDeclSignatures, 2, 213 | 2, kAstStmt, type, type, // (type,type)->void 214 | 2, kAstI32, type, type, // (type,type)->int 215 | // -- foreign function 216 | kDeclFunctions, 2, 217 | kDeclFunctionName | kDeclFunctionImport, 218 | 0, 0, // signature index 219 | kNameFunOffset, 0, 0, 0, // name offset 220 | // -- main function 221 | kDeclFunctionName | kDeclFunctionExport, 222 | 1, 0, // signature index 223 | kNameMainOffset, 0, 0, 0, // name offset 224 | kBodySize, 0, // body size 225 | // main body 226 | kExprBlock, 2, // -- 227 | kExprCallFunction, 0, // -- 228 | kExprGetLocal, 0, // -- 229 | kExprGetLocal, 1, // -- 230 | kExprI8Const, 99, // -- 231 | // names 232 | kDeclEnd, 233 | 'f', 'u', 'n', 0, // -- 234 | 'm', 'a', 'i', 'n', 0 // -- 235 | ); 236 | 237 | var module = WASM.instantiateModule(data, ffi); 238 | 239 | assertEquals("function", typeof module.main); 240 | 241 | print("testCallBinopVoid", type); 242 | 243 | for (var i = 0; i < 100000; i += 10003.1) { 244 | var a = 22.5 + i, b = 10.5 + i; 245 | var r = module.main(a, b); 246 | assertEquals(99, r); 247 | assertEquals(2, passed_length); 248 | var expected_a, expected_b; 249 | switch (type) { 250 | case kAstI32: { 251 | expected_a = a | 0; 252 | expected_b = b | 0; 253 | break; 254 | } 255 | case kAstF32: { 256 | expected_a = Math.fround(a); 257 | expected_b = Math.fround(b); 258 | break; 259 | } 260 | case kAstF64: { 261 | expected_a = a; 262 | expected_b = b; 263 | break; 264 | } 265 | } 266 | 267 | assertEquals(expected_a, args_a); 268 | assertEquals(expected_b, args_b); 269 | assertEquals(expected_a, passed_a); 270 | assertEquals(expected_b, passed_b); 271 | } 272 | } 273 | 274 | 275 | testCallBinopVoid(kAstI32); 276 | // TODO testCallBinopVoid(kAstI64); 277 | testCallBinopVoid(kAstF32); 278 | testCallBinopVoid(kAstF64); 279 | 280 | 281 | 282 | function testCallPrint() { 283 | var kBodySize = 10; 284 | var kNamePrintOffset = 10 + 7 + 7 + 9 + kBodySize + 1; 285 | var kNameMainOffset = kNamePrintOffset + 6; 286 | 287 | var ffi = new Object(); 288 | ffi.print = print; 289 | 290 | var data = bytes( 291 | // -- signatures 292 | kDeclSignatures, 2, 293 | 1, kAstStmt, kAstI32, // i32->void 294 | 1, kAstStmt, kAstF64, // f64->int 295 | kDeclFunctions, 3, 296 | // -- import print i32 297 | kDeclFunctionName | kDeclFunctionImport, 298 | 0, 0, // signature index 299 | kNamePrintOffset, 0, 0, 0, // name offset 300 | // -- import print f64 301 | kDeclFunctionName | kDeclFunctionImport, 302 | 1, 0, // signature index 303 | kNamePrintOffset, 0, 0, 0, // name offset 304 | // -- decl main 305 | kDeclFunctionName | kDeclFunctionExport, 306 | 1, 0, // signature index 307 | kNameMainOffset, 0, 0, 0, // name offset 308 | kBodySize, 0, // body size 309 | // main body 310 | kExprBlock, 2, // -- 311 | kExprCallFunction, 0, // -- 312 | kExprI8Const, 97, // -- 313 | kExprCallFunction, 1, // -- 314 | kExprGetLocal, 0, // -- 315 | // names 316 | kDeclEnd, 317 | 'p', 'r', 'i', 'n', 't', 0, // -- 318 | 'm', 'a', 'i', 'n', 0 // -- 319 | ); 320 | 321 | var module = WASM.instantiateModule(data, ffi); 322 | 323 | assertEquals("function", typeof module.main); 324 | 325 | for (var i = -9; i < 900; i += 6.125) { 326 | module.main(i); 327 | } 328 | } 329 | 330 | testCallPrint(); 331 | testCallPrint(); 332 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/indirect-calls.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | load("test/mjsunit/wasm/wasm-constants.js"); 6 | 7 | var module = (function () { 8 | var kFuncWithBody = 9; 9 | var kFuncImported = 7; 10 | var kBodySize1 = 5; 11 | var kBodySize2 = 8; 12 | var kFuncTableSize = 8; 13 | var kSubOffset = 13 + kFuncWithBody + kBodySize1 + kFuncImported + kFuncWithBody + kBodySize2 + kFuncTableSize + 1; 14 | var kAddOffset = kSubOffset + 4; 15 | var kMainOffset = kAddOffset + 4; 16 | 17 | var ffi = new Object(); 18 | ffi.add = (function(a, b) { return a + b | 0; }); 19 | 20 | return WASM.instantiateModule(bytes( 21 | // -- signatures 22 | kDeclSignatures, 2, 23 | 2, kAstI32, kAstI32, kAstI32, // int, int -> int 24 | 3, kAstI32, kAstI32, kAstI32, kAstI32, // int, int, int -> int 25 | // -- function #0 (sub) 26 | kDeclFunctions, 3, 27 | kDeclFunctionName, 28 | 0, 0, // signature offset 29 | kSubOffset, 0, 0, 0, // name offset 30 | kBodySize1, 0, // body size 31 | kExprI32Sub, // -- 32 | kExprGetLocal, 0, // -- 33 | kExprGetLocal, 1, // -- 34 | // -- function #1 (add) 35 | kDeclFunctionName | kDeclFunctionImport, 36 | 0, 0, // signature offset 37 | kAddOffset, 0, 0, 0, // name offset 38 | // -- function #2 (main) 39 | kDeclFunctionName | kDeclFunctionExport, 40 | 1, 0, // signature offset 41 | kMainOffset, 0, 0, 0, // name offset 42 | kBodySize2, 0, // body size 43 | kExprCallIndirect, 0, 44 | kExprGetLocal, 0, 45 | kExprGetLocal, 1, 46 | kExprGetLocal, 2, 47 | // -- function table 48 | kDeclFunctionTable, 49 | 3, 50 | 0, 0, 51 | 1, 0, 52 | 2, 0, 53 | kDeclEnd, 54 | 's', 'u', 'b', 0, // name 55 | 'a', 'd', 'd', 0, // name 56 | 'm', 'a', 'i', 'n', 0 // name 57 | ), ffi); 58 | })(); 59 | 60 | // Check the module exists. 61 | assertFalse(module === undefined); 62 | assertFalse(module === null); 63 | assertFalse(module === 0); 64 | assertEquals("object", typeof module); 65 | assertEquals("function", typeof module.main); 66 | 67 | assertEquals(5, module.main(0, 12, 7)); 68 | assertEquals(19, module.main(1, 12, 7)); 69 | 70 | assertTraps(kTrapFuncSigMismatch, "module.main(2, 12, 33)"); 71 | assertTraps(kTrapFuncInvalid, "module.main(3, 12, 33)"); 72 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/instantiate-module-basic.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | load("test/mjsunit/wasm/wasm-constants.js"); 6 | 7 | var kReturnValue = 117; 8 | 9 | var kBodySize = 2; 10 | var kNameOffset = 19 + kBodySize + 1; 11 | 12 | var data = bytes( 13 | // -- memory 14 | kDeclMemory, 15 | 10, 10, 1, 16 | // -- signatures 17 | kDeclSignatures, 1, 18 | 0, kAstI32, // signature: void -> int 19 | // -- main function 20 | kDeclFunctions, 1, 21 | kDeclFunctionName | kDeclFunctionExport, 22 | 0, 0, // signature index 23 | kNameOffset, 0, 0, 0, // name offset 24 | kBodySize, 0, // body size 25 | // -- body 26 | kExprI8Const, // -- 27 | kReturnValue, // -- 28 | kDeclEnd, 29 | 'm', 'a', 'i', 'n', 0 // name 30 | ); 31 | 32 | var module = WASM.instantiateModule(data); 33 | 34 | // Check the module exists. 35 | assertFalse(module === undefined); 36 | assertFalse(module === null); 37 | assertFalse(module === 0); 38 | assertEquals("object", typeof module); 39 | 40 | // Check the memory is an ArrayBuffer. 41 | var mem = module.memory; 42 | assertFalse(mem === undefined); 43 | assertFalse(mem === null); 44 | assertFalse(mem === 0); 45 | assertEquals("object", typeof mem); 46 | assertTrue(mem instanceof ArrayBuffer); 47 | for (var i = 0; i < 4; i++) { 48 | module.memory = 0; // should be ignored 49 | assertEquals(mem, module.memory); 50 | } 51 | 52 | assertEquals(1024, module.memory.byteLength); 53 | 54 | // Check the properties of the main function. 55 | assertFalse(module.main === undefined); 56 | assertFalse(module.main === null); 57 | assertFalse(module.main === 0); 58 | assertEquals("function", typeof module.main); 59 | 60 | assertEquals(kReturnValue, module.main()); 61 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/module-memory.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Flags: --expose-gc --stress-compaction 6 | 7 | load("test/mjsunit/wasm/wasm-constants.js"); 8 | 9 | var kMemSize = 4096; 10 | 11 | function genModule(memory) { 12 | var kBodySize = 27; 13 | var kNameMainOffset = 28 + kBodySize + 1; 14 | 15 | var data = bytes( 16 | kDeclMemory, 17 | 12, 12, 1, // memory 18 | // -- signatures 19 | kDeclSignatures, 1, 20 | 1, kAstI32, kAstI32, // int->int 21 | // -- main function 22 | kDeclFunctions, 1, 23 | kDeclFunctionLocals | kDeclFunctionName | kDeclFunctionExport, 24 | 0, 0, 25 | kNameMainOffset, 0, 0, 0, // name offset 26 | 1, 0, // local int32 count 27 | 0, 0, // local int64 count 28 | 0, 0, // local float32 count 29 | 0, 0, // local float64 count 30 | kBodySize, 0, // code size 31 | // main body: while(i) { if(mem[i]) return -1; i -= 4; } return 0; 32 | kExprBlock,2, 33 | kExprLoop,1, 34 | kExprIf, 35 | kExprGetLocal,0, 36 | kExprBr, 0, 37 | kExprIfElse, 38 | kExprI32LoadMem,0,kExprGetLocal,0, 39 | kExprBr,2, kExprI8Const, 255, 40 | kExprSetLocal,0, 41 | kExprI32Sub,kExprGetLocal,0,kExprI8Const,4, 42 | kExprI8Const,0, 43 | // names 44 | kDeclEnd, 45 | 'm', 'a', 'i', 'n', 0 // -- 46 | ); 47 | 48 | return WASM.instantiateModule(data, null, memory); 49 | } 50 | 51 | function testPokeMemory() { 52 | var module = genModule(null); 53 | var buffer = module.memory; 54 | assertEquals(kMemSize, buffer.byteLength); 55 | 56 | var array = new Int8Array(buffer); 57 | assertEquals(kMemSize, array.length); 58 | 59 | for (var i = 0; i < kMemSize; i++) { 60 | assertEquals(0, array[i]); 61 | } 62 | 63 | for (var i = 0; i < 10; i++) { 64 | assertEquals(0, module.main(kMemSize - 4)); 65 | 66 | array[kMemSize/2 + i] = 1; 67 | assertEquals(0, module.main(kMemSize/2 - 4)); 68 | assertEquals(-1, module.main(kMemSize - 4)); 69 | 70 | array[kMemSize/2 + i] = 0; 71 | assertEquals(0, module.main(kMemSize - 4)); 72 | } 73 | } 74 | 75 | testPokeMemory(); 76 | 77 | function testSurvivalAcrossGc() { 78 | var checker = genModule(null).main; 79 | for (var i = 0; i < 5; i++) { 80 | print("gc run ", i); 81 | assertEquals(0, checker(kMemSize - 4)); 82 | gc(); 83 | } 84 | } 85 | 86 | testSurvivalAcrossGc(); 87 | testSurvivalAcrossGc(); 88 | testSurvivalAcrossGc(); 89 | testSurvivalAcrossGc(); 90 | 91 | 92 | function testPokeOuterMemory() { 93 | var buffer = new ArrayBuffer(kMemSize); 94 | var module = genModule(buffer); 95 | assertEquals(kMemSize, buffer.byteLength); 96 | 97 | var array = new Int8Array(buffer); 98 | assertEquals(kMemSize, array.length); 99 | 100 | for (var i = 0; i < kMemSize; i++) { 101 | assertEquals(0, array[i]); 102 | } 103 | 104 | for (var i = 0; i < 10; i++) { 105 | assertEquals(0, module.main(kMemSize - 4)); 106 | 107 | array[kMemSize/2 + i] = 1; 108 | assertEquals(0, module.main(kMemSize/2 - 4)); 109 | assertEquals(-1, module.main(kMemSize - 4)); 110 | 111 | array[kMemSize/2 + i] = 0; 112 | assertEquals(0, module.main(kMemSize - 4)); 113 | } 114 | } 115 | 116 | testPokeOuterMemory(); 117 | 118 | function testOuterMemorySurvivalAcrossGc() { 119 | var buffer = new ArrayBuffer(kMemSize); 120 | var checker = genModule(buffer).main; 121 | for (var i = 0; i < 5; i++) { 122 | print("gc run ", i); 123 | assertEquals(0, checker(kMemSize - 4)); 124 | gc(); 125 | } 126 | } 127 | 128 | testOuterMemorySurvivalAcrossGc(); 129 | testOuterMemorySurvivalAcrossGc(); 130 | testOuterMemorySurvivalAcrossGc(); 131 | testOuterMemorySurvivalAcrossGc(); 132 | 133 | 134 | function testOOBThrows() { 135 | var kBodySize = 8; 136 | var kNameMainOffset = 29 + kBodySize + 1; 137 | 138 | var data = bytes( 139 | kDeclMemory, 140 | 12, 12, 1, // memory = 4KB 141 | // -- signatures 142 | kDeclSignatures, 1, 143 | 2, kAstI32, kAstI32, kAstI32, // int->int 144 | // -- main function 145 | kDeclFunctions, 1, 146 | kDeclFunctionLocals | kDeclFunctionName | kDeclFunctionExport, 147 | 0, 0, 148 | kNameMainOffset, 0, 0, 0, // name offset 149 | 1, 0, // local int32 count 150 | 0, 0, // local int64 count 151 | 0, 0, // local float32 count 152 | 0, 0, // local float64 count 153 | kBodySize, 0, // code size 154 | // geti: return mem[a] = mem[b] 155 | kExprI32StoreMem, 0, kExprGetLocal, 0, kExprI32LoadMem, 0, kExprGetLocal, 1, 156 | // names 157 | kDeclEnd, 158 | 'g','e','t','i', 0 // -- 159 | ); 160 | 161 | var memory = null; 162 | var module = WASM.instantiateModule(data, null, memory); 163 | 164 | var offset; 165 | 166 | function read() { return module.geti(0, offset); } 167 | function write() { return module.geti(offset, 0); } 168 | 169 | for (offset = 0; offset < 4092; offset++) { 170 | assertEquals(0, read()); 171 | assertEquals(0, write()); 172 | } 173 | 174 | 175 | for (offset = 4093; offset < 4124; offset++) { 176 | assertTraps(kTrapMemOutOfBounds, read); 177 | assertTraps(kTrapMemOutOfBounds, write); 178 | } 179 | } 180 | 181 | testOOBThrows(); 182 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/params.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | load("test/mjsunit/wasm/wasm-constants.js"); 6 | 7 | function runSelect2(module, which, a, b) { 8 | assertEquals(which == 0 ? a : b, module.select(a, b)); 9 | } 10 | 11 | function testSelect2(type) { 12 | var kBodySize = 2; 13 | var kNameOffset = 21 + kBodySize + 1; 14 | 15 | for (var which = 0; which < 2; which++) { 16 | print("type = " + type + ", which = " + which); 17 | 18 | var data = bytes( 19 | // -- memory 20 | kDeclMemory, 21 | 12, 12, 1, // memory 22 | // -- signatures 23 | kDeclSignatures, 1, 24 | 2, type, type, type, // signature: (t,t)->t 25 | // -- select 26 | kDeclFunctions, 1, 27 | kDeclFunctionName | kDeclFunctionExport, 28 | 0, 0, 29 | kNameOffset, 0, 0, 0, // name offset 30 | kBodySize, 0, // body size 31 | kExprGetLocal, which, // -- 32 | kDeclEnd, 33 | 's','e','l','e','c','t',0 // name 34 | ); 35 | 36 | var module = WASM.instantiateModule(data); 37 | 38 | assertEquals("function", typeof module.select); 39 | runSelect2(module, which, 99, 97); 40 | runSelect2(module, which, -99, -97); 41 | 42 | if (type != kAstF32) { 43 | runSelect2(module, which, 0x80000000 | 0, 0x7fffffff | 0); 44 | runSelect2(module, which, 0x80000001 | 0, 0x7ffffffe | 0); 45 | runSelect2(module, which, 0xffffffff | 0, 0xfffffffe | 0); 46 | runSelect2(module, which, -2147483647, 2147483646); 47 | runSelect2(module, which, -2147483646, 2147483645); 48 | runSelect2(module, which, -2147483648, 2147483647); 49 | } 50 | 51 | if (type != kAstI32 && type != kAstI64) { 52 | runSelect2(module, which, -1.25, 5.25); 53 | runSelect2(module, which, Infinity, -Infinity); 54 | } 55 | } 56 | } 57 | 58 | 59 | testSelect2(kAstI32); 60 | testSelect2(kAstF32); 61 | testSelect2(kAstF64); 62 | 63 | 64 | function runSelect10(module, which, a, b) { 65 | var x = -1; 66 | 67 | var result = [ 68 | module.select(a, b, x, x, x, x, x, x, x, x), 69 | module.select(x, a, b, x, x, x, x, x, x, x), 70 | module.select(x, x, a, b, x, x, x, x, x, x), 71 | module.select(x, x, x, a, b, x, x, x, x, x), 72 | module.select(x, x, x, x, a, b, x, x, x, x), 73 | module.select(x, x, x, x, x, a, b, x, x, x), 74 | module.select(x, x, x, x, x, x, a, b, x, x), 75 | module.select(x, x, x, x, x, x, x, a, b, x), 76 | module.select(x, x, x, x, x, x, x, x, a, b), 77 | module.select(x, x, x, x, x, x, x, x, x, a) 78 | ]; 79 | 80 | for (var i = 0; i < 10; i++) { 81 | if (which == i) assertEquals(a, result[i]); 82 | else if (which == i+1) assertEquals(b, result[i]); 83 | else assertEquals(x, result[i]); 84 | } 85 | } 86 | 87 | function testSelect10(type) { 88 | var kBodySize = 2; 89 | var kNameOffset = 29 + kBodySize + 1; 90 | 91 | for (var which = 0; which < 10; which++) { 92 | print("type = " + type + ", which = " + which); 93 | 94 | var t = type; 95 | var data = bytes( 96 | kDeclMemory, 97 | 12, 12, 1, // memory 98 | // signatures 99 | kDeclSignatures, 1, 100 | 10, t,t,t,t,t,t,t,t,t,t,t, // (tx10)->t 101 | // main function 102 | kDeclFunctions, 1, 103 | kDeclFunctionName | kDeclFunctionExport, 104 | 0, 0, 105 | kNameOffset, 0, 0, 0, // name offset 106 | kBodySize, 0, // body size 107 | kExprGetLocal, which, // -- 108 | kDeclEnd, 109 | 's','e','l','e','c','t',0 // name 110 | ); 111 | 112 | var module = WASM.instantiateModule(data); 113 | 114 | assertEquals("function", typeof module.select); 115 | runSelect10(module, which, 99, 97); 116 | runSelect10(module, which, -99, -97); 117 | 118 | if (type != kAstF32) { 119 | runSelect10(module, which, 0x80000000 | 0, 0x7fffffff | 0); 120 | runSelect10(module, which, 0x80000001 | 0, 0x7ffffffe | 0); 121 | runSelect10(module, which, 0xffffffff | 0, 0xfffffffe | 0); 122 | runSelect10(module, which, -2147483647, 2147483646); 123 | runSelect10(module, which, -2147483646, 2147483645); 124 | runSelect10(module, which, -2147483648, 2147483647); 125 | } 126 | 127 | if (type != kAstI32 && type != kAstI64) { 128 | runSelect10(module, which, -1.25, 5.25); 129 | runSelect10(module, which, Infinity, -Infinity); 130 | } 131 | } 132 | } 133 | 134 | 135 | testSelect10(kAstI32); 136 | testSelect10(kAstF32); 137 | testSelect10(kAstF64); 138 | 139 | 140 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/stackwalk.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | // Flags: --expose-gc --allow-natives-syntax 6 | 7 | load("test/mjsunit/wasm/wasm-constants.js"); 8 | 9 | function makeFFI(func) { 10 | var kBodySize = 6; 11 | var kNameFunOffset = 24 + kBodySize + 1; 12 | var kNameMainOffset = kNameFunOffset + 4; 13 | 14 | var ffi = new Object(); 15 | ffi.fun = func; 16 | 17 | var data = bytes( 18 | // signatures 19 | kDeclSignatures, 1, 20 | 2, kAstI32, kAstF64, kAstF64, // (f64,f64) -> int 21 | // -- foreign function 22 | kDeclFunctions, 2, 23 | kDeclFunctionName | kDeclFunctionImport, 24 | 0, 0, 25 | kNameFunOffset, 0, 0, 0, // name offset 26 | // -- main function 27 | kDeclFunctionName | kDeclFunctionExport, 28 | 0, 0, 29 | kNameMainOffset, 0, 0, 0, // name offset 30 | kBodySize, 0, 31 | // main body 32 | kExprCallFunction, 0, // -- 33 | kExprGetLocal, 0, // -- 34 | kExprGetLocal, 1, // -- 35 | // names 36 | kDeclEnd, 37 | 'f', 'u', 'n', 0, // -- 38 | 'm', 'a', 'i', 'n', 0 // -- 39 | ); 40 | 41 | var module = WASM.instantiateModule(data, ffi); 42 | 43 | assertEquals("function", typeof module.main); 44 | 45 | return module.main; 46 | } 47 | 48 | 49 | function makeReentrantFFI(func) { 50 | var main = makeFFI(reenter); 51 | 52 | function reenter(a, b) { 53 | print(" reenter " + a); 54 | if (a > 0) main(a - 1, b); 55 | else func(); 56 | } 57 | return main; 58 | } 59 | 60 | 61 | function runTest(builder) { 62 | // ---- THROWING TEST ----------------------------------------------- 63 | 64 | function throwadd(a, b) { 65 | print("-- trying throw --"); 66 | throw a + b; 67 | } 68 | 69 | function throwa(a) { 70 | print("-- trying throw --"); 71 | throw a; 72 | } 73 | 74 | function throwstr() { 75 | print("-- trying throw --"); 76 | throw "string"; 77 | } 78 | 79 | assertThrows(builder(throwadd)); 80 | assertThrows(builder(throwa)); 81 | assertThrows(builder(throwstr)); 82 | 83 | try { 84 | builder(throwadd)(7.8, 9.9); 85 | } catch(e) { 86 | print(e); 87 | } 88 | 89 | try { 90 | builder(throwa)(11.8, 9.3); 91 | } catch(e) { 92 | print(e); 93 | } 94 | 95 | 96 | try { 97 | builder(throwstr)(3, 5); 98 | } catch(e) { 99 | print(e); 100 | } 101 | 102 | 103 | // ---- DEOPT TEST ----------------------------------------------- 104 | 105 | function deopt() { 106 | print("-- trying deopt --"); 107 | %DeoptimizeFunction(deopter); 108 | } 109 | 110 | var deopter = builder(deopt); 111 | 112 | deopter(5, 5); 113 | for (var i = 0; i < 9; i++) { 114 | deopter(6, 6); 115 | } 116 | 117 | 118 | // ---- GC TEST ----------------------------------------------- 119 | function dogc(a, b) { 120 | print("-- trying gc --"); 121 | gc(); 122 | gc(); 123 | } 124 | 125 | 126 | var gcer = builder(dogc); 127 | gcer(7, 7); 128 | 129 | for (var i = 0; i < 9; i++) { 130 | gcer(8, 8); 131 | } 132 | } 133 | 134 | runTest(makeReentrantFFI); 135 | runTest(makeFFI); 136 | 137 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/unreachable.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | load("test/mjsunit/wasm/wasm-constants.js"); 6 | 7 | var module = (function () { 8 | var kFuncWithBody = 9; 9 | var kFuncImported = 7; 10 | var kBodySize1 = 1; 11 | var kMainOffset = 6 + kFuncWithBody + kBodySize1 + 1; 12 | 13 | var ffi = new Object(); 14 | ffi.add = (function(a, b) { return a + b | 0; }); 15 | 16 | return WASM.instantiateModule(bytes( 17 | // -- signatures 18 | kDeclSignatures, 1, 19 | 0, kAstStmt, // void -> void 20 | // -- function #0 (unreachable) 21 | kDeclFunctions, 1, 22 | kDeclFunctionName | kDeclFunctionExport, 23 | 0, 0, // signature offset 24 | kMainOffset, 0, 0, 0, // name offset 25 | kBodySize1, 0, // body size 26 | kExprUnreachable, 27 | kDeclEnd, 28 | 'm', 'a', 'i', 'n', 0 // name 29 | ), ffi); 30 | })(); 31 | 32 | // Check the module exists. 33 | assertFalse(module === undefined); 34 | assertFalse(module === null); 35 | assertFalse(module === 0); 36 | assertEquals("object", typeof module); 37 | assertEquals("function", typeof module.main); 38 | 39 | var exception = ""; 40 | try { 41 | assertEquals(0, module.main()); 42 | } catch(e) { 43 | print("correctly caught: " + e); 44 | exception = e; 45 | } 46 | assertEquals("unreachable", exception); 47 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/verify-function-basic-errors.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | function Foo() { } 6 | 7 | assertThrows(function() { WASM.verifyFunction(); }) 8 | assertThrows(function() { WASM.verifyFunction(0); }) 9 | assertThrows(function() { WASM.verifyFunction("s"); }) 10 | assertThrows(function() { WASM.verifyFunction(undefined); }) 11 | assertThrows(function() { WASM.verifyFunction(1.1); }) 12 | assertThrows(function() { WASM.verifyFunction(1/0); }) 13 | assertThrows(function() { WASM.verifyFunction(null); }) 14 | assertThrows(function() { WASM.verifyFunction(new Foo()); }) 15 | assertThrows(function() { WASM.verifyFunction(new ArrayBuffer(0)); }) 16 | assertThrows(function() { WASM.verifyFunction(new ArrayBuffer(140000)); }) 17 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/verify-function-simple.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | load("test/mjsunit/wasm/wasm-constants.js"); 6 | 7 | try { 8 | var data = bytes( 9 | 0, kAstStmt, // signature 10 | 3, 0, // local int32 count 11 | 4, 0, // local int64 count 12 | 5, 0, // local float32 count 13 | 6, 0, // local float64 count 14 | kExprNop // body 15 | ); 16 | 17 | WASM.verifyFunction(data); 18 | print("ok"); 19 | } catch (e) { 20 | assertTrue(false); 21 | } 22 | 23 | 24 | var threw = false; 25 | try { 26 | var data = bytes( 27 | 0, kAstI32, // signature 28 | 2, 0, // local int32 count 29 | 3, 0, // local int64 count 30 | 4, 0, // local float32 count 31 | 5, 0, // local float64 count 32 | kExprBlock, 2, kExprNop, kExprNop // body 33 | ); 34 | 35 | WASM.verifyFunction(data); 36 | print("not ok"); 37 | } catch (e) { 38 | print("ok: " + e); 39 | threw = true; 40 | } 41 | 42 | assertTrue(threw); 43 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/verify-module-basic-errors.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | function Foo() { } 6 | 7 | assertThrows(function() { WASM.verifyModule(); }) 8 | assertThrows(function() { WASM.verifyModule(0); }) 9 | assertThrows(function() { WASM.verifyModule("s"); }) 10 | assertThrows(function() { WASM.verifyModule(undefined); }) 11 | assertThrows(function() { WASM.verifyModule(1.1); }) 12 | assertThrows(function() { WASM.verifyModule(1/0); }) 13 | assertThrows(function() { WASM.verifyModule(null); }) 14 | assertThrows(function() { WASM.verifyModule(new Foo()); }) 15 | assertThrows(function() { WASM.verifyModule(new ArrayBuffer(0)); }) 16 | assertThrows(function() { WASM.verifyModule(new ArrayBuffer(7)); }) 17 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/wasm-constants.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | function bytes() { 6 | var buffer = new ArrayBuffer(arguments.length); 7 | var view = new Uint8Array(buffer); 8 | for (var i = 0; i < arguments.length; i++) { 9 | var val = arguments[i]; 10 | if ((typeof val) == "string") val = val.charCodeAt(0); 11 | view[i] = val | 0; 12 | } 13 | return buffer; 14 | } 15 | 16 | // Section declaration constants 17 | var kDeclMemory = 0x00; 18 | var kDeclSignatures = 0x01; 19 | var kDeclFunctions = 0x02; 20 | var kDeclGlobals = 0x03; 21 | var kDeclDataSegments = 0x04; 22 | var kDeclFunctionTable = 0x05; 23 | var kDeclEnd = 0x06; 24 | 25 | // Function declaration flags 26 | var kDeclFunctionName = 0x01; 27 | var kDeclFunctionImport = 0x02; 28 | var kDeclFunctionLocals = 0x04; 29 | var kDeclFunctionExport = 0x08; 30 | 31 | // Local types 32 | var kAstStmt = 0; 33 | var kAstI32 = 1; 34 | var kAstI64 = 2; 35 | var kAstF32 = 3; 36 | var kAstF64 = 4; 37 | 38 | // Opcodes 39 | var kExprNop = 0x00; 40 | var kExprBlock = 0x01; 41 | var kExprLoop = 0x02; 42 | var kExprIf = 0x03; 43 | var kExprIfElse = 0x04; 44 | var kExprSelect = 0x05; 45 | var kExprBr = 0x06; 46 | var kExprBrIf = 0x07; 47 | var kExprTableSwitch = 0x08; 48 | var kExprReturn = 0x14; 49 | var kExprUnreachable = 0x15; 50 | 51 | var kExprI8Const = 0x09; 52 | var kExprI32Const = 0x0a; 53 | var kExprI64Const = 0x0b; 54 | var kExprF64Const = 0x0c; 55 | var kExprF32Const = 0x0d; 56 | var kExprGetLocal = 0x0e; 57 | var kExprSetLocal = 0x0f; 58 | var kExprLoadGlobal = 0x10; 59 | var kExprStoreGlobal = 0x11; 60 | var kExprCallFunction = 0x12; 61 | var kExprCallIndirect = 0x13; 62 | 63 | var kExprI32LoadMem8S = 0x20; 64 | var kExprI32LoadMem8U = 0x21; 65 | var kExprI32LoadMem16S = 0x22; 66 | var kExprI32LoadMem16U = 0x23; 67 | var kExprI64LoadMem8S = 0x24; 68 | var kExprI64LoadMem8U = 0x25; 69 | var kExprI64LoadMem16S = 0x26; 70 | var kExprI64LoadMem16U = 0x27; 71 | var kExprI64LoadMem32S = 0x28; 72 | var kExprI64LoadMem32U = 0x29; 73 | var kExprI32LoadMem = 0x2a; 74 | var kExprI64LoadMem = 0x2b; 75 | var kExprF32LoadMem = 0x2c; 76 | var kExprF64LoadMem = 0x2d; 77 | 78 | var kExprI32StoreMem8 = 0x2e; 79 | var kExprI32StoreMem16 = 0x2f; 80 | var kExprI64StoreMem8 = 0x30; 81 | var kExprI64StoreMem16 = 0x31; 82 | var kExprI64StoreMem32 = 0x32; 83 | var kExprI32StoreMem = 0x33; 84 | var kExprI64StoreMem = 0x34; 85 | var kExprF32StoreMem = 0x35; 86 | var kExprF64StoreMem = 0x36; 87 | 88 | var kExprMemorySize = 0x3b; 89 | var kExprGrowMemory = 0x39; 90 | 91 | var kExprI32Add = 0x40; 92 | var kExprI32Sub = 0x41; 93 | var kExprI32Mul = 0x42; 94 | var kExprI32DivS = 0x43; 95 | var kExprI32DivU = 0x44; 96 | var kExprI32RemS = 0x45; 97 | var kExprI32RemU = 0x46; 98 | var kExprI32And = 0x47; 99 | var kExprI32Ior = 0x48; 100 | var kExprI32Xor = 0x49; 101 | var kExprI32Shl = 0x4a; 102 | var kExprI32ShrU = 0x4b; 103 | var kExprI32ShrS = 0x4c; 104 | var kExprI32Eq = 0x4d; 105 | var kExprI32Ne = 0x4e; 106 | var kExprI32LtS = 0x4f; 107 | var kExprI32LeS = 0x50; 108 | var kExprI32LtU = 0x51; 109 | var kExprI32LeU = 0x52; 110 | var kExprI32GtS = 0x53; 111 | var kExprI32GeS = 0x54; 112 | var kExprI32GtU = 0x55; 113 | var kExprI32GeU = 0x56; 114 | var kExprI32Clz = 0x57; 115 | var kExprI32Ctz = 0x58; 116 | var kExprI32Popcnt = 0x59; 117 | var kExprBoolNot = 0x5a; 118 | var kExprI64Add = 0x5b; 119 | var kExprI64Sub = 0x5c; 120 | var kExprI64Mul = 0x5d; 121 | var kExprI64DivS = 0x5e; 122 | var kExprI64DivU = 0x5f; 123 | var kExprI64RemS = 0x60; 124 | var kExprI64RemU = 0x61; 125 | var kExprI64And = 0x62; 126 | var kExprI64Ior = 0x63; 127 | var kExprI64Xor = 0x64; 128 | var kExprI64Shl = 0x65; 129 | var kExprI64ShrU = 0x66; 130 | var kExprI64ShrS = 0x67; 131 | var kExprI64Eq = 0x68; 132 | var kExprI64Ne = 0x69; 133 | var kExprI64LtS = 0x6a; 134 | var kExprI64LeS = 0x6b; 135 | var kExprI64LtU = 0x6c; 136 | var kExprI64LeU = 0x6d; 137 | var kExprI64GtS = 0x6e; 138 | var kExprI64GeS = 0x6f; 139 | var kExprI64GtU = 0x70; 140 | var kExprI64GeU = 0x71; 141 | var kExprI64Clz = 0x72; 142 | var kExprI64Ctz = 0x73; 143 | var kExprI64Popcnt = 0x74; 144 | var kExprF32Add = 0x75; 145 | var kExprF32Sub = 0x76; 146 | var kExprF32Mul = 0x77; 147 | var kExprF32Div = 0x78; 148 | var kExprF32Min = 0x79; 149 | var kExprF32Max = 0x7a; 150 | var kExprF32Abs = 0x7b; 151 | var kExprF32Neg = 0x7c; 152 | var kExprF32CopySign = 0x7d; 153 | var kExprF32Ceil = 0x7e; 154 | var kExprF32Floor = 0x7f; 155 | var kExprF32Trunc = 0x80; 156 | var kExprF32NearestInt = 0x81; 157 | var kExprF32Sqrt = 0x82; 158 | var kExprF32Eq = 0x83; 159 | var kExprF32Ne = 0x84; 160 | var kExprF32Lt = 0x85; 161 | var kExprF32Le = 0x86; 162 | var kExprF32Gt = 0x87; 163 | var kExprF32Ge = 0x88; 164 | var kExprF64Add = 0x89; 165 | var kExprF64Sub = 0x8a; 166 | var kExprF64Mul = 0x8b; 167 | var kExprF64Div = 0x8c; 168 | var kExprF64Min = 0x8d; 169 | var kExprF64Max = 0x8e; 170 | var kExprF64Abs = 0x8f; 171 | var kExprF64Neg = 0x90; 172 | var kExprF64CopySign = 0x91; 173 | var kExprF64Ceil = 0x92; 174 | var kExprF64Floor = 0x93; 175 | var kExprF64Trunc = 0x94; 176 | var kExprF64NearestInt = 0x95; 177 | var kExprF64Sqrt = 0x96; 178 | var kExprF64Eq = 0x97; 179 | var kExprF64Ne = 0x98; 180 | var kExprF64Lt = 0x99; 181 | var kExprF64Le = 0x9a; 182 | var kExprF64Gt = 0x9b; 183 | var kExprF64Ge = 0x9c; 184 | var kExprI32SConvertF32 = 0x9d; 185 | var kExprI32SConvertF64 = 0x9e; 186 | var kExprI32UConvertF32 = 0x9f; 187 | var kExprI32UConvertF64 = 0xa0; 188 | var kExprI32ConvertI64 = 0xa1; 189 | var kExprI64SConvertF32 = 0xa2; 190 | var kExprI64SConvertF64 = 0xa3; 191 | var kExprI64UConvertF32 = 0xa4; 192 | var kExprI64UConvertF64 = 0xa5; 193 | var kExprI64SConvertI32 = 0xa6; 194 | var kExprI64UConvertI32 = 0xa7; 195 | var kExprF32SConvertI32 = 0xa8; 196 | var kExprF32UConvertI32 = 0xa9; 197 | var kExprF32SConvertI64 = 0xaa; 198 | var kExprF32UConvertI64 = 0xab; 199 | var kExprF32ConvertF64 = 0xac; 200 | var kExprF32ReinterpretI32 = 0xad; 201 | var kExprF64SConvertI32 = 0xae; 202 | var kExprF64UConvertI32 = 0xaf; 203 | var kExprF64SConvertI64 = 0xb0; 204 | var kExprF64UConvertI64 = 0xb1; 205 | var kExprF64ConvertF32 = 0xb2; 206 | var kExprF64ReinterpretI64 = 0xb3; 207 | var kExprI32ReinterpretF32 = 0xb4; 208 | var kExprI64ReinterpretF64 = 0xb5; 209 | 210 | var kTrapUnreachable = 0; 211 | var kTrapMemOutOfBounds = 1; 212 | var kTrapDivByZero = 2; 213 | var kTrapDivUnrepresentable = 3; 214 | var kTrapRemByZero = 4; 215 | var kTrapFloatUnrepresentable = 5; 216 | var kTrapFuncInvalid = 6; 217 | var kTrapFuncSigMismatch = 7; 218 | 219 | var kTrapMsgs = [ 220 | "unreachable", 221 | "memory access out of bounds", 222 | "divide by zero", 223 | "divide result unrepresentable", 224 | "remainder by zero", 225 | "integer result unrepresentable", 226 | "invalid function", 227 | "function signature mismatch" 228 | ]; 229 | 230 | function assertTraps(trap, code) { 231 | var threwException = true; 232 | try { 233 | if (typeof code === 'function') { 234 | code(); 235 | } else { 236 | eval(code); 237 | } 238 | threwException = false; 239 | } catch (e) { 240 | assertEquals("string", typeof e); 241 | assertEquals(kTrapMsgs[trap], e); 242 | // Success. 243 | return; 244 | } 245 | throw new MjsUnitAssertionError("Did not trap, expected: " + kTrapMsgs[trap]); 246 | } 247 | -------------------------------------------------------------------------------- /test/mjsunit/wasm/wasm-object-api.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | assertFalse(undefined === WASM); 6 | assertFalse(undefined == WASM); 7 | assertEquals("function", typeof WASM.verifyModule); 8 | assertEquals("function", typeof WASM.verifyFunction); 9 | assertEquals("function", typeof WASM.compileRun); 10 | -------------------------------------------------------------------------------- /test/unittests/wasm/encoder-unittest.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "test/unittests/test-utils.h" 6 | 7 | #include "src/v8.h" 8 | 9 | #include "src/wasm/encoder.h" 10 | #include "src/wasm/ast-decoder.h" 11 | 12 | namespace v8 { 13 | namespace internal { 14 | namespace wasm { 15 | 16 | class EncoderTest : public TestWithZone { 17 | protected: 18 | void AddLocal(WasmFunctionBuilder* f, LocalType type) { 19 | uint16_t index = f->AddLocal(type); 20 | const std::vector& out_index = UnsignedLEB128From(index); 21 | std::vector code; 22 | code.push_back(kExprGetLocal); 23 | for(size_t i = 0; i < out_index.size(); i++) { 24 | code.push_back(out_index.at(i)); 25 | } 26 | uint32_t local_indices[] = {1}; 27 | f->EmitCode(code.data(), static_cast(code.size()), local_indices, 1); 28 | } 29 | 30 | void CheckReadValue( 31 | uint8_t* leb_value, 32 | uint32_t expected_result, 33 | int expected_length, 34 | ReadUnsignedLEB128ErrorCode expected_error_code) { 35 | int length; 36 | uint32_t result; 37 | ReadUnsignedLEB128ErrorCode error_code = 38 | ReadUnsignedLEB128Operand(leb_value, leb_value+5, &length, &result); 39 | CHECK_EQ(error_code, expected_error_code); 40 | if (error_code == 0) { 41 | CHECK_EQ(result, expected_result); 42 | CHECK_EQ(length, expected_length); 43 | } 44 | } 45 | 46 | void CheckWriteValue(uint32_t input, int length, uint8_t* vals) { 47 | const std::vector result = UnsignedLEB128From(input); 48 | CHECK_EQ(result.size(), length); 49 | for (size_t i = 0; i < length; i++) { 50 | CHECK_EQ(result.at(i), vals[i]); 51 | } 52 | } 53 | }; 54 | 55 | TEST_F(EncoderTest, Function_Builder_Variable_Indexing) { 56 | Zone zone; 57 | WasmModuleBuilder* builder = new(&zone) WasmModuleBuilder(&zone); 58 | uint16_t f_index = builder->AddFunction(); 59 | WasmFunctionBuilder* function = builder->FunctionAt(f_index); 60 | uint16_t local_float32 = function->AddLocal(kAstF32); 61 | uint16_t param_float32 = function->AddParam(kAstF32); 62 | uint16_t local_int32 = function->AddLocal(kAstI32); 63 | uint16_t local_float64 = function->AddLocal(kAstF64); 64 | uint16_t local_int64 = function->AddLocal(kAstI64); 65 | uint16_t param_int32 = function->AddParam(kAstI32); 66 | uint16_t local_int32_2 = function->AddLocal(kAstI32); 67 | 68 | byte code[] = {kExprGetLocal, static_cast(param_float32)}; 69 | uint32_t local_indices[] = {1}; 70 | function->EmitCode(code, sizeof(code), local_indices, 1); 71 | code[1] = static_cast(param_int32); 72 | function->EmitCode(code, sizeof(code), local_indices, 1); 73 | code[1] = static_cast(local_int32); 74 | function->EmitCode(code, sizeof(code), local_indices, 1); 75 | code[1] = static_cast(local_int32_2); 76 | function->EmitCode(code, sizeof(code), local_indices, 1); 77 | code[1] = static_cast(local_int64); 78 | function->EmitCode(code, sizeof(code), local_indices, 1); 79 | code[1] = static_cast(local_float32); 80 | function->EmitCode(code, sizeof(code), local_indices, 1); 81 | code[1] = static_cast(local_float64); 82 | function->EmitCode(code, sizeof(code), local_indices, 1); 83 | 84 | WasmFunctionEncoder* f = function->Build(&zone, builder); 85 | ZoneVector buffer_vector(f->HeaderSize() + f->BodySize(), &zone); 86 | byte* buffer = buffer_vector.data(); 87 | byte* header = buffer; 88 | byte* body = buffer + f->HeaderSize(); 89 | f->Serialize(buffer, &header, &body); 90 | for(size_t i = 0; i < 7; i++) { 91 | CHECK_EQ(i, static_cast(*(buffer + 2*i + f->HeaderSize() + 1))); 92 | } 93 | } 94 | 95 | TEST_F(EncoderTest, Function_Builder_Indexing_Variable_Width) { 96 | Zone zone; 97 | WasmModuleBuilder* builder = new(&zone) WasmModuleBuilder(&zone); 98 | uint16_t f_index = builder->AddFunction(); 99 | WasmFunctionBuilder* function = builder->FunctionAt(f_index); 100 | for (size_t i = 0; i < 128; i++) { 101 | AddLocal(function, kAstF32); 102 | } 103 | AddLocal(function, kAstI32); 104 | 105 | WasmFunctionEncoder* f = function->Build(&zone, builder); 106 | ZoneVector buffer_vector(f->HeaderSize() + f->BodySize(), &zone); 107 | byte* buffer = buffer_vector.data(); 108 | byte* header = buffer; 109 | byte* body = buffer + f->HeaderSize(); 110 | f->Serialize(buffer, &header, &body); 111 | body = buffer + f->HeaderSize(); 112 | for(size_t i = 0; i < 127; i++) { 113 | CHECK_EQ(kExprGetLocal, static_cast(*(body + 2*i))); 114 | CHECK_EQ(i+1, static_cast(*(body + 2*i + 1))); 115 | } 116 | CHECK_EQ(kExprGetLocal, static_cast(*(body + 2*127))); 117 | CHECK_EQ(0x80, static_cast(*(body + 2*127 + 1))); 118 | CHECK_EQ(0x01, static_cast(*(body + 2*127 + 2))); 119 | CHECK_EQ(kExprGetLocal, static_cast(*(body + 2*127 + 3))); 120 | CHECK_EQ(0x00, static_cast(*(body + 2*127 + 4))); 121 | } 122 | 123 | TEST_F(EncoderTest, LEB_Functions) { 124 | byte leb_value[5] = {0, 0, 0, 0, 0}; 125 | CheckReadValue(leb_value, 0, 1, kNoError); 126 | CheckWriteValue(0, 1, leb_value); 127 | leb_value[0] = 23; 128 | CheckReadValue(leb_value, 23, 1, kNoError); 129 | CheckWriteValue(23, 1, leb_value); 130 | leb_value[0] = 0x80; 131 | leb_value[1] = 0x01; 132 | CheckReadValue(leb_value, 128, 2, kNoError); 133 | CheckWriteValue(128, 2, leb_value); 134 | leb_value[0] = 0x80; 135 | leb_value[1] = 0x80; 136 | leb_value[2] = 0x80; 137 | leb_value[3] = 0x80; 138 | leb_value[4] = 0x01; 139 | CheckReadValue(leb_value, 0x10000000, 5, kNoError); 140 | CheckWriteValue(0x10000000, 5, leb_value); 141 | leb_value[0] = 0x80; 142 | leb_value[1] = 0x80; 143 | leb_value[2] = 0x80; 144 | leb_value[3] = 0x80; 145 | leb_value[4] = 0x80; 146 | CheckReadValue(leb_value, -1, -1, kInvalidLEB128); 147 | } 148 | 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /test/unittests/wasm/wasm-macro-gen-unittest.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015 the V8 project authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "test/unittests/test-utils.h" 6 | 7 | #include "src/wasm/wasm-macro-gen.h" 8 | 9 | namespace v8 { 10 | namespace internal { 11 | namespace wasm { 12 | 13 | class WasmMacroGenTest : public TestWithZone {}; 14 | 15 | #define EXPECT_SIZE(size, ...) \ 16 | do { \ 17 | byte code[] = {__VA_ARGS__}; \ 18 | EXPECT_EQ(size, sizeof(code)); \ 19 | } while (false) 20 | 21 | 22 | TEST_F(WasmMacroGenTest, Constants) { 23 | EXPECT_SIZE(2, WASM_ONE); 24 | EXPECT_SIZE(2, WASM_ZERO); 25 | 26 | EXPECT_SIZE(2, WASM_I8(122)); 27 | EXPECT_SIZE(2, WASM_I8(254)); 28 | 29 | EXPECT_SIZE(5, WASM_I32(1)); 30 | EXPECT_SIZE(5, WASM_I32(10000)); 31 | EXPECT_SIZE(5, WASM_I32(-9828934)); 32 | 33 | EXPECT_SIZE(9, WASM_I64(1)); 34 | EXPECT_SIZE(9, WASM_I64(10000)); 35 | EXPECT_SIZE(9, WASM_I64(-9828934)); 36 | EXPECT_SIZE(9, WASM_I64(0x123456789abcdef0ULL)); 37 | 38 | EXPECT_SIZE(5, WASM_F32(1.0f)); 39 | EXPECT_SIZE(5, WASM_F32(10000.0f)); 40 | EXPECT_SIZE(5, WASM_F32(-9828934.0f)); 41 | 42 | EXPECT_SIZE(9, WASM_F64(1.5)); 43 | EXPECT_SIZE(9, WASM_F64(10200.0)); 44 | EXPECT_SIZE(9, WASM_F64(-9818934.0)); 45 | } 46 | 47 | 48 | TEST_F(WasmMacroGenTest, Statements) { 49 | EXPECT_SIZE(1, WASM_NOP); 50 | 51 | EXPECT_SIZE(4, WASM_SET_LOCAL(0, WASM_ZERO)); 52 | 53 | EXPECT_SIZE(4, WASM_STORE_GLOBAL(0, WASM_ZERO)); 54 | 55 | EXPECT_SIZE(6, WASM_STORE_MEM(MachineType::Int32(), WASM_ZERO, WASM_ZERO)); 56 | 57 | EXPECT_SIZE(4, WASM_IF(WASM_ZERO, WASM_NOP)); 58 | 59 | EXPECT_SIZE(5, WASM_IF_ELSE(WASM_ZERO, WASM_NOP, WASM_NOP)); 60 | 61 | EXPECT_SIZE(5, WASM_SELECT(WASM_ZERO, WASM_NOP, WASM_NOP)); 62 | 63 | EXPECT_SIZE(3, WASM_BR(0)); 64 | EXPECT_SIZE(5, WASM_BR_IF(0, WASM_ZERO)); 65 | 66 | EXPECT_SIZE(3, WASM_BLOCK(1, WASM_NOP)); 67 | EXPECT_SIZE(4, WASM_BLOCK(2, WASM_NOP, WASM_NOP)); 68 | EXPECT_SIZE(5, WASM_BLOCK(3, WASM_NOP, WASM_NOP, WASM_NOP)); 69 | 70 | EXPECT_SIZE(5, WASM_INFINITE_LOOP); 71 | 72 | EXPECT_SIZE(3, WASM_LOOP(1, WASM_NOP)); 73 | EXPECT_SIZE(4, WASM_LOOP(2, WASM_NOP, WASM_NOP)); 74 | EXPECT_SIZE(5, WASM_LOOP(3, WASM_NOP, WASM_NOP, WASM_NOP)); 75 | EXPECT_SIZE(5, WASM_LOOP(1, WASM_BR(0))); 76 | EXPECT_SIZE(7, WASM_LOOP(1, WASM_BR_IF(0, WASM_ZERO))); 77 | 78 | EXPECT_SIZE(1, WASM_RETURN0); 79 | EXPECT_SIZE(3, WASM_RETURN(WASM_ZERO)); 80 | EXPECT_SIZE(5, WASM_RETURN(WASM_ZERO, WASM_ZERO)); 81 | 82 | EXPECT_SIZE(1, WASM_UNREACHABLE); 83 | } 84 | 85 | 86 | TEST_F(WasmMacroGenTest, MacroStatements) { 87 | EXPECT_SIZE(8, WASM_WHILE(WASM_I8(0), WASM_NOP)); 88 | EXPECT_SIZE(7, WASM_INC_LOCAL(0)); 89 | EXPECT_SIZE(7, WASM_INC_LOCAL_BY(0, 3)); 90 | 91 | EXPECT_SIZE(3, WASM_BREAK(0)); 92 | EXPECT_SIZE(3, WASM_CONTINUE(0)); 93 | } 94 | 95 | 96 | TEST_F(WasmMacroGenTest, TableSwitch) { 97 | EXPECT_SIZE(2, WASM_CASE(9)); 98 | EXPECT_SIZE(2, WASM_CASE_BR(11)); 99 | 100 | EXPECT_SIZE(7, WASM_TABLESWITCH_OP(0, 1, WASM_CASE(7))); 101 | EXPECT_SIZE(9, WASM_TABLESWITCH_OP(0, 2, WASM_CASE(7), WASM_CASE(8))); 102 | 103 | EXPECT_SIZE(4, WASM_TABLESWITCH_BODY(WASM_I8(88), WASM_I8(77))); 104 | EXPECT_SIZE(6, WASM_TABLESWITCH_BODY(WASM_I8(33), WASM_I8(44), WASM_GET_LOCAL(0))); 105 | } 106 | 107 | 108 | TEST_F(WasmMacroGenTest, Expressions) { 109 | EXPECT_SIZE(2, WASM_GET_LOCAL(0)); 110 | EXPECT_SIZE(2, WASM_GET_LOCAL(1)); 111 | EXPECT_SIZE(2, WASM_GET_LOCAL(12)); 112 | EXPECT_SIZE(2, WASM_LOAD_GLOBAL(0)); 113 | EXPECT_SIZE(2, WASM_LOAD_GLOBAL(1)); 114 | EXPECT_SIZE(2, WASM_LOAD_GLOBAL(12)); 115 | EXPECT_SIZE(4, WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO)); 116 | EXPECT_SIZE(4, WASM_LOAD_MEM(MachineType::Float64(), WASM_ZERO)); 117 | EXPECT_SIZE(4, WASM_LOAD_MEM(MachineType::Float32(), WASM_ZERO)); 118 | 119 | EXPECT_SIZE(3, WASM_NOT(WASM_ZERO)); 120 | 121 | EXPECT_SIZE(4, WASM_BRV(1, WASM_ZERO)); 122 | EXPECT_SIZE(6, WASM_BRV_IF(1, WASM_ZERO, WASM_ZERO)); 123 | 124 | EXPECT_SIZE(4, WASM_BLOCK(1, WASM_ZERO)); 125 | EXPECT_SIZE(5, WASM_BLOCK(2, WASM_NOP, WASM_ZERO)); 126 | EXPECT_SIZE(6, WASM_BLOCK(3, WASM_NOP, WASM_NOP, WASM_ZERO)); 127 | 128 | EXPECT_SIZE(4, WASM_LOOP(1, WASM_ZERO)); 129 | EXPECT_SIZE(5, WASM_LOOP(2, WASM_NOP, WASM_ZERO)); 130 | EXPECT_SIZE(6, WASM_LOOP(3, WASM_NOP, WASM_NOP, WASM_ZERO)); 131 | } 132 | 133 | 134 | TEST_F(WasmMacroGenTest, FunctionCalls) { 135 | EXPECT_SIZE(2, WASM_CALL_FUNCTION0(0)); 136 | EXPECT_SIZE(2, WASM_CALL_FUNCTION0(1)); 137 | EXPECT_SIZE(2, WASM_CALL_FUNCTION0(11)); 138 | 139 | EXPECT_SIZE(4, WASM_CALL_FUNCTION(0, WASM_ZERO)); 140 | EXPECT_SIZE(6, WASM_CALL_FUNCTION(1, WASM_ZERO, WASM_ZERO)); 141 | 142 | EXPECT_SIZE(4, WASM_CALL_INDIRECT0(0, WASM_ZERO)); 143 | EXPECT_SIZE(4, WASM_CALL_INDIRECT0(1, WASM_ZERO)); 144 | EXPECT_SIZE(4, WASM_CALL_INDIRECT0(11, WASM_ZERO)); 145 | 146 | EXPECT_SIZE(6, WASM_CALL_INDIRECT(0, WASM_ZERO, WASM_ZERO)); 147 | EXPECT_SIZE(8, WASM_CALL_INDIRECT(1, WASM_ZERO, WASM_ZERO, WASM_ZERO)); 148 | } 149 | 150 | 151 | TEST_F(WasmMacroGenTest, Int32Ops) { 152 | EXPECT_SIZE(5, WASM_I32_ADD(WASM_ZERO, WASM_ZERO)); 153 | EXPECT_SIZE(5, WASM_I32_SUB(WASM_ZERO, WASM_ZERO)); 154 | EXPECT_SIZE(5, WASM_I32_MUL(WASM_ZERO, WASM_ZERO)); 155 | EXPECT_SIZE(5, WASM_I32_DIVS(WASM_ZERO, WASM_ZERO)); 156 | EXPECT_SIZE(5, WASM_I32_DIVU(WASM_ZERO, WASM_ZERO)); 157 | EXPECT_SIZE(5, WASM_I32_REMS(WASM_ZERO, WASM_ZERO)); 158 | EXPECT_SIZE(5, WASM_I32_REMU(WASM_ZERO, WASM_ZERO)); 159 | EXPECT_SIZE(5, WASM_I32_AND(WASM_ZERO, WASM_ZERO)); 160 | EXPECT_SIZE(5, WASM_I32_IOR(WASM_ZERO, WASM_ZERO)); 161 | EXPECT_SIZE(5, WASM_I32_XOR(WASM_ZERO, WASM_ZERO)); 162 | EXPECT_SIZE(5, WASM_I32_SHL(WASM_ZERO, WASM_ZERO)); 163 | EXPECT_SIZE(5, WASM_I32_SHR(WASM_ZERO, WASM_ZERO)); 164 | EXPECT_SIZE(5, WASM_I32_SAR(WASM_ZERO, WASM_ZERO)); 165 | EXPECT_SIZE(5, WASM_I32_EQ(WASM_ZERO, WASM_ZERO)); 166 | 167 | EXPECT_SIZE(5, WASM_I32_LTS(WASM_ZERO, WASM_ZERO)); 168 | EXPECT_SIZE(5, WASM_I32_LES(WASM_ZERO, WASM_ZERO)); 169 | EXPECT_SIZE(5, WASM_I32_LTU(WASM_ZERO, WASM_ZERO)); 170 | EXPECT_SIZE(5, WASM_I32_LEU(WASM_ZERO, WASM_ZERO)); 171 | 172 | EXPECT_SIZE(5, WASM_I32_GTS(WASM_ZERO, WASM_ZERO)); 173 | EXPECT_SIZE(5, WASM_I32_GES(WASM_ZERO, WASM_ZERO)); 174 | EXPECT_SIZE(5, WASM_I32_GTU(WASM_ZERO, WASM_ZERO)); 175 | EXPECT_SIZE(5, WASM_I32_GEU(WASM_ZERO, WASM_ZERO)); 176 | 177 | EXPECT_SIZE(3, WASM_I32_CLZ(WASM_ZERO)); 178 | EXPECT_SIZE(3, WASM_I32_CTZ(WASM_ZERO)); 179 | EXPECT_SIZE(3, WASM_I32_POPCNT(WASM_ZERO)); 180 | } 181 | 182 | 183 | TEST_F(WasmMacroGenTest, Int64Ops) { 184 | EXPECT_SIZE(5, WASM_I64_ADD(WASM_ZERO, WASM_ZERO)); 185 | EXPECT_SIZE(5, WASM_I64_SUB(WASM_ZERO, WASM_ZERO)); 186 | EXPECT_SIZE(5, WASM_I64_MUL(WASM_ZERO, WASM_ZERO)); 187 | EXPECT_SIZE(5, WASM_I64_DIVS(WASM_ZERO, WASM_ZERO)); 188 | EXPECT_SIZE(5, WASM_I64_DIVU(WASM_ZERO, WASM_ZERO)); 189 | EXPECT_SIZE(5, WASM_I64_REMS(WASM_ZERO, WASM_ZERO)); 190 | EXPECT_SIZE(5, WASM_I64_REMU(WASM_ZERO, WASM_ZERO)); 191 | EXPECT_SIZE(5, WASM_I64_AND(WASM_ZERO, WASM_ZERO)); 192 | EXPECT_SIZE(5, WASM_I64_IOR(WASM_ZERO, WASM_ZERO)); 193 | EXPECT_SIZE(5, WASM_I64_XOR(WASM_ZERO, WASM_ZERO)); 194 | EXPECT_SIZE(5, WASM_I64_SHL(WASM_ZERO, WASM_ZERO)); 195 | EXPECT_SIZE(5, WASM_I64_SHR(WASM_ZERO, WASM_ZERO)); 196 | EXPECT_SIZE(5, WASM_I64_SAR(WASM_ZERO, WASM_ZERO)); 197 | EXPECT_SIZE(5, WASM_I64_EQ(WASM_ZERO, WASM_ZERO)); 198 | 199 | EXPECT_SIZE(5, WASM_I64_LTS(WASM_ZERO, WASM_ZERO)); 200 | EXPECT_SIZE(5, WASM_I64_LES(WASM_ZERO, WASM_ZERO)); 201 | EXPECT_SIZE(5, WASM_I64_LTU(WASM_ZERO, WASM_ZERO)); 202 | EXPECT_SIZE(5, WASM_I64_LEU(WASM_ZERO, WASM_ZERO)); 203 | 204 | EXPECT_SIZE(5, WASM_I64_GTS(WASM_ZERO, WASM_ZERO)); 205 | EXPECT_SIZE(5, WASM_I64_GES(WASM_ZERO, WASM_ZERO)); 206 | EXPECT_SIZE(5, WASM_I64_GTU(WASM_ZERO, WASM_ZERO)); 207 | EXPECT_SIZE(5, WASM_I64_GEU(WASM_ZERO, WASM_ZERO)); 208 | 209 | EXPECT_SIZE(3, WASM_I64_CLZ(WASM_ZERO)); 210 | EXPECT_SIZE(3, WASM_I64_CTZ(WASM_ZERO)); 211 | EXPECT_SIZE(3, WASM_I64_POPCNT(WASM_ZERO)); 212 | } 213 | 214 | 215 | TEST_F(WasmMacroGenTest, Float32Ops) { 216 | EXPECT_SIZE(5, WASM_F32_ADD(WASM_ZERO, WASM_ZERO)); 217 | EXPECT_SIZE(5, WASM_F32_SUB(WASM_ZERO, WASM_ZERO)); 218 | EXPECT_SIZE(5, WASM_F32_MUL(WASM_ZERO, WASM_ZERO)); 219 | EXPECT_SIZE(5, WASM_F32_DIV(WASM_ZERO, WASM_ZERO)); 220 | EXPECT_SIZE(5, WASM_F32_MIN(WASM_ZERO, WASM_ZERO)); 221 | EXPECT_SIZE(5, WASM_F32_MAX(WASM_ZERO, WASM_ZERO)); 222 | EXPECT_SIZE(5, WASM_F32_COPYSIGN(WASM_ZERO, WASM_ZERO)); 223 | 224 | EXPECT_SIZE(3, WASM_F32_ABS(WASM_ZERO)); 225 | EXPECT_SIZE(3, WASM_F32_NEG(WASM_ZERO)); 226 | EXPECT_SIZE(3, WASM_F32_CEIL(WASM_ZERO)); 227 | EXPECT_SIZE(3, WASM_F32_FLOOR(WASM_ZERO)); 228 | EXPECT_SIZE(3, WASM_F32_TRUNC(WASM_ZERO)); 229 | EXPECT_SIZE(3, WASM_F32_NEARESTINT(WASM_ZERO)); 230 | EXPECT_SIZE(3, WASM_F32_SQRT(WASM_ZERO)); 231 | 232 | EXPECT_SIZE(5, WASM_F32_EQ(WASM_ZERO, WASM_ZERO)); 233 | EXPECT_SIZE(5, WASM_F32_LT(WASM_ZERO, WASM_ZERO)); 234 | EXPECT_SIZE(5, WASM_F32_LE(WASM_ZERO, WASM_ZERO)); 235 | EXPECT_SIZE(5, WASM_F32_GT(WASM_ZERO, WASM_ZERO)); 236 | EXPECT_SIZE(5, WASM_F32_GE(WASM_ZERO, WASM_ZERO)); 237 | } 238 | 239 | 240 | TEST_F(WasmMacroGenTest, Float64Ops) { 241 | EXPECT_SIZE(5, WASM_F64_ADD(WASM_ZERO, WASM_ZERO)); 242 | EXPECT_SIZE(5, WASM_F64_SUB(WASM_ZERO, WASM_ZERO)); 243 | EXPECT_SIZE(5, WASM_F64_MUL(WASM_ZERO, WASM_ZERO)); 244 | EXPECT_SIZE(5, WASM_F64_DIV(WASM_ZERO, WASM_ZERO)); 245 | EXPECT_SIZE(5, WASM_F64_MIN(WASM_ZERO, WASM_ZERO)); 246 | EXPECT_SIZE(5, WASM_F64_MAX(WASM_ZERO, WASM_ZERO)); 247 | EXPECT_SIZE(5, WASM_F64_COPYSIGN(WASM_ZERO, WASM_ZERO)); 248 | 249 | EXPECT_SIZE(3, WASM_F64_ABS(WASM_ZERO)); 250 | EXPECT_SIZE(3, WASM_F64_NEG(WASM_ZERO)); 251 | EXPECT_SIZE(3, WASM_F64_CEIL(WASM_ZERO)); 252 | EXPECT_SIZE(3, WASM_F64_FLOOR(WASM_ZERO)); 253 | EXPECT_SIZE(3, WASM_F64_TRUNC(WASM_ZERO)); 254 | EXPECT_SIZE(3, WASM_F64_NEARESTINT(WASM_ZERO)); 255 | EXPECT_SIZE(3, WASM_F64_SQRT(WASM_ZERO)); 256 | 257 | EXPECT_SIZE(5, WASM_F64_EQ(WASM_ZERO, WASM_ZERO)); 258 | EXPECT_SIZE(5, WASM_F64_LT(WASM_ZERO, WASM_ZERO)); 259 | EXPECT_SIZE(5, WASM_F64_LE(WASM_ZERO, WASM_ZERO)); 260 | EXPECT_SIZE(5, WASM_F64_GT(WASM_ZERO, WASM_ZERO)); 261 | EXPECT_SIZE(5, WASM_F64_GE(WASM_ZERO, WASM_ZERO)); 262 | } 263 | 264 | 265 | TEST_F(WasmMacroGenTest, Conversions) { 266 | EXPECT_SIZE(3, WASM_I32_SCONVERT_F32(WASM_ZERO)); 267 | EXPECT_SIZE(3, WASM_I32_SCONVERT_F64(WASM_ZERO)); 268 | EXPECT_SIZE(3, WASM_I32_UCONVERT_F32(WASM_ZERO)); 269 | EXPECT_SIZE(3, WASM_I32_UCONVERT_F64(WASM_ZERO)); 270 | EXPECT_SIZE(3, WASM_I32_CONVERT_I64(WASM_ZERO)); 271 | EXPECT_SIZE(3, WASM_I64_SCONVERT_F32(WASM_ZERO)); 272 | EXPECT_SIZE(3, WASM_I64_SCONVERT_F64(WASM_ZERO)); 273 | EXPECT_SIZE(3, WASM_I64_UCONVERT_F32(WASM_ZERO)); 274 | EXPECT_SIZE(3, WASM_I64_UCONVERT_F64(WASM_ZERO)); 275 | EXPECT_SIZE(3, WASM_I64_SCONVERT_I32(WASM_ZERO)); 276 | EXPECT_SIZE(3, WASM_I64_UCONVERT_I32(WASM_ZERO)); 277 | EXPECT_SIZE(3, WASM_F32_SCONVERT_I32(WASM_ZERO)); 278 | EXPECT_SIZE(3, WASM_F32_UCONVERT_I32(WASM_ZERO)); 279 | EXPECT_SIZE(3, WASM_F32_SCONVERT_I64(WASM_ZERO)); 280 | EXPECT_SIZE(3, WASM_F32_UCONVERT_I64(WASM_ZERO)); 281 | EXPECT_SIZE(3, WASM_F32_CONVERT_F64(WASM_ZERO)); 282 | EXPECT_SIZE(3, WASM_F32_REINTERPRET_I32(WASM_ZERO)); 283 | EXPECT_SIZE(3, WASM_F64_SCONVERT_I32(WASM_ZERO)); 284 | EXPECT_SIZE(3, WASM_F64_UCONVERT_I32(WASM_ZERO)); 285 | EXPECT_SIZE(3, WASM_F64_SCONVERT_I64(WASM_ZERO)); 286 | EXPECT_SIZE(3, WASM_F64_UCONVERT_I64(WASM_ZERO)); 287 | EXPECT_SIZE(3, WASM_F64_CONVERT_F32(WASM_ZERO)); 288 | EXPECT_SIZE(3, WASM_F64_REINTERPRET_I64(WASM_ZERO)); 289 | } 290 | 291 | static const MachineType kMemTypes[] = { 292 | MachineType::Int8(), MachineType::Uint8(), MachineType::Int16(), 293 | MachineType::Uint16(), MachineType::Int32(), MachineType::Uint32(), 294 | MachineType::Int64(), MachineType::Uint64(), MachineType::Float32(), 295 | MachineType::Float64()}; 296 | 297 | TEST_F(WasmMacroGenTest, LoadsAndStores) { 298 | for (size_t i = 0; i < arraysize(kMemTypes); i++) { 299 | EXPECT_SIZE(4, WASM_LOAD_MEM(kMemTypes[i], WASM_ZERO)); 300 | } 301 | for (size_t i = 0; i < arraysize(kMemTypes); i++) { 302 | EXPECT_SIZE(6, WASM_STORE_MEM(kMemTypes[i], WASM_ZERO, WASM_GET_LOCAL(0))); 303 | } 304 | } 305 | 306 | 307 | TEST_F(WasmMacroGenTest, LoadsAndStoresWithOffset) { 308 | for (size_t i = 0; i < arraysize(kMemTypes); i++) { 309 | EXPECT_SIZE(5, WASM_LOAD_MEM_OFFSET(kMemTypes[i], 11, WASM_ZERO)); 310 | } 311 | for (size_t i = 0; i < arraysize(kMemTypes); i++) { 312 | EXPECT_SIZE(7, WASM_STORE_MEM_OFFSET(kMemTypes[i], 13, WASM_ZERO, WASM_GET_LOCAL(0))); 313 | } 314 | } 315 | } 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /test/unittests/wasm/wasm.gyp: -------------------------------------------------------------------------------- 1 | # Copyright 2015 the V8 project authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style license that can be 3 | # found in the LICENSE file. 4 | 5 | { 6 | 'targets': [ 7 | { 8 | 'target_name': 'wasm_unittests', 9 | 'type': 'none', 10 | # A list of additional sources and options to be injected into: 11 | # test/unittests/unittests.gyp:unittests 12 | 'direct_dependent_settings': { 13 | 'include_dirs': ['../../..'], 14 | 'sources': [ 15 | 'ast-decoder-unittest.cc', 16 | 'wasm-macro-gen-unittest.cc', 17 | 'module-decoder-unittest.cc', 18 | 'encoder-unittest.cc', 19 | ], 20 | }, 21 | }, 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /travis/build-and-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | 6 | # Move to a location relative to the script so it runs 7 | # from anywhere. 8 | cd $(dirname ${BASH_SOURCE[0]})/.. 9 | 10 | cd v8/v8 11 | 12 | echo "==== BUILDING V8 ====" 13 | make x64.optdebug wasm=on werror=no 14 | 15 | echo "==== unittests ====" 16 | ./out/x64.optdebug/unittests "--gtest_filter=Wasm*" 17 | 18 | echo "==== cctest/test-run-wasm* ====" 19 | ./tools/run-tests.py \ 20 | --no-presubmit --mode optdebug --arch x64 cctest/test-run-wasm* 21 | 22 | echo "==== mjsunit/wasm/* ====" 23 | ./tools/run-tests.py \ 24 | --no-presubmit --mode optdebug --arch x64 mjsunit/wasm/* 25 | -------------------------------------------------------------------------------- /travis/install-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | 6 | # Move to a location relative to the script so it runs 7 | # from anywhere. 8 | cd $(dirname ${BASH_SOURCE[0]})/.. 9 | 10 | if [[ ! -d depot_tools ]]; then 11 | echo "Cloning depot_tools" 12 | git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git 13 | fi 14 | 15 | export PATH=$PWD/depot_tools:$PATH 16 | 17 | if [[ ! -d v8 ]]; then 18 | echo "Fetching v8" 19 | mkdir v8 20 | cd v8 21 | fetch v8 22 | ln -fs $PWD/.. v8/third_party/wasm 23 | cd .. 24 | fi 25 | 26 | if [[ ! -d v8/v8/test/mjsunit/wasm ]]; then 27 | ln -fs $PWD/test/mjsunit/wasm v8/v8/test/mjsunit/wasm 28 | fi 29 | 30 | cd v8 31 | gclient update 32 | cd .. 33 | --------------------------------------------------------------------------------