| // Copyright 2025 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. |
| |
| #ifndef V8_WASM_WASM_EXPORT_WRAPPER_CACHE_H_ |
| #define V8_WASM_WASM_EXPORT_WRAPPER_CACHE_H_ |
| |
| #if !V8_ENABLE_WEBASSEMBLY |
| #error This header should only be included if WebAssembly is enabled. |
| #endif // !V8_ENABLE_WEBASSEMBLY |
| |
| #include "src/objects/code.h" |
| #include "src/objects/fixed-array.h" |
| #include "src/objects/internal-index.h" |
| #include "src/wasm/canonical-types.h" |
| #include "src/wasm/value-type.h" |
| |
| namespace v8::internal::wasm { |
| |
| // Provides functionality for caching JS-to-Wasm wrappers in an {Isolate}. |
| // Since these wrappers are JS-compatible {Code} objects living in managed |
| // code space, the cache is also Isolate-specific. It uses a WeakFixedArray |
| // as backing store in order to not leak unused wrappers, and a HashTable- |
| // inspired indexing scheme rather than a dense array layout because we expect |
| // only a minority of canonical type indices to have a corresponding wrapper. |
| // For sandbox purposes, the cache itself is untrusted, but calls through the |
| // wrappers are protected by our regular signature verification scheme. |
| class WasmExportWrapperCache : public AllStatic { |
| public: |
| // DCHECK-fails if a caller attempts to overwrite an existing wrapper. |
| static void Put(Isolate* isolate, CanonicalTypeIndex sig_index, |
| bool receiver_is_first_param, DirectHandle<Code> code); |
| |
| // Returns an empty Tagged if no cache entry was found. |
| static Tagged<CodeWrapper> Get(Isolate* isolate, CanonicalTypeIndex sig_index, |
| bool receiver_is_first_param); |
| |
| #ifdef VERIFY_HEAP |
| static void Verify(Heap* heap); |
| #endif // VERIFY_HEAP |
| |
| // Defined in cctest/test-run-wasm-wrappers.cc to not bloat shipping binaries. |
| static int CountWrappersForTesting(Isolate* isolate); |
| |
| private: |
| static constexpr int kUnused = -1; |
| |
| static constexpr int kNumUsedElementsIndex = 0; |
| static constexpr int kReservedSlots = 1; |
| |
| // Key (Smi), value (Weak<CodeWrapper>). |
| static constexpr int kSlotsPerEntry = 2; |
| |
| static DirectHandle<WeakFixedArray> New(Isolate* isolate, int capacity); |
| |
| static uint32_t Capacity(Tagged<WeakFixedArray> cache); |
| |
| static uint32_t Hash(CanonicalTypeIndex sig_index, |
| bool receiver_is_first_param) { |
| // We expect most signatures to get only one wrapper, so putting the |
| // {receiver_is_first_param} bit at the top should give good distribution |
| // of hash values. |
| // Note: "hash" is a bit of a misnomer here; we require this value to |
| // fully represent the identity of the cached value. See {FirstProbe} for |
| // the step where collisions can and do happen. |
| static_assert(kMaxCanonicalTypes < (1u << 20)); |
| return ((receiver_is_first_param ? 1 : 0) << 20) | sig_index.index; |
| } |
| |
| // Maps the n-th entry to an index in the underlying WeakFixedArray. |
| static int ToArraySlot(InternalIndex entry) { |
| return kReservedSlots + entry.as_int() * kSlotsPerEntry; |
| } |
| |
| static InternalIndex FirstProbe(uint32_t hash, uint32_t capacity) { |
| #if V8_HASHES_COLLIDE |
| if (v8_flags.hashes_collide) hash = base::kCollidingHash; |
| #endif // V8_HASHES_COLLIDE |
| // {New()} ensures that {capacity} is always a power of two. |
| return InternalIndex(hash & (capacity - 1)); |
| } |
| |
| static InternalIndex NextProbe(InternalIndex last, uint32_t number, |
| uint32_t capacity) { |
| // {New()} ensures that {capacity} is always a power of two. |
| return InternalIndex((last.as_uint32() + number) & (capacity - 1)); |
| } |
| |
| V8_WARN_UNUSED_RESULT static Tagged<WeakFixedArray> EnsureCapacity( |
| Isolate* isolate); |
| |
| template <bool entry_may_exist> |
| static void PutInternal(Tagged<WeakFixedArray> cache, uint32_t hash, |
| Tagged<MaybeWeak<Object>> value); |
| }; |
| |
| } // namespace v8::internal::wasm |
| |
| #endif // V8_WASM_WASM_EXPORT_WRAPPER_CACHE_H_ |