// Copyright 2008-2009 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.
// Used to decide whether we use the `Char` or `4Chars` variant of a bytecode. static constexpr int kMaxSingleCharValue =
OperandTypeTraits<BytecodeOperandType::kChar>::kMaxValue;
// TODO(jgruber): Move all Writer methods before Generator methods.
void BytecodeWriter::ExpandBuffer(size_t new_size) { // TODO(jgruber): It's not necessary to default-initialize new elements.
buffer_.resize(new_size);
}
void BytecodeWriter::EmitRawBytecodeStream(const uint8_t* data, int len) {
EnsureCapacity(len); // Must start at a bytecode boundary.
DCHECK_EQ(pc_within_bc_, end_of_bc_); // We cannot check whether we also end at a boundary since we don't know what // data contains. Let's at least verify alignment. // TODO(jgruber): We could use BytecodeIterator to verify in DEBUG.
DCHECK(IsAligned(len, kBytecodeAlignment));
MemCopy(buffer_.data() + pc_, data, len); // End at a bytecode boundary, update bookkeeping.
pc_ += len; #ifdef DEBUG
pc_within_bc_ = pc_;
end_of_bc_ = pc_; #endif
}
void BytecodeWriter::EmitRawBytecodeStream(const BytecodeWriter* src_writer, int src_offset, int length) { constint start_pc = pc_;
template <Bytecode bytecode, typename... Args> void BytecodeWriter::Emit(Args... args) { using Operands = BytecodeOperands<bytecode>;
static_assert(sizeof...(Args) == Operands::kCount, "Wrong number of operands");
auto arguments_tuple = std::make_tuple(args...);
EmitBytecode(bytecode);
Operands::ForEachOperandWithIndex([&]<auto op, size_t index>() {
constexpr BytecodeOperandType type = Operands::Type(op);
constexpr int offset = Operands::Offset(op); auto value = std::get<index>(arguments_tuple);
EmitOperand<type>(value, offset);
});
Finalize(bytecode);
}
namespace {
// Helper to get the underlying type of an enum, or the type itself if it isn't // an enum. template <typename T> struct get_underlying_or_self { using type = T;
};
template <typename T>
requires std::is_enum_v<T> struct get_underlying_or_self<T> { using type = std::underlying_type_t<T>;
};
} // namespace
template <BytecodeOperandType OperandType, typename T> auto BytecodeWriter::GetCheckedBasicOperandValue(T value) {
static_assert(OperandTypeTraits<OperandType>::kIsBasic); using Traits = OperandTypeTraits<OperandType>; using EnumOrCType = Traits::kCType; using CType = get_underlying_or_self<EnumOrCType>::type; if constexpr (std::is_enum_v<EnumOrCType>) {
static_assert(std::is_same_v<T, EnumOrCType>);
} else {
static_assert(std::is_convertible_v<T, CType>);
}
DCHECK_GE(value, Traits::kMinValue);
DCHECK_LE(value, Traits::kMaxValue); returnstatic_cast<CType>(value);
}
void BytecodeGenerator::LoadCurrentCharacterImpl(int cp_offset,
Label* on_failure, bool check_bounds, int characters, int eats_at_least) {
DCHECK_GE(eats_at_least, characters); if (eats_at_least > characters && check_bounds) { // eats_at_least + cp_offset can overflow BytecodeOperandType::kOffset. // Only emit this optimization if the computed value fits into the expected // range for the CheckPosition BC. using CheckPositionOps = BytecodeOperands<Bytecode::kCheckPosition>; using OffsetTraits =
OperandTypeTraits<CheckPositionOps::Type(CheckPositionOps::cp_offset)>; using OffsetType = OffsetTraits::kCType;
base::internal::CheckedNumeric<OffsetType> checked_offset = cp_offset;
checked_offset += eats_at_least - 1;
OffsetType total_offset; if (checked_offset.AssignIfValid(&total_offset) &&
base::IsInRange(total_offset, OffsetTraits::kMinValue,
OffsetTraits::kMaxValue)) {
Emit<Bytecode::kCheckPosition>(total_offset, on_failure);
check_bounds = false; // Load below doesn't need to check.
}
}
void BytecodeGenerator::CheckCharacterAfterAnd(uint32_t c, uint32_t mask,
Label* on_equal) { // TODO(pthier): This is super hacky. We could still check for 4 characters // (with the last 2 being 0 after masking them), but not emit AndCheck4Chars. // This is rather confusing and should be changed. if (c > kMaxSingleCharValue) {
Emit<Bytecode::kAndCheck4Chars>(c, mask, on_equal);
} else {
Emit<Bytecode::kCheckCharacterAfterAnd>(c, mask, on_equal);
}
}
void BytecodeGenerator::CheckNotCharacterAfterAnd(uint32_t c, uint32_t mask,
Label* on_not_equal) { // TODO(pthier): This is super hacky. We could still check for 4 characters // (with the last 2 being 0 after masking them), but not emit AndCheck4Chars. // This is rather confusing and should be changed. if (c > kMaxSingleCharValue) {
Emit<Bytecode::kAndCheckNot4Chars>(c, mask, on_not_equal);
} else {
Emit<Bytecode::kCheckNotCharacterAfterAnd>(c, mask, on_not_equal);
}
}
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.