blob: 36014dc711cdb118b9f2345b9efb422845e9047a [file] [log] [blame]
// Copyright 2023 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.
namespace runtime {
extern runtime IsWasmExternalFunction(NoContext, JSAny): Boolean;
} // namespace runtime
namespace wasm {
extern builtin CallVarargs(
Context,
JSAny, // target
int32, // number of arguments already on the stack
int32, // number of arguments in the FixedArray
FixedArray // arguments list
): JSAny;
macro ConvertToAndFromWasm(context: Context, wasmType: int32, value: JSAny):
JSAny {
if (wasmType == kWasmI32Type) {
typeswitch (value) {
case (smiParam: Smi): {
return smiParam;
}
case (heapParam: JSAnyNotSmi): {
return Convert<Number>(WasmTaggedNonSmiToInt32(heapParam));
}
}
} else if (wasmType == kWasmI64Type) {
if constexpr (Is64()) {
const val = TruncateBigIntToI64(context, value);
return I64ToBigInt(val);
} else {
const bigIntVal = ToBigInt(context, value);
const pair = BigIntToRawBytes(bigIntVal);
return I32PairToBigInt(Signed(pair.low), Signed(pair.high));
}
} else if (wasmType == kWasmF32Type) {
return Convert<Number>(WasmTaggedToFloat32(value));
} else if (wasmType == kWasmF64Type) {
return Convert<Number>(WasmTaggedToFloat64(value));
} else {
const wasmKind = wasmType & kValueTypeKindBitsMask;
dcheck(wasmKind == ValueKind::kRef || wasmKind == ValueKind::kRefNull);
if (value == Null) {
// At the moment it is not possible to define non-nullable types for
// WebAssembly.Functions.
return value;
}
const heapType = (wasmType >> kValueTypeKindBits) & kValueTypeHeapTypeMask;
if (heapType != HeapType::kFunc) {
// We only have to check funcrefs.
return value;
}
if (runtime::IsWasmExternalFunction(kNoContext, value) != True) {
ThrowTypeError(MessageTemplate::kWasmTrapJSTypeError);
}
return value;
}
}
extern runtime WasmThrowJSTypeError(Context): never;
// The varargs arguments is just there so that the generated Code has a
// parameter_count of 0 (kDontAdaptArgumentsSentinel) and so becomes compatible
// with an existing entry in the JSDispatchTable.
transitioning javascript builtin JSToJSWrapperInvalidSig(
js-implicit context: NativeContext)(...arguments): JSAny {
runtime::WasmThrowJSTypeError(context);
}
transitioning javascript builtin JSToJSWrapper(
js-implicit context: NativeContext, receiver: JSAny, target: JSFunction,
dispatchHandle: DispatchHandle)(...arguments): JSAny {
// This is a generic builtin that can be installed on functions with different
// parameter counts, so we need to support that.
SetSupportsDynamicParameterCount(target, dispatchHandle);
const functionData = target.shared_function_info.wasm_js_function_data;
const importData =
UnsafeCast<WasmImportData>(functionData.internal.implicit_arg);
const returnCount = *torque_internal::unsafe::NewOffHeapReference(
%RawDownCast<RawPtr<intptr>>(importData.sig + 0));
const paramCount = *torque_internal::unsafe::NewOffHeapReference(
%RawDownCast<RawPtr<intptr>>(
importData.sig + torque_internal::SizeOf<intptr>()));
const valueTypesStorage = *torque_internal::unsafe::NewOffHeapReference(
%RawDownCast<RawPtr<RawPtr<int32>>>(
importData.sig + 2 * torque_internal::SizeOf<intptr>()));
const signatureValueTypes =
torque_internal::unsafe::NewOffHeapConstSlice<int32>(
valueTypesStorage, paramCount + returnCount);
const returnTypes =
Subslice(signatureValueTypes, 0, returnCount) otherwise unreachable;
const paramTypes = Subslice(signatureValueTypes, returnCount, paramCount)
otherwise unreachable;
const numOutParams = paramCount + 1;
const outParams = WasmAllocateZeroedFixedArray(numOutParams);
let nextIndex: intptr = 0;
// Set the receiver to `Undefined` as the default. If the receiver would be
// different, e.g. the global proxy for sloppy functions, then the CallVarargs
// builtin takes care of it automatically
outParams.objects[nextIndex++] = Undefined;
for (let paramIndex: intptr = 0; paramIndex < paramCount; paramIndex++) {
const param = arguments[paramIndex];
const paramType = *paramTypes.UncheckedAtIndex(paramIndex);
outParams.objects[nextIndex++] =
ConvertToAndFromWasm(context, paramType, param);
}
dcheck(nextIndex == numOutParams);
const calleeResult = CallVarargs(
context, importData.callable, 0, Convert<int32>(numOutParams), outParams);
let result: JSAny;
if (returnCount == 0) {
result = Undefined;
} else if (returnCount == 1) {
result = ConvertToAndFromWasm(
context, *returnTypes.UncheckedAtIndex(0), calleeResult);
} else {
const returnValues = IterableToFixedArrayForWasm(
context, calleeResult, Convert<Smi>(returnCount));
const resultArray = WasmAllocateJSArray(Convert<Smi>(returnCount));
const resultFixedArray = UnsafeCast<FixedArray>(resultArray.elements);
for (let returnIndex: intptr = 0; returnIndex < returnCount;
returnIndex++) {
const retVal = UnsafeCast<JSAny>(returnValues.objects[returnIndex]);
const retType = *returnTypes.UncheckedAtIndex(returnIndex);
resultFixedArray.objects[returnIndex] =
ConvertToAndFromWasm(context, retType, retVal);
}
result = resultArray;
}
return result;
}
}