Commit d0b8e7fb authored by ritesht's avatar ritesht Committed by Commit bot

[wasm] Support undefined indirect table entries, behind a flag.

Add a flag to gate experimental support for dynamic code loading and JITing (at runtime in a wasm module).

Enhancing functionality of the indirect function table to support JITing and dynamic linking by allowing additional space to be filled with an "undefined" function signature.

BUG=v8:5044
LOG=N
TEST=None
R=mtrofin@chromium.org,bradnelson@chromium.org

Review-Url: https://codereview.chromium.org/2049513003
Cr-Commit-Position: refs/heads/master@{#37159}
parent 365e32b1
...@@ -514,6 +514,9 @@ DEFINE_BOOL(print_wasm_code_size, false, ...@@ -514,6 +514,9 @@ DEFINE_BOOL(print_wasm_code_size, false,
DEFINE_INT(typed_array_max_size_in_heap, 64, DEFINE_INT(typed_array_max_size_in_heap, 64,
"threshold for in-heap typed array") "threshold for in-heap typed array")
DEFINE_BOOL(wasm_jit_prototype, false,
"enable experimental wasm runtime dynamic code generation")
// Profiler flags. // Profiler flags.
DEFINE_INT(frame_count, 1, "number of stack frames inspected by the profiler") DEFINE_INT(frame_count, 1, "number of stack frames inspected by the profiler")
// 0x1800 fits in the immediate field of an ARM instruction. // 0x1800 fits in the immediate field of an ARM instruction.
......
...@@ -270,6 +270,20 @@ class ModuleDecoder : public Decoder { ...@@ -270,6 +270,20 @@ class ModuleDecoder : public Decoder {
} }
break; break;
} }
case WasmSection::Code::FunctionTablePad: {
if (!FLAG_wasm_jit_prototype) {
error("FunctionTablePad section without jiting enabled");
}
// An indirect function table requires functions first.
int length;
module->indirect_table_size =
consume_u32v(&length, "indirect entry count");
if (module->indirect_table_size > 0 &&
module->indirect_table_size < module->function_table.size()) {
error("more predefined indirect entries than table can hold");
}
break;
}
case WasmSection::Code::FunctionTable: { case WasmSection::Code::FunctionTable: {
// An indirect function table requires functions first. // An indirect function table requires functions first.
CheckForFunctions(module, section); CheckForFunctions(module, section);
...@@ -289,6 +303,10 @@ class ModuleDecoder : public Decoder { ...@@ -289,6 +303,10 @@ class ModuleDecoder : public Decoder {
} }
module->function_table.push_back(index); module->function_table.push_back(index);
} }
if (module->indirect_table_size > 0 &&
module->indirect_table_size < module->function_table.size()) {
error("more predefined indirect entries than table can hold");
}
break; break;
} }
case WasmSection::Code::StartFunction: { case WasmSection::Code::StartFunction: {
...@@ -391,7 +409,7 @@ class ModuleDecoder : public Decoder { ...@@ -391,7 +409,7 @@ class ModuleDecoder : public Decoder {
case WasmSection::Code::Max: case WasmSection::Code::Max:
// Skip unknown sections. // Skip unknown sections.
TRACE("Unknown section: '"); TRACE("Unknown section: '");
for (uint32_t i = 0; i != string_length; ++i) { for (uint32_t i = 0; i != string_length; i++) {
TRACE("%c", *(section_name_start + i)); TRACE("%c", *(section_name_start + i));
} }
TRACE("'\n"); TRACE("'\n");
......
...@@ -144,12 +144,16 @@ void LoadDataSegments(const WasmModule* module, byte* mem_addr, ...@@ -144,12 +144,16 @@ void LoadDataSegments(const WasmModule* module, byte* mem_addr,
Handle<FixedArray> BuildFunctionTable(Isolate* isolate, Handle<FixedArray> BuildFunctionTable(Isolate* isolate,
const WasmModule* module) { const WasmModule* module) {
if (module->function_table.size() == 0) { // Compute the size of the indirect function table
uint32_t table_size = module->FunctionTableSize();
if (table_size == 0) {
return Handle<FixedArray>::null(); return Handle<FixedArray>::null();
} }
int table_size = static_cast<int>(module->function_table.size());
Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size); Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size);
for (int i = 0; i < table_size; i++) { for (uint32_t i = 0;
i < static_cast<uint32_t>(module->function_table.size());
++i) {
const WasmFunction* function = const WasmFunction* function =
&module->functions[module->function_table[i]]; &module->functions[module->function_table[i]];
fixed->set(i, Smi::FromInt(function->sig_index)); fixed->set(i, Smi::FromInt(function->sig_index));
...@@ -342,7 +346,9 @@ WasmModule::WasmModule() ...@@ -342,7 +346,9 @@ WasmModule::WasmModule()
mem_export(false), mem_export(false),
mem_external(false), mem_external(false),
start_function_index(-1), start_function_index(-1),
origin(kWasmOrigin) {} origin(kWasmOrigin),
globals_size(0),
indirect_table_size(0) {}
static MaybeHandle<JSFunction> ReportFFIError(ErrorThrower& thrower, static MaybeHandle<JSFunction> ReportFFIError(ErrorThrower& thrower,
const char* error, uint32_t index, const char* error, uint32_t index,
...@@ -667,12 +673,14 @@ void CompileSequentially(Isolate* isolate, const WasmModule* module, ...@@ -667,12 +673,14 @@ void CompileSequentially(Isolate* isolate, const WasmModule* module,
void PopulateFunctionTable(WasmModuleInstance* instance) { void PopulateFunctionTable(WasmModuleInstance* instance) {
if (!instance->function_table.is_null()) { if (!instance->function_table.is_null()) {
int table_size = static_cast<int>(instance->module->function_table.size()); uint32_t table_size = instance->module->FunctionTableSize();
DCHECK_EQ(instance->function_table->length(), table_size * 2); DCHECK_EQ(table_size * 2, instance->function_table->length());
for (int i = 0; i < table_size; i++) { uint32_t populated_table_size =
instance->function_table->set( static_cast<uint32_t>(instance->module->function_table.size());
i + table_size, for (uint32_t i = 0; i < populated_table_size; ++i) {
*instance->function_code[instance->module->function_table[i]]); instance->function_table->set(
i + table_size,
*instance->function_code[instance->module->function_table[i]]);
} }
} }
} }
......
...@@ -41,6 +41,7 @@ const uint8_t kWasmFunctionTypeForm = 0x40; ...@@ -41,6 +41,7 @@ const uint8_t kWasmFunctionTypeForm = 0x40;
F(FunctionBodies, 8, "code") \ F(FunctionBodies, 8, "code") \
F(DataSegments, 9, "data") \ F(DataSegments, 9, "data") \
F(Names, 10, "name") \ F(Names, 10, "name") \
F(FunctionTablePad, 11, "table_pad") \
F(Globals, 0, "global") \ F(Globals, 0, "global") \
F(End, 0, "end") F(End, 0, "end")
...@@ -58,6 +59,8 @@ const uint8_t kWasmFunctionTypeForm = 0x40; ...@@ -58,6 +59,8 @@ const uint8_t kWasmFunctionTypeForm = 0x40;
8, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n' 8, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n'
#define WASM_SECTION_FUNCTION_BODIES 4, 'c', 'o', 'd', 'e' #define WASM_SECTION_FUNCTION_BODIES 4, 'c', 'o', 'd', 'e'
#define WASM_SECTION_NAMES 4, 'n', 'a', 'm', 'e' #define WASM_SECTION_NAMES 4, 'n', 'a', 'm', 'e'
#define WASM_SECTION_FUNCTION_TABLE_PAD \
9, 't', 'a', 'b', 'l', 'e', '_', 'p', 'a', 'd'
// Constants for the above section headers' size (LEB128 + characters). // Constants for the above section headers' size (LEB128 + characters).
#define WASM_SECTION_MEMORY_SIZE ((size_t)7) #define WASM_SECTION_MEMORY_SIZE ((size_t)7)
...@@ -72,6 +75,7 @@ const uint8_t kWasmFunctionTypeForm = 0x40; ...@@ -72,6 +75,7 @@ const uint8_t kWasmFunctionTypeForm = 0x40;
#define WASM_SECTION_FUNCTION_SIGNATURES_SIZE ((size_t)9) #define WASM_SECTION_FUNCTION_SIGNATURES_SIZE ((size_t)9)
#define WASM_SECTION_FUNCTION_BODIES_SIZE ((size_t)5) #define WASM_SECTION_FUNCTION_BODIES_SIZE ((size_t)5)
#define WASM_SECTION_NAMES_SIZE ((size_t)5) #define WASM_SECTION_NAMES_SIZE ((size_t)5)
#define WASM_SECTION_FUNCTION_TABLE_PAD_SIZE ((size_t)10)
class WasmDebugInfo; class WasmDebugInfo;
...@@ -166,6 +170,8 @@ struct WasmModule { ...@@ -166,6 +170,8 @@ struct WasmModule {
std::vector<WasmGlobal> globals; // globals in this module. std::vector<WasmGlobal> globals; // globals in this module.
uint32_t globals_size; // size of globals table. uint32_t globals_size; // size of globals table.
uint32_t indirect_table_size; // size of indirect function
// table (includes padding).
std::vector<FunctionSig*> signatures; // signatures in this module. std::vector<FunctionSig*> signatures; // signatures in this module.
std::vector<WasmFunction> functions; // functions in this module. std::vector<WasmFunction> functions; // functions in this module.
std::vector<WasmDataSegment> data_segments; // data segments in this module. std::vector<WasmDataSegment> data_segments; // data segments in this module.
...@@ -214,6 +220,14 @@ struct WasmModule { ...@@ -214,6 +220,14 @@ struct WasmModule {
Handle<JSArrayBuffer> memory) const; Handle<JSArrayBuffer> memory) const;
Handle<FixedArray> CompileFunctions(Isolate* isolate) const; Handle<FixedArray> CompileFunctions(Isolate* isolate) const;
uint32_t FunctionTableSize() const {
if (indirect_table_size > 0) {
return indirect_table_size;
}
DCHECK_LE(function_table.size(), UINT32_MAX);
return static_cast<uint32_t>(function_table.size());
}
}; };
// An instantiated WASM module, including memory, function table, etc. // An instantiated WASM module, including memory, function table, etc.
...@@ -280,15 +294,14 @@ struct ModuleEnv { ...@@ -280,15 +294,14 @@ struct ModuleEnv {
DCHECK(IsValidSignature(index)); DCHECK(IsValidSignature(index));
return module->signatures[index]; return module->signatures[index];
} }
size_t FunctionTableSize() { uint32_t FunctionTableSize() const {
return module ? module->function_table.size() : 0; return module->FunctionTableSize();
} }
bool asm_js() { return origin == kAsmJsOrigin; } bool asm_js() { return origin == kAsmJsOrigin; }
Handle<Code> GetCodeOrPlaceholder(uint32_t index) const; Handle<Code> GetCodeOrPlaceholder(uint32_t index) const;
Handle<Code> GetImportCode(uint32_t index); Handle<Code> GetImportCode(uint32_t index);
Handle<FixedArray> GetFunctionTable();
static compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone, static compiler::CallDescriptor* GetWasmCallDescriptor(Zone* zone,
FunctionSig* sig); FunctionSig* sig);
......
// Copyright 2015 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
// Flags: --wasm-jit-prototype
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
var module = (function () {
var builder = new WasmModuleBuilder();
var sig_index = builder.addType(kSig_i_ii);
builder.addPadFunctionTable(512);
builder.addImport("add", sig_index);
builder.addFunction("add", sig_index)
.addBody([
kExprGetLocal, 0, kExprGetLocal, 1, kExprCallImport, kArity2, 0
]);
builder.addFunction("sub", sig_index)
.addBody([
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
kExprI32Sub, // --
]);
builder.addFunction("main", kSig_i_iii)
.addBody([
kExprGetLocal, 0,
kExprGetLocal, 1,
kExprGetLocal, 2,
kExprCallIndirect, kArity2, sig_index
])
.exportFunc()
builder.appendToTable([0, 1, 2]);
return builder.instantiate({add: function(a, b) { return a + b | 0; }});
})();
// Check the module exists.
assertFalse(module === undefined);
assertFalse(module === null);
assertFalse(module === 0);
assertEquals("object", typeof module.exports);
assertEquals("function", typeof module.exports.main);
assertEquals(5, module.exports.main(1, 12, 7));
assertEquals(19, module.exports.main(0, 12, 7));
assertTraps(kTrapFuncSigMismatch, "module.exports.main(2, 12, 33)");
assertTraps(kTrapFuncSigMismatch, "module.exports.main(4, 12, 33)");
assertTraps(kTrapFuncSigMismatch, "module.exports.main(511, 12, 33)");
assertTraps(kTrapFuncInvalid, "module.exports.main(512, 12, 33)");
assertTraps(kTrapFuncInvalid, "module.exports.main(1025, 12, 33)");
assertTraps(kTrapFuncInvalid, "module.exports.main(-1, 12, 33)");
...@@ -64,6 +64,7 @@ var kDeclExports = 0x09; ...@@ -64,6 +64,7 @@ var kDeclExports = 0x09;
var kDeclFunctions = 0x0a; var kDeclFunctions = 0x0a;
var kDeclCode = 0x0b; var kDeclCode = 0x0b;
var kDeclNames = 0x0c; var kDeclNames = 0x0c;
var kDeclFunctionTablePad = 0x0d;
var kArity0 = 0; var kArity0 = 0;
var kArity1 = 1; var kArity1 = 1;
...@@ -74,7 +75,7 @@ var kWasmFunctionTypeForm = 0x40; ...@@ -74,7 +75,7 @@ var kWasmFunctionTypeForm = 0x40;
var section_names = [ var section_names = [
"memory", "type", "old_function", "global", "data", "memory", "type", "old_function", "global", "data",
"table", "end", "start", "import", "export", "table", "end", "start", "import", "export",
"function", "code", "name"]; "function", "code", "name", "table_pad"];
// Function declaration flags // Function declaration flags
var kDeclFunctionName = 0x01; var kDeclFunctionName = 0x01;
......
...@@ -109,6 +109,8 @@ class WasmModuleBuilder { ...@@ -109,6 +109,8 @@ class WasmModuleBuilder {
this.table = []; this.table = [];
this.segments = []; this.segments = [];
this.explicit = []; this.explicit = [];
this.pad = null;
return this;
} }
addStart(start_index) { addStart(start_index) {
...@@ -120,6 +122,11 @@ class WasmModuleBuilder { ...@@ -120,6 +122,11 @@ class WasmModuleBuilder {
return this; return this;
} }
addPadFunctionTable(size) {
this.pad = size;
return this;
}
addExplicitSection(bytes) { addExplicitSection(bytes) {
this.explicit.push(bytes); this.explicit.push(bytes);
return this; return this;
...@@ -331,6 +338,19 @@ class WasmModuleBuilder { ...@@ -331,6 +338,19 @@ class WasmModuleBuilder {
}); });
} }
// Add an indirect function table pad section.
if (wasm.pad !== null) {
if (debug)
print("emitting indirect function table pad @ " + binary.length);
binary.emit_section(kDeclFunctionTablePad, section => {
section.emit_varint(wasm.pad);
});
}
// End the module.
if (debug) print("emitting end @ " + binary.length);
binary.emit_section(kDeclEnd, section => {});
return binary; return binary;
} }
......
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