// Copyright 2012 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_X64_ASSEMBLER_X64_INL_H_ #define V8_X64_ASSEMBLER_X64_INL_H_ #include "src/x64/assembler-x64.h" #include "src/base/cpu.h" #include "src/debug/debug.h" #include "src/objects-inl.h" #include "src/v8memory.h" namespace v8 { namespace internal { bool CpuFeatures::SupportsOptimizer() { return true; } bool CpuFeatures::SupportsWasmSimd128() { return IsSupported(SSE4_1); } // ----------------------------------------------------------------------------- // Implementation of Assembler void Assembler::emitl(uint32_t x) { Memory::uint32_at(reinterpret_cast
(pc_)) = x; pc_ += sizeof(uint32_t); } void Assembler::emitp(Address x, RelocInfo::Mode rmode) { Memory::uintptr_at(reinterpret_cast(pc_)) = x; if (!RelocInfo::IsNone(rmode)) { RecordRelocInfo(rmode, x); } pc_ += sizeof(uintptr_t); } void Assembler::emitq(uint64_t x) { Memory::uint64_at(reinterpret_cast(pc_)) = x; pc_ += sizeof(uint64_t); } void Assembler::emitw(uint16_t x) { Memory::uint16_at(reinterpret_cast(pc_)) = x; pc_ += sizeof(uint16_t); } void Assembler::emit_runtime_entry(Address entry, RelocInfo::Mode rmode) { DCHECK(RelocInfo::IsRuntimeEntry(rmode)); RecordRelocInfo(rmode); emitl(static_cast Assembler::code_target_object_handle_at(Address pc) {
return GetCodeTarget(Memory::int32_at(pc));
}
Address Assembler::runtime_entry_at(Address pc) {
return Memory::int32_at(pc) + options().code_range_start;
}
// -----------------------------------------------------------------------------
// Implementation of RelocInfo
// The modes possibly affected by apply must be in kApplyMask.
void RelocInfo::apply(intptr_t delta) {
if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
Memory::int32_at(pc_) -= static_cast(delta);
} else if (IsInternalReference(rmode_)) {
// absolute code pointer inside code object moves with the code object.
Memory::Address_at(pc_) += delta;
}
}
Address RelocInfo::target_address() {
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_));
return Assembler::target_address_at(pc_, constant_pool_);
}
Address RelocInfo::target_address_address() {
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
IsWasmStubCall(rmode_) || IsEmbeddedObject(rmode_) ||
IsExternalReference(rmode_) || IsOffHeapTarget(rmode_));
return pc_;
}
Address RelocInfo::constant_pool_entry_address() {
UNREACHABLE();
}
int RelocInfo::target_address_size() {
if (IsCodedSpecially()) {
return Assembler::kSpecialTargetSize;
} else {
return kPointerSize;
}
}
HeapObject* RelocInfo::target_object() {
DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
return HeapObject::cast(Memory::Object_at(pc_));
}
Handle RelocInfo::target_object_handle(Assembler* origin) {
DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
if (rmode_ == EMBEDDED_OBJECT) {
return Handle::cast(Memory::Object_Handle_at(pc_));
} else {
return origin->code_target_object_handle_at(pc_);
}
}
Address RelocInfo::target_external_reference() {
DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
void RelocInfo::set_target_external_reference(
Address target, ICacheFlushMode icache_flush_mode) {
DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
Memory::Address_at(pc_) = target;
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Assembler::FlushICache(pc_, sizeof(Address));
}
}
Address RelocInfo::target_internal_reference() {
DCHECK(rmode_ == INTERNAL_REFERENCE);
return Memory::Address_at(pc_);
}
Address RelocInfo::target_internal_reference_address() {
DCHECK(rmode_ == INTERNAL_REFERENCE);
return pc_;
}
void RelocInfo::set_target_object(Heap* heap, HeapObject* target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
Memory::Object_at(pc_) = target;
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Assembler::FlushICache(pc_, sizeof(Address));
}
if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != nullptr) {
heap->incremental_marking()->RecordWriteIntoCode(host(), this, target);
heap->RecordWriteIntoCode(host(), this, target);
}
}
Address RelocInfo::target_runtime_entry(Assembler* origin) {
DCHECK(IsRuntimeEntry(rmode_));
return origin->runtime_entry_at(pc_);
}
void RelocInfo::set_target_runtime_entry(Address target,
WriteBarrierMode write_barrier_mode,
ICacheFlushMode icache_flush_mode) {
DCHECK(IsRuntimeEntry(rmode_));
if (target_address() != target) {
set_target_address(target, write_barrier_mode, icache_flush_mode);
}
}
Address RelocInfo::target_off_heap_target() {
DCHECK(IsOffHeapTarget(rmode_));
return Memory::Address_at(pc_);
}
void RelocInfo::WipeOut() {
if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
IsInternalReference(rmode_)) {
Memory::Address_at(pc_) = kNullAddress;
} else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
// Effectively write zero into the relocation.
Assembler::set_target_address_at(pc_, constant_pool_,
pc_ + sizeof(int32_t));
} else {
UNREACHABLE();
}
}
template
void RelocInfo::Visit(ObjectVisitor* visitor) {
RelocInfo::Mode mode = rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
visitor->VisitEmbeddedPointer(host(), this);
Assembler::FlushICache(pc_, sizeof(Address));
} else if (RelocInfo::IsCodeTargetMode(mode)) {
visitor->VisitCodeTarget(host(), this);
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
visitor->VisitExternalReference(host(), this);
} else if (mode == RelocInfo::INTERNAL_REFERENCE) {
visitor->VisitInternalReference(host(), this);
} else if (RelocInfo::IsRuntimeEntry(mode)) {
visitor->VisitRuntimeEntry(host(), this);
} else if (RelocInfo::IsOffHeapTarget(mode)) {
visitor->VisitOffHeapTarget(host(), this);
}
}
} // namespace internal
} // namespace v8
#endif // V8_X64_ASSEMBLER_X64_INL_H_