Separate metadata from code in the embedded data blob
Some platforms disable reading of bytes in the .text section, so move the metadata into a separate .rodata section. Bug: v8:10707 Change-Id: I30ef7a180f489f175c31f9d4dcd02115c9f516c2 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2301113 Commit-Queue: Toan Pham <toanpham@google.com> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#68984}
This commit is contained in:
parent
991fc23962
commit
66ed564412
@ -8887,9 +8887,9 @@ UnwindState Isolate::GetUnwindState() {
|
||||
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
unwind_state.embedded_code_range.start =
|
||||
reinterpret_cast<const void*>(isolate->embedded_blob());
|
||||
reinterpret_cast<const void*>(isolate->embedded_blob_code());
|
||||
unwind_state.embedded_code_range.length_in_bytes =
|
||||
isolate->embedded_blob_size();
|
||||
isolate->embedded_blob_code_size();
|
||||
|
||||
std::array<std::pair<i::Builtins::Name, JSEntryStub*>, 3> entry_stubs = {
|
||||
{{i::Builtins::kJSEntry, &unwind_state.js_entry_stub},
|
||||
|
@ -350,8 +350,8 @@ constexpr int OffHeapTrampolineGenerator::kBufferSize;
|
||||
Handle<Code> Builtins::GenerateOffHeapTrampolineFor(
|
||||
Isolate* isolate, Address off_heap_entry, int32_t kind_specfic_flags,
|
||||
bool generate_jump_to_instruction_stream) {
|
||||
DCHECK_NOT_NULL(isolate->embedded_blob());
|
||||
DCHECK_NE(0, isolate->embedded_blob_size());
|
||||
DCHECK_NOT_NULL(isolate->embedded_blob_code());
|
||||
DCHECK_NE(0, isolate->embedded_blob_code_size());
|
||||
|
||||
OffHeapTrampolineGenerator generator(isolate);
|
||||
|
||||
|
@ -237,7 +237,7 @@ bool SafeStackFrameIterator::IsNoFrameBytecodeHandlerPc(Isolate* isolate,
|
||||
Address pc,
|
||||
Address fp) const {
|
||||
// Return false for builds with non-embedded bytecode handlers.
|
||||
if (Isolate::CurrentEmbeddedBlob() == nullptr) return false;
|
||||
if (Isolate::CurrentEmbeddedBlobCode() == nullptr) return false;
|
||||
|
||||
EmbeddedData d = EmbeddedData::FromBlob();
|
||||
if (pc < d.InstructionStartOfBytecodeHandlers() ||
|
||||
|
@ -98,8 +98,10 @@
|
||||
#include "src/diagnostics/unwinding-info-win64.h"
|
||||
#endif // V8_OS_WIN64
|
||||
|
||||
extern "C" const uint8_t* v8_Default_embedded_blob_;
|
||||
extern "C" uint32_t v8_Default_embedded_blob_size_;
|
||||
extern "C" const uint8_t* v8_Default_embedded_blob_code_;
|
||||
extern "C" uint32_t v8_Default_embedded_blob_code_size_;
|
||||
extern "C" const uint8_t* v8_Default_embedded_blob_metadata_;
|
||||
extern "C" uint32_t v8_Default_embedded_blob_metadata_size_;
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -116,15 +118,37 @@ namespace internal {
|
||||
#define TRACE_ISOLATE(tag)
|
||||
#endif
|
||||
|
||||
const uint8_t* DefaultEmbeddedBlob() { return v8_Default_embedded_blob_; }
|
||||
uint32_t DefaultEmbeddedBlobSize() { return v8_Default_embedded_blob_size_; }
|
||||
const uint8_t* DefaultEmbeddedBlobCode() {
|
||||
return v8_Default_embedded_blob_code_;
|
||||
}
|
||||
uint32_t DefaultEmbeddedBlobCodeSize() {
|
||||
return v8_Default_embedded_blob_code_size_;
|
||||
}
|
||||
const uint8_t* DefaultEmbeddedBlobMetadata() {
|
||||
return v8_Default_embedded_blob_metadata_;
|
||||
}
|
||||
uint32_t DefaultEmbeddedBlobMetadataSize() {
|
||||
return v8_Default_embedded_blob_metadata_size_;
|
||||
}
|
||||
|
||||
#ifdef V8_MULTI_SNAPSHOTS
|
||||
extern "C" const uint8_t* v8_Trusted_embedded_blob_;
|
||||
extern "C" uint32_t v8_Trusted_embedded_blob_size_;
|
||||
extern "C" const uint8_t* v8_Trusted_embedded_blob_code_;
|
||||
extern "C" uint32_t v8_Trusted_embedded_blob_code_size_;
|
||||
extern "C" const uint8_t* v8_Trusted_embedded_blob_metadata_;
|
||||
extern "C" uint32_t v8_Trusted_embedded_blob_metadata_size_;
|
||||
|
||||
const uint8_t* TrustedEmbeddedBlob() { return v8_Trusted_embedded_blob_; }
|
||||
uint32_t TrustedEmbeddedBlobSize() { return v8_Trusted_embedded_blob_size_; }
|
||||
const uint8_t* TrustedEmbeddedBlobCode() {
|
||||
return v8_Trusted_embedded_blob_code_;
|
||||
}
|
||||
uint32_t TrustedEmbeddedBlobCodeSize() {
|
||||
return v8_Trusted_embedded_blob_code_size_;
|
||||
}
|
||||
const uint8_t* TrustedEmbeddedBlobMetadata() {
|
||||
return v8_Trusted_embedded_blob_metadata_;
|
||||
}
|
||||
uint32_t TrustedEmbeddedBlobMetadataSize() {
|
||||
return v8_Trusted_embedded_blob_metadata_size_;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
@ -136,8 +160,10 @@ namespace {
|
||||
// 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);
|
||||
std::atomic<const uint8_t*> current_embedded_blob_code_(nullptr);
|
||||
std::atomic<uint32_t> current_embedded_blob_code_size_(0);
|
||||
std::atomic<const uint8_t*> current_embedded_blob_metadata_(nullptr);
|
||||
std::atomic<uint32_t> current_embedded_blob_metadata_size_(0);
|
||||
|
||||
// The various workflows around embedded snapshots are fairly complex. We need
|
||||
// to support plain old snapshot builds, nosnap builds, and the requirements of
|
||||
@ -161,24 +187,39 @@ std::atomic<uint32_t> current_embedded_blob_size_(0);
|
||||
// - Nosnapshot builds set the sticky blob and enable refcounting.
|
||||
|
||||
// This mutex protects access to the following variables:
|
||||
// - sticky_embedded_blob_
|
||||
// - sticky_embedded_blob_size_
|
||||
// - sticky_embedded_blob_code_
|
||||
// - sticky_embedded_blob_code_size_
|
||||
// - sticky_embedded_blob_metadata_
|
||||
// - sticky_embedded_blob_metadata_size_
|
||||
// - enable_embedded_blob_refcounting_
|
||||
// - current_embedded_blob_refs_
|
||||
base::LazyMutex current_embedded_blob_refcount_mutex_ = LAZY_MUTEX_INITIALIZER;
|
||||
|
||||
const uint8_t* sticky_embedded_blob_ = nullptr;
|
||||
uint32_t sticky_embedded_blob_size_ = 0;
|
||||
const uint8_t* sticky_embedded_blob_code_ = nullptr;
|
||||
uint32_t sticky_embedded_blob_code_size_ = 0;
|
||||
const uint8_t* sticky_embedded_blob_metadata_ = nullptr;
|
||||
uint32_t sticky_embedded_blob_metadata_size_ = 0;
|
||||
|
||||
bool enable_embedded_blob_refcounting_ = true;
|
||||
int current_embedded_blob_refs_ = 0;
|
||||
|
||||
const uint8_t* StickyEmbeddedBlob() { return sticky_embedded_blob_; }
|
||||
uint32_t StickyEmbeddedBlobSize() { return sticky_embedded_blob_size_; }
|
||||
const uint8_t* StickyEmbeddedBlobCode() { return sticky_embedded_blob_code_; }
|
||||
uint32_t StickyEmbeddedBlobCodeSize() {
|
||||
return sticky_embedded_blob_code_size_;
|
||||
}
|
||||
const uint8_t* StickyEmbeddedBlobMetadata() {
|
||||
return sticky_embedded_blob_metadata_;
|
||||
}
|
||||
uint32_t StickyEmbeddedBlobMetadataSize() {
|
||||
return sticky_embedded_blob_metadata_size_;
|
||||
}
|
||||
|
||||
void SetStickyEmbeddedBlob(const uint8_t* blob, uint32_t blob_size) {
|
||||
sticky_embedded_blob_ = blob;
|
||||
sticky_embedded_blob_size_ = blob_size;
|
||||
void SetStickyEmbeddedBlob(const uint8_t* code, uint32_t code_size,
|
||||
const uint8_t* metadata, uint32_t metadata_size) {
|
||||
sticky_embedded_blob_code_ = code;
|
||||
sticky_embedded_blob_code_size_ = code_size;
|
||||
sticky_embedded_blob_metadata_ = metadata;
|
||||
sticky_embedded_blob_metadata_size_ = metadata_size;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -192,18 +233,26 @@ void FreeCurrentEmbeddedBlob() {
|
||||
CHECK(!enable_embedded_blob_refcounting_);
|
||||
base::MutexGuard guard(current_embedded_blob_refcount_mutex_.Pointer());
|
||||
|
||||
if (StickyEmbeddedBlob() == nullptr) return;
|
||||
if (StickyEmbeddedBlobCode() == nullptr) return;
|
||||
|
||||
CHECK_EQ(StickyEmbeddedBlob(), Isolate::CurrentEmbeddedBlob());
|
||||
CHECK_EQ(StickyEmbeddedBlobCode(), Isolate::CurrentEmbeddedBlobCode());
|
||||
CHECK_EQ(StickyEmbeddedBlobMetadata(),
|
||||
Isolate::CurrentEmbeddedBlobMetadata());
|
||||
|
||||
InstructionStream::FreeOffHeapInstructionStream(
|
||||
const_cast<uint8_t*>(Isolate::CurrentEmbeddedBlob()),
|
||||
Isolate::CurrentEmbeddedBlobSize());
|
||||
const_cast<uint8_t*>(Isolate::CurrentEmbeddedBlobCode()),
|
||||
Isolate::CurrentEmbeddedBlobCodeSize(),
|
||||
const_cast<uint8_t*>(Isolate::CurrentEmbeddedBlobMetadata()),
|
||||
Isolate::CurrentEmbeddedBlobMetadataSize());
|
||||
|
||||
current_embedded_blob_.store(nullptr, std::memory_order_relaxed);
|
||||
current_embedded_blob_size_.store(0, std::memory_order_relaxed);
|
||||
sticky_embedded_blob_ = nullptr;
|
||||
sticky_embedded_blob_size_ = 0;
|
||||
current_embedded_blob_code_.store(nullptr, std::memory_order_relaxed);
|
||||
current_embedded_blob_code_size_.store(0, std::memory_order_relaxed);
|
||||
current_embedded_blob_metadata_.store(nullptr, std::memory_order_relaxed);
|
||||
current_embedded_blob_metadata_size_.store(0, std::memory_order_relaxed);
|
||||
sticky_embedded_blob_code_ = nullptr;
|
||||
sticky_embedded_blob_code_size_ = 0;
|
||||
sticky_embedded_blob_metadata_ = nullptr;
|
||||
sticky_embedded_blob_metadata_size_ = 0;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -213,22 +262,29 @@ bool Isolate::CurrentEmbeddedBlobIsBinaryEmbedded() {
|
||||
// See blob lifecycle controls above for descriptions of when the current
|
||||
// embedded blob may change (e.g. in tests or mksnapshot). If the blob is
|
||||
// binary-embedded, it is immortal immovable.
|
||||
const uint8_t* blob =
|
||||
current_embedded_blob_.load(std::memory_order::memory_order_relaxed);
|
||||
if (blob == nullptr) return false;
|
||||
const uint8_t* code =
|
||||
current_embedded_blob_code_.load(std::memory_order::memory_order_relaxed);
|
||||
if (code == nullptr) return false;
|
||||
#ifdef V8_MULTI_SNAPSHOTS
|
||||
if (blob == TrustedEmbeddedBlob()) return true;
|
||||
if (code == TrustedEmbeddedBlobCode()) return true;
|
||||
#endif
|
||||
return blob == DefaultEmbeddedBlob();
|
||||
return code == DefaultEmbeddedBlobCode();
|
||||
}
|
||||
|
||||
void Isolate::SetEmbeddedBlob(const uint8_t* blob, uint32_t blob_size) {
|
||||
CHECK_NOT_NULL(blob);
|
||||
void Isolate::SetEmbeddedBlob(const uint8_t* code, uint32_t code_size,
|
||||
const uint8_t* metadata, uint32_t metadata_size) {
|
||||
CHECK_NOT_NULL(code);
|
||||
CHECK_NOT_NULL(metadata);
|
||||
|
||||
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);
|
||||
embedded_blob_code_ = code;
|
||||
embedded_blob_code_size_ = code_size;
|
||||
embedded_blob_metadata_ = metadata;
|
||||
embedded_blob_metadata_size_ = metadata_size;
|
||||
current_embedded_blob_code_.store(code, std::memory_order_relaxed);
|
||||
current_embedded_blob_code_size_.store(code_size, std::memory_order_relaxed);
|
||||
current_embedded_blob_metadata_.store(metadata, std::memory_order_relaxed);
|
||||
current_embedded_blob_metadata_size_.store(metadata_size,
|
||||
std::memory_order_relaxed);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Verify that the contents of the embedded blob are unchanged from
|
||||
@ -243,34 +299,65 @@ void Isolate::SetEmbeddedBlob(const uint8_t* blob, uint32_t blob_size) {
|
||||
#endif // DEBUG
|
||||
|
||||
if (FLAG_experimental_flush_embedded_blob_icache) {
|
||||
FlushInstructionCache(const_cast<uint8_t*>(blob), blob_size);
|
||||
FlushInstructionCache(const_cast<uint8_t*>(code), code_size);
|
||||
}
|
||||
}
|
||||
|
||||
void Isolate::ClearEmbeddedBlob() {
|
||||
CHECK(enable_embedded_blob_refcounting_);
|
||||
CHECK_EQ(embedded_blob_, CurrentEmbeddedBlob());
|
||||
CHECK_EQ(embedded_blob_, StickyEmbeddedBlob());
|
||||
CHECK_EQ(embedded_blob_code_, CurrentEmbeddedBlobCode());
|
||||
CHECK_EQ(embedded_blob_code_, StickyEmbeddedBlobCode());
|
||||
CHECK_EQ(embedded_blob_metadata_, CurrentEmbeddedBlobMetadata());
|
||||
CHECK_EQ(embedded_blob_metadata_, StickyEmbeddedBlobMetadata());
|
||||
|
||||
embedded_blob_ = nullptr;
|
||||
embedded_blob_size_ = 0;
|
||||
current_embedded_blob_.store(nullptr, std::memory_order_relaxed);
|
||||
current_embedded_blob_size_.store(0, std::memory_order_relaxed);
|
||||
sticky_embedded_blob_ = nullptr;
|
||||
sticky_embedded_blob_size_ = 0;
|
||||
embedded_blob_code_ = nullptr;
|
||||
embedded_blob_code_size_ = 0;
|
||||
embedded_blob_metadata_ = nullptr;
|
||||
embedded_blob_metadata_size_ = 0;
|
||||
current_embedded_blob_code_.store(nullptr, std::memory_order_relaxed);
|
||||
current_embedded_blob_code_size_.store(0, std::memory_order_relaxed);
|
||||
current_embedded_blob_metadata_.store(nullptr, std::memory_order_relaxed);
|
||||
current_embedded_blob_metadata_size_.store(0, std::memory_order_relaxed);
|
||||
sticky_embedded_blob_code_ = nullptr;
|
||||
sticky_embedded_blob_code_size_ = 0;
|
||||
sticky_embedded_blob_metadata_ = nullptr;
|
||||
sticky_embedded_blob_metadata_size_ = 0;
|
||||
}
|
||||
|
||||
const uint8_t* Isolate::embedded_blob() const { return embedded_blob_; }
|
||||
uint32_t Isolate::embedded_blob_size() const { return embedded_blob_size_; }
|
||||
|
||||
// static
|
||||
const uint8_t* Isolate::CurrentEmbeddedBlob() {
|
||||
return current_embedded_blob_.load(std::memory_order::memory_order_relaxed);
|
||||
const uint8_t* Isolate::embedded_blob_code() const {
|
||||
return embedded_blob_code_;
|
||||
}
|
||||
uint32_t Isolate::embedded_blob_code_size() const {
|
||||
return embedded_blob_code_size_;
|
||||
}
|
||||
const uint8_t* Isolate::embedded_blob_metadata() const {
|
||||
return embedded_blob_metadata_;
|
||||
}
|
||||
uint32_t Isolate::embedded_blob_metadata_size() const {
|
||||
return embedded_blob_metadata_size_;
|
||||
}
|
||||
|
||||
// static
|
||||
uint32_t Isolate::CurrentEmbeddedBlobSize() {
|
||||
return current_embedded_blob_size_.load(
|
||||
const uint8_t* Isolate::CurrentEmbeddedBlobCode() {
|
||||
return current_embedded_blob_code_.load(
|
||||
std::memory_order::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// static
|
||||
uint32_t Isolate::CurrentEmbeddedBlobCodeSize() {
|
||||
return current_embedded_blob_code_size_.load(
|
||||
std::memory_order::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// static
|
||||
const uint8_t* Isolate::CurrentEmbeddedBlobMetadata() {
|
||||
return current_embedded_blob_metadata_.load(
|
||||
std::memory_order::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// static
|
||||
uint32_t Isolate::CurrentEmbeddedBlobMetadataSize() {
|
||||
return current_embedded_blob_metadata_size_.load(
|
||||
std::memory_order::memory_order_relaxed);
|
||||
}
|
||||
|
||||
@ -3205,8 +3292,10 @@ void Isolate::InitializeLoggingAndCounters() {
|
||||
namespace {
|
||||
|
||||
void CreateOffHeapTrampolines(Isolate* isolate) {
|
||||
DCHECK_NOT_NULL(isolate->embedded_blob());
|
||||
DCHECK_NE(0, isolate->embedded_blob_size());
|
||||
DCHECK_NOT_NULL(isolate->embedded_blob_code());
|
||||
DCHECK_NE(0, isolate->embedded_blob_code_size());
|
||||
DCHECK_NOT_NULL(isolate->embedded_blob_metadata());
|
||||
DCHECK_NE(0, isolate->embedded_blob_metadata_size());
|
||||
|
||||
HandleScope scope(isolate);
|
||||
Builtins* builtins = isolate->builtins();
|
||||
@ -3236,30 +3325,36 @@ bool IsolateIsCompatibleWithEmbeddedBlob(Isolate* isolate) {
|
||||
} // namespace
|
||||
|
||||
void Isolate::InitializeDefaultEmbeddedBlob() {
|
||||
const uint8_t* blob = DefaultEmbeddedBlob();
|
||||
uint32_t size = DefaultEmbeddedBlobSize();
|
||||
const uint8_t* code = DefaultEmbeddedBlobCode();
|
||||
uint32_t code_size = DefaultEmbeddedBlobCodeSize();
|
||||
const uint8_t* metadata = DefaultEmbeddedBlobMetadata();
|
||||
uint32_t metadata_size = DefaultEmbeddedBlobMetadataSize();
|
||||
|
||||
#ifdef V8_MULTI_SNAPSHOTS
|
||||
if (!FLAG_untrusted_code_mitigations) {
|
||||
blob = TrustedEmbeddedBlob();
|
||||
size = TrustedEmbeddedBlobSize();
|
||||
code = TrustedEmbeddedBlobCode();
|
||||
code_size = TrustedEmbeddedBlobCodeSize();
|
||||
metadata = TrustedEmbeddedBlobMetadata();
|
||||
metadata_size = TrustedEmbeddedBlobMetadataSize();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (StickyEmbeddedBlob() != nullptr) {
|
||||
if (StickyEmbeddedBlobCode() != nullptr) {
|
||||
base::MutexGuard guard(current_embedded_blob_refcount_mutex_.Pointer());
|
||||
// Check again now that we hold the lock.
|
||||
if (StickyEmbeddedBlob() != nullptr) {
|
||||
blob = StickyEmbeddedBlob();
|
||||
size = StickyEmbeddedBlobSize();
|
||||
if (StickyEmbeddedBlobCode() != nullptr) {
|
||||
code = StickyEmbeddedBlobCode();
|
||||
code_size = StickyEmbeddedBlobCodeSize();
|
||||
metadata = StickyEmbeddedBlobMetadata();
|
||||
metadata_size = StickyEmbeddedBlobMetadataSize();
|
||||
current_embedded_blob_refs_++;
|
||||
}
|
||||
}
|
||||
|
||||
if (blob == nullptr) {
|
||||
CHECK_EQ(0, size);
|
||||
if (code == nullptr) {
|
||||
CHECK_EQ(0, code_size);
|
||||
} else {
|
||||
SetEmbeddedBlob(blob, size);
|
||||
SetEmbeddedBlob(code, code_size, metadata, metadata_size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3269,21 +3364,27 @@ void Isolate::CreateAndSetEmbeddedBlob() {
|
||||
PrepareBuiltinSourcePositionMap();
|
||||
|
||||
// If a sticky blob has been set, we reuse it.
|
||||
if (StickyEmbeddedBlob() != nullptr) {
|
||||
CHECK_EQ(embedded_blob(), StickyEmbeddedBlob());
|
||||
CHECK_EQ(CurrentEmbeddedBlob(), StickyEmbeddedBlob());
|
||||
if (StickyEmbeddedBlobCode() != nullptr) {
|
||||
CHECK_EQ(embedded_blob_code(), StickyEmbeddedBlobCode());
|
||||
CHECK_EQ(embedded_blob_metadata(), StickyEmbeddedBlobMetadata());
|
||||
CHECK_EQ(CurrentEmbeddedBlobCode(), StickyEmbeddedBlobCode());
|
||||
CHECK_EQ(CurrentEmbeddedBlobMetadata(), StickyEmbeddedBlobMetadata());
|
||||
} else {
|
||||
// Create and set a new embedded blob.
|
||||
uint8_t* data;
|
||||
uint32_t size;
|
||||
InstructionStream::CreateOffHeapInstructionStream(this, &data, &size);
|
||||
uint8_t* code;
|
||||
uint32_t code_size;
|
||||
uint8_t* metadata;
|
||||
uint32_t metadata_size;
|
||||
InstructionStream::CreateOffHeapInstructionStream(
|
||||
this, &code, &code_size, &metadata, &metadata_size);
|
||||
|
||||
CHECK_EQ(0, current_embedded_blob_refs_);
|
||||
const uint8_t* const_data = const_cast<const uint8_t*>(data);
|
||||
SetEmbeddedBlob(const_data, size);
|
||||
const uint8_t* const_code = const_cast<const uint8_t*>(code);
|
||||
const uint8_t* const_metadata = const_cast<const uint8_t*>(metadata);
|
||||
SetEmbeddedBlob(const_code, code_size, const_metadata, metadata_size);
|
||||
current_embedded_blob_refs_++;
|
||||
|
||||
SetStickyEmbeddedBlob(const_data, size);
|
||||
SetStickyEmbeddedBlob(code, code_size, metadata, metadata_size);
|
||||
}
|
||||
|
||||
CreateOffHeapTrampolines(this);
|
||||
@ -3291,17 +3392,21 @@ void Isolate::CreateAndSetEmbeddedBlob() {
|
||||
|
||||
void Isolate::TearDownEmbeddedBlob() {
|
||||
// Nothing to do in case the blob is embedded into the binary or unset.
|
||||
if (StickyEmbeddedBlob() == nullptr) return;
|
||||
if (StickyEmbeddedBlobCode() == nullptr) return;
|
||||
|
||||
CHECK_EQ(embedded_blob(), StickyEmbeddedBlob());
|
||||
CHECK_EQ(CurrentEmbeddedBlob(), StickyEmbeddedBlob());
|
||||
CHECK_EQ(embedded_blob_code(), StickyEmbeddedBlobCode());
|
||||
CHECK_EQ(embedded_blob_metadata(), StickyEmbeddedBlobMetadata());
|
||||
CHECK_EQ(CurrentEmbeddedBlobCode(), StickyEmbeddedBlobCode());
|
||||
CHECK_EQ(CurrentEmbeddedBlobMetadata(), StickyEmbeddedBlobMetadata());
|
||||
|
||||
base::MutexGuard guard(current_embedded_blob_refcount_mutex_.Pointer());
|
||||
current_embedded_blob_refs_--;
|
||||
if (current_embedded_blob_refs_ == 0 && enable_embedded_blob_refcounting_) {
|
||||
// We own the embedded blob and are the last holder. Free it.
|
||||
InstructionStream::FreeOffHeapInstructionStream(
|
||||
const_cast<uint8_t*>(embedded_blob()), embedded_blob_size());
|
||||
const_cast<uint8_t*>(embedded_blob_code()), embedded_blob_code_size(),
|
||||
const_cast<uint8_t*>(embedded_blob_metadata()),
|
||||
embedded_blob_metadata_size());
|
||||
ClearEmbeddedBlob();
|
||||
}
|
||||
}
|
||||
@ -3344,8 +3449,9 @@ void Isolate::AddCrashKeysForIsolateAndHeapPointers() {
|
||||
|
||||
void Isolate::InitializeCodeRanges() {
|
||||
DCHECK_NULL(GetCodePages());
|
||||
MemoryRange embedded_range{reinterpret_cast<const void*>(embedded_blob()),
|
||||
embedded_blob_size()};
|
||||
MemoryRange embedded_range{
|
||||
reinterpret_cast<const void*>(embedded_blob_code()),
|
||||
embedded_blob_code_size()};
|
||||
code_pages_buffer1_.push_back(embedded_range);
|
||||
SetCodePages(&code_pages_buffer1_);
|
||||
}
|
||||
|
@ -1372,14 +1372,18 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
||||
// builtins constants table to remain unchanged from build-time.
|
||||
size_t HashIsolateForEmbeddedBlob();
|
||||
|
||||
static const uint8_t* CurrentEmbeddedBlob();
|
||||
static uint32_t CurrentEmbeddedBlobSize();
|
||||
static const uint8_t* CurrentEmbeddedBlobCode();
|
||||
static uint32_t CurrentEmbeddedBlobCodeSize();
|
||||
static const uint8_t* CurrentEmbeddedBlobMetadata();
|
||||
static uint32_t CurrentEmbeddedBlobMetadataSize();
|
||||
static bool CurrentEmbeddedBlobIsBinaryEmbedded();
|
||||
|
||||
// These always return the same result as static methods above, but don't
|
||||
// access the global atomic variable (and thus *might be* slightly faster).
|
||||
const uint8_t* embedded_blob() const;
|
||||
uint32_t embedded_blob_size() const;
|
||||
const uint8_t* embedded_blob_code() const;
|
||||
uint32_t embedded_blob_code_size() const;
|
||||
const uint8_t* embedded_blob_metadata() const;
|
||||
uint32_t embedded_blob_metadata_size() const;
|
||||
|
||||
void set_array_buffer_allocator(v8::ArrayBuffer::Allocator* allocator) {
|
||||
array_buffer_allocator_ = allocator;
|
||||
@ -1811,11 +1815,14 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
||||
void CreateAndSetEmbeddedBlob();
|
||||
void TearDownEmbeddedBlob();
|
||||
|
||||
void SetEmbeddedBlob(const uint8_t* blob, uint32_t blob_size);
|
||||
void SetEmbeddedBlob(const uint8_t* code, uint32_t code_size,
|
||||
const uint8_t* metadata, uint32_t metadata_size);
|
||||
void ClearEmbeddedBlob();
|
||||
|
||||
const uint8_t* embedded_blob_ = nullptr;
|
||||
uint32_t embedded_blob_size_ = 0;
|
||||
const uint8_t* embedded_blob_code_ = nullptr;
|
||||
uint32_t embedded_blob_code_size_ = 0;
|
||||
const uint8_t* embedded_blob_metadata_ = nullptr;
|
||||
uint32_t embedded_blob_metadata_size_ = 0;
|
||||
|
||||
v8::ArrayBuffer::Allocator* array_buffer_allocator_ = nullptr;
|
||||
std::shared_ptr<v8::ArrayBuffer::Allocator> array_buffer_allocator_shared_;
|
||||
|
@ -2105,8 +2105,8 @@ Handle<CodeDataContainer> Factory::NewCodeDataContainer(
|
||||
|
||||
Handle<Code> Factory::NewOffHeapTrampolineFor(Handle<Code> code,
|
||||
Address off_heap_entry) {
|
||||
CHECK_NOT_NULL(isolate()->embedded_blob());
|
||||
CHECK_NE(0, isolate()->embedded_blob_size());
|
||||
CHECK_NOT_NULL(isolate()->embedded_blob_code());
|
||||
CHECK_NE(0, isolate()->embedded_blob_code_size());
|
||||
CHECK(Builtins::IsIsolateIndependentBuiltin(*code));
|
||||
|
||||
bool generate_jump_to_instruction_stream =
|
||||
|
@ -561,8 +561,9 @@ Code Code::GetCodeFromTargetAddress(Address address) {
|
||||
{
|
||||
// TODO(jgruber,v8:6666): Support embedded builtins here. We'd need to pass
|
||||
// in the current isolate.
|
||||
Address start = reinterpret_cast<Address>(Isolate::CurrentEmbeddedBlob());
|
||||
Address end = start + Isolate::CurrentEmbeddedBlobSize();
|
||||
Address start =
|
||||
reinterpret_cast<Address>(Isolate::CurrentEmbeddedBlobCode());
|
||||
Address end = start + Isolate::CurrentEmbeddedBlobCodeSize();
|
||||
CHECK(address < start || address >= end);
|
||||
}
|
||||
|
||||
|
@ -143,21 +143,24 @@ SafepointEntry Code::GetSafepointEntry(Address pc) {
|
||||
|
||||
int Code::OffHeapInstructionSize() const {
|
||||
DCHECK(is_off_heap_trampoline());
|
||||
if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_size();
|
||||
if (Isolate::CurrentEmbeddedBlobCode() == nullptr)
|
||||
return raw_instruction_size();
|
||||
EmbeddedData d = EmbeddedData::FromBlob();
|
||||
return d.InstructionSizeOfBuiltin(builtin_index());
|
||||
}
|
||||
|
||||
Address Code::OffHeapInstructionStart() const {
|
||||
DCHECK(is_off_heap_trampoline());
|
||||
if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_start();
|
||||
if (Isolate::CurrentEmbeddedBlobCode() == nullptr)
|
||||
return raw_instruction_start();
|
||||
EmbeddedData d = EmbeddedData::FromBlob();
|
||||
return d.InstructionStartOfBuiltin(builtin_index());
|
||||
}
|
||||
|
||||
Address Code::OffHeapInstructionEnd() const {
|
||||
DCHECK(is_off_heap_trampoline());
|
||||
if (Isolate::CurrentEmbeddedBlob() == nullptr) return raw_instruction_end();
|
||||
if (Isolate::CurrentEmbeddedBlobCode() == nullptr)
|
||||
return raw_instruction_end();
|
||||
EmbeddedData d = EmbeddedData::FromBlob();
|
||||
return d.InstructionStartOfBuiltin(builtin_index()) +
|
||||
d.InstructionSizeOfBuiltin(builtin_index());
|
||||
|
@ -848,10 +848,9 @@ RUNTIME_FUNCTION(Runtime_ProfileCreateSnapshotDataBlob) {
|
||||
|
||||
// Track the embedded blob size as well.
|
||||
{
|
||||
int embedded_blob_size = 0;
|
||||
i::EmbeddedData d = i::EmbeddedData::FromBlob();
|
||||
embedded_blob_size = static_cast<int>(d.size());
|
||||
PrintF("Embedded blob is %d bytes\n", embedded_blob_size);
|
||||
PrintF("Embedded blob is %d bytes\n",
|
||||
static_cast<int>(d.code_size() + d.metadata_size()));
|
||||
}
|
||||
|
||||
FreeCurrentEmbeddedBlob();
|
||||
|
@ -501,7 +501,7 @@ void Deserializer::VisitOffHeapTarget(Code host, RelocInfo* rinfo) {
|
||||
int builtin_index = source_.GetInt();
|
||||
DCHECK(Builtins::IsBuiltinId(builtin_index));
|
||||
|
||||
CHECK_NOT_NULL(isolate()->embedded_blob());
|
||||
CHECK_NOT_NULL(isolate()->embedded_blob_code());
|
||||
EmbeddedData d = EmbeddedData::FromBlob();
|
||||
Address address = d.InstructionStartOfBuiltin(builtin_index);
|
||||
CHECK_NE(kNullAddress, address);
|
||||
|
@ -15,8 +15,9 @@ namespace internal {
|
||||
|
||||
// static
|
||||
bool InstructionStream::PcIsOffHeap(Isolate* isolate, Address pc) {
|
||||
const Address start = reinterpret_cast<Address>(isolate->embedded_blob());
|
||||
return start <= pc && pc < start + isolate->embedded_blob_size();
|
||||
const Address start =
|
||||
reinterpret_cast<Address>(isolate->embedded_blob_code());
|
||||
return start <= pc && pc < start + isolate->embedded_blob_code_size();
|
||||
}
|
||||
|
||||
// static
|
||||
@ -49,9 +50,9 @@ Code InstructionStream::TryLookupCode(Isolate* isolate, Address address) {
|
||||
}
|
||||
|
||||
// static
|
||||
void InstructionStream::CreateOffHeapInstructionStream(Isolate* isolate,
|
||||
uint8_t** data,
|
||||
uint32_t* size) {
|
||||
void InstructionStream::CreateOffHeapInstructionStream(
|
||||
Isolate* isolate, uint8_t** code, uint32_t* code_size, uint8_t** metadata,
|
||||
uint32_t* metadata_size) {
|
||||
// Create the embedded blob from scratch using the current Isolate's heap.
|
||||
EmbeddedData d = EmbeddedData::FromIsolate(isolate);
|
||||
|
||||
@ -62,14 +63,22 @@ void InstructionStream::CreateOffHeapInstructionStream(Isolate* isolate,
|
||||
const uint32_t alignment =
|
||||
static_cast<uint32_t>(page_allocator->AllocatePageSize());
|
||||
|
||||
void* const requested_allocation_address =
|
||||
void* const requested_allocation_code_address =
|
||||
AlignedAddress(isolate->heap()->GetRandomMmapAddr(), alignment);
|
||||
const uint32_t allocation_size = RoundUp(d.size(), alignment);
|
||||
const uint32_t allocation_code_size = RoundUp(d.code_size(), alignment);
|
||||
uint8_t* allocated_code_bytes = static_cast<uint8_t*>(AllocatePages(
|
||||
page_allocator, requested_allocation_code_address, allocation_code_size,
|
||||
alignment, PageAllocator::kReadWrite));
|
||||
CHECK_NOT_NULL(allocated_code_bytes);
|
||||
|
||||
uint8_t* allocated_bytes = static_cast<uint8_t*>(
|
||||
AllocatePages(page_allocator, requested_allocation_address,
|
||||
allocation_size, alignment, PageAllocator::kReadWrite));
|
||||
CHECK_NOT_NULL(allocated_bytes);
|
||||
void* const requested_allocation_metadata_address =
|
||||
AlignedAddress(isolate->heap()->GetRandomMmapAddr(), alignment);
|
||||
const uint32_t allocation_metadata_size =
|
||||
RoundUp(d.metadata_size(), alignment);
|
||||
uint8_t* allocated_metadata_bytes = static_cast<uint8_t*>(AllocatePages(
|
||||
page_allocator, requested_allocation_metadata_address,
|
||||
allocation_metadata_size, alignment, PageAllocator::kReadWrite));
|
||||
CHECK_NOT_NULL(allocated_metadata_bytes);
|
||||
|
||||
// Copy the embedded blob into the newly allocated backing store. Switch
|
||||
// permissions to read-execute since builtin code is immutable from now on
|
||||
@ -79,23 +88,32 @@ void InstructionStream::CreateOffHeapInstructionStream(Isolate* isolate,
|
||||
// the difference between a 'real' embedded build (where the blob is embedded
|
||||
// in the binary) and what we are currently setting up here (where the blob is
|
||||
// on the native heap).
|
||||
std::memcpy(allocated_bytes, d.data(), d.size());
|
||||
CHECK(SetPermissions(page_allocator, allocated_bytes, allocation_size,
|
||||
PageAllocator::kReadExecute));
|
||||
std::memcpy(allocated_code_bytes, d.code(), d.code_size());
|
||||
CHECK(SetPermissions(page_allocator, allocated_code_bytes,
|
||||
allocation_code_size, PageAllocator::kReadExecute));
|
||||
|
||||
*data = allocated_bytes;
|
||||
*size = d.size();
|
||||
std::memcpy(allocated_metadata_bytes, d.metadata(), d.metadata_size());
|
||||
CHECK(SetPermissions(page_allocator, allocated_metadata_bytes,
|
||||
allocation_metadata_size, PageAllocator::kRead));
|
||||
|
||||
*code = allocated_code_bytes;
|
||||
*code_size = d.code_size();
|
||||
*metadata = allocated_metadata_bytes;
|
||||
*metadata_size = d.metadata_size();
|
||||
|
||||
d.Dispose();
|
||||
}
|
||||
|
||||
// static
|
||||
void InstructionStream::FreeOffHeapInstructionStream(uint8_t* data,
|
||||
uint32_t size) {
|
||||
void InstructionStream::FreeOffHeapInstructionStream(uint8_t* code,
|
||||
uint32_t code_size,
|
||||
uint8_t* metadata,
|
||||
uint32_t metadata_size) {
|
||||
v8::PageAllocator* page_allocator = v8::internal::GetPlatformPageAllocator();
|
||||
const uint32_t page_size =
|
||||
static_cast<uint32_t>(page_allocator->AllocatePageSize());
|
||||
CHECK(FreePages(page_allocator, data, RoundUp(size, page_size)));
|
||||
CHECK(FreePages(page_allocator, code, RoundUp(code_size, page_size)));
|
||||
CHECK(FreePages(page_allocator, metadata, RoundUp(metadata_size, page_size)));
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -190,7 +208,7 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
|
||||
std::vector<struct Metadata> metadata(kTableSize);
|
||||
|
||||
bool saw_unsafe_builtin = false;
|
||||
uint32_t raw_data_size = 0;
|
||||
uint32_t raw_code_size = 0;
|
||||
for (int i = 0; i < Builtins::builtin_count; i++) {
|
||||
Code code = builtins->builtin(i);
|
||||
|
||||
@ -209,14 +227,14 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
|
||||
|
||||
uint32_t length = static_cast<uint32_t>(code.raw_instruction_size());
|
||||
|
||||
DCHECK_EQ(0, raw_data_size % kCodeAlignment);
|
||||
metadata[i].instructions_offset = raw_data_size;
|
||||
DCHECK_EQ(0, raw_code_size % kCodeAlignment);
|
||||
metadata[i].instructions_offset = raw_code_size;
|
||||
metadata[i].instructions_length = length;
|
||||
|
||||
// Align the start of each instruction stream.
|
||||
raw_data_size += PadAndAlign(length);
|
||||
raw_code_size += PadAndAlign(length);
|
||||
} else {
|
||||
metadata[i].instructions_offset = raw_data_size;
|
||||
metadata[i].instructions_offset = raw_code_size;
|
||||
}
|
||||
}
|
||||
CHECK_WITH_MSG(
|
||||
@ -225,38 +243,42 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
|
||||
"isolate-dependent code or aliases the off-heap trampoline register. "
|
||||
"If in doubt, ask jgruber@");
|
||||
|
||||
const uint32_t blob_size = RawDataOffset() + raw_data_size;
|
||||
uint8_t* const blob = new uint8_t[blob_size];
|
||||
uint8_t* const raw_data_start = blob + RawDataOffset();
|
||||
const uint32_t blob_code_size = RawCodeOffset() + raw_code_size;
|
||||
uint8_t* const blob_code = new uint8_t[blob_code_size];
|
||||
uint8_t* const raw_code_start = blob_code + RawCodeOffset();
|
||||
const uint32_t blob_metadata_size =
|
||||
MetadataTableOffset() + MetadataTableSize();
|
||||
uint8_t* const blob_metadata = new uint8_t[blob_metadata_size];
|
||||
|
||||
// Initially zap the entire blob, effectively padding the alignment area
|
||||
// between two builtins with int3's (on x64/ia32).
|
||||
ZapCode(reinterpret_cast<Address>(blob), blob_size);
|
||||
ZapCode(reinterpret_cast<Address>(blob_code), blob_code_size);
|
||||
|
||||
// Hash relevant parts of the Isolate's heap and store the result.
|
||||
{
|
||||
STATIC_ASSERT(IsolateHashSize() == kSizetSize);
|
||||
const size_t hash = isolate->HashIsolateForEmbeddedBlob();
|
||||
std::memcpy(blob + IsolateHashOffset(), &hash, IsolateHashSize());
|
||||
std::memcpy(blob_metadata + IsolateHashOffset(), &hash, IsolateHashSize());
|
||||
}
|
||||
|
||||
// Write the metadata tables.
|
||||
DCHECK_EQ(MetadataSize(), sizeof(metadata[0]) * metadata.size());
|
||||
std::memcpy(blob + MetadataOffset(), metadata.data(), MetadataSize());
|
||||
DCHECK_EQ(MetadataTableSize(), sizeof(metadata[0]) * metadata.size());
|
||||
std::memcpy(blob_metadata + MetadataTableOffset(), metadata.data(),
|
||||
MetadataTableSize());
|
||||
|
||||
// Write the raw data section.
|
||||
for (int i = 0; i < Builtins::builtin_count; i++) {
|
||||
if (!Builtins::IsIsolateIndependent(i)) continue;
|
||||
Code code = builtins->builtin(i);
|
||||
uint32_t offset = metadata[i].instructions_offset;
|
||||
uint8_t* dst = raw_data_start + offset;
|
||||
DCHECK_LE(RawDataOffset() + offset + code.raw_instruction_size(),
|
||||
blob_size);
|
||||
uint8_t* dst = raw_code_start + offset;
|
||||
DCHECK_LE(RawCodeOffset() + offset + code.raw_instruction_size(),
|
||||
blob_code_size);
|
||||
std::memcpy(dst, reinterpret_cast<uint8_t*>(code.raw_instruction_start()),
|
||||
code.raw_instruction_size());
|
||||
}
|
||||
|
||||
EmbeddedData d(blob, blob_size);
|
||||
EmbeddedData d(blob_code, blob_code_size, blob_metadata, blob_metadata_size);
|
||||
|
||||
// Fix up call targets that point to other embedded builtins.
|
||||
FinalizeEmbeddedCodeTargets(isolate, &d);
|
||||
@ -265,7 +287,8 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
|
||||
{
|
||||
STATIC_ASSERT(EmbeddedBlobHashSize() == kSizetSize);
|
||||
const size_t hash = d.CreateEmbeddedBlobHash();
|
||||
std::memcpy(blob + EmbeddedBlobHashOffset(), &hash, EmbeddedBlobHashSize());
|
||||
std::memcpy(blob_metadata + EmbeddedBlobHashOffset(), &hash,
|
||||
EmbeddedBlobHashSize());
|
||||
|
||||
DCHECK_EQ(hash, d.CreateEmbeddedBlobHash());
|
||||
DCHECK_EQ(hash, d.EmbeddedBlobHash());
|
||||
@ -279,9 +302,10 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
|
||||
Address EmbeddedData::InstructionStartOfBuiltin(int i) const {
|
||||
DCHECK(Builtins::IsBuiltinId(i));
|
||||
const struct Metadata* metadata = Metadata();
|
||||
const uint8_t* result = RawData() + metadata[i].instructions_offset;
|
||||
DCHECK_LE(result, data_ + size_);
|
||||
DCHECK_IMPLIES(result == data_ + size_, InstructionSizeOfBuiltin(i) == 0);
|
||||
const uint8_t* result = RawCode() + metadata[i].instructions_offset;
|
||||
DCHECK_LE(result, code_ + code_size_);
|
||||
DCHECK_IMPLIES(result == code_ + code_size_,
|
||||
InstructionSizeOfBuiltin(i) == 0);
|
||||
return reinterpret_cast<Address>(result);
|
||||
}
|
||||
|
||||
@ -308,9 +332,10 @@ size_t EmbeddedData::CreateEmbeddedBlobHash() const {
|
||||
STATIC_ASSERT(EmbeddedBlobHashOffset() == 0);
|
||||
STATIC_ASSERT(EmbeddedBlobHashSize() == kSizetSize);
|
||||
// Hash the entire blob except the hash field itself.
|
||||
Vector<const byte> payload(data_ + EmbeddedBlobHashSize(),
|
||||
size_ - EmbeddedBlobHashSize());
|
||||
return Checksum(payload);
|
||||
Vector<const byte> payload1(metadata_ + EmbeddedBlobHashSize(),
|
||||
metadata_size_ - EmbeddedBlobHashSize());
|
||||
Vector<const byte> payload2(code_, code_size_);
|
||||
return Checksum(payload1, payload2);
|
||||
}
|
||||
|
||||
void EmbeddedData::PrintStatistics() const {
|
||||
@ -337,16 +362,14 @@ void EmbeddedData::PrintStatistics() const {
|
||||
const int k90th = embedded_count * 0.90;
|
||||
const int k99th = embedded_count * 0.99;
|
||||
|
||||
const int metadata_size = static_cast<int>(
|
||||
EmbeddedBlobHashSize() + IsolateHashSize() + MetadataSize());
|
||||
|
||||
PrintF("EmbeddedData:\n");
|
||||
PrintF(" Total size: %d\n",
|
||||
static_cast<int>(size()));
|
||||
PrintF(" Metadata size: %d\n", metadata_size);
|
||||
static_cast<int>(code_size() + metadata_size()));
|
||||
PrintF(" Metadata size: %d\n",
|
||||
static_cast<int>(metadata_size()));
|
||||
PrintF(" Instruction size: %d\n", instruction_size);
|
||||
PrintF(" Padding: %d\n",
|
||||
static_cast<int>(size() - metadata_size - instruction_size));
|
||||
static_cast<int>(code_size() - instruction_size));
|
||||
PrintF(" Embedded builtin count: %d\n", embedded_count);
|
||||
PrintF(" Instruction size (50th percentile): %d\n", sizes[k50th]);
|
||||
PrintF(" Instruction size (75th percentile): %d\n", sizes[k75th]);
|
||||
|
@ -30,9 +30,13 @@ class InstructionStream final : public AllStatic {
|
||||
// containing all off-heap code. The area is guaranteed to be contiguous.
|
||||
// Note that this only applies when building the snapshot, e.g. for
|
||||
// mksnapshot. Otherwise, off-heap code is embedded directly into the binary.
|
||||
static void CreateOffHeapInstructionStream(Isolate* isolate, uint8_t** data,
|
||||
uint32_t* size);
|
||||
static void FreeOffHeapInstructionStream(uint8_t* data, uint32_t size);
|
||||
static void CreateOffHeapInstructionStream(Isolate* isolate, uint8_t** code,
|
||||
uint32_t* code_size,
|
||||
uint8_t** metadata,
|
||||
uint32_t* metadata_size);
|
||||
static void FreeOffHeapInstructionStream(uint8_t* code, uint32_t code_size,
|
||||
uint8_t* metadata,
|
||||
uint32_t metadata_size);
|
||||
};
|
||||
|
||||
class EmbeddedData final {
|
||||
@ -40,19 +44,30 @@ class EmbeddedData final {
|
||||
static EmbeddedData FromIsolate(Isolate* isolate);
|
||||
|
||||
static EmbeddedData FromBlob() {
|
||||
return EmbeddedData(Isolate::CurrentEmbeddedBlob(),
|
||||
Isolate::CurrentEmbeddedBlobSize());
|
||||
return EmbeddedData(Isolate::CurrentEmbeddedBlobCode(),
|
||||
Isolate::CurrentEmbeddedBlobCodeSize(),
|
||||
Isolate::CurrentEmbeddedBlobMetadata(),
|
||||
Isolate::CurrentEmbeddedBlobMetadataSize());
|
||||
}
|
||||
|
||||
static EmbeddedData FromBlob(Isolate* isolate) {
|
||||
return EmbeddedData(isolate->embedded_blob(),
|
||||
isolate->embedded_blob_size());
|
||||
return EmbeddedData(isolate->embedded_blob_code(),
|
||||
isolate->embedded_blob_code_size(),
|
||||
isolate->embedded_blob_metadata(),
|
||||
isolate->embedded_blob_metadata_size());
|
||||
}
|
||||
|
||||
const uint8_t* data() const { return data_; }
|
||||
uint32_t size() const { return size_; }
|
||||
const uint8_t* code() const { return code_; }
|
||||
uint32_t code_size() const { return code_size_; }
|
||||
const uint8_t* metadata() const { return metadata_; }
|
||||
uint32_t metadata_size() const { return metadata_size_; }
|
||||
|
||||
void Dispose() { delete[] data_; }
|
||||
void Dispose() {
|
||||
delete[] code_;
|
||||
code_ = nullptr;
|
||||
delete[] metadata_;
|
||||
metadata_ = nullptr;
|
||||
}
|
||||
|
||||
Address InstructionStartOfBuiltin(int i) const;
|
||||
uint32_t InstructionSizeOfBuiltin(int i) const;
|
||||
@ -63,8 +78,8 @@ class EmbeddedData final {
|
||||
bool ContainsBuiltin(int i) const { return InstructionSizeOfBuiltin(i) > 0; }
|
||||
|
||||
uint32_t AddressForHashing(Address addr) {
|
||||
Address start = reinterpret_cast<Address>(data_);
|
||||
DCHECK(base::IsInRange(addr, start, start + size_));
|
||||
Address start = reinterpret_cast<Address>(code_);
|
||||
DCHECK(base::IsInRange(addr, start, start + code_size_));
|
||||
return static_cast<uint32_t>(addr - start);
|
||||
}
|
||||
|
||||
@ -76,11 +91,12 @@ class EmbeddedData final {
|
||||
|
||||
size_t CreateEmbeddedBlobHash() const;
|
||||
size_t EmbeddedBlobHash() const {
|
||||
return *reinterpret_cast<const size_t*>(data_ + EmbeddedBlobHashOffset());
|
||||
return *reinterpret_cast<const size_t*>(metadata_ +
|
||||
EmbeddedBlobHashOffset());
|
||||
}
|
||||
|
||||
size_t IsolateHash() const {
|
||||
return *reinterpret_cast<const size_t*>(data_ + IsolateHashOffset());
|
||||
return *reinterpret_cast<const size_t*>(metadata_ + IsolateHashOffset());
|
||||
}
|
||||
|
||||
struct Metadata {
|
||||
@ -94,10 +110,14 @@ class EmbeddedData final {
|
||||
|
||||
// The layout of the blob is as follows:
|
||||
//
|
||||
// metadata:
|
||||
// [0] hash of the remaining blob
|
||||
// [1] hash of embedded-blob-relevant heap objects
|
||||
// [2] metadata of instruction stream 0
|
||||
// ... metadata
|
||||
//
|
||||
// code:
|
||||
// [0] instruction streams 0
|
||||
// ... instruction streams
|
||||
|
||||
static constexpr uint32_t kTableSize = Builtins::builtin_count;
|
||||
@ -107,26 +127,32 @@ class EmbeddedData final {
|
||||
return EmbeddedBlobHashOffset() + EmbeddedBlobHashSize();
|
||||
}
|
||||
static constexpr uint32_t IsolateHashSize() { return kSizetSize; }
|
||||
static constexpr uint32_t MetadataOffset() {
|
||||
static constexpr uint32_t MetadataTableOffset() {
|
||||
return IsolateHashOffset() + IsolateHashSize();
|
||||
}
|
||||
static constexpr uint32_t MetadataSize() {
|
||||
static constexpr uint32_t MetadataTableSize() {
|
||||
return sizeof(struct Metadata) * kTableSize;
|
||||
}
|
||||
static constexpr uint32_t RawDataOffset() {
|
||||
return PadAndAlign(MetadataOffset() + MetadataSize());
|
||||
}
|
||||
static constexpr uint32_t RawCodeOffset() { return 0; }
|
||||
|
||||
private:
|
||||
EmbeddedData(const uint8_t* data, uint32_t size) : data_(data), size_(size) {
|
||||
DCHECK_NOT_NULL(data);
|
||||
DCHECK_LT(0, size);
|
||||
EmbeddedData(const uint8_t* code, uint32_t code_size, const uint8_t* metadata,
|
||||
uint32_t metadata_size)
|
||||
: code_(code),
|
||||
code_size_(code_size),
|
||||
metadata_(metadata),
|
||||
metadata_size_(metadata_size) {
|
||||
DCHECK_NOT_NULL(code);
|
||||
DCHECK_LT(0, code_size);
|
||||
DCHECK_NOT_NULL(metadata);
|
||||
DCHECK_LT(0, metadata_size);
|
||||
}
|
||||
|
||||
const Metadata* Metadata() const {
|
||||
return reinterpret_cast<const struct Metadata*>(data_ + MetadataOffset());
|
||||
return reinterpret_cast<const struct Metadata*>(metadata_ +
|
||||
MetadataTableOffset());
|
||||
}
|
||||
const uint8_t* RawData() const { return data_ + RawDataOffset(); }
|
||||
const uint8_t* RawCode() const { return code_ + RawCodeOffset(); }
|
||||
|
||||
static constexpr int PadAndAlign(int size) {
|
||||
// Ensure we have at least one byte trailing the actual builtin
|
||||
@ -136,8 +162,14 @@ class EmbeddedData final {
|
||||
|
||||
void PrintStatistics() const;
|
||||
|
||||
const uint8_t* data_;
|
||||
uint32_t size_;
|
||||
// This points to code for builtins. The contents are potentially unreadable
|
||||
// on platforms that disallow reads from the .text section.
|
||||
const uint8_t* code_;
|
||||
uint32_t code_size_;
|
||||
|
||||
// This is metadata for the code.
|
||||
const uint8_t* metadata_;
|
||||
uint32_t metadata_size_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -8,16 +8,24 @@
|
||||
|
||||
#include "src/base/macros.h"
|
||||
|
||||
extern "C" const uint8_t* v8_Default_embedded_blob_;
|
||||
extern "C" uint32_t v8_Default_embedded_blob_size_;
|
||||
extern "C" const uint8_t* v8_Default_embedded_blob_code_;
|
||||
extern "C" uint32_t v8_Default_embedded_blob_code_size_;
|
||||
extern "C" const uint8_t* v8_Default_embedded_blob_metadata_;
|
||||
extern "C" uint32_t v8_Default_embedded_blob_metadata_size_;
|
||||
|
||||
const uint8_t* v8_Default_embedded_blob_ = nullptr;
|
||||
uint32_t v8_Default_embedded_blob_size_ = 0;
|
||||
const uint8_t* v8_Default_embedded_blob_code_ = nullptr;
|
||||
uint32_t v8_Default_embedded_blob_code_size_ = 0;
|
||||
const uint8_t* v8_Default_embedded_blob_metadata_ = nullptr;
|
||||
uint32_t v8_Default_embedded_blob_metadata_size_ = 0;
|
||||
|
||||
#ifdef V8_MULTI_SNAPSHOTS
|
||||
extern "C" const uint8_t* v8_Trusted_embedded_blob_;
|
||||
extern "C" uint32_t v8_Trusted_embedded_blob_size_;
|
||||
extern "C" const uint8_t* v8_Trusted_embedded_blob_code_;
|
||||
extern "C" uint32_t v8_Trusted_embedded_blob_code_size_;
|
||||
extern "C" const uint8_t* v8_Trusted_embedded_blob_metadata_;
|
||||
extern "C" uint32_t v8_Trusted_embedded_blob_metadata_size_;
|
||||
|
||||
const uint8_t* v8_Trusted_embedded_blob_ = nullptr;
|
||||
uint32_t v8_Trusted_embedded_blob_size_ = 0;
|
||||
const uint8_t* v8_Trusted_embedded_blob_code_ = nullptr;
|
||||
uint32_t v8_Trusted_embedded_blob_code_size_ = 0;
|
||||
const uint8_t* v8_Trusted_embedded_blob_metadata_ = nullptr;
|
||||
uint32_t v8_Trusted_embedded_blob_metadata_size_ = 0;
|
||||
#endif
|
||||
|
@ -73,27 +73,49 @@ void EmbeddedFileWriter::WriteBuiltin(PlatformEmbeddedFileWriterBase* w,
|
||||
void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w,
|
||||
const i::EmbeddedData* blob) const {
|
||||
{
|
||||
i::EmbeddedVector<char, kTemporaryStringLength> embedded_blob_symbol;
|
||||
i::SNPrintF(embedded_blob_symbol, "v8_%s_embedded_blob_",
|
||||
i::EmbeddedVector<char, kTemporaryStringLength> embedded_blob_code_symbol;
|
||||
i::SNPrintF(embedded_blob_code_symbol, "v8_%s_embedded_blob_code_",
|
||||
embedded_variant_);
|
||||
|
||||
w->Comment("Pointer to the beginning of the embedded blob.");
|
||||
w->Comment("Pointer to the beginning of the embedded blob code.");
|
||||
w->SectionData();
|
||||
w->AlignToDataAlignment();
|
||||
w->DeclarePointerToSymbol(embedded_blob_symbol.begin(),
|
||||
EmbeddedBlobDataSymbol().c_str());
|
||||
w->DeclarePointerToSymbol(embedded_blob_code_symbol.begin(),
|
||||
EmbeddedBlobCodeDataSymbol().c_str());
|
||||
w->Newline();
|
||||
|
||||
i::EmbeddedVector<char, kTemporaryStringLength>
|
||||
embedded_blob_metadata_symbol;
|
||||
i::SNPrintF(embedded_blob_metadata_symbol, "v8_%s_embedded_blob_metadata_",
|
||||
embedded_variant_);
|
||||
|
||||
w->Comment("Pointer to the beginning of the embedded blob metadata.");
|
||||
w->AlignToDataAlignment();
|
||||
w->DeclarePointerToSymbol(embedded_blob_metadata_symbol.begin(),
|
||||
EmbeddedBlobMetadataDataSymbol().c_str());
|
||||
w->Newline();
|
||||
}
|
||||
|
||||
{
|
||||
i::EmbeddedVector<char, kTemporaryStringLength> embedded_blob_size_symbol;
|
||||
i::SNPrintF(embedded_blob_size_symbol, "v8_%s_embedded_blob_size_",
|
||||
embedded_variant_);
|
||||
i::EmbeddedVector<char, kTemporaryStringLength>
|
||||
embedded_blob_code_size_symbol;
|
||||
i::SNPrintF(embedded_blob_code_size_symbol,
|
||||
"v8_%s_embedded_blob_code_size_", embedded_variant_);
|
||||
|
||||
w->Comment("The size of the embedded blob in bytes.");
|
||||
w->Comment("The size of the embedded blob code in bytes.");
|
||||
w->SectionRoData();
|
||||
w->AlignToDataAlignment();
|
||||
w->DeclareUint32(embedded_blob_size_symbol.begin(), blob->size());
|
||||
w->DeclareUint32(embedded_blob_code_size_symbol.begin(), blob->code_size());
|
||||
w->Newline();
|
||||
|
||||
i::EmbeddedVector<char, kTemporaryStringLength>
|
||||
embedded_blob_metadata_size_symbol;
|
||||
i::SNPrintF(embedded_blob_metadata_size_symbol,
|
||||
"v8_%s_embedded_blob_metadata_size_", embedded_variant_);
|
||||
|
||||
w->Comment("The size of the embedded blob metadata in bytes.");
|
||||
w->DeclareUint32(embedded_blob_metadata_size_symbol.begin(),
|
||||
blob->metadata_size());
|
||||
w->Newline();
|
||||
}
|
||||
|
||||
@ -104,7 +126,7 @@ void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w,
|
||||
embedded_variant_);
|
||||
|
||||
w->MaybeEmitUnwindData(unwind_info_symbol.begin(),
|
||||
EmbeddedBlobDataSymbol().c_str(), blob,
|
||||
EmbeddedBlobCodeDataSymbol().c_str(), blob,
|
||||
reinterpret_cast<const void*>(&unwind_infos_[0]));
|
||||
}
|
||||
#endif // V8_OS_WIN64
|
||||
|
@ -142,23 +142,31 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface {
|
||||
// Fairly arbitrary but should fit all symbol names.
|
||||
static constexpr int kTemporaryStringLength = 256;
|
||||
|
||||
std::string EmbeddedBlobDataSymbol() const {
|
||||
i::EmbeddedVector<char, kTemporaryStringLength> embedded_blob_data_symbol;
|
||||
i::SNPrintF(embedded_blob_data_symbol, "v8_%s_embedded_blob_data_",
|
||||
embedded_variant_);
|
||||
return std::string{embedded_blob_data_symbol.begin()};
|
||||
std::string EmbeddedBlobCodeDataSymbol() const {
|
||||
i::EmbeddedVector<char, kTemporaryStringLength>
|
||||
embedded_blob_code_data_symbol;
|
||||
i::SNPrintF(embedded_blob_code_data_symbol,
|
||||
"v8_%s_embedded_blob_code_data_", embedded_variant_);
|
||||
return std::string{embedded_blob_code_data_symbol.begin()};
|
||||
}
|
||||
|
||||
std::string EmbeddedBlobMetadataDataSymbol() const {
|
||||
i::EmbeddedVector<char, kTemporaryStringLength>
|
||||
embedded_blob_metadata_data_symbol;
|
||||
i::SNPrintF(embedded_blob_metadata_data_symbol,
|
||||
"v8_%s_embedded_blob_metadata_data_", embedded_variant_);
|
||||
return std::string{embedded_blob_metadata_data_symbol.begin()};
|
||||
}
|
||||
|
||||
void WriteMetadataSection(PlatformEmbeddedFileWriterBase* w,
|
||||
const i::EmbeddedData* blob) const {
|
||||
w->Comment("The embedded blob starts here. Metadata comes first, followed");
|
||||
w->Comment("by builtin instruction streams.");
|
||||
w->SectionText();
|
||||
w->AlignToCodeAlignment();
|
||||
w->DeclareLabel(EmbeddedBlobDataSymbol().c_str());
|
||||
w->Comment("The embedded blob metadata starts here.");
|
||||
w->SectionRoData();
|
||||
w->AlignToDataAlignment();
|
||||
w->DeclareLabel(EmbeddedBlobMetadataDataSymbol().c_str());
|
||||
|
||||
WriteBinaryContentsAsInlineAssembly(w, blob->data(),
|
||||
i::EmbeddedData::RawDataOffset());
|
||||
WriteBinaryContentsAsInlineAssembly(w, blob->metadata(),
|
||||
blob->metadata_size());
|
||||
}
|
||||
|
||||
void WriteBuiltin(PlatformEmbeddedFileWriterBase* w,
|
||||
@ -166,6 +174,12 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface {
|
||||
|
||||
void WriteInstructionStreams(PlatformEmbeddedFileWriterBase* w,
|
||||
const i::EmbeddedData* blob) const {
|
||||
w->Comment("The embedded blob data starts here. It contains the builtin");
|
||||
w->Comment("instruction streams.");
|
||||
w->SectionText();
|
||||
w->AlignToCodeAlignment();
|
||||
w->DeclareLabel(EmbeddedBlobCodeDataSymbol().c_str());
|
||||
|
||||
for (int i = 0; i < i::Builtins::builtin_count; i++) {
|
||||
if (!blob->ContainsBuiltin(i)) continue;
|
||||
|
||||
|
@ -118,7 +118,7 @@ void EmitUnwindData(PlatformEmbeddedFileWriterWin* w,
|
||||
if (unwind_infos[i].is_leaf_function()) continue;
|
||||
|
||||
uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(i) -
|
||||
reinterpret_cast<Address>(blob->data());
|
||||
reinterpret_cast<Address>(blob->code());
|
||||
uint32_t builtin_size = blob->InstructionSizeOfBuiltin(i);
|
||||
|
||||
const std::vector<int>& xdata_desc = unwind_infos[i].fp_offsets();
|
||||
@ -198,7 +198,7 @@ void EmitUnwindData(PlatformEmbeddedFileWriterWin* w,
|
||||
if (unwind_infos[i].is_leaf_function()) continue;
|
||||
|
||||
uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(i) -
|
||||
reinterpret_cast<Address>(blob->data());
|
||||
reinterpret_cast<Address>(blob->code());
|
||||
uint32_t builtin_size = blob->InstructionSizeOfBuiltin(i);
|
||||
|
||||
const std::vector<int>& xdata_desc = unwind_infos[i].fp_offsets();
|
||||
|
@ -21,5 +21,20 @@ uint32_t Checksum(Vector<const byte> payload) {
|
||||
return static_cast<uint32_t>(adler32(0, payload.begin(), payload.length()));
|
||||
}
|
||||
|
||||
V8_EXPORT_PRIVATE uint32_t Checksum(Vector<const byte> payload1,
|
||||
Vector<const byte> payload2) {
|
||||
#ifdef MEMORY_SANITIZER
|
||||
// Computing the checksum includes padding bytes for objects like strings.
|
||||
// Mark every object as initialized in the code serializer.
|
||||
MSAN_MEMORY_IS_INITIALIZED(payload1.begin(), payload1.length());
|
||||
MSAN_MEMORY_IS_INITIALIZED(payload2.begin(), payload2.length());
|
||||
#endif // MEMORY_SANITIZER
|
||||
// Priming the adler32 call so it can see what CPU features are available.
|
||||
adler32(0, nullptr, 0);
|
||||
auto sum = adler32(0, payload1.begin(), payload1.length());
|
||||
sum = adler32(sum, payload2.begin(), payload2.length());
|
||||
return static_cast<uint32_t>(sum);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -11,6 +11,8 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
V8_EXPORT_PRIVATE uint32_t Checksum(Vector<const byte> payload);
|
||||
V8_EXPORT_PRIVATE uint32_t Checksum(Vector<const byte> payload1,
|
||||
Vector<const byte> payload2);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -98,9 +98,9 @@ TEST(CodeRangeCorrectContents) {
|
||||
// We should only have the code range and the embedded code range.
|
||||
CHECK_EQ(2, pages->size());
|
||||
CHECK(PagesHasExactPage(pages, code_range.begin(), code_range.size()));
|
||||
CHECK(PagesHasExactPage(pages,
|
||||
reinterpret_cast<Address>(i_isolate->embedded_blob()),
|
||||
i_isolate->embedded_blob_size()));
|
||||
CHECK(PagesHasExactPage(
|
||||
pages, reinterpret_cast<Address>(i_isolate->embedded_blob_code()),
|
||||
i_isolate->embedded_blob_code_size()));
|
||||
}
|
||||
|
||||
TEST(CodePagesCorrectContents) {
|
||||
@ -120,9 +120,9 @@ TEST(CodePagesCorrectContents) {
|
||||
|
||||
// We should have the embedded code range even when there is no regular code
|
||||
// range.
|
||||
CHECK(PagesHasExactPage(pages,
|
||||
reinterpret_cast<Address>(i_isolate->embedded_blob()),
|
||||
i_isolate->embedded_blob_size()));
|
||||
CHECK(PagesHasExactPage(
|
||||
pages, reinterpret_cast<Address>(i_isolate->embedded_blob_code()),
|
||||
i_isolate->embedded_blob_code_size()));
|
||||
}
|
||||
|
||||
TEST(OptimizedCodeWithCodeRange) {
|
||||
|
Loading…
Reference in New Issue
Block a user