v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
wasm-module-builder.h
Go to the documentation of this file.
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_BUILDER_H_
6#define V8_WASM_WASM_MODULE_BUILDER_H_
7
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
10#endif // !V8_ENABLE_WEBASSEMBLY
11
12#include <optional>
13
14#include "src/base/memory.h"
16#include "src/base/vector.h"
18#include "src/wasm/leb-helper.h"
20#include "src/wasm/value-type.h"
25
26namespace v8::internal::wasm {
27
28class ZoneBuffer : public ZoneObject {
29 public:
30 // This struct is just a type tag for Zone::NewArray<T>(size_t) call.
31 struct Buffer {};
32
33 static constexpr size_t kInitialSize = 1024;
34 explicit ZoneBuffer(Zone* zone, size_t initial = kInitialSize)
35 : zone_(zone), buffer_(zone->AllocateArray<uint8_t, Buffer>(initial)) {
36 pos_ = buffer_;
37 end_ = buffer_ + initial;
38 }
39
40 void write_u8(uint8_t x) {
41 EnsureSpace(1);
42 *(pos_++) = x;
43 }
44
45 void write_u16(uint16_t x) {
46 EnsureSpace(2);
48 pos_ += 2;
49 }
50
51 void write_u32(uint32_t x) {
52 EnsureSpace(4);
54 pos_ += 4;
55 }
56
57 void write_u64(uint64_t x) {
58 EnsureSpace(8);
60 pos_ += 8;
61 }
62
63 void write_u32v(uint32_t val) {
66 }
67
68 void write_u32v(ModuleTypeIndex index) { write_u32v(index.index); }
69
70 void write_i32v(int32_t val) {
73 }
74
75 void write_u64v(uint64_t val) {
78 }
79
80 void write_i64v(int64_t val) {
83 }
84
85 void write_size(size_t val) {
87 DCHECK_EQ(val, static_cast<uint32_t>(val));
88 LEBHelper::write_u32v(&pos_, static_cast<uint32_t>(val));
89 }
90
91 void write_f32(float val) { write_u32(base::bit_cast<uint32_t>(val)); }
92
93 void write_f64(double val) { write_u64(base::bit_cast<uint64_t>(val)); }
94
95 void write(const uint8_t* data, size_t size) {
96 if (size == 0) return;
97 EnsureSpace(size);
98 memcpy(pos_, data, size);
99 pos_ += size;
100 }
101
103 write_size(name.length());
104 write(reinterpret_cast<const uint8_t*>(name.begin()), name.length());
105 }
106
107 size_t reserve_u32v() {
108 size_t off = offset();
111 return off;
112 }
113
114 // Patch a (padded) u32v at the given offset to be the given value.
115 void patch_u32v(size_t offset, uint32_t val) {
116 uint8_t* ptr = buffer_ + offset;
117 for (size_t pos = 0; pos != kPaddedVarInt32Size; ++pos) {
118 uint32_t next = val >> 7;
119 uint8_t out = static_cast<uint8_t>(val & 0x7f);
120 if (pos != kPaddedVarInt32Size - 1) {
121 *(ptr++) = 0x80 | out;
122 val = next;
123 } else {
124 *(ptr++) = out;
125 }
126 }
127 }
128
129 void patch_u8(size_t offset, uint8_t val) {
131 buffer_[offset] = val;
132 }
133
134 size_t offset() const { return static_cast<size_t>(pos_ - buffer_); }
135 size_t size() const { return static_cast<size_t>(pos_ - buffer_); }
136 uint8_t* data() const { return buffer_; }
137 uint8_t* begin() const { return buffer_; }
138 uint8_t* end() const { return pos_; }
139
140 void EnsureSpace(size_t size) {
141 if ((pos_ + size) > end_) {
142 size_t new_size = size + (end_ - buffer_) * 2;
143 uint8_t* new_buffer = zone_->AllocateArray<uint8_t, Buffer>(new_size);
144 memcpy(new_buffer, buffer_, (pos_ - buffer_));
145 pos_ = new_buffer + (pos_ - buffer_);
146 buffer_ = new_buffer;
147 end_ = new_buffer + new_size;
148 }
149 DCHECK(pos_ + size <= end_);
150 }
151
152 void Truncate(size_t size) {
153 DCHECK_GE(offset(), size);
154 pos_ = buffer_ + size;
155 }
156
157 uint8_t** pos_ptr() { return &pos_; }
158
159 private:
161 uint8_t* buffer_;
162 uint8_t* pos_;
163 uint8_t* end_;
164};
165
167
169 public:
170 // Building methods.
171 void SetSignature(const FunctionSig* sig);
172 void SetSignature(ModuleTypeIndex sig_index);
173 uint32_t AddLocal(ValueType type);
174 void EmitByte(uint8_t b);
175 void EmitI32V(int32_t val);
176 // Some instructions need an "s33" heaptype immediate.
177 void EmitI32V(ModuleTypeIndex index) { EmitI32V(index.index); }
178 void EmitU32V(uint32_t val);
179 // Some instructions need a u32 type index immediate.
180 void EmitU32V(ModuleTypeIndex index) { EmitU32V(index.index); }
181 void EmitU64V(uint64_t val);
182 void EmitCode(const uint8_t* code, uint32_t code_size);
183 void EmitCode(std::initializer_list<const uint8_t> code);
184 void Emit(WasmOpcode opcode);
185 void EmitWithPrefix(WasmOpcode opcode);
186 void EmitGetLocal(uint32_t index);
187 void EmitSetLocal(uint32_t index);
188 void EmitTeeLocal(uint32_t index);
189 void EmitI32Const(int32_t val);
190 void EmitI64Const(int64_t val);
191 void EmitF32Const(float val);
192 void EmitF64Const(double val);
194 void EmitWithU8(WasmOpcode opcode, const uint8_t immediate);
195 void EmitWithU8U8(WasmOpcode opcode, const uint8_t imm1, const uint8_t imm2);
196 void EmitWithI32V(WasmOpcode opcode, int32_t immediate);
197 void EmitWithU32V(WasmOpcode opcode, uint32_t immediate);
199 EmitWithU32V(opcode, index.index);
200 }
201 void EmitHeapType(HeapType type);
202 void EmitValueType(ValueType type);
203 void EmitDirectCallIndex(uint32_t index);
204 void EmitFromInitializerExpression(const WasmInitExpr& init_expr);
205 void SetName(base::Vector<const char> name);
206 void AddAsmWasmOffset(size_t call_position, size_t to_number_position);
207 void SetAsmFunctionStartPosition(size_t function_position);
208 void SetCompilationHint(WasmCompilationHintStrategy strategy,
211
212 size_t GetPosition() const { return body_.size(); }
213 void FixupByte(size_t position, uint8_t value) {
214 body_.patch_u8(position, value);
215 }
216 void DeleteCodeAfter(size_t position);
217
218 void WriteSignature(ZoneBuffer* buffer) const;
219 void WriteBody(ZoneBuffer* buffer) const;
220 void WriteAsmWasmOffsetTable(ZoneBuffer* buffer) const;
221
222 WasmModuleBuilder* builder() const { return builder_; }
223 uint32_t func_index() const { return func_index_; }
224 ModuleTypeIndex sig_index() const { return signature_index_; }
225 inline const FunctionSig* signature() const;
226
227 private:
228 explicit WasmFunctionBuilder(WasmModuleBuilder* builder);
229 friend class WasmModuleBuilder;
230 friend Zone;
231
233 size_t offset;
234 uint32_t direct_index;
235 };
236
240 uint32_t func_index_;
248
249 // Delta-encoded mapping from wasm bytes to asm.js source positions.
251 uint32_t last_asm_byte_offset_ = 0;
252 uint32_t last_asm_source_position_ = 0;
253 uint32_t asm_func_start_source_position_ = 0;
254 uint8_t hint_ = kNoCompilationHint;
255};
256
258 public:
259 explicit WasmModuleBuilder(Zone* zone);
262
263 // Static representation of wasm element segment (table initializer). This is
264 // different than the version in wasm-module.h.
266 public:
267 // asm.js gives function indices starting with the first non-imported
268 // function.
271 kRelativeToDeclaredFunctions
272 };
273 enum Status {
274 kStatusActive, // copied automatically during instantiation.
275 kStatusPassive, // copied explicitly after instantiation.
276 kStatusDeclarative // purely declarative and never copied.
277 };
278 struct Entry {
279 enum Kind { kGlobalGetEntry, kRefFuncEntry, kRefNullEntry } kind;
280 uint32_t index;
281 Entry(Kind kind, uint32_t index) : kind(kind), index(index) {}
282 Entry() : kind(kRefNullEntry), index(0) {}
283 };
284
285 // Construct an active segment.
286 WasmElemSegment(Zone* zone, ValueType type, uint32_t table_index,
288 : type(type),
289 table_index(table_index),
290 offset(offset),
291 entries(zone),
292 status(kStatusActive) {
293 DCHECK(IsValidOffsetKind(offset.kind()));
294 }
295
296 // Construct a passive or declarative segment, which has no table
297 // index or offset.
298 WasmElemSegment(Zone* zone, ValueType type, bool declarative,
300 : type(type),
301 table_index(0),
302 offset(offset),
303 entries(zone),
304 status(declarative ? kStatusDeclarative : kStatusPassive) {
305 DCHECK(IsValidOffsetKind(offset.kind()));
306 }
307
309
311 uint32_t table_index;
313 FunctionIndexingMode indexing_mode = kRelativeToImports;
316
317 private:
318 // This ensures no {WasmInitExpr} with subexpressions is used, which would
319 // cause a memory leak because those are stored in an std::vector. Such
320 // offset would also be mistyped.
322 return kind == WasmInitExpr::kI32Const ||
323 kind == WasmInitExpr::kI64Const ||
324 kind == WasmInitExpr::kGlobalGet ||
325 kind == WasmInitExpr::kRefNullConst;
326 }
327 };
328
329 // Building methods.
330 uint32_t AddImport(base::Vector<const char> name, const FunctionSig* sig,
331 base::Vector<const char> module = {});
332 WasmFunctionBuilder* AddFunction(const FunctionSig* sig = nullptr);
333 WasmFunctionBuilder* AddFunction(ModuleTypeIndex sig_index);
334 uint32_t AddGlobal(ValueType type, bool mutability, WasmInitExpr init);
335 uint32_t AddGlobalImport(base::Vector<const char> name, ValueType type,
336 bool mutability,
337 base::Vector<const char> module = {});
338 void AddDataSegment(const uint8_t* data, uint32_t size, uint32_t dest);
339 void AddPassiveDataSegment(const uint8_t* data, uint32_t size);
340 // Add an element segment to this {WasmModuleBuilder}. {segment}'s enties
341 // have to be initialized.
342 uint32_t AddElementSegment(WasmElemSegment segment);
343 // Helper method to create an active segment with one function. Assumes that
344 // table segment at {table_index} is typed as funcref.
345 void SetIndirectFunction(uint32_t table_index, uint32_t index_in_table,
346 uint32_t direct_function_index,
347 WasmElemSegment::FunctionIndexingMode indexing_mode);
348 // Increase the starting size of the table at {table_index} by {count}. Also
349 // increases the maximum table size if needed. Returns the former starting
350 // size, or the maximum uint32_t value if the maximum table size has been
351 // exceeded.
352 uint32_t IncreaseTableMinSize(uint32_t table_index, uint32_t count);
353 // Adds the signature to the module if it does not already exist.
354 ModuleTypeIndex AddSignature(const FunctionSig* sig, bool is_final,
355 ModuleTypeIndex supertype = kNoSuperType);
356 // Does not deduplicate function signatures.
357 ModuleTypeIndex ForceAddSignature(const FunctionSig* sig, bool is_final,
358 ModuleTypeIndex supertype = kNoSuperType);
359 uint32_t AddTag(const FunctionSig* type);
360 ModuleTypeIndex AddStructType(StructType* type, bool is_final,
361 ModuleTypeIndex supertype = kNoSuperType);
362 ModuleTypeIndex AddArrayType(ArrayType* type, bool is_final,
363 ModuleTypeIndex supertype = kNoSuperType);
364 uint32_t AddTable(ValueType type, uint32_t min_size);
365 uint32_t AddTable(ValueType type, uint32_t min_size, uint32_t max_size,
366 AddressType address_type = AddressType::kI32);
367 uint32_t AddTable(ValueType type, uint32_t min_size, uint32_t max_size,
368 WasmInitExpr init,
369 AddressType address_type = AddressType::kI32);
370 uint32_t AddMemory(uint32_t min_pages);
371 uint32_t AddMemory(uint32_t min_pages, uint32_t max_pages);
372 uint32_t AddMemory64(uint32_t min_pages);
373 uint32_t AddMemory64(uint32_t min_pages, uint32_t max_pages);
374 void MarkStartFunction(WasmFunctionBuilder* builder);
375 void AddExport(base::Vector<const char> name, ImportExportKindCode kind,
376 uint32_t index);
378 AddExport(name, kExternalFunction, builder->func_index());
379 }
380 uint32_t AddExportedGlobal(ValueType type, bool mutability, WasmInitExpr init,
382 void ExportImportedFunction(base::Vector<const char> name, int import_index);
383
385 DCHECK_EQ(current_recursive_group_start_, -1);
386 current_recursive_group_start_ = static_cast<int>(types_.size());
387 }
388
390 // Make sure we are in a recursive group.
391 DCHECK_NE(current_recursive_group_start_, -1);
392 recursive_groups_.emplace_back(
393 current_recursive_group_start_,
394 static_cast<uint32_t>(types_.size()) - current_recursive_group_start_);
395 current_recursive_group_start_ = -1;
396 }
397
398 void AddRecursiveTypeGroup(uint32_t start, uint32_t size) {
399 recursive_groups_.emplace_back(start, size);
400 }
401
402 // Writing methods.
403 void WriteTo(ZoneBuffer* buffer) const;
404 void WriteAsmJsOffsetTable(ZoneBuffer* buffer) const;
405
406 Zone* zone() { return zone_; }
407
408 ValueType GetTableType(uint32_t index) { return tables_[index].type; }
409
410 bool IsSignature(uint32_t index) {
411 return types_[index].kind == TypeDefinition::kFunction;
412 }
413 bool IsSignature(ModuleTypeIndex index) { return IsSignature(index.index); }
414
415 const FunctionSig* GetSignature(uint32_t index) {
416 DCHECK(types_[index].kind == TypeDefinition::kFunction);
417 return types_[index].function_sig;
418 }
420 return GetSignature(index.index);
421 }
422
423 bool IsStructType(uint32_t index) {
424 return types_[index].kind == TypeDefinition::kStruct;
425 }
426 bool IsStructType(ModuleTypeIndex index) { return IsStructType(index.index); }
427 const StructType* GetStructType(uint32_t index) {
428 return types_[index].struct_type;
429 }
431 return GetStructType(index.index);
432 }
433
434 bool IsArrayType(uint32_t index) {
435 return types_[index].kind == TypeDefinition::kArray;
436 }
437 bool IsArrayType(ModuleTypeIndex index) { return IsArrayType(index.index); }
438 const ArrayType* GetArrayType(uint32_t index) {
439 return types_[index].array_type;
440 }
442 return GetArrayType(index.index);
443 }
444
446 return types_[index].supertype;
447 }
448
449 WasmFunctionBuilder* GetFunction(uint32_t index) { return functions_[index]; }
450 int NumTags() { return static_cast<int>(tags_.size()); }
451
452 int NumTypes() { return static_cast<int>(types_.size()); }
453
454 int NumTables() { return static_cast<int>(tables_.size()); }
455
456 int NumMemories() { return static_cast<int>(memories_.size()); }
457
458 int NumGlobals() { return static_cast<int>(globals_.size()); }
459
461 return static_cast<int>(function_imports_.size());
462 }
463 int NumDeclaredFunctions() { return static_cast<int>(functions_.size()); }
464
465 int NumDataSegments() { return static_cast<int>(data_segments_.size()); }
466
467 bool IsMemory64(uint32_t index) { return memories_[index].is_memory64(); }
468
469 bool IsTable64(uint32_t index) { return tables_[index].is_table64(); }
470
471 const FunctionSig* GetTagType(int index) {
472 return types_[tags_[index].index].function_sig;
473 }
474
475 ValueType GetGlobalType(uint32_t index) const { return globals_[index].type; }
476
477 bool IsMutableGlobal(uint32_t index) const {
478 return globals_[index].mutability;
479 }
480
481 private:
487
491 // TODO(manoskouk): Extend to full value type.
494 };
495
496 struct WasmExport {
499 int index; // Can be negative for re-exported imports.
500 };
501
507
508 struct WasmTable {
510 uint32_t min_size;
511 uint32_t max_size = 0;
512 bool has_maximum = false;
513 bool is_shared = false;
514 AddressType address_type = AddressType::kI32;
515 std::optional<WasmInitExpr> init = {};
516
517 bool is_table64() const { return address_type == AddressType::kI64; }
518 };
519
520 struct WasmMemory {
521 uint32_t min_pages;
522 uint32_t max_pages = 0;
523 bool has_max_pages = false;
524 bool is_shared = false;
525 AddressType address_type = AddressType::kI32;
526
527 bool is_memory64() const { return address_type == AddressType::kI64; }
528 };
529
532 uint32_t dest;
533 bool is_active = true;
534 };
535
551 struct RecGroup {
552 uint32_t start_index;
553 uint32_t size;
554 };
557#if DEBUG
558 // Once AddExportedImport is called, no more imports can be added.
559 bool adding_imports_allowed_ = true;
560#endif
561};
562
564 return builder_->types_[signature_index_.index].function_sig;
565}
566
567} // namespace v8::internal::wasm
568
569#endif // V8_WASM_WASM_MODULE_BUILDER_H_
Builtins::Kind kind
Definition builtins.cc:40
SourcePosition pos
T * AllocateArray(size_t length)
Definition zone.h:127
static void write_i32v(uint8_t **dest, int32_t val)
Definition leb-helper.h:37
static void write_u32v(uint8_t **dest, uint32_t val)
Definition leb-helper.h:27
static void write_u64v(uint8_t **dest, uint64_t val)
Definition leb-helper.h:55
static void write_i64v(uint8_t **dest, int64_t val)
Definition leb-helper.h:65
void EmitWithU32V(WasmOpcode opcode, ModuleTypeIndex index)
void FixupByte(size_t position, uint8_t value)
ZoneVector< DirectCallIndex > direct_calls_
WasmElemSegment(Zone *zone, ValueType type, uint32_t table_index, WasmInitExpr offset)
WasmElemSegment(Zone *zone, ValueType type, bool declarative, WasmInitExpr offset)
const FunctionSig * GetSignature(uint32_t index)
const ArrayType * GetArrayType(ModuleTypeIndex index)
const ArrayType * GetArrayType(uint32_t index)
ZoneUnorderedMap< FunctionSig, ModuleTypeIndex > signature_map_
bool IsMutableGlobal(uint32_t index) const
ZoneVector< ModuleTypeIndex > tags_
WasmModuleBuilder(const WasmModuleBuilder &)=delete
const FunctionSig * GetSignature(ModuleTypeIndex index)
const StructType * GetStructType(uint32_t index)
bool IsArrayType(ModuleTypeIndex index)
const StructType * GetStructType(ModuleTypeIndex index)
const FunctionSig * GetTagType(int index)
ZoneVector< WasmGlobalImport > global_imports_
bool IsStructType(ModuleTypeIndex index)
ValueType GetGlobalType(uint32_t index) const
WasmModuleBuilder & operator=(const WasmModuleBuilder &)=delete
bool IsSignature(ModuleTypeIndex index)
void AddExport(base::Vector< const char > name, WasmFunctionBuilder *builder)
ZoneVector< WasmElemSegment > element_segments_
void AddRecursiveTypeGroup(uint32_t start, uint32_t size)
ZoneVector< WasmDataSegment > data_segments_
ModuleTypeIndex GetSuperType(uint32_t index)
ZoneVector< WasmFunctionImport > function_imports_
ZoneVector< WasmFunctionBuilder * > functions_
WasmFunctionBuilder * GetFunction(uint32_t index)
void write_u32v(ModuleTypeIndex index)
void patch_u32v(size_t offset, uint32_t val)
void patch_u8(size_t offset, uint8_t val)
ZoneBuffer(Zone *zone, size_t initial=kInitialSize)
void write_string(base::Vector< const char > name)
static constexpr size_t kInitialSize
void write(const uint8_t *data, size_t size)
Zone * zone_
int start
OptionalOpIndex index
int32_t offset
ZoneVector< Entry > entries
const int func_index_
int x
int position
Definition liveedit.cc:290
ExecutionTier top_tier
static void WriteLittleEndianValue(Address p, V value)
Definition memory.h:67
V8_INLINE Dest bit_cast(Source const &source)
Definition macros.h:95
constexpr uint8_t kNoCompilationHint
constexpr size_t kPaddedVarInt32Size
Definition leb-helper.h:19
constexpr size_t kMaxVarInt64Size
Definition leb-helper.h:21
constexpr size_t kMaxVarInt32Size
Definition leb-helper.h:20
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
JSArrayBuffer::IsDetachableBit is_shared
const std::vector< ModuleTypeIndex > & functions_
std::vector< ValueType > globals_
RegExpBuilder builder_
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_EXPORT_PRIVATE
Definition macros.h:460
const wasm::FunctionBody & body_