Commit 4cbc5a4d authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm][anyref] Implement WebAssembly.Table.[get|set]

This Cl adds a type to {WasmTableObject}, and extends
{WasmTableObject::Set} and {WasmTableObject::Get} to support anyref
tables. I did it in one CL so that I can write tests.

R=mstarzinger@chromium.org

Bug: v8:7581
Change-Id: I6c6d78f84715a7805f7bb881a63d3c1174f6a6ab
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1511332Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60206}
parent de7ab39a
...@@ -393,7 +393,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { ...@@ -393,7 +393,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
for (int i = module_->num_imported_tables; i < table_count; i++) { for (int i = module_->num_imported_tables; i < table_count; i++) {
const WasmTable& table = module_->tables[i]; const WasmTable& table = module_->tables[i];
Handle<WasmTableObject> table_obj = WasmTableObject::New( Handle<WasmTableObject> table_obj = WasmTableObject::New(
isolate_, table.initial_size, table.maximum_size, nullptr); isolate_, table.type, table.initial_size, table.maximum_size, nullptr);
tables->set(i, *table_obj); tables->set(i, *table_obj);
} }
instance->set_tables(*tables); instance->set_tables(*tables);
...@@ -864,34 +864,26 @@ bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance, ...@@ -864,34 +864,26 @@ bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
// Initialize the dispatch table with the (foreign) JS functions // Initialize the dispatch table with the (foreign) JS functions
// that are already in the table. // that are already in the table.
for (int i = 0; i < imported_table_size; ++i) { for (int i = 0; i < imported_table_size; ++i) {
// TODO(ahaas): Extract this code here into a function on WasmTableObject. bool is_valid;
Handle<Object> val(table_object->elements()->get(i), isolate_); bool is_null;
Handle<WasmInstanceObject> target_instance; MaybeHandle<WasmInstanceObject> maybe_target_instance;
int function_index; int function_index;
FunctionSig* sig; WasmTableObject::GetFunctionTableEntry(isolate_, table_object, i, &is_valid,
if (val->IsNull(isolate_)) { &is_null, &maybe_target_instance,
continue; &function_index);
} else if (WasmExportedFunction::IsWasmExportedFunction(*val)) { if (!is_valid) {
auto target_func = Handle<WasmExportedFunction>::cast(val);
target_instance = handle(target_func->instance(), isolate_);
sig = target_func->sig();
function_index = target_func->function_index();
} else if (val->IsTuple2()) {
// {val} can be a {Tuple2} if no WasmExportedFunction has been
// constructed for the function yet, but the function exists.
auto tuple = Handle<Tuple2>::cast(val);
target_instance =
handle(WasmInstanceObject::cast(tuple->value1()), isolate_);
function_index = Smi::cast(tuple->value2()).value();
sig = target_instance->module_object()
->module()
->functions[function_index]
.sig;
} else {
thrower_->LinkError("table import %d[%d] is not a wasm function", thrower_->LinkError("table import %d[%d] is not a wasm function",
import_index, i); import_index, i);
return false; return false;
} }
if (is_null) continue;
Handle<WasmInstanceObject> target_instance =
maybe_target_instance.ToHandleChecked();
FunctionSig* sig = target_instance->module_object()
->module()
->functions[function_index]
.sig;
// Look up the signature's canonical id. If there is no canonical // Look up the signature's canonical id. If there is no canonical
// id, then the signature does not appear at all in this module, // id, then the signature does not appear at all in this module,
...@@ -1518,7 +1510,7 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance, ...@@ -1518,7 +1510,7 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
if (func_index == WasmElemSegment::kNullIndex) { if (func_index == WasmElemSegment::kNullIndex) {
IndirectFunctionTableEntry(instance, entry_index).clear(); IndirectFunctionTableEntry(instance, entry_index).clear();
WasmTableObject::Set(isolate, table_object, entry_index, WasmTableObject::Set(isolate, table_object, entry_index,
Handle<JSFunction>::null()); isolate->factory()->null_value());
continue; continue;
} }
...@@ -1543,12 +1535,8 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance, ...@@ -1543,12 +1535,8 @@ bool LoadElemSegmentImpl(Isolate* isolate, Handle<WasmInstanceObject> instance,
func_index, js_to_wasm_cache); func_index, js_to_wasm_cache);
table_object->elements()->set(entry_index, *function); table_object->elements()->set(entry_index, *function);
} else { } else {
// Put (instance, func_index) as a placeholder into the table_index. WasmTableObject::SetFunctionTablePlaceholder(
// The {WasmExportedFunction} will be created lazily. isolate, table_object, entry_index, instance, func_index);
Handle<Tuple2> tuple = isolate->factory()->NewTuple2(
instance, Handle<Smi>(Smi::FromInt(func_index), isolate),
AllocationType::kYoung);
table_object->elements()->set(entry_index, *tuple);
} }
} else { } else {
table_object->elements()->set(entry_index, table_object->elements()->set(entry_index,
......
...@@ -1027,6 +1027,7 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -1027,6 +1027,7 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
} }
Local<Context> context = isolate->GetCurrentContext(); Local<Context> context = isolate->GetCurrentContext();
Local<v8::Object> descriptor = Local<Object>::Cast(args[0]); Local<v8::Object> descriptor = Local<Object>::Cast(args[0]);
i::wasm::ValueType type;
// The descriptor's 'element'. // The descriptor's 'element'.
{ {
v8::MaybeLocal<v8::Value> maybe = v8::MaybeLocal<v8::Value> maybe =
...@@ -1035,7 +1036,13 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -1035,7 +1036,13 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (!maybe.ToLocal(&value)) return; if (!maybe.ToLocal(&value)) return;
v8::Local<v8::String> string; v8::Local<v8::String> string;
if (!value->ToString(context).ToLocal(&string)) return; if (!value->ToString(context).ToLocal(&string)) return;
if (!string->StringEquals(v8_str(isolate, "anyfunc"))) { auto enabled_features = i::wasm::WasmFeaturesFromFlags();
if (string->StringEquals(v8_str(isolate, "anyfunc"))) {
type = i::wasm::kWasmAnyFunc;
} else if (enabled_features.anyref &&
string->StringEquals(v8_str(isolate, "anyref"))) {
type = i::wasm::kWasmAnyRef;
} else {
thrower.TypeError("Descriptor property 'element' must be 'anyfunc'"); thrower.TypeError("Descriptor property 'element' must be 'anyfunc'");
return; return;
} }
...@@ -1057,7 +1064,7 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -1057,7 +1064,7 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
i::Handle<i::FixedArray> fixed_array; i::Handle<i::FixedArray> fixed_array;
i::Handle<i::JSObject> table_obj = i::Handle<i::JSObject> table_obj =
i::WasmTableObject::New(i_isolate, static_cast<uint32_t>(initial), i::WasmTableObject::New(i_isolate, type, static_cast<uint32_t>(initial),
static_cast<uint32_t>(maximum), &fixed_array); static_cast<uint32_t>(maximum), &fixed_array);
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue(); v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(Utils::ToLocal(table_obj)); return_value.Set(Utils::ToLocal(table_obj));
...@@ -1403,31 +1410,24 @@ void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -1403,31 +1410,24 @@ void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
HandleScope scope(isolate); HandleScope scope(isolate);
ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.set()"); ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Table.set()");
Local<Context> context = isolate->GetCurrentContext(); Local<Context> context = isolate->GetCurrentContext();
EXTRACT_THIS(receiver, WasmTableObject); EXTRACT_THIS(table_object, WasmTableObject);
// Parameter 0. // Parameter 0.
uint32_t index; uint32_t index;
if (!EnforceUint32("Argument 0", args[0], context, &thrower, &index)) { if (!EnforceUint32("Argument 0", args[0], context, &thrower, &index)) {
return; return;
} }
if (!i::WasmTableObject::IsInBounds(i_isolate, table_object, index)) {
// Parameter 1. thrower.RangeError("invalid index %u into function table", index);
i::Handle<i::Object> value = Utils::OpenHandle(*args[1]);
if (!value->IsNull(i_isolate) &&
!i::WasmExportedFunction::IsWasmExportedFunction(*value)) {
thrower.TypeError("Argument 1 must be null or a WebAssembly function");
return; return;
} }
if (index >= static_cast<uint64_t>(receiver->elements()->length())) { i::Handle<i::Object> element = Utils::OpenHandle(*args[1]);
thrower.RangeError("index out of bounds"); if (!i::WasmTableObject::IsValidElement(i_isolate, table_object, element)) {
thrower.TypeError("Argument 1 must be null or a WebAssembly function");
return; return;
} }
i::WasmTableObject::Set(i_isolate, table_object, index, element);
i::WasmTableObject::Set(i_isolate, receiver, index,
value->IsNull(i_isolate)
? i::Handle<i::JSFunction>::null()
: i::Handle<i::JSFunction>::cast(value));
} }
// WebAssembly.Memory.grow(num) -> num // WebAssembly.Memory.grow(num) -> num
......
...@@ -108,6 +108,7 @@ bool WasmModuleObject::is_asm_js() { ...@@ -108,6 +108,7 @@ bool WasmModuleObject::is_asm_js() {
ACCESSORS(WasmTableObject, elements, FixedArray, kElementsOffset) ACCESSORS(WasmTableObject, elements, FixedArray, kElementsOffset)
ACCESSORS(WasmTableObject, maximum_length, Object, kMaximumLengthOffset) ACCESSORS(WasmTableObject, maximum_length, Object, kMaximumLengthOffset)
ACCESSORS(WasmTableObject, dispatch_tables, FixedArray, kDispatchTablesOffset) ACCESSORS(WasmTableObject, dispatch_tables, FixedArray, kDispatchTablesOffset)
SMI_ACCESSORS(WasmTableObject, raw_type, kRawTypeOffset)
// WasmMemoryObject // WasmMemoryObject
ACCESSORS(WasmMemoryObject, array_buffer, JSArrayBuffer, kArrayBufferOffset) ACCESSORS(WasmMemoryObject, array_buffer, JSArrayBuffer, kArrayBufferOffset)
...@@ -301,6 +302,10 @@ OPTIONAL_ACCESSORS(WasmDebugInfo, c_wasm_entry_map, Managed<wasm::SignatureMap>, ...@@ -301,6 +302,10 @@ OPTIONAL_ACCESSORS(WasmDebugInfo, c_wasm_entry_map, Managed<wasm::SignatureMap>,
uint32_t WasmTableObject::current_length() { return elements()->length(); } uint32_t WasmTableObject::current_length() { return elements()->length(); }
wasm::ValueType WasmTableObject::type() {
return static_cast<wasm::ValueType>(raw_type());
}
bool WasmMemoryObject::has_maximum_pages() { return maximum_pages() >= 0; } bool WasmMemoryObject::has_maximum_pages() { return maximum_pages() >= 0; }
// WasmExceptionTag // WasmExceptionTag
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "src/wasm/module-compiler.h" #include "src/wasm/module-compiler.h"
#include "src/wasm/module-decoder.h" #include "src/wasm/module-decoder.h"
#include "src/wasm/module-instantiate.h" #include "src/wasm/module-instantiate.h"
#include "src/wasm/value-type.h"
#include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-code-manager.h"
#include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-limits.h" #include "src/wasm/wasm-limits.h"
...@@ -777,9 +778,10 @@ bool WasmModuleObject::GetPositionInfo(uint32_t position, ...@@ -777,9 +778,10 @@ bool WasmModuleObject::GetPositionInfo(uint32_t position,
return true; return true;
} }
Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial, Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate,
uint32_t maximum, wasm::ValueType type,
Handle<FixedArray>* js_functions) { uint32_t initial, uint32_t maximum,
Handle<FixedArray>* elements) {
Handle<JSFunction> table_ctor( Handle<JSFunction> table_ctor(
isolate->native_context()->wasm_table_constructor(), isolate); isolate->native_context()->wasm_table_constructor(), isolate);
auto table_obj = Handle<WasmTableObject>::cast( auto table_obj = Handle<WasmTableObject>::cast(
...@@ -790,13 +792,15 @@ Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial, ...@@ -790,13 +792,15 @@ Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial,
for (int i = 0; i < static_cast<int>(initial); ++i) { for (int i = 0; i < static_cast<int>(initial); ++i) {
backing_store->set(i, null); backing_store->set(i, null);
} }
table_obj->set_raw_type(static_cast<int>(type));
table_obj->set_elements(*backing_store); table_obj->set_elements(*backing_store);
Handle<Object> max = isolate->factory()->NewNumberFromUint(maximum); Handle<Object> max = isolate->factory()->NewNumberFromUint(maximum);
table_obj->set_maximum_length(*max); table_obj->set_maximum_length(*max);
table_obj->set_dispatch_tables(ReadOnlyRoots(isolate).empty_fixed_array()); table_obj->set_dispatch_tables(ReadOnlyRoots(isolate).empty_fixed_array());
if (js_functions != nullptr) { if (elements != nullptr) {
*js_functions = backing_store; *elements = backing_store;
} }
return Handle<WasmTableObject>::cast(table_obj); return Handle<WasmTableObject>::cast(table_obj);
} }
...@@ -857,16 +861,38 @@ bool WasmTableObject::IsInBounds(Isolate* isolate, ...@@ -857,16 +861,38 @@ bool WasmTableObject::IsInBounds(Isolate* isolate,
static_cast<int>(entry_index) < table->elements()->length()); static_cast<int>(entry_index) < table->elements()->length());
} }
bool WasmTableObject::IsValidElement(Isolate* isolate,
Handle<WasmTableObject> table,
Handle<Object> element) {
// Anyref tables take everything.
if (table->type() == wasm::kWasmAnyRef) return true;
// Anyfunc tables can store {null} or {WasmExportedFunction} objects.
if (element->IsNull(isolate)) return true;
return WasmExportedFunction::IsWasmExportedFunction(*element);
}
void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table, void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
uint32_t table_index, Handle<JSFunction> function) { uint32_t index, Handle<Object> element) {
Handle<FixedArray> array(table->elements(), isolate); // Callers need to perform bounds checks, type check, and error handling.
if (function.is_null()) { DCHECK(IsInBounds(isolate, table, index));
DCHECK(IsValidElement(isolate, table, element));
Handle<FixedArray> elements(table->elements(), isolate);
// The FixedArray is addressed with int's.
int table_index = static_cast<int>(index);
if (table->type() == wasm::kWasmAnyRef) {
elements->set(table_index, *element);
return;
}
if (element->IsNull(isolate)) {
ClearDispatchTables(isolate, table, table_index); // Degenerate case. ClearDispatchTables(isolate, table, table_index); // Degenerate case.
array->set(table_index, ReadOnlyRoots(isolate).null_value()); elements->set(table_index, ReadOnlyRoots(isolate).null_value());
return; return;
} }
auto exported_function = Handle<WasmExportedFunction>::cast(function); DCHECK(WasmExportedFunction::IsWasmExportedFunction(*element));
auto exported_function = Handle<WasmExportedFunction>::cast(element);
Handle<WasmInstanceObject> target_instance(exported_function->instance(), Handle<WasmInstanceObject> target_instance(exported_function->instance(),
isolate); isolate);
int func_index = exported_function->function_index(); int func_index = exported_function->function_index();
...@@ -876,19 +902,25 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table, ...@@ -876,19 +902,25 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
UpdateDispatchTables(isolate, table, table_index, wasm_function->sig, UpdateDispatchTables(isolate, table, table_index, wasm_function->sig,
handle(exported_function->instance(), isolate), handle(exported_function->instance(), isolate),
func_index); func_index);
array->set(table_index, *function); elements->set(table_index, *element);
} }
Handle<Object> WasmTableObject::Get(Isolate* isolate, Handle<Object> WasmTableObject::Get(Isolate* isolate,
Handle<WasmTableObject> table, Handle<WasmTableObject> table,
uint32_t index) { uint32_t index) {
Handle<FixedArray> elements(table->elements(), isolate); Handle<FixedArray> elements(table->elements(), isolate);
// Callers need to perform bounds checks and error handling.
DCHECK(IsInBounds(isolate, table, index)); DCHECK(IsInBounds(isolate, table, index));
// The FixedArray is addressed with int's. // The FixedArray is addressed with int's.
int entry_index = static_cast<int>(index); int entry_index = static_cast<int>(index);
Handle<Object> element(elements->get(entry_index), isolate); Handle<Object> element(elements->get(entry_index), isolate);
// First we handle the easy anyref table case.
if (table->type() == wasm::kWasmAnyRef) return element;
// Now we handle the anyfunc case.
if (WasmExportedFunction::IsWasmExportedFunction(*element)) { if (WasmExportedFunction::IsWasmExportedFunction(*element)) {
return element; return element;
} }
...@@ -973,6 +1005,44 @@ void WasmTableObject::ClearDispatchTables(Isolate* isolate, ...@@ -973,6 +1005,44 @@ void WasmTableObject::ClearDispatchTables(Isolate* isolate,
} }
} }
void WasmTableObject::SetFunctionTablePlaceholder(
Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
Handle<WasmInstanceObject> instance, int func_index) {
// Put (instance, func_index) as a Tuple2 into the table_index.
// The {WasmExportedFunction} will be created lazily.
Handle<Tuple2> tuple = isolate->factory()->NewTuple2(
instance, Handle<Smi>(Smi::FromInt(func_index), isolate),
AllocationType::kYoung);
table->elements()->set(entry_index, *tuple);
}
void WasmTableObject::GetFunctionTableEntry(
Isolate* isolate, Handle<WasmTableObject> table, int entry_index,
bool* is_valid, bool* is_null, MaybeHandle<WasmInstanceObject>* instance,
int* function_index) {
DCHECK_EQ(table->type(), wasm::kWasmAnyFunc);
DCHECK_LT(entry_index, table->elements()->length());
// We initialize {is_valid} with {true}. We may change it later.
*is_valid = true;
Handle<Object> element(table->elements()->get(entry_index), isolate);
*is_null = element->IsNull(isolate);
if (*is_null) return;
if (WasmExportedFunction::IsWasmExportedFunction(*element)) {
auto target_func = Handle<WasmExportedFunction>::cast(element);
*instance = handle(target_func->instance(), isolate);
*function_index = target_func->function_index();
return;
} else if (element->IsTuple2()) {
auto tuple = Handle<Tuple2>::cast(element);
*instance = handle(WasmInstanceObject::cast(tuple->value1()), isolate);
*function_index = Smi::cast(tuple->value2()).value();
return;
}
*is_valid = false;
}
namespace { namespace {
bool AdjustBufferPermissions(Isolate* isolate, Handle<JSArrayBuffer> old_buffer, bool AdjustBufferPermissions(Isolate* isolate, Handle<JSArrayBuffer> old_buffer,
size_t new_size) { size_t new_size) {
......
...@@ -258,23 +258,26 @@ class WasmTableObject : public JSObject { ...@@ -258,23 +258,26 @@ class WasmTableObject : public JSObject {
// TODO(titzer): introduce DECL_I64_ACCESSORS macro // TODO(titzer): introduce DECL_I64_ACCESSORS macro
DECL_ACCESSORS(maximum_length, Object) DECL_ACCESSORS(maximum_length, Object)
DECL_ACCESSORS(dispatch_tables, FixedArray) DECL_ACCESSORS(dispatch_tables, FixedArray)
DECL_INT_ACCESSORS(raw_type)
// Layout description. // Layout description.
#define WASM_TABLE_OBJECT_FIELDS(V) \ #define WASM_TABLE_OBJECT_FIELDS(V) \
V(kElementsOffset, kTaggedSize) \ V(kElementsOffset, kTaggedSize) \
V(kMaximumLengthOffset, kTaggedSize) \ V(kMaximumLengthOffset, kTaggedSize) \
V(kDispatchTablesOffset, kTaggedSize) \ V(kDispatchTablesOffset, kTaggedSize) \
V(kRawTypeOffset, kTaggedSize) \
V(kSize, 0) V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, WASM_TABLE_OBJECT_FIELDS) DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, WASM_TABLE_OBJECT_FIELDS)
#undef WASM_TABLE_OBJECT_FIELDS #undef WASM_TABLE_OBJECT_FIELDS
inline uint32_t current_length(); inline uint32_t current_length();
inline wasm::ValueType type();
void Grow(Isolate* isolate, uint32_t count); void Grow(Isolate* isolate, uint32_t count);
static Handle<WasmTableObject> New(Isolate* isolate, uint32_t initial, static Handle<WasmTableObject> New(Isolate* isolate, wasm::ValueType type,
uint32_t maximum, uint32_t initial, uint32_t maximum,
Handle<FixedArray>* js_functions); Handle<FixedArray>* elements);
static void AddDispatchTable(Isolate* isolate, Handle<WasmTableObject> table, static void AddDispatchTable(Isolate* isolate, Handle<WasmTableObject> table,
Handle<WasmInstanceObject> instance, Handle<WasmInstanceObject> instance,
int table_index); int table_index);
...@@ -282,8 +285,11 @@ class WasmTableObject : public JSObject { ...@@ -282,8 +285,11 @@ class WasmTableObject : public JSObject {
static bool IsInBounds(Isolate* isolate, Handle<WasmTableObject> table, static bool IsInBounds(Isolate* isolate, Handle<WasmTableObject> table,
uint32_t entry_index); uint32_t entry_index);
static bool IsValidElement(Isolate* isolate, Handle<WasmTableObject> table,
Handle<Object> entry);
static void Set(Isolate* isolate, Handle<WasmTableObject> table, static void Set(Isolate* isolate, Handle<WasmTableObject> table,
uint32_t index, Handle<JSFunction> function); uint32_t index, Handle<Object> element);
static Handle<Object> Get(Isolate* isolate, Handle<WasmTableObject> table, static Handle<Object> Get(Isolate* isolate, Handle<WasmTableObject> table,
uint32_t index); uint32_t index);
...@@ -297,6 +303,22 @@ class WasmTableObject : public JSObject { ...@@ -297,6 +303,22 @@ class WasmTableObject : public JSObject {
static void ClearDispatchTables(Isolate* isolate, static void ClearDispatchTables(Isolate* isolate,
Handle<WasmTableObject> table, int index); Handle<WasmTableObject> table, int index);
static void SetFunctionTablePlaceholder(Isolate* isolate,
Handle<WasmTableObject> table,
int entry_index,
Handle<WasmInstanceObject> instance,
int func_index);
// This function reads the content of a function table entry and returns it
// through the out parameters {is_valid}, {is_null}, {instance}, and
// {function_index}.
static void GetFunctionTableEntry(Isolate* isolate,
Handle<WasmTableObject> table,
int entry_index, bool* is_valid,
bool* is_null,
MaybeHandle<WasmInstanceObject>* instance,
int* function_index);
OBJECT_CONSTRUCTORS(WasmTableObject, JSObject); OBJECT_CONSTRUCTORS(WasmTableObject, JSObject);
}; };
......
// Copyright 2019 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: --experimental-wasm-anyref
load("test/mjsunit/wasm/wasm-module-builder.js");
(function TestAnyRefTableSetWithMultipleTypes() {
print(arguments.callee.name);
let table = new WebAssembly.Table({element: "anyref", initial: 10});
// Table should be initialized with null.
assertEquals(null, table.get(1));
let obj = {'hello' : 'world'};
table.set(2, obj);
assertSame(obj, table.get(2));
table.set(3, 1234);
assertEquals(1234, table.get(3));
table.set(4, 123.5);
assertEquals(123.5, table.get(4));
table.set(5, undefined);
assertEquals(undefined, table.get(5));
// Overwrite entry 4, because null would otherwise be the default value.
table.set(4, null);
assertEquals(null, table.get(4));
table.set(7, print);
assertEquals(print, table.get(7));
assertThrows(() => table.set(12), RangeError);
})();
...@@ -641,9 +641,9 @@ assertEq(get.call(tbl1, 0), null); ...@@ -641,9 +641,9 @@ assertEq(get.call(tbl1, 0), null);
assertEq(get.call(tbl1, 0, Infinity), null); assertEq(get.call(tbl1, 0, Infinity), null);
assertEq(get.call(tbl1, 1), null); assertEq(get.call(tbl1, 1), null);
assertEq(get.call(tbl1, 1.5), null); assertEq(get.call(tbl1, 1.5), null);
assertThrows(() => get.call(tbl1, 2), RangeError, /invalid index \d* into function table/); assertThrows(() => get.call(tbl1, 2), RangeError, /invalid index \d+ into function table/);
assertThrows( assertThrows(
() => get.call(tbl1, 2.5), RangeError, /invalid index \d* into function table/); () => get.call(tbl1, 2.5), RangeError, /invalid index \d+ into function table/);
assertThrows(() => get.call(tbl1, -1), TypeError, /must be non-negative/); assertThrows(() => get.call(tbl1, -1), TypeError, /must be non-negative/);
assertThrows( assertThrows(
() => get.call(tbl1, Math.pow(2, 33)), TypeError, () => get.call(tbl1, Math.pow(2, 33)), TypeError,
...@@ -670,7 +670,7 @@ assertThrows( ...@@ -670,7 +670,7 @@ assertThrows(
() => set.call(tbl1, undefined), TypeError, () => set.call(tbl1, undefined), TypeError,
/must be convertible to a valid number/); /must be convertible to a valid number/);
assertThrows( assertThrows(
() => set.call(tbl1, 2, null), RangeError, /index out of bounds/); () => set.call(tbl1, 2, null), RangeError, /invalid index \d+ into function table/);
assertThrows( assertThrows(
() => set.call(tbl1, -1, null), TypeError, /must be non-negative/); () => set.call(tbl1, -1, null), TypeError, /must be non-negative/);
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