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 4785034 : : 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 1231738 : 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 : typedef FunctionSig WasmExceptionSig;
76 :
77 : // Static representation of a wasm exception type.
78 : struct WasmException {
79 587 : explicit WasmException(const WasmExceptionSig* sig) : sig(sig) {}
80 690 : 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 3382 : : dest_addr(dest_addr), active(true) {}
90 :
91 : // Construct a passive segment, which has no dest_addr.
92 101 : 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 3581 : struct WasmElemSegment {
112 1620 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmElemSegment);
113 :
114 : // Construct an active segment.
115 : WasmElemSegment(uint32_t table_index, WasmInitExpr offset)
116 5444 : : table_index(table_index), offset(offset), active(true) {}
117 :
118 : // Construct a passive segment, which has no table index or offset.
119 98 : 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 : 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 first_tier;
163 : WasmCompilationHintTier second_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 5520744 : 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 : WireBytesRef name = {0, 0};
199 : std::vector<FunctionSig*> signatures; // by signature index
200 : std::vector<uint32_t> signature_ids; // by signature index
201 : std::vector<WasmFunction> functions;
202 : std::vector<WasmDataSegment> data_segments;
203 : std::vector<WasmTable> tables;
204 : std::vector<WasmImport> import_table;
205 : std::vector<WasmExport> export_table;
206 : std::vector<WasmException> exceptions;
207 : std::vector<WasmElemSegment> elem_segments;
208 : std::vector<WasmCompilationHint> compilation_hints;
209 : SignatureMap signature_map; // canonicalizing map for signature indexes.
210 :
211 : ModuleOrigin origin = kWasmOrigin; // origin of the module
212 : mutable std::unique_ptr<std::unordered_map<uint32_t, WireBytesRef>>
213 : function_names;
214 : std::string source_map_url;
215 :
216 : explicit WasmModule(std::unique_ptr<Zone> signature_zone = nullptr);
217 :
218 : WireBytesRef LookupFunctionName(const ModuleWireBytes& wire_bytes,
219 : uint32_t function_index) const;
220 : void AddFunctionNameForTesting(int function_index, WireBytesRef name);
221 : };
222 :
223 : size_t EstimateStoredSize(const WasmModule* module);
224 :
225 : // Interface to the storage (wire bytes) of a wasm module.
226 : // It is illegal for anyone receiving a ModuleWireBytes to store pointers based
227 : // on module_bytes, as this storage is only guaranteed to be alive as long as
228 : // this struct is alive.
229 : struct V8_EXPORT_PRIVATE ModuleWireBytes {
230 : explicit ModuleWireBytes(Vector<const byte> module_bytes)
231 23869 : : module_bytes_(module_bytes) {}
232 : ModuleWireBytes(const byte* start, const byte* end)
233 423296 : : module_bytes_(start, static_cast<int>(end - start)) {
234 : DCHECK_GE(kMaxInt, end - start);
235 : }
236 :
237 : // Get a string stored in the module bytes representing a name.
238 : WasmName GetNameOrNull(WireBytesRef ref) const;
239 :
240 : // Get a string stored in the module bytes representing a function name.
241 : WasmName GetNameOrNull(const WasmFunction* function,
242 : const WasmModule* module) const;
243 :
244 : // Checks the given offset range is contained within the module bytes.
245 : bool BoundsCheck(uint32_t offset, uint32_t length) const {
246 480 : uint32_t size = static_cast<uint32_t>(module_bytes_.length());
247 480 : return offset <= size && length <= size - offset;
248 : }
249 :
250 : Vector<const byte> GetFunctionBytes(const WasmFunction* function) const {
251 : return module_bytes_.SubVector(function->code.offset(),
252 8501 : function->code.end_offset());
253 : }
254 :
255 144807 : Vector<const byte> module_bytes() const { return module_bytes_; }
256 : const byte* start() const { return module_bytes_.start(); }
257 : const byte* end() const { return module_bytes_.end(); }
258 136870 : size_t length() const { return module_bytes_.length(); }
259 :
260 : private:
261 : Vector<const byte> module_bytes_;
262 : };
263 :
264 : // A helper for printing out the names of functions.
265 : struct WasmFunctionName {
266 : WasmFunctionName(const WasmFunction* function, WasmName name)
267 136691 : : function_(function), name_(name) {}
268 :
269 : const WasmFunction* function_;
270 : const WasmName name_;
271 : };
272 :
273 : std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name);
274 :
275 : // Get the debug info associated with the given wasm object.
276 : // If no debug info exists yet, it is created automatically.
277 : Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm);
278 :
279 : V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> CreateModuleObjectFromBytes(
280 : Isolate* isolate, const byte* start, const byte* end, ErrorThrower* thrower,
281 : ModuleOrigin origin, Handle<Script> asm_js_script,
282 : Vector<const byte> asm_offset_table);
283 :
284 : V8_EXPORT_PRIVATE bool IsWasmCodegenAllowed(Isolate* isolate,
285 : Handle<Context> context);
286 :
287 : V8_EXPORT_PRIVATE Handle<JSArray> GetImports(Isolate* isolate,
288 : Handle<WasmModuleObject> module);
289 : V8_EXPORT_PRIVATE Handle<JSArray> GetExports(Isolate* isolate,
290 : Handle<WasmModuleObject> module);
291 : V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections(
292 : Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name,
293 : ErrorThrower* thrower);
294 :
295 : // Decode local variable names from the names section. Return FixedArray of
296 : // FixedArray of <undefined|String>. The outer fixed array is indexed by the
297 : // function index, the inner one by the local index.
298 : Handle<FixedArray> DecodeLocalNames(Isolate*, Handle<WasmModuleObject>);
299 :
300 : // TruncatedUserString makes it easy to output names up to a certain length, and
301 : // output a truncation followed by '...' if they exceed a limit.
302 : // Use like this:
303 : // TruncatedUserString<> name (pc, len);
304 : // printf("... %.*s ...", name.length(), name.start())
305 : template <int kMaxLen = 50>
306 : class TruncatedUserString {
307 : static_assert(kMaxLen >= 4, "minimum length is 4 (length of '...' plus one)");
308 :
309 : public:
310 : template <typename T>
311 : explicit TruncatedUserString(Vector<T> name)
312 192 : : TruncatedUserString(name.start(), name.length()) {}
313 :
314 : TruncatedUserString(const byte* start, size_t len)
315 328 : : TruncatedUserString(reinterpret_cast<const char*>(start), len) {}
316 :
317 520 : TruncatedUserString(const char* start, size_t len)
318 1040 : : start_(start), length_(std::min(kMaxLen, static_cast<int>(len))) {
319 520 : if (len > static_cast<size_t>(kMaxLen)) {
320 8 : memcpy(buffer_, start, kMaxLen - 3);
321 8 : memset(buffer_ + kMaxLen - 3, '.', 3);
322 8 : start_ = buffer_;
323 : }
324 520 : }
325 :
326 : const char* start() const { return start_; }
327 :
328 : int length() const { return length_; }
329 :
330 : private:
331 : const char* start_;
332 : const int length_;
333 : char buffer_[kMaxLen];
334 : };
335 :
336 : } // namespace wasm
337 : } // namespace internal
338 : } // namespace v8
339 :
340 : #endif // V8_WASM_WASM_MODULE_H_
|