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 <memory>
9 
10 #include "src/api.h"
11 #include "src/globals.h"
12 #include "src/handles.h"
13 #include "src/parsing/preparse-data.h"
14 
15 #include "src/wasm/managed.h"
16 #include "src/wasm/signature-map.h"
17 #include "src/wasm/wasm-opcodes.h"
18 
19 namespace v8 {
20 namespace internal {
21 
22 class WasmCompiledModule;
23 class WasmDebugInfo;
24 class WasmModuleObject;
25 
26 namespace compiler {
27 class CallDescriptor;
28 class WasmCompilationUnit;
29 }
30 
31 namespace wasm {
32 class ErrorThrower;
33 
34 const size_t kMaxModuleSize = 1024 * 1024 * 1024;
35 const size_t kMaxFunctionSize = 128 * 1024;
36 const size_t kMaxStringSize = 256;
37 const uint32_t kWasmMagic = 0x6d736100;
38 const uint32_t kWasmVersion = 0x0d;
39 
40 const uint8_t kWasmFunctionTypeForm = 0x60;
41 const uint8_t kWasmAnyFunctionTypeForm = 0x70;
42 
43 enum WasmSectionCode {
44   kUnknownSectionCode = 0,   // code for unknown sections
45   kTypeSectionCode = 1,      // Function signature declarations
46   kImportSectionCode = 2,    // Import declarations
47   kFunctionSectionCode = 3,  // Function declarations
48   kTableSectionCode = 4,     // Indirect function table and other tables
49   kMemorySectionCode = 5,    // Memory attributes
50   kGlobalSectionCode = 6,    // Global declarations
51   kExportSectionCode = 7,    // Exports
52   kStartSectionCode = 8,     // Start function declaration
53   kElementSectionCode = 9,   // Elements section
54   kCodeSectionCode = 10,     // Function code
55   kDataSectionCode = 11,     // Data segments
56   kNameSectionCode = 12,     // Name section (encoded as a string)
57 };
58 
IsValidSectionCode(uint8_t byte)59 inline bool IsValidSectionCode(uint8_t byte) {
60   return kTypeSectionCode <= byte && byte <= kDataSectionCode;
61 }
62 
63 const char* SectionName(WasmSectionCode code);
64 
65 // Constants for fixed-size elements within a module.
66 static const uint32_t kMaxReturnCount = 1;
67 static const uint8_t kResizableMaximumFlag = 1;
68 static const int32_t kInvalidFunctionIndex = -1;
69 
70 enum WasmExternalKind {
71   kExternalFunction = 0,
72   kExternalTable = 1,
73   kExternalMemory = 2,
74   kExternalGlobal = 3
75 };
76 
77 // Representation of an initializer expression.
78 struct WasmInitExpr {
79   enum WasmInitKind {
80     kNone,
81     kGlobalIndex,
82     kI32Const,
83     kI64Const,
84     kF32Const,
85     kF64Const
86   } kind;
87 
88   union {
89     int32_t i32_const;
90     int64_t i64_const;
91     float f32_const;
92     double f64_const;
93     uint32_t global_index;
94   } val;
95 
WasmInitExprWasmInitExpr96   WasmInitExpr() : kind(kNone) {}
WasmInitExprWasmInitExpr97   explicit WasmInitExpr(int32_t v) : kind(kI32Const) { val.i32_const = v; }
WasmInitExprWasmInitExpr98   explicit WasmInitExpr(int64_t v) : kind(kI64Const) { val.i64_const = v; }
WasmInitExprWasmInitExpr99   explicit WasmInitExpr(float v) : kind(kF32Const) { val.f32_const = v; }
WasmInitExprWasmInitExpr100   explicit WasmInitExpr(double v) : kind(kF64Const) { val.f64_const = v; }
WasmInitExprWasmInitExpr101   WasmInitExpr(WasmInitKind kind, uint32_t global_index) : kind(kGlobalIndex) {
102     val.global_index = global_index;
103   }
104 };
105 
106 // Static representation of a WASM function.
107 struct WasmFunction {
108   FunctionSig* sig;      // signature of the function.
109   uint32_t func_index;   // index into the function table.
110   uint32_t sig_index;    // index into the signature table.
111   uint32_t name_offset;  // offset in the module bytes of the name, if any.
112   uint32_t name_length;  // length in bytes of the name.
113   uint32_t code_start_offset;    // offset in the module bytes of code start.
114   uint32_t code_end_offset;      // offset in the module bytes of code end.
115   bool imported;
116   bool exported;
117 };
118 
119 // Static representation of a wasm global variable.
120 struct WasmGlobal {
121   LocalType type;        // type of the global.
122   bool mutability;       // {true} if mutable.
123   WasmInitExpr init;     // the initialization expression of the global.
124   uint32_t offset;       // offset into global memory.
125   bool imported;         // true if imported.
126   bool exported;         // true if exported.
127 };
128 
129 // Static representation of a wasm data segment.
130 struct WasmDataSegment {
131   WasmInitExpr dest_addr;  // destination memory address of the data.
132   uint32_t source_offset;  // start offset in the module bytes.
133   uint32_t source_size;    // end offset in the module bytes.
134 };
135 
136 // Static representation of a wasm indirect call table.
137 struct WasmIndirectFunctionTable {
138   uint32_t min_size;            // minimum table size.
139   uint32_t max_size;            // maximum table size.
140   bool has_max;                 // true if there is a maximum size.
141   // TODO(titzer): Move this to WasmInstance. Needed by interpreter only.
142   std::vector<int32_t> values;  // function table, -1 indicating invalid.
143   bool imported;                // true if imported.
144   bool exported;                // true if exported.
145   SignatureMap map;             // canonicalizing map for sig indexes.
146 };
147 
148 // Static representation of how to initialize a table.
149 struct WasmTableInit {
150   uint32_t table_index;
151   WasmInitExpr offset;
152   std::vector<uint32_t> entries;
153 };
154 
155 // Static representation of a WASM import.
156 struct WasmImport {
157   uint32_t module_name_length;  // length in bytes of the module name.
158   uint32_t module_name_offset;  // offset in module bytes of the module name.
159   uint32_t field_name_length;   // length in bytes of the import name.
160   uint32_t field_name_offset;   // offset in module bytes of the import name.
161   WasmExternalKind kind;        // kind of the import.
162   uint32_t index;               // index into the respective space.
163 };
164 
165 // Static representation of a WASM export.
166 struct WasmExport {
167   uint32_t name_length;   // length in bytes of the exported name.
168   uint32_t name_offset;   // offset in module bytes of the name to export.
169   WasmExternalKind kind;  // kind of the export.
170   uint32_t index;         // index into the respective space.
171 };
172 
173 enum ModuleOrigin { kWasmOrigin, kAsmJsOrigin };
174 
175 // Static representation of a module.
176 struct V8_EXPORT_PRIVATE WasmModule {
177   static const uint32_t kPageSize = 0x10000;    // Page size, 64kb.
178   static const uint32_t kMinMemPages = 1;       // Minimum memory size = 64kb
179   static const size_t kV8MaxPages = 16384;      // Maximum memory size = 1gb
180   static const size_t kSpecMaxPages = 65536;    // Maximum according to the spec
181   static const size_t kV8MaxTableSize = 16 * 1024 * 1024;
182 
183   Zone* owned_zone;
184   const byte* module_start = nullptr;  // starting address for the module bytes
185   const byte* module_end = nullptr;    // end address for the module bytes
186   uint32_t min_mem_pages = 0;  // minimum size of the memory in 64k pages
187   uint32_t max_mem_pages = 0;  // maximum size of the memory in 64k pages
188   bool has_memory = false;     // true if the memory was defined or imported
189   bool mem_export = false;     // true if the memory is exported
190   // TODO(wasm): reconcile start function index being an int with
191   // the fact that we index on uint32_t, so we may technically not be
192   // able to represent some start_function_index -es.
193   int start_function_index = -1;      // start function, if any
194   ModuleOrigin origin = kWasmOrigin;  // origin of the module
195 
196   std::vector<WasmGlobal> globals;             // globals in this module.
197   uint32_t globals_size = 0;                   // size of globals table.
198   uint32_t num_imported_functions = 0;         // number of imported functions.
199   uint32_t num_declared_functions = 0;         // number of declared functions.
200   uint32_t num_exported_functions = 0;         // number of exported functions.
201   std::vector<FunctionSig*> signatures;        // signatures in this module.
202   std::vector<WasmFunction> functions;         // functions in this module.
203   std::vector<WasmDataSegment> data_segments;  // data segments in this module.
204   std::vector<WasmIndirectFunctionTable> function_tables;  // function tables.
205   std::vector<WasmImport> import_table;        // import table.
206   std::vector<WasmExport> export_table;        // export table.
207   std::vector<WasmTableInit> table_inits;      // initializations of tables
208   // We store the semaphore here to extend its lifetime. In <libc-2.21, which we
209   // use on the try bots, semaphore::Wait() can return while some compilation
210   // tasks are still executing semaphore::Signal(). If the semaphore is cleaned
211   // up right after semaphore::Wait() returns, then this can cause an
212   // invalid-semaphore error in the compilation tasks.
213   // TODO(wasm): Move this semaphore back to CompileInParallel when the try bots
214   // switch to libc-2.21 or higher.
215   std::unique_ptr<base::Semaphore> pending_tasks;
216 
WasmModuleWasmModule217   WasmModule() : WasmModule(nullptr, nullptr) {}
218   WasmModule(Zone* owned_zone, const byte* module_start);
~WasmModuleWasmModule219   ~WasmModule() {
220     if (owned_zone) delete owned_zone;
221   }
222 
223   // Get a string stored in the module bytes representing a name.
GetNameWasmModule224   WasmName GetName(uint32_t offset, uint32_t length) const {
225     if (length == 0) return {"<?>", 3};  // no name.
226     CHECK(BoundsCheck(offset, offset + length));
227     DCHECK_GE(static_cast<int>(length), 0);
228     return {reinterpret_cast<const char*>(module_start + offset),
229             static_cast<int>(length)};
230   }
231 
232   // Get a string stored in the module bytes representing a function name.
GetNameWasmModule233   WasmName GetName(WasmFunction* function) const {
234     return GetName(function->name_offset, function->name_length);
235   }
236 
237   // Get a string stored in the module bytes representing a name.
GetNameOrNullWasmModule238   WasmName GetNameOrNull(uint32_t offset, uint32_t length) const {
239     if (offset == 0 && length == 0) return {NULL, 0};  // no name.
240     CHECK(BoundsCheck(offset, offset + length));
241     DCHECK_GE(static_cast<int>(length), 0);
242     return {reinterpret_cast<const char*>(module_start + offset),
243             static_cast<int>(length)};
244   }
245 
246   // Get a string stored in the module bytes representing a function name.
GetNameOrNullWasmModule247   WasmName GetNameOrNull(const WasmFunction* function) const {
248     return GetNameOrNull(function->name_offset, function->name_length);
249   }
250 
251   // Checks the given offset range is contained within the module bytes.
BoundsCheckWasmModule252   bool BoundsCheck(uint32_t start, uint32_t end) const {
253     size_t size = module_end - module_start;
254     return start <= size && end <= size;
255   }
256 
257   // Creates a new instantiation of the module in the given isolate.
258   static MaybeHandle<JSObject> Instantiate(Isolate* isolate,
259                                            ErrorThrower* thrower,
260                                            Handle<JSObject> wasm_module,
261                                            Handle<JSReceiver> ffi,
262                                            Handle<JSArrayBuffer> memory);
263 
264   MaybeHandle<WasmCompiledModule> CompileFunctions(
265       Isolate* isolate, Handle<Managed<WasmModule>> module_wrapper,
266       ErrorThrower* thrower) const;
267 };
268 
269 typedef Managed<WasmModule> WasmModuleWrapper;
270 
271 // An instantiated WASM module, including memory, function table, etc.
272 struct WasmInstance {
273   const WasmModule* module;  // static representation of the module.
274   // -- Heap allocated --------------------------------------------------------
275   Handle<JSObject> js_object;            // JavaScript module object.
276   Handle<Context> context;               // JavaScript native context.
277   Handle<JSArrayBuffer> mem_buffer;      // Handle to array buffer of memory.
278   Handle<JSArrayBuffer> globals_buffer;  // Handle to array buffer of globals.
279   std::vector<Handle<FixedArray>> function_tables;  // indirect function tables.
280   std::vector<Handle<Code>> function_code;  // code objects for each function.
281   // -- raw memory ------------------------------------------------------------
282   byte* mem_start = nullptr;  // start of linear memory.
283   uint32_t mem_size = 0;      // size of the linear memory.
284   // -- raw globals -----------------------------------------------------------
285   byte* globals_start = nullptr;  // start of the globals area.
286 
WasmInstanceWasmInstance287   explicit WasmInstance(const WasmModule* m)
288       : module(m),
289         function_tables(m->function_tables.size()),
290         function_code(m->functions.size()) {}
291 };
292 
293 // Interface provided to the decoder/graph builder which contains only
294 // minimal information about the globals, functions, and function tables.
295 struct V8_EXPORT_PRIVATE ModuleEnv {
296   const WasmModule* module;
297   WasmInstance* instance;
298   ModuleOrigin origin;
299 
IsValidGlobalModuleEnv300   bool IsValidGlobal(uint32_t index) const {
301     return module && index < module->globals.size();
302   }
IsValidFunctionModuleEnv303   bool IsValidFunction(uint32_t index) const {
304     return module && index < module->functions.size();
305   }
IsValidSignatureModuleEnv306   bool IsValidSignature(uint32_t index) const {
307     return module && index < module->signatures.size();
308   }
IsValidTableModuleEnv309   bool IsValidTable(uint32_t index) const {
310     return module && index < module->function_tables.size();
311   }
GetGlobalTypeModuleEnv312   LocalType GetGlobalType(uint32_t index) {
313     DCHECK(IsValidGlobal(index));
314     return module->globals[index].type;
315   }
GetFunctionSignatureModuleEnv316   FunctionSig* GetFunctionSignature(uint32_t index) {
317     DCHECK(IsValidFunction(index));
318     return module->functions[index].sig;
319   }
GetSignatureModuleEnv320   FunctionSig* GetSignature(uint32_t index) {
321     DCHECK(IsValidSignature(index));
322     return module->signatures[index];
323   }
GetTableModuleEnv324   const WasmIndirectFunctionTable* GetTable(uint32_t index) const {
325     DCHECK(IsValidTable(index));
326     return &module->function_tables[index];
327   }
328 
asm_jsModuleEnv329   bool asm_js() { return origin == kAsmJsOrigin; }
330 
GetFunctionCodeModuleEnv331   Handle<Code> GetFunctionCode(uint32_t index) {
332     DCHECK_NOT_NULL(instance);
333     return instance->function_code[index];
334   }
335 
336   static compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone,
337                                                          FunctionSig* sig);
338   static compiler::CallDescriptor* GetI32WasmCallDescriptor(
339       Zone* zone, compiler::CallDescriptor* descriptor);
340   static compiler::CallDescriptor* GetI32WasmCallDescriptorForSimd(
341       Zone* zone, compiler::CallDescriptor* descriptor);
342 };
343 
344 // A helper for printing out the names of functions.
345 struct WasmFunctionName {
346   const WasmFunction* function_;
347   const WasmModule* module_;
WasmFunctionNameWasmFunctionName348   WasmFunctionName(const WasmFunction* function, const ModuleEnv* menv)
349       : function_(function), module_(menv ? menv->module : nullptr) {}
350 };
351 
352 std::ostream& operator<<(std::ostream& os, const WasmModule& module);
353 std::ostream& operator<<(std::ostream& os, const WasmFunction& function);
354 std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name);
355 
356 // Extract a function name from the given wasm instance.
357 // Returns "<WASM UNNAMED>" if no instance is passed, the function is unnamed or
358 // the name is not a valid UTF-8 string.
359 // TODO(5620): Refactor once we always get a wasm instance.
360 Handle<String> GetWasmFunctionName(Isolate* isolate, Handle<Object> instance,
361                                    uint32_t func_index);
362 
363 // Return the binary source bytes of a wasm module.
364 Handle<SeqOneByteString> GetWasmBytes(Handle<JSObject> wasm);
365 
366 // Get the debug info associated with the given wasm object.
367 // If no debug info exists yet, it is created automatically.
368 Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm);
369 
370 // Return the number of functions in the given wasm object.
371 int GetNumberOfFunctions(Handle<JSObject> wasm);
372 
373 // Create and export JSFunction
374 Handle<JSFunction> WrapExportCodeAsJSFunction(Isolate* isolate,
375                                               Handle<Code> export_code,
376                                               Handle<String> name,
377                                               FunctionSig* sig, int func_index,
378                                               Handle<JSObject> instance);
379 
380 // Check whether the given object represents a WebAssembly.Instance instance.
381 // This checks the number and type of internal fields, so it's not 100 percent
382 // secure. If it turns out that we need more complete checks, we could add a
383 // special marker as internal field, which will definitely never occur anywhere
384 // else.
385 bool IsWasmInstance(Object* instance);
386 
387 // Return the compiled module object for this WASM instance.
388 WasmCompiledModule* GetCompiledModule(Object* wasm_instance);
389 
390 // Check whether the wasm module was generated from asm.js code.
391 bool WasmIsAsmJs(Object* instance, Isolate* isolate);
392 
393 // Get the script of the wasm module. If the origin of the module is asm.js, the
394 // returned Script will be a JavaScript Script of Script::TYPE_NORMAL, otherwise
395 // it's of type TYPE_WASM.
396 Handle<Script> GetScript(Handle<JSObject> instance);
397 
398 // Get the asm.js source position for the given byte offset in the given
399 // function.
400 int GetAsmWasmSourcePosition(Handle<JSObject> instance, int func_index,
401                              int byte_offset);
402 
403 V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> CreateModuleObjectFromBytes(
404     Isolate* isolate, const byte* start, const byte* end, ErrorThrower* thrower,
405     ModuleOrigin origin, Handle<Script> asm_js_script,
406     const byte* asm_offset_tables_start, const byte* asm_offset_tables_end);
407 
408 V8_EXPORT_PRIVATE bool ValidateModuleBytes(Isolate* isolate, const byte* start,
409                                            const byte* end,
410                                            ErrorThrower* thrower,
411                                            ModuleOrigin origin);
412 
413 // Get the offset of the code of a function within a module.
414 int GetFunctionCodeOffset(Handle<WasmCompiledModule> compiled_module,
415                           int func_index);
416 
417 // Translate from byte offset in the module to function number and byte offset
418 // within that function, encoded as line and column in the position info.
419 bool GetPositionInfo(Handle<WasmCompiledModule> compiled_module,
420                      uint32_t position, Script::PositionInfo* info);
421 
422 // Assumed to be called with a code object associated to a wasm module instance.
423 // Intended to be called from runtime functions.
424 // Returns nullptr on failing to get owning instance.
425 Object* GetOwningWasmInstance(Code* code);
426 
427 MaybeHandle<JSArrayBuffer> GetInstanceMemory(Isolate* isolate,
428                                              Handle<JSObject> instance);
429 
430 int32_t GetInstanceMemorySize(Isolate* isolate, Handle<JSObject> instance);
431 
432 int32_t GrowInstanceMemory(Isolate* isolate, Handle<JSObject> instance,
433                            uint32_t pages);
434 
435 void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
436                           int index, Handle<JSFunction> js_function);
437 
438 namespace testing {
439 
440 void ValidateInstancesChain(Isolate* isolate, Handle<JSObject> wasm_module,
441                             int instance_count);
442 void ValidateModuleState(Isolate* isolate, Handle<JSObject> wasm_module);
443 void ValidateOrphanedInstance(Isolate* isolate, Handle<JSObject> instance);
444 
445 }  // namespace testing
446 }  // namespace wasm
447 }  // namespace internal
448 }  // namespace v8
449 
450 #endif  // V8_WASM_MODULE_H_
451