Home | History | Annotate | Download | only in wasm
      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 
     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 
     96   WasmInitExpr() : kind(kNone) {}
     97   explicit WasmInitExpr(int32_t v) : kind(kI32Const) { val.i32_const = v; }
     98   explicit WasmInitExpr(int64_t v) : kind(kI64Const) { val.i64_const = v; }
     99   explicit WasmInitExpr(float v) : kind(kF32Const) { val.f32_const = v; }
    100   explicit WasmInitExpr(double v) : kind(kF64Const) { val.f64_const = v; }
    101   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 
    217   WasmModule() : WasmModule(nullptr, nullptr) {}
    218   WasmModule(Zone* owned_zone, const byte* module_start);
    219   ~WasmModule() {
    220     if (owned_zone) delete owned_zone;
    221   }
    222 
    223   // Get a string stored in the module bytes representing a name.
    224   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.
    233   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.
    238   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.
    247   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.
    252   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 
    287   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 
    300   bool IsValidGlobal(uint32_t index) const {
    301     return module && index < module->globals.size();
    302   }
    303   bool IsValidFunction(uint32_t index) const {
    304     return module && index < module->functions.size();
    305   }
    306   bool IsValidSignature(uint32_t index) const {
    307     return module && index < module->signatures.size();
    308   }
    309   bool IsValidTable(uint32_t index) const {
    310     return module && index < module->function_tables.size();
    311   }
    312   LocalType GetGlobalType(uint32_t index) {
    313     DCHECK(IsValidGlobal(index));
    314     return module->globals[index].type;
    315   }
    316   FunctionSig* GetFunctionSignature(uint32_t index) {
    317     DCHECK(IsValidFunction(index));
    318     return module->functions[index].sig;
    319   }
    320   FunctionSig* GetSignature(uint32_t index) {
    321     DCHECK(IsValidSignature(index));
    322     return module->signatures[index];
    323   }
    324   const WasmIndirectFunctionTable* GetTable(uint32_t index) const {
    325     DCHECK(IsValidTable(index));
    326     return &module->function_tables[index];
    327   }
    328 
    329   bool asm_js() { return origin == kAsmJsOrigin; }
    330 
    331   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_;
    348   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