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/wasm/leb-helper.h" 12 #include "src/wasm/wasm-macro-gen.h" 13 #include "src/wasm/wasm-module.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 const uint32_t kInitialSize = 4096; 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>(pos_, x); 38 pos_ += 2; 39 } 40 41 void write_u32(uint32_t x) { 42 EnsureSpace(4); 43 WriteLittleEndianValue<uint32_t>(pos_, x); 44 pos_ += 4; 45 } 46 47 void write_u32v(uint32_t val) { 48 EnsureSpace(kMaxVarInt32Size); 49 LEBHelper::write_u32v(&pos_, val); 50 } 51 52 void write_i32v(int32_t val) { 53 EnsureSpace(kMaxVarInt32Size); 54 LEBHelper::write_i32v(&pos_, val); 55 } 56 57 void write_size(size_t val) { 58 EnsureSpace(kMaxVarInt32Size); 59 DCHECK_EQ(val, static_cast<uint32_t>(val)); 60 LEBHelper::write_u32v(&pos_, static_cast<uint32_t>(val)); 61 } 62 63 void write(const byte* data, size_t size) { 64 EnsureSpace(size); 65 memcpy(pos_, data, size); 66 pos_ += size; 67 } 68 69 size_t reserve_u32v() { 70 size_t off = offset(); 71 EnsureSpace(kMaxVarInt32Size); 72 pos_ += kMaxVarInt32Size; 73 return off; 74 } 75 76 // Patch a (padded) u32v at the given offset to be the given value. 77 void patch_u32v(size_t offset, uint32_t val) { 78 byte* ptr = buffer_ + offset; 79 for (size_t pos = 0; pos != kPaddedVarInt32Size; ++pos) { 80 uint32_t next = val >> 7; 81 byte out = static_cast<byte>(val & 0x7f); 82 if (pos != kPaddedVarInt32Size - 1) { 83 *(ptr++) = 0x80 | out; 84 val = next; 85 } else { 86 *(ptr++) = out; 87 } 88 } 89 } 90 91 size_t offset() const { return static_cast<size_t>(pos_ - buffer_); } 92 size_t size() const { return static_cast<size_t>(pos_ - buffer_); } 93 const byte* begin() const { return buffer_; } 94 const byte* end() const { return pos_; } 95 96 void EnsureSpace(size_t size) { 97 if ((pos_ + size) > end_) { 98 size_t new_size = 4096 + size + (end_ - buffer_) * 3; 99 byte* new_buffer = reinterpret_cast<byte*>(zone_->New(new_size)); 100 memcpy(new_buffer, buffer_, (pos_ - buffer_)); 101 pos_ = new_buffer + (pos_ - buffer_); 102 buffer_ = new_buffer; 103 end_ = new_buffer + new_size; 104 } 105 DCHECK(pos_ + size <= end_); 106 } 107 108 byte** pos_ptr() { return &pos_; } 109 110 private: 111 Zone* zone_; 112 byte* buffer_; 113 byte* pos_; 114 byte* end_; 115 }; 116 117 class WasmModuleBuilder; 118 119 class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject { 120 public: 121 // Building methods. 122 void SetSignature(FunctionSig* sig); 123 uint32_t AddLocal(LocalType type); 124 void EmitVarInt(uint32_t val); 125 void EmitCode(const byte* code, uint32_t code_size); 126 void Emit(WasmOpcode opcode); 127 void EmitGetLocal(uint32_t index); 128 void EmitSetLocal(uint32_t index); 129 void EmitTeeLocal(uint32_t index); 130 void EmitI32Const(int32_t val); 131 void EmitWithU8(WasmOpcode opcode, const byte immediate); 132 void EmitWithU8U8(WasmOpcode opcode, const byte imm1, const byte imm2); 133 void EmitWithVarInt(WasmOpcode opcode, uint32_t immediate); 134 void EmitDirectCallIndex(uint32_t index); 135 void Export(); 136 void ExportAs(Vector<const char> name); 137 void SetName(Vector<const char> name); 138 void AddAsmWasmOffset(int asm_position); 139 140 void WriteSignature(ZoneBuffer& buffer) const; 141 void WriteExport(ZoneBuffer& buffer) const; 142 void WriteBody(ZoneBuffer& buffer) const; 143 void WriteAsmWasmOffsetTable(ZoneBuffer& buffer) const; 144 145 bool exported() { return exported_; } 146 uint32_t func_index() { return func_index_; } 147 FunctionSig* signature(); 148 149 private: 150 explicit WasmFunctionBuilder(WasmModuleBuilder* builder); 151 friend class WasmModuleBuilder; 152 friend class WasmTemporary; 153 154 struct DirectCallIndex { 155 size_t offset; 156 uint32_t direct_index; 157 }; 158 159 WasmModuleBuilder* builder_; 160 LocalDeclEncoder locals_; 161 uint32_t signature_index_; 162 bool exported_; 163 uint32_t func_index_; 164 ZoneVector<uint8_t> body_; 165 ZoneVector<char> name_; 166 ZoneVector<char> exported_name_; 167 ZoneVector<uint32_t> i32_temps_; 168 ZoneVector<uint32_t> i64_temps_; 169 ZoneVector<uint32_t> f32_temps_; 170 ZoneVector<uint32_t> f64_temps_; 171 ZoneVector<DirectCallIndex> direct_calls_; 172 173 // Delta-encoded mapping from wasm bytes to asm.js source positions. 174 ZoneBuffer asm_offsets_; 175 uint32_t last_asm_byte_offset_ = 0; 176 uint32_t last_asm_source_position_ = 0; 177 }; 178 179 class WasmTemporary { 180 public: 181 WasmTemporary(WasmFunctionBuilder* builder, LocalType type) { 182 switch (type) { 183 case kAstI32: 184 temporary_ = &builder->i32_temps_; 185 break; 186 case kAstI64: 187 temporary_ = &builder->i64_temps_; 188 break; 189 case kAstF32: 190 temporary_ = &builder->f32_temps_; 191 break; 192 case kAstF64: 193 temporary_ = &builder->f64_temps_; 194 break; 195 default: 196 UNREACHABLE(); 197 temporary_ = nullptr; 198 } 199 if (temporary_->size() == 0) { 200 // Allocate a new temporary. 201 index_ = builder->AddLocal(type); 202 } else { 203 // Reuse a previous temporary. 204 index_ = temporary_->back(); 205 temporary_->pop_back(); 206 } 207 } 208 ~WasmTemporary() { 209 temporary_->push_back(index_); // return the temporary to the list. 210 } 211 uint32_t index() { return index_; } 212 213 private: 214 ZoneVector<uint32_t>* temporary_; 215 uint32_t index_; 216 }; 217 218 class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject { 219 public: 220 explicit WasmModuleBuilder(Zone* zone); 221 222 // Building methods. 223 uint32_t AddImport(const char* name, int name_length, FunctionSig* sig); 224 void SetImportName(uint32_t index, const char* name, int name_length) { 225 imports_[index].name = name; 226 imports_[index].name_length = name_length; 227 } 228 WasmFunctionBuilder* AddFunction(FunctionSig* sig = nullptr); 229 uint32_t AddGlobal(LocalType type, bool exported, bool mutability = true, 230 const WasmInitExpr& init = WasmInitExpr()); 231 void AddDataSegment(const byte* data, uint32_t size, uint32_t dest); 232 uint32_t AddSignature(FunctionSig* sig); 233 void AddIndirectFunction(uint32_t index); 234 void MarkStartFunction(WasmFunctionBuilder* builder); 235 236 // Writing methods. 237 void WriteTo(ZoneBuffer& buffer) const; 238 void WriteAsmJsOffsetTable(ZoneBuffer& buffer) const; 239 240 // TODO(titzer): use SignatureMap from signature-map.h here. 241 // This signature map is zone-allocated, but the other is heap allocated. 242 struct CompareFunctionSigs { 243 bool operator()(FunctionSig* a, FunctionSig* b) const; 244 }; 245 typedef ZoneMap<FunctionSig*, uint32_t, CompareFunctionSigs> SignatureMap; 246 247 Zone* zone() { return zone_; } 248 249 FunctionSig* GetSignature(uint32_t index) { return signatures_[index]; } 250 251 private: 252 struct WasmFunctionImport { 253 uint32_t sig_index; 254 const char* name; 255 int name_length; 256 }; 257 258 struct WasmGlobal { 259 LocalType type; 260 bool exported; 261 bool mutability; 262 WasmInitExpr init; 263 }; 264 265 struct WasmDataSegment { 266 ZoneVector<byte> data; 267 uint32_t dest; 268 }; 269 270 friend class WasmFunctionBuilder; 271 Zone* zone_; 272 ZoneVector<FunctionSig*> signatures_; 273 ZoneVector<WasmFunctionImport> imports_; 274 ZoneVector<WasmFunctionBuilder*> functions_; 275 ZoneVector<WasmDataSegment> data_segments_; 276 ZoneVector<uint32_t> indirect_functions_; 277 ZoneVector<WasmGlobal> globals_; 278 SignatureMap signature_map_; 279 int start_function_index_; 280 }; 281 282 inline FunctionSig* WasmFunctionBuilder::signature() { 283 return builder_->signatures_[signature_index_]; 284 } 285 286 } // namespace wasm 287 } // namespace internal 288 } // namespace v8 289 290 #endif // V8_WASM_WASM_MODULE_BUILDER_H_ 291