[assembler] Move reloc info to its own file
This reduced the number of targets depending on assembler.h from ~900 to ~350. Bug: v8:8054 Change-Id: I74ae2ce7a4b27791d0ee25542ee0b2175bedf5f7 Reviewed-on: https://chromium-review.googlesource.com/1174534 Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#55188}
This commit is contained in:
parent
4e686686ec
commit
5e59e5c0f8
3
BUILD.gn
3
BUILD.gn
@ -1525,6 +1525,7 @@ v8_source_set("v8_base") {
|
||||
"src/asmjs/asm-types.h",
|
||||
"src/asmjs/switch-logic.cc",
|
||||
"src/asmjs/switch-logic.h",
|
||||
"src/assembler-arch-inl.h",
|
||||
"src/assembler-arch.h",
|
||||
"src/assembler-inl.h",
|
||||
"src/assembler.cc",
|
||||
@ -2324,6 +2325,8 @@ v8_source_set("v8_base") {
|
||||
"src/register-configuration.cc",
|
||||
"src/register-configuration.h",
|
||||
"src/reglist.h",
|
||||
"src/reloc-info.cc",
|
||||
"src/reloc-info.h",
|
||||
"src/roots-inl.h",
|
||||
"src/roots.h",
|
||||
"src/runtime-profiler.cc",
|
||||
|
30
src/assembler-arch-inl.h
Normal file
30
src/assembler-arch-inl.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2018 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_ASSEMBLER_ARCH_INL_H_
|
||||
#define V8_ASSEMBLER_ARCH_INL_H_
|
||||
|
||||
#include "src/assembler-inl.h"
|
||||
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
#include "src/ia32/assembler-ia32-inl.h"
|
||||
#elif V8_TARGET_ARCH_X64
|
||||
#include "src/x64/assembler-x64-inl.h"
|
||||
#elif V8_TARGET_ARCH_ARM64
|
||||
#include "src/arm64/assembler-arm64-inl.h"
|
||||
#elif V8_TARGET_ARCH_ARM
|
||||
#include "src/arm/assembler-arm-inl.h"
|
||||
#elif V8_TARGET_ARCH_PPC
|
||||
#include "src/ppc/assembler-ppc-inl.h"
|
||||
#elif V8_TARGET_ARCH_MIPS
|
||||
#include "src/mips/assembler-mips-inl.h"
|
||||
#elif V8_TARGET_ARCH_MIPS64
|
||||
#include "src/mips64/assembler-mips64-inl.h"
|
||||
#elif V8_TARGET_ARCH_S390
|
||||
#include "src/s390/assembler-s390-inl.h"
|
||||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
|
||||
#endif // V8_ASSEMBLER_ARCH_INL_H_
|
528
src/assembler.cc
528
src/assembler.cc
@ -48,8 +48,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
|
||||
|
||||
AssemblerOptions AssemblerOptions::Default(
|
||||
Isolate* isolate, bool explicitly_support_serialization) {
|
||||
AssemblerOptions options;
|
||||
@ -149,532 +147,6 @@ unsigned CpuFeatures::supported_ = 0;
|
||||
unsigned CpuFeatures::icache_line_size_ = 0;
|
||||
unsigned CpuFeatures::dcache_line_size_ = 0;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of RelocInfoWriter and RelocIterator
|
||||
//
|
||||
// Relocation information is written backwards in memory, from high addresses
|
||||
// towards low addresses, byte by byte. Therefore, in the encodings listed
|
||||
// below, the first byte listed it at the highest address, and successive
|
||||
// bytes in the record are at progressively lower addresses.
|
||||
//
|
||||
// Encoding
|
||||
//
|
||||
// The most common modes are given single-byte encodings. Also, it is
|
||||
// easy to identify the type of reloc info and skip unwanted modes in
|
||||
// an iteration.
|
||||
//
|
||||
// The encoding relies on the fact that there are fewer than 14
|
||||
// different relocation modes using standard non-compact encoding.
|
||||
//
|
||||
// The first byte of a relocation record has a tag in its low 2 bits:
|
||||
// Here are the record schemes, depending on the low tag and optional higher
|
||||
// tags.
|
||||
//
|
||||
// Low tag:
|
||||
// 00: embedded_object: [6-bit pc delta] 00
|
||||
//
|
||||
// 01: code_target: [6-bit pc delta] 01
|
||||
//
|
||||
// 10: wasm_stub_call: [6-bit pc delta] 10
|
||||
//
|
||||
// 11: long_record [6 bit reloc mode] 11
|
||||
// followed by pc delta
|
||||
// followed by optional data depending on type.
|
||||
//
|
||||
// If a pc delta exceeds 6 bits, it is split into a remainder that fits into
|
||||
// 6 bits and a part that does not. The latter is encoded as a long record
|
||||
// with PC_JUMP as pseudo reloc info mode. The former is encoded as part of
|
||||
// the following record in the usual way. The long pc jump record has variable
|
||||
// length:
|
||||
// pc-jump: [PC_JUMP] 11
|
||||
// [7 bits data] 0
|
||||
// ...
|
||||
// [7 bits data] 1
|
||||
// (Bits 6..31 of pc delta, with leading zeroes
|
||||
// dropped, and last non-zero chunk tagged with 1.)
|
||||
|
||||
const int kTagBits = 2;
|
||||
const int kTagMask = (1 << kTagBits) - 1;
|
||||
const int kLongTagBits = 6;
|
||||
|
||||
const int kEmbeddedObjectTag = 0;
|
||||
const int kCodeTargetTag = 1;
|
||||
const int kWasmStubCallTag = 2;
|
||||
const int kDefaultTag = 3;
|
||||
|
||||
const int kSmallPCDeltaBits = kBitsPerByte - kTagBits;
|
||||
const int kSmallPCDeltaMask = (1 << kSmallPCDeltaBits) - 1;
|
||||
const int RelocInfo::kMaxSmallPCDelta = kSmallPCDeltaMask;
|
||||
|
||||
const int kChunkBits = 7;
|
||||
const int kChunkMask = (1 << kChunkBits) - 1;
|
||||
const int kLastChunkTagBits = 1;
|
||||
const int kLastChunkTagMask = 1;
|
||||
const int kLastChunkTag = 1;
|
||||
|
||||
uint32_t RelocInfoWriter::WriteLongPCJump(uint32_t pc_delta) {
|
||||
// Return if the pc_delta can fit in kSmallPCDeltaBits bits.
|
||||
// Otherwise write a variable length PC jump for the bits that do
|
||||
// not fit in the kSmallPCDeltaBits bits.
|
||||
if (is_uintn(pc_delta, kSmallPCDeltaBits)) return pc_delta;
|
||||
WriteMode(RelocInfo::PC_JUMP);
|
||||
uint32_t pc_jump = pc_delta >> kSmallPCDeltaBits;
|
||||
DCHECK_GT(pc_jump, 0);
|
||||
// Write kChunkBits size chunks of the pc_jump.
|
||||
for (; pc_jump > 0; pc_jump = pc_jump >> kChunkBits) {
|
||||
byte b = pc_jump & kChunkMask;
|
||||
*--pos_ = b << kLastChunkTagBits;
|
||||
}
|
||||
// Tag the last chunk so it can be identified.
|
||||
*pos_ = *pos_ | kLastChunkTag;
|
||||
// Return the remaining kSmallPCDeltaBits of the pc_delta.
|
||||
return pc_delta & kSmallPCDeltaMask;
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteShortTaggedPC(uint32_t pc_delta, int tag) {
|
||||
// Write a byte of tagged pc-delta, possibly preceded by an explicit pc-jump.
|
||||
pc_delta = WriteLongPCJump(pc_delta);
|
||||
*--pos_ = pc_delta << kTagBits | tag;
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteShortData(intptr_t data_delta) {
|
||||
*--pos_ = static_cast<byte>(data_delta);
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteMode(RelocInfo::Mode rmode) {
|
||||
STATIC_ASSERT(RelocInfo::NUMBER_OF_MODES <= (1 << kLongTagBits));
|
||||
*--pos_ = static_cast<int>((rmode << kTagBits) | kDefaultTag);
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteModeAndPC(uint32_t pc_delta, RelocInfo::Mode rmode) {
|
||||
// Write two-byte tagged pc-delta, possibly preceded by var. length pc-jump.
|
||||
pc_delta = WriteLongPCJump(pc_delta);
|
||||
WriteMode(rmode);
|
||||
*--pos_ = pc_delta;
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteIntData(int number) {
|
||||
for (int i = 0; i < kIntSize; i++) {
|
||||
*--pos_ = static_cast<byte>(number);
|
||||
// Signed right shift is arithmetic shift. Tested in test-utils.cc.
|
||||
number = number >> kBitsPerByte;
|
||||
}
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteData(intptr_t data_delta) {
|
||||
for (int i = 0; i < kIntptrSize; i++) {
|
||||
*--pos_ = static_cast<byte>(data_delta);
|
||||
// Signed right shift is arithmetic shift. Tested in test-utils.cc.
|
||||
data_delta = data_delta >> kBitsPerByte;
|
||||
}
|
||||
}
|
||||
|
||||
void RelocInfoWriter::Write(const RelocInfo* rinfo) {
|
||||
RelocInfo::Mode rmode = rinfo->rmode();
|
||||
#ifdef DEBUG
|
||||
byte* begin_pos = pos_;
|
||||
#endif
|
||||
DCHECK(rinfo->rmode() < RelocInfo::NUMBER_OF_MODES);
|
||||
DCHECK_GE(rinfo->pc() - reinterpret_cast<Address>(last_pc_), 0);
|
||||
// Use unsigned delta-encoding for pc.
|
||||
uint32_t pc_delta =
|
||||
static_cast<uint32_t>(rinfo->pc() - reinterpret_cast<Address>(last_pc_));
|
||||
|
||||
// The two most common modes are given small tags, and usually fit in a byte.
|
||||
if (rmode == RelocInfo::EMBEDDED_OBJECT) {
|
||||
WriteShortTaggedPC(pc_delta, kEmbeddedObjectTag);
|
||||
} else if (rmode == RelocInfo::CODE_TARGET) {
|
||||
WriteShortTaggedPC(pc_delta, kCodeTargetTag);
|
||||
DCHECK_LE(begin_pos - pos_, RelocInfo::kMaxCallSize);
|
||||
} else if (rmode == RelocInfo::WASM_STUB_CALL) {
|
||||
WriteShortTaggedPC(pc_delta, kWasmStubCallTag);
|
||||
} else {
|
||||
WriteModeAndPC(pc_delta, rmode);
|
||||
if (RelocInfo::IsComment(rmode)) {
|
||||
WriteData(rinfo->data());
|
||||
} else if (RelocInfo::IsDeoptReason(rmode)) {
|
||||
DCHECK_LT(rinfo->data(), 1 << kBitsPerByte);
|
||||
WriteShortData(rinfo->data());
|
||||
} else if (RelocInfo::IsConstPool(rmode) ||
|
||||
RelocInfo::IsVeneerPool(rmode) || RelocInfo::IsDeoptId(rmode) ||
|
||||
RelocInfo::IsDeoptPosition(rmode)) {
|
||||
WriteIntData(static_cast<int>(rinfo->data()));
|
||||
}
|
||||
}
|
||||
last_pc_ = reinterpret_cast<byte*>(rinfo->pc());
|
||||
#ifdef DEBUG
|
||||
DCHECK_LE(begin_pos - pos_, kMaxSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int RelocIterator::AdvanceGetTag() {
|
||||
return *--pos_ & kTagMask;
|
||||
}
|
||||
|
||||
inline RelocInfo::Mode RelocIterator::GetMode() {
|
||||
return static_cast<RelocInfo::Mode>((*pos_ >> kTagBits) &
|
||||
((1 << kLongTagBits) - 1));
|
||||
}
|
||||
|
||||
inline void RelocIterator::ReadShortTaggedPC() {
|
||||
rinfo_.pc_ += *pos_ >> kTagBits;
|
||||
}
|
||||
|
||||
inline void RelocIterator::AdvanceReadPC() {
|
||||
rinfo_.pc_ += *--pos_;
|
||||
}
|
||||
|
||||
void RelocIterator::AdvanceReadInt() {
|
||||
int x = 0;
|
||||
for (int i = 0; i < kIntSize; i++) {
|
||||
x |= static_cast<int>(*--pos_) << i * kBitsPerByte;
|
||||
}
|
||||
rinfo_.data_ = x;
|
||||
}
|
||||
|
||||
void RelocIterator::AdvanceReadData() {
|
||||
intptr_t x = 0;
|
||||
for (int i = 0; i < kIntptrSize; i++) {
|
||||
x |= static_cast<intptr_t>(*--pos_) << i * kBitsPerByte;
|
||||
}
|
||||
rinfo_.data_ = x;
|
||||
}
|
||||
|
||||
void RelocIterator::AdvanceReadLongPCJump() {
|
||||
// Read the 32-kSmallPCDeltaBits most significant bits of the
|
||||
// pc jump in kChunkBits bit chunks and shift them into place.
|
||||
// Stop when the last chunk is encountered.
|
||||
uint32_t pc_jump = 0;
|
||||
for (int i = 0; i < kIntSize; i++) {
|
||||
byte pc_jump_part = *--pos_;
|
||||
pc_jump |= (pc_jump_part >> kLastChunkTagBits) << i * kChunkBits;
|
||||
if ((pc_jump_part & kLastChunkTagMask) == 1) break;
|
||||
}
|
||||
// The least significant kSmallPCDeltaBits bits will be added
|
||||
// later.
|
||||
rinfo_.pc_ += pc_jump << kSmallPCDeltaBits;
|
||||
}
|
||||
|
||||
inline void RelocIterator::ReadShortData() {
|
||||
uint8_t unsigned_b = *pos_;
|
||||
rinfo_.data_ = unsigned_b;
|
||||
}
|
||||
|
||||
void RelocIterator::next() {
|
||||
DCHECK(!done());
|
||||
// Basically, do the opposite of RelocInfoWriter::Write.
|
||||
// Reading of data is as far as possible avoided for unwanted modes,
|
||||
// but we must always update the pc.
|
||||
//
|
||||
// We exit this loop by returning when we find a mode we want.
|
||||
while (pos_ > end_) {
|
||||
int tag = AdvanceGetTag();
|
||||
if (tag == kEmbeddedObjectTag) {
|
||||
ReadShortTaggedPC();
|
||||
if (SetMode(RelocInfo::EMBEDDED_OBJECT)) return;
|
||||
} else if (tag == kCodeTargetTag) {
|
||||
ReadShortTaggedPC();
|
||||
if (SetMode(RelocInfo::CODE_TARGET)) return;
|
||||
} else if (tag == kWasmStubCallTag) {
|
||||
ReadShortTaggedPC();
|
||||
if (SetMode(RelocInfo::WASM_STUB_CALL)) return;
|
||||
} else {
|
||||
DCHECK_EQ(tag, kDefaultTag);
|
||||
RelocInfo::Mode rmode = GetMode();
|
||||
if (rmode == RelocInfo::PC_JUMP) {
|
||||
AdvanceReadLongPCJump();
|
||||
} else {
|
||||
AdvanceReadPC();
|
||||
if (RelocInfo::IsComment(rmode)) {
|
||||
if (SetMode(rmode)) {
|
||||
AdvanceReadData();
|
||||
return;
|
||||
}
|
||||
Advance(kIntptrSize);
|
||||
} else if (RelocInfo::IsDeoptReason(rmode)) {
|
||||
Advance();
|
||||
if (SetMode(rmode)) {
|
||||
ReadShortData();
|
||||
return;
|
||||
}
|
||||
} else if (RelocInfo::IsConstPool(rmode) ||
|
||||
RelocInfo::IsVeneerPool(rmode) ||
|
||||
RelocInfo::IsDeoptId(rmode) ||
|
||||
RelocInfo::IsDeoptPosition(rmode)) {
|
||||
if (SetMode(rmode)) {
|
||||
AdvanceReadInt();
|
||||
return;
|
||||
}
|
||||
Advance(kIntSize);
|
||||
} else if (SetMode(static_cast<RelocInfo::Mode>(rmode))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
done_ = true;
|
||||
}
|
||||
|
||||
RelocIterator::RelocIterator(Code* code, int mode_mask)
|
||||
: RelocIterator(code, code->raw_instruction_start(), code->constant_pool(),
|
||||
code->relocation_end(), code->relocation_start(),
|
||||
mode_mask) {}
|
||||
|
||||
RelocIterator::RelocIterator(const CodeReference code_reference, int mode_mask)
|
||||
: RelocIterator(nullptr, code_reference.instruction_start(),
|
||||
code_reference.constant_pool(),
|
||||
code_reference.relocation_end(),
|
||||
code_reference.relocation_start(), mode_mask) {}
|
||||
|
||||
RelocIterator::RelocIterator(EmbeddedData* embedded_data, Code* code,
|
||||
int mode_mask)
|
||||
: RelocIterator(
|
||||
code, embedded_data->InstructionStartOfBuiltin(code->builtin_index()),
|
||||
code->constant_pool(),
|
||||
code->relocation_start() + code->relocation_size(),
|
||||
code->relocation_start(), mode_mask) {}
|
||||
|
||||
RelocIterator::RelocIterator(const CodeDesc& desc, int mode_mask)
|
||||
: RelocIterator(nullptr, reinterpret_cast<Address>(desc.buffer), 0,
|
||||
desc.buffer + desc.buffer_size,
|
||||
desc.buffer + desc.buffer_size - desc.reloc_size,
|
||||
mode_mask) {}
|
||||
|
||||
RelocIterator::RelocIterator(Vector<byte> instructions,
|
||||
Vector<const byte> reloc_info, Address const_pool,
|
||||
int mode_mask)
|
||||
: RelocIterator(nullptr, reinterpret_cast<Address>(instructions.start()),
|
||||
const_pool, reloc_info.start() + reloc_info.size(),
|
||||
reloc_info.start(), mode_mask) {}
|
||||
|
||||
RelocIterator::RelocIterator(Code* host, Address pc, Address constant_pool,
|
||||
const byte* pos, const byte* end, int mode_mask)
|
||||
: pos_(pos), end_(end), mode_mask_(mode_mask) {
|
||||
// Relocation info is read backwards.
|
||||
DCHECK_GE(pos_, end_);
|
||||
rinfo_.host_ = host;
|
||||
rinfo_.pc_ = pc;
|
||||
rinfo_.constant_pool_ = constant_pool;
|
||||
if (mode_mask_ == 0) pos_ = end_;
|
||||
next();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of RelocInfo
|
||||
|
||||
// static
|
||||
bool RelocInfo::OffHeapTargetIsCodedSpecially() {
|
||||
#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_ARM64) || \
|
||||
defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_IA32)
|
||||
return false;
|
||||
#elif defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64) || \
|
||||
defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_S390)
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
Address RelocInfo::wasm_call_address() const {
|
||||
DCHECK_EQ(rmode_, WASM_CALL);
|
||||
return Assembler::target_address_at(pc_, constant_pool_);
|
||||
}
|
||||
|
||||
void RelocInfo::set_wasm_call_address(Address address,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
DCHECK_EQ(rmode_, WASM_CALL);
|
||||
Assembler::set_target_address_at(pc_, constant_pool_, address,
|
||||
icache_flush_mode);
|
||||
}
|
||||
|
||||
Address RelocInfo::wasm_stub_call_address() const {
|
||||
DCHECK_EQ(rmode_, WASM_STUB_CALL);
|
||||
return Assembler::target_address_at(pc_, constant_pool_);
|
||||
}
|
||||
|
||||
void RelocInfo::set_wasm_stub_call_address(Address address,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
DCHECK_EQ(rmode_, WASM_STUB_CALL);
|
||||
Assembler::set_target_address_at(pc_, constant_pool_, address,
|
||||
icache_flush_mode);
|
||||
}
|
||||
|
||||
void RelocInfo::set_target_address(Address target,
|
||||
WriteBarrierMode write_barrier_mode,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
DCHECK(IsCodeTargetMode(rmode_) || IsRuntimeEntry(rmode_) ||
|
||||
IsWasmCall(rmode_));
|
||||
Assembler::set_target_address_at(pc_, constant_pool_, target,
|
||||
icache_flush_mode);
|
||||
if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != nullptr &&
|
||||
IsCodeTargetMode(rmode_)) {
|
||||
Code* target_code = Code::GetCodeFromTargetAddress(target);
|
||||
MarkingBarrierForCode(host(), this, target_code);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool RelocInfo::RequiresRelocation(const CodeDesc& desc) {
|
||||
// Ensure there are no code targets or embedded objects present in the
|
||||
// deoptimization entries, they would require relocation after code
|
||||
// generation.
|
||||
int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
|
||||
RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
|
||||
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
|
||||
RelocInfo::kApplyMask;
|
||||
RelocIterator it(desc, mode_mask);
|
||||
return !it.done();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
|
||||
switch (rmode) {
|
||||
case NONE:
|
||||
return "no reloc";
|
||||
case EMBEDDED_OBJECT:
|
||||
return "embedded object";
|
||||
case CODE_TARGET:
|
||||
return "code target";
|
||||
case RELATIVE_CODE_TARGET:
|
||||
return "relative code target";
|
||||
case RUNTIME_ENTRY:
|
||||
return "runtime entry";
|
||||
case COMMENT:
|
||||
return "comment";
|
||||
case EXTERNAL_REFERENCE:
|
||||
return "external reference";
|
||||
case INTERNAL_REFERENCE:
|
||||
return "internal reference";
|
||||
case INTERNAL_REFERENCE_ENCODED:
|
||||
return "encoded internal reference";
|
||||
case OFF_HEAP_TARGET:
|
||||
return "off heap target";
|
||||
case DEOPT_SCRIPT_OFFSET:
|
||||
return "deopt script offset";
|
||||
case DEOPT_INLINING_ID:
|
||||
return "deopt inlining id";
|
||||
case DEOPT_REASON:
|
||||
return "deopt reason";
|
||||
case DEOPT_ID:
|
||||
return "deopt index";
|
||||
case CONST_POOL:
|
||||
return "constant pool";
|
||||
case VENEER_POOL:
|
||||
return "veneer pool";
|
||||
case WASM_CALL:
|
||||
return "internal wasm call";
|
||||
case WASM_STUB_CALL:
|
||||
return "wasm stub call";
|
||||
case JS_TO_WASM_CALL:
|
||||
return "js to wasm call";
|
||||
case NUMBER_OF_MODES:
|
||||
case PC_JUMP:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return "unknown relocation type";
|
||||
}
|
||||
|
||||
void RelocInfo::Print(Isolate* isolate, std::ostream& os) { // NOLINT
|
||||
os << reinterpret_cast<const void*>(pc_) << " " << RelocModeName(rmode_);
|
||||
if (IsComment(rmode_)) {
|
||||
os << " (" << reinterpret_cast<char*>(data_) << ")";
|
||||
} else if (rmode_ == DEOPT_SCRIPT_OFFSET || rmode_ == DEOPT_INLINING_ID) {
|
||||
os << " (" << data() << ")";
|
||||
} else if (rmode_ == DEOPT_REASON) {
|
||||
os << " ("
|
||||
<< DeoptimizeReasonToString(static_cast<DeoptimizeReason>(data_)) << ")";
|
||||
} else if (rmode_ == EMBEDDED_OBJECT) {
|
||||
os << " (" << Brief(target_object()) << ")";
|
||||
} else if (rmode_ == EXTERNAL_REFERENCE) {
|
||||
if (isolate) {
|
||||
ExternalReferenceEncoder ref_encoder(isolate);
|
||||
os << " ("
|
||||
<< ref_encoder.NameOfAddress(isolate, target_external_reference())
|
||||
<< ") ";
|
||||
}
|
||||
os << " (" << reinterpret_cast<const void*>(target_external_reference())
|
||||
<< ")";
|
||||
} else if (IsCodeTargetMode(rmode_)) {
|
||||
const Address code_target = target_address();
|
||||
Code* code = Code::GetCodeFromTargetAddress(code_target);
|
||||
DCHECK(code->IsCode());
|
||||
os << " (" << Code::Kind2String(code->kind());
|
||||
if (Builtins::IsBuiltin(code)) {
|
||||
os << " " << Builtins::name(code->builtin_index());
|
||||
} else if (code->kind() == Code::STUB) {
|
||||
os << " " << CodeStub::MajorName(CodeStub::GetMajorKey(code));
|
||||
}
|
||||
os << ") (" << reinterpret_cast<const void*>(target_address()) << ")";
|
||||
} else if (IsRuntimeEntry(rmode_) && isolate->deoptimizer_data() != nullptr) {
|
||||
// Deoptimization bailouts are stored as runtime entries.
|
||||
DeoptimizeKind type;
|
||||
if (Deoptimizer::IsDeoptimizationEntry(isolate, target_address(), &type)) {
|
||||
int id = GetDeoptimizationId(isolate, type);
|
||||
os << " (" << Deoptimizer::MessageFor(type) << " deoptimization bailout "
|
||||
<< id << ")";
|
||||
}
|
||||
} else if (IsConstPool(rmode_)) {
|
||||
os << " (size " << static_cast<int>(data_) << ")";
|
||||
}
|
||||
|
||||
os << "\n";
|
||||
}
|
||||
#endif // ENABLE_DISASSEMBLER
|
||||
|
||||
#ifdef VERIFY_HEAP
|
||||
void RelocInfo::Verify(Isolate* isolate) {
|
||||
switch (rmode_) {
|
||||
case EMBEDDED_OBJECT:
|
||||
Object::VerifyPointer(isolate, target_object());
|
||||
break;
|
||||
case CODE_TARGET:
|
||||
case RELATIVE_CODE_TARGET: {
|
||||
// convert inline target address to code object
|
||||
Address addr = target_address();
|
||||
CHECK_NE(addr, kNullAddress);
|
||||
// Check that we can find the right code object.
|
||||
Code* code = Code::GetCodeFromTargetAddress(addr);
|
||||
Object* found = isolate->FindCodeObject(addr);
|
||||
CHECK(found->IsCode());
|
||||
CHECK(code->address() == HeapObject::cast(found)->address());
|
||||
break;
|
||||
}
|
||||
case INTERNAL_REFERENCE:
|
||||
case INTERNAL_REFERENCE_ENCODED: {
|
||||
Address target = target_internal_reference();
|
||||
Address pc = target_internal_reference_address();
|
||||
Code* code = Code::cast(isolate->FindCodeObject(pc));
|
||||
CHECK(target >= code->InstructionStart());
|
||||
CHECK(target <= code->InstructionEnd());
|
||||
break;
|
||||
}
|
||||
case OFF_HEAP_TARGET: {
|
||||
Address addr = target_off_heap_target();
|
||||
CHECK_NE(addr, kNullAddress);
|
||||
CHECK_NOT_NULL(InstructionStream::TryLookupCode(isolate, addr));
|
||||
break;
|
||||
}
|
||||
case RUNTIME_ENTRY:
|
||||
case COMMENT:
|
||||
case EXTERNAL_REFERENCE:
|
||||
case DEOPT_SCRIPT_OFFSET:
|
||||
case DEOPT_INLINING_ID:
|
||||
case DEOPT_REASON:
|
||||
case DEOPT_ID:
|
||||
case CONST_POOL:
|
||||
case VENEER_POOL:
|
||||
case WASM_CALL:
|
||||
case WASM_STUB_CALL:
|
||||
case JS_TO_WASM_CALL:
|
||||
case NONE:
|
||||
break;
|
||||
case NUMBER_OF_MODES:
|
||||
case PC_JUMP:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // VERIFY_HEAP
|
||||
|
||||
ConstantPoolBuilder::ConstantPoolBuilder(int ptr_reach_bits,
|
||||
int double_reach_bits) {
|
||||
info_[ConstantPoolEntry::INTPTR].entries.reserve(64);
|
||||
|
424
src/assembler.h
424
src/assembler.h
@ -51,6 +51,7 @@
|
||||
#include "src/objects.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/reglist.h"
|
||||
#include "src/reloc-info.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
@ -415,429 +416,6 @@ class CpuFeatures : public AllStatic {
|
||||
DISALLOW_COPY_AND_ASSIGN(CpuFeatures);
|
||||
};
|
||||
|
||||
// Specifies whether to perform icache flush operations on RelocInfo updates.
|
||||
// If FLUSH_ICACHE_IF_NEEDED, the icache will always be flushed if an
|
||||
// instruction was modified. If SKIP_ICACHE_FLUSH the flush will always be
|
||||
// skipped (only use this if you will flush the icache manually before it is
|
||||
// executed).
|
||||
enum ICacheFlushMode { FLUSH_ICACHE_IF_NEEDED, SKIP_ICACHE_FLUSH };
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Relocation information
|
||||
|
||||
|
||||
// Relocation information consists of the address (pc) of the datum
|
||||
// to which the relocation information applies, the relocation mode
|
||||
// (rmode), and an optional data field. The relocation mode may be
|
||||
// "descriptive" and not indicate a need for relocation, but simply
|
||||
// describe a property of the datum. Such rmodes are useful for GC
|
||||
// and nice disassembly output.
|
||||
|
||||
class RelocInfo {
|
||||
public:
|
||||
// This string is used to add padding comments to the reloc info in cases
|
||||
// where we are not sure to have enough space for patching in during
|
||||
// lazy deoptimization. This is the case if we have indirect calls for which
|
||||
// we do not normally record relocation info.
|
||||
static const char* const kFillerCommentString;
|
||||
|
||||
// The minimum size of a comment is equal to two bytes for the extra tagged
|
||||
// pc and kPointerSize for the actual pointer to the comment.
|
||||
static const int kMinRelocCommentSize = 2 + kPointerSize;
|
||||
|
||||
// The maximum size for a call instruction including pc-jump.
|
||||
static const int kMaxCallSize = 6;
|
||||
|
||||
// The maximum pc delta that will use the short encoding.
|
||||
static const int kMaxSmallPCDelta;
|
||||
|
||||
enum Mode : int8_t {
|
||||
// Please note the order is important (see IsRealRelocMode, IsGCRelocMode,
|
||||
// and IsShareableRelocMode predicates below).
|
||||
|
||||
CODE_TARGET,
|
||||
RELATIVE_CODE_TARGET, // LAST_CODE_TARGET_MODE
|
||||
EMBEDDED_OBJECT, // LAST_GCED_ENUM
|
||||
|
||||
JS_TO_WASM_CALL,
|
||||
WASM_CALL, // FIRST_SHAREABLE_RELOC_MODE
|
||||
WASM_STUB_CALL,
|
||||
|
||||
RUNTIME_ENTRY,
|
||||
COMMENT,
|
||||
|
||||
EXTERNAL_REFERENCE, // The address of an external C++ function.
|
||||
INTERNAL_REFERENCE, // An address inside the same function.
|
||||
|
||||
// Encoded internal reference, used only on MIPS, MIPS64 and PPC.
|
||||
INTERNAL_REFERENCE_ENCODED,
|
||||
|
||||
// An off-heap instruction stream target. See http://goo.gl/Z2HUiM.
|
||||
OFF_HEAP_TARGET,
|
||||
|
||||
// Marks constant and veneer pools. Only used on ARM and ARM64.
|
||||
// They use a custom noncompact encoding.
|
||||
CONST_POOL,
|
||||
VENEER_POOL,
|
||||
|
||||
DEOPT_SCRIPT_OFFSET,
|
||||
DEOPT_INLINING_ID, // Deoptimization source position.
|
||||
DEOPT_REASON, // Deoptimization reason index.
|
||||
DEOPT_ID, // Deoptimization inlining id.
|
||||
|
||||
// This is not an actual reloc mode, but used to encode a long pc jump that
|
||||
// cannot be encoded as part of another record.
|
||||
PC_JUMP,
|
||||
|
||||
// Pseudo-types
|
||||
NUMBER_OF_MODES,
|
||||
NONE, // never recorded value
|
||||
|
||||
LAST_CODE_TARGET_MODE = RELATIVE_CODE_TARGET,
|
||||
FIRST_REAL_RELOC_MODE = CODE_TARGET,
|
||||
LAST_REAL_RELOC_MODE = VENEER_POOL,
|
||||
LAST_GCED_ENUM = EMBEDDED_OBJECT,
|
||||
FIRST_SHAREABLE_RELOC_MODE = WASM_CALL,
|
||||
};
|
||||
|
||||
STATIC_ASSERT(NUMBER_OF_MODES <= kBitsPerInt);
|
||||
|
||||
RelocInfo() = default;
|
||||
|
||||
RelocInfo(Address pc, Mode rmode, intptr_t data, Code* host,
|
||||
Address constant_pool = kNullAddress)
|
||||
: pc_(pc),
|
||||
rmode_(rmode),
|
||||
data_(data),
|
||||
host_(host),
|
||||
constant_pool_(constant_pool) {}
|
||||
|
||||
static inline bool IsRealRelocMode(Mode mode) {
|
||||
return mode >= FIRST_REAL_RELOC_MODE && mode <= LAST_REAL_RELOC_MODE;
|
||||
}
|
||||
// Is the relocation mode affected by GC?
|
||||
static inline bool IsGCRelocMode(Mode mode) { return mode <= LAST_GCED_ENUM; }
|
||||
static inline bool IsShareableRelocMode(Mode mode) {
|
||||
static_assert(RelocInfo::NONE >= RelocInfo::FIRST_SHAREABLE_RELOC_MODE,
|
||||
"Users of this function rely on NONE being a sharable "
|
||||
"relocation mode.");
|
||||
return mode >= RelocInfo::FIRST_SHAREABLE_RELOC_MODE;
|
||||
}
|
||||
static inline bool IsCodeTarget(Mode mode) { return mode == CODE_TARGET; }
|
||||
static inline bool IsCodeTargetMode(Mode mode) {
|
||||
return mode <= LAST_CODE_TARGET_MODE;
|
||||
}
|
||||
static inline bool IsRelativeCodeTarget(Mode mode) {
|
||||
return mode == RELATIVE_CODE_TARGET;
|
||||
}
|
||||
static inline bool IsEmbeddedObject(Mode mode) {
|
||||
return mode == EMBEDDED_OBJECT;
|
||||
}
|
||||
static inline bool IsRuntimeEntry(Mode mode) {
|
||||
return mode == RUNTIME_ENTRY;
|
||||
}
|
||||
static inline bool IsWasmCall(Mode mode) { return mode == WASM_CALL; }
|
||||
static inline bool IsWasmStubCall(Mode mode) {
|
||||
return mode == WASM_STUB_CALL;
|
||||
}
|
||||
static inline bool IsComment(Mode mode) {
|
||||
return mode == COMMENT;
|
||||
}
|
||||
static inline bool IsConstPool(Mode mode) {
|
||||
return mode == CONST_POOL;
|
||||
}
|
||||
static inline bool IsVeneerPool(Mode mode) {
|
||||
return mode == VENEER_POOL;
|
||||
}
|
||||
static inline bool IsDeoptPosition(Mode mode) {
|
||||
return mode == DEOPT_SCRIPT_OFFSET || mode == DEOPT_INLINING_ID;
|
||||
}
|
||||
static inline bool IsDeoptReason(Mode mode) {
|
||||
return mode == DEOPT_REASON;
|
||||
}
|
||||
static inline bool IsDeoptId(Mode mode) {
|
||||
return mode == DEOPT_ID;
|
||||
}
|
||||
static inline bool IsExternalReference(Mode mode) {
|
||||
return mode == EXTERNAL_REFERENCE;
|
||||
}
|
||||
static inline bool IsInternalReference(Mode mode) {
|
||||
return mode == INTERNAL_REFERENCE;
|
||||
}
|
||||
static inline bool IsInternalReferenceEncoded(Mode mode) {
|
||||
return mode == INTERNAL_REFERENCE_ENCODED;
|
||||
}
|
||||
static inline bool IsOffHeapTarget(Mode mode) {
|
||||
return mode == OFF_HEAP_TARGET;
|
||||
}
|
||||
static inline bool IsNone(Mode mode) { return mode == NONE; }
|
||||
static inline bool IsWasmReference(Mode mode) {
|
||||
return IsWasmPtrReference(mode);
|
||||
}
|
||||
static inline bool IsWasmPtrReference(Mode mode) {
|
||||
return mode == WASM_CALL || mode == JS_TO_WASM_CALL;
|
||||
}
|
||||
|
||||
static inline bool IsOnlyForSerializer(Mode mode) {
|
||||
return mode == EXTERNAL_REFERENCE || mode == OFF_HEAP_TARGET;
|
||||
}
|
||||
|
||||
static constexpr int ModeMask(Mode mode) { return 1 << mode; }
|
||||
|
||||
// Accessors
|
||||
Address pc() const { return pc_; }
|
||||
Mode rmode() const { return rmode_; }
|
||||
intptr_t data() const { return data_; }
|
||||
Code* host() const { return host_; }
|
||||
Address constant_pool() const { return constant_pool_; }
|
||||
|
||||
// Apply a relocation by delta bytes. When the code object is moved, PC
|
||||
// relative addresses have to be updated as well as absolute addresses
|
||||
// inside the code (internal references).
|
||||
// Do not forget to flush the icache afterwards!
|
||||
V8_INLINE void apply(intptr_t delta);
|
||||
|
||||
// Is the pointer this relocation info refers to coded like a plain pointer
|
||||
// or is it strange in some way (e.g. relative or patched into a series of
|
||||
// instructions).
|
||||
bool IsCodedSpecially();
|
||||
|
||||
// The static pendant to IsCodedSpecially, just for off-heap targets. Used
|
||||
// during deserialization, when we don't actually have a RelocInfo handy.
|
||||
static bool OffHeapTargetIsCodedSpecially();
|
||||
|
||||
// If true, the pointer this relocation info refers to is an entry in the
|
||||
// constant pool, otherwise the pointer is embedded in the instruction stream.
|
||||
bool IsInConstantPool();
|
||||
|
||||
// Returns the deoptimization id for the entry associated with the reloc info
|
||||
// where {kind} is the deoptimization kind.
|
||||
// This is only used for printing RUNTIME_ENTRY relocation info.
|
||||
int GetDeoptimizationId(Isolate* isolate, DeoptimizeKind kind);
|
||||
|
||||
Address wasm_call_address() const;
|
||||
Address wasm_stub_call_address() const;
|
||||
Address js_to_wasm_address() const;
|
||||
|
||||
uint32_t wasm_call_tag() const;
|
||||
|
||||
void set_wasm_call_address(
|
||||
Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
void set_wasm_stub_call_address(
|
||||
Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
void set_js_to_wasm_address(
|
||||
Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
|
||||
void set_target_address(
|
||||
Address target,
|
||||
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
|
||||
// this relocation applies to;
|
||||
// can only be called if IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
|
||||
V8_INLINE Address target_address();
|
||||
V8_INLINE HeapObject* target_object();
|
||||
V8_INLINE Handle<HeapObject> target_object_handle(Assembler* origin);
|
||||
V8_INLINE void set_target_object(
|
||||
Heap* heap, HeapObject* target,
|
||||
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
V8_INLINE Address target_runtime_entry(Assembler* origin);
|
||||
V8_INLINE void set_target_runtime_entry(
|
||||
Address target,
|
||||
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
V8_INLINE Address target_off_heap_target();
|
||||
V8_INLINE Cell* target_cell();
|
||||
V8_INLINE Handle<Cell> target_cell_handle();
|
||||
V8_INLINE void set_target_cell(
|
||||
Cell* cell, WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
V8_INLINE void set_target_external_reference(
|
||||
Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
|
||||
// Returns the address of the constant pool entry where the target address
|
||||
// is held. This should only be called if IsInConstantPool returns true.
|
||||
V8_INLINE Address constant_pool_entry_address();
|
||||
|
||||
// Read the address of the word containing the target_address in an
|
||||
// instruction stream. What this means exactly is architecture-independent.
|
||||
// The only architecture-independent user of this function is the serializer.
|
||||
// The serializer uses it to find out how many raw bytes of instruction to
|
||||
// output before the next target. Architecture-independent code shouldn't
|
||||
// dereference the pointer it gets back from this.
|
||||
V8_INLINE Address target_address_address();
|
||||
|
||||
// This indicates how much space a target takes up when deserializing a code
|
||||
// stream. For most architectures this is just the size of a pointer. For
|
||||
// an instruction like movw/movt where the target bits are mixed into the
|
||||
// instruction bits the size of the target will be zero, indicating that the
|
||||
// serializer should not step forwards in memory after a target is resolved
|
||||
// and written. In this case the target_address_address function above
|
||||
// should return the end of the instructions to be patched, allowing the
|
||||
// deserializer to deserialize the instructions as raw bytes and put them in
|
||||
// place, ready to be patched with the target.
|
||||
V8_INLINE int target_address_size();
|
||||
|
||||
// Read the reference in the instruction this relocation
|
||||
// applies to; can only be called if rmode_ is EXTERNAL_REFERENCE.
|
||||
V8_INLINE Address target_external_reference();
|
||||
|
||||
// Read the reference in the instruction this relocation
|
||||
// applies to; can only be called if rmode_ is INTERNAL_REFERENCE.
|
||||
V8_INLINE Address target_internal_reference();
|
||||
|
||||
// Return the reference address this relocation applies to;
|
||||
// can only be called if rmode_ is INTERNAL_REFERENCE.
|
||||
V8_INLINE Address target_internal_reference_address();
|
||||
|
||||
// Wipe out a relocation to a fixed value, used for making snapshots
|
||||
// reproducible.
|
||||
V8_INLINE void WipeOut();
|
||||
|
||||
template <typename ObjectVisitor>
|
||||
inline void Visit(ObjectVisitor* v);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Check whether the given code contains relocation information that
|
||||
// either is position-relative or movable by the garbage collector.
|
||||
static bool RequiresRelocation(const CodeDesc& desc);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
// Printing
|
||||
static const char* RelocModeName(Mode rmode);
|
||||
void Print(Isolate* isolate, std::ostream& os); // NOLINT
|
||||
#endif // ENABLE_DISASSEMBLER
|
||||
#ifdef VERIFY_HEAP
|
||||
void Verify(Isolate* isolate);
|
||||
#endif
|
||||
|
||||
static const int kApplyMask; // Modes affected by apply. Depends on arch.
|
||||
|
||||
private:
|
||||
// On ARM/ARM64, note that pc_ is the address of the instruction referencing
|
||||
// the constant pool and not the address of the constant pool entry.
|
||||
Address pc_;
|
||||
Mode rmode_;
|
||||
intptr_t data_ = 0;
|
||||
Code* host_;
|
||||
Address constant_pool_ = kNullAddress;
|
||||
friend class RelocIterator;
|
||||
};
|
||||
|
||||
|
||||
// RelocInfoWriter serializes a stream of relocation info. It writes towards
|
||||
// lower addresses.
|
||||
class RelocInfoWriter BASE_EMBEDDED {
|
||||
public:
|
||||
RelocInfoWriter() : pos_(nullptr), last_pc_(nullptr) {}
|
||||
|
||||
byte* pos() const { return pos_; }
|
||||
byte* last_pc() const { return last_pc_; }
|
||||
|
||||
void Write(const RelocInfo* rinfo);
|
||||
|
||||
// Update the state of the stream after reloc info buffer
|
||||
// and/or code is moved while the stream is active.
|
||||
void Reposition(byte* pos, byte* pc) {
|
||||
pos_ = pos;
|
||||
last_pc_ = pc;
|
||||
}
|
||||
|
||||
// Max size (bytes) of a written RelocInfo. Longest encoding is
|
||||
// ExtraTag, VariableLengthPCJump, ExtraTag, pc_delta, data_delta.
|
||||
static constexpr int kMaxSize = 1 + 4 + 1 + 1 + kPointerSize;
|
||||
|
||||
private:
|
||||
inline uint32_t WriteLongPCJump(uint32_t pc_delta);
|
||||
|
||||
inline void WriteShortTaggedPC(uint32_t pc_delta, int tag);
|
||||
inline void WriteShortData(intptr_t data_delta);
|
||||
|
||||
inline void WriteMode(RelocInfo::Mode rmode);
|
||||
inline void WriteModeAndPC(uint32_t pc_delta, RelocInfo::Mode rmode);
|
||||
inline void WriteIntData(int data_delta);
|
||||
inline void WriteData(intptr_t data_delta);
|
||||
|
||||
byte* pos_;
|
||||
byte* last_pc_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RelocInfoWriter);
|
||||
};
|
||||
|
||||
|
||||
// A RelocIterator iterates over relocation information.
|
||||
// Typical use:
|
||||
//
|
||||
// for (RelocIterator it(code); !it.done(); it.next()) {
|
||||
// // do something with it.rinfo() here
|
||||
// }
|
||||
//
|
||||
// A mask can be specified to skip unwanted modes.
|
||||
class RelocIterator: public Malloced {
|
||||
public:
|
||||
// Create a new iterator positioned at
|
||||
// the beginning of the reloc info.
|
||||
// Relocation information with mode k is included in the
|
||||
// iteration iff bit k of mode_mask is set.
|
||||
explicit RelocIterator(Code* code, int mode_mask = -1);
|
||||
explicit RelocIterator(EmbeddedData* embedded_data, Code* code,
|
||||
int mode_mask);
|
||||
explicit RelocIterator(const CodeDesc& desc, int mode_mask = -1);
|
||||
explicit RelocIterator(const CodeReference code_reference,
|
||||
int mode_mask = -1);
|
||||
explicit RelocIterator(Vector<byte> instructions,
|
||||
Vector<const byte> reloc_info, Address const_pool,
|
||||
int mode_mask = -1);
|
||||
RelocIterator(RelocIterator&&) = default;
|
||||
RelocIterator& operator=(RelocIterator&&) = default;
|
||||
|
||||
// Iteration
|
||||
bool done() const { return done_; }
|
||||
void next();
|
||||
|
||||
// Return pointer valid until next next().
|
||||
RelocInfo* rinfo() {
|
||||
DCHECK(!done());
|
||||
return &rinfo_;
|
||||
}
|
||||
|
||||
private:
|
||||
RelocIterator(Code* host, Address pc, Address constant_pool, const byte* pos,
|
||||
const byte* end, int mode_mask);
|
||||
|
||||
// Advance* moves the position before/after reading.
|
||||
// *Read* reads from current byte(s) into rinfo_.
|
||||
// *Get* just reads and returns info on current byte.
|
||||
void Advance(int bytes = 1) { pos_ -= bytes; }
|
||||
int AdvanceGetTag();
|
||||
RelocInfo::Mode GetMode();
|
||||
|
||||
void AdvanceReadLongPCJump();
|
||||
|
||||
void ReadShortTaggedPC();
|
||||
void ReadShortData();
|
||||
|
||||
void AdvanceReadPC();
|
||||
void AdvanceReadInt();
|
||||
void AdvanceReadData();
|
||||
|
||||
// If the given mode is wanted, set it in rinfo_ and return true.
|
||||
// Else return false. Used for efficiently skipping unwanted modes.
|
||||
bool SetMode(RelocInfo::Mode mode) {
|
||||
return (mode_mask_ & (1 << mode)) ? (rinfo_.rmode_ = mode, true) : false;
|
||||
}
|
||||
|
||||
const byte* pos_;
|
||||
const byte* end_;
|
||||
RelocInfo rinfo_;
|
||||
bool done_ = false;
|
||||
const int mode_mask_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RelocIterator);
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Utility functions
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define V8_CODE_FACTORY_H_
|
||||
|
||||
#include "src/allocation.h"
|
||||
#include "src/assembler.h"
|
||||
#include "src/callable.h"
|
||||
#include "src/code-stubs.h"
|
||||
#include "src/globals.h"
|
||||
|
@ -5,12 +5,12 @@
|
||||
#ifndef V8_COMPILER_COMMON_OPERATOR_H_
|
||||
#define V8_COMPILER_COMMON_OPERATOR_H_
|
||||
|
||||
#include "src/assembler.h"
|
||||
#include "src/base/compiler-specific.h"
|
||||
#include "src/compiler/frame-states.h"
|
||||
#include "src/deoptimize-reason.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/machine-type.h"
|
||||
#include "src/reloc-info.h"
|
||||
#include "src/vector-slot-pair.h"
|
||||
#include "src/zone/zone-containers.h"
|
||||
#include "src/zone/zone-handle-set.h"
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "src/compiler/machine-graph.h"
|
||||
|
||||
#include "src/compiler/node-properties.h"
|
||||
#include "src/external-reference.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -5,13 +5,13 @@
|
||||
#ifndef V8_COMPILER_MACHINE_GRAPH_H_
|
||||
#define V8_COMPILER_MACHINE_GRAPH_H_
|
||||
|
||||
#include "src/assembler.h"
|
||||
#include "src/base/compiler-specific.h"
|
||||
#include "src/compiler/common-node-cache.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "src/allocation.h"
|
||||
#include "src/assembler.h"
|
||||
#include "src/base/atomicops.h"
|
||||
#include "src/base/hashmap.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
|
@ -5,10 +5,10 @@
|
||||
#ifndef V8_HEAP_REMEMBERED_SET_H_
|
||||
#define V8_HEAP_REMEMBERED_SET_H_
|
||||
|
||||
#include "src/assembler.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/heap/slot-set.h"
|
||||
#include "src/heap/spaces.h"
|
||||
#include "src/reloc-info.h"
|
||||
#include "src/v8memory.h"
|
||||
|
||||
namespace v8 {
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define V8_OBJECTS_MAP_INL_H_
|
||||
|
||||
#include "src/objects/map.h"
|
||||
|
||||
#include "src/field-type.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/objects/api-callbacks-inl.h"
|
||||
|
543
src/reloc-info.cc
Normal file
543
src/reloc-info.cc
Normal file
@ -0,0 +1,543 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
#include "src/reloc-info.h"
|
||||
|
||||
#include "src/assembler-arch-inl.h"
|
||||
#include "src/code-stubs.h"
|
||||
#include "src/deoptimize-reason.h"
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/heap/heap-write-barrier-inl.h"
|
||||
#include "src/objects/code-inl.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of RelocInfoWriter and RelocIterator
|
||||
//
|
||||
// Relocation information is written backwards in memory, from high addresses
|
||||
// towards low addresses, byte by byte. Therefore, in the encodings listed
|
||||
// below, the first byte listed it at the highest address, and successive
|
||||
// bytes in the record are at progressively lower addresses.
|
||||
//
|
||||
// Encoding
|
||||
//
|
||||
// The most common modes are given single-byte encodings. Also, it is
|
||||
// easy to identify the type of reloc info and skip unwanted modes in
|
||||
// an iteration.
|
||||
//
|
||||
// The encoding relies on the fact that there are fewer than 14
|
||||
// different relocation modes using standard non-compact encoding.
|
||||
//
|
||||
// The first byte of a relocation record has a tag in its low 2 bits:
|
||||
// Here are the record schemes, depending on the low tag and optional higher
|
||||
// tags.
|
||||
//
|
||||
// Low tag:
|
||||
// 00: embedded_object: [6-bit pc delta] 00
|
||||
//
|
||||
// 01: code_target: [6-bit pc delta] 01
|
||||
//
|
||||
// 10: wasm_stub_call: [6-bit pc delta] 10
|
||||
//
|
||||
// 11: long_record [6 bit reloc mode] 11
|
||||
// followed by pc delta
|
||||
// followed by optional data depending on type.
|
||||
//
|
||||
// If a pc delta exceeds 6 bits, it is split into a remainder that fits into
|
||||
// 6 bits and a part that does not. The latter is encoded as a long record
|
||||
// with PC_JUMP as pseudo reloc info mode. The former is encoded as part of
|
||||
// the following record in the usual way. The long pc jump record has variable
|
||||
// length:
|
||||
// pc-jump: [PC_JUMP] 11
|
||||
// [7 bits data] 0
|
||||
// ...
|
||||
// [7 bits data] 1
|
||||
// (Bits 6..31 of pc delta, with leading zeroes
|
||||
// dropped, and last non-zero chunk tagged with 1.)
|
||||
|
||||
const int kTagBits = 2;
|
||||
const int kTagMask = (1 << kTagBits) - 1;
|
||||
const int kLongTagBits = 6;
|
||||
|
||||
const int kEmbeddedObjectTag = 0;
|
||||
const int kCodeTargetTag = 1;
|
||||
const int kWasmStubCallTag = 2;
|
||||
const int kDefaultTag = 3;
|
||||
|
||||
const int kSmallPCDeltaBits = kBitsPerByte - kTagBits;
|
||||
const int kSmallPCDeltaMask = (1 << kSmallPCDeltaBits) - 1;
|
||||
const int RelocInfo::kMaxSmallPCDelta = kSmallPCDeltaMask;
|
||||
|
||||
const int kChunkBits = 7;
|
||||
const int kChunkMask = (1 << kChunkBits) - 1;
|
||||
const int kLastChunkTagBits = 1;
|
||||
const int kLastChunkTagMask = 1;
|
||||
const int kLastChunkTag = 1;
|
||||
|
||||
uint32_t RelocInfoWriter::WriteLongPCJump(uint32_t pc_delta) {
|
||||
// Return if the pc_delta can fit in kSmallPCDeltaBits bits.
|
||||
// Otherwise write a variable length PC jump for the bits that do
|
||||
// not fit in the kSmallPCDeltaBits bits.
|
||||
if (is_uintn(pc_delta, kSmallPCDeltaBits)) return pc_delta;
|
||||
WriteMode(RelocInfo::PC_JUMP);
|
||||
uint32_t pc_jump = pc_delta >> kSmallPCDeltaBits;
|
||||
DCHECK_GT(pc_jump, 0);
|
||||
// Write kChunkBits size chunks of the pc_jump.
|
||||
for (; pc_jump > 0; pc_jump = pc_jump >> kChunkBits) {
|
||||
byte b = pc_jump & kChunkMask;
|
||||
*--pos_ = b << kLastChunkTagBits;
|
||||
}
|
||||
// Tag the last chunk so it can be identified.
|
||||
*pos_ = *pos_ | kLastChunkTag;
|
||||
// Return the remaining kSmallPCDeltaBits of the pc_delta.
|
||||
return pc_delta & kSmallPCDeltaMask;
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteShortTaggedPC(uint32_t pc_delta, int tag) {
|
||||
// Write a byte of tagged pc-delta, possibly preceded by an explicit pc-jump.
|
||||
pc_delta = WriteLongPCJump(pc_delta);
|
||||
*--pos_ = pc_delta << kTagBits | tag;
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteShortData(intptr_t data_delta) {
|
||||
*--pos_ = static_cast<byte>(data_delta);
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteMode(RelocInfo::Mode rmode) {
|
||||
STATIC_ASSERT(RelocInfo::NUMBER_OF_MODES <= (1 << kLongTagBits));
|
||||
*--pos_ = static_cast<int>((rmode << kTagBits) | kDefaultTag);
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteModeAndPC(uint32_t pc_delta, RelocInfo::Mode rmode) {
|
||||
// Write two-byte tagged pc-delta, possibly preceded by var. length pc-jump.
|
||||
pc_delta = WriteLongPCJump(pc_delta);
|
||||
WriteMode(rmode);
|
||||
*--pos_ = pc_delta;
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteIntData(int number) {
|
||||
for (int i = 0; i < kIntSize; i++) {
|
||||
*--pos_ = static_cast<byte>(number);
|
||||
// Signed right shift is arithmetic shift. Tested in test-utils.cc.
|
||||
number = number >> kBitsPerByte;
|
||||
}
|
||||
}
|
||||
|
||||
void RelocInfoWriter::WriteData(intptr_t data_delta) {
|
||||
for (int i = 0; i < kIntptrSize; i++) {
|
||||
*--pos_ = static_cast<byte>(data_delta);
|
||||
// Signed right shift is arithmetic shift. Tested in test-utils.cc.
|
||||
data_delta = data_delta >> kBitsPerByte;
|
||||
}
|
||||
}
|
||||
|
||||
void RelocInfoWriter::Write(const RelocInfo* rinfo) {
|
||||
RelocInfo::Mode rmode = rinfo->rmode();
|
||||
#ifdef DEBUG
|
||||
byte* begin_pos = pos_;
|
||||
#endif
|
||||
DCHECK(rinfo->rmode() < RelocInfo::NUMBER_OF_MODES);
|
||||
DCHECK_GE(rinfo->pc() - reinterpret_cast<Address>(last_pc_), 0);
|
||||
// Use unsigned delta-encoding for pc.
|
||||
uint32_t pc_delta =
|
||||
static_cast<uint32_t>(rinfo->pc() - reinterpret_cast<Address>(last_pc_));
|
||||
|
||||
// The two most common modes are given small tags, and usually fit in a byte.
|
||||
if (rmode == RelocInfo::EMBEDDED_OBJECT) {
|
||||
WriteShortTaggedPC(pc_delta, kEmbeddedObjectTag);
|
||||
} else if (rmode == RelocInfo::CODE_TARGET) {
|
||||
WriteShortTaggedPC(pc_delta, kCodeTargetTag);
|
||||
DCHECK_LE(begin_pos - pos_, RelocInfo::kMaxCallSize);
|
||||
} else if (rmode == RelocInfo::WASM_STUB_CALL) {
|
||||
WriteShortTaggedPC(pc_delta, kWasmStubCallTag);
|
||||
} else {
|
||||
WriteModeAndPC(pc_delta, rmode);
|
||||
if (RelocInfo::IsComment(rmode)) {
|
||||
WriteData(rinfo->data());
|
||||
} else if (RelocInfo::IsDeoptReason(rmode)) {
|
||||
DCHECK_LT(rinfo->data(), 1 << kBitsPerByte);
|
||||
WriteShortData(rinfo->data());
|
||||
} else if (RelocInfo::IsConstPool(rmode) ||
|
||||
RelocInfo::IsVeneerPool(rmode) || RelocInfo::IsDeoptId(rmode) ||
|
||||
RelocInfo::IsDeoptPosition(rmode)) {
|
||||
WriteIntData(static_cast<int>(rinfo->data()));
|
||||
}
|
||||
}
|
||||
last_pc_ = reinterpret_cast<byte*>(rinfo->pc());
|
||||
#ifdef DEBUG
|
||||
DCHECK_LE(begin_pos - pos_, kMaxSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int RelocIterator::AdvanceGetTag() { return *--pos_ & kTagMask; }
|
||||
|
||||
inline RelocInfo::Mode RelocIterator::GetMode() {
|
||||
return static_cast<RelocInfo::Mode>((*pos_ >> kTagBits) &
|
||||
((1 << kLongTagBits) - 1));
|
||||
}
|
||||
|
||||
inline void RelocIterator::ReadShortTaggedPC() {
|
||||
rinfo_.pc_ += *pos_ >> kTagBits;
|
||||
}
|
||||
|
||||
inline void RelocIterator::AdvanceReadPC() { rinfo_.pc_ += *--pos_; }
|
||||
|
||||
void RelocIterator::AdvanceReadInt() {
|
||||
int x = 0;
|
||||
for (int i = 0; i < kIntSize; i++) {
|
||||
x |= static_cast<int>(*--pos_) << i * kBitsPerByte;
|
||||
}
|
||||
rinfo_.data_ = x;
|
||||
}
|
||||
|
||||
void RelocIterator::AdvanceReadData() {
|
||||
intptr_t x = 0;
|
||||
for (int i = 0; i < kIntptrSize; i++) {
|
||||
x |= static_cast<intptr_t>(*--pos_) << i * kBitsPerByte;
|
||||
}
|
||||
rinfo_.data_ = x;
|
||||
}
|
||||
|
||||
void RelocIterator::AdvanceReadLongPCJump() {
|
||||
// Read the 32-kSmallPCDeltaBits most significant bits of the
|
||||
// pc jump in kChunkBits bit chunks and shift them into place.
|
||||
// Stop when the last chunk is encountered.
|
||||
uint32_t pc_jump = 0;
|
||||
for (int i = 0; i < kIntSize; i++) {
|
||||
byte pc_jump_part = *--pos_;
|
||||
pc_jump |= (pc_jump_part >> kLastChunkTagBits) << i * kChunkBits;
|
||||
if ((pc_jump_part & kLastChunkTagMask) == 1) break;
|
||||
}
|
||||
// The least significant kSmallPCDeltaBits bits will be added
|
||||
// later.
|
||||
rinfo_.pc_ += pc_jump << kSmallPCDeltaBits;
|
||||
}
|
||||
|
||||
inline void RelocIterator::ReadShortData() {
|
||||
uint8_t unsigned_b = *pos_;
|
||||
rinfo_.data_ = unsigned_b;
|
||||
}
|
||||
|
||||
void RelocIterator::next() {
|
||||
DCHECK(!done());
|
||||
// Basically, do the opposite of RelocInfoWriter::Write.
|
||||
// Reading of data is as far as possible avoided for unwanted modes,
|
||||
// but we must always update the pc.
|
||||
//
|
||||
// We exit this loop by returning when we find a mode we want.
|
||||
while (pos_ > end_) {
|
||||
int tag = AdvanceGetTag();
|
||||
if (tag == kEmbeddedObjectTag) {
|
||||
ReadShortTaggedPC();
|
||||
if (SetMode(RelocInfo::EMBEDDED_OBJECT)) return;
|
||||
} else if (tag == kCodeTargetTag) {
|
||||
ReadShortTaggedPC();
|
||||
if (SetMode(RelocInfo::CODE_TARGET)) return;
|
||||
} else if (tag == kWasmStubCallTag) {
|
||||
ReadShortTaggedPC();
|
||||
if (SetMode(RelocInfo::WASM_STUB_CALL)) return;
|
||||
} else {
|
||||
DCHECK_EQ(tag, kDefaultTag);
|
||||
RelocInfo::Mode rmode = GetMode();
|
||||
if (rmode == RelocInfo::PC_JUMP) {
|
||||
AdvanceReadLongPCJump();
|
||||
} else {
|
||||
AdvanceReadPC();
|
||||
if (RelocInfo::IsComment(rmode)) {
|
||||
if (SetMode(rmode)) {
|
||||
AdvanceReadData();
|
||||
return;
|
||||
}
|
||||
Advance(kIntptrSize);
|
||||
} else if (RelocInfo::IsDeoptReason(rmode)) {
|
||||
Advance();
|
||||
if (SetMode(rmode)) {
|
||||
ReadShortData();
|
||||
return;
|
||||
}
|
||||
} else if (RelocInfo::IsConstPool(rmode) ||
|
||||
RelocInfo::IsVeneerPool(rmode) ||
|
||||
RelocInfo::IsDeoptId(rmode) ||
|
||||
RelocInfo::IsDeoptPosition(rmode)) {
|
||||
if (SetMode(rmode)) {
|
||||
AdvanceReadInt();
|
||||
return;
|
||||
}
|
||||
Advance(kIntSize);
|
||||
} else if (SetMode(static_cast<RelocInfo::Mode>(rmode))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
done_ = true;
|
||||
}
|
||||
|
||||
RelocIterator::RelocIterator(Code* code, int mode_mask)
|
||||
: RelocIterator(code, code->raw_instruction_start(), code->constant_pool(),
|
||||
code->relocation_end(), code->relocation_start(),
|
||||
mode_mask) {}
|
||||
|
||||
RelocIterator::RelocIterator(const CodeReference code_reference, int mode_mask)
|
||||
: RelocIterator(nullptr, code_reference.instruction_start(),
|
||||
code_reference.constant_pool(),
|
||||
code_reference.relocation_end(),
|
||||
code_reference.relocation_start(), mode_mask) {}
|
||||
|
||||
RelocIterator::RelocIterator(EmbeddedData* embedded_data, Code* code,
|
||||
int mode_mask)
|
||||
: RelocIterator(
|
||||
code, embedded_data->InstructionStartOfBuiltin(code->builtin_index()),
|
||||
code->constant_pool(),
|
||||
code->relocation_start() + code->relocation_size(),
|
||||
code->relocation_start(), mode_mask) {}
|
||||
|
||||
RelocIterator::RelocIterator(const CodeDesc& desc, int mode_mask)
|
||||
: RelocIterator(nullptr, reinterpret_cast<Address>(desc.buffer), 0,
|
||||
desc.buffer + desc.buffer_size,
|
||||
desc.buffer + desc.buffer_size - desc.reloc_size,
|
||||
mode_mask) {}
|
||||
|
||||
RelocIterator::RelocIterator(Vector<byte> instructions,
|
||||
Vector<const byte> reloc_info, Address const_pool,
|
||||
int mode_mask)
|
||||
: RelocIterator(nullptr, reinterpret_cast<Address>(instructions.start()),
|
||||
const_pool, reloc_info.start() + reloc_info.size(),
|
||||
reloc_info.start(), mode_mask) {}
|
||||
|
||||
RelocIterator::RelocIterator(Code* host, Address pc, Address constant_pool,
|
||||
const byte* pos, const byte* end, int mode_mask)
|
||||
: pos_(pos), end_(end), mode_mask_(mode_mask) {
|
||||
// Relocation info is read backwards.
|
||||
DCHECK_GE(pos_, end_);
|
||||
rinfo_.host_ = host;
|
||||
rinfo_.pc_ = pc;
|
||||
rinfo_.constant_pool_ = constant_pool;
|
||||
if (mode_mask_ == 0) pos_ = end_;
|
||||
next();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of RelocInfo
|
||||
|
||||
// static
|
||||
bool RelocInfo::OffHeapTargetIsCodedSpecially() {
|
||||
#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_ARM64) || \
|
||||
defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_IA32)
|
||||
return false;
|
||||
#elif defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64) || \
|
||||
defined(V8_TARGET_ARCH_PPC) || defined(V8_TARGET_ARCH_S390)
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
Address RelocInfo::wasm_call_address() const {
|
||||
DCHECK_EQ(rmode_, WASM_CALL);
|
||||
return Assembler::target_address_at(pc_, constant_pool_);
|
||||
}
|
||||
|
||||
void RelocInfo::set_wasm_call_address(Address address,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
DCHECK_EQ(rmode_, WASM_CALL);
|
||||
Assembler::set_target_address_at(pc_, constant_pool_, address,
|
||||
icache_flush_mode);
|
||||
}
|
||||
|
||||
Address RelocInfo::wasm_stub_call_address() const {
|
||||
DCHECK_EQ(rmode_, WASM_STUB_CALL);
|
||||
return Assembler::target_address_at(pc_, constant_pool_);
|
||||
}
|
||||
|
||||
void RelocInfo::set_wasm_stub_call_address(Address address,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
DCHECK_EQ(rmode_, WASM_STUB_CALL);
|
||||
Assembler::set_target_address_at(pc_, constant_pool_, address,
|
||||
icache_flush_mode);
|
||||
}
|
||||
|
||||
void RelocInfo::set_target_address(Address target,
|
||||
WriteBarrierMode write_barrier_mode,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
DCHECK(IsCodeTargetMode(rmode_) || IsRuntimeEntry(rmode_) ||
|
||||
IsWasmCall(rmode_));
|
||||
Assembler::set_target_address_at(pc_, constant_pool_, target,
|
||||
icache_flush_mode);
|
||||
if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != nullptr &&
|
||||
IsCodeTargetMode(rmode_)) {
|
||||
Code* target_code = Code::GetCodeFromTargetAddress(target);
|
||||
MarkingBarrierForCode(host(), this, target_code);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool RelocInfo::RequiresRelocation(const CodeDesc& desc) {
|
||||
// Ensure there are no code targets or embedded objects present in the
|
||||
// deoptimization entries, they would require relocation after code
|
||||
// generation.
|
||||
int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
|
||||
RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
|
||||
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
|
||||
RelocInfo::kApplyMask;
|
||||
RelocIterator it(desc, mode_mask);
|
||||
return !it.done();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
|
||||
switch (rmode) {
|
||||
case NONE:
|
||||
return "no reloc";
|
||||
case EMBEDDED_OBJECT:
|
||||
return "embedded object";
|
||||
case CODE_TARGET:
|
||||
return "code target";
|
||||
case RELATIVE_CODE_TARGET:
|
||||
return "relative code target";
|
||||
case RUNTIME_ENTRY:
|
||||
return "runtime entry";
|
||||
case COMMENT:
|
||||
return "comment";
|
||||
case EXTERNAL_REFERENCE:
|
||||
return "external reference";
|
||||
case INTERNAL_REFERENCE:
|
||||
return "internal reference";
|
||||
case INTERNAL_REFERENCE_ENCODED:
|
||||
return "encoded internal reference";
|
||||
case OFF_HEAP_TARGET:
|
||||
return "off heap target";
|
||||
case DEOPT_SCRIPT_OFFSET:
|
||||
return "deopt script offset";
|
||||
case DEOPT_INLINING_ID:
|
||||
return "deopt inlining id";
|
||||
case DEOPT_REASON:
|
||||
return "deopt reason";
|
||||
case DEOPT_ID:
|
||||
return "deopt index";
|
||||
case CONST_POOL:
|
||||
return "constant pool";
|
||||
case VENEER_POOL:
|
||||
return "veneer pool";
|
||||
case WASM_CALL:
|
||||
return "internal wasm call";
|
||||
case WASM_STUB_CALL:
|
||||
return "wasm stub call";
|
||||
case JS_TO_WASM_CALL:
|
||||
return "js to wasm call";
|
||||
case NUMBER_OF_MODES:
|
||||
case PC_JUMP:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return "unknown relocation type";
|
||||
}
|
||||
|
||||
void RelocInfo::Print(Isolate* isolate, std::ostream& os) { // NOLINT
|
||||
os << reinterpret_cast<const void*>(pc_) << " " << RelocModeName(rmode_);
|
||||
if (IsComment(rmode_)) {
|
||||
os << " (" << reinterpret_cast<char*>(data_) << ")";
|
||||
} else if (rmode_ == DEOPT_SCRIPT_OFFSET || rmode_ == DEOPT_INLINING_ID) {
|
||||
os << " (" << data() << ")";
|
||||
} else if (rmode_ == DEOPT_REASON) {
|
||||
os << " ("
|
||||
<< DeoptimizeReasonToString(static_cast<DeoptimizeReason>(data_)) << ")";
|
||||
} else if (rmode_ == EMBEDDED_OBJECT) {
|
||||
os << " (" << Brief(target_object()) << ")";
|
||||
} else if (rmode_ == EXTERNAL_REFERENCE) {
|
||||
if (isolate) {
|
||||
ExternalReferenceEncoder ref_encoder(isolate);
|
||||
os << " ("
|
||||
<< ref_encoder.NameOfAddress(isolate, target_external_reference())
|
||||
<< ") ";
|
||||
}
|
||||
os << " (" << reinterpret_cast<const void*>(target_external_reference())
|
||||
<< ")";
|
||||
} else if (IsCodeTargetMode(rmode_)) {
|
||||
const Address code_target = target_address();
|
||||
Code* code = Code::GetCodeFromTargetAddress(code_target);
|
||||
DCHECK(code->IsCode());
|
||||
os << " (" << Code::Kind2String(code->kind());
|
||||
if (Builtins::IsBuiltin(code)) {
|
||||
os << " " << Builtins::name(code->builtin_index());
|
||||
} else if (code->kind() == Code::STUB) {
|
||||
os << " " << CodeStub::MajorName(CodeStub::GetMajorKey(code));
|
||||
}
|
||||
os << ") (" << reinterpret_cast<const void*>(target_address()) << ")";
|
||||
} else if (IsRuntimeEntry(rmode_) && isolate->deoptimizer_data() != nullptr) {
|
||||
// Deoptimization bailouts are stored as runtime entries.
|
||||
DeoptimizeKind type;
|
||||
if (Deoptimizer::IsDeoptimizationEntry(isolate, target_address(), &type)) {
|
||||
int id = GetDeoptimizationId(isolate, type);
|
||||
os << " (" << Deoptimizer::MessageFor(type) << " deoptimization bailout "
|
||||
<< id << ")";
|
||||
}
|
||||
} else if (IsConstPool(rmode_)) {
|
||||
os << " (size " << static_cast<int>(data_) << ")";
|
||||
}
|
||||
|
||||
os << "\n";
|
||||
}
|
||||
#endif // ENABLE_DISASSEMBLER
|
||||
|
||||
#ifdef VERIFY_HEAP
|
||||
void RelocInfo::Verify(Isolate* isolate) {
|
||||
switch (rmode_) {
|
||||
case EMBEDDED_OBJECT:
|
||||
Object::VerifyPointer(isolate, target_object());
|
||||
break;
|
||||
case CODE_TARGET:
|
||||
case RELATIVE_CODE_TARGET: {
|
||||
// convert inline target address to code object
|
||||
Address addr = target_address();
|
||||
CHECK_NE(addr, kNullAddress);
|
||||
// Check that we can find the right code object.
|
||||
Code* code = Code::GetCodeFromTargetAddress(addr);
|
||||
Object* found = isolate->FindCodeObject(addr);
|
||||
CHECK(found->IsCode());
|
||||
CHECK(code->address() == HeapObject::cast(found)->address());
|
||||
break;
|
||||
}
|
||||
case INTERNAL_REFERENCE:
|
||||
case INTERNAL_REFERENCE_ENCODED: {
|
||||
Address target = target_internal_reference();
|
||||
Address pc = target_internal_reference_address();
|
||||
Code* code = Code::cast(isolate->FindCodeObject(pc));
|
||||
CHECK(target >= code->InstructionStart());
|
||||
CHECK(target <= code->InstructionEnd());
|
||||
break;
|
||||
}
|
||||
case OFF_HEAP_TARGET: {
|
||||
Address addr = target_off_heap_target();
|
||||
CHECK_NE(addr, kNullAddress);
|
||||
CHECK_NOT_NULL(InstructionStream::TryLookupCode(isolate, addr));
|
||||
break;
|
||||
}
|
||||
case RUNTIME_ENTRY:
|
||||
case COMMENT:
|
||||
case EXTERNAL_REFERENCE:
|
||||
case DEOPT_SCRIPT_OFFSET:
|
||||
case DEOPT_INLINING_ID:
|
||||
case DEOPT_REASON:
|
||||
case DEOPT_ID:
|
||||
case CONST_POOL:
|
||||
case VENEER_POOL:
|
||||
case WASM_CALL:
|
||||
case WASM_STUB_CALL:
|
||||
case JS_TO_WASM_CALL:
|
||||
case NONE:
|
||||
break;
|
||||
case NUMBER_OF_MODES:
|
||||
case PC_JUMP:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // VERIFY_HEAP
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
428
src/reloc-info.h
Normal file
428
src/reloc-info.h
Normal file
@ -0,0 +1,428 @@
|
||||
// Copyright 2018 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_RELOC_INFO_H_
|
||||
#define V8_RELOC_INFO_H_
|
||||
|
||||
#include "src/globals.h"
|
||||
#include "src/objects.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class CodeReference;
|
||||
class EmbeddedData;
|
||||
|
||||
// Specifies whether to perform icache flush operations on RelocInfo updates.
|
||||
// If FLUSH_ICACHE_IF_NEEDED, the icache will always be flushed if an
|
||||
// instruction was modified. If SKIP_ICACHE_FLUSH the flush will always be
|
||||
// skipped (only use this if you will flush the icache manually before it is
|
||||
// executed).
|
||||
enum ICacheFlushMode { FLUSH_ICACHE_IF_NEEDED, SKIP_ICACHE_FLUSH };
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Relocation information
|
||||
|
||||
// Relocation information consists of the address (pc) of the datum
|
||||
// to which the relocation information applies, the relocation mode
|
||||
// (rmode), and an optional data field. The relocation mode may be
|
||||
// "descriptive" and not indicate a need for relocation, but simply
|
||||
// describe a property of the datum. Such rmodes are useful for GC
|
||||
// and nice disassembly output.
|
||||
|
||||
class RelocInfo {
|
||||
public:
|
||||
// This string is used to add padding comments to the reloc info in cases
|
||||
// where we are not sure to have enough space for patching in during
|
||||
// lazy deoptimization. This is the case if we have indirect calls for which
|
||||
// we do not normally record relocation info.
|
||||
static const char* const kFillerCommentString;
|
||||
|
||||
// The minimum size of a comment is equal to two bytes for the extra tagged
|
||||
// pc and kPointerSize for the actual pointer to the comment.
|
||||
static const int kMinRelocCommentSize = 2 + kPointerSize;
|
||||
|
||||
// The maximum size for a call instruction including pc-jump.
|
||||
static const int kMaxCallSize = 6;
|
||||
|
||||
// The maximum pc delta that will use the short encoding.
|
||||
static const int kMaxSmallPCDelta;
|
||||
|
||||
enum Mode : int8_t {
|
||||
// Please note the order is important (see IsRealRelocMode, IsGCRelocMode,
|
||||
// and IsShareableRelocMode predicates below).
|
||||
|
||||
CODE_TARGET,
|
||||
RELATIVE_CODE_TARGET, // LAST_CODE_TARGET_MODE
|
||||
EMBEDDED_OBJECT, // LAST_GCED_ENUM
|
||||
|
||||
JS_TO_WASM_CALL,
|
||||
WASM_CALL, // FIRST_SHAREABLE_RELOC_MODE
|
||||
WASM_STUB_CALL,
|
||||
|
||||
RUNTIME_ENTRY,
|
||||
COMMENT,
|
||||
|
||||
EXTERNAL_REFERENCE, // The address of an external C++ function.
|
||||
INTERNAL_REFERENCE, // An address inside the same function.
|
||||
|
||||
// Encoded internal reference, used only on MIPS, MIPS64 and PPC.
|
||||
INTERNAL_REFERENCE_ENCODED,
|
||||
|
||||
// An off-heap instruction stream target. See http://goo.gl/Z2HUiM.
|
||||
OFF_HEAP_TARGET,
|
||||
|
||||
// Marks constant and veneer pools. Only used on ARM and ARM64.
|
||||
// They use a custom noncompact encoding.
|
||||
CONST_POOL,
|
||||
VENEER_POOL,
|
||||
|
||||
DEOPT_SCRIPT_OFFSET,
|
||||
DEOPT_INLINING_ID, // Deoptimization source position.
|
||||
DEOPT_REASON, // Deoptimization reason index.
|
||||
DEOPT_ID, // Deoptimization inlining id.
|
||||
|
||||
// This is not an actual reloc mode, but used to encode a long pc jump that
|
||||
// cannot be encoded as part of another record.
|
||||
PC_JUMP,
|
||||
|
||||
// Pseudo-types
|
||||
NUMBER_OF_MODES,
|
||||
NONE, // never recorded value
|
||||
|
||||
LAST_CODE_TARGET_MODE = RELATIVE_CODE_TARGET,
|
||||
FIRST_REAL_RELOC_MODE = CODE_TARGET,
|
||||
LAST_REAL_RELOC_MODE = VENEER_POOL,
|
||||
LAST_GCED_ENUM = EMBEDDED_OBJECT,
|
||||
FIRST_SHAREABLE_RELOC_MODE = WASM_CALL,
|
||||
};
|
||||
|
||||
STATIC_ASSERT(NUMBER_OF_MODES <= kBitsPerInt);
|
||||
|
||||
RelocInfo() = default;
|
||||
|
||||
RelocInfo(Address pc, Mode rmode, intptr_t data, Code* host,
|
||||
Address constant_pool = kNullAddress)
|
||||
: pc_(pc),
|
||||
rmode_(rmode),
|
||||
data_(data),
|
||||
host_(host),
|
||||
constant_pool_(constant_pool) {}
|
||||
|
||||
static inline bool IsRealRelocMode(Mode mode) {
|
||||
return mode >= FIRST_REAL_RELOC_MODE && mode <= LAST_REAL_RELOC_MODE;
|
||||
}
|
||||
// Is the relocation mode affected by GC?
|
||||
static inline bool IsGCRelocMode(Mode mode) { return mode <= LAST_GCED_ENUM; }
|
||||
static inline bool IsShareableRelocMode(Mode mode) {
|
||||
static_assert(RelocInfo::NONE >= RelocInfo::FIRST_SHAREABLE_RELOC_MODE,
|
||||
"Users of this function rely on NONE being a sharable "
|
||||
"relocation mode.");
|
||||
return mode >= RelocInfo::FIRST_SHAREABLE_RELOC_MODE;
|
||||
}
|
||||
static inline bool IsCodeTarget(Mode mode) { return mode == CODE_TARGET; }
|
||||
static inline bool IsCodeTargetMode(Mode mode) {
|
||||
return mode <= LAST_CODE_TARGET_MODE;
|
||||
}
|
||||
static inline bool IsRelativeCodeTarget(Mode mode) {
|
||||
return mode == RELATIVE_CODE_TARGET;
|
||||
}
|
||||
static inline bool IsEmbeddedObject(Mode mode) {
|
||||
return mode == EMBEDDED_OBJECT;
|
||||
}
|
||||
static inline bool IsRuntimeEntry(Mode mode) { return mode == RUNTIME_ENTRY; }
|
||||
static inline bool IsWasmCall(Mode mode) { return mode == WASM_CALL; }
|
||||
static inline bool IsWasmStubCall(Mode mode) {
|
||||
return mode == WASM_STUB_CALL;
|
||||
}
|
||||
static inline bool IsComment(Mode mode) { return mode == COMMENT; }
|
||||
static inline bool IsConstPool(Mode mode) { return mode == CONST_POOL; }
|
||||
static inline bool IsVeneerPool(Mode mode) { return mode == VENEER_POOL; }
|
||||
static inline bool IsDeoptPosition(Mode mode) {
|
||||
return mode == DEOPT_SCRIPT_OFFSET || mode == DEOPT_INLINING_ID;
|
||||
}
|
||||
static inline bool IsDeoptReason(Mode mode) { return mode == DEOPT_REASON; }
|
||||
static inline bool IsDeoptId(Mode mode) { return mode == DEOPT_ID; }
|
||||
static inline bool IsExternalReference(Mode mode) {
|
||||
return mode == EXTERNAL_REFERENCE;
|
||||
}
|
||||
static inline bool IsInternalReference(Mode mode) {
|
||||
return mode == INTERNAL_REFERENCE;
|
||||
}
|
||||
static inline bool IsInternalReferenceEncoded(Mode mode) {
|
||||
return mode == INTERNAL_REFERENCE_ENCODED;
|
||||
}
|
||||
static inline bool IsOffHeapTarget(Mode mode) {
|
||||
return mode == OFF_HEAP_TARGET;
|
||||
}
|
||||
static inline bool IsNone(Mode mode) { return mode == NONE; }
|
||||
static inline bool IsWasmReference(Mode mode) {
|
||||
return IsWasmPtrReference(mode);
|
||||
}
|
||||
static inline bool IsWasmPtrReference(Mode mode) {
|
||||
return mode == WASM_CALL || mode == JS_TO_WASM_CALL;
|
||||
}
|
||||
|
||||
static inline bool IsOnlyForSerializer(Mode mode) {
|
||||
return mode == EXTERNAL_REFERENCE || mode == OFF_HEAP_TARGET;
|
||||
}
|
||||
|
||||
static constexpr int ModeMask(Mode mode) { return 1 << mode; }
|
||||
|
||||
// Accessors
|
||||
Address pc() const { return pc_; }
|
||||
Mode rmode() const { return rmode_; }
|
||||
intptr_t data() const { return data_; }
|
||||
Code* host() const { return host_; }
|
||||
Address constant_pool() const { return constant_pool_; }
|
||||
|
||||
// Apply a relocation by delta bytes. When the code object is moved, PC
|
||||
// relative addresses have to be updated as well as absolute addresses
|
||||
// inside the code (internal references).
|
||||
// Do not forget to flush the icache afterwards!
|
||||
V8_INLINE void apply(intptr_t delta);
|
||||
|
||||
// Is the pointer this relocation info refers to coded like a plain pointer
|
||||
// or is it strange in some way (e.g. relative or patched into a series of
|
||||
// instructions).
|
||||
bool IsCodedSpecially();
|
||||
|
||||
// The static pendant to IsCodedSpecially, just for off-heap targets. Used
|
||||
// during deserialization, when we don't actually have a RelocInfo handy.
|
||||
static bool OffHeapTargetIsCodedSpecially();
|
||||
|
||||
// If true, the pointer this relocation info refers to is an entry in the
|
||||
// constant pool, otherwise the pointer is embedded in the instruction stream.
|
||||
bool IsInConstantPool();
|
||||
|
||||
// Returns the deoptimization id for the entry associated with the reloc info
|
||||
// where {kind} is the deoptimization kind.
|
||||
// This is only used for printing RUNTIME_ENTRY relocation info.
|
||||
int GetDeoptimizationId(Isolate* isolate, DeoptimizeKind kind);
|
||||
|
||||
Address wasm_call_address() const;
|
||||
Address wasm_stub_call_address() const;
|
||||
Address js_to_wasm_address() const;
|
||||
|
||||
uint32_t wasm_call_tag() const;
|
||||
|
||||
void set_wasm_call_address(
|
||||
Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
void set_wasm_stub_call_address(
|
||||
Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
void set_js_to_wasm_address(
|
||||
Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
|
||||
void set_target_address(
|
||||
Address target,
|
||||
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
|
||||
// this relocation applies to;
|
||||
// can only be called if IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
|
||||
V8_INLINE Address target_address();
|
||||
V8_INLINE HeapObject* target_object();
|
||||
V8_INLINE Handle<HeapObject> target_object_handle(Assembler* origin);
|
||||
V8_INLINE void set_target_object(
|
||||
Heap* heap, HeapObject* target,
|
||||
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
V8_INLINE Address target_runtime_entry(Assembler* origin);
|
||||
V8_INLINE void set_target_runtime_entry(
|
||||
Address target,
|
||||
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
V8_INLINE Address target_off_heap_target();
|
||||
V8_INLINE Cell* target_cell();
|
||||
V8_INLINE Handle<Cell> target_cell_handle();
|
||||
V8_INLINE void set_target_cell(
|
||||
Cell* cell, WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
V8_INLINE void set_target_external_reference(
|
||||
Address, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
|
||||
// Returns the address of the constant pool entry where the target address
|
||||
// is held. This should only be called if IsInConstantPool returns true.
|
||||
V8_INLINE Address constant_pool_entry_address();
|
||||
|
||||
// Read the address of the word containing the target_address in an
|
||||
// instruction stream. What this means exactly is architecture-independent.
|
||||
// The only architecture-independent user of this function is the serializer.
|
||||
// The serializer uses it to find out how many raw bytes of instruction to
|
||||
// output before the next target. Architecture-independent code shouldn't
|
||||
// dereference the pointer it gets back from this.
|
||||
V8_INLINE Address target_address_address();
|
||||
|
||||
// This indicates how much space a target takes up when deserializing a code
|
||||
// stream. For most architectures this is just the size of a pointer. For
|
||||
// an instruction like movw/movt where the target bits are mixed into the
|
||||
// instruction bits the size of the target will be zero, indicating that the
|
||||
// serializer should not step forwards in memory after a target is resolved
|
||||
// and written. In this case the target_address_address function above
|
||||
// should return the end of the instructions to be patched, allowing the
|
||||
// deserializer to deserialize the instructions as raw bytes and put them in
|
||||
// place, ready to be patched with the target.
|
||||
V8_INLINE int target_address_size();
|
||||
|
||||
// Read the reference in the instruction this relocation
|
||||
// applies to; can only be called if rmode_ is EXTERNAL_REFERENCE.
|
||||
V8_INLINE Address target_external_reference();
|
||||
|
||||
// Read the reference in the instruction this relocation
|
||||
// applies to; can only be called if rmode_ is INTERNAL_REFERENCE.
|
||||
V8_INLINE Address target_internal_reference();
|
||||
|
||||
// Return the reference address this relocation applies to;
|
||||
// can only be called if rmode_ is INTERNAL_REFERENCE.
|
||||
V8_INLINE Address target_internal_reference_address();
|
||||
|
||||
// Wipe out a relocation to a fixed value, used for making snapshots
|
||||
// reproducible.
|
||||
V8_INLINE void WipeOut();
|
||||
|
||||
template <typename ObjectVisitor>
|
||||
inline void Visit(ObjectVisitor* v);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Check whether the given code contains relocation information that
|
||||
// either is position-relative or movable by the garbage collector.
|
||||
static bool RequiresRelocation(const CodeDesc& desc);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
// Printing
|
||||
static const char* RelocModeName(Mode rmode);
|
||||
void Print(Isolate* isolate, std::ostream& os); // NOLINT
|
||||
#endif // ENABLE_DISASSEMBLER
|
||||
#ifdef VERIFY_HEAP
|
||||
void Verify(Isolate* isolate);
|
||||
#endif
|
||||
|
||||
static const int kApplyMask; // Modes affected by apply. Depends on arch.
|
||||
|
||||
private:
|
||||
// On ARM/ARM64, note that pc_ is the address of the instruction referencing
|
||||
// the constant pool and not the address of the constant pool entry.
|
||||
Address pc_;
|
||||
Mode rmode_;
|
||||
intptr_t data_ = 0;
|
||||
Code* host_;
|
||||
Address constant_pool_ = kNullAddress;
|
||||
friend class RelocIterator;
|
||||
};
|
||||
|
||||
// RelocInfoWriter serializes a stream of relocation info. It writes towards
|
||||
// lower addresses.
|
||||
class RelocInfoWriter BASE_EMBEDDED {
|
||||
public:
|
||||
RelocInfoWriter() : pos_(nullptr), last_pc_(nullptr) {}
|
||||
|
||||
byte* pos() const { return pos_; }
|
||||
byte* last_pc() const { return last_pc_; }
|
||||
|
||||
void Write(const RelocInfo* rinfo);
|
||||
|
||||
// Update the state of the stream after reloc info buffer
|
||||
// and/or code is moved while the stream is active.
|
||||
void Reposition(byte* pos, byte* pc) {
|
||||
pos_ = pos;
|
||||
last_pc_ = pc;
|
||||
}
|
||||
|
||||
// Max size (bytes) of a written RelocInfo. Longest encoding is
|
||||
// ExtraTag, VariableLengthPCJump, ExtraTag, pc_delta, data_delta.
|
||||
static constexpr int kMaxSize = 1 + 4 + 1 + 1 + kPointerSize;
|
||||
|
||||
private:
|
||||
inline uint32_t WriteLongPCJump(uint32_t pc_delta);
|
||||
|
||||
inline void WriteShortTaggedPC(uint32_t pc_delta, int tag);
|
||||
inline void WriteShortData(intptr_t data_delta);
|
||||
|
||||
inline void WriteMode(RelocInfo::Mode rmode);
|
||||
inline void WriteModeAndPC(uint32_t pc_delta, RelocInfo::Mode rmode);
|
||||
inline void WriteIntData(int data_delta);
|
||||
inline void WriteData(intptr_t data_delta);
|
||||
|
||||
byte* pos_;
|
||||
byte* last_pc_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RelocInfoWriter);
|
||||
};
|
||||
|
||||
// A RelocIterator iterates over relocation information.
|
||||
// Typical use:
|
||||
//
|
||||
// for (RelocIterator it(code); !it.done(); it.next()) {
|
||||
// // do something with it.rinfo() here
|
||||
// }
|
||||
//
|
||||
// A mask can be specified to skip unwanted modes.
|
||||
class RelocIterator : public Malloced {
|
||||
public:
|
||||
// Create a new iterator positioned at
|
||||
// the beginning of the reloc info.
|
||||
// Relocation information with mode k is included in the
|
||||
// iteration iff bit k of mode_mask is set.
|
||||
explicit RelocIterator(Code* code, int mode_mask = -1);
|
||||
explicit RelocIterator(EmbeddedData* embedded_data, Code* code,
|
||||
int mode_mask);
|
||||
explicit RelocIterator(const CodeDesc& desc, int mode_mask = -1);
|
||||
explicit RelocIterator(const CodeReference code_reference,
|
||||
int mode_mask = -1);
|
||||
explicit RelocIterator(Vector<byte> instructions,
|
||||
Vector<const byte> reloc_info, Address const_pool,
|
||||
int mode_mask = -1);
|
||||
RelocIterator(RelocIterator&&) = default;
|
||||
RelocIterator& operator=(RelocIterator&&) = default;
|
||||
|
||||
// Iteration
|
||||
bool done() const { return done_; }
|
||||
void next();
|
||||
|
||||
// Return pointer valid until next next().
|
||||
RelocInfo* rinfo() {
|
||||
DCHECK(!done());
|
||||
return &rinfo_;
|
||||
}
|
||||
|
||||
private:
|
||||
RelocIterator(Code* host, Address pc, Address constant_pool, const byte* pos,
|
||||
const byte* end, int mode_mask);
|
||||
|
||||
// Advance* moves the position before/after reading.
|
||||
// *Read* reads from current byte(s) into rinfo_.
|
||||
// *Get* just reads and returns info on current byte.
|
||||
void Advance(int bytes = 1) { pos_ -= bytes; }
|
||||
int AdvanceGetTag();
|
||||
RelocInfo::Mode GetMode();
|
||||
|
||||
void AdvanceReadLongPCJump();
|
||||
|
||||
void ReadShortTaggedPC();
|
||||
void ReadShortData();
|
||||
|
||||
void AdvanceReadPC();
|
||||
void AdvanceReadInt();
|
||||
void AdvanceReadData();
|
||||
|
||||
// If the given mode is wanted, set it in rinfo_ and return true.
|
||||
// Else return false. Used for efficiently skipping unwanted modes.
|
||||
bool SetMode(RelocInfo::Mode mode) {
|
||||
return (mode_mask_ & (1 << mode)) ? (rinfo_.rmode_ = mode, true) : false;
|
||||
}
|
||||
|
||||
const byte* pos_;
|
||||
const byte* end_;
|
||||
RelocInfo rinfo_;
|
||||
bool done_ = false;
|
||||
const int mode_mask_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RelocIterator);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_RELOC_INFO_H_
|
@ -5,7 +5,6 @@
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
|
||||
#include "src/arguments.h"
|
||||
#include "src/assembler.h"
|
||||
#include "src/base/utils/random-number-generator.h"
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/counters.h"
|
||||
|
@ -3,7 +3,6 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/arguments-inl.h"
|
||||
#include "src/assembler.h"
|
||||
#include "src/compiler/wasm-compiler.h"
|
||||
#include "src/conversions.h"
|
||||
#include "src/debug/debug.h"
|
||||
|
@ -4,13 +4,13 @@
|
||||
|
||||
#include "src/runtime/runtime.h"
|
||||
|
||||
#include "src/assembler.h"
|
||||
#include "src/base/hashmap.h"
|
||||
#include "src/contexts.h"
|
||||
#include "src/handles-inl.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/reloc-info.h"
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "src/assembler.h"
|
||||
#include "src/globals.h"
|
||||
#include "src/isolate.h"
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/api.h"
|
||||
#include "src/assembler.h"
|
||||
#include "src/base/atomicops.h"
|
||||
#include "src/base/once.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
@ -19,6 +18,7 @@
|
||||
#include "src/libsampler/sampler.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/profiler/heap-profiler.h"
|
||||
#include "src/reloc-info.h"
|
||||
#include "src/runtime-profiler.h"
|
||||
#include "src/simulator.h"
|
||||
#include "src/snapshot/natives.h"
|
||||
|
@ -32,7 +32,6 @@
|
||||
|
||||
#include "include/libplatform/libplatform.h"
|
||||
#include "include/v8-platform.h"
|
||||
#include "src/assembler.h"
|
||||
#include "src/debug/debug-interface.h"
|
||||
#include "src/flags.h"
|
||||
#include "src/heap/factory.h"
|
||||
|
Loading…
Reference in New Issue
Block a user