wasm-module-builder.h 8.77 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef V8_WASM_WASM_MODULE_BUILDER_H_
#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/vector.h"
13
#include "src/wasm/leb-helper.h"
14
#include "src/wasm/local-decl-encoder.h"
15
#include "src/wasm/wasm-module.h"
16 17 18 19 20 21 22
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-result.h"

namespace v8 {
namespace internal {
namespace wasm {

23 24
class ZoneBuffer : public ZoneObject {
 public:
25
  static constexpr size_t kInitialSize = 1024;
26 27 28 29 30 31 32 33 34 35 36 37 38
  explicit ZoneBuffer(Zone* zone, size_t initial = kInitialSize)
      : zone_(zone), buffer_(reinterpret_cast<byte*>(zone->New(initial))) {
    pos_ = buffer_;
    end_ = buffer_ + initial;
  }

  void write_u8(uint8_t x) {
    EnsureSpace(1);
    *(pos_++) = x;
  }

  void write_u16(uint16_t x) {
    EnsureSpace(2);
39
    WriteLittleEndianValue<uint16_t>(reinterpret_cast<Address>(pos_), x);
40 41 42 43 44
    pos_ += 2;
  }

  void write_u32(uint32_t x) {
    EnsureSpace(4);
45
    WriteLittleEndianValue<uint32_t>(reinterpret_cast<Address>(pos_), x);
46 47 48
    pos_ += 4;
  }

49 50
  void write_u64(uint64_t x) {
    EnsureSpace(8);
51
    WriteLittleEndianValue<uint64_t>(reinterpret_cast<Address>(pos_), x);
52 53 54
    pos_ += 8;
  }

55 56 57 58 59
  void write_u32v(uint32_t val) {
    EnsureSpace(kMaxVarInt32Size);
    LEBHelper::write_u32v(&pos_, val);
  }

60 61 62 63 64
  void write_i32v(int32_t val) {
    EnsureSpace(kMaxVarInt32Size);
    LEBHelper::write_i32v(&pos_, val);
  }

65 66 67 68 69 70 71 72 73 74
  void write_u64v(uint64_t val) {
    EnsureSpace(kMaxVarInt64Size);
    LEBHelper::write_u64v(&pos_, val);
  }

  void write_i64v(int64_t val) {
    EnsureSpace(kMaxVarInt64Size);
    LEBHelper::write_i64v(&pos_, val);
  }

75 76 77 78 79 80
  void write_size(size_t val) {
    EnsureSpace(kMaxVarInt32Size);
    DCHECK_EQ(val, static_cast<uint32_t>(val));
    LEBHelper::write_u32v(&pos_, static_cast<uint32_t>(val));
  }

81 82 83 84
  void write_f32(float val) { write_u32(bit_cast<uint32_t>(val)); }

  void write_f64(double val) { write_u64(bit_cast<uint64_t>(val)); }

85 86 87 88 89 90
  void write(const byte* data, size_t size) {
    EnsureSpace(size);
    memcpy(pos_, data, size);
    pos_ += size;
  }

91 92
  void write_string(Vector<const char> name) {
    write_size(name.length());
93
    write(reinterpret_cast<const byte*>(name.begin()), name.length());
94 95
  }

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
  size_t reserve_u32v() {
    size_t off = offset();
    EnsureSpace(kMaxVarInt32Size);
    pos_ += kMaxVarInt32Size;
    return off;
  }

  // Patch a (padded) u32v at the given offset to be the given value.
  void patch_u32v(size_t offset, uint32_t val) {
    byte* ptr = buffer_ + offset;
    for (size_t pos = 0; pos != kPaddedVarInt32Size; ++pos) {
      uint32_t next = val >> 7;
      byte out = static_cast<byte>(val & 0x7f);
      if (pos != kPaddedVarInt32Size - 1) {
        *(ptr++) = 0x80 | out;
        val = next;
      } else {
        *(ptr++) = out;
      }
    }
  }

118 119 120 121 122
  void patch_u8(size_t offset, byte val) {
    DCHECK_GE(size(), offset);
    buffer_[offset] = val;
  }

123 124 125 126
  size_t offset() const { return static_cast<size_t>(pos_ - buffer_); }
  size_t size() const { return static_cast<size_t>(pos_ - buffer_); }
  const byte* begin() const { return buffer_; }
  const byte* end() const { return pos_; }
127 128 129

