Revert "[builtins] Remove off-heap builtins from the snapshot"
This reverts commit f1b1ec70a6
.
Reason for revert: Tentative revert for https://logs.chromium.org/v/?s=chromium%2Fbb%2Fclient.v8.fyi%2FV8-Blink_Mac%2F13696%2F%2B%2Frecipes%2Fsteps%2Fwebkit_unit_tests%2F0%2Fstdout
Original change's description:
> [builtins] Remove off-heap builtins from the snapshot
>
> This CL is the final major step towards shipping off-heap-safe builtins
> embedded into the binary.
>
> Prior to snapshot serialization, we now:
> * create the embedded blob containing off-heap instruction streams,
> * use that to generate embedded.cc (containing embedded binary data),
> * replace off-heap-safe builtins with trampolines,
> * and serialize those into the final snapshot.
>
> The new RelocInfo::OFF_HEAP_TARGET kind is used to fix up trampoline
> targets on deserialization.
>
> Bug: v8:6666
> Change-Id: Ib07aea9e3bd7ecdec42291c1388b3a7453ea96ce
> Reviewed-on: https://chromium-review.googlesource.com/950775
> Commit-Queue: Jakob Gruber <jgruber@chromium.org>
> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
> Reviewed-by: Yang Guo <yangguo@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51960}
TBR=yangguo@chromium.org,mstarzinger@chromium.org,jgruber@chromium.org
Change-Id: I58dd4bf9a99d37416855b48807150e1dd9ecd9e8
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:6666
Reviewed-on: https://chromium-review.googlesource.com/964363
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51962}
This commit is contained in:
parent
ef99ff6ed4
commit
fda0d684c3
@ -73,8 +73,7 @@ Address RelocInfo::target_address() {
|
||||
|
||||
Address RelocInfo::target_address_address() {
|
||||
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
|
||||
IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
|
||||
IsOffHeapTarget(rmode_));
|
||||
rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE);
|
||||
if (Assembler::IsMovW(Memory::int32_at(pc_))) {
|
||||
return reinterpret_cast<Address>(pc_);
|
||||
} else {
|
||||
@ -152,11 +151,6 @@ void RelocInfo::set_target_runtime_entry(Address target,
|
||||
set_target_address(target, write_barrier_mode, icache_flush_mode);
|
||||
}
|
||||
|
||||
Address RelocInfo::target_off_heap_target() {
|
||||
DCHECK(IsOffHeapTarget(rmode_));
|
||||
return Assembler::target_address_at(pc_, constant_pool_);
|
||||
}
|
||||
|
||||
void RelocInfo::WipeOut() {
|
||||
DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
|
||||
IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
|
||||
@ -181,8 +175,6 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
|
||||
visitor->VisitInternalReference(host(), this);
|
||||
} else if (RelocInfo::IsRuntimeEntry(mode)) {
|
||||
visitor->VisitRuntimeEntry(host(), this);
|
||||
} else if (RelocInfo::IsOffHeapTarget(mode)) {
|
||||
visitor->VisitOffHeapTarget(host(), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1717,7 +1717,7 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
|
||||
|
||||
void MacroAssembler::JumpToInstructionStream(Address entry) {
|
||||
mov(kOffHeapTrampolineRegister,
|
||||
Operand(reinterpret_cast<int32_t>(entry), RelocInfo::OFF_HEAP_TARGET));
|
||||
Operand(reinterpret_cast<int32_t>(entry), RelocInfo::NONE));
|
||||
Jump(kOffHeapTrampolineRegister);
|
||||
}
|
||||
|
||||
|
@ -613,8 +613,7 @@ Address RelocInfo::target_address() {
|
||||
|
||||
Address RelocInfo::target_address_address() {
|
||||
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
|
||||
IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
|
||||
IsOffHeapTarget(rmode_));
|
||||
rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE);
|
||||
return Assembler::target_pointer_address_at(pc_);
|
||||
}
|
||||
|
||||
@ -683,11 +682,6 @@ void RelocInfo::set_target_runtime_entry(Address target,
|
||||
}
|
||||
}
|
||||
|
||||
Address RelocInfo::target_off_heap_target() {
|
||||
DCHECK(IsOffHeapTarget(rmode_));
|
||||
return Assembler::target_address_at(pc_, constant_pool_);
|
||||
}
|
||||
|
||||
void RelocInfo::WipeOut() {
|
||||
DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
|
||||
IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
|
||||
@ -712,8 +706,6 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
|
||||
visitor->VisitInternalReference(host(), this);
|
||||
} else if (RelocInfo::IsRuntimeEntry(mode)) {
|
||||
visitor->VisitRuntimeEntry(host(), this);
|
||||
} else if (RelocInfo::IsOffHeapTarget(mode)) {
|
||||
visitor->VisitOffHeapTarget(host(), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1760,8 +1760,7 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
|
||||
}
|
||||
|
||||
void MacroAssembler::JumpToInstructionStream(Address entry) {
|
||||
Mov(kOffHeapTrampolineRegister,
|
||||
Operand(reinterpret_cast<uint64_t>(entry), RelocInfo::OFF_HEAP_TARGET));
|
||||
Mov(kOffHeapTrampolineRegister, reinterpret_cast<uint64_t>(entry));
|
||||
Br(kOffHeapTrampolineRegister);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include "src/code-stubs.h"
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/disassembler.h"
|
||||
#include "src/instruction-stream.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/ostreams.h"
|
||||
#include "src/simulator.h" // For flushing instruction cache.
|
||||
@ -521,8 +520,6 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
|
||||
return "internal reference";
|
||||
case INTERNAL_REFERENCE_ENCODED:
|
||||
return "encoded internal reference";
|
||||
case OFF_HEAP_TARGET:
|
||||
return "off heap target";
|
||||
case DEOPT_SCRIPT_OFFSET:
|
||||
return "deopt script offset";
|
||||
case DEOPT_INLINING_ID:
|
||||
@ -624,12 +621,6 @@ void RelocInfo::Verify(Isolate* isolate) {
|
||||
CHECK(target <= code->instruction_end());
|
||||
break;
|
||||
}
|
||||
case OFF_HEAP_TARGET: {
|
||||
Address addr = target_off_heap_target();
|
||||
CHECK_NOT_NULL(addr);
|
||||
CHECK_NOT_NULL(InstructionStream::TryLookupCode(isolate, addr));
|
||||
break;
|
||||
}
|
||||
case RUNTIME_ENTRY:
|
||||
case COMMENT:
|
||||
case EXTERNAL_REFERENCE:
|
||||
|
@ -379,9 +379,6 @@ class RelocInfo {
|
||||
// Encoded internal reference, used only on MIPS, MIPS64 and PPC.
|
||||
INTERNAL_REFERENCE_ENCODED,
|
||||
|
||||
// An off-heap instruction stream target. See http://goo.gl/Z2HUiM.
|
||||
OFF_HEAP_TARGET,
|
||||
|
||||
// Marks constant and veneer pools. Only used on ARM and ARM64.
|
||||
// They use a custom noncompact encoding.
|
||||
CONST_POOL,
|
||||
@ -458,9 +455,6 @@ class RelocInfo {
|
||||
static inline bool IsInternalReferenceEncoded(Mode mode) {
|
||||
return mode == INTERNAL_REFERENCE_ENCODED;
|
||||
}
|
||||
static inline bool IsOffHeapTarget(Mode mode) {
|
||||
return mode == OFF_HEAP_TARGET;
|
||||
}
|
||||
static inline bool IsNone(Mode mode) { return mode == NONE; }
|
||||
static inline bool IsWasmContextReference(Mode mode) {
|
||||
return mode == WASM_CONTEXT_REFERENCE;
|
||||
@ -535,7 +529,6 @@ class RelocInfo {
|
||||
Address target,
|
||||
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
|
||||
INLINE(Address target_off_heap_target());
|
||||
INLINE(Cell* target_cell());
|
||||
INLINE(Handle<Cell> target_cell_handle());
|
||||
INLINE(void set_target_cell(
|
||||
|
@ -202,7 +202,8 @@ bool Builtins::IsBuiltin(Code* code) {
|
||||
// static
|
||||
bool Builtins::IsOffHeapBuiltin(Code* code) {
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
return Builtins::IsBuiltinId(code->builtin_index()) &&
|
||||
return FLAG_stress_off_heap_code &&
|
||||
Builtins::IsBuiltinId(code->builtin_index()) &&
|
||||
Builtins::IsOffHeapSafe(code->builtin_index());
|
||||
#else
|
||||
return false;
|
||||
@ -212,12 +213,6 @@ bool Builtins::IsOffHeapBuiltin(Code* code) {
|
||||
// static
|
||||
bool Builtins::IsLazy(int index) {
|
||||
DCHECK(IsBuiltinId(index));
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
// We don't want to lazy-deserialize off-heap builtins.
|
||||
if (Builtins::IsOffHeapSafe(index)) return false;
|
||||
#endif
|
||||
|
||||
// There are a couple of reasons that builtins can require eager-loading,
|
||||
// i.e. deserialization at isolate creation instead of on-demand. For
|
||||
// instance:
|
||||
@ -649,7 +644,7 @@ bool Builtins::IsIsolateIndependent(int index) {
|
||||
|
||||
// static
|
||||
bool Builtins::IsOffHeapSafe(int index) {
|
||||
#if !defined(V8_EMBEDDED_BUILTINS) || !defined(V8_USE_SNAPSHOT)
|
||||
#ifndef V8_EMBEDDED_BUILTINS
|
||||
return false;
|
||||
#else
|
||||
DCHECK(IsBuiltinId(index));
|
||||
@ -669,32 +664,6 @@ bool Builtins::IsTooShortForOffHeapTrampoline(int index) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
// static
|
||||
Handle<Code> Builtins::GenerateOffHeapTrampolineFor(Isolate* isolate,
|
||||
Address off_heap_entry) {
|
||||
DCHECK(isolate->serializer_enabled());
|
||||
DCHECK_NOT_NULL(isolate->embedded_blob());
|
||||
DCHECK_NE(0, isolate->embedded_blob_size());
|
||||
|
||||
constexpr size_t buffer_size = 256; // Enough to fit the single jmp.
|
||||
byte buffer[buffer_size]; // NOLINT(runtime/arrays)
|
||||
|
||||
// Generate replacement code that simply tail-calls the off-heap code.
|
||||
MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
|
||||
DCHECK(!masm.has_frame());
|
||||
{
|
||||
FrameScope scope(&masm, StackFrame::NONE);
|
||||
masm.JumpToInstructionStream(off_heap_entry);
|
||||
}
|
||||
|
||||
CodeDesc desc;
|
||||
masm.GetCode(isolate, &desc);
|
||||
|
||||
return isolate->factory()->NewCode(desc, Code::BUILTIN, masm.CodeObject());
|
||||
}
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
|
||||
// static
|
||||
Builtins::Kind Builtins::KindOf(int index) {
|
||||
DCHECK(IsBuiltinId(index));
|
||||
|
@ -72,7 +72,7 @@ class Builtins {
|
||||
Handle<Code> NewFunctionContext(ScopeType scope_type);
|
||||
Handle<Code> JSConstructStubGeneric();
|
||||
|
||||
// Used by BuiltinDeserializer and CreateOffHeapTrampolines in isolate.cc.
|
||||
// Used by BuiltinDeserializer.
|
||||
void set_builtin(int index, HeapObject* builtin);
|
||||
|
||||
Code* builtin(int index) {
|
||||
@ -160,14 +160,6 @@ class Builtins {
|
||||
private:
|
||||
Builtins();
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
// Creates a trampoline code object that jumps to the given off-heap entry.
|
||||
// The result should not be used directly, but only from the related Factory
|
||||
// function.
|
||||
static Handle<Code> GenerateOffHeapTrampolineFor(Isolate* isolate,
|
||||
Address off_heap_entry);
|
||||
#endif
|
||||
|
||||
static void Generate_CallFunction(MacroAssembler* masm,
|
||||
ConvertReceiverMode mode);
|
||||
|
||||
@ -206,7 +198,6 @@ class Builtins {
|
||||
Object* builtins_[builtin_count];
|
||||
bool initialized_;
|
||||
|
||||
friend class Factory; // For GenerateOffHeapTrampolineFor.
|
||||
friend class Isolate;
|
||||
friend class SetupIsolateDelegate;
|
||||
|
||||
|
@ -1856,36 +1856,6 @@ Handle<Code> Factory::NewCodeForDeserialization(uint32_t size) {
|
||||
Code);
|
||||
}
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
Handle<Code> Factory::NewOffHeapTrampolineFor(Handle<Code> code,
|
||||
Address off_heap_entry) {
|
||||
DCHECK(isolate()->serializer_enabled());
|
||||
DCHECK_NOT_NULL(isolate()->embedded_blob());
|
||||
DCHECK_NE(0, isolate()->embedded_blob_size());
|
||||
DCHECK(Builtins::IsOffHeapBuiltin(*code));
|
||||
|
||||
Handle<Code> result =
|
||||
Builtins::GenerateOffHeapTrampolineFor(isolate(), off_heap_entry);
|
||||
|
||||
// The trampoline code object must inherit specific flags from the original
|
||||
// builtin (e.g. the safepoint-table offset). We set them manually here.
|
||||
|
||||
const int stack_slots = code->has_safepoint_info() ? code->stack_slots() : 0;
|
||||
result->initialize_flags(code->kind(), code->has_unwinding_info(),
|
||||
code->is_turbofanned(), stack_slots);
|
||||
result->set_builtin_index(code->builtin_index());
|
||||
result->set_has_tagged_params(code->has_tagged_params());
|
||||
result->set_handler_table_offset(code->handler_table_offset());
|
||||
result->code_data_container()->set_kind_specific_flags(
|
||||
code->code_data_container()->kind_specific_flags());
|
||||
if (code->has_safepoint_info()) {
|
||||
result->set_safepoint_table_offset(code->safepoint_table_offset());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
Handle<Code> Factory::CopyCode(Handle<Code> code) {
|
||||
Handle<CodeDataContainer> data_container =
|
||||
NewCodeDataContainer(code->code_data_container()->kind_specific_flags());
|
||||
|
@ -716,13 +716,6 @@ class V8_EXPORT_PRIVATE Factory final {
|
||||
// given {size} argument specifies the size of the entire code object.
|
||||
Handle<Code> NewCodeForDeserialization(uint32_t size);
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
// Allocates a new code object and initializes it as the trampoline to the
|
||||
// given off-heap entry point.
|
||||
Handle<Code> NewOffHeapTrampolineFor(Handle<Code> code,
|
||||
Address off_heap_entry);
|
||||
#endif
|
||||
|
||||
Handle<Code> CopyCode(Handle<Code> code);
|
||||
|
||||
Handle<BytecodeArray> CopyBytecodeArray(Handle<BytecodeArray>);
|
||||
|
@ -6830,7 +6830,9 @@ bool Heap::GcSafeCodeContains(HeapObject* code, Address addr) {
|
||||
Map* map = GcSafeMapOfCodeSpaceObject(code);
|
||||
DCHECK(map == code->GetHeap()->code_map());
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
if (InstructionStream::TryLookupCode(isolate(), addr) == code) return true;
|
||||
if (FLAG_stress_off_heap_code) {
|
||||
if (InstructionStream::TryLookupCode(isolate(), addr) == code) return true;
|
||||
}
|
||||
#endif
|
||||
Address start = code->address();
|
||||
Address end = code->address() + code->SizeFromMap(map);
|
||||
@ -6839,8 +6841,10 @@ bool Heap::GcSafeCodeContains(HeapObject* code, Address addr) {
|
||||
|
||||
Code* Heap::GcSafeFindCodeForInnerPointer(Address inner_pointer) {
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
Code* code = InstructionStream::TryLookupCode(isolate(), inner_pointer);
|
||||
if (code != nullptr) return code;
|
||||
if (FLAG_stress_off_heap_code) {
|
||||
Code* code = InstructionStream::TryLookupCode(isolate(), inner_pointer);
|
||||
if (code != nullptr) return code;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check if the inner pointer points into a large object chunk.
|
||||
|
@ -72,8 +72,7 @@ Address RelocInfo::target_address() {
|
||||
|
||||
Address RelocInfo::target_address_address() {
|
||||
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
|
||||
IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
|
||||
IsOffHeapTarget(rmode_));
|
||||
rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE);
|
||||
return reinterpret_cast<Address>(pc_);
|
||||
}
|
||||
|
||||
@ -145,11 +144,6 @@ void RelocInfo::set_target_runtime_entry(Address target,
|
||||
}
|
||||
}
|
||||
|
||||
Address RelocInfo::target_off_heap_target() {
|
||||
DCHECK(IsOffHeapTarget(rmode_));
|
||||
return Memory::Address_at(pc_);
|
||||
}
|
||||
|
||||
void RelocInfo::WipeOut() {
|
||||
if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
|
||||
IsInternalReference(rmode_)) {
|
||||
@ -177,8 +171,6 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
|
||||
visitor->VisitInternalReference(host(), this);
|
||||
} else if (IsRuntimeEntry(mode)) {
|
||||
visitor->VisitRuntimeEntry(host(), this);
|
||||
} else if (RelocInfo::IsOffHeapTarget(mode)) {
|
||||
visitor->VisitOffHeapTarget(host(), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -848,7 +848,7 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
|
||||
}
|
||||
|
||||
void MacroAssembler::JumpToInstructionStream(Address entry) {
|
||||
mov(kOffHeapTrampolineRegister, Immediate(entry, RelocInfo::OFF_HEAP_TARGET));
|
||||
mov(kOffHeapTrampolineRegister, Immediate(entry, RelocInfo::NONE));
|
||||
jmp(kOffHeapTrampolineRegister);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ bool InstructionStream::PcIsOffHeap(Isolate* isolate, Address pc) {
|
||||
// static
|
||||
Code* InstructionStream::TryLookupCode(Isolate* isolate, Address address) {
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
DCHECK(FLAG_stress_off_heap_code);
|
||||
|
||||
if (!PcIsOffHeap(isolate, address)) return nullptr;
|
||||
|
||||
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
|
||||
@ -50,35 +52,5 @@ Code* InstructionStream::TryLookupCode(Isolate* isolate, Address address) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
// static
|
||||
void InstructionStream::CreateOffHeapInstructionStream(Isolate* isolate,
|
||||
uint8_t** data,
|
||||
uint32_t* size) {
|
||||
EmbeddedData d = EmbeddedData::FromIsolate(isolate);
|
||||
|
||||
const uint32_t page_size = static_cast<uint32_t>(AllocatePageSize());
|
||||
const uint32_t allocated_size = RoundUp(d.size(), page_size);
|
||||
|
||||
uint8_t* allocated_bytes = static_cast<uint8_t*>(
|
||||
AllocatePages(GetRandomMmapAddr(), allocated_size, page_size,
|
||||
PageAllocator::kReadWrite));
|
||||
CHECK_NOT_NULL(allocated_bytes);
|
||||
|
||||
std::memcpy(allocated_bytes, d.data(), d.size());
|
||||
CHECK(SetPermissions(allocated_bytes, allocated_size,
|
||||
PageAllocator::kReadExecute));
|
||||
|
||||
*data = allocated_bytes;
|
||||
*size = allocated_size;
|
||||
}
|
||||
|
||||
// static
|
||||
void InstructionStream::FreeOffHeapInstructionStream(uint8_t* data,
|
||||
uint32_t size) {
|
||||
CHECK(FreePages(data, size));
|
||||
}
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -23,16 +23,6 @@ class InstructionStream final : public AllStatic {
|
||||
|
||||
// Returns the corresponding Code object if it exists, and nullptr otherwise.
|
||||
static Code* TryLookupCode(Isolate* isolate, Address address);
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
// During snapshot creation, we first create an executable off-heap area
|
||||
// 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);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
129
src/isolate.cc
129
src/isolate.cc
@ -70,8 +70,11 @@ base::Atomic32 ThreadId::highest_thread_id_ = 0;
|
||||
extern const uint8_t* DefaultEmbeddedBlob();
|
||||
extern uint32_t DefaultEmbeddedBlobSize();
|
||||
|
||||
const uint8_t* Isolate::embedded_blob() const { return embedded_blob_; }
|
||||
uint32_t Isolate::embedded_blob_size() const { return embedded_blob_size_; }
|
||||
const uint8_t* Isolate::embedded_blob() const { return DefaultEmbeddedBlob(); }
|
||||
|
||||
uint32_t Isolate::embedded_blob_size() const {
|
||||
return DefaultEmbeddedBlobSize();
|
||||
}
|
||||
#endif
|
||||
|
||||
int ThreadId::AllocateThreadId() {
|
||||
@ -2648,14 +2651,6 @@ void Isolate::Deinit() {
|
||||
heap_.TearDown();
|
||||
logger_->TearDown();
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
if (DefaultEmbeddedBlob() == nullptr && embedded_blob() != nullptr) {
|
||||
// We own the embedded blob. Free it.
|
||||
uint8_t* data = const_cast<uint8_t*>(embedded_blob_);
|
||||
InstructionStream::FreeOffHeapInstructionStream(data, embedded_blob_size_);
|
||||
}
|
||||
#endif
|
||||
|
||||
delete interpreter_;
|
||||
interpreter_ = nullptr;
|
||||
|
||||
@ -2823,14 +2818,70 @@ void PrintBuiltinSizes(Isolate* isolate) {
|
||||
}
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
void CreateOffHeapTrampolines(Isolate* isolate) {
|
||||
DCHECK(isolate->serializer_enabled());
|
||||
void ChangeToOffHeapTrampoline(Isolate* isolate, Handle<Code> code,
|
||||
const uint8_t* entry) {
|
||||
DCHECK(Builtins::IsOffHeapSafe(code->builtin_index()));
|
||||
HandleScope scope(isolate);
|
||||
|
||||
constexpr size_t buffer_size = 256; // Enough to fit the single jmp.
|
||||
byte buffer[buffer_size]; // NOLINT(runtime/arrays)
|
||||
|
||||
// Generate replacement code that simply tail-calls the off-heap code.
|
||||
MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
|
||||
DCHECK(!masm.has_frame());
|
||||
{
|
||||
FrameScope scope(&masm, StackFrame::NONE);
|
||||
masm.JumpToInstructionStream(
|
||||
reinterpret_cast<Address>(const_cast<uint8_t*>(entry)));
|
||||
}
|
||||
|
||||
CodeDesc desc;
|
||||
masm.GetCode(isolate, &desc);
|
||||
|
||||
// Hack in an empty reloc info to satisfy the GC.
|
||||
DCHECK_EQ(0, desc.reloc_size);
|
||||
Handle<ByteArray> reloc_info =
|
||||
isolate->factory()->NewByteArray(desc.reloc_size, TENURED);
|
||||
code->set_relocation_info(*reloc_info);
|
||||
|
||||
// Overwrites the original code.
|
||||
CHECK_LE(desc.instr_size, code->instruction_size());
|
||||
CHECK_IMPLIES(code->has_safepoint_info(),
|
||||
desc.instr_size <= code->safepoint_table_offset());
|
||||
code->CopyFrom(desc);
|
||||
|
||||
// TODO(jgruber): CopyFrom isn't intended to overwrite existing code, and
|
||||
// doesn't update things like instruction_size. The result is a code object in
|
||||
// which the first instructions are overwritten while the rest remain intact
|
||||
// (but are never executed). That's fine for our current purposes, just
|
||||
// manually zero the trailing part.
|
||||
|
||||
int code_instruction_size = code->instruction_size();
|
||||
DCHECK_LE(desc.instr_size, code_instruction_size);
|
||||
byte* trailing_instruction_start =
|
||||
code->instruction_start() + desc.instr_size;
|
||||
if (code->has_safepoint_info()) {
|
||||
CHECK_LE(code->safepoint_table_offset(), code->instruction_size());
|
||||
code_instruction_size = code->safepoint_table_offset();
|
||||
CHECK_LE(desc.instr_size, code_instruction_size);
|
||||
}
|
||||
size_t trailing_instruction_size = code_instruction_size - desc.instr_size;
|
||||
std::memset(trailing_instruction_start, 0, trailing_instruction_size);
|
||||
}
|
||||
|
||||
void CreateOnHeapTrampolines(Isolate* isolate) {
|
||||
DCHECK(FLAG_stress_off_heap_code);
|
||||
DCHECK(!isolate->serializer_enabled());
|
||||
DCHECK_NOT_NULL(isolate->embedded_blob());
|
||||
DCHECK_NE(0, isolate->embedded_blob_size());
|
||||
|
||||
HandleScope scope(isolate);
|
||||
Builtins* builtins = isolate->builtins();
|
||||
|
||||
// Lazy deserialization would defeat our off-heap stress test (we'd
|
||||
// deserialize later without moving off-heap), so force eager
|
||||
// deserialization.
|
||||
Snapshot::EnsureAllBuiltinsAreDeserialized(isolate);
|
||||
|
||||
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
|
||||
isolate->embedded_blob_size());
|
||||
|
||||
@ -2839,49 +2890,22 @@ void CreateOffHeapTrampolines(Isolate* isolate) {
|
||||
if (!Builtins::IsOffHeapSafe(i)) continue;
|
||||
|
||||
const uint8_t* instruction_start = d.InstructionStartOfBuiltin(i);
|
||||
Handle<Code> trampoline = isolate->factory()->NewOffHeapTrampolineFor(
|
||||
builtins->builtin_handle(i), const_cast<Address>(instruction_start));
|
||||
|
||||
// Note that references to the old, on-heap code objects may still exist on
|
||||
// the heap. This is fine for the sake of serialization, as serialization
|
||||
// will replace all of them with a builtin reference which is later
|
||||
// deserialized to point to the object within the builtins table.
|
||||
//
|
||||
// From this point onwards, some builtin code objects may be unreachable and
|
||||
// thus collected by the GC.
|
||||
builtins->set_builtin(i, *trampoline);
|
||||
// TODO(jgruber,v8:6666): Create fresh trampolines instead of rewriting
|
||||
// existing ones. This could happen prior to serialization or
|
||||
// post-deserialization.
|
||||
Handle<Code> code(builtins->builtin(i));
|
||||
ChangeToOffHeapTrampoline(isolate, code, instruction_start);
|
||||
|
||||
if (isolate->logger()->is_logging_code_events() ||
|
||||
isolate->is_profiling()) {
|
||||
isolate->logger()->LogCodeObject(*trampoline);
|
||||
isolate->logger()->LogCodeObject(*code);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
} // namespace
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
void Isolate::PrepareEmbeddedBlobForSerialization() {
|
||||
// When preparing the embedded blob, ensure it doesn't exist yet.
|
||||
DCHECK_NULL(embedded_blob());
|
||||
DCHECK_NULL(DefaultEmbeddedBlob());
|
||||
DCHECK(serializer_enabled());
|
||||
|
||||
// The isolate takes ownership of this pointer into an executable mmap'd
|
||||
// area. We muck around with const-casts because the standard use-case in
|
||||
// shipping builds is for embedded_blob_ to point into a read-only
|
||||
// .text-embedded section.
|
||||
uint8_t* data;
|
||||
uint32_t size;
|
||||
InstructionStream::CreateOffHeapInstructionStream(this, &data, &size);
|
||||
|
||||
embedded_blob_ = const_cast<const uint8_t*>(data);
|
||||
embedded_blob_size_ = size;
|
||||
|
||||
CreateOffHeapTrampolines(this);
|
||||
}
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
|
||||
bool Isolate::Init(StartupDeserializer* des) {
|
||||
TRACE_ISOLATE(init);
|
||||
|
||||
@ -2935,11 +2959,6 @@ bool Isolate::Init(StartupDeserializer* des) {
|
||||
compiler_dispatcher_ =
|
||||
new CompilerDispatcher(this, V8::GetCurrentPlatform(), FLAG_stack_size);
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
embedded_blob_ = DefaultEmbeddedBlob();
|
||||
embedded_blob_size_ = DefaultEmbeddedBlobSize();
|
||||
#endif
|
||||
|
||||
// Enable logging before setting up the heap
|
||||
logger_->SetUp(this);
|
||||
|
||||
@ -3047,6 +3066,14 @@ bool Isolate::Init(StartupDeserializer* des) {
|
||||
|
||||
if (FLAG_print_builtin_size) PrintBuiltinSizes(this);
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
if (FLAG_stress_off_heap_code && !serializer_enabled() &&
|
||||
embedded_blob() != nullptr) {
|
||||
// Create the on-heap trampolines that jump into embedded code.
|
||||
CreateOnHeapTrampolines(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Finish initialization of ThreadLocal after deserialization is done.
|
||||
clear_pending_exception();
|
||||
clear_pending_message();
|
||||
|
@ -1247,11 +1247,6 @@ class Isolate {
|
||||
}
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
// Called only prior to serialization.
|
||||
// This function copies off-heap-safe builtins off the heap, creates off-heap
|
||||
// trampolines, and sets up this isolate's embedded blob.
|
||||
void PrepareEmbeddedBlobForSerialization();
|
||||
|
||||
BuiltinsConstantsTableBuilder* builtins_constants_table_builder() const {
|
||||
return builtins_constants_table_builder_;
|
||||
}
|
||||
@ -1633,9 +1628,6 @@ class Isolate {
|
||||
// Used during builtins compilation to build the builtins constants table,
|
||||
// which is stored on the root list prior to serialization.
|
||||
BuiltinsConstantsTableBuilder* builtins_constants_table_builder_ = nullptr;
|
||||
|
||||
const uint8_t* embedded_blob_ = nullptr;
|
||||
uint32_t embedded_blob_size_ = 0;
|
||||
#endif
|
||||
|
||||
v8::ArrayBuffer::Allocator* array_buffer_allocator_;
|
||||
|
@ -82,8 +82,7 @@ Address RelocInfo::target_address() {
|
||||
|
||||
Address RelocInfo::target_address_address() {
|
||||
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
|
||||
IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
|
||||
IsOffHeapTarget(rmode_));
|
||||
rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE);
|
||||
// Read the address of the word containing the target_address in an
|
||||
// instruction stream.
|
||||
// The only architecture-independent user of this function is the serializer.
|
||||
@ -255,11 +254,6 @@ void RelocInfo::set_target_runtime_entry(Address target,
|
||||
set_target_address(target, write_barrier_mode, icache_flush_mode);
|
||||
}
|
||||
|
||||
Address RelocInfo::target_off_heap_target() {
|
||||
DCHECK(IsOffHeapTarget(rmode_));
|
||||
return Assembler::target_address_at(pc_, constant_pool_);
|
||||
}
|
||||
|
||||
void RelocInfo::WipeOut() {
|
||||
DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
|
||||
IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
|
||||
@ -287,8 +281,6 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
|
||||
visitor->VisitInternalReference(host(), this);
|
||||
} else if (RelocInfo::IsRuntimeEntry(mode)) {
|
||||
visitor->VisitRuntimeEntry(host(), this);
|
||||
} else if (RelocInfo::IsOffHeapTarget(mode)) {
|
||||
visitor->VisitOffHeapTarget(host(), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4550,7 +4550,7 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
|
||||
|
||||
void MacroAssembler::JumpToInstructionStream(Address entry) {
|
||||
li(kOffHeapTrampolineRegister,
|
||||
Operand(reinterpret_cast<int32_t>(entry), RelocInfo::OFF_HEAP_TARGET));
|
||||
Operand(reinterpret_cast<int32_t>(entry), RelocInfo::NONE));
|
||||
Jump(kOffHeapTrampolineRegister);
|
||||
}
|
||||
|
||||
|
@ -80,9 +80,10 @@ Address RelocInfo::target_address() {
|
||||
}
|
||||
|
||||
Address RelocInfo::target_address_address() {
|
||||
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
|
||||
IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
|
||||
IsOffHeapTarget(rmode_));
|
||||
DCHECK(IsCodeTarget(rmode_) ||
|
||||
IsRuntimeEntry(rmode_) ||
|
||||
rmode_ == EMBEDDED_OBJECT ||
|
||||
rmode_ == EXTERNAL_REFERENCE);
|
||||
// Read the address of the word containing the target_address in an
|
||||
// instruction stream.
|
||||
// The only architecture-independent user of this function is the serializer.
|
||||
@ -221,11 +222,6 @@ void RelocInfo::set_target_runtime_entry(Address target,
|
||||
set_target_address(target, write_barrier_mode, icache_flush_mode);
|
||||
}
|
||||
|
||||
Address RelocInfo::target_off_heap_target() {
|
||||
DCHECK(IsOffHeapTarget(rmode_));
|
||||
return Assembler::target_address_at(pc_, constant_pool_);
|
||||
}
|
||||
|
||||
void RelocInfo::WipeOut() {
|
||||
DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
|
||||
IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
|
||||
@ -253,8 +249,6 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
|
||||
visitor->VisitInternalReference(host(), this);
|
||||
} else if (RelocInfo::IsRuntimeEntry(mode)) {
|
||||
visitor->VisitRuntimeEntry(host(), this);
|
||||
} else if (RelocInfo::IsOffHeapTarget(mode)) {
|
||||
visitor->VisitOffHeapTarget(host(), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4849,7 +4849,7 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
|
||||
|
||||
void MacroAssembler::JumpToInstructionStream(Address entry) {
|
||||
li(kOffHeapTrampolineRegister,
|
||||
Operand(reinterpret_cast<uint64_t>(entry), RelocInfo::OFF_HEAP_TARGET));
|
||||
Operand(reinterpret_cast<uint64_t>(entry), RelocInfo::NONE));
|
||||
Jump(kOffHeapTrampolineRegister);
|
||||
}
|
||||
|
||||
|
@ -414,7 +414,6 @@ class Code::BodyDescriptor final : public BodyDescriptorBase {
|
||||
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
|
||||
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
|
||||
RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
|
||||
RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) |
|
||||
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
|
||||
|
||||
// GC does not visit data/code in the header and in the body directly.
|
||||
|
@ -13970,7 +13970,6 @@ SafepointEntry Code::GetSafepointEntry(Address pc) {
|
||||
int Code::OffHeapInstructionSize() {
|
||||
DCHECK(Builtins::IsOffHeapBuiltin(this));
|
||||
Isolate* isolate = GetIsolate();
|
||||
if (isolate->embedded_blob() == nullptr) return instruction_size();
|
||||
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
|
||||
isolate->embedded_blob_size());
|
||||
return d.InstructionSizeOfBuiltin(builtin_index());
|
||||
@ -13979,7 +13978,6 @@ int Code::OffHeapInstructionSize() {
|
||||
Address Code::OffHeapInstructionStart() {
|
||||
DCHECK(Builtins::IsOffHeapBuiltin(this));
|
||||
Isolate* isolate = GetIsolate();
|
||||
if (isolate->embedded_blob() == nullptr) return instruction_start();
|
||||
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
|
||||
isolate->embedded_blob_size());
|
||||
return reinterpret_cast<Address>(
|
||||
@ -13989,7 +13987,6 @@ Address Code::OffHeapInstructionStart() {
|
||||
Address Code::OffHeapInstructionEnd() {
|
||||
DCHECK(Builtins::IsOffHeapBuiltin(this));
|
||||
Isolate* isolate = GetIsolate();
|
||||
if (isolate->embedded_blob() == nullptr) return instruction_end();
|
||||
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
|
||||
isolate->embedded_blob_size());
|
||||
return reinterpret_cast<Address>(
|
||||
@ -14141,7 +14138,6 @@ bool Code::IsProcessIndependent() {
|
||||
all_real_modes_mask & ~RelocInfo::ModeMask(RelocInfo::COMMENT) &
|
||||
~RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) &
|
||||
~RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) &
|
||||
~RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) &
|
||||
~RelocInfo::ModeMask(RelocInfo::CONST_POOL) &
|
||||
~RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
|
||||
STATIC_ASSERT(RelocInfo::LAST_REAL_RELOC_MODE == RelocInfo::VENEER_POOL);
|
||||
|
@ -91,8 +91,7 @@ Address RelocInfo::target_address() {
|
||||
|
||||
Address RelocInfo::target_address_address() {
|
||||
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
|
||||
IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
|
||||
IsOffHeapTarget(rmode_));
|
||||
rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE);
|
||||
|
||||
if (FLAG_enable_embedded_constant_pool &&
|
||||
Assembler::IsConstantPoolLoadStart(pc_)) {
|
||||
@ -207,11 +206,6 @@ void RelocInfo::set_target_runtime_entry(Address target,
|
||||
set_target_address(target, write_barrier_mode, icache_flush_mode);
|
||||
}
|
||||
|
||||
Address RelocInfo::target_off_heap_target() {
|
||||
DCHECK(IsOffHeapTarget(rmode_));
|
||||
return Assembler::target_address_at(pc_, constant_pool_);
|
||||
}
|
||||
|
||||
void RelocInfo::WipeOut() {
|
||||
DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
|
||||
IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
|
||||
@ -243,8 +237,6 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
|
||||
visitor->VisitInternalReference(host(), this);
|
||||
} else if (IsRuntimeEntry(mode)) {
|
||||
visitor->VisitRuntimeEntry(host(), this);
|
||||
} else if (RelocInfo::IsOffHeapTarget(mode)) {
|
||||
visitor->VisitOffHeapTarget(host(), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1617,7 +1617,7 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
|
||||
|
||||
void MacroAssembler::JumpToInstructionStream(Address entry) {
|
||||
mov(kOffHeapTrampolineRegister,
|
||||
Operand(reinterpret_cast<intptr_t>(entry), RelocInfo::OFF_HEAP_TARGET));
|
||||
Operand(reinterpret_cast<intptr_t>(entry), RelocInfo::NONE));
|
||||
Jump(kOffHeapTrampolineRegister);
|
||||
}
|
||||
|
||||
|
@ -98,8 +98,7 @@ Address RelocInfo::target_address() {
|
||||
|
||||
Address RelocInfo::target_address_address() {
|
||||
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
|
||||
IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
|
||||
IsOffHeapTarget(rmode_));
|
||||
rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE);
|
||||
|
||||
// Read the address of the word containing the target_address in an
|
||||
// instruction stream.
|
||||
@ -180,11 +179,6 @@ Address RelocInfo::target_runtime_entry(Assembler* origin) {
|
||||
return target_address();
|
||||
}
|
||||
|
||||
Address RelocInfo::target_off_heap_target() {
|
||||
DCHECK(IsOffHeapTarget(rmode_));
|
||||
return Assembler::target_address_at(pc_, constant_pool_);
|
||||
}
|
||||
|
||||
void RelocInfo::set_target_runtime_entry(Address target,
|
||||
WriteBarrierMode write_barrier_mode,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
@ -223,8 +217,6 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
|
||||
visitor->VisitInternalReference(host(), this);
|
||||
} else if (IsRuntimeEntry(mode)) {
|
||||
visitor->VisitRuntimeEntry(host(), this);
|
||||
} else if (RelocInfo::IsOffHeapTarget(mode)) {
|
||||
visitor->VisitOffHeapTarget(host(), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1524,8 +1524,7 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
|
||||
}
|
||||
|
||||
void MacroAssembler::JumpToInstructionStream(Address entry) {
|
||||
mov(kOffHeapTrampolineRegister,
|
||||
Operand(reinterpret_cast<intptr_t>(entry), RelocInfo::OFF_HEAP_TARGET));
|
||||
mov(kOffHeapTrampolineRegister, Operand(reinterpret_cast<intptr_t>(entry)));
|
||||
Jump(kOffHeapTrampolineRegister);
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "src/objects/string.h"
|
||||
#include "src/snapshot/builtin-deserializer-allocator.h"
|
||||
#include "src/snapshot/natives.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -492,28 +491,6 @@ bool Deserializer<AllocatorT>::ReadData(Object** current, Object** limit,
|
||||
break;
|
||||
}
|
||||
|
||||
case kOffHeapTarget: {
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
int skip = source_.GetInt();
|
||||
int builtin_index = source_.GetInt();
|
||||
DCHECK(Builtins::IsBuiltinId(builtin_index));
|
||||
|
||||
current = reinterpret_cast<Object**>(
|
||||
reinterpret_cast<Address>(current) + skip);
|
||||
|
||||
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
|
||||
isolate->embedded_blob_size());
|
||||
const uint8_t* address = d.InstructionStartOfBuiltin(builtin_index);
|
||||
Object* o = reinterpret_cast<Object*>(const_cast<uint8_t*>(address));
|
||||
UnalignedCopy(current, &o);
|
||||
|
||||
current++;
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case kNop:
|
||||
break;
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "src/snapshot/snapshot.h"
|
||||
#include "src/snapshot/startup-serializer.h"
|
||||
|
||||
namespace {
|
||||
class SnapshotWriter {
|
||||
public:
|
||||
SnapshotWriter()
|
||||
@ -306,56 +305,6 @@ v8::StartupData CreateSnapshotDataBlob(v8::SnapshotCreator* snapshot_creator,
|
||||
return result;
|
||||
}
|
||||
|
||||
v8::StartupData WarmUpSnapshotDataBlob(v8::SnapshotCreator* snapshot_creator,
|
||||
const char* warmup_source) {
|
||||
CHECK_NOT_NULL(warmup_source);
|
||||
// Use following steps to create a warmed up snapshot blob from a cold one:
|
||||
// - Create a new isolate from the cold snapshot.
|
||||
// - Create a new context to run the warmup script. This will trigger
|
||||
// compilation of executed functions.
|
||||
// - Create a new context. This context will be unpolluted.
|
||||
// - Serialize the isolate and the second context into a new snapshot blob.
|
||||
v8::StartupData result = {nullptr, 0};
|
||||
v8::base::ElapsedTimer timer;
|
||||
timer.Start();
|
||||
{
|
||||
v8::Isolate* isolate = snapshot_creator->GetIsolate();
|
||||
{
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
if (!RunExtraCode(isolate, context, warmup_source, "<warm-up>")) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
isolate->ContextDisposedNotification(false);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
snapshot_creator->SetDefaultContext(context);
|
||||
}
|
||||
result = snapshot_creator->CreateBlob(
|
||||
v8::SnapshotCreator::FunctionCodeHandling::kKeep);
|
||||
}
|
||||
|
||||
if (i::FLAG_profile_deserialization) {
|
||||
i::PrintF("Warming up snapshot took %0.3f ms\n",
|
||||
timer.Elapsed().InMillisecondsF());
|
||||
}
|
||||
timer.Stop();
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
void WriteEmbeddedFile(v8::SnapshotCreator* creator, SnapshotWriter* writer) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(creator->GetIsolate());
|
||||
isolate->PrepareEmbeddedBlobForSerialization();
|
||||
i::EmbeddedData embedded_blob = i::EmbeddedData::FromBlob(
|
||||
isolate->embedded_blob(), isolate->embedded_blob_size());
|
||||
writer->WriteEmbedded(&embedded_blob);
|
||||
}
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Make mksnapshot runs predictable to create reproducible snapshots.
|
||||
i::FLAG_predictable = true;
|
||||
@ -384,33 +333,31 @@ int main(int argc, char** argv) {
|
||||
if (i::FLAG_embedded_src) writer.SetEmbeddedFile(i::FLAG_embedded_src);
|
||||
#endif
|
||||
|
||||
std::unique_ptr<char> embed_script(
|
||||
GetExtraCode(argc >= 2 ? argv[1] : nullptr, "embedding"));
|
||||
std::unique_ptr<char> warmup_script(
|
||||
GetExtraCode(argc >= 3 ? argv[2] : nullptr, "warm up"));
|
||||
|
||||
v8::StartupData blob;
|
||||
{
|
||||
char* embed_script =
|
||||
GetExtraCode(argc >= 2 ? argv[1] : nullptr, "embedding");
|
||||
v8::SnapshotCreator snapshot_creator;
|
||||
blob = CreateSnapshotDataBlob(&snapshot_creator, embed_script);
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
// This process is a bit tricky since we might go on to make a second
|
||||
// snapshot if a warmup script is passed. In that case, create the first
|
||||
// snapshot without off-heap trampolines and only move code off-heap for
|
||||
// the warmed-up snapshot.
|
||||
if (!warmup_script) WriteEmbeddedFile(&snapshot_creator, &writer);
|
||||
i::Isolate* isolate =
|
||||
reinterpret_cast<i::Isolate*>(snapshot_creator.GetIsolate());
|
||||
i::EmbeddedData embedded_blob = i::Snapshot::CreateEmbeddedBlob(isolate);
|
||||
writer.WriteEmbedded(&embedded_blob);
|
||||
delete[] embedded_blob.data();
|
||||
#endif
|
||||
blob = CreateSnapshotDataBlob(&snapshot_creator, embed_script.get());
|
||||
|
||||
delete[] embed_script;
|
||||
}
|
||||
|
||||
char* warmup_script =
|
||||
GetExtraCode(argc >= 3 ? argv[2] : nullptr, "warm up");
|
||||
if (warmup_script) {
|
||||
CHECK(blob.raw_size > 0 && blob.data != nullptr);
|
||||
v8::StartupData cold = blob;
|
||||
v8::SnapshotCreator snapshot_creator(nullptr, &cold);
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
WriteEmbeddedFile(&snapshot_creator, &writer);
|
||||
#endif
|
||||
blob = WarmUpSnapshotDataBlob(&snapshot_creator, warmup_script.get());
|
||||
blob = v8::V8::WarmUpSnapshotDataBlob(cold, warmup_script);
|
||||
delete[] cold.data;
|
||||
delete[] warmup_script;
|
||||
}
|
||||
|
||||
CHECK(blob.data);
|
||||
|
@ -132,6 +132,7 @@ class SerializerDeserializer : public RootVisitor {
|
||||
V(0x7c) \
|
||||
V(0x7d) \
|
||||
V(0x7e) \
|
||||
V(0x7f) \
|
||||
V(0xf0) \
|
||||
V(0xf1) \
|
||||
V(0xf2) \
|
||||
@ -239,9 +240,6 @@ class SerializerDeserializer : public RootVisitor {
|
||||
// Used to encode external referenced provided through the API.
|
||||
static const int kApiReference = 0x37;
|
||||
|
||||
// Encodes an off-heap instruction stream target.
|
||||
static const int kOffHeapTarget = 0x7f;
|
||||
|
||||
// 8 hot (recently seen or back-referenced) objects with optional skip.
|
||||
static const int kNumberOfHotObjects = 8;
|
||||
STATIC_ASSERT(kNumberOfHotObjects == HotObjectsList::kSize);
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "src/objects/map.h"
|
||||
#include "src/snapshot/builtin-serializer-allocator.h"
|
||||
#include "src/snapshot/natives.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -831,29 +830,6 @@ void Serializer<AllocatorT>::ObjectSerializer::VisitRuntimeEntry(
|
||||
bytes_processed_so_far_ += rinfo->target_address_size();
|
||||
}
|
||||
|
||||
template <class AllocatorT>
|
||||
void Serializer<AllocatorT>::ObjectSerializer::VisitOffHeapTarget(
|
||||
Code* host, RelocInfo* rinfo) {
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
{
|
||||
STATIC_ASSERT(EmbeddedData::kTableSize == Builtins::builtin_count);
|
||||
CHECK(Builtins::IsOffHeapBuiltin(host));
|
||||
Address addr = rinfo->target_off_heap_target();
|
||||
CHECK_NOT_NULL(addr);
|
||||
CHECK_NOT_NULL(
|
||||
InstructionStream::TryLookupCode(serializer_->isolate(), addr));
|
||||
}
|
||||
|
||||
int skip = SkipTo(rinfo->target_address_address());
|
||||
sink_->Put(kOffHeapTarget, "OffHeapTarget");
|
||||
sink_->PutInt(skip, "SkipB4OffHeapTarget");
|
||||
sink_->PutInt(host->builtin_index(), "builtin index");
|
||||
bytes_processed_so_far_ += kPointerSize;
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class AllocatorT>
|
||||
void Serializer<AllocatorT>::ObjectSerializer::VisitCodeTarget(
|
||||
Code* host, RelocInfo* rinfo) {
|
||||
|
@ -305,7 +305,6 @@ class Serializer<AllocatorT>::ObjectSerializer : public ObjectVisitor {
|
||||
void VisitInternalReference(Code* host, RelocInfo* rinfo) override;
|
||||
void VisitCodeTarget(Code* host, RelocInfo* target) override;
|
||||
void VisitRuntimeEntry(Code* host, RelocInfo* reloc) override;
|
||||
void VisitOffHeapTarget(Code* host, RelocInfo* target) override;
|
||||
|
||||
private:
|
||||
void SerializePrologue(AllocationSpace space, int size, Map* map);
|
||||
|
@ -399,8 +399,6 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
|
||||
}
|
||||
|
||||
EmbeddedData EmbeddedData::FromBlob(const uint8_t* data, uint32_t size) {
|
||||
DCHECK_NOT_NULL(data);
|
||||
DCHECK_LT(0, size);
|
||||
return {data, size};
|
||||
}
|
||||
|
||||
@ -418,6 +416,12 @@ uint32_t EmbeddedData::InstructionSizeOfBuiltin(int i) const {
|
||||
const uint32_t* lengths = Lengths();
|
||||
return lengths[i];
|
||||
}
|
||||
|
||||
// static
|
||||
EmbeddedData Snapshot::CreateEmbeddedBlob(Isolate* isolate) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
return EmbeddedData::FromIsolate(isolate);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t Snapshot::ExtractNumContexts(const v8::StartupData* data) {
|
||||
|
@ -177,6 +177,10 @@ class Snapshot : public AllStatic {
|
||||
const std::vector<SnapshotData*>& context_snapshots,
|
||||
bool can_be_rehashed);
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
static EmbeddedData CreateEmbeddedBlob(Isolate* isolate);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool SnapshotIsValid(const v8::StartupData* snapshot_blob);
|
||||
#endif // DEBUG
|
||||
|
@ -119,9 +119,6 @@ class ObjectVisitor BASE_EMBEDDED {
|
||||
|
||||
// Visits an (encoded) internal reference.
|
||||
virtual void VisitInternalReference(Code* host, RelocInfo* rinfo) {}
|
||||
|
||||
// Visits an off-heap target in the instruction stream.
|
||||
virtual void VisitOffHeapTarget(Code* host, RelocInfo* rinfo) {}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -303,8 +303,7 @@ Address RelocInfo::target_address() {
|
||||
|
||||
Address RelocInfo::target_address_address() {
|
||||
DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
|
||||
IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
|
||||
IsOffHeapTarget(rmode_));
|
||||
rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE);
|
||||
return reinterpret_cast<Address>(pc_);
|
||||
}
|
||||
|
||||
@ -384,11 +383,6 @@ void RelocInfo::set_target_runtime_entry(Address target,
|
||||
}
|
||||
}
|
||||
|
||||
Address RelocInfo::target_off_heap_target() {
|
||||
DCHECK(IsOffHeapTarget(rmode_));
|
||||
return Memory::Address_at(pc_);
|
||||
}
|
||||
|
||||
void RelocInfo::WipeOut() {
|
||||
if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
|
||||
IsInternalReference(rmode_)) {
|
||||
@ -416,8 +410,6 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
|
||||
visitor->VisitInternalReference(host(), this);
|
||||
} else if (RelocInfo::IsRuntimeEntry(mode)) {
|
||||
visitor->VisitRuntimeEntry(host(), this);
|
||||
} else if (RelocInfo::IsOffHeapTarget(mode)) {
|
||||
visitor->VisitOffHeapTarget(host(), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1367,7 +1367,7 @@ void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
|
||||
}
|
||||
|
||||
void MacroAssembler::JumpToInstructionStream(Address entry) {
|
||||
Move(kOffHeapTrampolineRegister, entry, RelocInfo::OFF_HEAP_TARGET);
|
||||
Move(kOffHeapTrampolineRegister, entry, RelocInfo::NONE);
|
||||
jmp(kOffHeapTrampolineRegister);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,6 @@ UNINITIALIZED_TEST(VerifyBuiltinsIsolateIndependence) {
|
||||
all_real_modes_mask & ~RelocInfo::ModeMask(RelocInfo::COMMENT) &
|
||||
~RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) &
|
||||
~RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) &
|
||||
~RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) &
|
||||
~RelocInfo::ModeMask(RelocInfo::CONST_POOL) &
|
||||
~RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
|
||||
STATIC_ASSERT(RelocInfo::LAST_REAL_RELOC_MODE == RelocInfo::VENEER_POOL);
|
||||
|
@ -3324,5 +3324,26 @@ TEST(SerializationMemoryStats) {
|
||||
delete[] blob.data;
|
||||
}
|
||||
|
||||
TEST(BuiltinsHaveBuiltinIdForLazyDeserialization) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
i::HandleScope scope(isolate);
|
||||
|
||||
CHECK(Builtins::IsLazy(Builtins::kRegExpPrototypeExec));
|
||||
CHECK_EQ(Builtins::kRegExpPrototypeExec,
|
||||
isolate->regexp_exec_function()
|
||||
->shared()
|
||||
->lazy_deserialization_builtin_id());
|
||||
CHECK(Builtins::IsLazy(Builtins::kAsyncIteratorValueUnwrap));
|
||||
CHECK_EQ(Builtins::kAsyncIteratorValueUnwrap,
|
||||
isolate->async_iterator_value_unwrap_shared_fun()
|
||||
->lazy_deserialization_builtin_id());
|
||||
|
||||
CHECK(!Builtins::IsLazy(Builtins::kIllegal));
|
||||
CHECK(!isolate->opaque_reference_function()
|
||||
->shared()
|
||||
->HasLazyDeserializationBuiltinId());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user