%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/builtins/ |
Current File : /home/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