[wasm] Table.Grow should grow dispatch tables
- Table.Grow updates function, signature table sizes - Updates generated code with new base addresses for function, signature tables - Relocates size references for correct bounds check R=bradnelson@chromium.org, titzer@chromium.org Review-Url: https://codereview.chromium.org/2637643002 Cr-Commit-Position: refs/heads/master@{#42349}
This commit is contained in:
parent
6fad1ad27d
commit
ccf0998d63
@ -546,7 +546,10 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
isolate->ThrowException(e);
|
||||
return;
|
||||
}
|
||||
|
||||
int new_size = static_cast<int>(new_size64);
|
||||
i::WasmTableObject::Grow(i_isolate, receiver,
|
||||
static_cast<uint32_t>(new_size - old_size));
|
||||
|
||||
if (new_size != old_size) {
|
||||
i::Handle<i::FixedArray> new_array =
|
||||
@ -557,7 +560,9 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
receiver->set_functions(*new_array);
|
||||
}
|
||||
|
||||
// TODO(titzer): update relevant instances.
|
||||
// TODO(gdeepti): use weak links for instances
|
||||
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
|
||||
return_value.Set(old_size);
|
||||
}
|
||||
|
||||
void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
|
@ -147,6 +147,19 @@ void RelocateGlobals(Handle<FixedArray> code_table, Address old_start,
|
||||
}
|
||||
}
|
||||
|
||||
void RelocateTableSizeReferences(Handle<FixedArray> code_table,
|
||||
uint32_t old_size, uint32_t new_size) {
|
||||
for (int i = 0; i < code_table->length(); ++i) {
|
||||
DCHECK(code_table->get(i)->IsCode());
|
||||
Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i)));
|
||||
AllowDeferredHandleDereference embedding_raw_address;
|
||||
int mask = 1 << RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE;
|
||||
for (RelocIterator it(*code, mask); !it.done(); it.next()) {
|
||||
it.rinfo()->update_wasm_function_table_size_reference(old_size, new_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Handle<Code> CreatePlaceholder(Factory* factory, Code::Kind kind) {
|
||||
byte buffer[] = {0, 0, 0, 0}; // fake instructions.
|
||||
CodeDesc desc = {
|
||||
@ -2343,6 +2356,42 @@ int32_t wasm::GrowMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
|
||||
}
|
||||
}
|
||||
|
||||
void wasm::GrowDispatchTables(Isolate* isolate,
|
||||
Handle<FixedArray> dispatch_tables,
|
||||
uint32_t old_size, uint32_t count) {
|
||||
DCHECK_EQ(0, dispatch_tables->length() % 4);
|
||||
for (int i = 0; i < dispatch_tables->length(); i += 4) {
|
||||
Handle<FixedArray> old_function_table(
|
||||
FixedArray::cast(dispatch_tables->get(i + 2)));
|
||||
Handle<FixedArray> old_signature_table(
|
||||
FixedArray::cast(dispatch_tables->get(i + 3)));
|
||||
Handle<FixedArray> new_function_table =
|
||||
isolate->factory()->CopyFixedArrayAndGrow(old_function_table, count);
|
||||
Handle<FixedArray> new_signature_table =
|
||||
isolate->factory()->CopyFixedArrayAndGrow(old_signature_table, count);
|
||||
|
||||
// Get code table for the instance
|
||||
Handle<WasmInstanceObject> instance(
|
||||
WasmInstanceObject::cast(dispatch_tables->get(i)));
|
||||
Handle<FixedArray> code_table(instance->compiled_module()->code_table());
|
||||
|
||||
// Relocate size references
|
||||
RelocateTableSizeReferences(code_table, old_size, old_size + count);
|
||||
|
||||
// Replace references of old tables with new tables.
|
||||
for (int j = 0; j < code_table->length(); ++j) {
|
||||
if (!code_table->get(j)->IsCode()) continue;
|
||||
Handle<Code> code = Handle<Code>(Code::cast(code_table->get(j)));
|
||||
ReplaceReferenceInCode(code, old_function_table, new_function_table);
|
||||
ReplaceReferenceInCode(code, old_signature_table, new_signature_table);
|
||||
}
|
||||
|
||||
// Update dispatch tables with new function/signature tables
|
||||
dispatch_tables->set(i + 2, *new_function_table);
|
||||
dispatch_tables->set(i + 3, *new_signature_table);
|
||||
}
|
||||
}
|
||||
|
||||
void testing::ValidateInstancesChain(Isolate* isolate,
|
||||
Handle<WasmModuleObject> module_obj,
|
||||
int instance_count) {
|
||||
|
@ -440,6 +440,9 @@ int32_t GrowMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
|
||||
void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
|
||||
int index, Handle<JSFunction> js_function);
|
||||
|
||||
void GrowDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
|
||||
uint32_t old_size, uint32_t count);
|
||||
|
||||
namespace testing {
|
||||
|
||||
void ValidateInstancesChain(Isolate* isolate,
|
||||
|
@ -186,6 +186,13 @@ WasmTableObject* WasmTableObject::cast(Object* object) {
|
||||
return reinterpret_cast<WasmTableObject*>(object);
|
||||
}
|
||||
|
||||
void WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
|
||||
uint32_t count) {
|
||||
Handle<FixedArray> dispatch_tables(table->dispatch_tables());
|
||||
wasm::GrowDispatchTables(isolate, dispatch_tables,
|
||||
table->functions()->length(), count);
|
||||
}
|
||||
|
||||
Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
|
||||
Handle<JSArrayBuffer> buffer,
|
||||
int maximum) {
|
||||
|
@ -65,7 +65,8 @@ class WasmTableObject : public JSObject {
|
||||
static Handle<WasmTableObject> New(Isolate* isolate, uint32_t initial,
|
||||
uint32_t maximum,
|
||||
Handle<FixedArray>* js_functions);
|
||||
static bool Grow(Handle<WasmTableObject> table, uint32_t count);
|
||||
static void Grow(Isolate* isolate, Handle<WasmTableObject> table,
|
||||
uint32_t count);
|
||||
static Handle<FixedArray> AddDispatchTable(
|
||||
Isolate* isolate, Handle<WasmTableObject> table,
|
||||
Handle<WasmInstanceObject> instance, int table_index,
|
||||
@ -91,7 +92,8 @@ class WasmMemoryObject : public JSObject {
|
||||
Handle<JSArrayBuffer> buffer,
|
||||
int maximum);
|
||||
|
||||
static bool Grow(Handle<WasmMemoryObject> memory, uint32_t count);
|
||||
static bool Grow(Isolate* isolate, Handle<WasmMemoryObject> memory,
|
||||
uint32_t count);
|
||||
};
|
||||
|
||||
// Representation of a WebAssembly.Instance JavaScript-level object.
|
||||
|
@ -371,7 +371,89 @@ function js_div(a, b) { return (a / b) | 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
})();
|
||||
|
||||
(function TableGrowBoundsCheck() {
|
||||
print("TableGrowBoundsCheck");
|
||||
var kMaxSize = 30, kInitSize = 5;
|
||||
let table = new WebAssembly.Table({element: "anyfunc",
|
||||
initial: kInitSize, maximum: kMaxSize});
|
||||
var builder = new WasmModuleBuilder();
|
||||
builder.addImportedTable("x", "table", kInitSize, kMaxSize);
|
||||
let module = new WebAssembly.Module(builder.toBuffer());
|
||||
let instance = new WebAssembly.Instance(module, {x: {base: 1, table: table}});
|
||||
|
||||
for(var i = kInitSize; i < kMaxSize; i+=5) {
|
||||
assertEquals(i, table.length);
|
||||
for (var j = 0; j < i; j++) table.set(j, null);
|
||||
for (var j = 0; j < i; j++) assertEquals(null, table.get(j));
|
||||
assertThrows(() => table.set(i, null));
|
||||
assertThrows(() => table.get(i));
|
||||
assertEquals(i, table.grow(5));
|
||||
}
|
||||
assertEquals(30, table.length);
|
||||
assertThrows(() => table.grow(1));
|
||||
assertThrows(() => table.set(kMaxSize, null));
|
||||
assertThrows(() => table.get(kMaxSize));
|
||||
})();
|
||||
|
||||
(function CumulativeGrowTest() {
|
||||
print("CumulativeGrowTest...");
|
||||
let table = new WebAssembly.Table({
|
||||
element: "anyfunc", initial: 10, maximum: 30});
|
||||
var builder = new WasmModuleBuilder();
|
||||
builder.addImportedTable("x", "table", 10, 30);
|
||||
|
||||
let g = builder.addImportedGlobal("x", "base", kWasmI32);
|
||||
let sig_index = builder.addType(kSig_i_v);
|
||||
builder.addFunction("g", sig_index)
|
||||
.addBody([
|
||||
kExprGetGlobal, g
|
||||
]);
|
||||
builder.addFunction("main", kSig_i_ii)
|
||||
.addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprCallIndirect, sig_index, kTableZero]) // --
|
||||
.exportAs("main");
|
||||
builder.addFunctionTableInit(g, true, [g]);
|
||||
let module = new WebAssembly.Module(builder.toBuffer());
|
||||
|
||||
var instances = [];
|
||||
for (var i = 0; i < 10; i++) {
|
||||
print(" base = " + i);
|
||||
instances.push(new WebAssembly.Instance(
|
||||
module, {x: {base: i, table: table}}));
|
||||
}
|
||||
|
||||
for (var j = 0; j < 10; j++) {
|
||||
let func = table.get(j);
|
||||
assertEquals("function", typeof func);
|
||||
assertEquals(j, func());
|
||||
assertEquals(j, instances[j].exports.main(j));
|
||||
}
|
||||
|
||||
assertEquals(10, table.grow(10));
|
||||
|
||||
// Verify that grow does not alter function behaviors
|
||||
for (var j = 0; j < 10; j++) {
|
||||
let func = table.get(j);
|
||||
assertEquals("function", typeof func);
|
||||
assertEquals(j, func());
|
||||
assertEquals(j, instances[j].exports.main(j));
|
||||
}
|
||||
|
||||
let new_builder = new WasmModuleBuilder();
|
||||
new_builder.addExport("wasm", new_builder.addFunction("", kSig_v_v));
|
||||
new_builder.addImportedTable("x", "table", 20, 30);
|
||||
let new_module = new WebAssembly.Module(new_builder.toBuffer());
|
||||
let instance = new WebAssembly.Instance(new_module, {x: {table: table}});
|
||||
let new_func = instance.exports.wasm;
|
||||
|
||||
for (var j = 10; j < 20; j++) {
|
||||
table.set(j, new_func);
|
||||
let func = table.get(j);
|
||||
assertEquals("function", typeof func);
|
||||
assertSame(new_func, table.get(j));
|
||||
}
|
||||
assertThrows(() => table.grow(11));
|
||||
})();
|
||||
|
@ -508,7 +508,6 @@ assertEq(tblGrowDesc.enumerable, false);
|
||||
assertEq(tblGrowDesc.configurable, true);
|
||||
|
||||
// 'WebAssembly.Table.prototype.grow' method
|
||||
if (false) { // TODO: Table.grow
|
||||
let tblGrow = tblGrowDesc.value;
|
||||
assertEq(tblGrow.length, 1);
|
||||
assertErrorMessage(() => tblGrow.call(), TypeError, /called on incompatible undefined/);
|
||||
@ -522,7 +521,6 @@ assertEq(tbl.length, 1);
|
||||
assertEq(tbl.grow(1), 1);
|
||||
assertEq(tbl.length, 2);
|
||||
assertErrorMessage(() => tbl.grow(1), Error, /failed to grow table/);
|
||||
}
|
||||
|
||||
// 'WebAssembly.validate' function
|
||||
assertErrorMessage(() => WebAssembly.validate(), TypeError);
|
||||
|
Loading…
Reference in New Issue
Block a user