Commit ee03b721 authored by titzer's avatar titzer Committed by Commit bot

[wasm] Binary 11: Bump module version to 0xB.

[wasm] Binary 11: Swap the order of section name / section length.
[wasm] Binary 11: Shorter section names.
[wasm] Binary 11: Add a prefix for function type declarations.
[wasm] Binary 11: Function types encoded as pcount, p*, rcount, r*
[wasm] Fix numeric names for functions.

R=rossberg@chromium.org,jfb@chromium.org,ahaas@chromium.org
BUG=chromium:575167
LOG=Y

Review-Url: https://codereview.chromium.org/1896863003
Cr-Commit-Position: refs/heads/master@{#35897}
parent 2aa4656e
......@@ -80,11 +80,6 @@ void FixupSection(byte* start, byte* end) {
// Returns the start of the section, where the section VarInt size is.
byte* EmitSection(WasmSection::Code code, byte** b) {
// 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.
}
// Emit the section name.
const char* name = WasmSection::getName(code);
TRACE("emit section: %s\n", name);
......@@ -92,6 +87,12 @@ byte* EmitSection(WasmSection::Code code, byte** b) {
EmitVarInt(b, length); // Section name string size.
for (size_t i = 0; i != length; ++i) EmitUint8(b, name[i]);
// 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;
}
} // namespace
......@@ -586,7 +587,9 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
sizes.AddSection(WasmSection::Code::Signatures, signatures_.size());
for (auto sig : signatures_) {
sizes.Add(1 + LEBHelper::sizeof_u32v(sig->parameter_count()) +
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,
......@@ -594,7 +597,7 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
}
if (functions_.size() > 0) {
sizes.AddSection(WasmSection::Code::Functions, functions_.size());
sizes.AddSection(WasmSection::Code::OldFunctions, functions_.size());
for (auto function : functions_) {
sizes.Add(function->HeaderSize() + function->BodySize(),
function->NameSize());
......@@ -669,22 +672,22 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
EmitVarInt(&header, signatures_.size());
for (FunctionSig* sig : signatures_) {
EmitUint8(&header, kWasmFunctionTypeForm);
EmitVarInt(&header, sig->parameter_count());
if (sig->return_count() > 0) {
EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetReturn()));
} else {
EmitUint8(&header, kLocalVoid);
}
for (size_t j = 0; j < sig->parameter_count(); j++) {
EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j)));
}
EmitVarInt(&header, sig->return_count());
for (size_t j = 0; j < sig->return_count(); j++) {
EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetReturn(j)));
}
}
FixupSection(section, header);
}
// -- emit functions ---------------------------------------------------------
if (functions_.size() > 0) {
byte* section = EmitSection(WasmSection::Code::Functions, &header);
byte* section = EmitSection(WasmSection::Code::OldFunctions, &header);
EmitVarInt(&header, functions_.size());
for (auto func : functions_) {
......
......@@ -107,17 +107,6 @@ class ModuleDecoder : public Decoder {
TRACE("DecodeSection\n");
pos = pc_;
// Read and check the section size.
int section_leb_length = 0;
uint32_t section_length =
consume_u32v(&section_leb_length, "section length");
if (!checkAvailable(section_length)) {
// The section would extend beyond the end of the module.
break;
}
const byte* section_start = pc_;
const byte* expected_section_end = pc_ + section_length;
// Read the section name.
int string_leb_length = 0;
uint32_t string_length =
......@@ -128,15 +117,21 @@ class ModuleDecoder : public Decoder {
TRACE("Section name of length %u couldn't be read\n", string_length);
break;
}
if (pc_ > expected_section_end) {
error(section_name_start, pc_,
"section name string %u longer than total section bytes %u",
string_length, section_length);
}
WasmSection::Code section =
WasmSection::lookup(section_name_start, string_length);
// Read and check the section size.
int section_leb_length = 0;
uint32_t section_length =
consume_u32v(&section_leb_length, "section length");
if (!checkAvailable(section_length)) {
// The section would extend beyond the end of the module.
break;
}
const byte* section_start = pc_;
const byte* expected_section_end = pc_ + section_length;
current_order = CheckSectionOrder(current_order, section);
switch (section) {
......@@ -144,12 +139,13 @@ class ModuleDecoder : public Decoder {
// Terminate section decoding.
limit_ = pc_;
break;
case WasmSection::Code::Memory:
case WasmSection::Code::Memory: {
int length;
module->min_mem_pages = consume_u32v(&length, "min memory");
module->max_mem_pages = consume_u32v(&length, "max memory");
module->mem_export = consume_u8("export memory") != 0;
break;
}
case WasmSection::Code::Signatures: {
int length;
uint32_t signatures_count = consume_u32v(&length, "signatures count");
......@@ -159,7 +155,7 @@ class ModuleDecoder : public Decoder {
if (failed()) break;
TRACE("DecodeSignature[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
FunctionSig* s = consume_sig(); // read function sig.
FunctionSig* s = consume_sig();
module->signatures.push_back(s);
}
break;
......@@ -202,7 +198,7 @@ class ModuleDecoder : public Decoder {
}
break;
}
case WasmSection::Code::Functions: {
case WasmSection::Code::OldFunctions: {
int length;
uint32_t functions_count = consume_u32v(&length, "functions count");
module->functions.reserve(SafeReserve(functions_count));
......@@ -385,7 +381,7 @@ class ModuleDecoder : public Decoder {
TRACE("%c", *(section_name_start + i));
}
TRACE("'\n");
consume_bytes(section_length - string_length - string_leb_length);
consume_bytes(section_length);
break;
}
......@@ -700,20 +696,48 @@ class ModuleDecoder : public Decoder {
}
}
// Parses an inline function signature.
// Parses a type entry, which is currently limited to functions only.
FunctionSig* consume_sig() {
const byte* pos = pc_;
byte form = consume_u8("type form");
if (form != kWasmFunctionTypeForm) {
error(pos, pos, "expected function type form (0x%02x), got: 0x%02x",
kWasmFunctionTypeForm, form);
return nullptr;
}
int length;
byte count = consume_u32v(&length, "param count");
LocalType ret = consume_local_type();
FunctionSig::Builder builder(module_zone, ret == kAstStmt ? 0 : 1, count);
if (ret != kAstStmt) builder.AddReturn(ret);
for (int i = 0; i < count; i++) {
// parse parameter types
uint32_t param_count = consume_u32v(&length, "param count");
std::vector<LocalType> params;
for (uint32_t i = 0; i < param_count; i++) {
LocalType param = consume_local_type();
if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type");
builder.AddParam(param);
params.push_back(param);
}
// parse return types
const byte* pt = pc_;
uint32_t return_count = consume_u32v(&length, "return count");
if (return_count > kMaxReturnCount) {
error(pt, pt, "return count of %u exceeds maximum of %u", return_count,
kMaxReturnCount);
return nullptr;
}
std::vector<LocalType> returns;
for (uint32_t i = 0; i < return_count; i++) {
LocalType ret = consume_local_type();
if (ret == kAstStmt) error(pc_ - 1, "invalid void return type");
returns.push_back(ret);
}
return builder.Build();
// FunctionSig stores the return types first.
LocalType* buffer =
module_zone->NewArray<LocalType>(param_count + return_count);
uint32_t b = 0;
for (uint32_t i = 0; i < return_count; i++) buffer[b++] = returns[i];
for (uint32_t i = 0; i < param_count; i++) buffer[b++] = params[i];
return new (module_zone) FunctionSig(return_count, param_count, buffer);
}
};
......
......@@ -564,4 +564,23 @@ class LocalDeclEncoder {
#define WASM_I32_REINTERPRET_F32(x) x, kExprI32ReinterpretF32
#define WASM_I64_REINTERPRET_F64(x) x, kExprI64ReinterpretF64
#define SIG_ENTRY_v_v kWasmFunctionTypeForm, 0, 0
#define SIZEOF_SIG_ENTRY_v_v 3
#define SIG_ENTRY_v_x(a) kWasmFunctionTypeForm, 1, a, 0
#define SIG_ENTRY_v_xx(a, b) kWasmFunctionTypeForm, 2, a, b, 0
#define SIG_ENTRY_v_xxx(a, b, c) kWasmFunctionTypeForm, 3, a, b, c, 0
#define SIZEOF_SIG_ENTRY_v_x 4
#define SIZEOF_SIG_ENTRY_v_xx 5
#define SIZEOF_SIG_ENTRY_v_xxx 6
#define SIG_ENTRY_x(r) kWasmFunctionTypeForm, 0, 1, r
#define SIG_ENTRY_x_x(r, a) kWasmFunctionTypeForm, 1, a, 1, r
#define SIG_ENTRY_x_xx(r, a, b) kWasmFunctionTypeForm, 2, a, b, 1, r
#define SIG_ENTRY_x_xxx(r, a, b, c) kWasmFunctionTypeForm, 3, a, b, c, 1, r
#define SIZEOF_SIG_ENTRY_x 4
#define SIZEOF_SIG_ENTRY_x_x 5
#define SIZEOF_SIG_ENTRY_x_xx 6
#define SIZEOF_SIG_ENTRY_x_xxx 7
#endif // V8_WASM_MACRO_GEN_H_
......@@ -4,6 +4,7 @@
#include "src/macro-assembler.h"
#include "src/objects.h"
#include "src/property-descriptor.h"
#include "src/v8.h"
#include "src/simulator.h"
......@@ -409,6 +410,9 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
Factory* factory = isolate->factory();
PropertyDescriptor desc;
desc.set_writable(false);
//-------------------------------------------------------------------------
// Allocate the instance and its JS counterpart.
//-------------------------------------------------------------------------
......@@ -562,7 +566,11 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
if (func.exported) {
// Exported functions are installed as read-only properties on the
// module.
JSObject::AddProperty(instance.js_object, name, function, READ_ONLY);
desc.set_value(function);
Maybe<bool> status = JSReceiver::DefineOwnProperty(
isolate, instance.js_object, name, &desc, Object::THROW_ON_ERROR);
if (!status.IsJust())
thrower.Error("export of %.*s failed.", str.length(), str.start());
}
}
......@@ -593,7 +601,11 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
Handle<JSFunction> function = compiler::CompileJSToWasmWrapper(
isolate, &module_env, name, code, instance.js_object,
exp.func_index);
JSObject::AddProperty(exports_object, name, function, READ_ONLY);
desc.set_value(function);
Maybe<bool> status = JSReceiver::DefineOwnProperty(
isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
if (!status.IsJust())
thrower.Error("export of %.*s failed.", str.length(), str.start());
}
if (mem_export) {
......
......@@ -24,65 +24,59 @@ const size_t kMaxModuleSize = 1024 * 1024 * 1024;
const size_t kMaxFunctionSize = 128 * 1024;
const size_t kMaxStringSize = 256;
const uint32_t kWasmMagic = 0x6d736100;
const uint32_t kWasmVersion = 0x0a;
const uint32_t kWasmVersion = 0x0b;
const uint8_t kWasmFunctionTypeForm = 0x40;
// WebAssembly sections are named as strings in the binary format, but
// internally V8 uses an enum to handle them.
//
// Entries have the form F(enumerator, order, string).
#define FOR_EACH_WASM_SECTION_TYPE(F) \
F(Signatures, 1, "signatures") \
F(ImportTable, 2, "import_table") \
F(FunctionSignatures, 3, "function_signatures") \
F(FunctionTable, 4, "function_table") \
F(Memory, 5, "memory") \
F(ExportTable, 6, "export_table") \
F(StartFunction, 7, "start_function") \
F(FunctionBodies, 8, "function_bodies") \
F(DataSegments, 9, "data_segments") \
F(Names, 10, "names") \
F(Globals, 0, "globals") \
F(Functions, 0, "functions") \
// Entries have the form F(enumerator, string).
#define FOR_EACH_WASM_SECTION_TYPE(F) \
F(Signatures, 1, "type") \
F(ImportTable, 2, "import") \
F(FunctionSignatures, 3, "function") \
F(FunctionTable, 4, "table") \
F(Memory, 5, "memory") \
F(ExportTable, 6, "export") \
F(StartFunction, 7, "start") \
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 \
10, 's', 'i', 'g', 'n', 'a', 't', 'u', 'r', 'e', 's'
#define WASM_SECTION_FUNCTIONS 9, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', 's'
#define WASM_SECTION_GLOBALS 7, 'g', 'l', 'o', 'b', 'a', 'l', 's'
#define WASM_SECTION_DATA_SEGMENTS \
13, 'd', 'a', 't', 'a', '_', 's', 'e', 'g', 'm', 'e', 'n', 't', 's'
#define WASM_SECTION_FUNCTION_TABLE \
14, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', '_', 't', 'a', 'b', 'l', 'e'
#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'
#define WASM_SECTION_END 3, 'e', 'n', 'd'
#define WASM_SECTION_START_FUNCTION \
14, 's', 't', 'a', 'r', 't', '_', 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n'
#define WASM_SECTION_IMPORT_TABLE \
12, 'i', 'm', 'p', 'o', 'r', 't', '_', 't', 'a', 'b', 'l', 'e'
#define WASM_SECTION_EXPORT_TABLE \
12, 'e', 'x', 'p', 'o', 'r', 't', '_', 't', 'a', 'b', 'l', 'e'
#define WASM_SECTION_FUNCTION_SIGNATURES \
19, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', '_', 's', 'i', 'g', 'n', 'a', \
't', 'u', 'r', 'e', 's'
#define WASM_SECTION_FUNCTION_BODIES \
15, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', '_', 'b', 'o', 'd', 'i', 'e', 's'
#define WASM_SECTION_NAMES 5, 'n', 'a', 'm', 'e', 's'
#define WASM_SECTION_START_FUNCTION 5, 's', 't', 'a', 'r', 't'
#define WASM_SECTION_IMPORT_TABLE 6, 'i', 'm', 'p', 'o', 'r', 't'
#define WASM_SECTION_EXPORT_TABLE 6, 'e', 'x', 'p', 'o', 'r', 't'
#define WASM_SECTION_FUNCTION_SIGNATURES \
8, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n'
#define WASM_SECTION_FUNCTION_BODIES 4, 'c', 'o', 'd', 'e'
#define WASM_SECTION_NAMES 4, 'n', 'a', 'm', 'e'
// Constants for the above section headers' size (LEB128 + characters).
#define WASM_SECTION_MEMORY_SIZE ((size_t)7)
#define WASM_SECTION_SIGNATURES_SIZE ((size_t)11)
#define WASM_SECTION_FUNCTIONS_SIZE ((size_t)10)
#define WASM_SECTION_GLOBALS_SIZE ((size_t)8)
#define WASM_SECTION_DATA_SEGMENTS_SIZE ((size_t)14)
#define WASM_SECTION_FUNCTION_TABLE_SIZE ((size_t)15)
#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)
#define WASM_SECTION_END_SIZE ((size_t)4)
#define WASM_SECTION_START_FUNCTION_SIZE ((size_t)15)
#define WASM_SECTION_IMPORT_TABLE_SIZE ((size_t)13)
#define WASM_SECTION_EXPORT_TABLE_SIZE ((size_t)13)
#define WASM_SECTION_FUNCTION_SIGNATURES_SIZE ((size_t)20)
#define WASM_SECTION_FUNCTION_BODIES_SIZE ((size_t)16)
#define WASM_SECTION_NAMES_SIZE ((size_t)6)
#define WASM_SECTION_START_FUNCTION_SIZE ((size_t)6)
#define WASM_SECTION_IMPORT_TABLE_SIZE ((size_t)7)
#define WASM_SECTION_EXPORT_TABLE_SIZE ((size_t)7)
#define WASM_SECTION_FUNCTION_SIGNATURES_SIZE ((size_t)9)
#define WASM_SECTION_FUNCTION_BODIES_SIZE ((size_t)5)
#define WASM_SECTION_NAMES_SIZE ((size_t)5)
struct WasmSection {
enum class Code : uint32_t {
......@@ -111,6 +105,8 @@ enum WasmFunctionDeclBit {
static const size_t kDeclMemorySize = 3;
static const size_t kDeclDataSegmentSize = 13;
static const uint32_t kMaxReturnCount = 1;
// Static representation of a WASM function.
struct WasmFunction {
FunctionSig* sig; // signature of the function.
......
......@@ -18,8 +18,6 @@ using namespace v8::internal;
using namespace v8::internal::compiler;
using namespace v8::internal::wasm;
// TODO(titzer): fix arm64 frame alignment.
namespace {
void TestModule(WasmModuleIndex* module, int32_t expected_result) {
Isolate* isolate = CcTest::InitIsolateOnce();
......@@ -31,43 +29,6 @@ void TestModule(WasmModuleIndex* module, int32_t expected_result) {
}
} // namespace
// A raw test that skips the WasmModuleBuilder.
TEST(Run_WasmModule_CallAdd_rev) {
static const byte data[] = {
WASM_MODULE_HEADER,
// sig#0 ------------------------------------------
WASM_SECTION_SIGNATURES_SIZE + 7, // Section size.
WASM_SECTION_SIGNATURES, 2, // --
0, kLocalI32, // void -> int
2, kLocalI32, kLocalI32, kLocalI32, // int,int -> int
// func#0 (main) ----------------------------------
WASM_SECTION_FUNCTIONS_SIZE + 25, WASM_SECTION_FUNCTIONS, 2,
kDeclFunctionExport, 0, 0, // sig index
8, 0, // body size
0, // locals
kExprI8Const, 77, // --
kExprI8Const, 22, // --
kExprCallFunction, 2, 1, // --
// func#1 -----------------------------------------
0, // no name, not exported
1, 0, // sig index
6, 0, // body size
0, // locals
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
kExprI32Add, // --
};
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
WasmJs::InstallWasmFunctionMap(isolate, isolate->native_context());
int32_t result =
CompileAndRunWasmModule(isolate, data, data + arraysize(data));
CHECK_EQ(99, result);
}
TEST(Run_WasmModule_Return114) {
static const int32_t kReturnValue = 114;
v8::base::AccountingAllocator allocator;
......
......@@ -27,8 +27,10 @@ function makeSelect(type, args, which) {
var builder = new WasmModuleBuilder();
var sig = new Array();
sig.push(type);
sig.push(args);
for (var i = 0; i < args; i++) sig.push(type);
sig.push(1);
sig.push(type);
builder.addFunction("select", sig)
.addBody([kExprGetLocal, which])
.exportFunc();
......
......@@ -45,7 +45,7 @@ function assertFunction(module, func) {
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true);
builder.addFunction("sub", [kAstI64, kAstI64, kAstI64])
builder.addFunction("sub", kSig_l_ll)
.addBody([ // --
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
......@@ -67,7 +67,7 @@ function assertFunction(module, func) {
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true);
builder.addFunction("sub", [kAstI32, kAstI32, kAstI32])
builder.addFunction("sub", kSig_i_ii)
.addBody([
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
......@@ -92,7 +92,7 @@ function assertFunction(module, func) {
var kPages = 2;
builder.addMemory(kPages, kPages, true);
builder.addFunction("nop", [kAstStmt])
builder.addFunction("nop", kSig_v_v)
.addBody([kExprNop])
.exportFunc();
......@@ -109,7 +109,7 @@ function assertFunction(module, func) {
var kPages = 3;
builder.addMemory(kPages, kPages, true);
builder.addFunction("flt", [kAstI32, kAstF64, kAstF64])
builder.addFunction("flt", kSig_i_dd)
.addBody([
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
......
......@@ -33,7 +33,7 @@ function assertTraps(code, msg) {
function makeBinop(opcode) {
var builder = new WasmModuleBuilder();
builder.addFunction("main", [kAstI32, kAstI32, kAstI32])
builder.addFunction("main", kSig_i_ii)
.addBody([
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
......
......@@ -11,7 +11,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var kReturnValue = 88;
var builder = new WasmModuleBuilder();
builder.addFunction("main", [kAstI32])
builder.addFunction("main", kSig_i)
.addBody([
kExprI8Const,
kReturnValue,
......@@ -32,7 +32,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder();
builder.addFunction("main", [kAstI32])
builder.addFunction("main", kSig_i)
.addBody([
kExprI8Const,
kReturnValue,
......@@ -50,3 +50,25 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertEquals(kReturnValue, module.exports.foo());
assertEquals(kReturnValue, module.exports.blah());
})();
(function testNumericName() {
var kReturnValue = 93;
var builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i)
.addBody([
kExprI8Const,
kReturnValue,
kExprReturn, kArity1
])
.exportAs("0");
var module = builder.instantiate();
assertEquals("object", typeof module.exports);
assertEquals("function", typeof module.exports["0"]);
assertEquals(kReturnValue, module.exports["0"]());
})();
......@@ -10,7 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
function testCallFFI(ffi) {
var builder = new WasmModuleBuilder();
var sig_index = [kAstI32, kAstF64, kAstF64];
var sig_index = kSig_i_dd;
builder.addImport("fun", sig_index);
builder.addFunction("main", sig_index)
.addBody([
......
......@@ -10,7 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
function testCallFFI(func, check) {
var builder = new WasmModuleBuilder();
var sig_index = builder.addSignature([kAstI32, kAstF64, kAstF64]);
var sig_index = builder.addSignature(kSig_i_dd);
builder.addImport("func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
......@@ -185,8 +185,8 @@ function testCallBinopVoid(type, func, check) {
var builder = new WasmModuleBuilder();
builder.addImport("func", [kAstStmt, type, type]);
builder.addFunction("main", [kAstI32, type, type])
builder.addImport("func", makeSig_v_xx(type));
builder.addFunction("main", makeSig_r_xx(kAstI32, type))
.addBody([
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
......@@ -241,9 +241,9 @@ testCallBinopVoid(kAstF64);
function testCallPrint() {
var builder = new WasmModuleBuilder();
builder.addImport("print", [kAstStmt, kAstI32]);
builder.addImport("print", [kAstStmt, kAstF64]);
builder.addFunction("main", [kAstStmt, kAstF64])
builder.addImport("print", makeSig_v_x(kAstI32));
builder.addImport("print", makeSig_v_x(kAstF64));
builder.addFunction("main", makeSig_v_x(kAstF64))
.addBody([
kExprI8Const, 97, // --
kExprCallImport, kArity1, 0, // --
......
......@@ -10,7 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function TestFunctionPrototype() {
var builder = new WasmModuleBuilder();
builder.addFunction("nine", [kAstI32])
builder.addFunction("nine", kSig_i)
.addBody([kExprI8Const, 9])
.exportFunc();
......
......@@ -10,7 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
function makeFFI(func, t) {
var builder = new WasmModuleBuilder();
var sig_index = builder.addSignature([t,t,t,t,t,t,t,t,t,t,t]);
var sig_index = builder.addSignature([10,t,t,t,t,t,t,t,t,t,t,1,t]);
builder.addImport("func", sig_index);
// Try to create a frame with lots of spilled values and parameters
// on the stack to try to catch GC bugs in the reference maps for
......
......@@ -10,7 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
function testCallImport(func, check) {
var builder = new WasmModuleBuilder();
var sig_index = builder.addSignature([kAstI32, kAstF64, kAstF64]);
var sig_index = builder.addSignature(kSig_i_dd);
builder.addImport("func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
......@@ -186,8 +186,8 @@ function testCallBinopVoid(type, func, check) {
var builder = new WasmModuleBuilder();
builder.addImport("func", [kAstStmt, type, type]);
builder.addFunction("main", [kAstI32, type, type])
builder.addImport("func", makeSig_v_xx(type));
builder.addFunction("main", makeSig_r_xx(kAstI32, type))
.addBody([
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
......@@ -241,9 +241,9 @@ testCallBinopVoid(kAstF64);
function testCallPrint() {
var builder = new WasmModuleBuilder();
builder.addImport("print", [kAstStmt, kAstI32]);
builder.addImport("print", [kAstStmt, kAstF64]);
builder.addFunction("main", [kAstStmt, kAstF64])
builder.addImport("print", makeSig_v_x(kAstI32));
builder.addImport("print", makeSig_r_x(kAstF64, kAstF64));
builder.addFunction("main", makeSig_r_x(kAstF64, kAstF64))
.addBody([
kExprI8Const, 97, // --
kExprCallImport, kArity1, 0, // --
......@@ -266,9 +266,9 @@ testCallPrint();
function testCallImport2(foo, bar, expected) {
var builder = new WasmModuleBuilder();
builder.addImport("foo", [kAstI32]);
builder.addImport("bar", [kAstI32]);
builder.addFunction("main", [kAstI32])
builder.addImport("foo", kSig_i);
builder.addImport("bar", kSig_i);
builder.addFunction("main", kSig_i)
.addBody([
kExprCallImport, kArity0, 0, // --
kExprCallImport, kArity0, 1, // --
......
......@@ -10,7 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var module = (function () {
var builder = new WasmModuleBuilder();
var sig_index = builder.addSignature([kAstI32, kAstI32, kAstI32]);
var sig_index = builder.addSignature(kSig_i_ii);
builder.addImport("add", sig_index);
builder.addFunction("add", sig_index)
.addBody([
......@@ -22,7 +22,7 @@ var module = (function () {
kExprGetLocal, 1, // --
kExprI32Sub, // --
]);
builder.addFunction("main", [kAstI32, kAstI32, kAstI32, kAstI32])
builder.addFunction("main", kSig_i_iii)
.addBody([
kExprGetLocal, 0,
kExprGetLocal, 1,
......
......@@ -13,7 +13,7 @@ var module = (function Build() {
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true);
builder.addFunction("main", [kAstI32])
builder.addFunction("main", kSig_i)
.addBody([kExprI8Const, kReturnValue])
.exportFunc();
......
......@@ -11,7 +11,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var kReturnValue = 107;
var builder = new WasmModuleBuilder();
builder.addFunction("main", [kAstI32])
builder.addFunction("main", kSig_i_i)
.addBody([kExprI8Const, kReturnValue])
.exportFunc();
......
......@@ -13,7 +13,7 @@ function genModule(memory) {
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true);
builder.addFunction("main", [kAstI32, kAstI32])
builder.addFunction("main", kSig_i_i)
.addBody([
// main body: while(i) { if(mem[i]) return -1; i -= 4; } return 0;
kExprLoop,
......@@ -128,7 +128,7 @@ function testOOBThrows() {
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true);
builder.addFunction("geti", [kAstI32, kAstI32, kAstI32])
builder.addFunction("geti", kSig_i_ii)
.addBody([
kExprGetLocal, 0,
kExprGetLocal, 1,
......
......@@ -17,7 +17,7 @@ function testSelect2(type) {
var builder = new WasmModuleBuilder();
builder.addFunction("select", [type, type, type])
builder.addFunction("select", makeSig_r_xx(type, type))
.addBody([kExprGetLocal, which])
.exportFunc()
......@@ -79,7 +79,7 @@ function testSelect10(t) {
print("type = " + t + ", which = " + which);
var builder = new WasmModuleBuilder();
builder.addFunction("select", [t,t,t,t,t,t,t,t,t,t,t])
builder.addFunction("select", [10,t,t,t,t,t,t,t,t,t,t,1,t])
.addBody([kExprGetLocal, which])
.exportFunc();
......
......@@ -36,24 +36,24 @@ function STACK() {
var builder = new WasmModuleBuilder();
builder.addImport("func", [kAstStmt]);
builder.addImport("func", kSig_v_v);
builder.addFunction("main", [kAstStmt])
builder.addFunction("main", kSig_v_v)
.addBody([kExprCallImport, kArity0, 0])
.exportAs("main");
builder.addFunction("exec_unreachable", [kAstStmt])
builder.addFunction("exec_unreachable", kSig_v_v)
.addBody([kExprUnreachable])
.exportAs("exec_unreachable");
// make this function unnamed, just to test also this case
var mem_oob_func = builder.addFunction(undefined, [kAstStmt])
var mem_oob_func = builder.addFunction(undefined, kSig_v_v)
// access the memory at offset -1
.addBody([kExprI32Const, 0x7f, kExprI32LoadMem8S, 0, 0])
.exportAs("mem_out_of_bounds");
// call the mem_out_of_bounds function, in order to have two WASM stack frames
builder.addFunction("call_mem_out_of_bounds", [kAstStmt])
builder.addFunction("call_mem_out_of_bounds", kSig_v_v)
.addBody([kExprCallFunction, kArity0, mem_oob_func.index])
.exportAs("call_mem_out_of_bounds");
......
......@@ -10,7 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
function makeFFI(func) {
var builder = new WasmModuleBuilder();
var sig_index = builder.addSignature([kAstI32, kAstF64, kAstF64]);
var sig_index = builder.addSignature(kSig_i_dd);
builder.addImport("func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
......
......@@ -37,19 +37,19 @@ function assertVerifies(sig, body) {
return module;
}
assertVerifies([kAstStmt], [kExprNop]);
assertVerifies([kAstI32], [kExprI8Const, 0]);
assertVerifies(kSig_v_v, [kExprNop]);
assertVerifies(kSig_i, [kExprI8Const, 0]);
// Arguments aren't allow to start functions.
assertFails([kAstI32, kAstI32], [kExprGetLocal, 0]);
assertFails([kAstI32, kAstI32, kAstF32], [kExprGetLocal, 0]);
assertFails([kAstI32, kAstI32, kAstF32, kAstF64], [kExprGetLocal, 0]);
assertFails(kSig_i_i, [kExprGetLocal, 0]);
assertFails(kSig_i_ii, [kExprGetLocal, 0]);
assertFails(kSig_i_dd, [kExprGetLocal, 0]);
(function testInvalidIndex() {
print("testInvalidIndex");
var builder = new WasmModuleBuilder();
var func = builder.addFunction("", [kAstStmt])
var func = builder.addFunction("", kSig_v_v)
.addBody([kExprNop]);
builder.addStart(func.index + 1);
......@@ -62,7 +62,7 @@ assertFails([kAstI32, kAstI32, kAstF32, kAstF64], [kExprGetLocal, 0]);
print("testTwoStartFuncs");
var builder = new WasmModuleBuilder();
var func = builder.addFunction("", [kAstStmt])
var func = builder.addFunction("", kSig_v_v)
.addBody([kExprNop]);
builder.addExplicitSection([kDeclStartFunction, 0]);
......@@ -78,7 +78,7 @@ assertFails([kAstI32, kAstI32, kAstF32, kAstF64], [kExprGetLocal, 0]);
builder.addMemory(12, 12, true);
var func = builder.addFunction("", [kAstStmt])
var func = builder.addFunction("", kSig_v_v)
.addBody([kExprI8Const, 0, kExprI8Const, 77, kExprI32StoreMem, 0, 0]);
builder.addStart(func.index);
......@@ -98,7 +98,7 @@ assertFails([kAstI32, kAstI32, kAstF32, kAstF64], [kExprGetLocal, 0]);
}};
var builder = new WasmModuleBuilder();
var sig_index = builder.addSignature([kAstStmt]);
var sig_index = builder.addSignature(kSig_v_v);
builder.addImport("foo", sig_index);
var func = builder.addFunction("", sig_index)
......
......@@ -12,7 +12,7 @@ var debug = false;
(function BasicTest() {
var module = new WasmModuleBuilder();
module.addMemory(1, 2, false);
module.addFunction("foo", [kAstI32])
module.addFunction("foo", kSig_i)
.addBody([kExprI8Const, 11])
.exportAs("blarg");
......@@ -23,8 +23,8 @@ var debug = false;
(function ImportTest() {
var module = new WasmModuleBuilder();
var index = module.addImport("print", [kAstStmt, kAstI32]);
module.addFunction("foo", [kAstStmt])
var index = module.addImport("print", makeSig_v_x(kAstI32));
module.addFunction("foo", kSig_v_v)
.addBody([kExprI8Const, 13, kExprCallImport, kArity1, index])
.exportAs("main");
......@@ -36,7 +36,7 @@ var debug = false;
(function LocalsTest() {
var module = new WasmModuleBuilder();
module.addFunction(undefined, [kAstI32, kAstI32])
module.addFunction(undefined, kSig_i_i)
.addLocals({i32_count: 1})
.addBody([kExprGetLocal, 0, kExprSetLocal, 1])
.exportAs("main");
......@@ -58,7 +58,7 @@ var debug = false;
for (p of types) {
var module = new WasmModuleBuilder();
module.addFunction(undefined, [p.type, p.type])
module.addFunction(undefined, makeSig_r_x(p.type, p.type))
.addLocals(p.locals)
.addBody([kExprGetLocal, 0, kExprSetLocal, 1])
.exportAs("main");
......@@ -72,9 +72,9 @@ var debug = false;
(function CallTest() {
var module = new WasmModuleBuilder();
module.addFunction("add", [kAstI32, kAstI32, kAstI32])
module.addFunction("add", kSig_i_ii)
.addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprI32Add]);
module.addFunction("main", [kAstI32, kAstI32, kAstI32])
module.addFunction("main", kSig_i_ii)
.addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprCallFunction, kArity2, 0])
.exportAs("main");
......@@ -85,9 +85,9 @@ var debug = false;
(function IndirectCallTest() {
var module = new WasmModuleBuilder();
module.addFunction("add", [kAstI32, kAstI32, kAstI32])
module.addFunction("add", kSig_i_ii)
.addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprI32Add]);
module.addFunction("main", [kAstI32, kAstI32, kAstI32, kAstI32])
module.addFunction("main", kSig_i_iii)
.addBody([kExprGetLocal,
0, kExprGetLocal, 1, kExprGetLocal, 2, kExprCallIndirect, kArity2, 0])
.exportAs("main");
......@@ -102,7 +102,7 @@ var debug = false;
(function DataSegmentTest() {
var module = new WasmModuleBuilder();
module.addMemory(1, 1, false);
module.addFunction("load", [kAstI32, kAstI32])
module.addFunction("load", kSig_i_i)
.addBody([kExprGetLocal, 0, kExprI32LoadMem, 0, 0])
.exportAs("load");
module.addDataSegment(0, [9, 9, 9, 9], true);
......@@ -116,7 +116,7 @@ var debug = false;
(function BasicTestWithUint8Array() {
var module = new WasmModuleBuilder();
module.addMemory(1, 2, false);
module.addFunction("foo", [kAstI32])
module.addFunction("foo", kSig_i)
.addBody([kExprI8Const, 17])
.exportAs("blarg");
......@@ -141,8 +141,8 @@ var debug = false;
(function ImportTestTwoLevel() {
var module = new WasmModuleBuilder();
var index = module.addImportWithModule("mod", "print", [kAstStmt, kAstI32]);
module.addFunction("foo", [kAstStmt])
var index = module.addImportWithModule("mod", "print", makeSig_v_x(kAstI32));
module.addFunction("foo", kSig_v_v)
.addBody([kExprI8Const, 19, kExprCallImport, kArity1, index])
.exportAs("main");
......
......@@ -9,7 +9,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var main = (function () {
var builder = new WasmModuleBuilder();
builder.addFunction("main", [kAstStmt])
builder.addFunction("main", kSig_v_v)
.addBody([kExprUnreachable])
.exportAs("main");
......
......@@ -8,9 +8,9 @@ load("test/mjsunit/wasm/wasm-constants.js");
try {
var data = bytes(
0, kAstStmt, // signature
kDeclNoLocals, // --
kExprNop // body
kWasmFunctionTypeForm, 0, kAstStmt, // signature
kDeclNoLocals, // --
kExprNop // body
);
Wasm.verifyFunction(data);
......@@ -23,8 +23,8 @@ try {
var threw = false;
try {
var data = bytes(
0, kAstI32, // signature
kDeclNoLocals, // --
kWasmFunctionTypeForm, 0, 1, kAstI32, // signature
kDeclNoLocals, // --
kExprBlock, kExprNop, kExprNop, kExprEnd // body
);
......
......@@ -21,7 +21,7 @@ var kWasmH1 = 0x61;
var kWasmH2 = 0x73;
var kWasmH3 = 0x6d;
var kWasmV0 = 10;
var kWasmV0 = 11;
var kWasmV1 = 0;
var kWasmV2 = 0;
var kWasmV3 = 0;
......@@ -69,11 +69,12 @@ var kArity0 = 0;
var kArity1 = 1;
var kArity2 = 2;
var kArity3 = 3;
var kWasmFunctionTypeForm = 0x40;
var section_names = [
"memory", "signatures", "functions", "globals", "data_segments",
"function_table", "end", "start_function", "import_table", "export_table",
"function_signatures", "function_bodies", "names"];
"memory", "type", "old_function", "global", "data",
"table", "end", "start", "import", "export",
"function", "code", "name"];
// Function declaration flags
var kDeclFunctionName = 0x01;
......@@ -88,6 +89,33 @@ var kAstI64 = 2;
var kAstF32 = 3;
var kAstF64 = 4;
// Useful signatures
var kSig_i = [0, 1, kAstI32];
var kSig_d = [0, 1, kAstF64];
var kSig_i_i = [1, kAstI32, 1, kAstI32];
var kSig_i_ii = [2, kAstI32, kAstI32, 1, kAstI32];
var kSig_i_iii = [3, kAstI32, kAstI32, kAstI32, 1, kAstI32];
var kSig_d_dd = [2, kAstF64, kAstF64, 1, kAstF64];
var kSig_l_ll = [2, kAstI64, kAstI64, 1, kAstI64];
var kSig_i_dd = [2, kAstF64, kAstF64, 1, kAstI32];
var kSig_v_v = [0, 0];
function makeSig_v_xx(x) {
return [2, x, x, 0];
}
function makeSig_v_x(x) {
return [1, x, 0];
}
function makeSig_r_xx(r, x) {
return [2, x, x, 1, r];
}
function makeSig_r_x(r, x) {
return [1, x, 1, r];
}
// Opcodes
var kExprNop = 0x00;
var kExprBlock = 0x01;
......
......@@ -53,7 +53,7 @@ WasmModuleBuilder.prototype.addExplicitSection = function(bytes) {
return this;
}
// Add a signature; format is [rettype, param0, param1, ...]
// Add a signature; format is [param_count, param0, param1, ..., retcount, ret0]
WasmModuleBuilder.prototype.addSignature = function(sig) {
// TODO: canonicalize signatures?
this.signatures.push(sig);
......@@ -132,12 +132,14 @@ function emit_bytes(bytes, data) {
}
function emit_section(bytes, section_code, content_generator) {
// Start the section in a temporary buffer: its full length isn't know yet.
// Emit section name.
emit_string(bytes, section_names[section_code]);
// Emit the section to a temporary buffer: its full length isn't know yet.
var tmp_bytes = [];
emit_string(tmp_bytes, section_names[section_code]);
content_generator(tmp_bytes);
// Now that we know the section length, emit it and copy the section.
// Emit section length.
emit_varint(bytes, tmp_bytes.length);
// Copy the temporary buffer.
Array.prototype.push.apply(bytes, tmp_bytes);
}
......@@ -155,8 +157,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
emit_section(bytes, kDeclSignatures, function(bytes) {
emit_varint(bytes, wasm.signatures.length);
for (sig of wasm.signatures) {
var params = sig.length - 1;
emit_varint(bytes, params);
emit_u8(bytes, kWasmFunctionTypeForm);
for (var j = 0; j < sig.length; j++) {
emit_u8(bytes, sig[j]);
}
......
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