Commit 5c5c6e38 authored by titzer's avatar titzer Committed by Commit bot

[wasm] Add support for a start function.

Add a section identifier for declaring a start function as an index into
the function table. (This could also be done as a decl flag on the
function, but don't feel strongly here, since we probably want to redo
this when adding an import/export section.)

The start function must accept no parameters. Its return value is
currently ignored.

R=binji@chromium.org,bradnelson@chromium.org
BUG=chromium:575167
LOG=Y

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

Cr-Commit-Position: refs/heads/master@{#33978}
parent e768bcca
......@@ -180,6 +180,29 @@ class ModuleDecoder : public Decoder {
}
break;
}
case kDeclStartFunction: {
// Declares a start function for a module.
CheckForPreviousSection(sections, kDeclFunctions, true);
if (module->start_function_index >= 0) {
error("start function already declared");
break;
}
int length;
const byte* before = pc_;
uint32_t index = consume_u32v(&length, "start function index");
if (index >= module->functions->size()) {
error(before, "invalid start function index");
break;
}
module->start_function_index = static_cast<int>(index);
FunctionSig* sig =
module->signatures->at(module->functions->at(index).sig_index);
if (sig->parameter_count() > 0) {
error(before, "invalid start function: non-zero parameter count");
break;
}
break;
}
case kDeclWLL: {
// Reserved for experimentation by the Web Low-level Language project
// which is augmenting the binary encoding with source code meta
......
......@@ -256,15 +256,21 @@ bool AllocateGlobals(ErrorThrower* thrower, Isolate* isolate,
}
} // namespace
WasmModule::WasmModule()
: globals(nullptr),
: shared_isolate(nullptr),
module_start(nullptr),
module_end(nullptr),
min_mem_size_log2(0),
max_mem_size_log2(0),
mem_export(false),
mem_external(false),
start_function_index(-1),
globals(nullptr),
signatures(nullptr),
functions(nullptr),
data_segments(nullptr),
function_table(nullptr) {}
WasmModule::~WasmModule() {
if (globals) delete globals;
if (signatures) delete signatures;
......@@ -403,6 +409,25 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
linker.Link(instance.function_table, this->function_table);
instance.js_object->SetInternalField(kWasmModuleFunctionTable,
Smi::FromInt(0));
// Run the start function if one was specified.
if (this->start_function_index >= 0) {
HandleScope scope(isolate);
uint32_t index = static_cast<uint32_t>(this->start_function_index);
Handle<String> name = isolate->factory()->NewStringFromStaticChars("start");
Handle<Code> code = linker.GetFunctionCode(index);
Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
isolate, &module_env, name, code, instance.js_object, index);
// Call the JS function.
Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
MaybeHandle<Object> retval =
Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
if (retval.is_null()) {
thrower.Error("WASM.instantiateModule(): start function failed");
}
}
return instance.js_object;
}
......
......@@ -32,6 +32,7 @@ enum WasmSectionDeclCode {
kDeclFunctionTable = 0x05,
kDeclWLL = 0x11,
kDeclEnd = 0x06,
kDeclStartFunction = 0x07,
};
static const int kMaxModuleSectionCode = 6;
......@@ -93,6 +94,7 @@ struct WasmModule {
uint8_t max_mem_size_log2; // maximum size of the memory (log base 2).
bool mem_export; // true if the memory is exported.
bool mem_external; // true if the memory is external.
int start_function_index; // start function, if any.
std::vector<WasmGlobal>* globals; // globals in this module.
std::vector<FunctionSig*>* signatures; // signatures in this module.
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-wasm
load("test/mjsunit/wasm/wasm-constants.js");
function instantiate(sig, body) {
var module = new Array();
module = module.concat([
// -- signatures
kDeclSignatures, 1,
]);
module = module.concat(sig);
module = module.concat([
// -- functions
kDeclFunctions, 1,
0, // decl flags
0, 0, // signature
body.length, 0, // body size
]);
module = module.concat(body);
module = module.concat([
// -- declare start function
kDeclStartFunction,
0
]);
var data = bytes.apply(this, module);
print(module);
print(data instanceof ArrayBuffer);
print(data.byteLength);
return _WASMEXP_.instantiateModule(data);
}
function assertFails(sig, body) {
try {
var module = instantiate(sig, body);
print("expected failure, but passes");
assertFalse(true);
} catch (expected) {
print("ok: " + expected);
}
}
function assertVerifies(sig, body) {
var module = instantiate(sig, body);
assertFalse(module === undefined);
assertFalse(module === null);
assertFalse(module === 0);
assertEquals("object", typeof module);
return module;
}
assertVerifies([0, kAstStmt], [kExprNop]);
assertVerifies([0, kAstI32], [kExprI8Const, 0]);
// Arguments aren't allow to start functions.
assertFails([1, kAstI32, kAstI32], [kExprGetLocal, 0]);
assertFails([2, kAstI32, kAstI32, kAstF32], [kExprGetLocal, 0]);
assertFails([3, kAstI32, kAstI32, kAstF32, kAstF64], [kExprGetLocal, 0]);
(function testInvalidIndex() {
var kBodySize = 1;
var data = bytes(
// -- signatures
kDeclSignatures, 1,
0, kAstStmt,
// -- functions
kDeclFunctions, 1,
0, // decl flags
0, 0, // signature
kBodySize, 0, // body size
kExprNop, // body
// -- declare start function
kDeclStartFunction,
1
);
assertThrows(function() { _WASMEXP_.instantiateModule(data); });
})();
(function testTwoStartFuncs() {
var kBodySize = 1;
var data = bytes(
// -- signatures
kDeclSignatures, 1,
0, kAstStmt,
// -- functions
kDeclFunctions, 1,
0, // decl flags
0, 0, // signature
kBodySize, 0, // body size
kExprNop, // body
// -- declare start function
kDeclStartFunction,
0,
// -- declare start function
kDeclStartFunction,
0
);
assertThrows(function() { _WASMEXP_.instantiateModule(data); });
})();
(function testRun() {
var kBodySize = 6;
var data = bytes(
kDeclMemory,
12, 12, 1, // memory
// -- signatures
kDeclSignatures, 1,
0, kAstStmt,
// -- start function
kDeclFunctions, 1,
0, // decl flags
0, 0, // signature
kBodySize, 0, // code size
// -- start body
kExprI32StoreMem, 0, kExprI8Const, 0, kExprI8Const, 77,
// -- declare start function
kDeclStartFunction,
0
);
var module = _WASMEXP_.instantiateModule(data);
var memory = module.memory;
var view = new Int8Array(memory);
assertEquals(77, view[0]);
})();
(function testStartFFI() {
var kBodySize = 2;
var kNameOffset = 4 + 9 + 7 + 3;
var data = bytes(
// -- signatures
kDeclSignatures, 1,
0, kAstStmt,
// -- imported function
kDeclFunctions, 2,
kDeclFunctionImport | kDeclFunctionName, // decl flags
0, 0, // signature
kNameOffset, 0, 0, 0,
// -- start function
0, // decl flags
0, 0, // signature
kBodySize, 0, // code size
// -- start body
kExprCallFunction, 0,
// -- declare start function
kDeclStartFunction,
1,
kDeclEnd,
'f', 'o', 'o', 0
);
var ranned = false;
var ffi = new Object();
ffi.foo = function() {
print("we ranned at stert!");
ranned = true;
}
var module = _WASMEXP_.instantiateModule(data, ffi);
var memory = module.memory;
var view = new Int8Array(memory);
assertTrue(ranned);
})();
......@@ -22,6 +22,7 @@ var kDeclFunctions = 0x02;
var kDeclGlobals = 0x03;
var kDeclDataSegments = 0x04;
var kDeclFunctionTable = 0x05;
var kDeclStartFunction = 0x07;
var kDeclEnd = 0x06;
// Function declaration flags
......
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