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 #include "src/signature.h"
9 #include "src/zone/zone-containers.h"
10
11 #include "src/v8memory.h"
12 #include "src/wasm/leb-helper.h"
13 #include "src/wasm/local-decl-encoder.h"
14 #include "src/wasm/wasm-opcodes.h"
15 #include "src/wasm/wasm-result.h"
16
17 namespace v8 {
18 namespace internal {
19 namespace wasm {
20
21 class ZoneBuffer : public ZoneObject {
22 public:
23 static constexpr size_t kInitialSize = 1024;
24 explicit ZoneBuffer(Zone* zone, size_t initial = kInitialSize)
zone_(zone)25 : zone_(zone), buffer_(reinterpret_cast<byte*>(zone->New(initial))) {
26 pos_ = buffer_;
27 end_ = buffer_ + initial;
28 }
29
write_u8(uint8_t x)30 void write_u8(uint8_t x) {
31 EnsureSpace(1);
32 *(pos_++) = x;
33 }
34
write_u16(uint16_t x)35 void write_u16(uint16_t x) {
36 EnsureSpace(2);
37 WriteLittleEndianValue<uint16_t>(reinterpret_cast<Address>(pos_), x);
38 pos_ += 2;
39 }
40
write_u32(uint32_t x)41 void write_u32(uint32_t x) {
42 EnsureSpace(4);
43 WriteLittleEndianValue<uint32_t>(reinterpret_cast<Address>(pos_), x);
44 pos_ += 4;
45 }
46
write_u64(uint64_t x)47 void write_u64(uint64_t x) {
48 EnsureSpace(8);
49 WriteLittleEndianValue<uint64_t>(reinterpret_cast<Address>(pos_), x);
50 pos_ += 8;
51 }
52
write_u32v(uint32_t val)53 void write_u32v(uint32_t val) {
54 EnsureSpace(kMaxVarInt32Size);
55 LEBHelper::write_u32v(&pos_, val);
56 }
57
write_i32v(int32_t val)58 void write_i32v(int32_t val) {
59 EnsureSpace(kMaxVarInt32Size);
60 LEBHelper::write_i32v(&pos_, val);
61 }
62
write_u64v(uint64_t val)63 void write_u64v(uint64_t val) {
64 EnsureSpace(kMaxVarInt64Size);
65 LEBHelper::write_u64v(&pos_, val);
66 }
67
write_i64v(int64_t val)68 void write_i64v(int64_t val) {
69 EnsureSpace(kMaxVarInt64Size);
70 LEBHelper::write_i64v(&pos_, val);
71 }
72
write_size(size_t val)73 void write_size(size_t val) {
74 EnsureSpace(kMaxVarInt32Size);
75 DCHECK_EQ(val, static_cast<uint32_t>(val));
76 LEBHelper::write_u32v(&pos_, static_cast<uint32_t>(val));
77 }
78
write_f32(float val)79 void write_f32(float val) { write_u32(bit_cast<uint32_t>(val)); }
80
write_f64(double val)81 void write_f64(double val) { write_u64(bit_cast<uint64_t>(val)); }
82
write(const byte * data,size_t size)83 void write(const byte* data, size_t size) {
84 EnsureSpace(size);
85 memcpy(pos_, data, size);
86 pos_ += size;
87 }
88
write_string(Vector<const char> name)89 void write_string(Vector<const char> name) {
90 write_size(name.length());
91 write(reinterpret_cast<const byte*>(name.start()), name.length());
92 }
93
reserve_u32v()94 size_t reserve_u32v() {
95 size_t off = offset();
96 EnsureSpace(kMaxVarInt32Size);
97 pos_ += kMaxVarInt32Size;
98 return off;
99 }
100
101 // Patch a (padded) u32v at the given offset to be the given value.
patch_u32v(size_t offset,uint32_t val)102 void patch_u32v(size_t offset, uint32_t val) {
103 byte* ptr = buffer_ + offset;
104 for (size_t pos = 0; pos != kPaddedVarInt32Size; ++pos) {
105 uint32_t next = val >> 7;
106 byte out = static_cast<byte>(val & 0x7f);
107 if (pos != kPaddedVarInt32Size - 1) {
108 *(ptr++) = 0x80 | out;
109 val = next;
110 } else {
111 *(ptr++) = out;
112 }
113 }
114 }
115
patch_u8(size_t offset,byte val)116 void patch_u8(size_t offset, byte val) {
117 DCHECK_GE(size(), offset);
118 buffer_[offset] = val;
119 }
120
offset()121 size_t offset() const { return static_cast<size_t>(pos_ - buffer_); }
size()122 size_t size() const { return static_cast<size_t>(pos_ - buffer_); }
begin()123 const byte* begin() const { return buffer_; }
end()124 const byte* end() const { return pos_; }
125
EnsureSpace(size_t size)126 void EnsureSpace(size_t size) {
127 if ((pos_ + size) > end_) {
128 size_t new_size = size + (end_ - buffer_) * 2;
129 byte* new_buffer = reinterpret_cast<byte*>(zone_->New(new_size));
130 memcpy(new_buffer, buffer_, (pos_ - buffer_));
131 pos_ = new_buffer + (pos_ - buffer_);
132 buffer_ = new_buffer;
133 end_ = new_buffer + new_size;
134 }
135 DCHECK(pos_ + size <= end_);
136 }
137
Truncate(size_t size)138 void Truncate(size_t size) {
139 DCHECK_GE(offset(), size);
140 pos_ = buffer_ + size;
141 }
142
pos_ptr()143 byte** pos_ptr() { return &pos_; }
144
145 private:
146 Zone* zone_;
147 byte* buffer_;
148 byte* pos_;
149 byte* end_;
150 };
151
152 class WasmModuleBuilder;
153
154 class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject {
155 public:
156 // Building methods.
157 void SetSignature(FunctionSig* sig);
158 uint32_t AddLocal(ValueType type);
159 void EmitI32V(int32_t val);
160 void EmitU32V(uint32_t val);
161 void EmitCode(const byte* code, uint32_t code_size);
162 void Emit(WasmOpcode opcode);
163 void EmitGetLocal(uint32_t index);
164 void EmitSetLocal(uint32_t index);
165 void EmitTeeLocal(uint32_t index);
166 void EmitI32Const(int32_t val);
167 void EmitI64Const(int64_t val);
168 void EmitF32Const(float val);
169 void EmitF64Const(double val);
170 void EmitWithU8(WasmOpcode opcode, const byte immediate);
171 void EmitWithU8U8(WasmOpcode opcode, const byte imm1, const byte imm2);
172 void EmitWithI32V(WasmOpcode opcode, int32_t immediate);
173 void EmitWithU32V(WasmOpcode opcode, uint32_t immediate);
174 void EmitDirectCallIndex(uint32_t index);
175 void SetName(Vector<const char> name);
176 void AddAsmWasmOffset(size_t call_position, size_t to_number_position);
177 void SetAsmFunctionStartPosition(size_t function_position);
178
GetPosition()179 size_t GetPosition() const { return body_.size(); }
FixupByte(size_t position,byte value)180 void FixupByte(size_t position, byte value) {
181 body_.patch_u8(position, value);
182 }
183 void DeleteCodeAfter(size_t position);
184
185 void WriteSignature(ZoneBuffer& buffer) const;
186 void WriteBody(ZoneBuffer& buffer) const;
187 void WriteAsmWasmOffsetTable(ZoneBuffer& buffer) const;
188
builder()189 WasmModuleBuilder* builder() const { return builder_; }
func_index()190 uint32_t func_index() { return func_index_; }
191 FunctionSig* signature();
192
193 private:
194 explicit WasmFunctionBuilder(WasmModuleBuilder* builder);
195 friend class WasmModuleBuilder;
196
197 struct DirectCallIndex {
198 size_t offset;
199 uint32_t direct_index;
200 };
201
202 WasmModuleBuilder* builder_;
203 LocalDeclEncoder locals_;
204 uint32_t signature_index_;
205 uint32_t func_index_;
206 ZoneBuffer body_;
207 Vector<const char> name_;
208 ZoneVector<uint32_t> i32_temps_;
209 ZoneVector<uint32_t> i64_temps_;
210 ZoneVector<uint32_t> f32_temps_;
211 ZoneVector<uint32_t> f64_temps_;
212 ZoneVector<DirectCallIndex> direct_calls_;
213
214 // Delta-encoded mapping from wasm bytes to asm.js source positions.
215 ZoneBuffer asm_offsets_;
216 uint32_t last_asm_byte_offset_ = 0;
217 uint32_t last_asm_source_position_ = 0;
218 uint32_t asm_func_start_source_position_ = 0;
219 };
220
221 class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
222 public:
223 explicit WasmModuleBuilder(Zone* zone);
224
225 // Building methods.
226 uint32_t AddImport(Vector<const char> name, FunctionSig* sig);
227 WasmFunctionBuilder* AddFunction(FunctionSig* sig = nullptr);
228 uint32_t AddGlobal(ValueType type, bool exported, bool mutability = true,
229 const WasmInitExpr& init = WasmInitExpr());
230 uint32_t AddGlobalImport(Vector<const char> name, ValueType type);
231 void AddDataSegment(const byte* data, uint32_t size, uint32_t dest);
232 uint32_t AddSignature(FunctionSig* sig);
233 uint32_t AllocateIndirectFunctions(uint32_t count);
234 void SetIndirectFunction(uint32_t indirect, uint32_t direct);
235 void MarkStartFunction(WasmFunctionBuilder* builder);
236 void AddExport(Vector<const char> name, WasmFunctionBuilder* builder);
237 void SetMinMemorySize(uint32_t value);
238 void SetMaxMemorySize(uint32_t value);
239 void SetHasSharedMemory();
240
241 // Writing methods.
242 void WriteTo(ZoneBuffer& buffer) const;
243 void WriteAsmJsOffsetTable(ZoneBuffer& buffer) const;
244
zone()245 Zone* zone() { return zone_; }
246
GetSignature(uint32_t index)247 FunctionSig* GetSignature(uint32_t index) { return signatures_[index]; }
248
249 private:
250 struct WasmFunctionImport {
251 Vector<const char> name;
252 uint32_t sig_index;
253 };
254
255 struct WasmFunctionExport {
256 Vector<const char> name;
257 uint32_t function_index;
258 };
259
260 struct WasmGlobalImport {
261 Vector<const char> name;
262 ValueTypeCode type_code;
263 };
264
265 struct WasmGlobal {
266 ValueType type;
267 bool exported;
268 bool mutability;
269 WasmInitExpr init;
270 };
271
272 struct WasmDataSegment {
273 ZoneVector<byte> data;
274 uint32_t dest;
275 };
276
277 friend class WasmFunctionBuilder;
278 Zone* zone_;
279 ZoneVector<FunctionSig*> signatures_;
280 ZoneVector<WasmFunctionImport> function_imports_;
281 ZoneVector<WasmFunctionExport> function_exports_;
282 ZoneVector<WasmGlobalImport> global_imports_;
283 ZoneVector<WasmFunctionBuilder*> functions_;
284 ZoneVector<WasmDataSegment> data_segments_;
285 ZoneVector<uint32_t> indirect_functions_;
286 ZoneVector<WasmGlobal> globals_;
287 ZoneUnorderedMap<FunctionSig, uint32_t> signature_map_;
288 int start_function_index_;
289 uint32_t min_memory_size_;
290 uint32_t max_memory_size_;
291 bool has_max_memory_size_;
292 bool has_shared_memory_;
293 };
294
signature()295 inline FunctionSig* WasmFunctionBuilder::signature() {
296 return builder_->signatures_[signature_index_];
297 }
298
299 } // namespace wasm
300 } // namespace internal
301 } // namespace v8
302
303 #endif // V8_WASM_WASM_MODULE_BUILDER_H_
304