blob: ee727aff9ce20d76f6056d63905cb3e0a9a75294 [file] [log] [blame]
// Copyright 2024 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_DEOPT_DATA_H_
#define V8_WASM_WASM_DEOPT_DATA_H_
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif // !V8_ENABLE_WEBASSEMBLY
#include "src/base/memory.h"
#include "src/utils/utils.h"
#include "src/wasm/baseline/liftoff-varstate.h"
#include "src/zone/zone-containers.h"
namespace v8::internal {
class DeoptimizationLiteral;
}
namespace v8::internal::wasm {
// The "header" of the full deopt data for an optimized wasm function containing
// overall counts used to access the unerlying translated values, literals etc.
struct WasmDeoptData {
uint32_t entry_count = 0; // Count of deopt points.
uint32_t translation_array_size = 0;
uint32_t deopt_literals_size = 0;
// The offset inside the code to the first deopt builtin call instruction.
// This is used to map a pc back to a the "deopt index".
int deopt_exit_start_offset = 0;
// The count of eager deopt points.
int eager_deopt_count = 0;
};
struct WasmDeoptEntry {
// The wire bytes offset of the deopt point. This is used to map a deopt entry
// to a liftoff deopt point.
BytecodeOffset bytecode_offset = BytecodeOffset::None();
// The index inside the translations array at which this deopt entry starts.
// (The translations array is shared for all deopt points of a function.)
int translation_index = -1;
};
// A view to access the deopt data stored in the WasmCode's metadata as raw
// bytes.
class WasmDeoptView {
public:
explicit WasmDeoptView(base::Vector<const uint8_t> deopt_data)
: deopt_data_(deopt_data) {
if (!deopt_data.empty()) {
static_assert(std::is_trivially_copy_assignable_v<WasmDeoptData>);
DCHECK_GE(deopt_data_.size(), sizeof(WasmDeoptData));
std::memcpy(&base_data_, deopt_data_.begin(), sizeof(base_data_));
}
}
bool HasDeoptData() const { return !deopt_data_.empty(); }
const WasmDeoptData& GetDeoptData() const {
DCHECK(HasDeoptData());
return base_data_;
}
base::Vector<const uint8_t> GetTranslationsArray() const {
DCHECK(HasDeoptData());
return {deopt_data_.begin() + sizeof(base_data_),
base_data_.translation_array_size};
}
WasmDeoptEntry GetDeoptEntry(uint32_t deopt_index) const {
DCHECK(HasDeoptData());
DCHECK(deopt_index < base_data_.entry_count);
const uint8_t* begin = deopt_data_.begin() + sizeof(base_data_) +
base_data_.translation_array_size;
return base::ReadUnalignedValue<WasmDeoptEntry>(reinterpret_cast<Address>(
begin + sizeof(WasmDeoptEntry) * deopt_index));
}
std::vector<DeoptimizationLiteral> BuildDeoptimizationLiteralArray();
private:
base::Vector<const uint8_t> deopt_data_;
WasmDeoptData base_data_;
};
class WasmDeoptDataProcessor {
public:
static base::OwnedVector<uint8_t> Serialize(
int deopt_exit_start_offset, int eager_deopt_count,
base::Vector<const uint8_t> translation_array,
base::Vector<wasm::WasmDeoptEntry> deopt_entries,
const ZoneDeque<DeoptimizationLiteral>& deopt_literals);
};
// All the information needed by the deoptimizer to know what the Liftoff frame
// has to look like.
struct LiftoffFrameDescriptionForDeopt {
uint32_t wire_bytes_offset = 0;
uint32_t pc_offset = 0;
#ifdef V8_ENABLE_CET_SHADOW_STACK
uint32_t adapt_shadow_stack_pc_offset = 0;
#endif // V8_ENABLE_CET_SHADOW_STACK
std::vector<LiftoffVarState> var_state = {};
// If the trusted_instance is cached in a register additionally to the stack
// slot, this register needs to be updated as well.
Register trusted_instance = no_reg;
int total_frame_size = 0;
};
} // namespace v8::internal::wasm
#endif // V8_WASM_WASM_DEOPT_DATA_H_