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_WASM_MODULE_H_
      6 #define V8_WASM_WASM_MODULE_H_
      7 
      8 #include <memory>
      9 
     10 #include "src/globals.h"
     11 #include "src/handles.h"
     12 #include "src/wasm/decoder.h"
     13 #include "src/wasm/signature-map.h"
     14 #include "src/wasm/wasm-constants.h"
     15 #include "src/wasm/wasm-opcodes.h"
     16 
     17 namespace v8 {
     18 namespace internal {
     19 
     20 class WasmDebugInfo;
     21 class WasmModuleObject;
     22 
     23 namespace wasm {
     24 
     25 class ErrorThrower;
     26 
     27 // Static representation of a wasm function.
     28 struct WasmFunction {
     29   FunctionSig* sig;      // signature of the function.
     30   uint32_t func_index;   // index into the function table.
     31   uint32_t sig_index;    // index into the signature table.
     32   WireBytesRef code;     // code of this function.
     33   bool imported;
     34   bool exported;
     35 };
     36 
     37 // Static representation of a wasm global variable.
     38 struct WasmGlobal {
     39   ValueType type;     // type of the global.
     40   bool mutability;    // {true} if mutable.
     41   WasmInitExpr init;  // the initialization expression of the global.
     42   union {
     43     uint32_t index;   // index of imported mutable global.
     44     uint32_t offset;  // offset into global memory (if not imported & mutable).
     45   };
     46   bool imported;  // true if imported.
     47   bool exported;  // true if exported.
     48 };
     49 
     50 // Note: An exception signature only uses the params portion of a
     51 // function signature.
     52 typedef FunctionSig WasmExceptionSig;
     53 
     54 struct WasmException {
     55   explicit WasmException(const WasmExceptionSig* sig = &empty_sig_)
     56       : sig(sig) {}
     57   FunctionSig* ToFunctionSig() const { return const_cast<FunctionSig*>(sig); }
     58 
     59   const WasmExceptionSig* sig;  // type signature of the exception.
     60 
     61   // Used to hold data on runtime exceptions.
     62   static constexpr const char* kRuntimeIdStr = "WasmExceptionRuntimeId";
     63   static constexpr const char* kRuntimeValuesStr = "WasmExceptionValues";
     64 
     65  private:
     66   static const WasmExceptionSig empty_sig_;
     67 };
     68 
     69 // Static representation of a wasm data segment.
     70 struct WasmDataSegment {
     71   WasmInitExpr dest_addr;  // destination memory address of the data.
     72   WireBytesRef source;     // start offset in the module bytes.
     73 };
     74 
     75 // Static representation of a wasm indirect call table.
     76 struct WasmTable {
     77   MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(WasmTable);
     78   ValueType type = kWasmStmt;     // table type.
     79   uint32_t initial_size = 0;      // initial table size.
     80   uint32_t maximum_size = 0;      // maximum table size.
     81   bool has_maximum_size = false;  // true if there is a maximum size.
     82   // TODO(titzer): Move this to WasmInstance. Needed by interpreter only.
     83   std::vector<int32_t> values;  // function table, -1 indicating invalid.
     84   bool imported = false;        // true if imported.
     85   bool exported = false;        // true if exported.
     86 };
     87 
     88 // Static representation of how to initialize a table.
     89 struct WasmTableInit {
     90   MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmTableInit);
     91 
     92   WasmTableInit(uint32_t table_index, WasmInitExpr offset)
     93       : table_index(table_index), offset(offset) {}
     94 
     95   uint32_t table_index;
     96   WasmInitExpr offset;
     97   std::vector<uint32_t> entries;
     98 };
     99 
    100 // Static representation of a wasm import.
    101 struct WasmImport {
    102   WireBytesRef module_name;  // module name.
    103   WireBytesRef field_name;   // import name.
    104   ImportExportKindCode kind;  // kind of the import.
    105   uint32_t index;            // index into the respective space.
    106 };
    107 
    108 // Static representation of a wasm export.
    109 struct WasmExport {
    110   WireBytesRef name;      // exported name.
    111   ImportExportKindCode kind;  // kind of the export.
    112   uint32_t index;         // index into the respective space.
    113 };
    114 
    115 enum ModuleOrigin : uint8_t { kWasmOrigin, kAsmJsOrigin };
    116 
    117 #define SELECT_WASM_COUNTER(counters, origin, prefix, suffix)     \
    118   ((origin) == kWasmOrigin ? (counters)->prefix##_wasm_##suffix() \
    119                            : (counters)->prefix##_asm_##suffix())
    120 
    121 struct ModuleWireBytes;
    122 
    123 // Static representation of a module.
    124 struct V8_EXPORT_PRIVATE WasmModule {
    125   MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmModule);
    126 
    127   std::unique_ptr<Zone> signature_zone;
    128   uint32_t initial_pages = 0;      // initial size of the memory in 64k pages
    129   uint32_t maximum_pages = 0;      // maximum size of the memory in 64k pages
    130   bool has_shared_memory = false;  // true if memory is a SharedArrayBuffer
    131   bool has_maximum_pages = false;  // true if there is a maximum memory size
    132   bool has_memory = false;         // true if the memory was defined or imported
    133   bool mem_export = false;         // true if the memory is exported
    134   int start_function_index = -1;   // start function, >= 0 if any
    135 
    136   std::vector<WasmGlobal> globals;
    137   // Size of the buffer required for all globals that are not imported and
    138   // mutable.
    139   uint32_t globals_buffer_size = 0;
    140   uint32_t num_imported_mutable_globals = 0;
    141   uint32_t num_imported_functions = 0;
    142   uint32_t num_declared_functions = 0;  // excluding imported
    143   uint32_t num_exported_functions = 0;
    144   WireBytesRef name = {0, 0};
    145   std::vector<FunctionSig*> signatures;  // by signature index
    146   std::vector<uint32_t> signature_ids;   // by signature index
    147   std::vector<WasmFunction> functions;
    148   std::vector<WasmDataSegment> data_segments;
    149   std::vector<WasmTable> tables;
    150   std::vector<WasmImport> import_table;
    151   std::vector<WasmExport> export_table;
    152   std::vector<WasmException> exceptions;
    153   std::vector<WasmTableInit> table_inits;
    154   SignatureMap signature_map;  // canonicalizing map for signature indexes.
    155 
    156   ModuleOrigin origin = kWasmOrigin;  // origin of the module
    157   mutable std::unique_ptr<std::unordered_map<uint32_t, WireBytesRef>>
    158       function_names;
    159 
    160   explicit WasmModule(std::unique_ptr<Zone> owned = nullptr);
    161 
    162   WireBytesRef LookupFunctionName(const ModuleWireBytes& wire_bytes,
    163                                   uint32_t function_index) const;
    164   void AddFunctionNameForTesting(int function_index, WireBytesRef name);
    165 };
    166 
    167 size_t EstimateWasmModuleSize(const WasmModule* module);
    168 
    169 // Interface to the storage (wire bytes) of a wasm module.
    170 // It is illegal for anyone receiving a ModuleWireBytes to store pointers based
    171 // on module_bytes, as this storage is only guaranteed to be alive as long as
    172 // this struct is alive.
    173 struct V8_EXPORT_PRIVATE ModuleWireBytes {
    174   ModuleWireBytes(Vector<const byte> module_bytes)
    175       : module_bytes_(module_bytes) {}
    176   ModuleWireBytes(const byte* start, const byte* end)
    177       : module_bytes_(start, static_cast<int>(end - start)) {
    178     DCHECK_GE(kMaxInt, end - start);
    179   }
    180 
    181   // Get a string stored in the module bytes representing a name.
    182   WasmName GetName(WireBytesRef ref) const;
    183 
    184   // Get a string stored in the module bytes representing a function name.
    185   WasmName GetName(const WasmFunction* function,
    186                    const WasmModule* module) const;
    187 
    188   // Get a string stored in the module bytes representing a name.
    189   WasmName GetNameOrNull(WireBytesRef ref) const;
    190 
    191   // Get a string stored in the module bytes representing a function name.
    192   WasmName GetNameOrNull(const WasmFunction* function,
    193                          const WasmModule* module) const;
    194 
    195   // Checks the given offset range is contained within the module bytes.
    196   bool BoundsCheck(uint32_t offset, uint32_t length) const {
    197     uint32_t size = static_cast<uint32_t>(module_bytes_.length());
    198     return offset <= size && length <= size - offset;
    199   }
    200 
    201   Vector<const byte> GetFunctionBytes(const WasmFunction* function) const {
    202     return module_bytes_.SubVector(function->code.offset(),
    203                                    function->code.end_offset());
    204   }
    205 
    206   Vector<const byte> module_bytes() const { return module_bytes_; }
    207   const byte* start() const { return module_bytes_.start(); }
    208   const byte* end() const { return module_bytes_.end(); }
    209   size_t length() const { return module_bytes_.length(); }
    210 
    211  private:
    212   Vector<const byte> module_bytes_;
    213 };
    214 
    215 // A helper for printing out the names of functions.
    216 struct WasmFunctionName {
    217   WasmFunctionName(const WasmFunction* function, WasmName name)
    218       : function_(function), name_(name) {}
    219 
    220   const WasmFunction* function_;
    221   const WasmName name_;
    222 };
    223 
    224 std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name);
    225 
    226 // Get the debug info associated with the given wasm object.
    227 // If no debug info exists yet, it is created automatically.
    228 Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm);
    229 
    230 V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> CreateModuleObjectFromBytes(
    231     Isolate* isolate, const byte* start, const byte* end, ErrorThrower* thrower,
    232     ModuleOrigin origin, Handle<Script> asm_js_script,
    233     Vector<const byte> asm_offset_table);
    234 
    235 V8_EXPORT_PRIVATE bool IsWasmCodegenAllowed(Isolate* isolate,
    236                                             Handle<Context> context);
    237 
    238 V8_EXPORT_PRIVATE Handle<JSArray> GetImports(Isolate* isolate,
    239                                              Handle<WasmModuleObject> module);
    240 V8_EXPORT_PRIVATE Handle<JSArray> GetExports(Isolate* isolate,
    241                                              Handle<WasmModuleObject> module);
    242 V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections(
    243     Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name,
    244     ErrorThrower* thrower);
    245 
    246 // Decode local variable names from the names section. Return FixedArray of
    247 // FixedArray of <undefined|String>. The outer fixed array is indexed by the
    248 // function index, the inner one by the local index.
    249 Handle<FixedArray> DecodeLocalNames(Isolate*, Handle<WasmModuleObject>);
    250 
    251 // TruncatedUserString makes it easy to output names up to a certain length, and
    252 // output a truncation followed by '...' if they exceed a limit.
    253 // Use like this:
    254 //   TruncatedUserString<> name (pc, len);
    255 //   printf("... %.*s ...", name.length(), name.start())
    256 template <int kMaxLen = 50>
    257 class TruncatedUserString {
    258   static_assert(kMaxLen >= 4, "minimum length is 4 (length of '...' plus one)");
    259 
    260  public:
    261   template <typename T>
    262   explicit TruncatedUserString(Vector<T> name)
    263       : TruncatedUserString(name.start(), name.length()) {}
    264 
    265   TruncatedUserString(const byte* start, size_t len)
    266       : TruncatedUserString(reinterpret_cast<const char*>(start), len) {}
    267 
    268   TruncatedUserString(const char* start, size_t len)
    269       : start_(start), length_(std::min(kMaxLen, static_cast<int>(len))) {
    270     if (len > static_cast<size_t>(kMaxLen)) {
    271       memcpy(buffer_, start, kMaxLen - 3);
    272       memset(buffer_ + kMaxLen - 3, '.', 3);
    273       start_ = buffer_;
    274     }
    275   }
    276 
    277   const char* start() const { return start_; }
    278 
    279   int length() const { return length_; }
    280 
    281  private:
    282   const char* start_;
    283   const int length_;
    284   char buffer_[kMaxLen];
    285 };
    286 
    287 }  // namespace wasm
    288 }  // namespace internal
    289 }  // namespace v8
    290 
    291 #endif  // V8_WASM_WASM_MODULE_H_
    292