Commit 66ed5644 authored by Toan Pham's avatar Toan Pham Committed by Commit Bot

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