[wasm] Refactor encoder.h to use a proper buffer and remove OldFunctions section.
This removes the last use of the old_functions section, which greatly simplifies encoding. R=bradnelson@chromium.org,aseemgarg@chromium.org,mtrofin@chromium.org BUG= Review-Url: https://codereview.chromium.org/2014533003 Cr-Commit-Position: refs/heads/master@{#36523}
This commit is contained in:
parent
4a4f2537a3
commit
3412af0b40
@ -1759,12 +1759,14 @@ AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
|
||||
|
||||
// TODO(aseemgarg): probably should take zone (to write wasm to) as input so
|
||||
// that zone in constructor may be thrown away once wasm module is written.
|
||||
WasmModuleIndex* AsmWasmBuilder::Run(i::Handle<i::FixedArray>* foreign_args) {
|
||||
ZoneBuffer* AsmWasmBuilder::Run(i::Handle<i::FixedArray>* foreign_args) {
|
||||
AsmWasmBuilderImpl impl(isolate_, zone_, literal_, typer_);
|
||||
impl.Compile();
|
||||
*foreign_args = impl.GetForeignArgs();
|
||||
ZoneBuffer* buffer = new (zone_) ZoneBuffer(zone_);
|
||||
WasmModuleWriter* writer = impl.builder_->Build(zone_);
|
||||
return writer->WriteTo(zone_);
|
||||
writer->WriteTo(*buffer);
|
||||
return buffer;
|
||||
}
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
|
@ -22,7 +22,7 @@ class AsmWasmBuilder {
|
||||
public:
|
||||
explicit AsmWasmBuilder(Isolate* isolate, Zone* zone, FunctionLiteral* root,
|
||||
AsmTyper* typer);
|
||||
WasmModuleIndex* Run(Handle<FixedArray>* foreign_args);
|
||||
ZoneBuffer* Run(Handle<FixedArray>* foreign_args);
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
|
@ -30,70 +30,25 @@ namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
/*TODO: add error cases for adding too many locals, too many functions and bad
|
||||
indices in body */
|
||||
|
||||
namespace {
|
||||
void EmitUint8(byte** b, uint8_t x) {
|
||||
Memory::uint8_at(*b) = x;
|
||||
*b += 1;
|
||||
}
|
||||
|
||||
void EmitUint16(byte** b, uint16_t x) {
|
||||
WriteUnalignedUInt16(*b, x);
|
||||
*b += 2;
|
||||
}
|
||||
|
||||
void EmitUint32(byte** b, uint32_t x) {
|
||||
WriteUnalignedUInt32(*b, x);
|
||||
*b += 4;
|
||||
}
|
||||
|
||||
void EmitVarInt(byte** b, size_t val) {
|
||||
LEBHelper::write_u32v(b, static_cast<uint32_t>(val));
|
||||
}
|
||||
|
||||
// Sections all start with a size, but it's unknown at the start.
|
||||
// We generate a large varint which we then fixup later when the size is known.
|
||||
//
|
||||
// TODO(jfb) Not strictly necessary since sizes are calculated ahead of time.
|
||||
const size_t kPaddedVarintSize = 5;
|
||||
|
||||
void FixupSection(byte* start, byte* end) {
|
||||
// Same as LEBHelper::write_u32v, but fixed-width with zeroes in the MSBs.
|
||||
size_t val = end - start - kPaddedVarintSize;
|
||||
TRACE(" fixup %u\n", (unsigned)val);
|
||||
for (size_t pos = 0; pos != kPaddedVarintSize; ++pos) {
|
||||
size_t next = val >> 7;
|
||||
byte out = static_cast<byte>(val & 0x7f);
|
||||
if (pos != kPaddedVarintSize - 1) {
|
||||
*(start++) = 0x80 | out;
|
||||
val = next;
|
||||
} else {
|
||||
*(start++) = out;
|
||||
// TODO(jfb) check that the pre-allocated fixup size isn't overflowed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the start of the section, where the section VarInt size is.
|
||||
byte* EmitSection(WasmSection::Code code, byte** b) {
|
||||
// Emit a section name and the size as a padded varint that can be patched
|
||||
// later.
|
||||
size_t EmitSection(WasmSection::Code code, ZoneBuffer& buffer) {
|
||||
// Emit the section name.
|
||||
const char* name = WasmSection::getName(code);
|
||||
TRACE("emit section: %s\n", name);
|
||||
size_t length = WasmSection::getNameLength(code);
|
||||
EmitVarInt(b, length); // Section name string size.
|
||||
for (size_t i = 0; i != length; ++i) EmitUint8(b, name[i]);
|
||||
buffer.write_size(length); // Section name string size.
|
||||
buffer.write(reinterpret_cast<const byte*>(name), length);
|
||||
|
||||
// Emit a placeholder for the length.
|
||||
byte* start = *b;
|
||||
for (size_t padding = 0; padding != kPaddedVarintSize; ++padding) {
|
||||
EmitUint8(b, 0xff); // Will get fixed up later.
|
||||
}
|
||||
|
||||
return start;
|
||||
return buffer.reserve_u32v();
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
WasmFunctionBuilder::WasmFunctionBuilder(Zone* zone)
|
||||
: locals_(zone), exported_(0), body_(zone), name_(zone) {}
|
||||
@ -189,45 +144,30 @@ WasmFunctionEncoder::WasmFunctionEncoder(Zone* zone, LocalDeclEncoder locals,
|
||||
bool exported)
|
||||
: locals_(locals), exported_(exported), body_(zone), name_(zone) {}
|
||||
|
||||
uint32_t WasmFunctionEncoder::HeaderSize() const {
|
||||
uint32_t size = 3;
|
||||
size += 2;
|
||||
if (HasName()) {
|
||||
uint32_t name_size = NameSize();
|
||||
size +=
|
||||
static_cast<uint32_t>(LEBHelper::sizeof_u32v(name_size)) + name_size;
|
||||
}
|
||||
return size;
|
||||
void WasmFunctionEncoder::WriteSignature(ZoneBuffer& buffer) const {
|
||||
buffer.write_u32v(signature_index_);
|
||||
}
|
||||
|
||||
uint32_t WasmFunctionEncoder::BodySize(void) const {
|
||||
return static_cast<uint32_t>(body_.size() + locals_.Size());
|
||||
}
|
||||
|
||||
uint32_t WasmFunctionEncoder::NameSize() const {
|
||||
return HasName() ? static_cast<uint32_t>(name_.size()) : 0;
|
||||
}
|
||||
|
||||
void WasmFunctionEncoder::Serialize(byte* buffer, byte** header,
|
||||
byte** body) const {
|
||||
uint8_t decl_bits = (exported_ ? kDeclFunctionExport : 0) |
|
||||
(HasName() ? kDeclFunctionName : 0);
|
||||
|
||||
EmitUint8(header, decl_bits);
|
||||
EmitUint16(header, signature_index_);
|
||||
|
||||
if (HasName()) {
|
||||
EmitVarInt(header, NameSize());
|
||||
for (size_t i = 0; i < name_.size(); ++i) {
|
||||
EmitUint8(header, name_[i]);
|
||||
void WasmFunctionEncoder::WriteExport(ZoneBuffer& buffer,
|
||||
uint32_t func_index) const {
|
||||
if (exported_) {
|
||||
buffer.write_u32v(func_index);
|
||||
buffer.write_size(name_.size());
|
||||
if (name_.size() > 0) {
|
||||
buffer.write(reinterpret_cast<const byte*>(&name_[0]), name_.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EmitUint16(header, static_cast<uint16_t>(body_.size() + locals_.Size()));
|
||||
(*header) += locals_.Emit(*header);
|
||||
void WasmFunctionEncoder::WriteBody(ZoneBuffer& buffer) const {
|
||||
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
|
||||
if (body_.size() > 0) {
|
||||
std::memcpy(*header, &body_[0], body_.size());
|
||||
(*header) += body_.size();
|
||||
buffer.write(&body_[0], body_.size());
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,22 +179,10 @@ WasmDataSegmentEncoder::WasmDataSegmentEncoder(Zone* zone, const byte* data,
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t WasmDataSegmentEncoder::HeaderSize() const {
|
||||
static const int kDataSegmentSize = 13;
|
||||
return kDataSegmentSize;
|
||||
}
|
||||
|
||||
uint32_t WasmDataSegmentEncoder::BodySize() const {
|
||||
return static_cast<uint32_t>(data_.size());
|
||||
}
|
||||
|
||||
void WasmDataSegmentEncoder::Serialize(byte* buffer, byte** header,
|
||||
byte** body) const {
|
||||
EmitVarInt(header, dest_);
|
||||
EmitVarInt(header, static_cast<uint32_t>(data_.size()));
|
||||
|
||||
std::memcpy(*header, &data_[0], data_.size());
|
||||
(*header) += data_.size();
|
||||
void WasmDataSegmentEncoder::Write(ZoneBuffer& buffer) const {
|
||||
buffer.write_u32v(dest_);
|
||||
buffer.write_u32v(static_cast<uint32_t>(data_.size()));
|
||||
buffer.write(&data_[0], data_.size());
|
||||
}
|
||||
|
||||
WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
|
||||
@ -365,223 +293,130 @@ WasmModuleWriter::WasmModuleWriter(Zone* zone)
|
||||
indirect_functions_(zone),
|
||||
globals_(zone) {}
|
||||
|
||||
struct Sizes {
|
||||
size_t header_size;
|
||||
size_t body_size;
|
||||
void WasmModuleWriter::WriteTo(ZoneBuffer& buffer) const {
|
||||
uint32_t exports = 0;
|
||||
|
||||
size_t total() { return header_size + body_size; }
|
||||
|
||||
void Add(size_t header, size_t body) {
|
||||
header_size += header;
|
||||
body_size += body;
|
||||
}
|
||||
|
||||
void AddSection(WasmSection::Code code, size_t other_size) {
|
||||
Add(kPaddedVarintSize +
|
||||
LEBHelper::sizeof_u32v(WasmSection::getNameLength(code)) +
|
||||
WasmSection::getNameLength(code),
|
||||
0);
|
||||
if (other_size) Add(LEBHelper::sizeof_u32v(other_size), 0);
|
||||
}
|
||||
};
|
||||
|
||||
WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
||||
Sizes sizes = {0, 0};
|
||||
|
||||
sizes.Add(2 * sizeof(uint32_t), 0); // header
|
||||
|
||||
if (globals_.size() > 0) {
|
||||
sizes.AddSection(WasmSection::Code::Globals, globals_.size());
|
||||
/* These globals never have names, so are always 3 bytes. */
|
||||
sizes.Add(3 * globals_.size(), 0);
|
||||
TRACE("Size after globals: %u, %u\n", (unsigned)sizes.header_size,
|
||||
(unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
if (signatures_.size() > 0) {
|
||||
sizes.AddSection(WasmSection::Code::Signatures, signatures_.size());
|
||||
for (auto sig : signatures_) {
|
||||
sizes.Add(1 + LEBHelper::sizeof_u32v(sig->parameter_count()) +
|
||||
sig->parameter_count() +
|
||||
LEBHelper::sizeof_u32v(sig->return_count()) +
|
||||
sig->return_count(),
|
||||
0);
|
||||
}
|
||||
TRACE("Size after signatures: %u, %u\n", (unsigned)sizes.header_size,
|
||||
(unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
if (functions_.size() > 0) {
|
||||
sizes.AddSection(WasmSection::Code::OldFunctions, functions_.size());
|
||||
for (auto function : functions_) {
|
||||
sizes.Add(function->HeaderSize() + function->BodySize(),
|
||||
function->NameSize());
|
||||
}
|
||||
TRACE("Size after functions: %u, %u\n", (unsigned)sizes.header_size,
|
||||
(unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
if (imports_.size() > 0) {
|
||||
sizes.AddSection(WasmSection::Code::ImportTable, imports_.size());
|
||||
for (auto import : imports_) {
|
||||
sizes.Add(LEBHelper::sizeof_u32v(import.sig_index), 0);
|
||||
sizes.Add(LEBHelper::sizeof_u32v(import.name_length), 0);
|
||||
sizes.Add(import.name_length, 0);
|
||||
sizes.Add(1, 0);
|
||||
}
|
||||
TRACE("Size after imports: %u, %u\n", (unsigned)sizes.header_size,
|
||||
(unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
if (indirect_functions_.size() > 0) {
|
||||
sizes.AddSection(WasmSection::Code::FunctionTable,
|
||||
indirect_functions_.size());
|
||||
for (auto function_index : indirect_functions_) {
|
||||
sizes.Add(LEBHelper::sizeof_u32v(function_index), 0);
|
||||
}
|
||||
TRACE("Size after indirect functions: %u, %u\n",
|
||||
(unsigned)sizes.header_size, (unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
sizes.AddSection(WasmSection::Code::Memory, 0);
|
||||
sizes.Add(kDeclMemorySize, 0);
|
||||
TRACE("Size after memory: %u, %u\n", (unsigned)sizes.header_size,
|
||||
(unsigned)sizes.body_size);
|
||||
|
||||
if (start_function_index_ >= 0) {
|
||||
sizes.AddSection(WasmSection::Code::StartFunction, 0);
|
||||
sizes.Add(LEBHelper::sizeof_u32v(start_function_index_), 0);
|
||||
TRACE("Size after start: %u, %u\n", (unsigned)sizes.header_size,
|
||||
(unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
if (data_segments_.size() > 0) {
|
||||
sizes.AddSection(WasmSection::Code::DataSegments, data_segments_.size());
|
||||
for (auto segment : data_segments_) {
|
||||
sizes.Add(segment->HeaderSize(), segment->BodySize());
|
||||
}
|
||||
TRACE("Size after data segments: %u, %u\n", (unsigned)sizes.header_size,
|
||||
(unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
if (sizes.body_size > 0) {
|
||||
sizes.AddSection(WasmSection::Code::End, 0);
|
||||
TRACE("Size after end: %u, %u\n", (unsigned)sizes.header_size,
|
||||
(unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
ZoneVector<uint8_t> buffer_vector(sizes.total(), zone);
|
||||
byte* buffer = &buffer_vector[0];
|
||||
byte* header = buffer;
|
||||
byte* body = buffer + sizes.header_size;
|
||||
|
||||
// -- emit magic -------------------------------------------------------------
|
||||
// == Emit magic =============================================================
|
||||
TRACE("emit magic\n");
|
||||
EmitUint32(&header, kWasmMagic);
|
||||
EmitUint32(&header, kWasmVersion);
|
||||
buffer.write_u32(kWasmMagic);
|
||||
buffer.write_u32(kWasmVersion);
|
||||
|
||||
// -- emit globals -----------------------------------------------------------
|
||||
if (globals_.size() > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::Globals, &header);
|
||||
EmitVarInt(&header, globals_.size());
|
||||
|
||||
for (auto global : globals_) {
|
||||
EmitVarInt(&header, 0); // Length of the global name.
|
||||
EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first));
|
||||
EmitUint8(&header, global.second);
|
||||
}
|
||||
FixupSection(section, header);
|
||||
}
|
||||
|
||||
// -- emit signatures --------------------------------------------------------
|
||||
// == Emit signatures ========================================================
|
||||
if (signatures_.size() > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::Signatures, &header);
|
||||
EmitVarInt(&header, signatures_.size());
|
||||
size_t start = EmitSection(WasmSection::Code::Signatures, buffer);
|
||||
buffer.write_size(signatures_.size());
|
||||
|
||||
for (FunctionSig* sig : signatures_) {
|
||||
EmitUint8(&header, kWasmFunctionTypeForm);
|
||||
EmitVarInt(&header, sig->parameter_count());
|
||||
buffer.write_u8(kWasmFunctionTypeForm);
|
||||
buffer.write_size(sig->parameter_count());
|
||||
for (size_t j = 0; j < sig->parameter_count(); j++) {
|
||||
EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j)));
|
||||
buffer.write_u8(WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j)));
|
||||
}
|
||||
EmitVarInt(&header, sig->return_count());
|
||||
buffer.write_size(sig->return_count());
|
||||
for (size_t j = 0; j < sig->return_count(); j++) {
|
||||
EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetReturn(j)));
|
||||
buffer.write_u8(WasmOpcodes::LocalTypeCodeFor(sig->GetReturn(j)));
|
||||
}
|
||||
}
|
||||
FixupSection(section, header);
|
||||
FixupSection(buffer, start);
|
||||
}
|
||||
|
||||
// -- emit imports -----------------------------------------------------------
|
||||
// == Emit globals ===========================================================
|
||||
if (globals_.size() > 0) {
|
||||
size_t start = EmitSection(WasmSection::Code::Globals, buffer);
|
||||
buffer.write_size(globals_.size());
|
||||
|
||||
for (auto global : globals_) {
|
||||
buffer.write_u32v(0); // Length of the global name.
|
||||
buffer.write_u8(WasmOpcodes::MemTypeCodeFor(global.first));
|
||||
buffer.write_u8(global.second);
|
||||
}
|
||||
FixupSection(buffer, start);
|
||||
}
|
||||
|
||||
// == Emit imports ===========================================================
|
||||
if (imports_.size() > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::ImportTable, &header);
|
||||
EmitVarInt(&header, imports_.size());
|
||||
size_t start = EmitSection(WasmSection::Code::ImportTable, buffer);
|
||||
buffer.write_size(imports_.size());
|
||||
for (auto import : imports_) {
|
||||
EmitVarInt(&header, import.sig_index);
|
||||
EmitVarInt(&header, import.name_length);
|
||||
std::memcpy(header, import.name, import.name_length);
|
||||
header += import.name_length;
|
||||
EmitVarInt(&header, 0);
|
||||
buffer.write_u32v(import.sig_index);
|
||||
buffer.write_u32v(import.name_length);
|
||||
buffer.write(reinterpret_cast<const byte*>(import.name),
|
||||
import.name_length);
|
||||
buffer.write_u32v(0);
|
||||
}
|
||||
FixupSection(section, header);
|
||||
FixupSection(buffer, start);
|
||||
}
|
||||
|
||||
// -- emit functions ---------------------------------------------------------
|
||||
// == Emit function signatures ===============================================
|
||||
if (functions_.size() > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::OldFunctions, &header);
|
||||
EmitVarInt(&header, functions_.size());
|
||||
|
||||
for (auto func : functions_) {
|
||||
func->Serialize(buffer, &header, &body);
|
||||
size_t start = EmitSection(WasmSection::Code::FunctionSignatures, buffer);
|
||||
buffer.write_size(functions_.size());
|
||||
for (auto function : functions_) {
|
||||
function->WriteSignature(buffer);
|
||||
if (function->exported()) exports++;
|
||||
}
|
||||
FixupSection(section, header);
|
||||
FixupSection(buffer, start);
|
||||
}
|
||||
|
||||
// -- emit function table ----------------------------------------------------
|
||||
// == emit function table ====================================================
|
||||
if (indirect_functions_.size() > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::FunctionTable, &header);
|
||||
EmitVarInt(&header, indirect_functions_.size());
|
||||
size_t start = EmitSection(WasmSection::Code::FunctionTable, buffer);
|
||||
buffer.write_size(indirect_functions_.size());
|
||||
|
||||
for (auto index : indirect_functions_) {
|
||||
EmitVarInt(&header, index);
|
||||
buffer.write_u32v(index);
|
||||
}
|
||||
FixupSection(section, header);
|
||||
FixupSection(buffer, start);
|
||||
}
|
||||
|
||||
// -- emit memory declaration ------------------------------------------------
|
||||
// == emit memory declaration ================================================
|
||||
{
|
||||
byte* section = EmitSection(WasmSection::Code::Memory, &header);
|
||||
EmitVarInt(&header, 16); // min memory size
|
||||
EmitVarInt(&header, 16); // max memory size
|
||||
EmitUint8(&header, 0); // memory export
|
||||
size_t start = EmitSection(WasmSection::Code::Memory, buffer);
|
||||
buffer.write_u32v(16); // min memory size
|
||||
buffer.write_u32v(16); // max memory size
|
||||
buffer.write_u8(0); // memory export
|
||||
static_assert(kDeclMemorySize == 3, "memory size must match emit above");
|
||||
FixupSection(section, header);
|
||||
FixupSection(buffer, start);
|
||||
}
|
||||
|
||||
// -- emit start function index ----------------------------------------------
|
||||
// == emit exports ===========================================================
|
||||
if (exports > 0) {
|
||||
size_t start = EmitSection(WasmSection::Code::ExportTable, buffer);
|
||||
buffer.write_u32v(exports);
|
||||
uint32_t index = 0;
|
||||
for (auto function : functions_) {
|
||||
function->WriteExport(buffer, index++);
|
||||
}
|
||||
FixupSection(buffer, start);
|
||||
}
|
||||
|
||||
// == emit start function index ==============================================
|
||||
if (start_function_index_ >= 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::StartFunction, &header);
|
||||
EmitVarInt(&header, start_function_index_);
|
||||
FixupSection(section, header);
|
||||
size_t start = EmitSection(WasmSection::Code::StartFunction, buffer);
|
||||
buffer.write_u32v(start_function_index_);
|
||||
FixupSection(buffer, start);
|
||||
}
|
||||
|
||||
// -- emit data segments -----------------------------------------------------
|
||||
// == emit code ==============================================================
|
||||
if (functions_.size() > 0) {
|
||||
size_t start = EmitSection(WasmSection::Code::FunctionBodies, buffer);
|
||||
buffer.write_size(functions_.size());
|
||||
for (auto function : functions_) {
|
||||
function->WriteBody(buffer);
|
||||
}
|
||||
FixupSection(buffer, start);
|
||||
}
|
||||
|
||||
// == emit data segments =====================================================
|
||||
if (data_segments_.size() > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::DataSegments, &header);
|
||||
EmitVarInt(&header, data_segments_.size());
|
||||
size_t start = EmitSection(WasmSection::Code::DataSegments, buffer);
|
||||
buffer.write_size(data_segments_.size());
|
||||
|
||||
for (auto segment : data_segments_) {
|
||||
segment->Serialize(buffer, &header, &body);
|
||||
segment->Write(buffer);
|
||||
}
|
||||
FixupSection(section, header);
|
||||
FixupSection(buffer, start);
|
||||
}
|
||||
|
||||
if (sizes.body_size > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::End, &header);
|
||||
FixupSection(section, header);
|
||||
}
|
||||
|
||||
return new (zone) WasmModuleIndex(buffer, buffer + sizes.total());
|
||||
}
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "src/base/smart-pointers.h"
|
||||
|
||||
#include "src/wasm/leb-helper.h"
|
||||
#include "src/wasm/wasm-macro-gen.h"
|
||||
#include "src/wasm/wasm-module.h"
|
||||
#include "src/wasm/wasm-opcodes.h"
|
||||
@ -19,14 +20,104 @@ namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
class ZoneBuffer : public ZoneObject {
|
||||
public:
|
||||
static const uint32_t kInitialSize = 4096;
|
||||
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);
|
||||
WriteUnalignedUInt16(pos_, x);
|
||||
pos_ += 2;
|
||||
}
|
||||
|
||||
void write_u32(uint32_t x) {
|
||||
EnsureSpace(4);
|
||||
WriteUnalignedUInt32(pos_, x);
|
||||
pos_ += 4;
|
||||
}
|
||||
|
||||
void write_u32v(uint32_t val) {
|
||||
EnsureSpace(kMaxVarInt32Size);
|
||||
LEBHelper::write_u32v(&pos_, val);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void write(const byte* data, size_t size) {
|
||||
EnsureSpace(size);
|
||||
memcpy(pos_, data, size);
|
||||
pos_ += size;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t offset() { return static_cast<size_t>(pos_ - buffer_); }
|
||||
size_t size() { return static_cast<size_t>(pos_ - buffer_); }
|
||||
const byte* begin() { return buffer_; }
|
||||
const byte* end() { return pos_; }
|
||||
|
||||
void EnsureSpace(size_t size) {
|
||||
if ((pos_ + size) > end_) {
|
||||
size_t new_size = 4096 + (end_ - buffer_) * 3;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
byte** pos_ptr() { return &pos_; }
|
||||
|
||||
private:
|
||||
Zone* zone_;
|
||||
byte* buffer_;
|
||||
byte* pos_;
|
||||
byte* end_;
|
||||
};
|
||||
|
||||
class WasmModuleBuilder;
|
||||
|
||||
class WasmFunctionEncoder : public ZoneObject {
|
||||
public:
|
||||
uint32_t HeaderSize() const;
|
||||
uint32_t BodySize() const;
|
||||
uint32_t NameSize() const;
|
||||
void Serialize(byte* buffer, byte** header, byte** body) const;
|
||||
void WriteSignature(ZoneBuffer& buffer) const;
|
||||
void WriteExport(ZoneBuffer& buffer, uint32_t func_index) const;
|
||||
void WriteBody(ZoneBuffer& buffer) const;
|
||||
bool exported() const { return exported_; }
|
||||
|
||||
private:
|
||||
WasmFunctionEncoder(Zone* zone, LocalDeclEncoder locals, bool exported);
|
||||
@ -71,28 +162,13 @@ class WasmDataSegmentEncoder : public ZoneObject {
|
||||
public:
|
||||
WasmDataSegmentEncoder(Zone* zone, const byte* data, uint32_t size,
|
||||
uint32_t dest);
|
||||
uint32_t HeaderSize() const;
|
||||
uint32_t BodySize() const;
|
||||
void Serialize(byte* buffer, byte** header, byte** body) const;
|
||||
void Write(ZoneBuffer& buffer) const;
|
||||
|
||||
private:
|
||||
ZoneVector<byte> data_;
|
||||
uint32_t dest_;
|
||||
};
|
||||
|
||||
class WasmModuleIndex : public ZoneObject {
|
||||
public:
|
||||
const byte* Begin() const { return begin_; }
|
||||
const byte* End() const { return end_; }
|
||||
|
||||
private:
|
||||
friend class WasmModuleWriter;
|
||||
WasmModuleIndex(const byte* begin, const byte* end)
|
||||
: begin_(begin), end_(end) {}
|
||||
const byte* begin_;
|
||||
const byte* end_;
|
||||
};
|
||||
|
||||
struct WasmFunctionImport {
|
||||
uint32_t sig_index;
|
||||
const char* name;
|
||||
@ -101,7 +177,7 @@ struct WasmFunctionImport {
|
||||
|
||||
class WasmModuleWriter : public ZoneObject {
|
||||
public:
|
||||
WasmModuleIndex* WriteTo(Zone* zone) const;
|
||||
void WriteTo(ZoneBuffer& buffer) const;
|
||||
|
||||
private:
|
||||
friend class WasmModuleBuilder;
|
||||
|
@ -9,6 +9,9 @@ namespace v8 {
|
||||
namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
static const size_t kPaddedVarInt32Size = 5;
|
||||
static const size_t kMaxVarInt32Size = 5;
|
||||
|
||||
class LEBHelper {
|
||||
public:
|
||||
// Write a 32-bit unsigned LEB to {dest}, updating {dest} to point after
|
||||
|
@ -118,6 +118,10 @@ class ModuleDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE(" +%d section name : \"%.*s\"\n",
|
||||
static_cast<int>(section_name_start - start_),
|
||||
string_length < 20 ? string_length : 20, section_name_start);
|
||||
|
||||
WasmSection::Code section =
|
||||
WasmSection::lookup(section_name_start, string_length);
|
||||
|
||||
@ -171,8 +175,7 @@ class ModuleDecoder : public Decoder {
|
||||
0, // name_offset
|
||||
0, // name_length
|
||||
0, // code_start_offset
|
||||
0, // code_end_offset
|
||||
false}); // exported
|
||||
0}); // code_end_offset
|
||||
WasmFunction* function = &module->functions.back();
|
||||
function->sig_index = consume_sig_index(module, &function->sig);
|
||||
}
|
||||
@ -204,44 +207,6 @@ class ModuleDecoder : public Decoder {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmSection::Code::OldFunctions: {
|
||||
int length;
|
||||
uint32_t functions_count = consume_u32v(&length, "functions count");
|
||||
module->functions.reserve(SafeReserve(functions_count));
|
||||
// Set up module environment for verification.
|
||||
ModuleEnv menv;
|
||||
menv.module = module;
|
||||
menv.instance = nullptr;
|
||||
menv.origin = origin_;
|
||||
// Decode functions.
|
||||
for (uint32_t i = 0; i < functions_count; i++) {
|
||||
if (failed()) break;
|
||||
TRACE("DecodeFunction[%d] module+%d\n", i,
|
||||
static_cast<int>(pc_ - start_));
|
||||
|
||||
module->functions.push_back({nullptr, // sig
|
||||
i, // func_index
|
||||
0, // sig_index
|
||||
0, // name_offset
|
||||
0, // name_length
|
||||
0, // code_start_offset
|
||||
0, // code_end_offset
|
||||
false}); // exported
|
||||
WasmFunction* function = &module->functions.back();
|
||||
DecodeFunctionInModule(module, function, false);
|
||||
}
|
||||
if (ok() && verify_functions) {
|
||||
for (uint32_t i = 0; i < functions_count; i++) {
|
||||
if (failed()) break;
|
||||
WasmFunction* function = &module->functions[i];
|
||||
VerifyFunctionBody(i, &menv, function);
|
||||
if (result_.failed()) {
|
||||
error(result_.error_pc, result_.error_msg.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmSection::Code::Names: {
|
||||
int length;
|
||||
const byte* pos = pc_;
|
||||
@ -464,7 +429,6 @@ class ModuleDecoder : public Decoder {
|
||||
function->name_length = 0; // ---- name length
|
||||
function->code_start_offset = off(pc_); // ---- code start
|
||||
function->code_end_offset = off(limit_); // ---- code end
|
||||
function->exported = false; // ---- exported
|
||||
|
||||
if (ok()) VerifyFunctionBody(0, module_env, function);
|
||||
|
||||
@ -498,46 +462,6 @@ class ModuleDecoder : public Decoder {
|
||||
global->exported = consume_u8("exported") != 0;
|
||||
}
|
||||
|
||||
// Decodes a single function entry inside a module starting at {pc_}.
|
||||
// TODO(titzer): legacy function body; remove
|
||||
void DecodeFunctionInModule(WasmModule* module, WasmFunction* function,
|
||||
bool verify_body = true) {
|
||||
byte decl_bits = consume_u8("function decl");
|
||||
|
||||
const byte* sigpos = pc_;
|
||||
function->sig_index = consume_u16("signature index");
|
||||
|
||||
if (function->sig_index >= module->signatures.size()) {
|
||||
return error(sigpos, "invalid signature index");
|
||||
} else {
|
||||
function->sig = module->signatures[function->sig_index];
|
||||
}
|
||||
|
||||
TRACE(" +%d <function attributes:%s%s>\n", static_cast<int>(pc_ - start_),
|
||||
decl_bits & kDeclFunctionName ? " name" : "",
|
||||
decl_bits & kDeclFunctionExport ? " exported" : "");
|
||||
|
||||
function->exported = decl_bits & kDeclFunctionExport;
|
||||
|
||||
if (decl_bits & kDeclFunctionName) {
|
||||
function->name_offset =
|
||||
consume_string(&function->name_length, function->exported);
|
||||
}
|
||||
|
||||
uint16_t size = consume_u16("body size");
|
||||
if (ok()) {
|
||||
if ((pc_ + size) > limit_) {
|
||||
return error(pc_, limit_,
|
||||
"expected %d bytes for function body, fell off end", size);
|
||||
}
|
||||
function->code_start_offset = static_cast<uint32_t>(pc_ - start_);
|
||||
function->code_end_offset = function->code_start_offset + size;
|
||||
TRACE(" +%d %-20s: (%d bytes)\n", static_cast<int>(pc_ - start_),
|
||||
"function body", size);
|
||||
pc_ += size;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsWithinLimit(uint32_t limit, uint32_t offset, uint32_t size) {
|
||||
if (offset > limit) return false;
|
||||
if ((offset + size) < offset) return false; // overflow
|
||||
|
@ -121,7 +121,7 @@ void VerifyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
|
||||
v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(
|
||||
v8::internal::wasm::ZoneBuffer* TranslateAsmModule(
|
||||
i::ParseInfo* info, ErrorThrower* thrower,
|
||||
i::Handle<i::FixedArray>* foreign_args) {
|
||||
info->set_global();
|
||||
@ -154,9 +154,7 @@ v8::internal::wasm::WasmModuleIndex* TranslateAsmModule(
|
||||
v8::internal::wasm::AsmWasmBuilder builder(info->isolate(), info->zone(),
|
||||
info->literal(), &typer);
|
||||
|
||||
auto module = builder.Run(foreign_args);
|
||||
|
||||
return module;
|
||||
return builder.Run(foreign_args);
|
||||
}
|
||||
|
||||
i::MaybeHandle<i::JSObject> InstantiateModuleCommon(
|
||||
@ -231,7 +229,7 @@ void InstantiateModuleFromAsm(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
}
|
||||
|
||||
i::MaybeHandle<i::Object> maybe_module_object =
|
||||
InstantiateModuleCommon(args, module->Begin(), module->End(), &thrower,
|
||||
InstantiateModuleCommon(args, module->begin(), module->end(), &thrower,
|
||||
internal::wasm::kAsmJsOrigin);
|
||||
if (maybe_module_object.is_null()) {
|
||||
return;
|
||||
|
@ -577,8 +577,6 @@ bool FinishCompilation(Isolate* isolate, const WasmModule* module,
|
||||
DCHECK_EQ(i, func.func_index);
|
||||
WasmName str = module->GetName(func.name_offset, func.name_length);
|
||||
Handle<Code> code = Handle<Code>::null();
|
||||
Handle<JSFunction> function = Handle<JSFunction>::null();
|
||||
Handle<String> function_name = Handle<String>::null();
|
||||
if (FLAG_wasm_num_compilation_tasks != 0) {
|
||||
code = results[i];
|
||||
} else {
|
||||
@ -591,28 +589,12 @@ bool FinishCompilation(Isolate* isolate, const WasmModule* module,
|
||||
str.start());
|
||||
return false;
|
||||
}
|
||||
if (func.exported) {
|
||||
function_name = factory->InternalizeUtf8String(str);
|
||||
function = compiler::CompileJSToWasmWrapper(
|
||||
isolate, &module_env, function_name, code, instance.js_object, i);
|
||||
code_stats.Record(function->code());
|
||||
}
|
||||
if (!code.is_null()) {
|
||||
// Install the code into the linker table.
|
||||
module_env.linker->Finish(i, code);
|
||||
code_table->set(i, *code);
|
||||
code_stats.Record(*code);
|
||||
}
|
||||
if (func.exported) {
|
||||
// Exported functions are installed as read-only properties on the
|
||||
// module.
|
||||
desc.set_value(function);
|
||||
Maybe<bool> status = JSReceiver::DefineOwnProperty(
|
||||
isolate, instance.js_object, function_name, &desc,
|
||||
Object::THROW_ON_ERROR);
|
||||
if (!status.IsJust())
|
||||
thrower.Error("export of %.*s failed.", str.length(), str.start());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -786,14 +768,19 @@ MaybeHandle<JSObject> WasmModule::Instantiate(
|
||||
// Create and populate the exports object.
|
||||
//-------------------------------------------------------------------------
|
||||
if (export_table.size() > 0 || mem_export) {
|
||||
// Create the "exports" object.
|
||||
Handle<JSFunction> object_function = Handle<JSFunction>(
|
||||
isolate->native_context()->object_function(), isolate);
|
||||
Handle<JSObject> exports_object =
|
||||
factory->NewJSObject(object_function, TENURED);
|
||||
Handle<String> exports_name = factory->InternalizeUtf8String("exports");
|
||||
JSObject::AddProperty(instance.js_object, exports_name, exports_object,
|
||||
READ_ONLY);
|
||||
Handle<JSObject> exports_object;
|
||||
if (origin == kWasmOrigin) {
|
||||
// Create the "exports" object.
|
||||
Handle<JSFunction> object_function = Handle<JSFunction>(
|
||||
isolate->native_context()->object_function(), isolate);
|
||||
exports_object = factory->NewJSObject(object_function, TENURED);
|
||||
Handle<String> exports_name = factory->InternalizeUtf8String("exports");
|
||||
JSObject::AddProperty(instance.js_object, exports_name, exports_object,
|
||||
READ_ONLY);
|
||||
} else {
|
||||
// Just export the functions directly on the object returned.
|
||||
exports_object = instance.js_object;
|
||||
}
|
||||
|
||||
// Compile wrappers and add them to the exports object.
|
||||
for (const WasmExport& exp : export_table) {
|
||||
@ -808,8 +795,10 @@ MaybeHandle<JSObject> WasmModule::Instantiate(
|
||||
desc.set_value(function);
|
||||
Maybe<bool> status = JSReceiver::DefineOwnProperty(
|
||||
isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
|
||||
if (!status.IsJust())
|
||||
if (!status.IsJust()) {
|
||||
thrower.Error("export of %.*s failed.", str.length(), str.start());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mem_export) {
|
||||
@ -879,8 +868,9 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
|
||||
Zone zone(isolate->allocator());
|
||||
// Decode the module, but don't verify function bodies, since we'll
|
||||
// be compiling them anyway.
|
||||
ModuleResult result = DecodeWasmModule(isolate, &zone, module_start,
|
||||
module_end, false, kWasmOrigin);
|
||||
ModuleResult result =
|
||||
DecodeWasmModule(isolate, &zone, module_start, module_end, false,
|
||||
asm_js ? kAsmJsOrigin : kWasmOrigin);
|
||||
if (result.failed()) {
|
||||
if (result.val) {
|
||||
delete result.val;
|
||||
@ -924,34 +914,25 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const WasmModule* module) {
|
||||
module_env.linker = &linker;
|
||||
module_env.origin = module->origin;
|
||||
|
||||
// Compile all functions.
|
||||
Handle<Code> main_code = Handle<Code>::null(); // record last code.
|
||||
uint32_t index = 0;
|
||||
int main_index = 0;
|
||||
for (const WasmFunction& func : module->functions) {
|
||||
DCHECK_EQ(index, func.func_index);
|
||||
// Compile the function and install it in the code table.
|
||||
Handle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction(
|
||||
&thrower, isolate, &module_env, &func);
|
||||
if (!code.is_null()) {
|
||||
if (func.exported) {
|
||||
main_code = code;
|
||||
main_index = index;
|
||||
}
|
||||
linker.Finish(index, code);
|
||||
}
|
||||
if (thrower.error()) return -1;
|
||||
index++;
|
||||
if (module->export_table.size() == 0) {
|
||||
thrower.Error("WASM.compileRun() failed: no exported functions");
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (main_code.is_null()) {
|
||||
thrower.Error("WASM.compileRun() failed: no main code found");
|
||||
return -1;
|
||||
// Compile all functions.
|
||||
for (const WasmFunction& func : module->functions) {
|
||||
// Compile the function and install it in the linker.
|
||||
Handle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction(
|
||||
&thrower, isolate, &module_env, &func);
|
||||
if (!code.is_null()) linker.Finish(func.func_index, code);
|
||||
if (thrower.error()) return -1;
|
||||
}
|
||||
|
||||
linker.Link(instance.function_table, instance.module->function_table);
|
||||
|
||||
// Wrap the main code so it can be called as a JS function.
|
||||
uint32_t main_index = module->export_table.back().func_index;
|
||||
Handle<Code> main_code = linker.GetFunctionCode(main_index);
|
||||
Handle<String> name = isolate->factory()->NewStringFromStaticChars("main");
|
||||
Handle<JSObject> module_object = Handle<JSObject>(0, isolate);
|
||||
Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
|
||||
|
@ -42,15 +42,12 @@ const uint8_t kWasmFunctionTypeForm = 0x40;
|
||||
F(FunctionBodies, 8, "code") \
|
||||
F(DataSegments, 9, "data") \
|
||||
F(Names, 10, "name") \
|
||||
F(OldFunctions, 0, "old_function") \
|
||||
F(Globals, 0, "global") \
|
||||
F(End, 0, "end")
|
||||
|
||||
// Contants for the above section types: {LEB128 length, characters...}.
|
||||
#define WASM_SECTION_MEMORY 6, 'm', 'e', 'm', 'o', 'r', 'y'
|
||||
#define WASM_SECTION_SIGNATURES 4, 't', 'y', 'p', 'e'
|
||||
#define WASM_SECTION_OLD_FUNCTIONS \
|
||||
12, 'o', 'l', 'd', '_', 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n'
|
||||
#define WASM_SECTION_GLOBALS 6, 'g', 'l', 'o', 'b', 'a', 'l'
|
||||
#define WASM_SECTION_DATA_SEGMENTS 4, 'd', 'a', 't', 'a'
|
||||
#define WASM_SECTION_FUNCTION_TABLE 5, 't', 'a', 'b', 'l', 'e'
|
||||
@ -66,7 +63,6 @@ const uint8_t kWasmFunctionTypeForm = 0x40;
|
||||
// Constants for the above section headers' size (LEB128 + characters).
|
||||
#define WASM_SECTION_MEMORY_SIZE ((size_t)7)
|
||||
#define WASM_SECTION_SIGNATURES_SIZE ((size_t)5)
|
||||
#define WASM_SECTION_OLD_FUNCTIONS_SIZE ((size_t)13)
|
||||
#define WASM_SECTION_GLOBALS_SIZE ((size_t)7)
|
||||
#define WASM_SECTION_DATA_SEGMENTS_SIZE ((size_t)5)
|
||||
#define WASM_SECTION_FUNCTION_TABLE_SIZE ((size_t)6)
|
||||
@ -114,7 +110,6 @@ struct WasmFunction {
|
||||
uint32_t name_length; // length in bytes of the name.
|
||||
uint32_t code_start_offset; // offset in the module bytes of code start.
|
||||
uint32_t code_end_offset; // offset in the module bytes of code end.
|
||||
bool exported; // true if this function is exported.
|
||||
};
|
||||
|
||||
// Static representation of an imported WASM function.
|
||||
|
@ -29,7 +29,8 @@ std::ostream& operator<<(std::ostream& os, const ErrorCode& error_code) {
|
||||
}
|
||||
|
||||
void ErrorThrower::Error(const char* format, ...) {
|
||||
if (error_) return; // only report the first error.
|
||||
// only report the first error.
|
||||
if (error_ || isolate_->has_pending_exception()) return;
|
||||
error_ = true;
|
||||
char buffer[256];
|
||||
|
||||
|
@ -20,12 +20,17 @@ using namespace v8::internal::compiler;
|
||||
using namespace v8::internal::wasm;
|
||||
|
||||
namespace {
|
||||
void TestModule(WasmModuleIndex* module, int32_t expected_result) {
|
||||
void TestModule(Zone* zone, WasmModuleBuilder* builder,
|
||||
int32_t expected_result) {
|
||||
ZoneBuffer buffer(zone);
|
||||
WasmModuleWriter* writer = builder->Build(zone);
|
||||
writer->WriteTo(buffer);
|
||||
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
HandleScope scope(isolate);
|
||||
WasmJs::InstallWasmFunctionMap(isolate, isolate->native_context());
|
||||
int32_t result =
|
||||
CompileAndRunWasmModule(isolate, module->Begin(), module->End());
|
||||
CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end());
|
||||
CHECK_EQ(expected_result, result);
|
||||
}
|
||||
} // namespace
|
||||
@ -43,8 +48,7 @@ TEST(Run_WasmModule_Return114) {
|
||||
f->Exported(1);
|
||||
byte code[] = {WASM_I8(kReturnValue)};
|
||||
f->EmitCode(code, sizeof(code));
|
||||
WasmModuleWriter* writer = builder->Build(&zone);
|
||||
TestModule(writer->WriteTo(&zone), kReturnValue);
|
||||
TestModule(&zone, builder, kReturnValue);
|
||||
}
|
||||
|
||||
TEST(Run_WasmModule_CallAdd) {
|
||||
@ -69,8 +73,7 @@ TEST(Run_WasmModule_CallAdd) {
|
||||
f->Exported(1);
|
||||
byte code2[] = {WASM_CALL_FUNCTION2(f1_index, WASM_I8(77), WASM_I8(22))};
|
||||
f->EmitCode(code2, sizeof(code2));
|
||||
WasmModuleWriter* writer = builder->Build(&zone);
|
||||
TestModule(writer->WriteTo(&zone), 99);
|
||||
TestModule(&zone, builder, 99);
|
||||
}
|
||||
|
||||
TEST(Run_WasmModule_ReadLoadedDataSegment) {
|
||||
@ -91,8 +94,7 @@ TEST(Run_WasmModule_ReadLoadedDataSegment) {
|
||||
byte data[] = {0xaa, 0xbb, 0xcc, 0xdd};
|
||||
builder->AddDataSegment(new (&zone) WasmDataSegmentEncoder(
|
||||
&zone, data, sizeof(data), kDataSegmentDest0));
|
||||
WasmModuleWriter* writer = builder->Build(&zone);
|
||||
TestModule(writer->WriteTo(&zone), 0xddccbbaa);
|
||||
TestModule(&zone, builder, 0xddccbbaa);
|
||||
}
|
||||
|
||||
TEST(Run_WasmModule_CheckMemoryIsZero) {
|
||||
@ -117,8 +119,7 @@ TEST(Run_WasmModule_CheckMemoryIsZero) {
|
||||
WASM_BRV(2, WASM_I8(-1)), WASM_INC_LOCAL_BY(localIndex, 4))),
|
||||
WASM_I8(11))};
|
||||
f->EmitCode(code, sizeof(code));
|
||||
WasmModuleWriter* writer = builder->Build(&zone);
|
||||
TestModule(writer->WriteTo(&zone), 11);
|
||||
TestModule(&zone, builder, 11);
|
||||
}
|
||||
|
||||
TEST(Run_WasmModule_CallMain_recursive) {
|
||||
@ -142,8 +143,7 @@ TEST(Run_WasmModule_CallMain_recursive) {
|
||||
WASM_BRV(1, WASM_CALL_FUNCTION0(0))),
|
||||
WASM_BRV(0, WASM_I8(55))))};
|
||||
f->EmitCode(code, sizeof(code));
|
||||
WasmModuleWriter* writer = builder->Build(&zone);
|
||||
TestModule(writer->WriteTo(&zone), 55);
|
||||
TestModule(&zone, builder, 55);
|
||||
}
|
||||
|
||||
TEST(Run_WasmModule_Global) {
|
||||
@ -168,6 +168,5 @@ TEST(Run_WasmModule_Global) {
|
||||
WASM_STORE_GLOBAL(global2, WASM_I32V_1(41)),
|
||||
WASM_RETURN1(WASM_CALL_FUNCTION0(f1_index))};
|
||||
f->EmitCode(code2, sizeof(code2));
|
||||
WasmModuleWriter* writer = builder->Build(&zone);
|
||||
TestModule(writer->WriteTo(&zone), 97);
|
||||
TestModule(&zone, builder, 97);
|
||||
}
|
||||
|
@ -41,9 +41,9 @@ void testFunctionNameTable(Vector<Vector<const char>> names) {
|
||||
name.start() + name.length());
|
||||
// Make every second function name null-terminated.
|
||||
if (func_index % 2) all_names.push_back('\0');
|
||||
module.functions.push_back(
|
||||
{nullptr, 0, 0, static_cast<uint32_t>(name_offset),
|
||||
static_cast<uint32_t>(name.length()), 0, 0, false});
|
||||
module.functions.push_back({nullptr, 0, 0,
|
||||
static_cast<uint32_t>(name_offset),
|
||||
static_cast<uint32_t>(name.length()), 0, 0});
|
||||
++func_index;
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,7 @@ class TestingModule : public ModuleEnv {
|
||||
module_.functions.reserve(kMaxFunctions);
|
||||
}
|
||||
uint32_t index = static_cast<uint32_t>(module->functions.size());
|
||||
module_.functions.push_back({sig, index, 0, 0, 0, 0, 0, false});
|
||||
module_.functions.push_back({sig, index, 0, 0, 0, 0, 0});
|
||||
instance->function_code.push_back(code);
|
||||
if (interpreter_) {
|
||||
const WasmFunction* function = &module->functions.back();
|
||||
|
@ -1169,14 +1169,13 @@ class TestModuleEnv : public ModuleEnv {
|
||||
return static_cast<byte>(mod.signatures.size() - 1);
|
||||
}
|
||||
byte AddFunction(FunctionSig* sig) {
|
||||
mod.functions.push_back({sig, // sig
|
||||
0, // func_index
|
||||
0, // sig_index
|
||||
0, // name_offset
|
||||
0, // name_length
|
||||
0, // code_start_offset
|
||||
0, // code_end_offset
|
||||
false}); // exported
|
||||
mod.functions.push_back({sig, // sig
|
||||
0, // func_index
|
||||
0, // sig_index
|
||||
0, // name_offset
|
||||
0, // name_length
|
||||
0, // code_start_offset
|
||||
0}); // code_end_offset
|
||||
CHECK(mod.functions.size() <= 127);
|
||||
return static_cast<byte>(mod.functions.size() - 1);
|
||||
}
|
||||
|
@ -39,6 +39,38 @@ namespace wasm {
|
||||
#define EMPTY_FUNCTION_BODIES_SECTION SECTION(FUNCTION_BODIES, 1), 0
|
||||
#define EMPTY_NAMES_SECTION SECTION(NAMES, 1), 0
|
||||
|
||||
#define X1(...) __VA_ARGS__
|
||||
#define X2(...) __VA_ARGS__, __VA_ARGS__
|
||||
#define X3(...) __VA_ARGS__, __VA_ARGS__, __VA_ARGS__
|
||||
#define X4(...) __VA_ARGS__, __VA_ARGS__, __VA_ARGS__, __VA_ARGS__
|
||||
|
||||
#define ONE_EMPTY_FUNCTION WASM_SECTION_FUNCTION_SIGNATURES, 1 + 1 * 1, 1, X1(0)
|
||||
|
||||
#define TWO_EMPTY_FUNCTIONS \
|
||||
WASM_SECTION_FUNCTION_SIGNATURES, 1 + 2 * 1, 2, X2(0)
|
||||
|
||||
#define THREE_EMPTY_FUNCTIONS \
|
||||
WASM_SECTION_FUNCTION_SIGNATURES, 1 + 3 * 1, 3, X3(0)
|
||||
|
||||
#define FOUR_EMPTY_FUNCTIONS \
|
||||
WASM_SECTION_FUNCTION_SIGNATURES, 1 + 4 * 1, 4, X4(0)
|
||||
|
||||
#define ONE_EMPTY_BODY \
|
||||
WASM_SECTION_FUNCTION_BODIES, 1 + 1 * (1 + SIZEOF_EMPTY_BODY), 1, \
|
||||
X1(SIZEOF_EMPTY_BODY, EMPTY_BODY)
|
||||
|
||||
#define TWO_EMPTY_BODIES \
|
||||
WASM_SECTION_FUNCTION_BODIES, 1 + 2 * (1 + SIZEOF_EMPTY_BODY), 2, \
|
||||
X2(SIZEOF_EMPTY_BODY, EMPTY_BODY)
|
||||
|
||||
#define THREE_EMPTY_BODIES \
|
||||
WASM_SECTION_FUNCTION_BODIES, 1 + 3 * (1 + SIZEOF_EMPTY_BODY), 3, \
|
||||
X3(SIZEOF_EMPTY_BODY, EMPTY_BODY)
|
||||
|
||||
#define FOUR_EMPTY_BODIES \
|
||||
WASM_SECTION_FUNCTION_BODIES, 1 + 4 * (1 + SIZEOF_EMPTY_BODY), 4, \
|
||||
X4(SIZEOF_EMPTY_BODY, EMPTY_BODY)
|
||||
|
||||
#define SIGNATURES_SECTION_VOID_VOID \
|
||||
SECTION(SIGNATURES, 1 + SIZEOF_SIG_ENTRY_v_v), 1, SIG_ENTRY_v_v
|
||||
|
||||
@ -321,163 +353,6 @@ TEST_F(WasmModuleVerifyTest, MultipleSignatures) {
|
||||
EXPECT_OFF_END_FAILURE(data, 1, sizeof(data));
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, FunctionWithoutSig) {
|
||||
static const byte data[] = {
|
||||
SECTION(OLD_FUNCTIONS, 25), 1,
|
||||
// func#0 ------------------------------------------------------
|
||||
SIG_INDEX(0), // signature index
|
||||
NO_NAME, // name length
|
||||
U32_LE(0), // code start offset
|
||||
U32_LE(0), // code end offset
|
||||
U16_LE(899), // local int32 count
|
||||
U16_LE(799), // local int64 count
|
||||
U16_LE(699), // local float32 count
|
||||
U16_LE(599), // local float64 count
|
||||
0, // exported
|
||||
0 // external
|
||||
};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_FALSE(result.ok());
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) {
|
||||
const int kCodeStartOffset = 41;
|
||||
const int kCodeEndOffset = kCodeStartOffset + 1;
|
||||
|
||||
static const byte data[] = {
|
||||
// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
// func#0 ------------------------------------------------------
|
||||
SECTION(OLD_FUNCTIONS, 10), 1, kDeclFunctionExport | kDeclFunctionName,
|
||||
SIG_INDEX(0), // signature index
|
||||
NAME_LENGTH(2), 'h', 'i', // name
|
||||
1, 0, // size
|
||||
kExprNop,
|
||||
};
|
||||
|
||||
{
|
||||
// Should decode to exactly one function.
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(0, result.val->globals.size());
|
||||
EXPECT_EQ(1, result.val->signatures.size());
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
EXPECT_EQ(0, result.val->data_segments.size());
|
||||
EXPECT_EQ(0, result.val->function_table.size());
|
||||
|
||||
const WasmFunction* function = &result.val->functions.back();
|
||||
|
||||
EXPECT_EQ(37, function->name_offset);
|
||||
EXPECT_EQ(2, function->name_length);
|
||||
EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
|
||||
EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
|
||||
|
||||
EXPECT_TRUE(function->exported);
|
||||
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
|
||||
EXPECT_OFF_END_FAILURE(data, 16, sizeof(data));
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody) {
|
||||
static const byte kCodeStartOffset = 38;
|
||||
static const byte kCodeEndOffset = kCodeStartOffset + 1;
|
||||
|
||||
static const byte data[] = {
|
||||
SIGNATURES_SECTION_VOID_VOID, // --
|
||||
SECTION(OLD_FUNCTIONS, 7), 1,
|
||||
// func#0 ------------------------------------------------------
|
||||
0, // no name, no locals
|
||||
0, 0, // signature index
|
||||
1, 0, // body size
|
||||
kExprNop // body
|
||||
};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
const WasmFunction* function = &result.val->functions.back();
|
||||
|
||||
EXPECT_EQ(0, function->name_length);
|
||||
EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
|
||||
EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
|
||||
|
||||
EXPECT_FALSE(function->exported);
|
||||
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) {
|
||||
static const byte kNameOffset = 49;
|
||||
static const byte kCodeStartOffset = 53;
|
||||
static const byte kCodeEndOffset = kCodeStartOffset + 3;
|
||||
static const byte kDataSegmentSourceOffset = kCodeEndOffset + 22;
|
||||
|
||||
static const byte data[] = {
|
||||
// global#0 --------------------------------------------------
|
||||
SECTION(GLOBALS, 4), 1,
|
||||
0, // name length
|
||||
kMemU8, // memory type
|
||||
0, // exported
|
||||
// sig#0 -----------------------------------------------------
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
// func#0 ----------------------------------------------------
|
||||
SECTION(OLD_FUNCTIONS, 12), 1,
|
||||
kDeclFunctionName, // --
|
||||
SIG_INDEX(0), // signature index
|
||||
2, 'h', 'i', // name
|
||||
3, 0, // body size
|
||||
kExprNop, // func#0 body
|
||||
kExprNop, // func#0 body
|
||||
kExprNop, // func#0 body
|
||||
// memory section --------------------------------------------
|
||||
SECTION(MEMORY, 3), 28, 28, 1,
|
||||
// segment#0 -------------------------------------------------
|
||||
SECTION(DATA_SEGMENTS, 10), 1,
|
||||
U32V_3(0x8b3ae), // dest addr
|
||||
U32V_1(5), // source size
|
||||
0, 1, 2, 3, 4, // data bytes
|
||||
// rest ------------------------------------------------------
|
||||
SECTION(END, 0),
|
||||
};
|
||||
|
||||
{
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(1, result.val->globals.size());
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
EXPECT_EQ(1, result.val->data_segments.size());
|
||||
|
||||
const WasmGlobal* global = &result.val->globals.back();
|
||||
|
||||
EXPECT_EQ(0, global->name_length);
|
||||
EXPECT_EQ(MachineType::Uint8(), global->type);
|
||||
EXPECT_EQ(0, global->offset);
|
||||
EXPECT_FALSE(global->exported);
|
||||
|
||||
const WasmFunction* function = &result.val->functions.back();
|
||||
|
||||
EXPECT_EQ(kNameOffset, function->name_offset);
|
||||
EXPECT_EQ(2, function->name_length);
|
||||
EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
|
||||
EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
|
||||
|
||||
EXPECT_FALSE(function->exported);
|
||||
|
||||
const WasmDataSegment* segment = &result.val->data_segments.back();
|
||||
|
||||
EXPECT_EQ(0x8b3ae, segment->dest_addr);
|
||||
EXPECT_EQ(kDataSegmentSourceOffset, segment->source_offset);
|
||||
EXPECT_EQ(5, segment->source_size);
|
||||
EXPECT_TRUE(segment->init);
|
||||
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, OneDataSegment) {
|
||||
const byte kDataSegmentSourceOffset = 30;
|
||||
const byte data[] = {
|
||||
@ -605,9 +480,8 @@ TEST_F(WasmModuleVerifyTest, OneIndirectFunction) {
|
||||
static const byte data[] = {
|
||||
// sig#0 -------------------------------------------------------
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
// func#0 ------------------------------------------------------
|
||||
SECTION(OLD_FUNCTIONS, 1 + SIZEOF_EMPTY_FUNCTION), 1, // --
|
||||
EMPTY_FUNCTION(0),
|
||||
// funcs ------------------------------------------------------
|
||||
ONE_EMPTY_FUNCTION,
|
||||
// indirect table ----------------------------------------------
|
||||
SECTION(FUNCTION_TABLE, 2), 1, U32V_1(0)};
|
||||
|
||||
@ -629,12 +503,8 @@ TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) {
|
||||
2, // --
|
||||
SIG_ENTRY_v_v, // void -> void
|
||||
SIG_ENTRY_v_x(kLocalI32), // void -> i32
|
||||
// func#0 ------------------------------------------------------
|
||||
SECTION(OLD_FUNCTIONS, 1 + 4 * SIZEOF_EMPTY_FUNCTION), 4, // --
|
||||
EMPTY_FUNCTION(0), // --
|
||||
EMPTY_FUNCTION(1), // --
|
||||
EMPTY_FUNCTION(0), // --
|
||||
EMPTY_FUNCTION(1), // --
|
||||
// funcs ------------------------------------------------------
|
||||
FOUR_EMPTY_FUNCTIONS,
|
||||
// indirect table ----------------------------------------------
|
||||
SECTION(FUNCTION_TABLE, 9), 8,
|
||||
U32V_1(0), // --
|
||||
@ -645,7 +515,7 @@ TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) {
|
||||
U32V_1(1), // --
|
||||
U32V_1(2), // --
|
||||
U32V_1(3), // --
|
||||
};
|
||||
FOUR_EMPTY_BODIES};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_OK(result);
|
||||
@ -676,8 +546,7 @@ TEST_F(WasmModuleVerifyTest, IndirectFunctionInvalidIndex) {
|
||||
// sig#0 -------------------------------------------------------
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
// functions ---------------------------------------------------
|
||||
SECTION(OLD_FUNCTIONS, 1 + SIZEOF_EMPTY_FUNCTION), 1, // --
|
||||
EMPTY_FUNCTION(0),
|
||||
ONE_EMPTY_FUNCTION,
|
||||
// indirect table ----------------------------------------------
|
||||
SECTION(FUNCTION_TABLE, 3), 1, 1, 0,
|
||||
};
|
||||
@ -839,7 +708,6 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
|
||||
EXPECT_EQ(SIZEOF_SIG_ENTRY_v_v, function->code_start_offset);
|
||||
EXPECT_EQ(arraysize(data), function->code_end_offset);
|
||||
// TODO(titzer): verify encoding of local declarations
|
||||
EXPECT_FALSE(function->exported);
|
||||
}
|
||||
|
||||
if (result.val) delete result.val;
|
||||
@ -1071,22 +939,24 @@ TEST_F(WasmModuleVerifyTest, ImportTable_off_end) {
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ExportTable_empty1) {
|
||||
static const byte data[] = {
|
||||
// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
SECTION(OLD_FUNCTIONS, 1 + SIZEOF_EMPTY_FUNCTION),
|
||||
1,
|
||||
EMPTY_FUNCTION(0),
|
||||
SECTION(EXPORT_TABLE, 1),
|
||||
0 // --
|
||||
};
|
||||
EXPECT_VERIFIES(data);
|
||||
static const byte data[] = {// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID, ONE_EMPTY_FUNCTION,
|
||||
SECTION(EXPORT_TABLE, 1),
|
||||
0, // --
|
||||
ONE_EMPTY_BODY};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_OK(result);
|
||||
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
EXPECT_EQ(0, result.val->export_table.size());
|
||||
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ExportTable_empty2) {
|
||||
static const byte data[] = {
|
||||
SECTION(SIGNATURES, 1), 0, SECTION(OLD_FUNCTIONS, 1), 0,
|
||||
SECTION(EXPORT_TABLE, 1), 0 // --
|
||||
SECTION(SIGNATURES, 1), 0, SECTION(EXPORT_TABLE, 1), 0 // --
|
||||
};
|
||||
// TODO(titzer): current behavior treats empty functions section as missing.
|
||||
EXPECT_FAILURE(data);
|
||||
@ -1105,85 +975,88 @@ TEST_F(WasmModuleVerifyTest, ExportTable_NoFunctions2) {
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ExportTableOne) {
|
||||
static const byte data[] = {
|
||||
// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
SECTION(OLD_FUNCTIONS, 1 + SIZEOF_EMPTY_FUNCTION),
|
||||
1, // functions
|
||||
EMPTY_FUNCTION(0), // --
|
||||
SECTION(EXPORT_TABLE, 3),
|
||||
1, // exports
|
||||
FUNC_INDEX(0), // --
|
||||
NO_NAME // --
|
||||
};
|
||||
EXPECT_VERIFIES(data);
|
||||
static const byte data[] = {// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
ONE_EMPTY_FUNCTION,
|
||||
SECTION(EXPORT_TABLE, 3),
|
||||
1, // exports
|
||||
FUNC_INDEX(0), // --
|
||||
NO_NAME, // --
|
||||
ONE_EMPTY_BODY};
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_OK(result);
|
||||
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
EXPECT_EQ(1, result.val->export_table.size());
|
||||
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ExportTableTwo) {
|
||||
static const byte data[] = {
|
||||
// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
SECTION(OLD_FUNCTIONS, 1 + SIZEOF_EMPTY_FUNCTION),
|
||||
1, // functions
|
||||
EMPTY_FUNCTION(0), // --
|
||||
SECTION(EXPORT_TABLE, 12),
|
||||
2, // exports
|
||||
FUNC_INDEX(0), // --
|
||||
NAME_LENGTH(4),
|
||||
'n',
|
||||
'a',
|
||||
'm',
|
||||
'e', // --
|
||||
FUNC_INDEX(0), // --
|
||||
NAME_LENGTH(3),
|
||||
'n',
|
||||
'o',
|
||||
'm' // --
|
||||
};
|
||||
EXPECT_VERIFIES(data);
|
||||
static const byte data[] = {// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
ONE_EMPTY_FUNCTION,
|
||||
SECTION(EXPORT_TABLE, 12),
|
||||
2, // exports
|
||||
FUNC_INDEX(0), // --
|
||||
NAME_LENGTH(4),
|
||||
'n',
|
||||
'a',
|
||||
'm',
|
||||
'e', // --
|
||||
FUNC_INDEX(0), // --
|
||||
NAME_LENGTH(3),
|
||||
'n',
|
||||
'o',
|
||||
'm', // --
|
||||
ONE_EMPTY_BODY};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_OK(result);
|
||||
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
EXPECT_EQ(2, result.val->export_table.size());
|
||||
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ExportTableThree) {
|
||||
static const byte data[] = {
|
||||
// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
SECTION(OLD_FUNCTIONS, 1 + 3 * SIZEOF_EMPTY_FUNCTION),
|
||||
3, // functions
|
||||
EMPTY_FUNCTION(0), // --
|
||||
EMPTY_FUNCTION(0), // --
|
||||
EMPTY_FUNCTION(0), // --
|
||||
SECTION(EXPORT_TABLE, 10),
|
||||
3, // exports
|
||||
FUNC_INDEX(0), // --
|
||||
NAME_LENGTH(1),
|
||||
'a', // --
|
||||
FUNC_INDEX(1), // --
|
||||
NAME_LENGTH(1),
|
||||
'b', // --
|
||||
FUNC_INDEX(2), // --
|
||||
NAME_LENGTH(1),
|
||||
'c' // --
|
||||
};
|
||||
EXPECT_VERIFIES(data);
|
||||
static const byte data[] = {// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
THREE_EMPTY_FUNCTIONS,
|
||||
SECTION(EXPORT_TABLE, 10),
|
||||
3, // exports
|
||||
FUNC_INDEX(0), // --
|
||||
NAME_LENGTH(1),
|
||||
'a', // --
|
||||
FUNC_INDEX(1), // --
|
||||
NAME_LENGTH(1),
|
||||
'b', // --
|
||||
FUNC_INDEX(2), // --
|
||||
NAME_LENGTH(1),
|
||||
'c', // --
|
||||
THREE_EMPTY_BODIES};
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_OK(result);
|
||||
|
||||
EXPECT_EQ(3, result.val->functions.size());
|
||||
EXPECT_EQ(3, result.val->export_table.size());
|
||||
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ExportTableThreeOne) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
const byte data[] = {
|
||||
// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
SECTION(OLD_FUNCTIONS, 1 + 3 * SIZEOF_EMPTY_FUNCTION),
|
||||
3, // functions
|
||||
EMPTY_FUNCTION(0), // --
|
||||
EMPTY_FUNCTION(0), // --
|
||||
EMPTY_FUNCTION(0), // --
|
||||
SECTION(EXPORT_TABLE, 5),
|
||||
1, // exports
|
||||
FUNC_INDEX(i), // --
|
||||
NAME_LENGTH(2),
|
||||
'e',
|
||||
'x', // --
|
||||
};
|
||||
const byte data[] = {// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
THREE_EMPTY_FUNCTIONS,
|
||||
SECTION(EXPORT_TABLE, 5),
|
||||
1, // exports
|
||||
FUNC_INDEX(i), // --
|
||||
NAME_LENGTH(2),
|
||||
'e',
|
||||
'x', // --
|
||||
THREE_EMPTY_BODIES};
|
||||
|
||||
if (i < 3) {
|
||||
EXPECT_VERIFIES(data);
|
||||
@ -1197,9 +1070,7 @@ TEST_F(WasmModuleVerifyTest, ExportTableOne_off_end) {
|
||||
static const byte data[] = {
|
||||
// signatures
|
||||
SIGNATURES_SECTION_VOID_VOID,
|
||||
SECTION(OLD_FUNCTIONS, 1 + SIZEOF_EMPTY_FUNCTION),
|
||||
1, // functions
|
||||
EMPTY_FUNCTION(0), // --
|
||||
ONE_EMPTY_FUNCTION,
|
||||
SECTION(EXPORT_TABLE, 1 + 6),
|
||||
1, // exports
|
||||
FUNC_INDEX(0), // --
|
||||
|
Loading…
Reference in New Issue
Block a user