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 5778716 : : offset_(offset), length_(length) {
35 : DCHECK_IMPLIES(offset_ == 0, length_ == 0);
36 : DCHECK_LE(offset_, offset_ + length_); // no uint32_t overflow.
37 : }
38 :
39 90 : uint32_t offset() const { return offset_; }
40 : uint32_t length() const { return length_; }
41 1919906 : 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 582 : explicit WasmException(const WasmExceptionSig* sig) : sig(sig) {}
80 685 : 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 3808 : : dest_addr(dest_addr), active(true) {}
90 :
91 : // Construct a passive segment, which has no dest_addr.
92 64 : 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 26 : 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 : // TODO(titzer): Move this to WasmInstance. Needed by interpreter only.
107 : std::vector<int32_t> values; // function table, -1 indicating invalid.
108 : bool imported = false; // true if imported.
109 : bool exported = false; // true if exported.
110 : };
111 :
112 : // Static representation of wasm element segment (table initializer).
113 : struct WasmElemSegment {
114 1676 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmElemSegment);
115 :
116 : // Construct an active segment.
117 : WasmElemSegment(uint32_t table_index, WasmInitExpr offset)
118 5104 : : table_index(table_index), offset(offset), active(true) {}
119 :
120 : // Construct a passive segment, which has no table index or offset.
121 72 : WasmElemSegment() : table_index(0), active(false) {}
122 :
123 : uint32_t table_index;
124 : WasmInitExpr offset;
125 : std::vector<uint32_t> entries;
126 : bool active; // true if copied automatically during instantiation.
127 : };
128 :
129 : // Static representation of a wasm import.
130 : struct WasmImport {
131 : WireBytesRef module_name; // module name.
132 : WireBytesRef field_name; // import name.
133 : ImportExportKindCode kind; // kind of the import.
134 : uint32_t index; // index into the respective space.
135 : };
136 :
137 : // Static representation of a wasm export.
138 : struct WasmExport {
139 : WireBytesRef name; // exported name.
140 : ImportExportKindCode kind; // kind of the export.
141 : uint32_t index; // index into the respective space.
142 : };
143 :
144 : enum ModuleOrigin : uint8_t { kWasmOrigin, kAsmJsOrigin };
145 :
146 : #define SELECT_WASM_COUNTER(counters, origin, prefix, suffix) \
147 : ((origin) == kWasmOrigin ? (counters)->prefix##_wasm_##suffix() \
148 : : (counters)->prefix##_asm_##suffix())
149 :
150 : struct ModuleWireBytes;
151 :
152 : // Static representation of a module.
153 6736784 : struct V8_EXPORT_PRIVATE WasmModule {
154 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmModule);
155 :
156 : std::unique_ptr<Zone> signature_zone;
157 : uint32_t initial_pages = 0; // initial size of the memory in 64k pages
158 : uint32_t maximum_pages = 0; // maximum size of the memory in 64k pages
159 : bool has_shared_memory = false; // true if memory is a SharedArrayBuffer
160 : bool has_maximum_pages = false; // true if there is a maximum memory size
161 : bool has_memory = false; // true if the memory was defined or imported
162 : bool mem_export = false; // true if the memory is exported
163 : int start_function_index = -1; // start function, >= 0 if any
164 :
165 : std::vector<WasmGlobal> globals;
166 : // Size of the buffer required for all globals that are not imported and
167 : // mutable.
168 : uint32_t untagged_globals_buffer_size = 0;
169 : uint32_t tagged_globals_buffer_size = 0;
170 : uint32_t num_imported_mutable_globals = 0;
171 : uint32_t num_imported_functions = 0;
172 : uint32_t num_declared_functions = 0; // excluding imported
173 : uint32_t num_exported_functions = 0;
174 : uint32_t num_declared_data_segments = 0; // From the DataCount section.
175 : WireBytesRef name = {0, 0};
176 : std::vector<FunctionSig*> signatures; // by signature index
177 : std::vector<uint32_t> signature_ids; // by signature index
178 : std::vector<WasmFunction> functions;
179 : std::vector<WasmDataSegment> data_segments;
180 : std::vector<WasmTable> tables;
181 : std::vector<WasmImport> import_table;
182 : std::vector<WasmExport> export_table;
183 : std::vector<WasmException> exceptions;
184 : std::vector<WasmElemSegment> elem_segments;
185 : SignatureMap signature_map; // canonicalizing map for signature indexes.
186 :
187 : ModuleOrigin origin = kWasmOrigin; // origin of the module
188 : mutable std::unique_ptr<std::unordered_map<uint32_t, WireBytesRef>>
189 : function_names;
190 : std::string source_map_url;
191 :
192 : explicit WasmModule(std::unique_ptr<Zone> signature_zone = nullptr);
193 :
194 : WireBytesRef LookupFunctionName(const ModuleWireBytes& wire_bytes,
195 : uint32_t function_index) const;
196 : void AddFunctionNameForTesting(int function_index, WireBytesRef name);
197 : };
198 :
199 : size_t EstimateStoredSize(const WasmModule* module);
200 :
201 : // Interface to the storage (wire bytes) of a wasm module.
202 : // It is illegal for anyone receiving a ModuleWireBytes to store pointers based
203 : // on module_bytes, as this storage is only guaranteed to be alive as long as
204 : // this struct is alive.
205 : struct V8_EXPORT_PRIVATE ModuleWireBytes {
206 : explicit ModuleWireBytes(Vector<const byte> module_bytes)
207 26011 : : module_bytes_(module_bytes) {}
208 : ModuleWireBytes(const byte* start, const byte* end)
209 469462 : : module_bytes_(start, static_cast<int>(end - start)) {
210 : DCHECK_GE(kMaxInt, end - start);
211 : }
212 :
213 : // Get a string stored in the module bytes representing a name.
214 : WasmName GetNameOrNull(WireBytesRef ref) const;
215 :
216 : // Get a string stored in the module bytes representing a function name.
217 : WasmName GetNameOrNull(const WasmFunction* function,
218 : const WasmModule* module) const;
219 :
220 : // Checks the given offset range is contained within the module bytes.
221 : bool BoundsCheck(uint32_t offset, uint32_t length) const {
222 398 : uint32_t size = static_cast<uint32_t>(module_bytes_.length());
223 398 : return offset <= size && length <= size - offset;
224 : }
225 :
226 : Vector<const byte> GetFunctionBytes(const WasmFunction* function) const {
227 : return module_bytes_.SubVector(function->code.offset(),
228 199 : function->code.end_offset());
229 : }
230 :
231 160368 : Vector<const byte> module_bytes() const { return module_bytes_; }
232 298248 : const byte* start() const { return module_bytes_.start(); }
233 : const byte* end() const { return module_bytes_.end(); }
234 314073 : size_t length() const { return module_bytes_.length(); }
235 :
236 : private:
237 : Vector<const byte> module_bytes_;
238 : };
239 :
240 : // A helper for printing out the names of functions.
241 : struct WasmFunctionName {
242 : WasmFunctionName(const WasmFunction* function, WasmName name)
243 151734 : : function_(function), name_(name) {}
244 :
245 : const WasmFunction* function_;
246 : const WasmName name_;
247 : };
248 :
249 : std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name);
250 :
251 : // Get the debug info associated with the given wasm object.
252 : // If no debug info exists yet, it is created automatically.
253 : Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm);
254 :
255 : V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> CreateModuleObjectFromBytes(
256 : Isolate* isolate, const byte* start, const byte* end, ErrorThrower* thrower,
257 : ModuleOrigin origin, Handle<Script> asm_js_script,
258 : Vector<const byte> asm_offset_table);
259 :
260 : V8_EXPORT_PRIVATE bool IsWasmCodegenAllowed(Isolate* isolate,
261 : Handle<Context> context);
262 :
263 : V8_EXPORT_PRIVATE Handle<JSArray> GetImports(Isolate* isolate,
264 : Handle<WasmModuleObject> module);
265 : V8_EXPORT_PRIVATE Handle<JSArray> GetExports(Isolate* isolate,
266 : Handle<WasmModuleObject> module);
267 : V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections(
268 : Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name,
269 : ErrorThrower* thrower);
270 :
271 : // Decode local variable names from the names section. Return FixedArray of
272 : // FixedArray of <undefined|String>. The outer fixed array is indexed by the
273 : // function index, the inner one by the local index.
274 : Handle<FixedArray> DecodeLocalNames(Isolate*, Handle<WasmModuleObject>);
275 :
276 : // TruncatedUserString makes it easy to output names up to a certain length, and
277 : // output a truncation followed by '...' if they exceed a limit.
278 : // Use like this:
279 : // TruncatedUserString<> name (pc, len);
280 : // printf("... %.*s ...", name.length(), name.start())
281 : template <int kMaxLen = 50>
282 : class TruncatedUserString {
283 : static_assert(kMaxLen >= 4, "minimum length is 4 (length of '...' plus one)");
284 :
285 : public:
286 : template <typename T>
287 : explicit TruncatedUserString(Vector<T> name)
288 9 : : TruncatedUserString(name.start(), name.length()) {}
289 :
290 : TruncatedUserString(const byte* start, size_t len)
291 369 : : TruncatedUserString(reinterpret_cast<const char*>(start), len) {}
292 :
293 378 : TruncatedUserString(const char* start, size_t len)
294 756 : : start_(start), length_(std::min(kMaxLen, static_cast<int>(len))) {
295 378 : if (len > static_cast<size_t>(kMaxLen)) {
296 9 : memcpy(buffer_, start, kMaxLen - 3);
297 9 : memset(buffer_ + kMaxLen - 3, '.', 3);
298 9 : start_ = buffer_;
299 : }
300 378 : }
301 :
302 : const char* start() const { return start_; }
303 :
304 : int length() const { return length_; }
305 :
306 : private:
307 : const char* start_;
308 : const int length_;
309 : char buffer_[kMaxLen];
310 : };
311 :
312 : } // namespace wasm
313 : } // namespace internal
314 : } // namespace v8
315 :
316 : #endif // V8_WASM_WASM_MODULE_H_
|