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) 25 : zone_(zone), buffer_(reinterpret_cast<byte*>(zone->New(initial))) { 26 pos_ = buffer_; 27 end_ = buffer_ + initial; 28 } 29 30 void write_u8(uint8_t x) { 31 EnsureSpace(1); 32 *(pos_++) = x; 33 } 34 35 void write_u16(uint16_t x) { 36 EnsureSpace(2); 37 WriteLittleEndianValue<uint16_t>(reinterpret_cast<Address>(pos_), x); 38 pos_ += 2; 39 } 40 41 void write_u32(uint32_t x) { 42 EnsureSpace(4); 43 WriteLittleEndianValue<uint32_t>(reinterpret_cast<Address>(pos_), x); 44 pos_ += 4; 45 } 46 47 void write_u64(uint64_t x) { 48 EnsureSpace(8); 49 WriteLittleEndianValue<uint64_t>(reinterpret_cast<Address>(pos_), x); 50 pos_ += 8; 51 } 52 53 void write_u32v(uint32_t val) { 54 EnsureSpace(kMaxVarInt32Size); 55 LEBHelper::write_u32v(&pos_, val); 56 } 57 58 void write_i32v(int32_t val) { 59 EnsureSpace(kMaxVarInt32Size); 60 LEBHelper::write_i32v(&pos_, val); 61 } 62 63 void write_u64v(uint64_t val) { 64 EnsureSpace(kMaxVarInt64Size); 65 LEBHelper::write_u64v(&pos_, val); 66 } 67 68 void write_i64v(int64_t val) { 69 EnsureSpace(kMaxVarInt64Size); 70 LEBHelper::write_i64v(&pos_, val); 71 } 72 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 79 void write_f32(float val) { write_u32(bit_cast<uint32_t>(val)); } 80 81 void write_f64(double val) { write_u64(bit_cast<uint64_t>(val)); } 82 83 void write(const byte* data, size_t size) { 84 EnsureSpace(size); 85 memcpy(pos_, data, size); 86 pos_ += size; 87 } 88 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 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. 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 116 void patch_u8(size_t offset, byte val) { 117 DCHECK_GE(size(), offset); 118 buffer_[offset] = val; 119 } 120 121 size_t offset() const { return static_cast<size_t>(pos_ - buffer_); } 122 size_t size() const { return static_cast<size_t>(pos_ - buffer_); } 123 const byte* begin() const { return buffer_; } 124 const byte* end() const { return pos_; } 125 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 138 void Truncate(size_t size) { 139 DCHECK_GE(offset(), size); 140 pos_ = buffer_ + size; 141 } 142 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 179 size_t GetPosition() const { return body_.size(); } 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 189 WasmModuleBuilder* builder() const { return builder_; } 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 245 Zone* zone() { return zone_; } 246 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 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