blob: 4e5aa7848605cddd3c8597434a9b97fab9174688 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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 "src/wasm/wasm-opcodes.h"
9#include "src/wasm/wasm-result.h"
10
11#include "src/api.h"
12#include "src/handles.h"
13
14namespace v8 {
15namespace internal {
16
17namespace compiler {
18class CallDescriptor;
19}
20
21namespace wasm {
22const size_t kMaxModuleSize = 1024 * 1024 * 1024;
23const size_t kMaxFunctionSize = 128 * 1024;
24const size_t kMaxStringSize = 256;
Ben Murdochda12d292016-06-02 14:46:10 +010025const uint32_t kWasmMagic = 0x6d736100;
26const uint32_t kWasmVersion = 0x0a;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000027
Ben Murdochda12d292016-06-02 14:46:10 +010028// WebAssembly sections are named as strings in the binary format, but
29// internally V8 uses an enum to handle them.
30//
31// Entries have the form F(enumerator, string).
32#define FOR_EACH_WASM_SECTION_TYPE(F) \
33 F(Memory, "memory") \
34 F(Signatures, "signatures") \
35 F(Functions, "functions") \
36 F(Globals, "globals") \
37 F(DataSegments, "data_segments") \
38 F(FunctionTable, "function_table") \
39 F(End, "end") \
40 F(StartFunction, "start_function") \
41 F(ImportTable, "import_table") \
42 F(ExportTable, "export_table") \
43 F(FunctionSignatures, "function_signatures") \
44 F(FunctionBodies, "function_bodies") \
45 F(Names, "names")
46
47// Contants for the above section types: {LEB128 length, characters...}.
48#define WASM_SECTION_MEMORY 6, 'm', 'e', 'm', 'o', 'r', 'y'
49#define WASM_SECTION_SIGNATURES \
50 10, 's', 'i', 'g', 'n', 'a', 't', 'u', 'r', 'e', 's'
51#define WASM_SECTION_FUNCTIONS 9, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', 's'
52#define WASM_SECTION_GLOBALS 7, 'g', 'l', 'o', 'b', 'a', 'l', 's'
53#define WASM_SECTION_DATA_SEGMENTS \
54 13, 'd', 'a', 't', 'a', '_', 's', 'e', 'g', 'm', 'e', 'n', 't', 's'
55#define WASM_SECTION_FUNCTION_TABLE \
56 14, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', '_', 't', 'a', 'b', 'l', 'e'
57#define WASM_SECTION_END 3, 'e', 'n', 'd'
58#define WASM_SECTION_START_FUNCTION \
59 14, 's', 't', 'a', 'r', 't', '_', 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n'
60#define WASM_SECTION_IMPORT_TABLE \
61 12, 'i', 'm', 'p', 'o', 'r', 't', '_', 't', 'a', 'b', 'l', 'e'
62#define WASM_SECTION_EXPORT_TABLE \
63 12, 'e', 'x', 'p', 'o', 'r', 't', '_', 't', 'a', 'b', 'l', 'e'
64#define WASM_SECTION_FUNCTION_SIGNATURES \
65 19, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', '_', 's', 'i', 'g', 'n', 'a', \
66 't', 'u', 'r', 'e', 's'
67#define WASM_SECTION_FUNCTION_BODIES \
68 15, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', '_', 'b', 'o', 'd', 'i', 'e', 's'
69#define WASM_SECTION_NAMES 5, 'n', 'a', 'm', 'e', 's'
70
71// Constants for the above section headers' size (LEB128 + characters).
72#define WASM_SECTION_MEMORY_SIZE ((size_t)7)
73#define WASM_SECTION_SIGNATURES_SIZE ((size_t)11)
74#define WASM_SECTION_FUNCTIONS_SIZE ((size_t)10)
75#define WASM_SECTION_GLOBALS_SIZE ((size_t)8)
76#define WASM_SECTION_DATA_SEGMENTS_SIZE ((size_t)14)
77#define WASM_SECTION_FUNCTION_TABLE_SIZE ((size_t)15)
78#define WASM_SECTION_END_SIZE ((size_t)4)
79#define WASM_SECTION_START_FUNCTION_SIZE ((size_t)15)
80#define WASM_SECTION_IMPORT_TABLE_SIZE ((size_t)13)
81#define WASM_SECTION_EXPORT_TABLE_SIZE ((size_t)13)
82#define WASM_SECTION_FUNCTION_SIGNATURES_SIZE ((size_t)20)
83#define WASM_SECTION_FUNCTION_BODIES_SIZE ((size_t)16)
84#define WASM_SECTION_NAMES_SIZE ((size_t)6)
85
86struct WasmSection {
87 enum class Code : uint32_t {
88#define F(enumerator, string) enumerator,
89 FOR_EACH_WASM_SECTION_TYPE(F)
90#undef F
91 Max
92 };
93 static WasmSection::Code begin();
94 static WasmSection::Code end();
95 static WasmSection::Code next(WasmSection::Code code);
96 static const char* getName(Code code);
97 static size_t getNameLength(Code code);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000098};
99
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000100enum WasmFunctionDeclBit {
101 kDeclFunctionName = 0x01,
102 kDeclFunctionImport = 0x02,
103 kDeclFunctionLocals = 0x04,
104 kDeclFunctionExport = 0x08
105};
106
107// Constants for fixed-size elements within a module.
108static const size_t kDeclMemorySize = 3;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109static const size_t kDeclDataSegmentSize = 13;
110
Ben Murdoch097c5b22016-05-18 11:27:45 +0100111// Static representation of a WASM function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112struct WasmFunction {
113 FunctionSig* sig; // signature of the function.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100114 uint32_t func_index; // index into the function table.
Ben Murdochda12d292016-06-02 14:46:10 +0100115 uint32_t sig_index; // index into the signature table.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000116 uint32_t name_offset; // offset in the module bytes of the name, if any.
Ben Murdochda12d292016-06-02 14:46:10 +0100117 uint32_t name_length; // length in bytes of the name.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118 uint32_t code_start_offset; // offset in the module bytes of code start.
119 uint32_t code_end_offset; // offset in the module bytes of code end.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100120 uint16_t local_i32_count; // number of i32 local variables.
121 uint16_t local_i64_count; // number of i64 local variables.
122 uint16_t local_f32_count; // number of f32 local variables.
123 uint16_t local_f64_count; // number of f64 local variables.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124 bool exported; // true if this function is exported.
125 bool external; // true if this function is externally supplied.
126};
127
Ben Murdoch097c5b22016-05-18 11:27:45 +0100128// Static representation of an imported WASM function.
129struct WasmImport {
130 FunctionSig* sig; // signature of the function.
Ben Murdochda12d292016-06-02 14:46:10 +0100131 uint32_t sig_index; // index into the signature table.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100132 uint32_t module_name_offset; // offset in module bytes of the module name.
Ben Murdochda12d292016-06-02 14:46:10 +0100133 uint32_t module_name_length; // length in bytes of the module name.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100134 uint32_t function_name_offset; // offset in module bytes of the import name.
Ben Murdochda12d292016-06-02 14:46:10 +0100135 uint32_t function_name_length; // length in bytes of the import name.
136};
137
138// Static representation of an exported WASM function.
139struct WasmExport {
140 uint32_t func_index; // index into the function table.
141 uint32_t name_offset; // offset in module bytes of the name to export.
142 uint32_t name_length; // length in bytes of the exported name.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100143};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144
145// Static representation of a wasm global variable.
146struct WasmGlobal {
147 uint32_t name_offset; // offset in the module bytes of the name, if any.
Ben Murdochda12d292016-06-02 14:46:10 +0100148 uint32_t name_length; // length in bytes of the global name.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 MachineType type; // type of the global.
150 uint32_t offset; // offset from beginning of globals area.
151 bool exported; // true if this global is exported.
152};
153
154// Static representation of a wasm data segment.
155struct WasmDataSegment {
156 uint32_t dest_addr; // destination memory address of the data.
157 uint32_t source_offset; // start offset in the module bytes.
158 uint32_t source_size; // end offset in the module bytes.
159 bool init; // true if loaded upon instantiation.
160};
161
Ben Murdochda12d292016-06-02 14:46:10 +0100162enum ModuleOrigin { kWasmOrigin, kAsmJsOrigin };
163
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000164// Static representation of a module.
165struct WasmModule {
Ben Murdochda12d292016-06-02 14:46:10 +0100166 static const uint32_t kPageSize = 0x10000; // Page size, 64kb.
167 static const uint32_t kMinMemPages = 1; // Minimum memory size = 64kb
168 static const uint32_t kMaxMemPages = 16384; // Maximum memory size = 1gb
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000169
170 Isolate* shared_isolate; // isolate for storing shared code.
171 const byte* module_start; // starting address for the module bytes.
172 const byte* module_end; // end address for the module bytes.
Ben Murdochda12d292016-06-02 14:46:10 +0100173 uint32_t min_mem_pages; // minimum size of the memory in 64k pages.
174 uint32_t max_mem_pages; // maximum size of the memory in 64k pages.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000175 bool mem_export; // true if the memory is exported.
176 bool mem_external; // true if the memory is external.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100177 int start_function_index; // start function, if any.
Ben Murdochda12d292016-06-02 14:46:10 +0100178 ModuleOrigin origin; // origin of the module
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179
Ben Murdochda12d292016-06-02 14:46:10 +0100180 std::vector<WasmGlobal> globals; // globals in this module.
181 std::vector<FunctionSig*> signatures; // signatures in this module.
182 std::vector<WasmFunction> functions; // functions in this module.
183 std::vector<WasmDataSegment> data_segments; // data segments in this module.
184 std::vector<uint16_t> function_table; // function table.
185 std::vector<WasmImport> import_table; // import table.
186 std::vector<WasmExport> export_table; // export table.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000187
188 WasmModule();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000189
Ben Murdochda12d292016-06-02 14:46:10 +0100190 // Get a string stored in the module bytes representing a name.
191 WasmName GetName(uint32_t offset, uint32_t length) const {
192 if (length == 0) return {"<?>", 3}; // no name.
193 CHECK(BoundsCheck(offset, offset + length));
194 return {reinterpret_cast<const char*>(module_start + offset), length};
195 }
196
197 // Get a string stored in the module bytes representing a name.
198 WasmName GetNameOrNull(uint32_t offset, uint32_t length) const {
199 if (length == 0) return {NULL, 0}; // no name.
200 CHECK(BoundsCheck(offset, offset + length));
201 return {reinterpret_cast<const char*>(module_start + offset), length};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000202 }
203
204 // Checks the given offset range is contained within the module bytes.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100205 bool BoundsCheck(uint32_t start, uint32_t end) const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000206 size_t size = module_end - module_start;
207 return start < size && end < size;
208 }
209
210 // Creates a new instantiation of the module in the given isolate.
211 MaybeHandle<JSObject> Instantiate(Isolate* isolate, Handle<JSObject> ffi,
212 Handle<JSArrayBuffer> memory);
213};
214
Ben Murdoch097c5b22016-05-18 11:27:45 +0100215// An instantiated WASM module, including memory, function table, etc.
216struct WasmModuleInstance {
217 WasmModule* module; // static representation of the module.
218 // -- Heap allocated --------------------------------------------------------
219 Handle<JSObject> js_object; // JavaScript module object.
220 Handle<Context> context; // JavaScript native context.
221 Handle<JSArrayBuffer> mem_buffer; // Handle to array buffer of memory.
222 Handle<JSArrayBuffer> globals_buffer; // Handle to array buffer of globals.
223 Handle<FixedArray> function_table; // indirect function table.
Ben Murdochda12d292016-06-02 14:46:10 +0100224 std::vector<Handle<Code>> function_code; // code objects for each function.
225 std::vector<Handle<Code>> import_code; // code objects for each import.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100226 // -- raw memory ------------------------------------------------------------
227 byte* mem_start; // start of linear memory.
228 size_t mem_size; // size of the linear memory.
229 // -- raw globals -----------------------------------------------------------
230 byte* globals_start; // start of the globals area.
231 size_t globals_size; // size of the globals area.
232
233 explicit WasmModuleInstance(WasmModule* m)
234 : module(m),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100235 mem_start(nullptr),
236 mem_size(0),
237 globals_start(nullptr),
238 globals_size(0) {}
239};
240
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241// forward declaration.
242class WasmLinker;
243
244// Interface provided to the decoder/graph builder which contains only
245// minimal information about the globals, functions, and function tables.
246struct ModuleEnv {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 WasmModule* module;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100248 WasmModuleInstance* instance;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249 WasmLinker* linker;
Ben Murdochda12d292016-06-02 14:46:10 +0100250 ModuleOrigin origin;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251
252 bool IsValidGlobal(uint32_t index) {
Ben Murdochda12d292016-06-02 14:46:10 +0100253 return module && index < module->globals.size();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 }
255 bool IsValidFunction(uint32_t index) {
Ben Murdochda12d292016-06-02 14:46:10 +0100256 return module && index < module->functions.size();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000257 }
258 bool IsValidSignature(uint32_t index) {
Ben Murdochda12d292016-06-02 14:46:10 +0100259 return module && index < module->signatures.size();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100261 bool IsValidImport(uint32_t index) {
Ben Murdochda12d292016-06-02 14:46:10 +0100262 return module && index < module->import_table.size();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100263 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264 MachineType GetGlobalType(uint32_t index) {
265 DCHECK(IsValidGlobal(index));
Ben Murdochda12d292016-06-02 14:46:10 +0100266 return module->globals[index].type;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267 }
268 FunctionSig* GetFunctionSignature(uint32_t index) {
269 DCHECK(IsValidFunction(index));
Ben Murdochda12d292016-06-02 14:46:10 +0100270 return module->functions[index].sig;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000271 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100272 FunctionSig* GetImportSignature(uint32_t index) {
273 DCHECK(IsValidImport(index));
Ben Murdochda12d292016-06-02 14:46:10 +0100274 return module->import_table[index].sig;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100275 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276 FunctionSig* GetSignature(uint32_t index) {
277 DCHECK(IsValidSignature(index));
Ben Murdochda12d292016-06-02 14:46:10 +0100278 return module->signatures[index];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000279 }
280 size_t FunctionTableSize() {
Ben Murdochda12d292016-06-02 14:46:10 +0100281 return module ? module->function_table.size() : 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 }
283
Ben Murdochda12d292016-06-02 14:46:10 +0100284 bool asm_js() { return origin == kAsmJsOrigin; }
285
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000286 Handle<Code> GetFunctionCode(uint32_t index);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100287 Handle<Code> GetImportCode(uint32_t index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 Handle<FixedArray> GetFunctionTable();
289
Ben Murdoch097c5b22016-05-18 11:27:45 +0100290 static compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone,
291 FunctionSig* sig);
292 static compiler::CallDescriptor* GetI32WasmCallDescriptor(
293 Zone* zone, compiler::CallDescriptor* descriptor);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294 compiler::CallDescriptor* GetCallDescriptor(Zone* zone, uint32_t index);
295};
296
Ben Murdoch097c5b22016-05-18 11:27:45 +0100297// A helper for printing out the names of functions.
298struct WasmFunctionName {
299 const WasmFunction* function_;
300 const WasmModule* module_;
301 WasmFunctionName(const WasmFunction* function, const ModuleEnv* menv)
302 : function_(function), module_(menv ? menv->module : nullptr) {}
303};
304
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000305std::ostream& operator<<(std::ostream& os, const WasmModule& module);
306std::ostream& operator<<(std::ostream& os, const WasmFunction& function);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100307std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000308
309typedef Result<WasmModule*> ModuleResult;
310typedef Result<WasmFunction*> FunctionResult;
311
312// For testing. Decode, verify, and run the last exported function in the
313// given encoded module.
314int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
315 const byte* module_end, bool asm_js = false);
316
317// For testing. Decode, verify, and run the last exported function in the
318// given decoded module.
319int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100320
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321} // namespace wasm
322} // namespace internal
323} // namespace v8
324
325#endif // V8_WASM_MODULE_H_