// 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.
for (size_t i = 0; i < N; ++i) {
size_t comma = names.find(',', start);
DCHECK_EQ(i == N - 1, comma == std::string_view::npos);
// Trim whitespace.
start = names.find_first_not_of(" ", start);
size_t end = (comma == std::string_view::npos) ? names_size : comma;
end = names.find_last_not_of(" ,)", end) + 1;
result[i] = names.substr(start, end - start);
start = comma + 1;
}
return result;
}
// Calculates packed offsets for each Bytecode operand. // All operands are aligned to their own size. template <BytecodeOperandType... operand_types>
constexpr auto CalculateAlignedOffsets() {
constexpr int N = sizeof...(operand_types);
constexpr std::array<uint8_t, N> kOperandSizes = {
OperandTypeTraits<operand_types>::kSize...};
constexpr std::array<uint8_t, N> kOperandAlignments = {
OperandTypeTraits<operand_types>::kAlignment...};
std::array<int, N> offsets{}; int first_offset = sizeof(Bytecode); int offset = first_offset;
for (size_t i = 0; i < N; ++i) {
uint8_t operand_size = kOperandSizes[i];
size_t operand_alignment = kOperandAlignments[i];
offset = RoundUp(offset, operand_alignment);
// If the operand doesn't fit into the current 4-byte block, start a new // 4-byte block. if ((offset % kBytecodeAlignment) + operand_size > kBytecodeAlignment) {
offset = RoundUp<kBytecodeAlignment>(offset);
}
// Returns a tuple of all operands. static constexpr auto GetOperandsTuple() { return []<size_t... Is>(std::index_sequence<Is...>) { return std::tuple_cat([]<size_t I>() {
constexpr auto id = static_cast<Operand>(I); return std::tuple(std::integral_constant<Operand, id>{});
}.templateoperator()<Is>()...);
}(std::make_index_sequence<kCount>{});
}
// Calls |f| templatized by Operand for each Operand in the Operands list. // Example: // using Operands = BytecodeOperands<Bytecode::...>; // size_t op_sizes = 0; // Operands::ForEachOperand([]<auto op>() { // op_sizes += Operands::Size(op); // }); // Note that this gets evaluated at compile time, so op_sizes in the example // above is essentially a constant. template <typename Func> static constexpr void ForEachOperand(Func&& f) {
constexpr auto filtered_ops = GetOperandsTuple();
std::apply([&](auto... ops) { (..., f.templateoperator()<ops.value>()); },
filtered_ops);
}
// Similar to ForEachOperand, but additionally provides the current index as // a template argument. The index is a sequential index of operands. template <typename Func> static constexpr void ForEachOperandWithIndex(Func&& f) {
constexpr auto filtered_ops = GetOperandsTuple();
[&]<size_t... I>(std::index_sequence<I...>) {
(...,
f.templateoperator()<
std::tuple_element_t<I, decltype(filtered_ops)>::value /* Operand */,
I /* Index */>());
}(std::make_index_sequence<std::tuple_size_v<decltype(filtered_ops)>>{});
}
// Similar to above, but calls |f| only for operands of a given type. template <BytecodeOperandType OpType, typename Func> static constexpr void ForEachOperandOfType(Func&& f) {
ForEachOperand([&]<auto operand>() { if constexpr (Type(operand) == OpType) {
f.templateoperator()<operand>();
}
});
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.