  void EnsureSpace(size_t size) {
    if ((pos_ + size) > end_) {
130
      size_t new_size = size + (end_ - buffer_) * 2;
131 132 133 134 135 136
      byte* new_buffer = reinterpret_cast<byte*>(zone_->New(new_size));
      memcpy(new_buffer, buffer_, (pos_ - buffer_));
      pos_ = new_buffer + (pos_ - buffer_);
      buffer_ = new_buffer;
      end_ = new_buffer + new_size;
    }
137
    DCHECK(pos_ + size <= end_);
138 139
  }

140 141 142 143 144
  void Truncate(size_t size) {
    DCHECK_GE(offset(), size);
    pos_ = buffer_ + size;
  }

145 146 147 148 149 150 151 152 153
  byte** pos_ptr() { return &pos_; }

 private:
  Zone* zone_;
  byte* buffer_;
  byte* pos_;
  byte* end_;
};

154 155
class WasmModuleBuilder;

156
class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject {
157
 public:
158
  // Building methods.
159
  void SetSignature(FunctionSig* sig);
160
  uint32_t AddLocal(ValueType type);
161 162
  void EmitI32V(int32_t val);
  void EmitU32V(uint32_t val);
163 164
  void EmitCode(const byte* code, uint32_t code_size);
  void Emit(WasmOpcode opcode);
165 166
  void EmitGetLocal(uint32_t index);
  void EmitSetLocal(uint32_t index);
167
  void EmitTeeLocal(uint32_t index);
168
  void EmitI32Const(int32_t val);
169 170 171
  void EmitI64Const(int64_t val);
  void EmitF32Const(float val);
  void EmitF64Const(double val);
172
  void EmitWithU8(WasmOpcode opcode, const byte immediate);
173
  void EmitWithU8U8(WasmOpcode opcode, const byte imm1, const byte imm2);
174 175
  void EmitWithI32V(WasmOpcode opcode, int32_t immediate);
  void EmitWithU32V(WasmOpcode opcode, uint32_t immediate);
176
  void EmitDirectCallIndex(uint32_t index);
177
  void SetName(Vector<const char> name);
178 179
  void AddAsmWasmOffset(size_t call_position, size_t to_number_position);
  void SetAsmFunctionStartPosition(size_t function_position);
180 181 182
  void SetCompilationHint(WasmCompilationHintStrategy strategy,
                          WasmCompilationHintTier baseline,
                          WasmCompilationHintTier top_tier);
183

184
  size_t GetPosition() const { return body_.size(); }
185 186 187
  void FixupByte(size_t position, byte value) {
    body_.patch_u8(position, value);
  }
188
  void DeleteCodeAfter(size_t position);
189

190 191
  void WriteSignature(ZoneBuffer& buffer) const;
  void WriteBody(ZoneBuffer& buffer) const;
192
  void WriteAsmWasmOffsetTable(ZoneBuffer& buffer) const;
193

194
  WasmModuleBuilder* builder() const { return builder_; }
195 196 197
  uint32_t func_index() { return func_index_; }
  FunctionSig* signature();

198
 private:
199
  explicit WasmFunctionBuilder(WasmModuleBuilder* builder);
200
  friend class WasmModuleBuilder;
201 202 203 204 205 206

  struct DirectCallIndex {
    size_t offset;
    uint32_t direct_index;
  };

207
  WasmModuleBuilder* builder_;
208
  LocalDeclEncoder locals_;
209
  uint32_t signature_index_;
210
  uint32_t func_index_;
211
  ZoneBuffer body_;
212
  Vector<const char> name_;
213 214 215 216
  ZoneVector<uint32_t> i32_temps_;
  ZoneVector<uint32_t> i64_temps_;
  ZoneVector<uint32_t> f32_temps_;
  ZoneVector<uint32_t> f64_temps_;
217
  ZoneVector<DirectCallIndex> direct_calls_;
218 219 220 221 222

