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_MODULE_H_
6 : #define V8_WASM_MODULE_H_
7 :
8 : #include <memory>
9 :
10 : #include "src/debug/debug-interface.h"
11 : #include "src/globals.h"
12 : #include "src/handles.h"
13 : #include "src/managed.h"
14 : #include "src/parsing/preparse-data.h"
15 :
16 : #include "src/wasm/decoder.h"
17 : #include "src/wasm/signature-map.h"
18 : #include "src/wasm/wasm-opcodes.h"
19 :
20 : namespace v8 {
21 : namespace internal {
22 :
23 : class WasmCompiledModule;
24 : class WasmDebugInfo;
25 : class WasmModuleObject;
26 : class WasmInstanceObject;
27 : class WasmTableObject;
28 : class WasmMemoryObject;
29 :
30 : namespace compiler {
31 : class CallDescriptor;
32 : }
33 :
34 : namespace wasm {
35 : class ErrorThrower;
36 :
37 : enum WasmExternalKind {
38 : kExternalFunction = 0,
39 : kExternalTable = 1,
40 : kExternalMemory = 2,
41 : kExternalGlobal = 3
42 : };
43 :
44 : // Static representation of a wasm function.
45 : struct WasmFunction {
46 : FunctionSig* sig; // signature of the function.
47 : uint32_t func_index; // index into the function table.
48 : uint32_t sig_index; // index into the signature table.
49 : WireBytesRef name; // function name, if any.
50 : WireBytesRef code; // code of this function.
51 : bool imported;
52 : bool exported;
53 : };
54 :
55 : // Static representation of a wasm global variable.
56 : struct WasmGlobal {
57 : ValueType type; // type of the global.
58 : bool mutability; // {true} if mutable.
59 : WasmInitExpr init; // the initialization expression of the global.
60 : uint32_t offset; // offset into global memory.
61 : bool imported; // true if imported.
62 : bool exported; // true if exported.
63 : };
64 :
65 : // Note: An exception signature only uses the params portion of a
66 : // function signature.
67 : typedef FunctionSig WasmExceptionSig;
68 :
69 : struct WasmException {
70 : explicit WasmException(const WasmExceptionSig* sig = &empty_sig_)
71 150 : : sig(sig) {}
72 143 : FunctionSig* ToFunctionSig() const { return const_cast<FunctionSig*>(sig); }
73 :
74 : const WasmExceptionSig* sig; // type signature of the exception.
75 :
76 : // Used to hold data on runtime exceptions.
77 : static constexpr const char* kRuntimeIdStr = "WasmExceptionRuntimeId";
78 : static constexpr const char* kRuntimeValuesStr = "WasmExceptionValues";
79 :
80 : private:
81 : static const WasmExceptionSig empty_sig_;
82 : };
83 :
84 : // Static representation of a wasm data segment.
85 : struct WasmDataSegment {
86 : WasmInitExpr dest_addr; // destination memory address of the data.
87 : WireBytesRef source; // start offset in the module bytes.
88 : };
89 :
90 : // Static representation of a wasm indirect call table.
91 : struct WasmIndirectFunctionTable {
92 0 : MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(WasmIndirectFunctionTable);
93 :
94 : uint32_t initial_size = 0; // initial table size.
95 : uint32_t maximum_size = 0; // maximum table size.
96 : bool has_maximum_size = false; // true if there is a maximum size.
97 : // TODO(titzer): Move this to WasmInstance. Needed by interpreter only.
98 : std::vector<int32_t> values; // function table, -1 indicating invalid.
99 : bool imported = false; // true if imported.
100 : bool exported = false; // true if exported.
101 : };
102 :
103 : // Static representation of how to initialize a table.
104 : struct WasmTableInit {
105 80 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmTableInit);
106 :
107 : WasmTableInit(uint32_t table_index, WasmInitExpr offset)
108 1163 : : table_index(table_index), offset(offset) {}
109 :
110 : uint32_t table_index;
111 : WasmInitExpr offset;
112 : std::vector<uint32_t> entries;
113 : };
114 :
115 : // Static representation of a wasm import.
116 : struct WasmImport {
117 : WireBytesRef module_name; // module name.
118 : WireBytesRef field_name; // import name.
119 : WasmExternalKind kind; // kind of the import.
120 : uint32_t index; // index into the respective space.
121 : };
122 :
123 : // Static representation of a wasm export.
124 : struct WasmExport {
125 : WireBytesRef name; // exported name.
126 : WasmExternalKind kind; // kind of the export.
127 : uint32_t index; // index into the respective space.
128 : };
129 :
130 : enum ModuleOrigin : uint8_t { kWasmOrigin, kAsmJsOrigin };
131 :
132 : struct ModuleWireBytes;
133 :
134 : // Static representation of a module.
135 1383368 : struct V8_EXPORT_PRIVATE WasmModule {
136 : MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(WasmModule);
137 :
138 : static const uint32_t kPageSize = 0x10000; // Page size, 64kb.
139 : static const uint32_t kMinMemPages = 1; // Minimum memory size = 64kb
140 :
141 : static constexpr int kInvalidExceptionTag = -1;
142 :
143 : std::unique_ptr<Zone> signature_zone;
144 : uint32_t initial_pages = 0; // initial size of the memory in 64k pages
145 : uint32_t maximum_pages = 0; // maximum size of the memory in 64k pages
146 : bool has_shared_memory = false; // true if memory is a SharedArrayBuffer
147 : bool has_maximum_pages = false; // true if there is a maximum memory size
148 : bool has_memory = false; // true if the memory was defined or imported
149 : bool mem_export = false; // true if the memory is exported
150 : int start_function_index = -1; // start function, >= 0 if any
151 :
152 : std::vector<WasmGlobal> globals;
153 : uint32_t globals_size = 0;
154 : uint32_t num_imported_functions = 0;
155 : uint32_t num_declared_functions = 0;
156 : uint32_t num_exported_functions = 0;
157 : WireBytesRef name = {0, 0};
158 : // TODO(wasm): Add url here, for spec'ed location information.
159 : std::vector<FunctionSig*> signatures; // by signature index
160 : std::vector<uint32_t> signature_ids; // by signature index
161 : std::vector<WasmFunction> functions;
162 : std::vector<WasmDataSegment> data_segments;
163 : std::vector<WasmIndirectFunctionTable> function_tables;
164 : std::vector<WasmImport> import_table;
165 : std::vector<WasmExport> export_table;
166 : std::vector<WasmException> exceptions;
167 : std::vector<WasmTableInit> table_inits;
168 : SignatureMap signature_map; // canonicalizing map for signature indexes.
169 :
170 112506 : WasmModule() : WasmModule(nullptr) {}
171 : WasmModule(std::unique_ptr<Zone> owned);
172 :
173 : ModuleOrigin origin() const { return origin_; }
174 309108 : void set_origin(ModuleOrigin new_value) { origin_ = new_value; }
175 40 : bool is_wasm() const { return origin_ == kWasmOrigin; }
176 196471 : bool is_asm_js() const { return origin_ == kAsmJsOrigin; }
177 :
178 : private:
179 : // TODO(kschimpf) - Encapsulate more fields.
180 : ModuleOrigin origin_ = kWasmOrigin; // origin of the module
181 : };
182 :
183 : typedef Managed<WasmModule> WasmModuleWrapper;
184 :
185 : // Interface to the storage (wire bytes) of a wasm module.
186 : // It is illegal for anyone receiving a ModuleWireBytes to store pointers based
187 : // on module_bytes, as this storage is only guaranteed to be alive as long as
188 : // this struct is alive.
189 : struct V8_EXPORT_PRIVATE ModuleWireBytes {
190 : ModuleWireBytes(Vector<const byte> module_bytes)
191 18727 : : module_bytes_(module_bytes) {}
192 : ModuleWireBytes(const byte* start, const byte* end)
193 622485 : : module_bytes_(start, static_cast<int>(end - start)) {
194 : DCHECK_GE(kMaxInt, end - start);
195 : }
196 :
197 : // Get a string stored in the module bytes representing a name.
198 43887 : WasmName GetName(WireBytesRef ref) const {
199 43887 : if (ref.is_empty()) return {"<?>", 3}; // no name.
200 18284 : CHECK(BoundsCheck(ref.offset(), ref.length()));
201 : return Vector<const char>::cast(
202 18284 : module_bytes_.SubVector(ref.offset(), ref.end_offset()));
203 : }
204 :
205 : // Get a string stored in the module bytes representing a function name.
206 : WasmName GetName(const WasmFunction* function) const {
207 43887 : return GetName(function->name);
208 : }
209 :
210 : // Get a string stored in the module bytes representing a name.
211 300997 : WasmName GetNameOrNull(WireBytesRef ref) const {
212 300997 : if (!ref.is_set()) return {nullptr, 0}; // no name.
213 4528 : CHECK(BoundsCheck(ref.offset(), ref.length()));
214 : return Vector<const char>::cast(
215 4528 : module_bytes_.SubVector(ref.offset(), ref.end_offset()));
216 : }
217 :
218 : // Get a string stored in the module bytes representing a function name.
219 : WasmName GetNameOrNull(const WasmFunction* function) const {
220 300997 : return GetNameOrNull(function->name);
221 : }
222 :
223 : // Checks the given offset range is contained within the module bytes.
224 : bool BoundsCheck(uint32_t offset, uint32_t length) const {
225 22812 : uint32_t size = static_cast<uint32_t>(module_bytes_.length());
226 22812 : return offset <= size && length <= size - offset;
227 : }
228 :
229 : Vector<const byte> GetFunctionBytes(const WasmFunction* function) const {
230 : return module_bytes_.SubVector(function->code.offset(),
231 89 : function->code.end_offset());
232 : }
233 :
234 200 : Vector<const byte> module_bytes() const { return module_bytes_; }
235 778425 : const byte* start() const { return module_bytes_.start(); }
236 : const byte* end() const { return module_bytes_.end(); }
237 1528417 : size_t length() const { return module_bytes_.length(); }
238 :
239 : private:
240 : Vector<const byte> module_bytes_;
241 : };
242 :
243 : // A helper for printing out the names of functions.
244 : struct WasmFunctionName {
245 : WasmFunctionName(const WasmFunction* function, WasmName name)
246 157373 : : function_(function), name_(name) {}
247 :
248 : const WasmFunction* function_;
249 : WasmName name_;
250 : };
251 :
252 : std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name);
253 :
254 : // Get the debug info associated with the given wasm object.
255 : // If no debug info exists yet, it is created automatically.
256 : Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm);
257 :
258 : V8_EXPORT_PRIVATE MaybeHandle<WasmModuleObject> CreateModuleObjectFromBytes(
259 : Isolate* isolate, const byte* start, const byte* end, ErrorThrower* thrower,
260 : ModuleOrigin origin, Handle<Script> asm_js_script,
261 : Vector<const byte> asm_offset_table);
262 :
263 : V8_EXPORT_PRIVATE bool IsWasmCodegenAllowed(Isolate* isolate,
264 : Handle<Context> context);
265 :
266 : V8_EXPORT_PRIVATE Handle<JSArray> GetImports(Isolate* isolate,
267 : Handle<WasmModuleObject> module);
268 : V8_EXPORT_PRIVATE Handle<JSArray> GetExports(Isolate* isolate,
269 : Handle<WasmModuleObject> module);
270 : V8_EXPORT_PRIVATE Handle<JSArray> GetCustomSections(
271 : Isolate* isolate, Handle<WasmModuleObject> module, Handle<String> name,
272 : ErrorThrower* thrower);
273 :
274 : // Decode local variable names from the names section. Return FixedArray of
275 : // FixedArray of <undefined|String>. The outer fixed array is indexed by the
276 : // function index, the inner one by the local index.
277 : Handle<FixedArray> DecodeLocalNames(Isolate*, Handle<WasmCompiledModule>);
278 :
279 : // If the target is an export wrapper, return the {WasmFunction*} corresponding
280 : // to the wrapped wasm function; in all other cases, return nullptr.
281 : // The returned pointer is owned by the wasm instance target belongs to. The
282 : // result is alive as long as the instance exists.
283 : // TODO(titzer): move this to WasmExportedFunction.
284 : WasmFunction* GetWasmFunctionForExport(Isolate* isolate, Handle<Object> target);
285 :
286 : void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
287 : int index, WasmFunction* function, Handle<Code> code);
288 :
289 : void UnpackAndRegisterProtectedInstructions(Isolate* isolate,
290 : Handle<FixedArray> code_table);
291 :
292 : const char* ExternalKindName(WasmExternalKind);
293 :
294 : // TruncatedUserString makes it easy to output names up to a certain length, and
295 : // output a truncation followed by '...' if they exceed a limit.
296 : // Use like this:
297 : // TruncatedUserString<> name (pc, len);
298 : // printf("... %.*s ...", name.length(), name.start())
299 : template <int kMaxLen = 50>
300 : class TruncatedUserString {
301 : static_assert(kMaxLen >= 4, "minimum length is 4 (length of '...' plus one)");
302 :
303 : public:
304 : template <typename T>
305 : explicit TruncatedUserString(Vector<T> name)
306 5841 : : TruncatedUserString(name.start(), name.length()) {}
307 :
308 : TruncatedUserString(const byte* start, size_t len)
309 400 : : TruncatedUserString(reinterpret_cast<const char*>(start), len) {}
310 :
311 6241 : TruncatedUserString(const char* start, size_t len)
312 12482 : : start_(start), length_(std::min(kMaxLen, static_cast<int>(len))) {
313 6241 : if (len > static_cast<size_t>(kMaxLen)) {
314 10 : memcpy(buffer_, start, kMaxLen - 3);
315 10 : memset(buffer_ + kMaxLen - 3, '.', 3);
316 10 : start_ = buffer_;
317 : }
318 6241 : }
319 :
320 : const char* start() const { return start_; }
321 :
322 : int length() const { return length_; }
323 :
324 : private:
325 : const char* start_;
326 : int length_;
327 : char buffer_[kMaxLen];
328 : };
329 :
330 : } // namespace wasm
331 : } // namespace internal
332 : } // namespace v8
333 :
334 : #endif // V8_WASM_MODULE_H_
|