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_) sigWasmException56 : sig(sig) {} ToFunctionSigWasmException57 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 WasmTableInitWasmTableInit92 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 { ModuleWireBytesModuleWireBytes174 ModuleWireBytes(Vector<const byte> module_bytes) 175 : module_bytes_(module_bytes) {} ModuleWireBytesModuleWireBytes176 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. BoundsCheckModuleWireBytes196 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 GetFunctionBytesModuleWireBytes201 Vector<const byte> GetFunctionBytes(const WasmFunction* function) const { 202 return module_bytes_.SubVector(function->code.offset(), 203 function->code.end_offset()); 204 } 205 module_bytesModuleWireBytes206 Vector<const byte> module_bytes() const { return module_bytes_; } startModuleWireBytes207 const byte* start() const { return module_bytes_.start(); } endModuleWireBytes208 const byte* end() const { return module_bytes_.end(); } lengthModuleWireBytes209 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 { WasmFunctionNameWasmFunctionName217 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> TruncatedUserString(Vector<T> name)262 explicit TruncatedUserString(Vector<T> name) 263 : TruncatedUserString(name.start(), name.length()) {} 264 TruncatedUserString(const byte * start,size_t len)265 TruncatedUserString(const byte* start, size_t len) 266 : TruncatedUserString(reinterpret_cast<const char*>(start), len) {} 267 TruncatedUserString(const char * start,size_t len)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 start()277 const char* start() const { return start_; } 278 length()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