  // Delta-encoded mapping from wasm bytes to asm.js source positions.
  ZoneBuffer asm_offsets_;
  uint32_t last_asm_byte_offset_ = 0;
  uint32_t last_asm_source_position_ = 0;
223
  uint32_t asm_func_start_source_position_ = 0;
224
  uint8_t hint_ = kNoCompilationHint;
225 226
};

227
class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
228 229
 public:
  explicit WasmModuleBuilder(Zone* zone);
230 231

  // Building methods.
232
  uint32_t AddImport(Vector<const char> name, FunctionSig* sig);
233
  WasmFunctionBuilder* AddFunction(FunctionSig* sig = nullptr);
234
  uint32_t AddGlobal(ValueType type, bool exported, bool mutability = true,
235
                     const WasmInitExpr& init = WasmInitExpr());
236
  uint32_t AddGlobalImport(Vector<const char> name, ValueType type);
237
  void AddDataSegment(const byte* data, uint32_t size, uint32_t dest);
238
  uint32_t AddSignature(FunctionSig* sig);
239 240
  uint32_t AllocateIndirectFunctions(uint32_t count);
  void SetIndirectFunction(uint32_t indirect, uint32_t direct);
241
  void MarkStartFunction(WasmFunctionBuilder* builder);
242
  void AddExport(Vector<const char> name, WasmFunctionBuilder* builder);
243
  void SetMinMemorySize(uint32_t value);
244
  void SetMaxMemorySize(uint32_t value);
245
  void SetHasSharedMemory();
246 247 248

  // Writing methods.
  void WriteTo(ZoneBuffer& buffer) const;
249
  void WriteAsmJsOffsetTable(ZoneBuffer& buffer) const;
250

251 252
  Zone* zone() { return zone_; }

253 254
  FunctionSig* GetSignature(uint32_t index) { return signatures_[index]; }

255
 private:
256
  struct WasmFunctionImport {
257
    Vector<const char> name;
258
    uint32_t sig_index;
259 260 261 262 263
  };

  struct WasmFunctionExport {
    Vector<const char> name;
    uint32_t function_index;
264 265
  };

266
  struct WasmGlobalImport {
267
    Vector<const char> name;
268 269 270
    ValueTypeCode type_code;
  };

271
  struct WasmGlobal {
272
    ValueType type;
273 274
    bool exported;
    bool mutability;
275
    WasmInitExpr init;
276 277 278 279 280 281 282
  };

  struct WasmDataSegment {
    ZoneVector<byte> data;
    uint32_t dest;
  };

283
  friend class WasmFunctionBuilder;
284 285
  Zone* zone_;
  ZoneVector<FunctionSig*> signatures_;
286
  ZoneVector<WasmFunctionImport> function_imports_;
287
  ZoneVector<WasmFunctionExport> function_exports_;
288
  ZoneVector<WasmGlobalImport> global_imports_;
289
  ZoneVector<WasmFunctionBuilder*> functions_;
290
  ZoneVector<WasmDataSegment> data_segments_;
291
  ZoneVector<uint32_t> indirect_functions_;
292
  ZoneVector<WasmGlobal> globals_;
293
  ZoneUnorderedMap<FunctionSig, uint32_t> signature_map_;
294
  int start_function_index_;
295
  uint32_t min_memory_size_;
296 297
  uint32_t max_memory_size_;
  bool has_max_memory_size_;
298
  bool has_shared_memory_;
299 300
};

301 302 303 304
inline FunctionSig* WasmFunctionBuilder::signature() {
  return builder_->signatures_[signature_index_];
}

305 306 307 308
}  // namespace wasm
}  // namespace internal
}  // namespace v8

309
#endif  // V8_WASM_WASM_MODULE_BUILDER_H_