5 #include "src/signature.h" 7 #include "src/handles.h" 8 #include "src/objects-inl.h" 10 #include "src/zone/zone-containers.h" 12 #include "src/wasm/function-body-decoder.h" 13 #include "src/wasm/leb-helper.h" 14 #include "src/wasm/wasm-constants.h" 15 #include "src/wasm/wasm-module-builder.h" 16 #include "src/wasm/wasm-module.h" 17 #include "src/wasm/wasm-opcodes.h" 19 #include "src/v8memory.h" 29 size_t EmitSection(SectionCode code, ZoneBuffer& buffer) {
31 buffer.write_u8(code);
34 return buffer.reserve_u32v();
38 void FixupSection(ZoneBuffer& buffer,
size_t start) {
39 buffer.patch_u32v(start, static_cast<uint32_t>(buffer.offset() - start -
40 kPaddedVarInt32Size));
45 WasmFunctionBuilder::WasmFunctionBuilder(WasmModuleBuilder* builder)
47 locals_(builder->zone()),
49 func_index_(static_cast<
uint32_t>(builder->functions_.size())),
50 body_(builder->zone(), 256),
51 i32_temps_(builder->zone()),
52 i64_temps_(builder->zone()),
53 f32_temps_(builder->zone()),
54 f64_temps_(builder->zone()),
55 direct_calls_(builder->zone()),
56 asm_offsets_(builder->zone(), 8) {}
58 void WasmFunctionBuilder::EmitI32V(int32_t val) { body_.write_i32v(val); }
60 void WasmFunctionBuilder::EmitU32V(
uint32_t val) { body_.write_u32v(val); }
62 void WasmFunctionBuilder::SetSignature(FunctionSig* sig) {
63 DCHECK(!locals_.has_sig());
65 signature_index_ = builder_->AddSignature(sig);
68 uint32_t WasmFunctionBuilder::AddLocal(ValueType type) {
69 DCHECK(locals_.has_sig());
70 return locals_.AddLocals(1, type);
73 void WasmFunctionBuilder::EmitGetLocal(
uint32_t local_index) {
74 EmitWithU32V(kExprGetLocal, local_index);
77 void WasmFunctionBuilder::EmitSetLocal(
uint32_t local_index) {
78 EmitWithU32V(kExprSetLocal, local_index);
81 void WasmFunctionBuilder::EmitTeeLocal(
uint32_t local_index) {
82 EmitWithU32V(kExprTeeLocal, local_index);
85 void WasmFunctionBuilder::EmitCode(
const byte* code,
uint32_t code_size) {
86 body_.write(code, code_size);
89 void WasmFunctionBuilder::Emit(WasmOpcode opcode) { body_.write_u8(opcode); }
91 void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode,
const byte immediate) {
92 body_.write_u8(opcode);
93 body_.write_u8(immediate);
96 void WasmFunctionBuilder::EmitWithU8U8(WasmOpcode opcode,
const byte imm1,
98 body_.write_u8(opcode);
100 body_.write_u8(imm2);
103 void WasmFunctionBuilder::EmitWithI32V(WasmOpcode opcode, int32_t immediate) {
104 body_.write_u8(opcode);
105 body_.write_i32v(immediate);
108 void WasmFunctionBuilder::EmitWithU32V(WasmOpcode opcode,
uint32_t immediate) {
109 body_.write_u8(opcode);
110 body_.write_u32v(immediate);
113 void WasmFunctionBuilder::EmitI32Const(int32_t value) {
114 EmitWithI32V(kExprI32Const, value);
117 void WasmFunctionBuilder::EmitI64Const(
int64_t value) {
118 body_.write_u8(kExprI64Const);
119 body_.write_i64v(value);
122 void WasmFunctionBuilder::EmitF32Const(
float value) {
123 body_.write_u8(kExprF32Const);
124 body_.write_f32(value);
127 void WasmFunctionBuilder::EmitF64Const(
double value) {
128 body_.write_u8(kExprF64Const);
129 body_.write_f64(value);
132 void WasmFunctionBuilder::EmitDirectCallIndex(
uint32_t index) {
133 DirectCallIndex call;
134 call.offset = body_.size();
135 call.direct_index = index;
136 direct_calls_.push_back(call);
137 byte placeholder_bytes[kMaxVarInt32Size] = {0};
138 EmitCode(placeholder_bytes, arraysize(placeholder_bytes));
141 void WasmFunctionBuilder::SetName(Vector<const char> name) { name_ = name; }
143 void WasmFunctionBuilder::AddAsmWasmOffset(
size_t call_position,
144 size_t to_number_position) {
146 DCHECK(asm_offsets_.size() == 0 || body_.size() > last_asm_byte_offset_);
148 DCHECK_LE(body_.size(), kMaxUInt32);
150 asm_offsets_.write_u32v(byte_offset - last_asm_byte_offset_);
151 last_asm_byte_offset_ = byte_offset;
153 DCHECK_GE(std::numeric_limits<uint32_t>::max(), call_position);
155 asm_offsets_.write_i32v(call_position_u32 - last_asm_source_position_);
157 DCHECK_GE(std::numeric_limits<uint32_t>::max(), to_number_position);
158 uint32_t to_number_position_u32 =
static_cast<uint32_t>(to_number_position);
159 asm_offsets_.write_i32v(to_number_position_u32 - call_position_u32);
160 last_asm_source_position_ = to_number_position_u32;
163 void WasmFunctionBuilder::SetAsmFunctionStartPosition(
164 size_t function_position) {
165 DCHECK_EQ(0, asm_func_start_source_position_);
166 DCHECK_GE(std::numeric_limits<uint32_t>::max(), function_position);
169 DCHECK_EQ(0, asm_offsets_.size());
170 asm_func_start_source_position_ = function_position_u32;
171 last_asm_source_position_ = function_position_u32;
174 void WasmFunctionBuilder::DeleteCodeAfter(
size_t position) {
175 DCHECK_LE(position, body_.size());
176 body_.Truncate(position);
179 void WasmFunctionBuilder::WriteSignature(ZoneBuffer& buffer)
const {
180 buffer.write_u32v(signature_index_);
183 void WasmFunctionBuilder::WriteBody(ZoneBuffer& buffer)
const {
184 size_t locals_size = locals_.Size();
185 buffer.write_size(locals_size + body_.size());
186 buffer.EnsureSpace(locals_size);
187 byte** ptr = buffer.pos_ptr();
189 (*ptr) += locals_size;
190 if (body_.size() > 0) {
191 size_t base = buffer.offset();
192 buffer.write(body_.begin(), body_.size());
193 for (DirectCallIndex call : direct_calls_) {
197 static_cast<uint32_t>(builder_->function_imports_.size()));
202 void WasmFunctionBuilder::WriteAsmWasmOffsetTable(ZoneBuffer& buffer)
const {
203 if (asm_func_start_source_position_ == 0 && asm_offsets_.size() == 0) {
204 buffer.write_size(0);
207 size_t locals_enc_size = LEBHelper::sizeof_u32v(locals_.Size());
208 size_t func_start_size =
209 LEBHelper::sizeof_u32v(asm_func_start_source_position_);
210 buffer.write_size(asm_offsets_.size() + locals_enc_size + func_start_size);
212 DCHECK_GE(kMaxUInt32, locals_.Size());
213 buffer.write_u32v(static_cast<uint32_t>(locals_.Size()));
215 buffer.write_u32v(asm_func_start_source_position_);
216 buffer.write(asm_offsets_.begin(), asm_offsets_.size());
219 WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
222 function_imports_(zone),
223 function_exports_(zone),
224 global_imports_(zone),
226 data_segments_(zone),
227 indirect_functions_(zone),
229 signature_map_(zone),
230 start_function_index_(-1),
231 min_memory_size_(16),
233 has_max_memory_size_(false),
234 has_shared_memory_(false) {}
236 WasmFunctionBuilder* WasmModuleBuilder::AddFunction(FunctionSig* sig) {
237 functions_.push_back(
new (zone_) WasmFunctionBuilder(
this));
239 if (sig) functions_.back()->SetSignature(sig);
240 return functions_.back();
243 void WasmModuleBuilder::AddDataSegment(
const byte* data,
uint32_t size,
245 data_segments_.push_back({ZoneVector<byte>(zone()), dest});
246 ZoneVector<byte>& vec = data_segments_.back().data;
248 vec.push_back(data[
i]);
252 uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
253 auto sig_entry = signature_map_.find(*sig);
254 if (sig_entry != signature_map_.end())
return sig_entry->second;
255 uint32_t index = static_cast<uint32_t>(signatures_.size());
256 signature_map_.emplace(*sig, index);
257 signatures_.push_back(sig);
263 DCHECK_GE(FLAG_wasm_max_table_size, index);
264 if (count > FLAG_wasm_max_table_size - index) {
265 return std::numeric_limits<uint32_t>::max();
267 indirect_functions_.resize(indirect_functions_.size() + count);
271 void WasmModuleBuilder::SetIndirectFunction(
uint32_t indirect,
273 indirect_functions_[indirect] = direct;
276 uint32_t WasmModuleBuilder::AddImport(Vector<const char> name,
278 function_imports_.push_back({name, AddSignature(sig)});
279 return static_cast<uint32_t>(function_imports_.size() - 1);
282 uint32_t WasmModuleBuilder::AddGlobalImport(Vector<const char> name,
284 global_imports_.push_back({name, ValueTypes::ValueTypeCodeFor(type)});
285 return static_cast<uint32_t>(global_imports_.size() - 1);
288 void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder*
function) {
289 start_function_index_ =
function->func_index();
292 void WasmModuleBuilder::AddExport(Vector<const char> name,
293 WasmFunctionBuilder*
function) {
294 function_exports_.push_back({name,
function->func_index()});
297 uint32_t WasmModuleBuilder::AddGlobal(ValueType type,
bool exported,
299 const WasmInitExpr& init) {
300 globals_.push_back({type, exported, mutability, init});
301 return static_cast<uint32_t>(globals_.size() - 1);
304 void WasmModuleBuilder::SetMinMemorySize(
uint32_t value) {
305 min_memory_size_ = value;
308 void WasmModuleBuilder::SetMaxMemorySize(
uint32_t value) {
309 has_max_memory_size_ =
true;
310 max_memory_size_ = value;
313 void WasmModuleBuilder::SetHasSharedMemory() { has_shared_memory_ =
true; }
315 void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer)
const {
317 buffer.write_u32(kWasmMagic);
318 buffer.write_u32(kWasmVersion);
321 if (signatures_.size() > 0) {
322 size_t start = EmitSection(kTypeSectionCode, buffer);
323 buffer.write_size(signatures_.size());
325 for (FunctionSig* sig : signatures_) {
326 buffer.write_u8(kWasmFunctionTypeCode);
327 buffer.write_size(sig->parameter_count());
328 for (
auto param : sig->parameters()) {
329 buffer.write_u8(ValueTypes::ValueTypeCodeFor(param));
331 buffer.write_size(sig->return_count());
332 for (
auto ret : sig->returns()) {
333 buffer.write_u8(ValueTypes::ValueTypeCodeFor(ret));
336 FixupSection(buffer, start);
340 if (global_imports_.size() + function_imports_.size() > 0) {
341 size_t start = EmitSection(kImportSectionCode, buffer);
342 buffer.write_size(global_imports_.size() + function_imports_.size());
343 for (
auto import : global_imports_) {
344 buffer.write_u32v(0);
345 buffer.write_string(
import.name);
346 buffer.write_u8(kExternalGlobal);
347 buffer.write_u8(
import.type_code);
350 for (
auto import : function_imports_) {
351 buffer.write_u32v(0);
352 buffer.write_string(
import.name);
353 buffer.write_u8(kExternalFunction);
354 buffer.write_u32v(
import.sig_index);
356 FixupSection(buffer, start);
361 if (functions_.size() > 0) {
362 size_t start = EmitSection(kFunctionSectionCode, buffer);
363 buffer.write_size(functions_.size());
364 for (
auto function : functions_) {
365 function->WriteSignature(buffer);
366 if (!function->name_.is_empty()) ++num_function_names;
368 FixupSection(buffer, start);
372 if (indirect_functions_.size() > 0) {
373 size_t start = EmitSection(kTableSectionCode, buffer);
375 buffer.write_u8(kLocalAnyFunc);
376 buffer.write_u8(kHasMaximumFlag);
377 buffer.write_size(indirect_functions_.size());
378 buffer.write_size(indirect_functions_.size());
379 FixupSection(buffer, start);
384 size_t start = EmitSection(kMemorySectionCode, buffer);
386 if (has_shared_memory_) {
387 buffer.write_u8(has_max_memory_size_ ? MemoryFlags::kSharedAndMaximum
388 : MemoryFlags::kSharedNoMaximum);
390 buffer.write_u8(has_max_memory_size_ ? MemoryFlags::kMaximum
391 : MemoryFlags::kNoMaximum);
393 buffer.write_u32v(min_memory_size_);
394 if (has_max_memory_size_) {
395 buffer.write_u32v(max_memory_size_);
397 FixupSection(buffer, start);
401 if (globals_.size() > 0) {
402 size_t start = EmitSection(kGlobalSectionCode, buffer);
403 buffer.write_size(globals_.size());
405 for (
auto global : globals_) {
406 buffer.write_u8(ValueTypes::ValueTypeCodeFor(global.type));
407 buffer.write_u8(global.mutability ? 1 : 0);
408 switch (global.init.kind) {
409 case WasmInitExpr::kI32Const:
410 DCHECK_EQ(kWasmI32, global.type);
411 buffer.write_u8(kExprI32Const);
412 buffer.write_i32v(global.init.val.i32_const);
414 case WasmInitExpr::kI64Const:
415 DCHECK_EQ(kWasmI64, global.type);
416 buffer.write_u8(kExprI64Const);
417 buffer.write_i64v(global.init.val.i64_const);
419 case WasmInitExpr::kF32Const:
420 DCHECK_EQ(kWasmF32, global.type);
421 buffer.write_u8(kExprF32Const);
422 buffer.write_f32(global.init.val.f32_const);
424 case WasmInitExpr::kF64Const:
425 DCHECK_EQ(kWasmF64, global.type);
426 buffer.write_u8(kExprF64Const);
427 buffer.write_f64(global.init.val.f64_const);
429 case WasmInitExpr::kGlobalIndex:
430 buffer.write_u8(kExprGetGlobal);
431 buffer.write_u32v(global.init.val.global_index);
435 switch (global.type) {
437 buffer.write_u8(kExprI32Const);
442 buffer.write_u8(kExprI64Const);
447 buffer.write_u8(kExprF32Const);
448 buffer.write_f32(0.f);
451 buffer.write_u8(kExprF64Const);
452 buffer.write_f64(0.);
459 buffer.write_u8(kExprEnd);
461 FixupSection(buffer, start);
465 if (!function_exports_.empty()) {
466 size_t start = EmitSection(kExportSectionCode, buffer);
467 buffer.write_size(function_exports_.size());
468 for (
auto function_export : function_exports_) {
469 buffer.write_string(function_export.name);
470 buffer.write_u8(kExternalFunction);
471 buffer.write_size(function_export.function_index +
472 function_imports_.size());
474 FixupSection(buffer, start);
478 if (start_function_index_ >= 0) {
479 size_t start = EmitSection(kStartSectionCode, buffer);
480 buffer.write_size(start_function_index_ + function_imports_.size());
481 FixupSection(buffer, start);
485 if (indirect_functions_.size() > 0) {
486 size_t start = EmitSection(kElementSectionCode, buffer);
489 buffer.write_u8(kExprI32Const);
490 buffer.write_u32v(0);
491 buffer.write_u8(kExprEnd);
492 buffer.write_size(indirect_functions_.size());
494 for (
auto index : indirect_functions_) {
495 buffer.write_size(index + function_imports_.size());
498 FixupSection(buffer, start);
502 if (functions_.size() > 0) {
503 size_t start = EmitSection(kCodeSectionCode, buffer);
504 buffer.write_size(functions_.size());
505 for (
auto function : functions_) {
506 function->WriteBody(buffer);
508 FixupSection(buffer, start);
512 if (data_segments_.size() > 0) {
513 size_t start = EmitSection(kDataSectionCode, buffer);
514 buffer.write_size(data_segments_.size());
516 for (
auto segment : data_segments_) {
518 buffer.write_u8(kExprI32Const);
519 buffer.write_u32v(segment.dest);
520 buffer.write_u8(kExprEnd);
521 buffer.write_u32v(static_cast<uint32_t>(segment.data.size()));
522 buffer.write(&segment.data[0], segment.data.size());
524 FixupSection(buffer, start);
528 if (num_function_names > 0 || !function_imports_.empty()) {
530 buffer.write_u8(kUnknownSectionCode);
532 size_t start = buffer.reserve_u32v();
534 buffer.write_size(4);
535 buffer.write(reinterpret_cast<const byte*>(
"name"), 4);
537 buffer.write_u8(NameSectionKindCode::kFunction);
539 size_t functions_start = buffer.reserve_u32v();
543 buffer.write_size(num_imports + num_function_names);
545 for (; function_index < num_imports; ++function_index) {
546 const WasmFunctionImport*
import = &function_imports_[function_index];
547 DCHECK(!import->name.is_empty());
548 buffer.write_u32v(function_index);
549 buffer.write_string(import->name);
551 if (num_function_names > 0) {
552 for (
auto function : functions_) {
553 DCHECK_EQ(function_index,
554 function->func_index() + function_imports_.size());
555 if (!function->name_.is_empty()) {
556 buffer.write_u32v(function_index);
557 buffer.write_string(function->name_);
562 FixupSection(buffer, functions_start);
563 FixupSection(buffer, start);
567 void WasmModuleBuilder::WriteAsmJsOffsetTable(ZoneBuffer& buffer)
const {
569 buffer.write_size(functions_.size());
571 for (
auto function : functions_) {
572 function->WriteAsmWasmOffsetTable(buffer);