Line data Source code
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/vector.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 : using WasmName = Vector<const char>;
26 :
27 : class ErrorThrower;
28 :
29 : // Reference to a string in the wire bytes.
30 : class WireBytesRef {
31 : public:
32 : WireBytesRef() : WireBytesRef(0, 0) {}
33 : WireBytesRef(uint32_t offset, uint32_t length)
34 4788363 : : offset_(offset), length_(length) {
35 : DCHECK_IMPLIES(offset_ == 0, length_ == 0);
36 : DCHECK_LE(offset_, offset_ + length_); // no uint32_t overflow.
37 : }
38 :
39 : uint32_t offset() const { return offset_; }
40 : uint32_t length() const { return length_; }
41 1222938 : uint32_t end_offset() const { return offset_ + length_; }
42 : bool is_empty() const { return length_ == 0; }
43 : bool is_set() const { return offset_ != 0; }
44 :
45 : private:
46 : uint32_t offset_;
47 : uint32_t length_;
48 : };
49 :
50 : // Static representation of a wasm function.
51 : struct WasmFunction {
52 : FunctionSig* sig; // signature of the function.
53 : uint32_t func_index; // index into the function table.
54 : uint32_t sig_index; // index into the signature table.
55 : WireBytesRef code; // code of this function.
56 : bool imported;
57 : bool exported;
58 : };
59 :
60 : // Static representation of a wasm global variable.
61 : struct WasmGlobal {
62 : ValueType type; // type of the global.
63 : bool mutability; // {true} if mutable.
64 : WasmInitExpr init; // the initialization expression of the global.
65 : union {
66 : uint32_t index; // index of imported mutable global.
67 : uint32_t offset; // offset into global memory (if not imported & mutable).
68 : };
69 : bool imported; // true if imported.
70 : bool exported; // true if exported.
71 : };
72 :
73 : // Note: An exception signature only uses the params portion of a
74 : // function signature.
75 : using WasmExceptionSig = FunctionSig;
76 :
77 : // Static representation of a wasm exception type.
78 : struct WasmException {
79 835 : explicit WasmException(const WasmExceptionSig* sig) : sig(sig) {}
80 933 : FunctionSig* ToFunctionSig() const { return const_cast<FunctionSig*>(sig); }
81 :
82 : const WasmExceptionSig* sig; // type signature of the exception.
83 : };
84 :
85 : // Static representation of a wasm data segment.
86 : struct WasmDataSegment {
87 : // Construct an active segment.
88 : explicit WasmDataSegment(WasmInitExpr dest_addr)
89 3126 : : dest_addr(dest_addr), active(true) {}
90 :
91 : // Construct a passive segment, which has no dest_addr.
92 109 : WasmDataSegment() : active(false) {}
93 :
94 : WasmInitExpr dest_addr; // destination memory address of the data.
95 : WireBytesRef source; // start offset in the module bytes.
96 : bool active = true; // true if copied automatically during instantiation.
97 : };
98 :
99 : // Static representation of a wasm indirect call table.
100 : struct WasmTable {
101 : MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(WasmTable);
102 : ValueType type = kWasmStmt; // table type.
103 : uint32_t initial_size = 0; // initial table size.
104 : uint32_t maximum_size = 0; // maximum table size.
105 : bool has_maximum_size = false; // true if there is a maximum size.
106 : bool imported = false; // true if imported.
107 : bool exported = false; // true if exported.
108 : };
109 :
110 : // Static representation of wasm element segment (table initializer).
111 3525 : struct WasmElemSegment {
112 1604 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmElemSegment);
113 :
114 : // Construct an active segment.
115 : WasmElemSegment(uint32_t table_index, WasmInitExpr offset)
116 5300 : : table_index(table_index), offset(offset), active(true) {}
117 :
118 : // Construct a passive segment, which has no table index or offset.
119 146 : WasmElemSegment() : table_index(0), active(false) {}
120 :
121 : // Used in the {entries} vector to represent a `ref.null` entry in a passive
122 : // segment.
123 : V8_EXPORT_PRIVATE static const uint32_t kNullIndex = ~0u;
124 :
125 : uint32_t table_index;
126 : WasmInitExpr offset;
127 : std::vector<uint32_t> entries;
128 : bool active; // true if copied automatically during instantiation.
129 : };
130 :
131 : // Static representation of a wasm import.
132 : struct WasmImport {
133 : WireBytesRef module_name; // module name.
134 : WireBytesRef field_name; // import name.
135 : ImportExportKindCode kind; // kind of the import.
136 : uint32_t index; // index into the respective space.
137 : };
138 :
139 : // Static representation of a wasm export.
140 : struct WasmExport {
141 : WireBytesRef name; // exported name.
142 : ImportExportKindCode kind; // kind of the export.
143 : uint32_t index; // index into the respective space.
144 : };
145 :
146 : enum class WasmCompilationHintStrategy : uint8_t {
147 : kDefault = 0,
148 : kLazy = 1,
149 : kEager = 2,
150 : };
151 :
152 : enum class WasmCompilationHintTier : uint8_t {
153 : kDefault = 0,
154 : kInterpreter = 1,
155 : kBaseline = 2,
156 : kOptimized = 3,
157 : };
158 :
159 : // Static representation of a wasm compilation hint
160 : struct WasmCompilationHint {
161 : WasmCompilationHintStrategy strategy;
162 : WasmCompilationHintTier baseline_tier;
163 : WasmCompilationHintTier top_tier;
164 : };
165 :
166 : enum ModuleOrigin : uint8_t { kWasmOrigin, kAsmJsOrigin };
167 :
168 : #define SELECT_WASM_COUNTER(counters, origin, prefix, suffix) \
169 : ((origin) == kWasmOrigin ? (counters)->prefix##_wasm_##suffix() \
170 : : (counters)->prefix##_asm_##suffix())
171 :
172 : struct ModuleWireBytes;
173 :
174 : // Static representation of a module.
175 5524540 : struct V8_EXPORT_PRIVATE WasmModule {
176 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmModule);
177 :
178 : std::unique_ptr<Zone> signature_zone;
179 : uint32_t initial_pages = 0; // initial size of the memory in 64k pages
180 : uint32_t maximum_pages = 0; // maximum size of the memory in 64k pages
181 : bool has_shared_memory = false; // true if memory is a SharedArrayBuffer
182 : bool has_maximum_pages = false; // true if there is a maximum memory size
183 : bool has_memory = false; // true if the memory was defined or imported
184 : bool mem_export = false; // true if the memory is exported
185 : int start_function_index = -1; // start function, >= 0 if any
186 :
187 : std::vector<WasmGlobal> globals;
188 : // Size of the buffer required for all globals that are not imported and
189 : // mutable.
190 : uint32_t untagged_globals_buffer_size = 0;
191 : uint32_t tagged_globals_buffer_size = 0;
192 : uint32_t num_imported_mutable_globals = 0;
193 : uint32_t num_imported_functions = 0;
194 : uint32_t num_imported_tables = 0;
195 : uint32_t num_declared_functions = 0; // excluding imported
196 : uint32_t num_exported_functions = 0;
197 : uint32_t num_declared_data_segments = 0; // From the DataCount section.
198 : uint32_t num_lazy_compilation_hints = 0; // From compilation hints section.
199 : WireBytesRef name = {0, 0};
200 : std::vector<FunctionSig*> signatures; // by signature index
201 : std::vector<uint32_t> signature_ids; // by signature index
202 : std::vector<WasmFunction> functions;
203 : std::vector<WasmDataSegment> data_segments;
204 : std::vector<WasmTable> tables;
205 : std::vector<WasmImport> import_table;
206 : std::vector<WasmExport> export_table;
207 : std::vector<WasmException> exceptions;
208 : std::vector<WasmElemSegment> elem_segments;
209 : std::vector<WasmCompilationHint> compilation_hints;
210 : SignatureMap signature_map; // canonicalizing map for signature indexes.
211 :
212 : ModuleOrigin origin = kWasmOrigin; // origin of the module
213 : mutable std::unique_ptr<std::unordered_map<uint32_t, WireBytesRef>>
214 : function_names;
215 : std::string source_map_url;
216 :
217 : explicit WasmModule(std::unique_ptr<Zone> signature_zone = nullptr);
218 :
219 : WireBytesRef LookupFunctionName(const ModuleWireBytes& wire_bytes,
220 : uint32_t function_index) const;
221 : void AddFunctionNameForTesting(int function_index, WireBytesRef name);
222 : };
223 :
224 : size_t EstimateStoredSize(const WasmModule* module);
225 :
226 : // Interface to the storage (wire bytes) of a wasm module.
227 : // It is illegal for anyone receiving a ModuleWireBytes to store pointers based
228 : // on module_bytes, as this storage is only guaranteed to be alive as long as
229 : // this struct is alive.
230 : struct V8_EXPORT_PRIVATE ModuleWireBytes {
231 : explicit ModuleWireBytes(Vector<const byte> module_bytes)
232 20975 : : module_bytes_(module_bytes) {}
233 : ModuleWireBytes(const byte* start, const byte* end)
234 423934 : : module_bytes_(start, static_cast<int>(end - start)) {
235 : DCHECK_GE(kMaxInt, end - start);
236 : }
237 :
238 : // Get a string stored in the module bytes representing a name.
239 : WasmName GetNameOrNull(WireBytesRef ref) const;
240 :
241 : // Get a string stored in the module bytes representing a function name.
242 : WasmName GetNameOrNull(const WasmFunction* function,
243 : const WasmModule* module) const;
244 :
245 : // Checks the given offset range is contained within the module bytes.
246 : bool BoundsCheck(uint32_t offset, uint32_t length) const {
247 799 : uint32_t size = static_cast<uint32_t>(module_bytes_.length());
248 799 : return offset <= size && length <= size - offset;
249 : }
250 :
251 : Vector<const byte> GetFunctionBytes(const WasmFunction* function) const {
252 : return module_bytes_.SubVector(function->code.offset(),
253 9081 : function->code.end_offset());
254 : }
255 :
256 145546 : Vector<const byte> module_bytes() const { return module_bytes_; }
257 : const byte* start() const { return module_bytes_.start(); }
258 : const byte* end() const { return module_bytes_.end(); }
259 136927 : size_t length() const { return module_bytes_.length(); }
260 :
261 : private:
262 : Vector<const byte> module_bytes_;
263 : };
264 :
265 : // A helper for printing out the names of functions.
266 : struct WasmFunctionName {
267 : WasmFunctionName(const WasmFunction* function, WasmName name)
268 136551 : : function_(function), name_(name) {}
269 :
270 : const WasmFunction* function_;
271 : const WasmName name_;
272 : };
273 :
274 : std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name);
275 :
276 : // Get the debug info associated with the given wasm object.
277 : // If no debug info exists yet, it is created automatically.
278 : Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm);
279 :
280 : V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> CreateModuleObjectFromBytes(
281 : Isolate* isolate, const byte* start, const byte* end, ErrorThrower* thrower,
282 : ModuleOrigin origin, Handle<Script> asm_js_script,
283 : Vector<const byte> asm_offset_table);
284 :
285 : V8_EXPORT_PRIVATE bool IsWasmCodegenAllowed(Isolate* isolate,
286 : Handle<Context> context);
287 :
288 : V8_EXPORT_PRIVATE Handle<JSArray> GetImports(Isolate* isolate,
289 : Handle<WasmModuleObject> module);
290 : V8_EXPORT_PRIVATE Handle<JSArray> GetExports(Isolate* isolate,
291 : Handle<WasmModuleObject> module);
292 : V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections(
293 : Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name,
294 : ErrorThrower* thrower);
295 :
296 : // Decode local variable names from the names section. Return FixedArray of
297 : // FixedArray of <undefined|String>. The outer fixed array is indexed by the
298 : // function index, the inner one by the local index.
299 : Handle<FixedArray> DecodeLocalNames(Isolate*, Handle<WasmModuleObject>);
300 :
301 : // TruncatedUserString makes it easy to output names up to a certain length, and
302 : // output a truncation followed by '...' if they exceed a limit.
303 : // Use like this:
304 : // TruncatedUserString<> name (pc, len);
305 : // printf("... %.*s ...", name.length(), name.start())
306 : template <int kMaxLen = 50>
307 : class TruncatedUserString {
308 : static_assert(kMaxLen >= 4, "minimum length is 4 (length of '...' plus one)");
309 :
310 : public:
311 : template <typename T>
312 : explicit TruncatedUserString(Vector<T> name)
313 344 : : TruncatedUserString(name.start(), name.length()) {}
314 :
315 : TruncatedUserString(const byte* start, size_t len)
316 328 : : TruncatedUserString(reinterpret_cast<const char*>(start), len) {}
317 :
318 672 : TruncatedUserString(const char* start, size_t len)
319 1344 : : start_(start), length_(std::min(kMaxLen, static_cast<int>(len))) {
320 672 : if (len > static_cast<size_t>(kMaxLen)) {
321 8 : memcpy(buffer_, start, kMaxLen - 3);
322 8 : memset(buffer_ + kMaxLen - 3, '.', 3);
323 8 : start_ = buffer_;
324 : }
325 672 : }
326 :
327 : const char* start() const { return start_; }
328 :
329 : int length() const { return length_; }
330 :
331 : private:
332 : const char* start_;
333 : const int length_;
334 : char buffer_[kMaxLen];
335 : };
336 :
337 : } // namespace wasm
338 : } // namespace internal
339 : } // namespace v8
340 :
341 : #endif // V8_WASM_WASM_MODULE_H_
|