%PDF- %PDF-
| Direktori : /home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/builtins/ |
| Current File : //home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/builtins/wasm-to-js.tq |
// 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 TierUpWasmToJSWrapper(NoContext, WasmApiFunctionRef): JSAny;
} // namespace runtime
namespace wasm {
@export
struct WasmToJSResult {
popCount: intptr;
result0: intptr;
result1: intptr;
result2: float64;
result3: float64;
}
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;
extern builtin IterableToFixedArrayForWasm(Context, JSAny, Smi): FixedArray;
extern macro StackAlignmentInBytes(): intptr;
const kSignatureOffset: constexpr intptr
generates 'WasmToJSWrapperConstants::kSignatureOffset';
@export
transitioning macro WasmToJSWrapper(ref: WasmApiFunctionRef): WasmToJSResult {
// Spill the signature on the stack so that it can be read by the GC. This is
// done in the very beginning before a GC could be triggered.
// Caller FP + return address.
const sigSlot = LoadFramePointer() + kSignatureOffset;
*GetRefAt<intptr>(sigSlot, 0) = BitcastTaggedToWord(ref.sig);
const sizeOfSig = StackAlignmentInBytes() / torque_internal::SizeOf<intptr>();
ModifyWasmToJSCounter(1);
ModifyThreadInWasmFlag(0);
// Trigger a wrapper tier-up when this function got called often enough.
dcheck(ref.wrapper_budget > 0);
ref.wrapper_budget = ref.wrapper_budget - 1;
if (ref.wrapper_budget == 0) {
runtime::TierUpWasmToJSWrapper(kNoContext, ref);
}
const signaturePod = &ref.sig.bytes;
const serializedSig = torque_internal::unsafe::NewConstSlice<int32>(
signaturePod.object, signaturePod.offset,
signaturePod.length / torque_internal::SizeOf<int32>());
const returnCount =
Convert<intptr>(*torque_internal::unsafe::NewReference<int32>(
serializedSig.object, serializedSig.offset));
const paramCount: intptr = serializedSig.length - returnCount - 1;
const returnTypes = Subslice(serializedSig, Convert<intptr>(1), returnCount)
otherwise unreachable;
const paramTypes = Subslice(serializedSig, returnCount + 1, paramCount)
otherwise unreachable;
// The number of parameters that get pushed on the stack is (at least) the
// number of incoming parameters plus the receiver.
const numStackParams = paramCount + 1;
const outParams = WasmAllocateZeroedFixedArray(numStackParams);
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;
// Caller FP + return address + signature.
const stackParamStart =
LoadFramePointer() + (2 + sizeOfSig) * torque_internal::SizeOf<intptr>();
const inParams = torque_internal::unsafe::NewOffHeapReference(
%RawDownCast<RawPtr<intptr>>(stackParamStart));
let locationAllocator = LocationAllocatorForParams(inParams);
let paramIt = paramTypes.Iterator();
let hasTaggedParams: bool = false;
while (!paramIt.Empty()) {
const paramType = paramIt.NextNotEmpty();
if (paramType == kWasmI32Type) {
const slot = locationAllocator.GetGPSlot();
const val = *RefCast<int32>(slot);
outParams.objects[nextIndex++] = Convert<Number>(val);
} else if (paramType == kWasmF32Type) {
const slot = locationAllocator.GetFP32Slot();
const val = *RefCast<float32>(slot);
outParams.objects[nextIndex++] = Convert<Number>(val);
} else if (paramType == kWasmI64Type) {
if constexpr (Is64()) {
const slot = locationAllocator.GetGPSlot();
const val = *slot;
outParams.objects[nextIndex++] = I64ToBigInt(val);
} else {
const lowWordSlot = locationAllocator.GetGPSlot();
const highWordSlot = locationAllocator.GetGPSlot();
const lowWord = *lowWordSlot;
const highWord = *highWordSlot;
outParams.objects[nextIndex++] = I32PairToBigInt(lowWord, highWord);
}
} else if (paramType == kWasmF64Type) {
const slot = locationAllocator.GetFP64Slot();
const val = *RefCast<float64>(slot);
outParams.objects[nextIndex++] = Convert<Number>(val);
} else {
nextIndex++;
hasTaggedParams = true;
}
}
// Second loop for tagged parameters.
if (hasTaggedParams) {
locationAllocator.StartRefs();
nextIndex = 1;
paramIt = paramTypes.Iterator();
while (!paramIt.Empty()) {
const paramType = paramIt.NextNotEmpty();
const paramKind = paramType & kValueTypeKindBitsMask;
if (paramKind == ValueKind::kRef || paramKind == ValueKind::kRefNull) {
const slot = locationAllocator.GetGPSlot();
const rawRef = *slot;
const value = BitcastWordToTagged(rawRef);
outParams.objects[nextIndex] =
WasmToJSObject(ref.native_context, value, paramType);
}
nextIndex++;
}
}
const target = ref.callable;
const context = ref.native_context;
// Reset the signature on the stack, so that incoming parameters don't get
// scanned anymore.
*GetRefAt<intptr>(sigSlot, 0) = 0;
const result = CallVarargs(
context, target, 0, Convert<int32>(numStackParams), outParams);
// Put a marker on the stack to indicate to the frame iterator that the call
// to JavaScript is finished. For asm.js source positions it is important to
// know if an exception happened in the call to JS, or in the ToNumber
// conversion afterwards.
*GetRefAt<intptr>(sigSlot, 0) = BitcastTaggedToWord(SmiConstant(-1));
let resultFixedArray: FixedArray;
if (returnCount > 1) {
resultFixedArray =
IterableToFixedArrayForWasm(context, result, Convert<Smi>(returnCount));
} else {
resultFixedArray = kEmptyFixedArray;
}
const gpRegSlots = %RawDownCast<RawPtr<intptr>>(StackSlotPtr(
2 * torque_internal::SizeOf<intptr>(),
torque_internal::SizeOf<intptr>()));
const fpRegSlots = %RawDownCast<RawPtr<float64>>(StackSlotPtr(
2 * torque_internal::SizeOf<float64>(),
torque_internal::SizeOf<float64>()));
// The return area on the stack starts right after the stack area.
const stackSlots =
locationAllocator.GetAlignedStackEnd(StackAlignmentInBytes());
locationAllocator =
LocationAllocatorForReturns(gpRegSlots, fpRegSlots, stackSlots);
let returnIt = returnTypes.Iterator();
nextIndex = 0;
let hasTagged: bool = false;
while (!returnIt.Empty()) {
let retVal: JSAny;
if (returnCount == 1) {
retVal = result;
} else {
retVal = UnsafeCast<JSAny>(resultFixedArray.objects[nextIndex]);
}
const retType = returnIt.NextNotEmpty();
if (retType == kWasmI32Type) {
let toRef = locationAllocator.GetGPSlot();
typeswitch (retVal) {
case (smiVal: Smi): {
*toRef = Convert<intptr>(Unsigned(SmiToInt32(smiVal)));
}
case (heapVal: JSAnyNotSmi): {
*toRef = Convert<intptr>(Unsigned(WasmTaggedNonSmiToInt32(heapVal)));
}
}
} else if (retType == kWasmF32Type) {
let toRef = locationAllocator.GetFP32Slot();
*toRef = Convert<intptr>(Bitcast<uint32>(WasmTaggedToFloat32(retVal)));
} else if (retType == kWasmF64Type) {
let toRef = locationAllocator.GetFP64Slot();
*RefCast<float64>(toRef) = ChangeTaggedToFloat64(retVal);
} else if (retType == kWasmI64Type) {
if constexpr (Is64()) {
let toRef = locationAllocator.GetGPSlot();
const v = TruncateBigIntToI64(context, retVal);
*toRef = v;
} else {
let toLowRef = locationAllocator.GetGPSlot();
let toHighRef = locationAllocator.GetGPSlot();
const bigIntVal = ToBigInt(context, retVal);
const pair = BigIntToRawBytes(bigIntVal);
*toLowRef = Signed(pair.low);
*toHighRef = Signed(pair.high);
}
} else {
const converted = JSToWasmObject(context, ref.instance, retType, retVal);
let toRef = locationAllocator.GetGPSlot();
if (returnCount == 1) {
// There are no other values, we can write the object directly into the
// result buffer.
*toRef = BitcastTaggedToWord(converted);
} else {
// There may be other parameters that could still trigger a GC when they
// get transformed. For now we just store the converted value back in
// the FixedArray.
hasTagged = true;
resultFixedArray.objects[nextIndex] = converted;
}
}
nextIndex++;
}
if (hasTagged) {
returnIt = returnTypes.Iterator();
nextIndex = 0;
locationAllocator =
LocationAllocatorForReturns(gpRegSlots, fpRegSlots, stackSlots);
while (!returnIt.Empty()) {
const retType = returnIt.NextNotEmpty();
if (retType == kWasmI32Type) {
locationAllocator.GetGPSlot();
} else if (retType == kWasmF32Type) {
locationAllocator.GetFP32Slot();
} else if (retType == kWasmF64Type) {
locationAllocator.GetFP64Slot();
} else if (retType == kWasmI64Type) {
if constexpr (Is64()) {
locationAllocator.GetGPSlot();
} else {
locationAllocator.GetGPSlot();
locationAllocator.GetGPSlot();
}
} else {
let toRef = locationAllocator.GetGPSlot();
const value = resultFixedArray.objects[nextIndex];
*toRef = BitcastTaggedToWord(value);
}
nextIndex++;
}
}
const popCount =
(Convert<intptr>(stackSlots) - Convert<intptr>(stackParamStart)) /
torque_internal::SizeOf<intptr>() +
sizeOfSig;
ModifyThreadInWasmFlag(1);
ModifyWasmToJSCounter(-1);
return WasmToJSResult{
popCount: popCount,
result0: *GetRefAt<intptr>(gpRegSlots, 0),
result1: *GetRefAt<intptr>(gpRegSlots, torque_internal::SizeOf<intptr>()),
result2: *GetRefAt<float64>(fpRegSlots, 0),
result3: *GetRefAt<float64>(fpRegSlots, torque_internal::SizeOf<float64>())
};
}
} // namespace wasm