Commit 4cb568ec authored by titzer's avatar titzer Committed by Commit bot

[wasm] Encode function signatures, bodies, and names as separate sections.

R=binji@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1783593002

Cr-Commit-Position: refs/heads/master@{#34641}
parent c48c1736
......@@ -333,6 +333,7 @@ class Decoder {
const byte* start() { return start_; }
const byte* pc() { return pc_; }
uint32_t pc_offset() { return static_cast<uint32_t>(pc_ - start_); }
protected:
const byte* start_;
......
This diff is collapsed.
......@@ -29,17 +29,20 @@ const uint32_t kWasmVersion = 0x0a;
// internally V8 uses an enum to handle them.
//
// Entries have the form F(enumerator, string).
#define FOR_EACH_WASM_SECTION_TYPE(F) \
F(kDeclMemory, "memory") \
F(kDeclSignatures, "signatures") \
F(kDeclFunctions, "functions") \
F(kDeclGlobals, "globals") \
F(kDeclDataSegments, "data_segments") \
F(kDeclFunctionTable, "function_table") \
F(kDeclEnd, "end") \
F(kDeclStartFunction, "start_function") \
F(kDeclImportTable, "import_table") \
F(kDeclExportTable, "export_table")
#define FOR_EACH_WASM_SECTION_TYPE(F) \
F(kDeclMemory, "memory") \
F(kDeclSignatures, "signatures") \
F(kDeclFunctions, "functions") \
F(kDeclGlobals, "globals") \
F(kDeclDataSegments, "data_segments") \
F(kDeclFunctionTable, "function_table") \
F(kDeclEnd, "end") \
F(kDeclStartFunction, "start_function") \
F(kDeclImportTable, "import_table") \
F(kDeclExportTable, "export_table") \
F(kDeclFunctionSignatures, "function_signatures") \
F(kDeclFunctionBodies, "function_bodies") \
F(kDeclNames, "names")
enum WasmSectionDeclCode : uint32_t {
#define F(enumerator, string) enumerator,
......
......@@ -61,6 +61,9 @@ var kDeclStartFunction = 0x07;
var kDeclImportTable = 0x08;
var kDeclExportTable = 0x09;
var kDeclEnd = 0x06;
var kDeclFunctionSignatures = 0x0a;
var kDeclFunctionBodies = 0x0b;
var kDeclNames = 0x0c;
// Function declaration flags
var kDeclFunctionName = 0x01;
......
......@@ -125,6 +125,12 @@ function emit_varint(bytes, val) {
}
}
function emit_bytes(bytes, data) {
for (var i = 0; i < data.length; i++) {
bytes.push(data[i] & 0xff);
}
}
WasmModuleBuilder.prototype.toArray = function(debug) {
// Add header bytes
var bytes = [];
......@@ -170,26 +176,26 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
var names = false;
var exports = 0;
if (this.functions.length > 0) {
if (debug) print("emitting functions @ " + bytes.length);
emit_u8(bytes, kDeclFunctions);
var has_names = false;
// emit function signatures
if (debug) print("emitting function sigs @ " + bytes.length);
emit_u8(bytes, kDeclFunctionSignatures);
emit_varint(bytes, this.functions.length);
var index = 0;
for (func of this.functions) {
var flags = 0;
var hasName = func.name != undefined && func.name.length > 0;
names = names || hasName;
if (hasName) flags |= kDeclFunctionName;
exports += func.exports.length;
emit_u8(bytes, flags);
emit_u16(bytes, func.sig_index);
has_names = has_names || (func.name != undefined &&
func.name.length > 0);
exports += func.exports.length;
if (hasName) emit_string(bytes, func.name);
emit_varint(bytes, func.sig_index);
}
// emit function bodies
if (debug) print("emitting function bodies @ " + bytes.length);
emit_u8(bytes, kDeclFunctionBodies);
emit_varint(bytes, this.functions.length);
for (func of this.functions) {
// Function body length will be patched later.
var length_pos = bytes.length;
emit_u16(bytes, 0);
var local_decls = [];
var l = func.locals;
if (l != undefined) {
......@@ -207,28 +213,37 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
local_decls.push({count: l.f64_count, type: kAstF64});
}
}
emit_varint(bytes, local_decls.length);
var header = new Array();
emit_varint(header, local_decls.length);
for (decl of local_decls) {
emit_varint(bytes, decl.count);
emit_u8(bytes, decl.type);
emit_varint(header, decl.count);
emit_u8(header, decl.type);
}
for (var i = 0; i < func.body.length; i++) {
emit_u8(bytes, func.body[i]);
}
var length = bytes.length - length_pos - 2;
bytes[length_pos] = length & 0xff;
bytes[length_pos + 1] = (length >> 8) & 0xff;
emit_varint(bytes, header.length + func.body.length);
emit_bytes(bytes, header);
emit_bytes(bytes, func.body);
}
}
index++;
// emit function names
if (has_names) {
if (debug) print("emitting names @ " + bytes.length);
emit_u8(bytes, kDeclNames);
emit_varint(bytes, this.functions.length);
for (func of this.functions) {
var name = func.name == undefined ? "" : func.name;
emit_string(bytes, name);
emit_u8(bytes, 0); // local names count == 0
}
}
// Add start function section.
if (this.start_index != undefined) {
if (debug) print("emitting start function @ " + bytes.length);
emit_u8(bytes, kDeclStartFunction);
emit_varint(bytes, this.start_index);
emit_u8(bytes, kDeclStartFunction);
emit_varint(bytes, this.start_index);
}
if (this.function_table.length > 0) {
......@@ -259,18 +274,14 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
for (seg of this.data_segments) {
emit_varint(bytes, seg.addr);
emit_varint(bytes, seg.data.length);
for (var i = 0; i < seg.data.length; i++) {
emit_u8(bytes, seg.data[i]);
}
emit_bytes(bytes, seg.data);
}
}
// Emit any explicitly added sections
for (exp of this.explicit) {
if (debug) print("emitting explicit @ " + bytes.length);
for (var i = 0; i < exp.length; i++) {
emit_u8(bytes, exp[i]);
}
emit_bytes(bytes, exp);
}
// End the module.
......
......@@ -13,6 +13,8 @@ namespace internal {
namespace wasm {
#define EMPTY_FUNCTION(sig_index) 0, SIG_INDEX(sig_index), U16_LE(0)
#define EMPTY_BODY 0
#define NOP_BODY 2, 0, kExprNop
#define VOID_VOID_SIG 0, kLocalVoid
#define INT_INT_SIG 1, kLocalI32, kLocalI32
......@@ -1059,12 +1061,20 @@ TEST_F(WasmModuleVerifyTest, ImportTable_off_end) {
EXPECT_OFF_END_FAILURE(data, 5, sizeof(data));
}
TEST_F(WasmModuleVerifyTest, ExportTable_empty) {
static const byte data[] = {kDeclSignatures, 0, kDeclFunctions, 0,
TEST_F(WasmModuleVerifyTest, ExportTable_empty1) {
static const byte data[] = {kDeclSignatures, 1, VOID_VOID_SIG,
kDeclFunctions, 1, EMPTY_FUNCTION(0),
kDeclExportTable, 0};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, ExportTable_empty2) {
static const byte data[] = {kDeclSignatures, 0, kDeclFunctions, 0,
kDeclExportTable, 0};
// TODO(titzer): current behavior treats empty functions section as missing.
EXPECT_FAILURE(data);
}
TEST_F(WasmModuleVerifyTest, ExportTable_NoFunctions1) {
static const byte data[] = {kDeclSignatures, 0, kDeclExportTable, 0};
EXPECT_FAILURE(data);
......@@ -1162,6 +1172,96 @@ TEST_F(WasmModuleVerifyTest, ExportTableOne_off_end) {
}
}
#define SIGNATURES_SECTION(count, ...) \
kDeclSignatures, U32V_1(count), __VA_ARGS__
#define FUNCTION_SIGNATURES_SECTION(count, ...) \
kDeclFunctionSignatures, U32V_1(count), __VA_ARGS__
#define FUNCTION_BODIES_SECTION(count, ...) \
kDeclFunctionBodies, U32V_1(count), __VA_ARGS__
#define NAMES_SECTION(count, ...) kDeclNames, U32V_1(count), __VA_ARGS__
#define FOO_STRING 3, 'f', 'o', 'o'
#define NO_LOCAL_NAMES 0
#define EMPTY_SIGNATURES_SECTION kDeclSignatures, 0
#define EMPTY_FUNCTION_SIGNATURES_SECTION kDeclFunctionSignatures, 0
#define EMPTY_FUNCTION_BODIES_SECTION kDeclFunctionBodies, 0
#define EMPTY_NAMES_SECTION kDeclNames, 0
TEST_F(WasmModuleVerifyTest, FunctionSignatures_empty) {
static const byte data[] = {kDeclSignatures, 0, kDeclFunctionSignatures, 0};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, FunctionSignatures_one) {
static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG),
FUNCTION_SIGNATURES_SECTION(1, 0)};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, FunctionBodies_empty) {
static const byte data[] = {EMPTY_SIGNATURES_SECTION,
EMPTY_FUNCTION_SIGNATURES_SECTION,
EMPTY_FUNCTION_BODIES_SECTION};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, FunctionBodies_one_empty) {
static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG),
FUNCTION_SIGNATURES_SECTION(1, 0),
FUNCTION_BODIES_SECTION(1, EMPTY_BODY)};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, FunctionBodies_one_nop) {
static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG),
FUNCTION_SIGNATURES_SECTION(1, 0),
FUNCTION_BODIES_SECTION(1, NOP_BODY)};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, FunctionBodies_count_mismatch1) {
static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG),
FUNCTION_SIGNATURES_SECTION(2, 0, 0),
FUNCTION_BODIES_SECTION(1, EMPTY_BODY)};
EXPECT_FAILURE(data);
}
TEST_F(WasmModuleVerifyTest, FunctionBodies_count_mismatch2) {
static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG),
FUNCTION_SIGNATURES_SECTION(1, 0),
FUNCTION_BODIES_SECTION(2, NOP_BODY, NOP_BODY)};
EXPECT_FAILURE(data);
}
TEST_F(WasmModuleVerifyTest, Names_empty) {
static const byte data[] = {
EMPTY_SIGNATURES_SECTION, EMPTY_FUNCTION_SIGNATURES_SECTION,
EMPTY_FUNCTION_BODIES_SECTION, EMPTY_NAMES_SECTION};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, Names_one_empty) {
static const byte data[] = {
SIGNATURES_SECTION(1, VOID_VOID_SIG), // --
FUNCTION_SIGNATURES_SECTION(1, 0), // --
FUNCTION_BODIES_SECTION(1, EMPTY_BODY), // --
NAMES_SECTION(1, FOO_STRING, NO_LOCAL_NAMES) // --
};
EXPECT_VERIFIES(data);
}
TEST_F(WasmModuleVerifyTest, Names_two_empty) {
static const byte data[] = {
SIGNATURES_SECTION(1, VOID_VOID_SIG), // --
FUNCTION_SIGNATURES_SECTION(2, 0, 0), // --
FUNCTION_BODIES_SECTION(2, EMPTY_BODY, EMPTY_BODY), // --
NAMES_SECTION(2, FOO_STRING, NO_LOCAL_NAMES, // --
FOO_STRING, NO_LOCAL_NAMES) // --
};
EXPECT_VERIFIES(data);
}
} // namespace wasm
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment