#ifndef V8_OBJECTS_INSTRUCTION_STREAM_INL_H_
#define V8_OBJECTS_INSTRUCTION_STREAM_INL_H_
#include "src/objects/instruction-stream.h"
#include <optional>
#include "src/common/ptr-compr-inl.h"
#include "src/heap/heap-layout-inl.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/objects/code.h"
#include "src/objects/objects-inl.h"
#include "src/objects/object-macros.h"
namespace v8::internal {
OBJECT_CONSTRUCTORS_IMPL(InstructionStream, TrustedObject)
uint32_t InstructionStream::body_size() const {
return ReadField<uint32_t>(kBodySizeOffset);
}
#if V8_EMBEDDED_CONSTANT_POOL_BOOL
Address InstructionStream::constant_pool() const {
return address() + ReadField<int>(kConstantPoolOffsetOffset);
}
#else
Address InstructionStream::constant_pool() const { return kNullAddress; }
#endif
Tagged<InstructionStream> InstructionStream::Initialize(
Tagged<HeapObject> self, Tagged<Map> map, uint32_t body_size,
int constant_pool_offset, Tagged<TrustedByteArray> reloc_info) {
{
WritableJitAllocation writable_allocation =
ThreadIsolation::RegisterInstructionStreamAllocation(
self.address(), InstructionStream::SizeFor(body_size));
CHECK_EQ(InstructionStream::SizeFor(body_size), writable_allocation.size());
writable_allocation.WriteHeaderSlot<Map, kMapOffset>(map, kRelaxedStore);
writable_allocation.WriteHeaderSlot<uint32_t, kBodySizeOffset>(body_size);
if constexpr (V8_EMBEDDED_CONSTANT_POOL_BOOL) {
writable_allocation.WriteHeaderSlot<int, kConstantPoolOffsetOffset>(
kHeaderSize + constant_pool_offset);
}
writable_allocation.WriteHeaderSlot<Smi, kCodeOffset>(Smi::zero(),
kReleaseStore);
DCHECK(!HeapLayout::InYoungGeneration(reloc_info));
writable_allocation.WriteProtectedPointerHeaderSlot<TrustedByteArray,
kRelocationInfoOffset>(
reloc_info, kRelaxedStore);
writable_allocation.ClearBytes(kUnalignedSize,
kHeaderSize - kUnalignedSize);
writable_allocation.ClearBytes(kHeaderSize + body_size,
TrailingPaddingSizeFor(body_size));
}
Tagged<InstructionStream> istream = TrustedCast<InstructionStream>(self);
#if V8_VERIFY_WRITE_BARRIERS
if (v8_flags.verify_write_barriers) {
CHECK(!WriteBarrier::IsRequired(istream, map));
}
#endif
CONDITIONAL_PROTECTED_POINTER_WRITE_BARRIER(*istream, kRelocationInfoOffset,
reloc_info, UPDATE_WRITE_BARRIER);
return istream;
}
void InstructionStream::Finalize(Tagged<Code> code,
Tagged<TrustedByteArray> reloc_info,
CodeDesc desc, Heap* heap) {
DisallowGarbageCollection no_gc;
std::optional<WriteBarrierPromise> promise;
DCHECK_EQ(reloc_info->length(), desc.reloc_size);
CopyBytes(reloc_info->begin(), desc.buffer + desc.reloc_offset,
static_cast<size_t>(desc.reloc_size));
{
WritableJitAllocation writable_allocation =
ThreadIsolation::LookupJitAllocation(
address(), InstructionStream::SizeFor(body_size()),
ThreadIsolation::JitAllocationType::kInstructionStream, true);
static_assert(InstructionStream::kOnHeapBodyIsContiguous);
writable_allocation.CopyCode(kHeaderSize, desc.buffer,
static_cast<size_t>(desc.instr_size));
writable_allocation.CopyData(kHeaderSize + desc.instr_size,
desc.unwinding_info,
static_cast<size_t>(desc.unwinding_info_size));
DCHECK_EQ(desc.body_size(), desc.instr_size + desc.unwinding_info_size);
DCHECK_EQ(code->body_size(),
code->instruction_size() + code->metadata_size());
promise.emplace(RelocateFromDesc(writable_allocation, heap, desc,
code->constant_pool(), no_gc));
writable_allocation.WriteProtectedPointerHeaderSlot<Code, kCodeOffset>(
code, kReleaseStore);
}
RelocateFromDescWriteBarriers(heap, desc, code->constant_pool(), *promise,
no_gc);
CONDITIONAL_PROTECTED_POINTER_WRITE_BARRIER(*this, kCodeOffset, code,
UPDATE_WRITE_BARRIER);
code->FlushICache();
}
bool InstructionStream::IsFullyInitialized() {
return raw_code(kAcquireLoad) != Smi::zero();
}
Address InstructionStream::body_end() const {
static_assert(kOnHeapBodyIsContiguous);
return instruction_start() + body_size();
}
Tagged<Object> InstructionStream::raw_code(AcquireLoadTag tag) const {
Tagged<Object> value = RawProtectedPointerField(kCodeOffset).Acquire_Load();
DCHECK(!HeapLayout::InYoungGeneration(value));
DCHECK(IsSmi(value) ||
TrustedHeapLayout::InTrustedSpace(Cast<HeapObject>(value)));
return value;
}
Tagged<Code> InstructionStream::code(AcquireLoadTag tag) const {
return TrustedCast<Code>(raw_code(tag));
}
bool InstructionStream::TryGetCode(Tagged<Code>* code_out,
AcquireLoadTag tag) const {
Tagged<Object> maybe_code = raw_code(tag);
if (maybe_code == Smi::zero()) return false;
return TryCast(maybe_code, code_out);
}
bool InstructionStream::TryGetCodeUnchecked(Tagged<Code>* code_out,
AcquireLoadTag tag) const {
Tagged<Object> maybe_code = raw_code(tag);
if (maybe_code == Smi::zero()) return false;
*code_out = UncheckedCast<Code>(maybe_code);
return true;
}
Tagged<TrustedByteArray> InstructionStream::relocation_info() const {
return ReadProtectedPointerField<TrustedByteArray>(kRelocationInfoOffset);
}
Address InstructionStream::instruction_start() const {
return field_address(kHeaderSize);
}
Tagged<TrustedByteArray> InstructionStream::unchecked_relocation_info() const {
Tagged<Object> value =
RawProtectedPointerField(kRelocationInfoOffset).Acquire_Load();
return UncheckedCast<TrustedByteArray>(value);
}
uint8_t* InstructionStream::relocation_start() const {
return relocation_info()->begin();
}
uint8_t* InstructionStream::relocation_end() const {
return relocation_info()->end();
}
int InstructionStream::relocation_size() const {
return relocation_info()->length();
}
int InstructionStream::Size() const { return SizeFor(body_size()); }
Tagged<InstructionStream> InstructionStream::FromTargetAddress(
Address address) {
{
Address start =
reinterpret_cast<Address>(Isolate::CurrentEmbeddedBlobCode());
Address end = start + Isolate::CurrentEmbeddedBlobCodeSize();
CHECK(address < start || address >= end);
}
Tagged<HeapObject> code =
HeapObject::FromAddress(address - InstructionStream::kHeaderSize);
return UncheckedCast<InstructionStream>(code);
}
Tagged<InstructionStream> InstructionStream::FromEntryAddress(
Address location_of_address) {
Address code_entry = base::Memory<Address>(location_of_address);
Tagged<HeapObject> code =
HeapObject::FromAddress(code_entry - InstructionStream::kHeaderSize);
return UncheckedCast<InstructionStream>(code);
}
PtrComprCageBase InstructionStream::main_cage_base() {
#ifdef V8_COMPRESS_POINTERS
return PtrComprCageBase{V8HeapCompressionScheme::base()};
#else
return PtrComprCageBase{};
#endif
}
}
#include "src/objects/object-macros-undef.h"
#endif