Commit c7627bbc authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm] Refactor WasmTableObject::Grow

This CL refactors WasmTableObject::Grow to make it usable for the
table.grow instruction of WebAssembly.

The refactored version of WasmTableObject::Grow does additionally:
* Check if growing is possible
* Grow the FixedArray backing store of the table and initialize the new
  fields.
* Calculate the return value of WasmTableObject::Grow.

R=jkummerow@chromium.org

Bug: v8:7581
Change-Id: Ic6c867b96c30bd987ea281d5b3515a04bc5a3900
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1588136
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61112}
parent 2e6b9f57
...@@ -2000,37 +2000,11 @@ auto Table::size() const -> size_t { ...@@ -2000,37 +2000,11 @@ auto Table::size() const -> size_t {
auto Table::grow(size_t delta, const Ref* ref) -> bool { auto Table::grow(size_t delta, const Ref* ref) -> bool {
i::Handle<i::WasmTableObject> table = impl(this)->v8_object(); i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
const uint32_t kMax = i::FLAG_wasm_max_table_size;
if (delta > kMax) return false;
uint32_t old_size = table->current_length();
if (kMax - old_size < delta) return false;
uint32_t new_size = old_size + static_cast<uint32_t>(delta);
// TODO(v8): The max check should happen in WasmTableObject::Grow.
uint32_t max;
if (table->maximum_length()->ToUint32(&max)) {
if (new_size > max) return false;
}
if (new_size != old_size) {
i::Isolate* isolate = table->GetIsolate(); i::Isolate* isolate = table->GetIsolate();
i::HandleScope scope(isolate); int result =
table->Grow(isolate, static_cast<uint32_t>(delta)); i::WasmTableObject::Grow(isolate, table, static_cast<uint32_t>(delta),
// TODO(v8): This should happen in WasmTableObject::Grow. isolate->factory()->null_value());
i::Handle<i::FixedArray> old_array(table->elements(), isolate); return result >= 0;
i::Handle<i::FixedArray> new_array =
isolate->factory()->NewFixedArray(static_cast<int>(new_size));
for (int i = 0; i < static_cast<int>(old_size); i++) {
new_array->set(i, old_array->get(i));
}
i::Handle<i::Object> val =
ref ? i::Handle<i::Object>::cast(impl(ref)->v8_object())
: i::Handle<i::Object>::cast(
i::ReadOnlyRoots(isolate).null_value_handle());
for (int i = old_size; i < static_cast<int>(new_size); i++) {
new_array->set(i, *val);
}
table->set_elements(*new_array);
}
return true;
} }
// Memory Instances // Memory Instances
......
...@@ -1412,40 +1412,13 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -1412,40 +1412,13 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
return; return;
} }
i::Handle<i::FixedArray> old_array(receiver->elements(), i_isolate); int old_size = i::WasmTableObject::Grow(i_isolate, receiver, grow_by,
uint32_t old_size = static_cast<uint32_t>(old_array->length()); i_isolate->factory()->null_value());
uint64_t max_size64 = receiver->maximum_length().IsUndefined(i_isolate) if (old_size < 0) {
? i::FLAG_wasm_max_table_size thrower.RangeError("failed to grow table by %u", grow_by);
: receiver->maximum_length()->Number();
if (max_size64 > i::FLAG_wasm_max_table_size) {
max_size64 = i::FLAG_wasm_max_table_size;
}
DCHECK_LE(max_size64, std::numeric_limits<uint32_t>::max());
uint64_t new_size64 =
static_cast<uint64_t>(old_size) + static_cast<uint64_t>(grow_by);
if (new_size64 > max_size64) {
thrower.RangeError("maximum table size exceeded");
return; return;
} }
uint32_t new_size = static_cast<uint32_t>(new_size64);
if (new_size != old_size) {
receiver->Grow(i_isolate, new_size - old_size);
i::Handle<i::FixedArray> new_array =
i_isolate->factory()->NewFixedArray(new_size);
for (uint32_t i = 0; i < old_size; ++i) {
new_array->set(i, old_array->get(i));
}
i::Object null = i::ReadOnlyRoots(i_isolate).null_value();
for (uint32_t i = old_size; i < new_size; ++i) new_array->set(i, null);
receiver->set_elements(*new_array);
}
// TODO(gdeepti): use weak links for instances
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(old_size); return_value.Set(old_size);
} }
......
...@@ -835,13 +835,27 @@ void WasmTableObject::AddDispatchTable(Isolate* isolate, ...@@ -835,13 +835,27 @@ void WasmTableObject::AddDispatchTable(Isolate* isolate,
table_obj->set_dispatch_tables(*new_dispatch_tables); table_obj->set_dispatch_tables(*new_dispatch_tables);
} }
void WasmTableObject::Grow(Isolate* isolate, uint32_t count) { int WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
if (count == 0) return; // Degenerate case: nothing to do. uint32_t count, Handle<Object> init_value) {
uint32_t old_size = table->current_length();
if (count == 0) return old_size; // Degenerate case: nothing to do.
Handle<FixedArray> dispatch_tables(this->dispatch_tables(), isolate); // Check if growing by {count} is valid.
DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements); uint32_t max_size;
uint32_t old_size = elements()->length(); if (!table->maximum_length()->ToUint32(&max_size)) {
max_size = FLAG_wasm_max_table_size;
}
DCHECK_LE(old_size, max_size);
if (max_size - old_size < count) return -1;
uint32_t new_size = old_size + count;
auto new_store = isolate->factory()->CopyFixedArrayAndGrow(
handle(table->elements(), isolate), count);
table->set_elements(*new_store, WriteBarrierMode::UPDATE_WRITE_BARRIER);
Handle<FixedArray> dispatch_tables(table->dispatch_tables(), isolate);
DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
// Tables are stored in the instance object, no code patching is // Tables are stored in the instance object, no code patching is
// necessary. We simply have to grow the raw tables in each instance // necessary. We simply have to grow the raw tables in each instance
// that has imported this table. // that has imported this table.
...@@ -853,10 +867,14 @@ void WasmTableObject::Grow(Isolate* isolate, uint32_t count) { ...@@ -853,10 +867,14 @@ void WasmTableObject::Grow(Isolate* isolate, uint32_t count) {
Handle<WasmInstanceObject> instance( Handle<WasmInstanceObject> instance(
WasmInstanceObject::cast(dispatch_tables->get(i)), isolate); WasmInstanceObject::cast(dispatch_tables->get(i)), isolate);
DCHECK_EQ(old_size, instance->indirect_function_table_size()); DCHECK_EQ(old_size, instance->indirect_function_table_size());
uint32_t new_size = old_size + count;
WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(instance, WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(instance,
new_size); new_size);
} }
for (uint32_t entry = old_size; entry < new_size; ++entry) {
WasmTableObject::Set(isolate, table, entry, init_value);
}
return old_size;
} }
bool WasmTableObject::IsInBounds(Isolate* isolate, bool WasmTableObject::IsInBounds(Isolate* isolate,
......
...@@ -262,7 +262,9 @@ class V8_EXPORT_PRIVATE WasmTableObject : public JSObject { ...@@ -262,7 +262,9 @@ class V8_EXPORT_PRIVATE WasmTableObject : public JSObject {
inline uint32_t current_length(); inline uint32_t current_length();
inline wasm::ValueType type(); inline wasm::ValueType type();
void Grow(Isolate* isolate, uint32_t count);
static int Grow(Isolate* isolate, Handle<WasmTableObject> table,
uint32_t count, Handle<Object> init_value);
static Handle<WasmTableObject> New(Isolate* isolate, wasm::ValueType type, static Handle<WasmTableObject> New(Isolate* isolate, wasm::ValueType type,
uint32_t initial, bool has_maximum, uint32_t initial, bool has_maximum,
......
...@@ -734,7 +734,7 @@ assertEq(tbl.length, 1); ...@@ -734,7 +734,7 @@ assertEq(tbl.length, 1);
assertEq(tbl.grow(1, 4), 1); assertEq(tbl.grow(1, 4), 1);
assertEq(tbl.length, 2); assertEq(tbl.length, 2);
assertEq(tbl.length, 2); assertEq(tbl.length, 2);
assertThrows(() => tbl.grow(1), Error, /maximum table size exceeded/); assertThrows(() => tbl.grow(1), Error, /failed to grow table by \d+/);
assertThrows( assertThrows(
() => tbl.grow(Infinity), TypeError, /must be convertible to a valid number/); () => tbl.grow(Infinity), TypeError, /must be convertible to a valid number/);
assertThrows( assertThrows(
......
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