From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- js/src/wasm/WasmExprType.h | 330 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 js/src/wasm/WasmExprType.h (limited to 'js/src/wasm/WasmExprType.h') diff --git a/js/src/wasm/WasmExprType.h b/js/src/wasm/WasmExprType.h new file mode 100644 index 0000000000..4b02cd5e60 --- /dev/null +++ b/js/src/wasm/WasmExprType.h @@ -0,0 +1,330 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * + * Copyright 2021 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef wasm_expr_type_h +#define wasm_expr_type_h + +#include + +#include "wasm/WasmTypeDef.h" +#include "wasm/WasmValType.h" + +namespace js { +namespace wasm { + +template +class TaggedValue { + public: + enum Kind { + ImmediateKind1 = 0, + ImmediateKind2 = 1, + PointerKind1 = 2, + PointerKind2 = 3 + }; + using PackedRepr = uint64_t; + static_assert(std::is_same(), + "can use pointer tagging with PackedTypeCode"); + + private: + PackedRepr bits_; + + static constexpr PackedRepr PayloadShift = 2; + static constexpr PackedRepr KindMask = 0x3; + static constexpr PackedRepr PointerKindBit = 0x2; + + constexpr static bool IsPointerKind(Kind kind) { + return PackedRepr(kind) & PointerKindBit; + } + constexpr static bool IsImmediateKind(Kind kind) { + return !IsPointerKind(kind); + } + + static_assert(IsImmediateKind(ImmediateKind1), "immediate kind 1"); + static_assert(IsImmediateKind(ImmediateKind2), "immediate kind 2"); + static_assert(IsPointerKind(PointerKind1), "pointer kind 1"); + static_assert(IsPointerKind(PointerKind2), "pointer kind 2"); + + static PackedRepr PackImmediate(Kind kind, PackedRepr imm) { + MOZ_ASSERT(IsImmediateKind(kind)); + MOZ_ASSERT((PackedRepr(kind) & KindMask) == kind); + MOZ_ASSERT((imm & (PackedRepr(KindMask) + << ((sizeof(PackedRepr) * 8) - PayloadShift))) == 0); + return PackedRepr(kind) | (PackedRepr(imm) << PayloadShift); + } + + static PackedRepr PackPointer(Kind kind, PointerType* ptr) { + PackedRepr ptrBits = reinterpret_cast(ptr); + MOZ_ASSERT(IsPointerKind(kind)); + MOZ_ASSERT((PackedRepr(kind) & KindMask) == kind); + MOZ_ASSERT((ptrBits & KindMask) == 0); + return PackedRepr(kind) | ptrBits; + } + + public: + TaggedValue(Kind kind, PackedRepr imm) : bits_(PackImmediate(kind, imm)) {} + TaggedValue(Kind kind, PointerType* ptr) : bits_(PackPointer(kind, ptr)) {} + + PackedRepr bits() const { return bits_; } + Kind kind() const { return Kind(bits() & KindMask); } + PackedRepr immediate() const { + MOZ_ASSERT(IsImmediateKind(kind())); + return mozilla::AssertedCast(bits() >> PayloadShift); + } + PointerType* pointer() const { + MOZ_ASSERT(IsPointerKind(kind())); + return reinterpret_cast(bits() & ~KindMask); + } +}; + +// ResultType represents the WebAssembly spec's `resulttype`. Semantically, a +// result type is just a vec(valtype). For effiency, though, the ResultType +// value is packed into a word, with separate encodings for these 3 cases: +// [] +// [valtype] +// pointer to ValTypeVector +// +// Additionally there is an encoding indicating uninitialized ResultType +// values. +// +// Generally in the latter case the ValTypeVector is the args() or results() of +// a FuncType in the compilation unit, so as long as the lifetime of the +// ResultType value is less than the OpIter, we can just borrow the pointer +// without ownership or copying. +class ResultType { + using Tagged = TaggedValue; + Tagged tagged_; + + enum Kind { + EmptyKind = Tagged::ImmediateKind1, + SingleKind = Tagged::ImmediateKind2, + VectorKind = Tagged::PointerKind1, + InvalidKind = Tagged::PointerKind2, + }; + + ResultType(Kind kind, Tagged::PackedRepr imm) + : tagged_(Tagged::Kind(kind), imm) {} + explicit ResultType(const ValTypeVector* ptr) + : tagged_(Tagged::Kind(VectorKind), ptr) {} + + Kind kind() const { return Kind(tagged_.kind()); } + + ValType singleValType() const { + MOZ_ASSERT(kind() == SingleKind); + return ValType(PackedTypeCode::fromBits(tagged_.immediate())); + } + + const ValTypeVector& values() const { + MOZ_ASSERT(kind() == VectorKind); + return *tagged_.pointer(); + } + + public: + ResultType() : tagged_(Tagged::Kind(InvalidKind), nullptr) {} + + static ResultType Empty() { + return ResultType(EmptyKind, Tagged::PackedRepr(0)); + } + static ResultType Single(ValType vt) { + return ResultType(SingleKind, vt.bitsUnsafe()); + } + static ResultType Vector(const ValTypeVector& vals) { + switch (vals.length()) { + case 0: + return Empty(); + case 1: + return Single(vals[0]); + default: + return ResultType(&vals); + } + } + + [[nodiscard]] bool cloneToVector(ValTypeVector* out) { + MOZ_ASSERT(out->empty()); + switch (kind()) { + case EmptyKind: + return true; + case SingleKind: + return out->append(singleValType()); + case VectorKind: + return out->appendAll(values()); + default: + MOZ_CRASH("bad resulttype"); + } + } + + bool valid() const { return kind() != InvalidKind; } + bool empty() const { return kind() == EmptyKind; } + + size_t length() const { + switch (kind()) { + case EmptyKind: + return 0; + case SingleKind: + return 1; + case VectorKind: + return values().length(); + default: + MOZ_CRASH("bad resulttype"); + } + } + + // Polyfill the Span API, which is polyfilling the std library + size_t size() const { return length(); } + + ValType operator[](size_t i) const { + switch (kind()) { + case SingleKind: + MOZ_ASSERT(i == 0); + return singleValType(); + case VectorKind: + return values()[i]; + default: + MOZ_CRASH("bad resulttype"); + } + } + + bool operator==(ResultType rhs) const { + switch (kind()) { + case EmptyKind: + case SingleKind: + case InvalidKind: + return tagged_.bits() == rhs.tagged_.bits(); + case VectorKind: { + if (rhs.kind() != VectorKind) { + return false; + } + return EqualContainers(values(), rhs.values()); + } + default: + MOZ_CRASH("bad resulttype"); + } + } + bool operator!=(ResultType rhs) const { return !(*this == rhs); } +}; + +// BlockType represents the WebAssembly spec's `blocktype`. Semantically, a +// block type is just a (vec(valtype) -> vec(valtype)) with four special +// encodings which are represented explicitly in BlockType: +// [] -> [] +// [] -> [valtype] +// [params] -> [results] via pointer to FuncType +// [] -> [results] via pointer to FuncType (ignoring [params]) + +class BlockType { + using Tagged = TaggedValue; + Tagged tagged_; + + enum Kind { + VoidToVoidKind = Tagged::ImmediateKind1, + VoidToSingleKind = Tagged::ImmediateKind2, + FuncKind = Tagged::PointerKind1, + FuncResultsKind = Tagged::PointerKind2 + }; + + BlockType(Kind kind, Tagged::PackedRepr imm) + : tagged_(Tagged::Kind(kind), imm) {} + BlockType(Kind kind, const FuncType& type) + : tagged_(Tagged::Kind(kind), &type) {} + + Kind kind() const { return Kind(tagged_.kind()); } + ValType singleValType() const { + MOZ_ASSERT(kind() == VoidToSingleKind); + return ValType(PackedTypeCode::fromBits(tagged_.immediate())); + } + + const FuncType& funcType() const { return *tagged_.pointer(); } + + public: + BlockType() + : tagged_(Tagged::Kind(VoidToVoidKind), + PackedTypeCode::invalid().bits()) {} + + static BlockType VoidToVoid() { + return BlockType(VoidToVoidKind, Tagged::PackedRepr(0)); + } + static BlockType VoidToSingle(ValType vt) { + return BlockType(VoidToSingleKind, vt.bitsUnsafe()); + } + static BlockType Func(const FuncType& type) { + if (type.args().length() == 0) { + return FuncResults(type); + } + return BlockType(FuncKind, type); + } + static BlockType FuncResults(const FuncType& type) { + switch (type.results().length()) { + case 0: + return VoidToVoid(); + case 1: + return VoidToSingle(type.results()[0]); + default: + return BlockType(FuncResultsKind, type); + } + } + + ResultType params() const { + switch (kind()) { + case VoidToVoidKind: + case VoidToSingleKind: + case FuncResultsKind: + return ResultType::Empty(); + case FuncKind: + return ResultType::Vector(funcType().args()); + default: + MOZ_CRASH("unexpected kind"); + } + } + + ResultType results() const { + switch (kind()) { + case VoidToVoidKind: + return ResultType::Empty(); + case VoidToSingleKind: + return ResultType::Single(singleValType()); + case FuncKind: + case FuncResultsKind: + return ResultType::Vector(funcType().results()); + default: + MOZ_CRASH("unexpected kind"); + } + } + + bool operator==(BlockType rhs) const { + if (kind() != rhs.kind()) { + return false; + } + switch (kind()) { + case VoidToVoidKind: + case VoidToSingleKind: + return tagged_.bits() == rhs.tagged_.bits(); + case FuncKind: + return FuncType::strictlyEquals(funcType(), rhs.funcType()); + case FuncResultsKind: + return EqualContainers(funcType().results(), rhs.funcType().results()); + default: + MOZ_CRASH("unexpected kind"); + } + } + + bool operator!=(BlockType rhs) const { return !(*this == rhs); } +}; + +} // namespace wasm +} // namespace js + +#endif // wasm_expr_type_h -- cgit v1.2.3