Commit 71a2887f authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm-gc] Change signature/name of TypeCheckJSObject

Rename {TypeCheckJSObject} to {JSToWasmObject}. Change it to return
a MaybeHandle containing the typechecked object transformed to its wasm representation. Use the new function to simplify
{WasmWrapperGraphBuilder::FromJS}.

Bug: v8:7748
Change-Id: I036f3a1c197041d0b12e7338adca2bc10e66038b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3874931
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarMatthias Liedtke <mliedtke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83002}
parent 4c1236c1
...@@ -6365,7 +6365,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6365,7 +6365,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
case wasm::kVoid: case wasm::kVoid:
case wasm::kBottom: case wasm::kBottom:
// If this is reached, then IsJSCompatibleSignature() is too permissive. // If this is reached, then IsJSCompatibleSignature() is too permissive.
// TODO(7748): Figure out what to do for RTTs.
UNREACHABLE(); UNREACHABLE();
} }
} }
...@@ -6383,50 +6382,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6383,50 +6382,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
kUnwrapWasmExternalFunctions = true, kUnwrapWasmExternalFunctions = true,
kLeaveFunctionsAlone = false kLeaveFunctionsAlone = false
}; };
// Assumes {input} has been checked for validity against the target wasm type.
// If {input} is a function, returns the WasmInternalFunction associated with
// it. If {input} has the {wasm_wrapped_object_symbol} property, returns the
// value of that property. Otherwise, returns {input}.
Node* BuildUnpackObjectWrapper(
Node* input, Node* context,
UnwrapExternalFunctions unwrap_wasm_external_functions) {
auto end = gasm_->MakeLabel(MachineRepresentation::kTaggedPointer);
if (unwrap_wasm_external_functions) {
auto not_a_function = gasm_->MakeLabel();
gasm_->GotoIf(IsSmi(input), &not_a_function);
gasm_->GotoIfNot(gasm_->HasInstanceType(input, JS_FUNCTION_TYPE),
&not_a_function);
Node* function_data = gasm_->LoadFunctionDataFromJSFunction(input);
// Due to type checking, {function_data} will be a WasmFunctionData.
Node* internal = gasm_->LoadFromObject(
MachineType::TaggedPointer(), function_data,
wasm::ObjectAccess::ToTagged(WasmFunctionData::kInternalOffset));
gasm_->Goto(&end, internal);
gasm_->Bind(&not_a_function);
}
if (!v8_flags.wasm_gc_js_interop) {
Node* obj = gasm_->CallBuiltin(
Builtin::kWasmGetOwnProperty, Operator::kEliminatable, input,
LOAD_ROOT(wasm_wrapped_object_symbol, wasm_wrapped_object_symbol),
context);
// Invalid object wrappers (i.e. any other JS object that doesn't have the
// magic hidden property) will return {undefined}. Map that to {input}.
Node* is_undefined = gasm_->TaggedEqual(obj, UndefinedValue());
gasm_->GotoIf(is_undefined, &end, input);
gasm_->Goto(&end, obj);
} else {
gasm_->Goto(&end, input);
}
gasm_->Bind(&end);
return end.PhiAt(0);
}
Node* BuildChangeInt64ToBigInt(Node* input) { Node* BuildChangeInt64ToBigInt(Node* input) {
Node* target; Node* target;
...@@ -6465,34 +6420,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6465,34 +6420,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
target, input, context); target, input, context);
} }
enum class I31Check : bool { Invalid, Valid };
void BuildCheckValidRefValue(Node* input, Node* js_context,
wasm::ValueType type, I31Check i31_check) {
// Make sure ValueType fits in a Smi.
static_assert(wasm::ValueType::kLastUsedBit + 1 <= kSmiValueSize);
auto done = gasm_->MakeLabel();
// The instance node is always defined: if an instance is not available, it
// is the undefined value.
Node* inputs[] = {GetInstance(), input,
mcgraph()->IntPtrConstant(
IntToSmi(static_cast<int>(type.raw_bit_field())))};
Node* check = gasm_->BuildChangeSmiToInt32(BuildCallToRuntimeWithContext(
Runtime::kWasmIsValidRefValue, js_context, inputs, 3));
gasm_->GotoIf(check, &done, BranchHint::kTrue);
if (i31_check == I31Check::Valid) {
Node* is_smi = IsSmi(input);
gasm_->GotoIf(is_smi, &done, BranchHint::kTrue);
}
BuildCallToRuntimeWithContext(Runtime::kWasmThrowJSTypeError, js_context,
nullptr, 0);
gasm_->Goto(&done);
gasm_->Bind(&done);
}
Node* BuildCheckString(Node* input, Node* js_context, wasm::ValueType type) { Node* BuildCheckString(Node* input, Node* js_context, wasm::ValueType type) {
auto done = gasm_->MakeLabel(MachineRepresentation::kTagged); auto done = gasm_->MakeLabel(MachineRepresentation::kTagged);
auto type_error = gasm_->MakeLabel(); auto type_error = gasm_->MakeLabel();
...@@ -6518,27 +6445,10 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6518,27 +6445,10 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
case wasm::kRef: case wasm::kRef:
case wasm::kRefNull: { case wasm::kRefNull: {
switch (type.heap_representation()) { switch (type.heap_representation()) {
// Fast paths for extern and string.
// TODO(7748): Add more/all fast paths?
case wasm::HeapType::kExtern: case wasm::HeapType::kExtern:
return input; return input;
case wasm::HeapType::kFunc:
BuildCheckValidRefValue(input, js_context, type, I31Check::Invalid);
return BuildUnpackObjectWrapper(input, js_context,
kUnwrapWasmExternalFunctions);
case wasm::HeapType::kData:
case wasm::HeapType::kArray:
// TODO(7748): Update this when JS interop has settled.
BuildCheckValidRefValue(input, js_context, type, I31Check::Invalid);
// This will just return {input} if the object is not wrapped, i.e.
// if it is null (given the check just above).
return BuildUnpackObjectWrapper(input, js_context,
kLeaveFunctionsAlone);
case wasm::HeapType::kEq:
// TODO(7748): Update this when JS interop has settled.
BuildCheckValidRefValue(input, js_context, type, I31Check::Valid);
// This will just return {input} if the object is not wrapped, i.e.
// if it is null (given the check just above).
return BuildUnpackObjectWrapper(input, js_context,
kLeaveFunctionsAlone);
case wasm::HeapType::kString: case wasm::HeapType::kString:
return BuildCheckString(input, js_context, type); return BuildCheckString(input, js_context, type);
case wasm::HeapType::kNone: case wasm::HeapType::kNone:
...@@ -6547,16 +6457,23 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6547,16 +6457,23 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
case wasm::HeapType::kAny: case wasm::HeapType::kAny:
case wasm::HeapType::kI31: case wasm::HeapType::kI31:
UNREACHABLE(); UNREACHABLE();
default: case wasm::HeapType::kFunc:
if (module_->has_signature(type.ref_index())) { case wasm::HeapType::kData:
BuildCheckValidRefValue(input, js_context, type, case wasm::HeapType::kArray:
I31Check::Invalid); case wasm::HeapType::kEq:
return BuildUnpackObjectWrapper(input, js_context, default: {
kUnwrapWasmExternalFunctions); // Make sure ValueType fits in a Smi.
static_assert(wasm::ValueType::kLastUsedBit + 1 <= kSmiValueSize);
// The instance node is always defined: if an instance is not
// available, it is the undefined value.
Node* inputs[] = {GetInstance(), input,
mcgraph()->IntPtrConstant(IntToSmi(
static_cast<int>(type.raw_bit_field())))};
return BuildCallToRuntimeWithContext(Runtime::kWasmJSToWasmObject,
js_context, inputs, 3);
} }
// If this is reached, then IsJSCompatibleSignature() is too
// permissive.
UNREACHABLE();
} }
} }
case wasm::kF32: case wasm::kF32:
...@@ -6580,7 +6497,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder { ...@@ -6580,7 +6497,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
case wasm::kBottom: case wasm::kBottom:
case wasm::kVoid: case wasm::kVoid:
// If this is reached, then IsJSCompatibleSignature() is too permissive. // If this is reached, then IsJSCompatibleSignature() is too permissive.
// TODO(7748): Figure out what to do for RTTs.
UNREACHABLE(); UNREACHABLE();
} }
} }
......
...@@ -709,6 +709,10 @@ bool SharedFunctionInfo::HasAsmWasmData() const { ...@@ -709,6 +709,10 @@ bool SharedFunctionInfo::HasAsmWasmData() const {
return function_data(kAcquireLoad).IsAsmWasmData(); return function_data(kAcquireLoad).IsAsmWasmData();
} }
bool SharedFunctionInfo::HasWasmFunctionData() const {
return function_data(kAcquireLoad).IsWasmFunctionData();
}
bool SharedFunctionInfo::HasWasmExportedFunctionData() const { bool SharedFunctionInfo::HasWasmExportedFunctionData() const {
return function_data(kAcquireLoad).IsWasmExportedFunctionData(); return function_data(kAcquireLoad).IsWasmExportedFunctionData();
} }
......
...@@ -137,6 +137,11 @@ CodeT SharedFunctionInfo::GetCode() const { ...@@ -137,6 +137,11 @@ CodeT SharedFunctionInfo::GetCode() const {
} }
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
WasmFunctionData SharedFunctionInfo::wasm_function_data() const {
DCHECK(HasWasmFunctionData());
return WasmFunctionData::cast(function_data(kAcquireLoad));
}
WasmExportedFunctionData SharedFunctionInfo::wasm_exported_function_data() WasmExportedFunctionData SharedFunctionInfo::wasm_exported_function_data()
const { const {
DCHECK(HasWasmExportedFunctionData()); DCHECK(HasWasmExportedFunctionData());
......
...@@ -37,6 +37,7 @@ class DebugInfo; ...@@ -37,6 +37,7 @@ class DebugInfo;
class IsCompiledScope; class IsCompiledScope;
template <typename> template <typename>
class Signature; class Signature;
class WasmFunctionData;
class WasmCapiFunctionData; class WasmCapiFunctionData;
class WasmExportedFunctionData; class WasmExportedFunctionData;
class WasmJSFunctionData; class WasmJSFunctionData;
...@@ -344,6 +345,7 @@ class SharedFunctionInfo ...@@ -344,6 +345,7 @@ class SharedFunctionInfo
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
inline bool HasAsmWasmData() const; inline bool HasAsmWasmData() const;
inline bool HasWasmFunctionData() const;
inline bool HasWasmExportedFunctionData() const; inline bool HasWasmExportedFunctionData() const;
inline bool HasWasmJSFunctionData() const; inline bool HasWasmJSFunctionData() const;
inline bool HasWasmCapiFunctionData() const; inline bool HasWasmCapiFunctionData() const;
...@@ -353,6 +355,7 @@ class SharedFunctionInfo ...@@ -353,6 +355,7 @@ class SharedFunctionInfo
V8_EXPORT_PRIVATE WasmExportedFunctionData V8_EXPORT_PRIVATE WasmExportedFunctionData
wasm_exported_function_data() const; wasm_exported_function_data() const;
WasmFunctionData wasm_function_data() const;
WasmJSFunctionData wasm_js_function_data() const; WasmJSFunctionData wasm_js_function_data() const;
WasmCapiFunctionData wasm_capi_function_data() const; WasmCapiFunctionData wasm_capi_function_data() const;
WasmResumeData wasm_resume_data() const; WasmResumeData wasm_resume_data() const;
......
...@@ -117,7 +117,10 @@ Object ThrowWasmError(Isolate* isolate, MessageTemplate message, ...@@ -117,7 +117,10 @@ Object ThrowWasmError(Isolate* isolate, MessageTemplate message,
} }
} // namespace } // namespace
RUNTIME_FUNCTION(Runtime_WasmIsValidRefValue) { // Takes a JS object and a wasm type as Smi. Type checks the object against the
// type; if the check succeeds, returns the object in its wasm representation;
// otherwise throws a type error.
RUNTIME_FUNCTION(Runtime_WasmJSToWasmObject) {
// This code is called from wrappers, so the "thread is wasm" flag is not set. // This code is called from wrappers, so the "thread is wasm" flag is not set.
DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(), DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(),
!trap_handler::IsThreadInWasm()); !trap_handler::IsThreadInWasm());
...@@ -138,9 +141,13 @@ RUNTIME_FUNCTION(Runtime_WasmIsValidRefValue) { ...@@ -138,9 +141,13 @@ RUNTIME_FUNCTION(Runtime_WasmIsValidRefValue) {
wasm::ValueType type = wasm::ValueType::FromRawBitField(raw_type); wasm::ValueType type = wasm::ValueType::FromRawBitField(raw_type);
const char* error_message; const char* error_message;
bool result = internal::wasm::TypecheckJSObject(isolate, module, value, type, Handle<Object> result;
&error_message); bool success = internal::wasm::JSToWasmObject(isolate, module, value, type,
return Smi::FromInt(result); &error_message)
.ToHandle(&result);
if (success) return *result;
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kWasmTrapJSTypeError));
} }
RUNTIME_FUNCTION(Runtime_WasmMemoryGrow) { RUNTIME_FUNCTION(Runtime_WasmMemoryGrow) {
......
...@@ -611,7 +611,7 @@ namespace internal { ...@@ -611,7 +611,7 @@ namespace internal {
F(WasmTableCopy, 6, 1) \ F(WasmTableCopy, 6, 1) \
F(WasmTableGrow, 3, 1) \ F(WasmTableGrow, 3, 1) \
F(WasmTableFill, 5, 1) \ F(WasmTableFill, 5, 1) \
F(WasmIsValidRefValue, 3, 1) \ F(WasmJSToWasmObject, 3, 1) \
F(WasmCompileLazy, 3, 1) \ F(WasmCompileLazy, 3, 1) \
F(WasmCompileWrapper, 2, 1) \ F(WasmCompileWrapper, 2, 1) \
F(WasmTriggerTierUp, 1, 1) \ F(WasmTriggerTierUp, 1, 1) \
......
...@@ -1535,8 +1535,9 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance, ...@@ -1535,8 +1535,9 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
if (global.type.is_reference()) { if (global.type.is_reference()) {
const char* error_message; const char* error_message;
if (!wasm::TypecheckJSObject(isolate_, module_, value, global.type, if (wasm::JSToWasmObject(isolate_, module_, value, global.type,
&error_message)) { &error_message)
.is_null()) {
ReportLinkError(error_message, global_index, module_name, import_name); ReportLinkError(error_message, global_index, module_name, import_name);
return false; return false;
} }
...@@ -1548,7 +1549,7 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance, ...@@ -1548,7 +1549,7 @@ bool InstanceBuilder::ProcessImportedGlobal(Handle<WasmInstanceObject> instance,
!value->IsNull()) { !value->IsNull()) {
bool unpacked = TryUnpackObjectWrapper(isolate_, value); bool unpacked = TryUnpackObjectWrapper(isolate_, value);
// Excluding SMIs and stringrefs, every value received here, must have // Excluding SMIs and stringrefs, every value received here, must have
// been wrapped. This is ensured by TypeCheckJSObject(). // been wrapped. This is ensured by JSToWasmObject().
DCHECK_EQ(unpacked, !value->IsSmi() && !value->IsString()); DCHECK_EQ(unpacked, !value->IsSmi() && !value->IsString());
USE(unpacked); // Prevent nused warning if DCHECKs disabled. USE(unpacked); // Prevent nused warning if DCHECKs disabled.
} }
......
...@@ -1445,8 +1445,9 @@ bool checkAndUnpackAnyRef(i::Isolate* i_isolate, ...@@ -1445,8 +1445,9 @@ bool checkAndUnpackAnyRef(i::Isolate* i_isolate,
i::wasm::ValueType type, ErrorThrower& thrower) { i::wasm::ValueType type, ErrorThrower& thrower) {
const char* error_message = nullptr; const char* error_message = nullptr;
auto module = nullptr; auto module = nullptr;
bool valid = internal::wasm::TypecheckJSObject( bool valid = !internal::wasm::JSToWasmObject(i_isolate, module, in_out_value,
i_isolate, module, in_out_value, type, &error_message); type, &error_message)
.is_null();
if (!valid) { if (!valid) {
DCHECK(error_message != nullptr); DCHECK(error_message != nullptr);
thrower.TypeError("%s", error_message); thrower.TypeError("%s", error_message);
......
...@@ -325,8 +325,9 @@ bool WasmTableObject::IsValidJSElement(Isolate* isolate, ...@@ -325,8 +325,9 @@ bool WasmTableObject::IsValidJSElement(Isolate* isolate,
!table->instance().IsUndefined() !table->instance().IsUndefined()
? WasmInstanceObject::cast(table->instance()).module() ? WasmInstanceObject::cast(table->instance()).module()
: nullptr; : nullptr;
return wasm::TypecheckJSObject(isolate, module, entry, table->type(), return !wasm::JSToWasmObject(isolate, module, entry, table->type(),
&error_message); &error_message)
.is_null();
} }
void WasmTableObject::SetFunctionTableEntry( void WasmTableObject::SetFunctionTableEntry(
...@@ -2346,9 +2347,7 @@ bool TryUnpackObjectWrapper(Isolate* isolate, Handle<Object>& in_out_value) { ...@@ -2346,9 +2347,7 @@ bool TryUnpackObjectWrapper(Isolate* isolate, Handle<Object>& in_out_value) {
return true; return true;
} }
// TODO(7748): Unify this with transforming from JS to wasm representation, and MaybeHandle<Object> JSToWasmObject(Isolate* isolate, const WasmModule* module,
// use it as the single interface for the JS->wasm boundary.
bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
Handle<Object> value, ValueType expected, Handle<Object> value, ValueType expected,
const char** error_message) { const char** error_message) {
DCHECK(expected.is_reference()); DCHECK(expected.is_reference());
...@@ -2359,15 +2358,15 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module, ...@@ -2359,15 +2358,15 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
switch (repr) { switch (repr) {
case HeapType::kStringViewWtf8: case HeapType::kStringViewWtf8:
*error_message = "stringview_wtf8 has no JS representation"; *error_message = "stringview_wtf8 has no JS representation";
return false; return {};
case HeapType::kStringViewWtf16: case HeapType::kStringViewWtf16:
*error_message = "stringview_wtf16 has no JS representation"; *error_message = "stringview_wtf16 has no JS representation";
return false; return {};
case HeapType::kStringViewIter: case HeapType::kStringViewIter:
*error_message = "stringview_iter has no JS representation"; *error_message = "stringview_iter has no JS representation";
return false; return {};
default: default:
return true; return value;
} }
} }
V8_FALLTHROUGH; V8_FALLTHROUGH;
...@@ -2384,79 +2383,85 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module, ...@@ -2384,79 +2383,85 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
*error_message = *error_message =
"function-typed object must be null (if nullable) or a Wasm " "function-typed object must be null (if nullable) or a Wasm "
"function object"; "function object";
return false; return {};
} }
return true; return MaybeHandle<Object>(Handle<JSFunction>::cast(value)
->shared()
.wasm_function_data()
.internal(),
isolate);
} }
case HeapType::kExtern: case HeapType::kExtern: {
if (!value->IsNull(isolate)) return true; if (!value->IsNull(isolate)) return value;
*error_message = "null is not allowed for (ref extern)"; *error_message = "null is not allowed for (ref extern)";
return false; return {};
case HeapType::kAny: }
case HeapType::kAny: {
if (!v8_flags.wasm_gc_js_interop) { if (!v8_flags.wasm_gc_js_interop) {
TryUnpackObjectWrapper(isolate, value); TryUnpackObjectWrapper(isolate, value);
} }
if (!value->IsNull(isolate)) return true; if (!value->IsNull(isolate)) return value;
*error_message = "null is not allowed for (ref any)"; *error_message = "null is not allowed for (ref any)";
return false; return {};
}
case HeapType::kData: { case HeapType::kData: {
if (v8_flags.wasm_gc_js_interop if (v8_flags.wasm_gc_js_interop
? value->IsWasmStruct() || value->IsWasmArray() ? value->IsWasmStruct() || value->IsWasmArray()
: TryUnpackObjectWrapper(isolate, value)) { : TryUnpackObjectWrapper(isolate, value)) {
return true; return value;
} }
*error_message = *error_message =
"dataref object must be null (if nullable) or a wasm " "dataref object must be null (if nullable) or a wasm "
"struct/array"; "struct/array";
return false; return {};
} }
case HeapType::kArray: { case HeapType::kArray: {
if ((v8_flags.wasm_gc_js_interop || if ((v8_flags.wasm_gc_js_interop ||
TryUnpackObjectWrapper(isolate, value)) && TryUnpackObjectWrapper(isolate, value)) &&
value->IsWasmArray()) { value->IsWasmArray()) {
return true; return value;
} }
*error_message = *error_message =
"arrayref object must be null (if nullable) or a wasm array"; "arrayref object must be null (if nullable) or a wasm array";
return false; return {};
} }
case HeapType::kEq: { case HeapType::kEq: {
if (value->IsSmi() || if (value->IsSmi() ||
(v8_flags.wasm_gc_js_interop (v8_flags.wasm_gc_js_interop
? value->IsWasmStruct() || value->IsWasmArray() ? value->IsWasmStruct() || value->IsWasmArray()
: TryUnpackObjectWrapper(isolate, value))) { : TryUnpackObjectWrapper(isolate, value))) {
return true; return value;
} }
*error_message = *error_message =
"eqref object must be null (if nullable) or a wasm " "eqref object must be null (if nullable) or a wasm "
"i31/struct/array"; "i31/struct/array";
return false; return {};
} }
case HeapType::kI31: { case HeapType::kI31: {
if (value->IsSmi()) return true; if (value->IsSmi()) return value;
*error_message = *error_message =
"i31ref object must be null (if nullable) or a wasm i31"; "i31ref object must be null (if nullable) or a wasm i31";
return false; return {};
} }
case HeapType::kString: case HeapType::kString:
if (value->IsString()) return true; if (value->IsString()) return value;
*error_message = "wrong type (expected a string)"; *error_message = "wrong type (expected a string)";
return false; return {};
case HeapType::kStringViewWtf8: case HeapType::kStringViewWtf8:
*error_message = "stringview_wtf8 has no JS representation"; *error_message = "stringview_wtf8 has no JS representation";
return false; return {};
case HeapType::kStringViewWtf16: case HeapType::kStringViewWtf16:
*error_message = "stringview_wtf16 has no JS representation"; *error_message = "stringview_wtf16 has no JS representation";
return false; return {};
case HeapType::kStringViewIter: case HeapType::kStringViewIter:
*error_message = "stringview_iter has no JS representation"; *error_message = "stringview_iter has no JS representation";
return false; return {};
default: default:
if (module == nullptr) { if (module == nullptr) {
*error_message = *error_message =
"an object defined in JavaScript cannot be compatible with a " "an object defined in JavaScript cannot be compatible with a "
"type defined in a Webassembly module"; "type defined in a Webassembly module";
return false; return {};
} }
DCHECK(module->has_type(expected.ref_index())); DCHECK(module->has_type(expected.ref_index()));
if (module->has_signature(expected.ref_index())) { if (module->has_signature(expected.ref_index())) {
...@@ -2471,12 +2476,9 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module, ...@@ -2471,12 +2476,9 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
*error_message = *error_message =
"assigned exported function has to be a subtype of the " "assigned exported function has to be a subtype of the "
"expected type"; "expected type";
return false; return {};
} }
return true; } else if (WasmJSFunction::IsWasmJSFunction(*value)) {
}
if (WasmJSFunction::IsWasmJSFunction(*value)) {
// Since a WasmJSFunction cannot refer to indexed types (definable // Since a WasmJSFunction cannot refer to indexed types (definable
// only in a module), we do not need full function subtyping. // only in a module), we do not need full function subtyping.
// TODO(manoskouk): Change this if wasm types can be exported. // TODO(manoskouk): Change this if wasm types can be exported.
...@@ -2485,12 +2487,9 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module, ...@@ -2485,12 +2487,9 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
*error_message = *error_message =
"assigned WasmJSFunction has to be a subtype of the " "assigned WasmJSFunction has to be a subtype of the "
"expected type"; "expected type";
return false; return {};
} }
return true; } else if (WasmCapiFunction::IsWasmCapiFunction(*value)) {
}
if (WasmCapiFunction::IsWasmCapiFunction(*value)) {
// Since a WasmCapiFunction cannot refer to indexed types // Since a WasmCapiFunction cannot refer to indexed types
// (definable only in a module), we do not need full function // (definable only in a module), we do not need full function
// subtyping. // subtyping.
...@@ -2500,33 +2499,28 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module, ...@@ -2500,33 +2499,28 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
*error_message = *error_message =
"assigned WasmCapiFunction has to be a subtype of the " "assigned WasmCapiFunction has to be a subtype of the "
"expected type"; "expected type";
return false; return {};
}
return true;
} }
} else {
*error_message = *error_message =
"function-typed object must be null (if nullable) or a Wasm " "function-typed object must be null (if nullable) or a Wasm "
"function object"; "function object";
return {};
return false; }
return MaybeHandle<Object>(Handle<JSFunction>::cast(value)
->shared()
.wasm_function_data()
.internal(),
isolate);
} else { } else {
// A struct or array type with index is expected. // A struct or array type with index is expected.
DCHECK(module->has_struct(expected.ref_index()) || DCHECK(module->has_struct(expected.ref_index()) ||
module->has_array(expected.ref_index())); module->has_array(expected.ref_index()));
if (value->IsNull()) {
if (expected.is_non_nullable()) {
*error_message =
"invalid null value for non-nullable element type";
return false;
}
return true;
}
if (v8_flags.wasm_gc_js_interop if (v8_flags.wasm_gc_js_interop
? !value->IsWasmStruct() && !value->IsWasmArray() ? !value->IsWasmStruct() && !value->IsWasmArray()
: !TryUnpackObjectWrapper(isolate, value)) { : !TryUnpackObjectWrapper(isolate, value)) {
*error_message = "object incompatible with wasm type"; *error_message = "object incompatible with wasm type";
return false; return {};
} }
auto wasm_obj = Handle<WasmObject>::cast(value); auto wasm_obj = Handle<WasmObject>::cast(value);
WasmTypeInfo type_info = wasm_obj->map().wasm_type_info(); WasmTypeInfo type_info = wasm_obj->map().wasm_type_info();
...@@ -2535,9 +2529,9 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module, ...@@ -2535,9 +2529,9 @@ bool TypecheckJSObject(Isolate* isolate, const WasmModule* module,
if (!IsHeapSubtypeOf(HeapType(actual_idx), expected.heap_type(), if (!IsHeapSubtypeOf(HeapType(actual_idx), expected.heap_type(),
actual_module, module)) { actual_module, module)) {
*error_message = "object is not a subtype of element type"; *error_message = "object is not a subtype of element type";
return false; return {};
} }
return true; return value;
} }
} }
} }
......
...@@ -1067,9 +1067,16 @@ class WasmSuspenderObject ...@@ -1067,9 +1067,16 @@ class WasmSuspenderObject
#undef DECL_OPTIONAL_ACCESSORS #undef DECL_OPTIONAL_ACCESSORS
namespace wasm { namespace wasm {
bool TypecheckJSObject(Isolate* isolate, const WasmModule* module, // Takes a {value} in the JS representation and typechecks it according to
// {expected}. If the typecheck succeeds, returns the wasm representation of the
// object; otherwise, returns the empty handle.
MaybeHandle<Object> JSToWasmObject(Isolate* isolate, const WasmModule* module,
Handle<Object> value, ValueType expected, Handle<Object> value, ValueType expected,
const char** error_message); 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); bool TryUnpackObjectWrapper(Isolate* isolate, Handle<Object>& in_out_value);
} // namespace wasm } // namespace wasm
......
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