2015-12-11 12:26:16 +00:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
#include "src/signature.h"
|
|
|
|
|
|
|
|
#include "src/handles.h"
|
2017-02-13 09:52:26 +00:00
|
|
|
#include "src/objects-inl.h"
|
2015-12-11 12:26:16 +00:00
|
|
|
#include "src/v8.h"
|
2016-09-20 16:07:25 +00:00
|
|
|
#include "src/zone/zone-containers.h"
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2016-12-21 12:42:06 +00:00
|
|
|
#include "src/wasm/function-body-decoder.h"
|
2016-04-21 10:14:34 +00:00
|
|
|
#include "src/wasm/leb-helper.h"
|
2018-01-11 11:49:29 +00:00
|
|
|
#include "src/wasm/wasm-constants.h"
|
2016-09-29 11:29:05 +00:00
|
|
|
#include "src/wasm/wasm-module-builder.h"
|
2015-12-11 12:26:16 +00:00
|
|
|
#include "src/wasm/wasm-module.h"
|
|
|
|
#include "src/wasm/wasm-opcodes.h"
|
|
|
|
|
|
|
|
#include "src/v8memory.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace wasm {
|
|
|
|
|
2017-04-25 10:45:46 +00:00
|
|
|
namespace {
|
|
|
|
|
2016-09-27 20:46:10 +00:00
|
|
|
// Emit a section code and the size as a padded varint that can be patched
|
2016-05-25 16:12:09 +00:00
|
|
|
// later.
|
2017-04-07 14:37:30 +00:00
|
|
|
size_t EmitSection(SectionCode code, ZoneBuffer& buffer) {
|
2016-09-27 20:46:10 +00:00
|
|
|
// Emit the section code.
|
|
|
|
buffer.write_u8(code);
|
2016-04-21 11:18:41 +00:00
|
|
|
|
2016-04-29 09:39:26 +00:00
|
|
|
// Emit a placeholder for the length.
|
2016-05-25 16:12:09 +00:00
|
|
|
return buffer.reserve_u32v();
|
|
|
|
}
|
2016-04-29 09:39:26 +00:00
|
|
|
|
2016-05-25 16:12:09 +00:00
|
|
|
// Patch the size of a section after it's finished.
|
|
|
|
void FixupSection(ZoneBuffer& buffer, size_t start) {
|
|
|
|
buffer.patch_u32v(start, static_cast<uint32_t>(buffer.offset() - start -
|
|
|
|
kPaddedVarInt32Size));
|
2016-03-10 12:36:42 +00:00
|
|
|
}
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2017-04-25 10:45:46 +00:00
|
|
|
} // namespace
|
|
|
|
|
2016-05-27 12:15:23 +00:00
|
|
|
WasmFunctionBuilder::WasmFunctionBuilder(WasmModuleBuilder* builder)
|
|
|
|
: builder_(builder),
|
|
|
|
locals_(builder->zone()),
|
|
|
|
signature_index_(0),
|
2016-10-03 21:04:29 +00:00
|
|
|
func_index_(static_cast<uint32_t>(builder->functions_.size())),
|
2017-05-19 08:47:09 +00:00
|
|
|
body_(builder->zone(), 256),
|
2016-08-30 09:42:34 +00:00
|
|
|
i32_temps_(builder->zone()),
|
|
|
|
i64_temps_(builder->zone()),
|
|
|
|
f32_temps_(builder->zone()),
|
2016-10-03 21:04:29 +00:00
|
|
|
f64_temps_(builder->zone()),
|
2016-10-12 09:17:12 +00:00
|
|
|
direct_calls_(builder->zone()),
|
|
|
|
asm_offsets_(builder->zone(), 8) {}
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2017-04-25 10:45:46 +00:00
|
|
|
void WasmFunctionBuilder::EmitI32V(int32_t val) { body_.write_i32v(val); }
|
2017-02-14 18:15:31 +00:00
|
|
|
|
2017-04-25 10:45:46 +00:00
|
|
|
void WasmFunctionBuilder::EmitU32V(uint32_t val) { body_.write_u32v(val); }
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2016-05-17 17:53:46 +00:00
|
|
|
void WasmFunctionBuilder::SetSignature(FunctionSig* sig) {
|
|
|
|
DCHECK(!locals_.has_sig());
|
|
|
|
locals_.set_sig(sig);
|
2016-05-27 12:15:23 +00:00
|
|
|
signature_index_ = builder_->AddSignature(sig);
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
2016-12-21 13:43:00 +00:00
|
|
|
uint32_t WasmFunctionBuilder::AddLocal(ValueType type) {
|
2016-05-17 17:53:46 +00:00
|
|
|
DCHECK(locals_.has_sig());
|
|
|
|
return locals_.AddLocals(1, type);
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
2016-04-18 20:57:05 +00:00
|
|
|
void WasmFunctionBuilder::EmitGetLocal(uint32_t local_index) {
|
2017-04-25 10:45:46 +00:00
|
|
|
EmitWithU32V(kExprGetLocal, local_index);
|
2016-04-18 20:57:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void WasmFunctionBuilder::EmitSetLocal(uint32_t local_index) {
|
2017-04-25 10:45:46 +00:00
|
|
|
EmitWithU32V(kExprSetLocal, local_index);
|
2016-04-18 20:57:05 +00:00
|
|
|
}
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2016-09-27 20:46:10 +00:00
|
|
|
void WasmFunctionBuilder::EmitTeeLocal(uint32_t local_index) {
|
2017-04-25 10:45:46 +00:00
|
|
|
EmitWithU32V(kExprTeeLocal, local_index);
|
2016-09-27 20:46:10 +00:00
|
|
|
}
|
|
|
|
|
2016-05-17 17:53:46 +00:00
|
|
|
void WasmFunctionBuilder::EmitCode(const byte* code, uint32_t code_size) {
|
2017-04-25 10:45:46 +00:00
|
|
|
body_.write(code, code_size);
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
2017-04-25 10:45:46 +00:00
|
|
|
void WasmFunctionBuilder::Emit(WasmOpcode opcode) { body_.write_u8(opcode); }
|
2015-12-11 12:26:16 +00:00
|
|
|
|
|
|
|
void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
|
2017-04-25 10:45:46 +00:00
|
|
|
body_.write_u8(opcode);
|
|
|
|
body_.write_u8(immediate);
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
2016-03-09 18:51:28 +00:00
|
|
|
void WasmFunctionBuilder::EmitWithU8U8(WasmOpcode opcode, const byte imm1,
|
|
|
|
const byte imm2) {
|
2017-04-25 10:45:46 +00:00
|
|
|
body_.write_u8(opcode);
|
|
|
|
body_.write_u8(imm1);
|
|
|
|
body_.write_u8(imm2);
|
2016-03-09 18:51:28 +00:00
|
|
|
}
|
|
|
|
|
2017-04-25 10:45:46 +00:00
|
|
|
void WasmFunctionBuilder::EmitWithI32V(WasmOpcode opcode, int32_t immediate) {
|
|
|
|
body_.write_u8(opcode);
|
|
|
|
body_.write_i32v(immediate);
|
2017-02-14 18:15:31 +00:00
|
|
|
}
|
|
|
|
|
2017-04-25 10:45:46 +00:00
|
|
|
void WasmFunctionBuilder::EmitWithU32V(WasmOpcode opcode, uint32_t immediate) {
|
|
|
|
body_.write_u8(opcode);
|
|
|
|
body_.write_u32v(immediate);
|
2016-03-08 22:54:43 +00:00
|
|
|
}
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2016-04-29 09:15:26 +00:00
|
|
|
void WasmFunctionBuilder::EmitI32Const(int32_t value) {
|
2017-04-25 10:45:46 +00:00
|
|
|
EmitWithI32V(kExprI32Const, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WasmFunctionBuilder::EmitI64Const(int64_t value) {
|
|
|
|
body_.write_u8(kExprI64Const);
|
|
|
|
body_.write_i64v(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WasmFunctionBuilder::EmitF32Const(float value) {
|
|
|
|
body_.write_u8(kExprF32Const);
|
|
|
|
body_.write_f32(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WasmFunctionBuilder::EmitF64Const(double value) {
|
|
|
|
body_.write_u8(kExprF64Const);
|
|
|
|
body_.write_f64(value);
|
2016-04-29 09:15:26 +00:00
|
|
|
}
|
|
|
|
|
2016-10-03 21:04:29 +00:00
|
|
|
void WasmFunctionBuilder::EmitDirectCallIndex(uint32_t index) {
|
|
|
|
DirectCallIndex call;
|
|
|
|
call.offset = body_.size();
|
|
|
|
call.direct_index = index;
|
|
|
|
direct_calls_.push_back(call);
|
2017-04-25 10:45:46 +00:00
|
|
|
byte placeholder_bytes[kMaxVarInt32Size] = {0};
|
|
|
|
EmitCode(placeholder_bytes, arraysize(placeholder_bytes));
|
2016-10-03 21:04:29 +00:00
|
|
|
}
|
|
|
|
|
2017-05-11 08:15:46 +00:00
|
|
|
void WasmFunctionBuilder::SetName(Vector<const char> name) { name_ = name; }
|
2016-01-13 01:23:43 +00:00
|
|
|
|
2018-01-09 14:12:04 +00:00
|
|
|
void WasmFunctionBuilder::AddAsmWasmOffset(size_t call_position,
|
|
|
|
size_t to_number_position) {
|
2017-01-09 09:43:04 +00:00
|
|
|
// We only want to emit one mapping per byte offset.
|
2016-10-12 09:17:12 +00:00
|
|
|
DCHECK(asm_offsets_.size() == 0 || body_.size() > last_asm_byte_offset_);
|
|
|
|
|
|
|
|
DCHECK_LE(body_.size(), kMaxUInt32);
|
|
|
|
uint32_t byte_offset = static_cast<uint32_t>(body_.size());
|
|
|
|
asm_offsets_.write_u32v(byte_offset - last_asm_byte_offset_);
|
|
|
|
last_asm_byte_offset_ = byte_offset;
|
|
|
|
|
2018-01-09 14:12:04 +00:00
|
|
|
DCHECK_GE(std::numeric_limits<uint32_t>::max(), call_position);
|
|
|
|
uint32_t call_position_u32 = static_cast<uint32_t>(call_position);
|
|
|
|
asm_offsets_.write_i32v(call_position_u32 - last_asm_source_position_);
|
2016-12-09 10:29:53 +00:00
|
|
|
|
2018-01-09 14:12:04 +00:00
|
|
|
DCHECK_GE(std::numeric_limits<uint32_t>::max(), to_number_position);
|
|
|
|
uint32_t to_number_position_u32 = static_cast<uint32_t>(to_number_position);
|
|
|
|
asm_offsets_.write_i32v(to_number_position_u32 - call_position_u32);
|
|
|
|
last_asm_source_position_ = to_number_position_u32;
|
2016-10-12 09:17:12 +00:00
|
|
|
}
|
|
|
|
|
2018-01-09 14:12:04 +00:00
|
|
|
void WasmFunctionBuilder::SetAsmFunctionStartPosition(
|
|
|
|
size_t function_position) {
|
2017-01-09 09:43:04 +00:00
|
|
|
DCHECK_EQ(0, asm_func_start_source_position_);
|
2018-01-09 14:12:04 +00:00
|
|
|
DCHECK_GE(std::numeric_limits<uint32_t>::max(), function_position);
|
|
|
|
uint32_t function_position_u32 = static_cast<uint32_t>(function_position);
|
2017-01-09 09:43:04 +00:00
|
|
|
// Must be called before emitting any asm.js source position.
|
|
|
|
DCHECK_EQ(0, asm_offsets_.size());
|
2018-01-09 14:12:04 +00:00
|
|
|
asm_func_start_source_position_ = function_position_u32;
|
|
|
|
last_asm_source_position_ = function_position_u32;
|
2017-01-09 09:43:04 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 07:58:43 +00:00
|
|
|
void WasmFunctionBuilder::DeleteCodeAfter(size_t position) {
|
2017-03-28 17:43:09 +00:00
|
|
|
DCHECK_LE(position, body_.size());
|
2017-04-25 10:45:46 +00:00
|
|
|
body_.Truncate(position);
|
2017-03-24 05:53:50 +00:00
|
|
|
}
|
|
|
|
|
2016-05-27 12:15:23 +00:00
|
|
|
void WasmFunctionBuilder::WriteSignature(ZoneBuffer& buffer) const {
|
2016-05-25 16:12:09 +00:00
|
|
|
buffer.write_u32v(signature_index_);
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
2016-05-27 12:15:23 +00:00
|
|
|
void WasmFunctionBuilder::WriteBody(ZoneBuffer& buffer) const {
|
2016-05-25 16:12:09 +00:00
|
|
|
size_t locals_size = locals_.Size();
|
|
|
|
buffer.write_size(locals_size + body_.size());
|
|
|
|
buffer.EnsureSpace(locals_size);
|
|
|
|
byte** ptr = buffer.pos_ptr();
|
|
|
|
locals_.Emit(*ptr);
|
|
|
|
(*ptr) += locals_size; // UGLY: manual bump of position pointer
|
2016-05-13 08:44:28 +00:00
|
|
|
if (body_.size() > 0) {
|
2016-10-03 21:04:29 +00:00
|
|
|
size_t base = buffer.offset();
|
2017-04-25 10:45:46 +00:00
|
|
|
buffer.write(body_.begin(), body_.size());
|
2016-10-03 21:04:29 +00:00
|
|
|
for (DirectCallIndex call : direct_calls_) {
|
|
|
|
buffer.patch_u32v(
|
|
|
|
base + call.offset,
|
2017-03-24 05:53:50 +00:00
|
|
|
call.direct_index +
|
|
|
|
static_cast<uint32_t>(builder_->function_imports_.size()));
|
2016-10-03 21:04:29 +00:00
|
|
|
}
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-12 09:17:12 +00:00
|
|
|
void WasmFunctionBuilder::WriteAsmWasmOffsetTable(ZoneBuffer& buffer) const {
|
2017-01-09 09:43:04 +00:00
|
|
|
if (asm_func_start_source_position_ == 0 && asm_offsets_.size() == 0) {
|
2016-10-12 09:17:12 +00:00
|
|
|
buffer.write_size(0);
|
|
|
|
return;
|
|
|
|
}
|
2017-01-09 09:43:04 +00:00
|
|
|
size_t locals_enc_size = LEBHelper::sizeof_u32v(locals_.Size());
|
|
|
|
size_t func_start_size =
|
|
|
|
LEBHelper::sizeof_u32v(asm_func_start_source_position_);
|
|
|
|
buffer.write_size(asm_offsets_.size() + locals_enc_size + func_start_size);
|
2016-10-12 09:17:12 +00:00
|
|
|
// Offset of the recorded byte offsets.
|
|
|
|
DCHECK_GE(kMaxUInt32, locals_.Size());
|
2017-01-09 09:43:04 +00:00
|
|
|
buffer.write_u32v(static_cast<uint32_t>(locals_.Size()));
|
|
|
|
// Start position of the function.
|
|
|
|
buffer.write_u32v(asm_func_start_source_position_);
|
2016-10-12 09:17:12 +00:00
|
|
|
buffer.write(asm_offsets_.begin(), asm_offsets_.size());
|
|
|
|
}
|
|
|
|
|
2015-12-11 12:26:16 +00:00
|
|
|
WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
|
|
|
|
: zone_(zone),
|
|
|
|
signatures_(zone),
|
2017-03-24 05:53:50 +00:00
|
|
|
function_imports_(zone),
|
2017-05-12 11:06:25 +00:00
|
|
|
function_exports_(zone),
|
2017-03-24 05:53:50 +00:00
|
|
|
global_imports_(zone),
|
2015-12-11 12:26:16 +00:00
|
|
|
functions_(zone),
|
|
|
|
data_segments_(zone),
|
|
|
|
indirect_functions_(zone),
|
|
|
|
globals_(zone),
|
2016-03-01 05:49:51 +00:00
|
|
|
signature_map_(zone),
|
2017-08-28 14:19:46 +00:00
|
|
|
start_function_index_(-1),
|
2017-08-29 08:47:47 +00:00
|
|
|
min_memory_size_(16),
|
|
|
|
max_memory_size_(0),
|
2017-09-14 06:14:48 +00:00
|
|
|
has_max_memory_size_(false),
|
|
|
|
has_shared_memory_(false) {}
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2016-09-27 20:46:10 +00:00
|
|
|
WasmFunctionBuilder* WasmModuleBuilder::AddFunction(FunctionSig* sig) {
|
2016-05-27 12:15:23 +00:00
|
|
|
functions_.push_back(new (zone_) WasmFunctionBuilder(this));
|
2016-09-27 20:46:10 +00:00
|
|
|
// Add the signature if one was provided here.
|
|
|
|
if (sig) functions_.back()->SetSignature(sig);
|
|
|
|
return functions_.back();
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
2016-09-29 18:12:45 +00:00
|
|
|
void WasmModuleBuilder::AddDataSegment(const byte* data, uint32_t size,
|
|
|
|
uint32_t dest) {
|
|
|
|
data_segments_.push_back({ZoneVector<byte>(zone()), dest});
|
|
|
|
ZoneVector<byte>& vec = data_segments_.back().data;
|
|
|
|
for (uint32_t i = 0; i < size; i++) {
|
|
|
|
vec.push_back(data[i]);
|
|
|
|
}
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
2016-05-13 08:44:28 +00:00
|
|
|
uint32_t WasmModuleBuilder::AddSignature(FunctionSig* sig) {
|
2018-07-12 11:41:34 +00:00
|
|
|
auto sig_entry = signature_map_.find(*sig);
|
|
|
|
if (sig_entry != signature_map_.end()) return sig_entry->second;
|
|
|
|
uint32_t index = static_cast<uint32_t>(signatures_.size());
|
|
|
|
signature_map_.emplace(*sig, index);
|
|
|
|
signatures_.push_back(sig);
|
|
|
|
return index;
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
2016-11-30 00:25:21 +00:00
|
|
|
uint32_t WasmModuleBuilder::AllocateIndirectFunctions(uint32_t count) {
|
2017-05-19 13:39:07 +00:00
|
|
|
uint32_t index = static_cast<uint32_t>(indirect_functions_.size());
|
|
|
|
DCHECK_GE(FLAG_wasm_max_table_size, index);
|
|
|
|
if (count > FLAG_wasm_max_table_size - index) {
|
|
|
|
return std::numeric_limits<uint32_t>::max();
|
|
|
|
}
|
2016-11-30 00:25:21 +00:00
|
|
|
indirect_functions_.resize(indirect_functions_.size() + count);
|
2017-05-19 13:39:07 +00:00
|
|
|
return index;
|
2016-11-30 00:25:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void WasmModuleBuilder::SetIndirectFunction(uint32_t indirect,
|
|
|
|
uint32_t direct) {
|
|
|
|
indirect_functions_[indirect] = direct;
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
2017-05-09 09:39:09 +00:00
|
|
|
uint32_t WasmModuleBuilder::AddImport(Vector<const char> name,
|
2016-05-13 08:44:28 +00:00
|
|
|
FunctionSig* sig) {
|
2017-05-12 11:06:25 +00:00
|
|
|
function_imports_.push_back({name, AddSignature(sig)});
|
2017-03-24 05:53:50 +00:00
|
|
|
return static_cast<uint32_t>(function_imports_.size() - 1);
|
|
|
|
}
|
|
|
|
|
2017-05-09 09:39:09 +00:00
|
|
|
uint32_t WasmModuleBuilder::AddGlobalImport(Vector<const char> name,
|
2017-03-24 05:53:50 +00:00
|
|
|
ValueType type) {
|
2018-04-24 13:07:51 +00:00
|
|
|
global_imports_.push_back({name, ValueTypes::ValueTypeCodeFor(type)});
|
2017-03-24 05:53:50 +00:00
|
|
|
return static_cast<uint32_t>(global_imports_.size() - 1);
|
2016-05-13 08:44:28 +00:00
|
|
|
}
|
|
|
|
|
2016-09-27 20:46:10 +00:00
|
|
|
void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) {
|
|
|
|
start_function_index_ = function->func_index();
|
2016-03-01 05:49:51 +00:00
|
|
|
}
|
2015-12-11 12:26:16 +00:00
|
|
|
|
2017-05-12 11:06:25 +00:00
|
|
|
void WasmModuleBuilder::AddExport(Vector<const char> name,
|
|
|
|
WasmFunctionBuilder* function) {
|
|
|
|
function_exports_.push_back({name, function->func_index()});
|
|
|
|
}
|
|
|
|
|
2016-12-21 13:43:00 +00:00
|
|
|
uint32_t WasmModuleBuilder::AddGlobal(ValueType type, bool exported,
|
2016-10-06 15:43:10 +00:00
|
|
|
bool mutability,
|
|
|
|
const WasmInitExpr& init) {
|
|
|
|
globals_.push_back({type, exported, mutability, init});
|
2015-12-11 12:26:16 +00:00
|
|
|
return static_cast<uint32_t>(globals_.size() - 1);
|
|
|
|
}
|
|
|
|
|
2017-08-28 14:19:46 +00:00
|
|
|
void WasmModuleBuilder::SetMinMemorySize(uint32_t value) {
|
|
|
|
min_memory_size_ = value;
|
|
|
|
}
|
|
|
|
|
2017-08-29 08:47:47 +00:00
|
|
|
void WasmModuleBuilder::SetMaxMemorySize(uint32_t value) {
|
|
|
|
has_max_memory_size_ = true;
|
|
|
|
max_memory_size_ = value;
|
|
|
|
}
|
|
|
|
|
2017-09-14 06:14:48 +00:00
|
|
|
void WasmModuleBuilder::SetHasSharedMemory() { has_shared_memory_ = true; }
|
|
|
|
|
2016-05-27 12:15:23 +00:00
|
|
|
void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
|
2016-05-25 16:12:09 +00:00
|
|
|
// == Emit magic =============================================================
|
|
|
|
buffer.write_u32(kWasmMagic);
|
|
|
|
buffer.write_u32(kWasmVersion);
|
2016-02-28 00:37:11 +00:00
|
|
|
|
2016-05-25 16:12:09 +00:00
|
|
|
// == Emit signatures ========================================================
|
2015-12-11 12:26:16 +00:00
|
|
|
if (signatures_.size() > 0) {
|
2016-09-27 20:46:10 +00:00
|
|
|
size_t start = EmitSection(kTypeSectionCode, buffer);
|
2016-05-25 16:12:09 +00:00
|
|
|
buffer.write_size(signatures_.size());
|
2015-12-11 12:26:16 +00:00
|
|
|
|
|
|
|
for (FunctionSig* sig : signatures_) {
|
2018-01-11 11:49:29 +00:00
|
|
|
buffer.write_u8(kWasmFunctionTypeCode);
|
2016-05-25 16:12:09 +00:00
|
|
|
buffer.write_size(sig->parameter_count());
|
2017-03-16 10:23:59 +00:00
|
|
|
for (auto param : sig->parameters()) {
|
2018-04-24 13:07:51 +00:00
|
|
|
buffer.write_u8(ValueTypes::ValueTypeCodeFor(param));
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
2016-05-25 16:12:09 +00:00
|
|
|
buffer.write_size(sig->return_count());
|
2017-03-16 10:23:59 +00:00
|
|
|
for (auto ret : sig->returns()) {
|
2018-04-24 13:07:51 +00:00
|
|
|
buffer.write_u8(ValueTypes::ValueTypeCodeFor(ret));
|
2016-04-29 09:39:26 +00:00
|
|
|
}
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
2016-05-25 16:12:09 +00:00
|
|
|
FixupSection(buffer, start);
|
|
|
|
}
|
|
|
|
|
|
|
|
// == Emit imports ===========================================================
|
2017-03-24 05:53:50 +00:00
|
|
|
if (global_imports_.size() + function_imports_.size() > 0) {
|
2016-09-27 20:46:10 +00:00
|
|
|
size_t start = EmitSection(kImportSectionCode, buffer);
|
2017-03-24 05:53:50 +00:00
|
|
|
buffer.write_size(global_imports_.size() + function_imports_.size());
|
|
|
|
for (auto import : global_imports_) {
|
2017-05-12 11:06:25 +00:00
|
|
|
buffer.write_u32v(0); // module name (length)
|
|
|
|
buffer.write_string(import.name); // field name
|
2017-03-24 05:53:50 +00:00
|
|
|
buffer.write_u8(kExternalGlobal);
|
|
|
|
buffer.write_u8(import.type_code);
|
|
|
|
buffer.write_u8(0); // immutable
|
|
|
|
}
|
|
|
|
for (auto import : function_imports_) {
|
2017-05-12 11:06:25 +00:00
|
|
|
buffer.write_u32v(0); // module name (length)
|
|
|
|
buffer.write_string(import.name); // field name
|
2016-09-27 20:46:10 +00:00
|
|
|
buffer.write_u8(kExternalFunction);
|
|
|
|
buffer.write_u32v(import.sig_index);
|
2016-05-13 08:44:28 +00:00
|
|
|
}
|
2016-05-25 16:12:09 +00:00
|
|
|
FixupSection(buffer, start);
|
2016-05-13 08:44:28 +00:00
|
|
|
}
|
|
|
|
|
2016-05-25 16:12:09 +00:00
|
|
|
// == Emit function signatures ===============================================
|
2017-04-07 14:37:30 +00:00
|
|
|
uint32_t num_function_names = 0;
|
2015-12-11 12:26:16 +00:00
|
|
|
if (functions_.size() > 0) {
|
2016-09-27 20:46:10 +00:00
|
|
|
size_t start = EmitSection(kFunctionSectionCode, buffer);
|
2016-05-25 16:12:09 +00:00
|
|
|
buffer.write_size(functions_.size());
|
|
|
|
for (auto function : functions_) {
|
|
|
|
function->WriteSignature(buffer);
|
2017-05-11 08:15:46 +00:00
|
|
|
if (!function->name_.is_empty()) ++num_function_names;
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
2016-05-25 16:12:09 +00:00
|
|
|
FixupSection(buffer, start);
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
2016-05-25 16:12:09 +00:00
|
|
|
// == emit function table ====================================================
|
2016-04-21 11:18:41 +00:00
|
|
|
if (indirect_functions_.size() > 0) {
|
2016-09-27 20:46:10 +00:00
|
|
|
size_t start = EmitSection(kTableSectionCode, buffer);
|
|
|
|
buffer.write_u8(1); // table count
|
2018-07-10 12:14:06 +00:00
|
|
|
buffer.write_u8(kLocalAnyFunc);
|
2017-10-13 07:30:13 +00:00
|
|
|
buffer.write_u8(kHasMaximumFlag);
|
2016-09-27 20:46:10 +00:00
|
|
|
buffer.write_size(indirect_functions_.size());
|
2016-05-25 16:12:09 +00:00
|
|
|
buffer.write_size(indirect_functions_.size());
|
|
|
|
FixupSection(buffer, start);
|
2016-04-21 11:18:41 +00:00
|
|
|
}
|
|
|
|
|
2016-05-25 16:12:09 +00:00
|
|
|
// == emit memory declaration ================================================
|
2016-04-21 11:18:41 +00:00
|
|
|
{
|
2016-09-27 20:46:10 +00:00
|
|
|
size_t start = EmitSection(kMemorySectionCode, buffer);
|
2017-08-29 08:47:47 +00:00
|
|
|
buffer.write_u8(1); // memory count
|
2017-09-14 06:14:48 +00:00
|
|
|
if (has_shared_memory_) {
|
|
|
|
buffer.write_u8(has_max_memory_size_ ? MemoryFlags::kSharedAndMaximum
|
|
|
|
: MemoryFlags::kSharedNoMaximum);
|
|
|
|
} else {
|
|
|
|
buffer.write_u8(has_max_memory_size_ ? MemoryFlags::kMaximum
|
|
|
|
: MemoryFlags::kNoMaximum);
|
|
|
|
}
|
2017-08-29 08:47:47 +00:00
|
|
|
buffer.write_u32v(min_memory_size_);
|
|
|
|
if (has_max_memory_size_) {
|
|
|
|
buffer.write_u32v(max_memory_size_);
|
|
|
|
}
|
2016-09-27 20:46:10 +00:00
|
|
|
FixupSection(buffer, start);
|
|
|
|
}
|
|
|
|
|
|
|
|
// == Emit globals ===========================================================
|
|
|
|
if (globals_.size() > 0) {
|
|
|
|
size_t start = EmitSection(kGlobalSectionCode, buffer);
|
|
|
|
buffer.write_size(globals_.size());
|
|
|
|
|
|
|
|
for (auto global : globals_) {
|
2018-04-24 13:07:51 +00:00
|
|
|
buffer.write_u8(ValueTypes::ValueTypeCodeFor(global.type));
|
2016-09-29 18:12:45 +00:00
|
|
|
buffer.write_u8(global.mutability ? 1 : 0);
|
2016-10-06 15:43:10 +00:00
|
|
|
switch (global.init.kind) {
|
2017-04-25 10:45:46 +00:00
|
|
|
case WasmInitExpr::kI32Const:
|
2016-12-21 13:43:00 +00:00
|
|
|
DCHECK_EQ(kWasmI32, global.type);
|
2017-04-25 10:45:46 +00:00
|
|
|
buffer.write_u8(kExprI32Const);
|
|
|
|
buffer.write_i32v(global.init.val.i32_const);
|
2016-09-27 20:46:10 +00:00
|
|
|
break;
|
2017-04-25 10:45:46 +00:00
|
|
|
case WasmInitExpr::kI64Const:
|
2016-12-21 13:43:00 +00:00
|
|
|
DCHECK_EQ(kWasmI64, global.type);
|
2017-04-25 10:45:46 +00:00
|
|
|
buffer.write_u8(kExprI64Const);
|
|
|
|
buffer.write_i64v(global.init.val.i64_const);
|
2016-09-27 20:46:10 +00:00
|
|
|
break;
|
2017-04-25 10:45:46 +00:00
|
|
|
case WasmInitExpr::kF32Const:
|
2016-12-21 13:43:00 +00:00
|
|
|
DCHECK_EQ(kWasmF32, global.type);
|
2017-04-25 10:45:46 +00:00
|
|
|
buffer.write_u8(kExprF32Const);
|
|
|
|
buffer.write_f32(global.init.val.f32_const);
|
2016-09-27 20:46:10 +00:00
|
|
|
break;
|
2017-04-25 10:45:46 +00:00
|
|
|
case WasmInitExpr::kF64Const:
|
2016-12-21 13:43:00 +00:00
|
|
|
DCHECK_EQ(kWasmF64, global.type);
|
2017-04-25 10:45:46 +00:00
|
|
|
buffer.write_u8(kExprF64Const);
|
|
|
|
buffer.write_f64(global.init.val.f64_const);
|
2016-09-27 20:46:10 +00:00
|
|
|
break;
|
2017-04-25 10:45:46 +00:00
|
|
|
case WasmInitExpr::kGlobalIndex:
|
|
|
|
buffer.write_u8(kExprGetGlobal);
|
|
|
|
buffer.write_u32v(global.init.val.global_index);
|
2016-10-06 15:43:10 +00:00
|
|
|
break;
|
|
|
|
default: {
|
|
|
|
// No initializer, emit a default value.
|
|
|
|
switch (global.type) {
|
2017-04-25 10:45:46 +00:00
|
|
|
case kWasmI32:
|
|
|
|
buffer.write_u8(kExprI32Const);
|
|
|
|
// LEB encoding of 0.
|
|
|
|
buffer.write_u8(0);
|
2016-10-06 15:43:10 +00:00
|
|
|
break;
|
2017-04-25 10:45:46 +00:00
|
|
|
case kWasmI64:
|
|
|
|
buffer.write_u8(kExprI64Const);
|
|
|
|
// LEB encoding of 0.
|
|
|
|
buffer.write_u8(0);
|
2016-10-06 15:43:10 +00:00
|
|
|
break;
|
2017-04-25 10:45:46 +00:00
|
|
|
case kWasmF32:
|
|
|
|
buffer.write_u8(kExprF32Const);
|
|
|
|
buffer.write_f32(0.f);
|
2016-10-06 15:43:10 +00:00
|
|
|
break;
|
2017-04-25 10:45:46 +00:00
|
|
|
case kWasmF64:
|
|
|
|
buffer.write_u8(kExprF64Const);
|
|
|
|
buffer.write_f64(0.);
|
2016-10-06 15:43:10 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
2016-09-27 20:46:10 +00:00
|
|
|
}
|
|
|
|
buffer.write_u8(kExprEnd);
|
|
|
|
}
|
2016-05-25 16:12:09 +00:00
|
|
|
FixupSection(buffer, start);
|
2016-04-21 11:18:41 +00:00
|
|
|
}
|
|
|
|
|
2016-05-25 16:12:09 +00:00
|
|
|
// == emit exports ===========================================================
|
2017-05-12 11:06:25 +00:00
|
|
|
if (!function_exports_.empty()) {
|
2016-09-27 20:46:10 +00:00
|
|
|
size_t start = EmitSection(kExportSectionCode, buffer);
|
2017-05-12 11:06:25 +00:00
|
|
|
buffer.write_size(function_exports_.size());
|
|
|
|
for (auto function_export : function_exports_) {
|
|
|
|
buffer.write_string(function_export.name);
|
|
|
|
buffer.write_u8(kExternalFunction);
|
|
|
|
buffer.write_size(function_export.function_index +
|
|
|
|
function_imports_.size());
|
|
|
|
}
|
2016-05-25 16:12:09 +00:00
|
|
|
FixupSection(buffer, start);
|
|
|
|
}
|
|
|
|
|
|
|
|
// == emit start function index ==============================================
|
2016-03-01 05:49:51 +00:00
|
|
|
if (start_function_index_ >= 0) {
|
2016-09-27 20:46:10 +00:00
|
|
|
size_t start = EmitSection(kStartSectionCode, buffer);
|
2017-04-07 14:37:30 +00:00
|
|
|
buffer.write_size(start_function_index_ + function_imports_.size());
|
2016-05-25 16:12:09 +00:00
|
|
|
FixupSection(buffer, start);
|
2016-03-01 05:49:51 +00:00
|
|
|
}
|
|
|
|
|
2016-09-27 20:46:10 +00:00
|
|
|
// == emit function table elements ===========================================
|
|
|
|
if (indirect_functions_.size() > 0) {
|
|
|
|
size_t start = EmitSection(kElementSectionCode, buffer);
|
|
|
|
buffer.write_u8(1); // count of entries
|
|
|
|
buffer.write_u8(0); // table index
|
|
|
|
buffer.write_u8(kExprI32Const); // offset
|
|
|
|
buffer.write_u32v(0);
|
|
|
|
buffer.write_u8(kExprEnd);
|
|
|
|
buffer.write_size(indirect_functions_.size()); // element count
|
|
|
|
|
|
|
|
for (auto index : indirect_functions_) {
|
2017-04-07 14:37:30 +00:00
|
|
|
buffer.write_size(index + function_imports_.size());
|
2016-09-27 20:46:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FixupSection(buffer, start);
|
|
|
|
}
|
|
|
|
|
2016-05-25 16:12:09 +00:00
|
|
|
// == emit code ==============================================================
|
|
|
|
if (functions_.size() > 0) {
|
2016-09-27 20:46:10 +00:00
|
|
|
size_t start = EmitSection(kCodeSectionCode, buffer);
|
2016-05-25 16:12:09 +00:00
|
|
|
buffer.write_size(functions_.size());
|
|
|
|
for (auto function : functions_) {
|
|
|
|
function->WriteBody(buffer);
|
|
|
|
}
|
|
|
|
FixupSection(buffer, start);
|
|
|
|
}
|
|
|
|
|
|
|
|
// == emit data segments =====================================================
|
2015-12-11 12:26:16 +00:00
|
|
|
if (data_segments_.size() > 0) {
|
2016-09-27 20:46:10 +00:00
|
|
|
size_t start = EmitSection(kDataSectionCode, buffer);
|
2016-05-25 16:12:09 +00:00
|
|
|
buffer.write_size(data_segments_.size());
|
2015-12-11 12:26:16 +00:00
|
|
|
|
|
|
|
for (auto segment : data_segments_) {
|
2016-09-29 18:12:45 +00:00
|
|
|
buffer.write_u8(0); // linear memory segment
|
|
|
|
buffer.write_u8(kExprI32Const); // initializer expression for dest
|
|
|
|
buffer.write_u32v(segment.dest);
|
|
|
|
buffer.write_u8(kExprEnd);
|
|
|
|
buffer.write_u32v(static_cast<uint32_t>(segment.data.size()));
|
|
|
|
buffer.write(&segment.data[0], segment.data.size());
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
2016-05-25 16:12:09 +00:00
|
|
|
FixupSection(buffer, start);
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
2016-09-27 20:46:10 +00:00
|
|
|
|
|
|
|
// == Emit names =============================================================
|
2017-04-07 14:37:30 +00:00
|
|
|
if (num_function_names > 0 || !function_imports_.empty()) {
|
2016-09-27 20:46:10 +00:00
|
|
|
// Emit the section code.
|
|
|
|
buffer.write_u8(kUnknownSectionCode);
|
|
|
|
// Emit a placeholder for the length.
|
|
|
|
size_t start = buffer.reserve_u32v();
|
|
|
|
// Emit the section string.
|
|
|
|
buffer.write_size(4);
|
|
|
|
buffer.write(reinterpret_cast<const byte*>("name"), 4);
|
2017-04-07 14:37:30 +00:00
|
|
|
// Emit a subsection for the function names.
|
2018-01-11 11:49:29 +00:00
|
|
|
buffer.write_u8(NameSectionKindCode::kFunction);
|
2017-04-07 14:37:30 +00:00
|
|
|
// Emit a placeholder for the subsection length.
|
|
|
|
size_t functions_start = buffer.reserve_u32v();
|
|
|
|
// Emit the function names.
|
|
|
|
// Imports are always named.
|
|
|
|
uint32_t num_imports = static_cast<uint32_t>(function_imports_.size());
|
|
|
|
buffer.write_size(num_imports + num_function_names);
|
|
|
|
uint32_t function_index = 0;
|
|
|
|
for (; function_index < num_imports; ++function_index) {
|
|
|
|
const WasmFunctionImport* import = &function_imports_[function_index];
|
2017-05-12 11:06:25 +00:00
|
|
|
DCHECK(!import->name.is_empty());
|
2017-04-07 14:37:30 +00:00
|
|
|
buffer.write_u32v(function_index);
|
2017-05-12 11:06:25 +00:00
|
|
|
buffer.write_string(import->name);
|
2016-11-15 20:55:33 +00:00
|
|
|
}
|
2017-04-07 14:37:30 +00:00
|
|
|
if (num_function_names > 0) {
|
|
|
|
for (auto function : functions_) {
|
|
|
|
DCHECK_EQ(function_index,
|
|
|
|
function->func_index() + function_imports_.size());
|
2017-05-11 08:15:46 +00:00
|
|
|
if (!function->name_.is_empty()) {
|
2017-04-07 14:37:30 +00:00
|
|
|
buffer.write_u32v(function_index);
|
2017-05-12 11:06:25 +00:00
|
|
|
buffer.write_string(function->name_);
|
2017-04-07 14:37:30 +00:00
|
|
|
}
|
|
|
|
++function_index;
|
|
|
|
}
|
2016-09-27 20:46:10 +00:00
|
|
|
}
|
2017-04-07 14:37:30 +00:00
|
|
|
FixupSection(buffer, functions_start);
|
2016-09-27 20:46:10 +00:00
|
|
|
FixupSection(buffer, start);
|
|
|
|
}
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
2016-10-12 09:17:12 +00:00
|
|
|
|
|
|
|
void WasmModuleBuilder::WriteAsmJsOffsetTable(ZoneBuffer& buffer) const {
|
|
|
|
// == Emit asm.js offset table ===============================================
|
|
|
|
buffer.write_size(functions_.size());
|
|
|
|
// Emit the offset table per function.
|
|
|
|
for (auto function : functions_) {
|
|
|
|
function->WriteAsmWasmOffsetTable(buffer);
|
|
|
|
}
|
2016-11-28 13:04:58 +00:00
|
|
|
// Append a 0 to indicate that this is an encoded table.
|
|
|
|
buffer.write_u8(0);
|
2016-10-12 09:17:12 +00:00
|
|
|
}
|
2015-12-11 12:26:16 +00:00
|
|
|
} // namespace wasm
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|