[wasm-gc] Always use JSToWasmObject at the JS-to-Wasm boundary

- Remove the {ValueRepr} parameter from Wasm table and global object
  internals. It is now the responsibility of the user to transform
  to/from a JS object. This removes duplicate work in some cases (type
  checking in the caller, transforming in the callee).
- For the reverse direction in the JS API, introduce
  {WasmObjectToJSReturnValue}.

Bug: v8:7748
Change-Id: Ie7625cc0f08d38fe74dbe57e69004de2d93b8a11
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3876184
Reviewed-by: Simon Zünd <szuend@chromium.org>
Reviewed-by: Matthias Liedtke <mliedtke@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83031}
This commit is contained in:
Manos Koukoutos 2022-09-07 13:09:52 +02:00 committed by V8 LUCI CQ
parent a77183b126
commit b5919c416a
14 changed files with 282 additions and 467 deletions

View File

@ -1035,8 +1035,7 @@ Handle<ArrayList> AddWasmTableObjectInternalProperties(
int length = table->current_length();
Handle<FixedArray> entries = isolate->factory()->NewFixedArray(length);
for (int i = 0; i < length; ++i) {
Handle<Object> entry =
WasmTableObject::Get(isolate, table, i, WasmTableObject::kWasm);
Handle<Object> entry = WasmTableObject::Get(isolate, table, i);
wasm::WasmValue wasm_value(entry, table->type());
Handle<WasmModuleObject> module(
WasmInstanceObject::cast(table->instance()).module_object(), isolate);

View File

@ -458,8 +458,7 @@ RUNTIME_FUNCTION(Runtime_WasmFunctionTableGet) {
return ThrowWasmError(isolate, MessageTemplate::kWasmTrapTableOutOfBounds);
}
return *WasmTableObject::Get(isolate, table, entry_index,
WasmTableObject::kWasm);
return *WasmTableObject::Get(isolate, table, entry_index);
}
RUNTIME_FUNCTION(Runtime_WasmFunctionTableSet) {
@ -483,8 +482,7 @@ RUNTIME_FUNCTION(Runtime_WasmFunctionTableSet) {
if (!WasmTableObject::IsInBounds(isolate, table, entry_index)) {
return ThrowWasmError(isolate, MessageTemplate::kWasmTrapTableOutOfBounds);
}
WasmTableObject::Set(isolate, table, entry_index, element,
WasmTableObject::kWasm);
WasmTableObject::Set(isolate, table, entry_index, element);
return ReadOnlyRoots(isolate).undefined_value();
}
@ -548,8 +546,7 @@ RUNTIME_FUNCTION(Runtime_WasmTableGrow) {
Handle<WasmTableObject> table(
WasmTableObject::cast(instance.tables().get(table_index)), isolate);
int result = WasmTableObject::Grow(isolate, table, delta, value,
WasmTableObject::kWasm);
int result = WasmTableObject::Grow(isolate, table, delta, value);
return Smi::FromInt(result);
}

View File

@ -1858,10 +1858,16 @@ auto Global::get() const -> Val {
return Val(v8_global->GetF64());
case i::wasm::kRef:
case i::wasm::kRefNull: {
// TODO(7748): Make sure this works for all heap types.
// TODO(7748): Handle types other than funcref and externref if needed.
StoreImpl* store = impl(this)->store();
i::HandleScope scope(store->i_isolate());
return Val(V8RefValueToWasm(store, v8_global->GetRef()));
i::Handle<i::Object> result = v8_global->GetRef();
if (result->IsWasmInternalFunction()) {
result =
handle(i::Handle<i::WasmInternalFunction>::cast(result)->external(),
v8_global->GetIsolate());
}
return Val(V8RefValueToWasm(store, result));
}
case i::wasm::kRtt:
case i::wasm::kS128:
@ -1887,14 +1893,16 @@ void Global::set(const Val& val) {
case F64:
return v8_global->SetF64(val.f64());
case ANYREF:
return v8_global->SetExternRef(
return v8_global->SetRef(
WasmRefToV8(impl(this)->store()->i_isolate(), val.ref()));
case FUNCREF: {
i::Isolate* isolate = impl(this)->store()->i_isolate();
bool result =
v8_global->SetFuncRef(isolate, WasmRefToV8(isolate, val.ref()));
DCHECK(result);
USE(result);
auto external = WasmRefToV8(impl(this)->store()->i_isolate(), val.ref());
const char* error_message;
auto internal = i::wasm::JSToWasmObject(isolate, nullptr, external,
v8_global->type(), &error_message)
.ToHandleChecked();
v8_global->SetRef(internal);
return;
}
default:
@ -1984,13 +1992,18 @@ auto Table::type() const -> own<TableType> {
return TableType::make(ValType::make(kind), Limits(min, max));
}
// TODO(7748): Handle types other than funcref and externref if needed.
auto Table::get(size_t index) const -> own<Ref> {
i::Handle<i::WasmTableObject> table = impl(this)->v8_object();
if (index >= static_cast<size_t>(table->current_length())) return own<Ref>();
i::Isolate* isolate = table->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> result = i::WasmTableObject::Get(
isolate, table, static_cast<uint32_t>(index), i::WasmTableObject::kJS);
i::Handle<i::Object> result =
i::WasmTableObject::Get(isolate, table, static_cast<uint32_t>(index));
if (result->IsWasmInternalFunction()) {
result = handle(
i::Handle<i::WasmInternalFunction>::cast(result)->external(), isolate);
}
DCHECK(result->IsNull(isolate) || result->IsJSReceiver());
return V8RefValueToWasm(impl(this)->store(), result);
}
@ -2001,9 +2014,13 @@ auto Table::set(size_t index, const Ref* ref) -> bool {
i::Isolate* isolate = table->GetIsolate();
i::HandleScope handle_scope(isolate);
i::Handle<i::Object> obj = WasmRefToV8(isolate, ref);
// TODO(12868): Enforce type restrictions for stringref tables.
i::WasmTableObject::Set(isolate, table, static_cast<uint32_t>(index), obj,
i::WasmTableObject::kJS);
const char* error_message;
i::Handle<i::Object> obj_as_wasm =
i::wasm::JSToWasmObject(isolate, nullptr, obj, table->type(),
&error_message)
.ToHandleChecked();
i::WasmTableObject::Set(isolate, table, static_cast<uint32_t>(index),
obj_as_wasm);
return true;
}
@ -2017,9 +2034,13 @@ auto Table::grow(size_t delta, const Ref* ref) -> bool {
i::Isolate* isolate = table->GetIsolate();
i::HandleScope scope(isolate);
i::Handle<i::Object> obj = WasmRefToV8(isolate, ref);
int result =
i::WasmTableObject::Grow(isolate, table, static_cast<uint32_t>(delta),
obj, i::WasmTableObject::kJS);
const char* error_message;
i::Handle<i::Object> obj_as_wasm =
i::wasm::JSToWasmObject(isolate, nullptr, obj, table->type(),
&error_message)
.ToHandleChecked();
int result = i::WasmTableObject::Grow(
isolate, table, static_cast<uint32_t>(delta), obj_as_wasm);
return result >= 0;
}

View File

@ -1535,25 +1535,14 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
if (global.type.is_reference()) {
const char* error_message;
if (wasm::JSToWasmObject(isolate_, module_, value, global.type,
&error_message)
.is_null()) {
Handle<Object> wasm_value;
if (!wasm::JSToWasmObject(isolate_, module_, value, global.type,
&error_message)
.ToHandle(&wasm_value)) {
ReportLinkError(error_message, global_index, module_name, import_name);
return false;
}
if (IsSubtypeOf(global.type, kWasmFuncRef, module_) && !value->IsNull()) {
value =
WasmInternalFunction::FromExternal(value, isolate_).ToHandleChecked();
} else if (!v8_flags.wasm_gc_js_interop &&
global.type.heap_representation() != HeapType::kExtern &&
!value->IsNull()) {
bool unpacked = TryUnpackObjectWrapper(isolate_, value);
// Excluding SMIs and stringrefs, every value received here, must have
// been wrapped. This is ensured by JSToWasmObject().
DCHECK_EQ(unpacked, !value->IsSmi() && !value->IsString());
USE(unpacked); // Prevent nused warning if DCHECKs disabled.
}
WriteGlobalValue(global, WasmValue(value, global.type));
WriteGlobalValue(global, WasmValue(wasm_value, global.type));
return true;
}
@ -2011,8 +2000,7 @@ void InstanceBuilder::SetTableInitialValues(
for (uint32_t entry_index = 0; entry_index < table.initial_size;
entry_index++) {
WasmTableObject::Set(isolate_, table_object, entry_index,
to_value(result).to_ref(),
WasmTableObject::kWasm);
to_value(result).to_ref());
}
}
}
@ -2061,7 +2049,7 @@ base::Optional<MessageTemplate> LoadElemSegmentImpl(
zone, entry, elem_segment.type, isolate, instance);
if (is_error(result)) return to_error(result);
WasmTableObject::Set(isolate, table_object, entry_index,
to_value(result).to_ref(), WasmTableObject::kWasm);
to_value(result).to_ref());
}
}
return {};

View File

@ -1224,15 +1224,18 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (initial > 0 && args.Length() >= 2 && !args[1]->IsUndefined()) {
i::Handle<i::Object> element = Utils::OpenHandle(*args[1]);
if (!i::WasmTableObject::IsValidJSElement(i_isolate, table_obj, element)) {
const char* error_message;
if (!i::WasmTableObject::JSToWasmElement(i_isolate, table_obj, element,
&error_message)
.ToHandle(&element)) {
thrower.TypeError(
"Argument 2 must be undefined, null, or a value of type compatible "
"with the type of the new table.");
"Argument 2 must be undefined or a value of type compatible "
"with the type of the new table: %s.",
error_message);
return;
}
for (uint32_t index = 0; index < static_cast<uint32_t>(initial); ++index) {
i::WasmTableObject::Set(i_isolate, table_obj, index, element,
i::WasmTableObject::kJS);
i::WasmTableObject::Set(i_isolate, table_obj, index, element);
}
} else if (initial > 0) {
switch (table_obj->type().heap_representation()) {
@ -1439,26 +1442,6 @@ bool ToF64(Local<v8::Value> value, Local<Context> context, double* f64_value) {
}
return true;
}
bool checkAndUnpackAnyRef(i::Isolate* i_isolate,
i::Handle<i::Object>& in_out_value,
i::wasm::ValueType type, ErrorThrower& thrower) {
const char* error_message = nullptr;
auto module = nullptr;
bool valid = !internal::wasm::JSToWasmObject(i_isolate, module, in_out_value,
type, &error_message)
.is_null();
if (!valid) {
DCHECK(error_message != nullptr);
thrower.TypeError("%s", error_message);
return false;
}
if (!internal::v8_flags.wasm_gc_js_interop) {
internal::wasm::TryUnpackObjectWrapper(i_isolate, in_out_value);
}
return true;
}
} // namespace
// WebAssembly.Global
@ -1561,72 +1544,24 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
break;
}
case i::wasm::kRef:
case i::wasm::kRefNull: {
switch (type.heap_representation()) {
case i::wasm::HeapType::kExtern: {
if (args.Length() < 2) {
// When no initial value is provided, we have to use the WebAssembly
// default value 'null', and not the JS default value 'undefined'.
global_obj->SetExternRef(i_isolate->factory()->null_value());
break;
}
global_obj->SetExternRef(Utils::OpenHandle(*value));
break;
}
case i::wasm::HeapType::kFunc: {
if (args.Length() < 2) {
// When no initial value is provided, we have to use the WebAssembly
// default value 'null', and not the JS default value 'undefined'.
global_obj->SetFuncRef(i_isolate,
i_isolate->factory()->null_value());
break;
}
if (!global_obj->SetFuncRef(i_isolate, Utils::OpenHandle(*value))) {
thrower.TypeError(
"The value of funcref globals must be null or an "
"exported function");
}
break;
}
case i::wasm::HeapType::kString: {
if (args.Length() < 2) {
thrower.TypeError(
"Missing initial value when creating stringref global");
break;
}
DCHECK_EQ(type.nullability(), i::wasm::kNullable);
if (!value->IsNull() && !value->IsString()) {
thrower.TypeError(
"The value of stringref globals must be null or a string");
break;
}
global_obj->SetStringRef(Utils::OpenHandle(*value));
break;
}
case internal::wasm::HeapType::kBottom:
UNREACHABLE();
case i::wasm::HeapType::kEq:
case internal::wasm::HeapType::kI31:
case internal::wasm::HeapType::kData:
case internal::wasm::HeapType::kArray:
case internal::wasm::HeapType::kAny: {
internal::Handle<internal::Object> value_handle =
Utils::OpenHandle(*value);
if (checkAndUnpackAnyRef(i_isolate, value_handle, type, thrower)) {
global_obj->SetAnyRef(value_handle);
}
break;
}
case internal::wasm::HeapType::kStringViewWtf8:
case internal::wasm::HeapType::kStringViewWtf16:
case internal::wasm::HeapType::kStringViewIter:
default:
// TODO(7748): Implement these.
UNIMPLEMENTED();
if (args.Length() < 2) {
thrower.TypeError("Non-defaultable global needs initial value");
break;
}
V8_FALLTHROUGH;
case i::wasm::kRefNull: {
// We need the wasm default value {null} over {undefined}.
i::Handle<i::Object> value_handle =
(args.Length() < 2) ? i_isolate->factory()->null_value()
: Utils::OpenHandle(*value);
const char* error_message;
if (!i::wasm::JSToWasmObject(i_isolate, nullptr, value_handle, type,
&error_message)
.ToHandle(&value_handle)) {
thrower.TypeError("%s", error_message);
break;
}
global_obj->SetRef(value_handle);
break;
}
case i::wasm::kRtt:
@ -2270,9 +2205,11 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() >= 2 && !args[1]->IsUndefined()) {
init_value = Utils::OpenHandle(*args[1]);
if (!i::WasmTableObject::IsValidJSElement(i_isolate, receiver,
init_value)) {
thrower.TypeError("Argument 1 must be a valid type for the table");
const char* error_message;
if (!i::WasmTableObject::JSToWasmElement(i_isolate, receiver, init_value,
&error_message)
.ToHandle(&init_value)) {
thrower.TypeError("Argument 1 is invalid: %s", error_message);
return;
}
} else if (receiver->type().is_non_nullable()) {
@ -2283,9 +2220,8 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
init_value = DefaultReferenceValue(i_isolate, receiver->type());
}
int old_size = i::WasmTableObject::Grow(i_isolate, receiver, grow_by,
init_value, i::WasmTableObject::kJS);
int old_size =
i::WasmTableObject::Grow(i_isolate, receiver, grow_by, init_value);
if (old_size < 0) {
thrower.RangeError("failed to grow table by %u", grow_by);
return;
@ -2294,6 +2230,83 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
return_value.Set(old_size);
}
namespace {
void WasmObjectToJSReturnValue(v8::ReturnValue<v8::Value>& return_value,
i::Handle<i::Object> value,
i::wasm::HeapType::Representation repr,
const i::wasm::WasmModule* module,
i::Isolate* isolate,
ScheduledErrorThrower* thrower) {
switch (repr) {
case i::wasm::HeapType::kExtern:
case i::wasm::HeapType::kString:
// TODO(7748): Make sure i31ref is compatible with Smi, or transform here.
case i::wasm::HeapType::kI31:
return_value.Set(Utils::ToLocal(value));
return;
case i::wasm::HeapType::kFunc: {
if (!value->IsNull()) {
DCHECK(value->IsWasmInternalFunction());
value =
handle(i::Handle<i::WasmInternalFunction>::cast(value)->external(),
isolate);
}
return_value.Set(Utils::ToLocal(value));
return;
}
case i::wasm::HeapType::kStringViewWtf8:
thrower->TypeError("stringview_wtf8 has no JS representation");
return;
case i::wasm::HeapType::kStringViewWtf16:
thrower->TypeError("stringview_wtf16 has no JS representation");
return;
case i::wasm::HeapType::kStringViewIter:
thrower->TypeError("stringview_iter has no JS representation");
return;
case i::wasm::HeapType::kBottom:
UNREACHABLE();
case i::wasm::HeapType::kData:
case i::wasm::HeapType::kArray:
case i::wasm::HeapType::kEq:
case i::wasm::HeapType::kAny: {
if (!i::v8_flags.wasm_gc_js_interop && value->IsWasmObject()) {
// Transform wasm object into JS-compliant representation.
i::Handle<i::JSObject> wrapper =
isolate->factory()->NewJSObject(isolate->object_function());
i::JSObject::AddProperty(
isolate, wrapper, isolate->factory()->wasm_wrapped_object_symbol(),
value, i::NONE);
value = wrapper;
}
return_value.Set(Utils::ToLocal(value));
return;
}
default:
if (module->has_signature(repr)) {
if (!value->IsNull()) {
DCHECK(value->IsWasmInternalFunction());
value = handle(
i::Handle<i::WasmInternalFunction>::cast(value)->external(),
isolate);
}
return_value.Set(Utils::ToLocal(value));
return;
}
if (!i::v8_flags.wasm_gc_js_interop && value->IsWasmObject()) {
// Transform wasm object into JS-compliant representation.
i::Handle<i::JSObject> wrapper =
isolate->factory()->NewJSObject(isolate->object_function());
i::JSObject::AddProperty(
isolate, wrapper, isolate->factory()->wasm_wrapped_object_symbol(),
value, i::NONE);
value = wrapper;
}
return_value.Set(Utils::ToLocal(value));
return;
}
}
} // namespace
// WebAssembly.Table.get(num) -> any
void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
@ -2325,11 +2338,17 @@ void WebAssemblyTableGet(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
i::Handle<i::Object> result = i::WasmTableObject::Get(
i_isolate, receiver, index, i::WasmTableObject::kJS);
i::Handle<i::Object> result =
i::WasmTableObject::Get(i_isolate, receiver, index);
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(Utils::ToLocal(result));
const i::wasm::WasmModule* module =
receiver->instance().IsWasmInstanceObject()
? i::WasmInstanceObject::cast(receiver->instance()).module()
: nullptr;
WasmObjectToJSReturnValue(return_value, result,
receiver->type().heap_representation(), module,
i_isolate, &thrower);
}
// WebAssembly.Table.set(num, any)
@ -2351,19 +2370,26 @@ void WebAssemblyTableSet(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
i::Handle<i::Object> element =
args.Length() >= 2
? Utils::OpenHandle(*args[1])
: DefaultReferenceValue(i_isolate, table_object->type());
if (!i::WasmTableObject::IsValidJSElement(i_isolate, table_object, element)) {
thrower.TypeError("Argument 1 is invalid for table of type %s",
i::Handle<i::Object> element;
if (args.Length() >= 2) {
element = Utils::OpenHandle(*args[1]);
} else if (table_object->type().is_defaultable()) {
element = DefaultReferenceValue(i_isolate, table_object->type());
} else {
thrower.TypeError("Table of non-defaultable type %s needs explicit element",
table_object->type().name().c_str());
return;
}
i::WasmTableObject::Set(i_isolate, table_object, index, element,
i::WasmTableObject::kJS);
const char* error_message;
if (!i::WasmTableObject::JSToWasmElement(i_isolate, table_object, element,
&error_message)
.ToHandle(&element)) {
thrower.TypeError("Argument 1 is invalid for table: %s", error_message);
return;
}
i::WasmTableObject::Set(i_isolate, table_object, index, element);
}
// WebAssembly.Table.type() -> TableType
@ -2688,57 +2714,16 @@ void WebAssemblyGlobalGetValueCommon(
thrower.TypeError("Can't get the value of s128 WebAssembly.Global");
break;
case i::wasm::kRef:
case i::wasm::kRefNull:
switch (receiver->type().heap_representation()) {
case i::wasm::HeapType::kExtern:
case i::wasm::HeapType::kString:
return_value.Set(Utils::ToLocal(receiver->GetRef()));
break;
case i::wasm::HeapType::kFunc: {
i::Handle<i::Object> result = receiver->GetRef();
if (result->IsWasmInternalFunction()) {
result = handle(
i::Handle<i::WasmInternalFunction>::cast(result)->external(),
i_isolate);
}
return_value.Set(Utils::ToLocal(result));
break;
}
case i::wasm::HeapType::kStringViewWtf8:
thrower.TypeError("stringview_wtf8 has no JS representation");
break;
case i::wasm::HeapType::kStringViewWtf16:
thrower.TypeError("stringview_wtf16 has no JS representation");
break;
case i::wasm::HeapType::kStringViewIter:
thrower.TypeError("stringview_iter has no JS representation");
break;
case i::wasm::HeapType::kBottom:
UNREACHABLE();
case i::wasm::HeapType::kI31:
case i::wasm::HeapType::kData:
case i::wasm::HeapType::kArray:
case i::wasm::HeapType::kEq:
case i::wasm::HeapType::kAny: {
i::Handle<i::Object> result = receiver->GetRef();
if (!i::v8_flags.wasm_gc_js_interop && result->IsWasmObject()) {
// Transform wasm object into JS-compliant representation.
i::Handle<i::JSObject> wrapper =
i_isolate->factory()->NewJSObject(i_isolate->object_function());
i::JSObject::AddProperty(
i_isolate, wrapper,
i_isolate->factory()->wasm_wrapped_object_symbol(), result,
i::NONE);
result = wrapper;
}
return_value.Set(Utils::ToLocal(result));
break;
}
default:
// TODO(7748): Implement these.
UNIMPLEMENTED();
}
case i::wasm::kRefNull: {
const i::wasm::WasmModule* module =
receiver->instance().IsWasmInstanceObject()
? i::WasmInstanceObject::cast(receiver->instance()).module()
: nullptr;
WasmObjectToJSReturnValue(return_value, receiver->GetRef(),
receiver->type().heap_representation(), module,
i_isolate, &thrower);
break;
}
case i::wasm::kRtt:
UNIMPLEMENTED(); // TODO(7748): Implement.
case i::wasm::kI8:
@ -2808,70 +2793,23 @@ void WebAssemblyGlobalSetValue(
thrower.TypeError("Can't set the value of s128 WebAssembly.Global");
break;
case i::wasm::kRef:
case i::wasm::kRefNull:
switch (receiver->type().heap_representation()) {
case i::wasm::HeapType::kExtern:
receiver->SetExternRef(Utils::OpenHandle(*args[0]));
break;
case i::wasm::HeapType::kFunc: {
if (!receiver->SetFuncRef(i_isolate, Utils::OpenHandle(*args[0]))) {
thrower.TypeError(
"value of an funcref reference must be either null or an "
"exported function");
}
break;
}
case i::wasm::HeapType::kString: {
if (!args[0]->IsString()) {
if (args[0]->IsNull()) {
if (receiver->type().nullability() == i::wasm::kNonNullable) {
thrower.TypeError(
"Can't set non-nullable stringref global to null");
break;
}
} else {
thrower.TypeError(
receiver->type().nullability() == i::wasm::kNonNullable
? "Non-nullable stringref global can only hold a string"
: "Stringref global can only hold null or a string");
break;
}
}
receiver->SetStringRef(Utils::OpenHandle(*args[0]));
break;
}
case i::wasm::HeapType::kStringViewWtf8:
thrower.TypeError("stringview_wtf8 has no JS representation");
break;
case i::wasm::HeapType::kStringViewWtf16:
thrower.TypeError("stringview_wtf16 has no JS representation");
break;
case i::wasm::HeapType::kStringViewIter:
thrower.TypeError("stringview_iter has no JS representation");
break;
case i::wasm::HeapType::kBottom:
UNREACHABLE();
case i::wasm::HeapType::kI31:
case i::wasm::HeapType::kData:
case i::wasm::HeapType::kArray:
case i::wasm::HeapType::kEq:
case i::wasm::HeapType::kAny: {
internal::Handle<internal::Object> value_handle =
Utils::OpenHandle(*args[0]);
if (checkAndUnpackAnyRef(i_isolate, value_handle, receiver->type(),
thrower)) {
receiver->SetAnyRef(value_handle);
}
break;
}
default:
// TODO(7748): Implement these.
UNIMPLEMENTED();
case i::wasm::kRefNull: {
const i::wasm::WasmModule* module =
receiver->instance().IsWasmInstanceObject()
? i::WasmInstanceObject::cast(receiver->instance()).module()
: nullptr;
i::Handle<i::Object> value = Utils::OpenHandle(*args[0]);
const char* error_message;
if (!i::wasm::JSToWasmObject(i_isolate, module, value, receiver->type(),
&error_message)
.ToHandle(&value)) {
thrower.TypeError("%s", error_message);
return;
}
break;
receiver->SetRef(value);
return;
}
case i::wasm::kRtt:
// TODO(7748): Implement.
UNIMPLEMENTED();
case i::wasm::kI8:
case i::wasm::kI16:
case i::wasm::kBottom:

View File

@ -166,33 +166,8 @@ void WasmGlobalObject::SetF64(double value) {
base::WriteUnalignedValue(address(), value);
}
void WasmGlobalObject::SetExternRef(Handle<Object> value) {
DCHECK(type().is_reference_to(wasm::HeapType::kExtern));
tagged_buffer().set(offset(), *value);
}
void WasmGlobalObject::SetAnyRef(Handle<Object> value) {
DCHECK(type().is_reference_to(wasm::HeapType::kAny) ||
type().is_reference_to(wasm::HeapType::kEq) ||
type().is_reference_to(wasm::HeapType::kData) ||
type().is_reference_to(wasm::HeapType::kArray) ||
type().is_reference_to(wasm::HeapType::kI31));
tagged_buffer().set(offset(), *value);
}
bool WasmGlobalObject::SetFuncRef(Isolate* isolate, Handle<Object> value) {
DCHECK_EQ(type(), wasm::kWasmFuncRef);
if (value->IsNull() ||
WasmInternalFunction::FromExternal(value, isolate).ToHandle(&value)) {
tagged_buffer().set(offset(), *value);
return true;
}
return false;
}
void WasmGlobalObject::SetStringRef(Handle<Object> value) {
DCHECK_EQ(type(), wasm::kWasmStringRef);
DCHECK(value->IsNull() || value->IsString());
void WasmGlobalObject::SetRef(Handle<Object> value) {
DCHECK(type().is_object_reference());
tagged_buffer().set(offset(), *value);
}

View File

@ -207,8 +207,7 @@ void WasmTableObject::AddDispatchTable(Isolate* isolate,
}
int WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
uint32_t count, Handle<Object> init_value,
ValueRepr entry_repr) {
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.
@ -260,49 +259,8 @@ int WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
instance, table_index, new_size);
}
// Instead of passing through the representation, perform an eager
// internalization of the value to avoid repeating it for every entry.
if (entry_repr == ValueRepr::kJS && !init_value->IsNull()) {
switch (table->type().heap_representation()) {
case wasm::HeapType::kExtern:
case wasm::HeapType::kString:
case wasm::HeapType::kStringViewWtf8:
case wasm::HeapType::kStringViewWtf16:
case wasm::HeapType::kStringViewIter:
break;
case wasm::HeapType::kFunc:
init_value = i::WasmInternalFunction::FromExternal(init_value, isolate)
.ToHandleChecked();
break;
case wasm::HeapType::kEq:
case wasm::HeapType::kData:
case wasm::HeapType::kArray:
case wasm::HeapType::kAny:
case wasm::HeapType::kI31:
if (!v8_flags.wasm_gc_js_interop && entry_repr == ValueRepr::kJS) {
wasm::TryUnpackObjectWrapper(isolate, init_value);
}
break;
case wasm::HeapType::kBottom:
UNREACHABLE();
default:
DCHECK(!table->instance().IsUndefined());
const bool kIsFunc = WasmInstanceObject::cast(table->instance())
.module()
->has_signature(table->type().ref_index());
if (kIsFunc) {
init_value =
i::WasmInternalFunction::FromExternal(init_value, isolate)
.ToHandleChecked();
} else if (!i::FLAG_wasm_gc_js_interop &&
entry_repr == ValueRepr::kJS) {
i::wasm::TryUnpackObjectWrapper(isolate, init_value);
}
}
}
for (uint32_t entry = old_size; entry < new_size; ++entry) {
WasmTableObject::Set(isolate, table, entry, init_value, ValueRepr::kWasm);
WasmTableObject::Set(isolate, table, entry, init_value);
}
return old_size;
}
@ -313,36 +271,31 @@ bool WasmTableObject::IsInBounds(Isolate* isolate,
return entry_index < static_cast<uint32_t>(table->current_length());
}
bool WasmTableObject::IsValidJSElement(Isolate* isolate,
Handle<WasmTableObject> table,
Handle<Object> entry) {
MaybeHandle<Object> WasmTableObject::JSToWasmElement(
Isolate* isolate, Handle<WasmTableObject> table, Handle<Object> entry,
const char** error_message) {
// Any `entry` has to be in its JS representation.
DCHECK(!entry->IsWasmInternalFunction());
DCHECK_IMPLIES(!v8_flags.wasm_gc_js_interop,
!entry->IsWasmArray() && !entry->IsWasmStruct());
const char* error_message;
const WasmModule* module =
!table->instance().IsUndefined()
? WasmInstanceObject::cast(table->instance()).module()
: nullptr;
return !wasm::JSToWasmObject(isolate, module, entry, table->type(),
&error_message)
.is_null();
return wasm::JSToWasmObject(isolate, module, entry, table->type(),
error_message);
}
void WasmTableObject::SetFunctionTableEntry(
Isolate* isolate, Handle<WasmTableObject> table, Handle<FixedArray> entries,
int entry_index, Handle<Object> entry, ValueRepr entry_repr) {
void WasmTableObject::SetFunctionTableEntry(Isolate* isolate,
Handle<WasmTableObject> table,
Handle<FixedArray> entries,
int entry_index,
Handle<Object> entry) {
if (entry->IsNull(isolate)) {
ClearDispatchTables(isolate, table, entry_index); // Degenerate case.
entries->set(entry_index, ReadOnlyRoots(isolate).null_value());
return;
}
if (entry_repr == ValueRepr::kJS) {
entry =
i::WasmInternalFunction::FromExternal(entry, isolate).ToHandleChecked();
}
Handle<Object> external =
handle(Handle<WasmInternalFunction>::cast(entry)->external(), isolate);
@ -366,12 +319,9 @@ void WasmTableObject::SetFunctionTableEntry(
}
void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
uint32_t index, Handle<Object> entry,
ValueRepr entry_repr) {
uint32_t index, Handle<Object> entry) {
// Callers need to perform bounds checks, type check, and error handling.
DCHECK(IsInBounds(isolate, table, index));
DCHECK_IMPLIES(entry_repr == WasmTableObject::kJS,
IsValidJSElement(isolate, table, entry));
Handle<FixedArray> entries(table->entries(), isolate);
// The FixedArray is addressed with int's.
@ -383,22 +333,16 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
case wasm::HeapType::kStringViewWtf8:
case wasm::HeapType::kStringViewWtf16:
case wasm::HeapType::kStringViewIter:
entries->set(entry_index, *entry);
return;
case wasm::HeapType::kFunc:
SetFunctionTableEntry(isolate, table, entries, entry_index, entry,
entry_repr);
return;
case wasm::HeapType::kEq:
case wasm::HeapType::kData:
case wasm::HeapType::kArray:
case wasm::HeapType::kAny:
case wasm::HeapType::kI31:
if (!v8_flags.wasm_gc_js_interop && entry_repr == ValueRepr::kJS) {
wasm::TryUnpackObjectWrapper(isolate, entry);
}
entries->set(entry_index, *entry);
return;
case wasm::HeapType::kFunc:
SetFunctionTableEntry(isolate, table, entries, entry_index, entry);
return;
case wasm::HeapType::kBottom:
UNREACHABLE();
default:
@ -406,14 +350,9 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
if (WasmInstanceObject::cast(table->instance())
.module()
->has_signature(table->type().ref_index())) {
SetFunctionTableEntry(isolate, table, entries, entry_index, entry,
entry_repr);
SetFunctionTableEntry(isolate, table, entries, entry_index, entry);
return;
}
// Indexed struct and array types.
if (!i::FLAG_wasm_gc_js_interop && entry_repr == ValueRepr::kJS) {
i::wasm::TryUnpackObjectWrapper(isolate, entry);
}
entries->set(entry_index, *entry);
return;
}
@ -421,7 +360,7 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
Handle<Object> WasmTableObject::Get(Isolate* isolate,
Handle<WasmTableObject> table,
uint32_t index, ValueRepr as_repr) {
uint32_t index) {
Handle<FixedArray> entries(table->entries(), isolate);
// Callers need to perform bounds checks and error handling.
DCHECK(IsInBounds(isolate, table, index));
@ -439,35 +378,16 @@ Handle<Object> WasmTableObject::Get(Isolate* isolate,
case wasm::HeapType::kStringViewWtf8:
case wasm::HeapType::kStringViewWtf16:
case wasm::HeapType::kStringViewIter:
DCHECK(as_repr != ValueRepr::kJS); // No representation in JavaScript.
return entry;
case wasm::HeapType::kExtern:
case wasm::HeapType::kString:
return entry;
case wasm::HeapType::kEq:
case wasm::HeapType::kI31:
case wasm::HeapType::kData:
case wasm::HeapType::kArray:
case wasm::HeapType::kAny:
if (as_repr == ValueRepr::kJS && !v8_flags.wasm_gc_js_interop &&
entry->IsWasmObject()) {
// Transform wasm object into JS-compliant representation.
Handle<JSObject> wrapper =
isolate->factory()->NewJSObject(isolate->object_function());
JSObject::AddProperty(isolate, wrapper,
isolate->factory()->wasm_wrapped_object_symbol(),
entry, NONE);
return wrapper;
}
return entry;
case wasm::HeapType::kFunc:
if (entry->IsWasmInternalFunction()) {
return as_repr == ValueRepr::kJS
? handle(
Handle<WasmInternalFunction>::cast(entry)->external(),
isolate)
: entry;
}
if (entry->IsWasmInternalFunction()) return entry;
break;
case wasm::HeapType::kBottom:
UNREACHABLE();
@ -477,26 +397,10 @@ Handle<Object> WasmTableObject::Get(Isolate* isolate,
WasmInstanceObject::cast(table->instance()).module();
if (module->has_array(table->type().ref_index()) ||
module->has_struct(table->type().ref_index())) {
if (as_repr == ValueRepr::kJS && !FLAG_wasm_gc_js_interop &&
!entry->IsNull()) {
// Transform wasm object into JS-compliant representation.
Handle<JSObject> wrapper =
isolate->factory()->NewJSObject(isolate->object_function());
JSObject::AddProperty(
isolate, wrapper,
isolate->factory()->wasm_wrapped_object_symbol(), entry, NONE);
return wrapper;
}
return entry;
}
DCHECK(module->has_signature(table->type().ref_index()));
if (entry->IsWasmInternalFunction()) {
return as_repr == ValueRepr::kJS
? handle(
Handle<WasmInternalFunction>::cast(entry)->external(),
isolate)
: entry;
}
if (entry->IsWasmInternalFunction()) return entry;
break;
}
@ -512,8 +416,7 @@ Handle<Object> WasmTableObject::Get(Isolate* isolate,
WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate, instance,
function_index);
entries->set(entry_index, *internal);
return as_repr == ValueRepr::kJS ? handle(internal->external(), isolate)
: internal;
return internal;
}
void WasmTableObject::Fill(Isolate* isolate, Handle<WasmTableObject> table,
@ -525,7 +428,7 @@ void WasmTableObject::Fill(Isolate* isolate, Handle<WasmTableObject> table,
DCHECK_LE(start + count, table->current_length());
for (uint32_t i = 0; i < count; i++) {
WasmTableObject::Set(isolate, table, start + i, entry, ValueRepr::kWasm);
WasmTableObject::Set(isolate, table, start + i, entry);
}
}
@ -1431,10 +1334,8 @@ bool WasmInstanceObject::CopyTableEntries(Isolate* isolate,
for (uint32_t i = 0; i < count; ++i) {
uint32_t src_index = copy_backward ? (src + count - i - 1) : src + i;
uint32_t dst_index = copy_backward ? (dst + count - i - 1) : dst + i;
auto repr =
WasmTableObject::kWasm; // Do not externalize / internalize values.
auto value = WasmTableObject::Get(isolate, table_src, src_index, repr);
WasmTableObject::Set(isolate, table_dst, dst_index, value, repr);
auto value = WasmTableObject::Get(isolate, table_src, src_index);
WasmTableObject::Set(isolate, table_dst, dst_index, value);
}
return true;
}
@ -2335,8 +2236,10 @@ Handle<AsmWasmData> AsmWasmData::New(
return result;
}
namespace wasm {
namespace {
// If {in_out_value} is a wrapped wasm struct/array, it gets unwrapped in-place
// and this returns {true}. Otherwise, the value remains unchanged and this
// returns {false}.
bool TryUnpackObjectWrapper(Isolate* isolate, Handle<Object>& in_out_value) {
if (in_out_value->IsUndefined(isolate) || in_out_value->IsNull(isolate) ||
!in_out_value->IsJSObject()) {
@ -2349,7 +2252,9 @@ bool TryUnpackObjectWrapper(Isolate* isolate, Handle<Object>& in_out_value) {
in_out_value = it.GetDataValue();
return true;
}
} // namespace
namespace wasm {
MaybeHandle<Object> JSToWasmObject(Isolate* isolate, const WasmModule* module,
Handle<Object> value, ValueType expected,
const char** error_message) {
@ -2376,7 +2281,8 @@ MaybeHandle<Object> JSToWasmObject(Isolate* isolate, const WasmModule* module,
case kRef: {
// TODO(7748): Follow any changes in proposed JS API. In particular,
// finalize the v8_flags.wasm_gc_js_interop situation.
// TODO(7748): Allow all in-range numbers for i31.
// TODO(7748): Allow all in-range numbers for i31. Make sure to convert
// Smis to i31refs if needed.
// TODO(7748): Streamline interaction of undefined and (ref any).
HeapType::Representation repr = expected.heap_representation();
switch (repr) {

View File

@ -176,12 +176,9 @@ class WasmTableObject
public:
inline wasm::ValueType type();
enum ValueRepr { kJS, kWasm };
V8_EXPORT_PRIVATE static int Grow(Isolate* isolate,
Handle<WasmTableObject> table,
uint32_t count, Handle<Object> init_value,
ValueRepr entry_repr);
uint32_t count, Handle<Object> init_value);
V8_EXPORT_PRIVATE static Handle<WasmTableObject> New(
Isolate* isolate, Handle<WasmInstanceObject> instance,
@ -196,18 +193,21 @@ class WasmTableObject
static bool IsInBounds(Isolate* isolate, Handle<WasmTableObject> table,
uint32_t entry_index);
static bool IsValidJSElement(Isolate* isolate, Handle<WasmTableObject> table,
Handle<Object> entry);
// Thin wrapper around {JsToWasmObject}.
static MaybeHandle<Object> JSToWasmElement(Isolate* isolate,
Handle<WasmTableObject> table,
Handle<Object> entry,
const char** error_message);
// This function will not handle JS objects; i.e., {entry} needs to be in wasm
// representation.
V8_EXPORT_PRIVATE static void Set(Isolate* isolate,
Handle<WasmTableObject> table,
uint32_t index, Handle<Object> entry,
ValueRepr entry_repr);
uint32_t index, Handle<Object> entry);
V8_EXPORT_PRIVATE static Handle<Object> Get(Isolate* isolate,
Handle<WasmTableObject> table,
uint32_t index,
ValueRepr as_repr);
uint32_t index);
V8_EXPORT_PRIVATE static void Fill(Isolate* isolate,
Handle<WasmTableObject> table,
@ -249,7 +249,7 @@ class WasmTableObject
static void SetFunctionTableEntry(Isolate* isolate,
Handle<WasmTableObject> table,
Handle<FixedArray> entries, int entry_index,
Handle<Object> entry, ValueRepr entry_repr);
Handle<Object> entry);
TQ_OBJECT_CONSTRUCTORS(WasmTableObject)
};
@ -314,10 +314,8 @@ class WasmGlobalObject
inline void SetI64(int64_t value);
inline void SetF32(float value);
inline void SetF64(double value);
inline void SetExternRef(Handle<Object> value);
inline void SetAnyRef(Handle<Object> value);
inline bool SetFuncRef(Isolate* isolate, Handle<Object> value);
inline void SetStringRef(Handle<Object> value);
// {value} must be an object in Wasm representation.
inline void SetRef(Handle<Object> value);
private:
// This function returns the address of the global's data in the
@ -1075,11 +1073,6 @@ namespace wasm {
MaybeHandle<Object> JSToWasmObject(Isolate* isolate, const WasmModule* module,
Handle<Object> value, ValueType expected,
const char** error_message);
// If {in_out_value} is a wrapped wasm struct/array, it gets unwrapped in-place
// and this returns {true}. Otherwise, the value remains unchanged and this
// returns {false}.
bool TryUnpackObjectWrapper(Isolate* isolate, Handle<Object>& in_out_value);
} // namespace wasm
} // namespace internal

View File

@ -377,8 +377,7 @@ void CheckTable(Isolate* isolate, Handle<WasmTableObject> table, Args... args) {
CHECK_EQ(table->current_length(), args_length);
Handle<Object> handles[] = {args...};
for (uint32_t i = 0; i < args_length; ++i) {
CHECK(WasmTableObject::Get(isolate, table, i, WasmTableObject::kWasm)
.is_identical_to(handles[i]));
CHECK(WasmTableObject::Get(isolate, table, i).is_identical_to(handles[i]));
}
}
@ -573,11 +572,11 @@ void TestTableCopyElems(TestExecutionTier execution_tier, int table_dst,
r.builder().instance_object()->tables().get(table_dst)),
isolate);
r.CheckCallViaJS(0, 0, 0, kTableSize);
auto f0 = WasmTableObject::Get(isolate, table, 0, WasmTableObject::kWasm);
auto f1 = WasmTableObject::Get(isolate, table, 1, WasmTableObject::kWasm);
auto f2 = WasmTableObject::Get(isolate, table, 2, WasmTableObject::kWasm);
auto f3 = WasmTableObject::Get(isolate, table, 3, WasmTableObject::kWasm);
auto f4 = WasmTableObject::Get(isolate, table, 4, WasmTableObject::kWasm);
auto f0 = WasmTableObject::Get(isolate, table, 0);
auto f1 = WasmTableObject::Get(isolate, table, 1);
auto f2 = WasmTableObject::Get(isolate, table, 2);
auto f3 = WasmTableObject::Get(isolate, table, 3);
auto f4 = WasmTableObject::Get(isolate, table, 4);
if (table_dst == table_src) {
CheckTable(isolate, table, f0, f1, f2, f3, f4);
@ -723,11 +722,11 @@ void TestTableCopyOobWrites(TestExecutionTier execution_tier, int table_dst,
isolate);
// Fill the dst table with values from the src table, to make checks easier.
r.CheckCallViaJS(0, 0, 0, kTableSize);
auto f0 = WasmTableObject::Get(isolate, table, 0, WasmTableObject::kWasm);
auto f1 = WasmTableObject::Get(isolate, table, 1, WasmTableObject::kWasm);
auto f2 = WasmTableObject::Get(isolate, table, 2, WasmTableObject::kWasm);
auto f3 = WasmTableObject::Get(isolate, table, 3, WasmTableObject::kWasm);
auto f4 = WasmTableObject::Get(isolate, table, 4, WasmTableObject::kWasm);
auto f0 = WasmTableObject::Get(isolate, table, 0);
auto f1 = WasmTableObject::Get(isolate, table, 1);
auto f2 = WasmTableObject::Get(isolate, table, 2);
auto f3 = WasmTableObject::Get(isolate, table, 3);
auto f4 = WasmTableObject::Get(isolate, table, 4);
CheckTable(isolate, table, f0, f1, f2, f3, f4);

View File

@ -336,8 +336,8 @@ TEST(WrapperReplacement_IndirectExport) {
Handle<WasmTableObject> table(
WasmTableObject::cast(instance->tables().get(table_index)), isolate);
// Get the Wasm function through the exported table.
Handle<Object> function = WasmTableObject::Get(
isolate, table, function_index, WasmTableObject::kWasm);
Handle<Object> function =
WasmTableObject::Get(isolate, table, function_index);
Handle<WasmExportedFunction> indirect_function(
WasmExportedFunction::cast(
WasmInternalFunction::cast(*function).external()),

View File

@ -1942,8 +1942,7 @@ class WasmInterpreterInternals {
isolate_);
auto delta = Pop().to<uint32_t>();
auto value = Pop().to_ref();
int32_t result = WasmTableObject::Grow(isolate_, table, delta, value,
WasmTableObject::kWasm);
int32_t result = WasmTableObject::Grow(isolate_, table, delta, value);
Push(WasmValue(result));
*len += imm.length;
return true;
@ -3703,8 +3702,8 @@ class WasmInterpreterInternals {
if (entry_index >= table_size) {
return DoTrap(kTrapTableOutOfBounds, pc);
}
Handle<Object> value = WasmTableObject::Get(
isolate_, table, entry_index, WasmTableObject::kWasm);
Handle<Object> value =
WasmTableObject::Get(isolate_, table, entry_index);
Push(WasmValue(value, table->type()));
len = 1 + imm.length;
break;
@ -3722,8 +3721,7 @@ class WasmInterpreterInternals {
if (entry_index >= table_size) {
return DoTrap(kTrapTableOutOfBounds, pc);
}
WasmTableObject::Set(isolate_, table, entry_index, value,
WasmTableObject::kWasm);
WasmTableObject::Set(isolate_, table, entry_index, value);
len = 1 + imm.length;
break;
}

View File

@ -715,18 +715,19 @@ assertThrows(
/must be convertible to a valid number/);
assertThrows(
() => set.call(tbl1, 0, undefined), TypeError,
/Argument 1 is invalid for table of type funcref/);
/Argument 1 is invalid for table: /);
assertThrows(
() => set.call(tbl1, undefined, undefined), TypeError,
/must be convertible to a valid number/);
assertThrows(
() => set.call(tbl1, 0, {}), TypeError,
/Argument 1 is invalid for table of type funcref/);
assertThrows(() => set.call(tbl1, 0, function() {}),
TypeError, /Argument 1 is invalid for table of type funcref/);
/Argument 1 is invalid for table:.*null.*or a Wasm function object/);
assertThrows(
() => set.call(tbl1, 0, function() {}), TypeError,
/Argument 1 is invalid for table:.*null.*or a Wasm function object/);
assertThrows(
() => set.call(tbl1, 0, Math.sin), TypeError,
/Argument 1 is invalid for table of type funcref/);
/Argument 1 is invalid for table:.*null.*or a Wasm function object/);
assertThrows(
() => set.call(tbl1, {valueOf() { throw Error('hai') }}, null), Error,
'hai');

View File

@ -99,7 +99,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
assertThrows(
() => instance.exports.table.set(0, exporting_instance.exports.addition),
TypeError,
/Argument 1 is invalid for table of type \(ref null 0\)/);
/Argument 1 is invalid for table: assigned exported function has to be a subtype of the expected type/);
})();
(function TestNonNullableTables() {

View File

@ -197,10 +197,10 @@ function assertInvalid(fn, message) {
TypeError, msg);
}
assertThrows(()=>new WebAssembly.Global({ value: 'stringref' }),
TypeError,
"WebAssembly.Global(): " +
"Missing initial value when creating stringref global");
// String with default initializer.
// TODO(12868): Is this the intended behavior?
let null_str = new WebAssembly.Global({ value: 'stringref' });
assertEquals(null, null_str.value);
let kSig_w_v = makeSig([], [kWasmStringRef]);
let kSig_v_w = makeSig([kWasmStringRef], []);
@ -302,8 +302,8 @@ function assertInvalid(fn, message) {
let unsupportedGetMessage =
`WebAssembly.Table.get(): ${type} has no JS representation`;
let unsupportedSetMessage =
'WebAssembly.Table.set(): Argument 1 is invalid for table of type '
+ `${type}ref`;
'WebAssembly.Table.set(): Argument 1 is invalid for table: '
+ `${type} has no JS representation`;
assertThrows(()=>table.get(0), TypeError, unsupportedGetMessage);
assertThrows(()=>{table.set(0, null);}, TypeError, unsupportedSetMessage);
}