#include "src/objects/instruction-stream.h"
#include "src/builtins/builtins-inl.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/flush-instruction-cache.h"
#include "src/codegen/reloc-info-inl.h"
#include "src/codegen/reloc-info.h"
#include "src/objects/instruction-stream-inl.h"
#include "src/objects/objects.h"
namespace v8 {
namespace internal {
void InstructionStream::Relocate(WritableJitAllocation& jit_allocation,
intptr_t delta) {
Tagged<Code> code;
if (!TryGetCodeUnchecked(&code, kAcquireLoad)) return;
for (WritableRelocIterator it(jit_allocation, *this, constant_pool(),
RelocInfo::kApplyMask);
!it.done(); it.next()) {
it.rinfo()->apply(delta);
}
FlushInstructionCache(instruction_start(), body_size());
}
InstructionStream::WriteBarrierPromise InstructionStream::RelocateFromDesc(
WritableJitAllocation& jit_allocation, Heap* heap, const CodeDesc& desc,
Address constant_pool, const DisallowGarbageCollection& no_gc) {
WriteBarrierPromise write_barrier_promise(*this);
Assembler* origin = desc.origin;
const int mode_mask = RelocInfo::PostCodegenRelocationMask();
for (WritableRelocIterator it(jit_allocation, *this, constant_pool,
mode_mask);
!it.done(); it.next()) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (RelocInfo::IsEmbeddedObjectMode(mode)) {
DirectHandle<HeapObject> p = it.rinfo()->target_object_handle(origin);
it.rinfo()->set_target_object(*this, *p, SKIP_WRITE_BARRIER_SCOPE,
SKIP_ICACHE_FLUSH);
write_barrier_promise.RegisterAddress(it.rinfo()->pc());
} else if (RelocInfo::IsCodeTargetMode(mode)) {
DirectHandle<HeapObject> p = it.rinfo()->target_object_handle(origin);
Tagged<InstructionStream> target_istream =
TrustedCast<Code>(*p)->instruction_stream();
it.rinfo()->set_target_address(*this, target_istream->instruction_start(),
SKIP_WRITE_BARRIER_SCOPE,
SKIP_ICACHE_FLUSH);
write_barrier_promise.RegisterAddress(it.rinfo()->pc());
} else if (RelocInfo::IsNearBuiltinEntry(mode)) {
Builtin builtin = it.rinfo()->target_builtin_at(origin);
Address p = Builtins::EntryOf(builtin, heap->isolate());
it.rinfo()->set_target_address(*this, p, UPDATE_WRITE_BARRIER,
SKIP_ICACHE_FLUSH);
DCHECK_EQ(p, it.rinfo()->target_address());
} else if (RelocInfo::IsWasmStubCall(mode)) {
#if V8_ENABLE_WEBASSEMBLY
uint32_t stub_call_tag = it.rinfo()->wasm_call_tag();
DCHECK_LT(stub_call_tag,
static_cast<uint32_t>(Builtin::kFirstBytecodeHandler));
Builtin builtin = static_cast<Builtin>(stub_call_tag);
Address entry = Builtins::EntryOf(builtin, heap->isolate());
it.rinfo()->set_wasm_stub_call_address(entry);
#else
UNREACHABLE();
#endif
} else {
intptr_t delta =
instruction_start() - reinterpret_cast<Address>(desc.buffer);
it.rinfo()->apply(delta);
}
}
return write_barrier_promise;
}
void InstructionStream::RelocateFromDescWriteBarriers(
Heap* heap, const CodeDesc& desc, Address constant_pool,
WriteBarrierPromise& write_barrier_promise,
const DisallowGarbageCollection& no_gc) {
const int mode_mask = RelocInfo::PostCodegenRelocationMask();
for (RelocIterator it(code(kAcquireLoad), mode_mask); !it.done(); it.next()) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (RelocInfo::IsEmbeddedObjectMode(mode)) {
Tagged<HeapObject> p = it.rinfo()->target_object(heap->isolate());
WriteBarrier::ForRelocInfo(*this, it.rinfo(), p, UPDATE_WRITE_BARRIER);
write_barrier_promise.ResolveAddress(it.rinfo()->pc());
} else if (RelocInfo::IsCodeTargetMode(mode)) {
Tagged<InstructionStream> target_istream =
InstructionStream::FromTargetAddress(it.rinfo()->target_address());
WriteBarrier::ForRelocInfo(*this, it.rinfo(), target_istream,
UPDATE_WRITE_BARRIER);
write_barrier_promise.ResolveAddress(it.rinfo()->pc());
}
}
}
#ifdef DEBUG
void InstructionStream::WriteBarrierPromise::RegisterAddress(Address address) {
DCHECK(delayed_write_barriers_.insert(address).second);
}
void InstructionStream::WriteBarrierPromise::ResolveAddress(Address address) {
DCHECK_EQ(delayed_write_barriers_.erase(address), 1);
}
InstructionStream::WriteBarrierPromise::~WriteBarrierPromise() {
DCHECK(delayed_write_barriers_.empty());
}
#endif
}
}