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 {
auto Table::grow(size_t delta, const Ref* ref) -> bool {
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::HandleScope scope(isolate);
table->Grow(isolate, static_cast<uint32_t>(delta));
// TODO(v8): This should happen in WasmTableObject::Grow.
i::Handle<i::FixedArray> old_array(table->elements(), isolate);
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;
i::Isolate* isolate = table->GetIsolate();
int result =
i::WasmTableObject::Grow(isolate, table, static_cast<uint32_t>(delta),
isolate->factory()->null_value());
return result >= 0;
}
// Memory Instances
......
......@@ -1412,40 +1412,13 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
i::Handle<i::FixedArray> old_array(receiver->elements(), i_isolate);
uint32_t old_size = static_cast<uint32_t>(old_array->length());
int old_size = i::WasmTableObject::Grow(i_isolate, receiver, grow_by,
i_isolate->factory()->null_value());
uint64_t max_size64 = receiver->maximum_length().IsUndefined(i_isolate)
? i::FLAG_wasm_max_table_size
: 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");
if (old_size < 0) {
thrower.RangeError("failed to grow table by %u", grow_by);
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();
return_value.Set(old_size);
}
......
......@@ -835,13 +835,27 @@ void WasmTableObject::AddDispatchTable(Isolate* isolate,
table_obj->set_dispatch_tables(*new_dispatch_tables);
}
void WasmTableObject::Grow(Isolate* isolate, uint32_t count) {
if (count == 0) return; // Degenerate case: nothing to do.
int WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
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);
DCHECK_EQ(0, dispatch_tables->length() % kDispatchTableNumElements);
uint32_t old_size = elements()->length();
// Check if growing by {count} is valid.
uint32_t max_size;
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
// necessary. We simply have to grow the raw tables in each instance
// that has imported this table.
......@@ -853,10 +867,14 @@ void WasmTableObject::Grow(Isolate* isolate, uint32_t count) {
Handle<WasmInstanceObject> instance(
WasmInstanceObject::cast(dispatch_tables->get(i)), isolate);
DCHECK_EQ(old_size, instance->indirect_function_table_size());
uint32_t new_size = old_size + count;
WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(instance,
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,
......
......@@ -262,7 +262,9 @@ class V8_EXPORT_PRIVATE WasmTableObject : public JSObject {
inline uint32_t current_length();
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,
uint32_t initial, bool has_maximum,
......
......@@ -734,7 +734,7 @@ assertEq(tbl.length, 1);
assertEq(tbl.grow(1, 4), 1);
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(
() => tbl.grow(Infinity), TypeError, /must be convertible to a valid number/);
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