diff options
Diffstat (limited to 'erts/emulator/beam/jit/beam_jit_types.hpp')
-rw-r--r-- | erts/emulator/beam/jit/beam_jit_types.hpp | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/erts/emulator/beam/jit/beam_jit_types.hpp b/erts/emulator/beam/jit/beam_jit_types.hpp new file mode 100644 index 0000000000..74edc66496 --- /dev/null +++ b/erts/emulator/beam/jit/beam_jit_types.hpp @@ -0,0 +1,150 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2023. All Rights Reserved. + * + * 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. + * + * %CopyrightEnd% + */ + +#ifndef __BEAM_JIT_TYPES_HPP__ +#define __BEAM_JIT_TYPES_HPP__ + +/* Type-safe wrapper around the definitions in beam_types.h. We've redefined it + * as an `enum class` to force the usage of our helpers, which lets us check + * for common usage errors at compile time. */ +enum class BeamTypeId : int { + None = BEAM_TYPE_NONE, + + Atom = BEAM_TYPE_ATOM, + Bitstring = BEAM_TYPE_BITSTRING, + BsMatchState = BEAM_TYPE_BS_MATCHSTATE, + Cons = BEAM_TYPE_CONS, + Float = BEAM_TYPE_FLOAT, + Fun = BEAM_TYPE_FUN, + Integer = BEAM_TYPE_INTEGER, + Map = BEAM_TYPE_MAP, + Nil = BEAM_TYPE_NIL, + Pid = BEAM_TYPE_PID, + Port = BEAM_TYPE_PORT, + Reference = BEAM_TYPE_REFERENCE, + Tuple = BEAM_TYPE_TUPLE, + + Any = BEAM_TYPE_ANY, + + Identifier = Pid | Port | Reference, + List = Cons | Nil, + Number = Float | Integer, + + /** @brief Types that can be boxed, including those that may also be + * immediates (e.g. pids, integers). */ + MaybeBoxed = Bitstring | BsMatchState | Float | Fun | Integer | Map | Pid | + Port | Reference | Tuple, + /** @brief Types that can be immediates, including those that may also be + * boxed (e.g. pids, integers). */ + MaybeImmediate = Atom | Integer | Nil | Pid | Port, + + /** @brief Types that are _always_ boxed. */ + AlwaysBoxed = MaybeBoxed & ~(Cons | MaybeImmediate), + /** @brief Types that are _always_ immediates. */ + AlwaysImmediate = MaybeImmediate & ~(Cons | MaybeBoxed), +}; + +template<BeamTypeId... T> +struct BeamTypeIdUnion; + +template<> +struct BeamTypeIdUnion<> { + static constexpr BeamTypeId value() { + return BeamTypeId::None; + } +}; + +template<BeamTypeId T, BeamTypeId... Rest> +struct BeamTypeIdUnion<T, Rest...> : BeamTypeIdUnion<Rest...> { + using integral = std::underlying_type_t<BeamTypeId>; + using super = BeamTypeIdUnion<Rest...>; + + /* Overlapping type specifications are redundant at best and a subtle error + * at worst. We've had several bugs where `Integer | MaybeBoxed` was used + * instead of `Integer | AlwaysBoxed` or similar, and erroneously drew the + * conclusion that the value is always an integer when not boxed, when it + * could also be a pid or port. */ + static constexpr bool no_overlap = + (static_cast<integral>(super::value()) & + static_cast<integral>(T)) == BEAM_TYPE_NONE; + static constexpr bool no_boxed_overlap = + no_overlap || (super::value() != BeamTypeId::MaybeBoxed && + T != BeamTypeId::MaybeBoxed); + static constexpr bool no_immed_overlap = + no_overlap || (super::value() != BeamTypeId::MaybeImmediate && + T != BeamTypeId::MaybeImmediate); + + static_assert(no_boxed_overlap, + "types must not overlap, did you mean to use " + "BeamTypeId::AlwaysBoxed here?"); + static_assert(no_immed_overlap, + "types must not overlap, did you mean to use " + "BeamTypeId::AlwaysImmediate here?"); + static_assert(no_overlap || no_boxed_overlap || no_immed_overlap, + "types must not overlap"); + + static constexpr bool is_single_typed() { + constexpr auto V = static_cast<integral>(value()); + return (static_cast<integral>(V) & (static_cast<integral>(V) - 1)) == + BEAM_TYPE_NONE; + } + + static constexpr BeamTypeId value() { + return static_cast<BeamTypeId>(static_cast<integral>(super::value()) | + static_cast<integral>(T)); + } +}; + +struct BeamArgType : public BeamType { + BeamTypeId type() const { + return static_cast<BeamTypeId>(BeamType::type_union); + } + + bool hasLowerBound() const { + return metadata_flags & BEAM_TYPE_HAS_LOWER_BOUND; + } + + bool hasUpperBound() const { + return metadata_flags & BEAM_TYPE_HAS_UPPER_BOUND; + } + + bool hasUnit() const { + return metadata_flags & BEAM_TYPE_HAS_UNIT; + } + + auto max() const { + ASSERT(hasUpperBound()); + return BeamType::max; + } + + auto min() const { + ASSERT(hasLowerBound()); + return BeamType::min; + } + + auto unit() const { + ASSERT(hasUnit()); + return BeamType::size_unit; + } +}; + +static_assert(std::is_standard_layout<BeamArgType>::value); + +#endif |