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

[wasm] Add an export table.

R=binji@chromium.org,jfb@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#34342}
parent c1507e15
......@@ -55,6 +55,7 @@ class ModuleDecoder : public Decoder {
module->data_segments = new std::vector<WasmDataSegment>();
module->function_table = new std::vector<uint16_t>();
module->import_table = new std::vector<WasmImport>();
module->export_table = new std::vector<WasmExport>();
bool sections[kMaxModuleSectionCode];
memset(sections, 0, sizeof(sections));
......@@ -234,6 +235,34 @@ class ModuleDecoder : public Decoder {
}
break;
}
case kDeclExportTable: {
// Declares an export table.
CheckForPreviousSection(sections, kDeclFunctions, true);
int length;
uint32_t export_table_count =
consume_u32v(&length, "export table count");
module->export_table->reserve(SafeReserve(export_table_count));
// Decode export table.
for (uint32_t i = 0; i < export_table_count; i++) {
if (failed()) break;
TRACE("DecodeExportTable[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
module->export_table->push_back({0, 0});
WasmExport* exp = &module->export_table->back();
const byte* sigpos = pc_;
exp->func_index = consume_u16("function index");
if (exp->func_index >= module->functions->size()) {
error(sigpos, sigpos,
"function index %u out of bounds (%d functions)",
exp->func_index,
static_cast<int>(module->functions->size()));
}
exp->name_offset = consume_string("export name");
}
break;
}
case kDeclWLL: {
// Reserved for experimentation by the Web Low-level Language project
// which is augmenting the binary encoding with source code meta
......
......@@ -283,7 +283,8 @@ WasmModule::WasmModule()
functions(nullptr),
data_segments(nullptr),
function_table(nullptr),
import_table(nullptr) {}
import_table(nullptr),
export_table(nullptr) {}
WasmModule::~WasmModule() {
if (globals) delete globals;
......@@ -292,6 +293,7 @@ WasmModule::~WasmModule() {
if (data_segments) delete data_segments;
if (function_table) delete function_table;
if (import_table) delete import_table;
if (export_table) delete export_table;
}
static MaybeHandle<JSFunction> LookupFunction(ErrorThrower& thrower,
......@@ -455,6 +457,32 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
instance.js_object->SetInternalField(kWasmModuleFunctionTable,
Smi::FromInt(0));
//-------------------------------------------------------------------------
// Create and populate the exports object.
//-------------------------------------------------------------------------
if (export_table->size() > 0) {
index = 0;
// 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);
// Compile wrappers and add them to the exports object.
for (const WasmExport& exp : *export_table) {
if (thrower.error()) break;
const char* cstr = GetName(exp.name_offset);
Handle<String> name = factory->InternalizeUtf8String(cstr);
Handle<Code> code = linker.GetFunctionCode(exp.func_index);
Handle<JSFunction> function = compiler::CompileJSToWasmWrapper(
isolate, &module_env, name, code, instance.js_object, exp.func_index);
JSObject::AddProperty(exports_object, name, function, READ_ONLY);
}
}
// Run the start function if one was specified.
if (this->start_function_index >= 0) {
HandleScope scope(isolate);
......
......@@ -33,6 +33,7 @@ enum WasmSectionDeclCode {
kDeclEnd = 0x06,
kDeclStartFunction = 0x07,
kDeclImportTable = 0x08,
kDeclExportTable = 0x09,
kDeclWLL = 0x11,
};
......@@ -74,6 +75,12 @@ struct WasmImport {
uint32_t function_name_offset; // offset in module bytes of the import name.
};
// Static representation of an exported WASM function.
struct WasmExport {
uint16_t func_index; // index into the function table.
uint32_t name_offset; // offset in module bytes of the name to export.
};
// Static representation of a wasm global variable.
struct WasmGlobal {
uint32_t name_offset; // offset in the module bytes of the name, if any.
......@@ -110,6 +117,7 @@ struct WasmModule {
std::vector<WasmDataSegment>* data_segments; // data segments in this module.
std::vector<uint16_t>* function_table; // function table.
std::vector<WasmImport>* import_table; // import table.
std::vector<WasmExport>* export_table; // export table.
WasmModule();
~WasmModule();
......
// 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 testExportedMain() {
var kBodySize = 3;
var kReturnValue = 99;
var kNameMainOffset = 4 + 7 + kBodySize + 8 + 1;
var data = bytes(
// signatures
kDeclSignatures, 1,
0, kAstI32, // void -> i32
// -- main function
kDeclFunctions,
1,
0, // decl flags
0, 0, // signature index
kBodySize, 0,
// main body
kExprReturn,
kExprI8Const,
kReturnValue,
// exports
kDeclExportTable,
1,
0, 0, // func index index
kNameMainOffset, 0, 0, 0, // function name offset
// names
kDeclEnd,
'm', 'a', 'i', 'n', 0 // --
);
var ffi = new Object();
var module = _WASMEXP_.instantiateModule(data, ffi);
assertEquals("object", typeof module.exports);
assertEquals("function", typeof module.exports.main);
assertEquals(kReturnValue, module.exports.main());
})();
(function testExportedTwice() {
var kBodySize = 3;
var kReturnValue = 99;
var kNameMainOffset = 4 + 7 + kBodySize + 14 + 1;
var kNameFooOffset = kNameMainOffset + 5;
var data = bytes(
// signatures
kDeclSignatures, 1,
0, kAstI32, // void -> i32
// -- main function
kDeclFunctions,
1,
0, // decl flags
0, 0, // signature index
kBodySize, 0,
// main body
kExprReturn,
kExprI8Const,
kReturnValue,
// exports
kDeclExportTable,
2,
0, 0, // func index index
kNameMainOffset, 0, 0, 0, // function name offset
0, 0, // func index index
kNameFooOffset, 0, 0, 0, // function name offset
// names
kDeclEnd,
'b', 'l', 'a', 'h', 0, // --
'f', 'o', 'o', 0 // --
);
var ffi = new Object();
var module = _WASMEXP_.instantiateModule(data, ffi);
assertEquals("object", typeof module.exports);
assertEquals("function", typeof module.exports.blah);
assertEquals("function", typeof module.exports.foo);
assertEquals(kReturnValue, module.exports.blah());
assertEquals(kReturnValue, module.exports.foo());
})();
......@@ -24,6 +24,7 @@ var kDeclDataSegments = 0x04;
var kDeclFunctionTable = 0x05;
var kDeclStartFunction = 0x07;
var kDeclImportTable = 0x08;
var kDeclExportTable = 0x09;
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