Commit 4c5bf68e authored by jgruber's avatar jgruber Committed by Commit Bot

[builtins] Support off-heap constant pool access

Access to the constant pool of off-heap builtins must use
Instruction{Start,Size} instead of the raw instruction_{start,size}
accessors, and we need to copy the constant_pool_offset field when
creating trampolines.

This in turn required access to the embedded blob without an
associated isolate, which is now implemented by global variable set by
each isolate. Both writes and reads are relaxed, as races do not
matter since each isolate will attempt to set the same value of the
blob and its size.

Drive-by: Support off-heap code disassembly.

Bug: v8:6666,v8:7575
Change-Id: I4f203acd4dc128339cf2dd54b3253d9552616649
Reviewed-on: https://chromium-review.googlesource.com/973442
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52209}
parent 451d0c76
......@@ -66,10 +66,8 @@ declare_args() {
v8_enable_fast_mksnapshot = false
# Enable embedded builtins.
# TODO(jgruber,v8:6666): Support ppc, ia32 and maybe MSVC.
v8_enable_embedded_builtins =
v8_current_cpu != "x86" && v8_current_cpu != "ppc" &&
v8_current_cpu != "ppc64" && (!is_win || is_clang)
# TODO(jgruber,v8:6666): Support ia32 and maybe MSVC.
v8_enable_embedded_builtins = v8_current_cpu != "x86" && (!is_win || is_clang)
# Enable code-generation-time checking of types in the CodeStubAssembler.
v8_enable_verify_csa = false
......
......@@ -195,12 +195,12 @@ Address Builtins::CppEntryOf(int index) {
}
// static
bool Builtins::IsBuiltin(Code* code) {
bool Builtins::IsBuiltin(const Code* code) {
return Builtins::IsBuiltinId(code->builtin_index());
}
// static
bool Builtins::IsOffHeapBuiltin(Code* code) {
bool Builtins::IsOffHeapBuiltin(const Code* code) {
#ifdef V8_EMBEDDED_BUILTINS
return Builtins::IsBuiltinId(code->builtin_index()) &&
Builtins::IsOffHeapSafe(code->builtin_index());
......
......@@ -111,10 +111,10 @@ class Builtins {
// True, iff the given code object is a builtin. Note that this does not
// necessarily mean that its kind is Code::BUILTIN.
static bool IsBuiltin(Code* code);
static bool IsBuiltin(const Code* code);
// True, iff the given code object is a builtin with off-heap code.
static bool IsOffHeapBuiltin(Code* code);
static bool IsOffHeapBuiltin(const Code* code);
// Returns true iff the given builtin can be lazy-loaded from the snapshot.
// This is true in general for most builtins with the exception of a few
......
......@@ -1877,6 +1877,7 @@ Handle<Code> Factory::NewOffHeapTrampolineFor(Handle<Code> code,
result->set_handler_table_offset(code->handler_table_offset());
result->code_data_container()->set_kind_specific_flags(
code->code_data_container()->kind_specific_flags());
result->set_constant_pool_offset(code->constant_pool_offset());
if (code->has_safepoint_info()) {
result->set_safepoint_table_offset(code->safepoint_table_offset());
}
......
......@@ -26,8 +26,7 @@ Code* InstructionStream::TryLookupCode(Isolate* isolate, Address address) {
#ifdef V8_EMBEDDED_BUILTINS
if (!PcIsOffHeap(isolate, address)) return nullptr;
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
isolate->embedded_blob_size());
EmbeddedData d = EmbeddedData::FromBlob();
int l = 0, r = Builtins::builtin_count;
while (l < r) {
......
......@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <atomic>
#include <fstream> // NOLINT(readability/streams)
#include <sstream>
......@@ -75,9 +76,40 @@ extern const uint8_t* TrustedEmbeddedBlob();
extern uint32_t TrustedEmbeddedBlobSize();
#endif
namespace {
// These variables provide access to the current embedded blob without requiring
// an isolate instance. This is needed e.g. by Code::InstructionStart, which may
// not have access to an isolate but still needs to access the embedded blob.
// The variables are initialized by each isolate in Init(). Writes and reads are
// relaxed since we can guarantee that the current thread has initialized these
// variables before accessing them. Different threads may race, but this is fine
// since they all attempt to set the same values of the blob pointer and size.
std::atomic<const uint8_t*> current_embedded_blob_(nullptr);
std::atomic<uint32_t> current_embedded_blob_size_(0);
} // namespace
void Isolate::SetEmbeddedBlob(const uint8_t* blob, uint32_t blob_size) {
embedded_blob_ = blob;
embedded_blob_size_ = blob_size;
current_embedded_blob_.store(blob, std::memory_order_relaxed);
current_embedded_blob_size_.store(blob_size, std::memory_order_relaxed);
}
const uint8_t* Isolate::embedded_blob() const { return embedded_blob_; }
uint32_t Isolate::embedded_blob_size() const { return embedded_blob_size_; }
#endif
// static
const uint8_t* Isolate::CurrentEmbeddedBlob() {
return current_embedded_blob_.load(std::memory_order::memory_order_relaxed);
}
// static
uint32_t Isolate::CurrentEmbeddedBlobSize() {
return current_embedded_blob_size_.load(
std::memory_order::memory_order_relaxed);
}
#endif // V8_EMBEDDED_BUILTINS
int ThreadId::AllocateThreadId() {
int new_id = base::Relaxed_AtomicIncrement(&highest_thread_id_, 1);
......@@ -2838,8 +2870,7 @@ void CreateOffHeapTrampolines(Isolate* isolate) {
HandleScope scope(isolate);
Builtins* builtins = isolate->builtins();
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
isolate->embedded_blob_size());
EmbeddedData d = EmbeddedData::FromBlob();
CodeSpaceMemoryModificationScope code_allocation(isolate->heap());
for (int i = 0; i < Builtins::builtin_count; i++) {
......@@ -2881,10 +2912,7 @@ void Isolate::PrepareEmbeddedBlobForSerialization() {
uint8_t* data;
uint32_t size;
InstructionStream::CreateOffHeapInstructionStream(this, &data, &size);
embedded_blob_ = const_cast<const uint8_t*>(data);
embedded_blob_size_ = size;
SetEmbeddedBlob(const_cast<const uint8_t*>(data), size);
CreateOffHeapTrampolines(this);
}
#endif // V8_EMBEDDED_BUILTINS
......@@ -2948,15 +2976,12 @@ bool Isolate::Init(StartupDeserializer* des) {
#ifdef V8_EMBEDDED_BUILTINS
#ifdef V8_MULTI_SNAPSHOTS
if (FLAG_untrusted_code_mitigations) {
embedded_blob_ = DefaultEmbeddedBlob();
embedded_blob_size_ = DefaultEmbeddedBlobSize();
SetEmbeddedBlob(DefaultEmbeddedBlob(), DefaultEmbeddedBlobSize());
} else {
embedded_blob_ = TrustedEmbeddedBlob();
embedded_blob_size_ = TrustedEmbeddedBlobSize();
SetEmbeddedBlob(TrustedEmbeddedBlob(), TrustedEmbeddedBlobSize());
}
#else
embedded_blob_ = DefaultEmbeddedBlob();
embedded_blob_size_ = DefaultEmbeddedBlobSize();
SetEmbeddedBlob(DefaultEmbeddedBlob(), DefaultEmbeddedBlobSize());
#endif
#endif
......
......@@ -1268,6 +1268,10 @@ class Isolate {
return builtins_constants_table_builder_;
}
static const uint8_t* CurrentEmbeddedBlob();
static uint32_t CurrentEmbeddedBlobSize();
// TODO(jgruber): Remove these in favor of the static methods above.
const uint8_t* embedded_blob() const;
uint32_t embedded_blob_size() const;
#endif
......@@ -1648,6 +1652,8 @@ class Isolate {
// which is stored on the root list prior to serialization.
BuiltinsConstantsTableBuilder* builtins_constants_table_builder_ = nullptr;
void SetEmbeddedBlob(const uint8_t* blob, uint32_t blob_size);
const uint8_t* embedded_blob_ = nullptr;
uint32_t embedded_blob_size_ = 0;
#endif
......
......@@ -966,8 +966,8 @@ void CodeDataContainer::CodeDataContainerVerify() {
}
void Code::CodeVerify() {
CHECK_LE(constant_pool_offset(), instruction_size());
CHECK(IsAligned(reinterpret_cast<intptr_t>(instruction_start()),
CHECK_LE(constant_pool_offset(), InstructionSize());
CHECK(IsAligned(reinterpret_cast<intptr_t>(InstructionStart()),
kCodeAlignment));
relocation_info()->ObjectVerify();
Address last_gc_pc = nullptr;
......
......@@ -14000,31 +14000,25 @@ SafepointEntry Code::GetSafepointEntry(Address pc) {
}
#ifdef V8_EMBEDDED_BUILTINS
int Code::OffHeapInstructionSize() {
int Code::OffHeapInstructionSize() const {
DCHECK(Builtins::IsOffHeapBuiltin(this));
Isolate* isolate = GetIsolate();
if (isolate->embedded_blob() == nullptr) return instruction_size();
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
isolate->embedded_blob_size());
if (Isolate::CurrentEmbeddedBlob() == nullptr) return instruction_size();
EmbeddedData d = EmbeddedData::FromBlob();
return d.InstructionSizeOfBuiltin(builtin_index());
}
Address Code::OffHeapInstructionStart() {
Address Code::OffHeapInstructionStart() const {
DCHECK(Builtins::IsOffHeapBuiltin(this));
Isolate* isolate = GetIsolate();
if (isolate->embedded_blob() == nullptr) return instruction_start();
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
isolate->embedded_blob_size());
if (Isolate::CurrentEmbeddedBlob() == nullptr) return instruction_start();
EmbeddedData d = EmbeddedData::FromBlob();
return reinterpret_cast<Address>(
const_cast<uint8_t*>(d.InstructionStartOfBuiltin(builtin_index())));
}
Address Code::OffHeapInstructionEnd() {
Address Code::OffHeapInstructionEnd() const {
DCHECK(Builtins::IsOffHeapBuiltin(this));
Isolate* isolate = GetIsolate();
if (isolate->embedded_blob() == nullptr) return instruction_end();
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
isolate->embedded_blob_size());
if (Isolate::CurrentEmbeddedBlob() == nullptr) return instruction_end();
EmbeddedData d = EmbeddedData::FromBlob();
return reinterpret_cast<Address>(
const_cast<uint8_t*>(d.InstructionStartOfBuiltin(builtin_index()) +
d.InstructionSizeOfBuiltin(builtin_index())));
......@@ -14520,10 +14514,10 @@ void Code::Disassemble(const char* name, std::ostream& os, void* current_pc) {
os << "compiler = " << (is_turbofanned() ? "turbofan" : "unknown") << "\n";
os << "address = " << static_cast<const void*>(this) << "\n";
os << "Body (size = " << instruction_size() << ")\n";
os << "Body (size = " << InstructionSize() << ")\n";
{
Isolate* isolate = GetIsolate();
int size = instruction_size();
int size = InstructionSize();
int safepoint_offset =
has_safepoint_info() ? safepoint_table_offset() : size;
int constant_pool_offset = this->constant_pool_offset();
......@@ -14533,7 +14527,7 @@ void Code::Disassemble(const char* name, std::ostream& os, void* current_pc) {
int code_size =
Min(handler_offset, Min(safepoint_offset, constant_pool_offset));
os << "Instructions (size = " << code_size << ")\n";
byte* begin = instruction_start();
byte* begin = InstructionStart();
byte* end = begin + code_size;
Disassembler::Decode(isolate, &os, begin, end, this, current_pc);
......@@ -14574,7 +14568,7 @@ void Code::Disassemble(const char* name, std::ostream& os, void* current_pc) {
os << "Safepoints (size = " << table.size() << ")\n";
for (unsigned i = 0; i < table.length(); i++) {
unsigned pc_offset = table.GetPcOffset(i);
os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
os << static_cast<const void*>(InstructionStart() + pc_offset) << " ";
os << std::setw(6) << std::hex << pc_offset << " " << std::setw(4);
int trampoline_pc = table.GetTrampolinePcOffset(i);
print_pc(os, trampoline_pc);
......
......@@ -224,7 +224,7 @@ void Code::set_next_code_link(Object* value) {
code_data_container()->set_next_code_link(value);
}
int Code::InstructionSize() {
int Code::InstructionSize() const {
#ifdef V8_EMBEDDED_BUILTINS
if (Builtins::IsOffHeapBuiltin(this)) return OffHeapInstructionSize();
#endif
......@@ -235,7 +235,7 @@ byte* Code::instruction_start() const {
return const_cast<byte*>(FIELD_ADDR_CONST(this, kHeaderSize));
}
Address Code::InstructionStart() {
Address Code::InstructionStart() const {
#ifdef V8_EMBEDDED_BUILTINS
if (Builtins::IsOffHeapBuiltin(this)) return OffHeapInstructionStart();
#endif
......@@ -246,7 +246,7 @@ byte* Code::instruction_end() const {
return instruction_start() + instruction_size();
}
Address Code::InstructionEnd() {
Address Code::InstructionEnd() const {
#ifdef V8_EMBEDDED_BUILTINS
if (Builtins::IsOffHeapBuiltin(this)) return OffHeapInstructionEnd();
#endif
......@@ -503,7 +503,7 @@ bool Code::is_optimized_code() const { return kind() == OPTIMIZED_FUNCTION; }
bool Code::is_wasm_code() const { return kind() == WASM_FUNCTION; }
int Code::constant_pool_offset() const {
if (!FLAG_enable_embedded_constant_pool) return instruction_size();
if (!FLAG_enable_embedded_constant_pool) return InstructionSize();
return READ_INT_FIELD(this, kConstantPoolOffset);
}
......@@ -512,11 +512,11 @@ void Code::set_constant_pool_offset(int value) {
WRITE_INT_FIELD(this, kConstantPoolOffset, value);
}
Address Code::constant_pool() {
Address Code::constant_pool() const {
if (FLAG_enable_embedded_constant_pool) {
int offset = constant_pool_offset();
if (offset < instruction_size()) {
return FIELD_ADDR(this, kHeaderSize + offset);
if (offset < InstructionSize()) {
return InstructionStart() + offset;
}
}
return nullptr;
......
......@@ -63,9 +63,9 @@ class Code : public HeapObject {
// this may from instruction_size in that this will return the size of the
// off-heap instruction stream rather than the on-heap trampoline located
// at instruction_start.
inline int InstructionSize();
inline int InstructionSize() const;
#ifdef V8_EMBEDDED_BUILTINS
int OffHeapInstructionSize();
int OffHeapInstructionSize() const;
#endif
// [relocation_info]: Code relocation information
......@@ -182,7 +182,7 @@ class Code : public HeapObject {
inline void set_is_exception_caught(bool flag);
// [constant_pool]: The constant pool for this function.
inline Address constant_pool();
inline Address constant_pool() const;
// Get the safepoint entry for the given pc.
SafepointEntry GetSafepointEntry(Address pc);
......@@ -219,9 +219,9 @@ class Code : public HeapObject {
// Returns the address of the first instruction. For off-heap code objects
// this differs from instruction_start (which would point to the off-heap
// trampoline instead).
inline Address InstructionStart();
inline Address InstructionStart() const;
#ifdef V8_EMBEDDED_BUILTINS
Address OffHeapInstructionStart();
Address OffHeapInstructionStart() const;
#endif
// Returns the address right after the last instruction.
......@@ -230,9 +230,9 @@ class Code : public HeapObject {
// Returns the address right after the last instruction. For off-heap code
// objects this differs from instruction_end (which would point to the
// off-heap trampoline instead).
inline Address InstructionEnd();
inline Address InstructionEnd() const;
#ifdef V8_EMBEDDED_BUILTINS
Address OffHeapInstructionEnd();
Address OffHeapInstructionEnd() const;
#endif
// Returns the size of the instructions, padding, relocation and unwinding
......
......@@ -524,8 +524,7 @@ bool Deserializer<AllocatorT>::ReadData(MaybeObject** current,
reinterpret_cast<Address>(current) + skip);
CHECK_NOT_NULL(isolate->embedded_blob());
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
isolate->embedded_blob_size());
EmbeddedData d = EmbeddedData::FromBlob();
const uint8_t* address = d.InstructionStartOfBuiltin(builtin_index);
CHECK_NOT_NULL(address);
......
......@@ -353,8 +353,7 @@ v8::StartupData WarmUpSnapshotDataBlob(v8::SnapshotCreator* snapshot_creator,
void WriteEmbeddedFile(v8::SnapshotCreator* creator, SnapshotWriter* writer) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(creator->GetIsolate());
isolate->PrepareEmbeddedBlobForSerialization();
i::EmbeddedData embedded_blob = i::EmbeddedData::FromBlob(
isolate->embedded_blob(), isolate->embedded_blob_size());
i::EmbeddedData embedded_blob = i::EmbeddedData::FromBlob();
writer->WriteEmbedded(&embedded_blob);
}
#endif // V8_EMBEDDED_BUILTINS
......
......@@ -394,7 +394,9 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
return {blob, blob_size};
}
EmbeddedData EmbeddedData::FromBlob(const uint8_t* data, uint32_t size) {
EmbeddedData EmbeddedData::FromBlob() {
const uint8_t* data = Isolate::CurrentEmbeddedBlob();
uint32_t size = Isolate::CurrentEmbeddedBlobSize();
DCHECK_NOT_NULL(data);
DCHECK_LT(0, size);
return {data, size};
......
......@@ -83,7 +83,7 @@ class BuiltinSnapshotData final : public SnapshotData {
class EmbeddedData final {
public:
static EmbeddedData FromIsolate(Isolate* isolate);
static EmbeddedData FromBlob(const uint8_t* data, uint32_t size);
static EmbeddedData FromBlob();
const uint8_t* data() const { return data_; }
uint32_t size() const { return size_; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment