Commit 5025e415 authored by jgruber's avatar jgruber Committed by Commit Bot

Reland "[builtins] Execute binary-embedded builtin code"

This is a reland of 6afd25ff

Original change's description:
> [builtins] Execute binary-embedded builtin code
>
> This CL creates trampolines into binary-embedded builtins on
> isolate-creation, if --stress-off-heap-code is passed.
>
> Note that this still overwrites existing code objects with the
> off-heap trampoline, and that off-heap builtins still exist both in
> the snapshot and the binary. Addressing these points are the next
> steps.
>
> Drive-by-change: More efficient off-heap code lookups now that the
> off-heap memory area has a contiguous and static layout.
>
> Cq-Include-Trybots: luci.v8.try:v8_linux64_fyi_rel_ng
> Bug: v8:6666
> Change-Id: I7e7ef0aa2cd7b8184ae3a13fa02bdcbb4f2c9f86
> Reviewed-on: https://chromium-review.googlesource.com/947969
> Commit-Queue: Jakob Gruber <jgruber@chromium.org>
> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51809}

TBR=mstarzinger@chromium.org

Bug: v8:6666
Change-Id: I4e0684de90733e5f18f6f0ea4832e327d03dfbf7
Cq-Include-Trybots: luci.v8.try:v8_linux64_fyi_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/955595Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51835}
parent b3f4a377
...@@ -8,58 +8,57 @@ ...@@ -8,58 +8,57 @@
#include "src/heap/heap.h" #include "src/heap/heap.h"
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects/code-inl.h" #include "src/objects/code-inl.h"
#include "src/snapshot/snapshot.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
InstructionStream::InstructionStream(Code* code) InstructionStream::InstructionStream(uint8_t* bytes, size_t byte_length,
: builtin_index_(code->builtin_index()) { int builtin_index)
DCHECK(Builtins::IsOffHeapBuiltin(code)); : byte_length_(byte_length), bytes_(bytes), builtin_index_(builtin_index) {
const size_t page_size = AllocatePageSize(); DCHECK(Builtins::IsBuiltinId(builtin_index_));
byte_length_ = DCHECK_NOT_NULL(bytes_);
RoundUp(static_cast<size_t>(code->instruction_size()), page_size);
bytes_ = static_cast<uint8_t*>(AllocatePages(
GetRandomMmapAddr(), byte_length_, page_size, PageAllocator::kReadWrite));
CHECK_NOT_NULL(bytes_);
std::memcpy(bytes_, code->instruction_start(), code->instruction_size());
CHECK(SetPermissions(bytes_, byte_length_, PageAllocator::kReadExecute));
} }
InstructionStream::~InstructionStream() { // static
CHECK(FreePages(bytes_, byte_length_)); bool InstructionStream::PcIsOffHeap(Isolate* isolate, Address pc) {
#ifdef V8_EMBEDDED_BUILTINS
const uint8_t* start = isolate->embedded_blob();
return start <= pc && pc < start + isolate->embedded_blob_size();
#else
return false;
#endif
} }
// static // static
Code* InstructionStream::TryLookupCode(Isolate* isolate, Address address) { Code* InstructionStream::TryLookupCode(Isolate* isolate, Address address) {
#ifdef V8_EMBEDDED_BUILTINS
DCHECK(FLAG_stress_off_heap_code); DCHECK(FLAG_stress_off_heap_code);
// TODO(jgruber,v8:6666): Replace with binary search through range checks
// once off-heap code is mapped into a contiguous memory space. if (!PcIsOffHeap(isolate, address)) return nullptr;
for (const InstructionStream* stream : isolate->off_heap_code_) {
if (stream->Contains(address)) { EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
return isolate->builtins()->builtin(stream->builtin_index()); isolate->embedded_blob_size());
int l = 0, r = Builtins::builtin_count;
while (l < r) {
const int mid = (l + r) / 2;
const uint8_t* start = d.InstructionStartOfBuiltin(mid);
const uint8_t* end = start + d.InstructionSizeOfBuiltin(mid);
if (address < start) {
r = mid;
} else if (address >= end) {
l = mid + 1;
} else {
return isolate->builtins()->builtin(mid);
} }
} }
return nullptr;
}
// static UNREACHABLE();
InstructionStream* InstructionStream::TryLookupInstructionStream( #else
Isolate* isolate, Code* code) {
DCHECK(FLAG_stress_off_heap_code);
// TODO(jgruber,v8:6666): Replace with binary search through range checks
// once off-heap code is mapped into a contiguous memory space.
const int builtin_index = code->builtin_index();
DCHECK(Builtins::IsBuiltinId(builtin_index));
for (InstructionStream* stream : isolate->off_heap_code_) {
if (stream->builtin_index() == builtin_index) return stream;
}
return nullptr; return nullptr;
} #endif
bool InstructionStream::Contains(Address address) const {
return bytes_ <= address && address < bytes_ + byte_length_;
} }
} // namespace internal } // namespace internal
......
...@@ -14,22 +14,18 @@ namespace internal { ...@@ -14,22 +14,18 @@ namespace internal {
class Code; class Code;
class Isolate; class Isolate;
// Wraps an mmap'ed off-heap instruction stream. This class will likely become // Wraps an off-heap instruction stream.
// unneeded once --stress-off-heap-code is removed. // TODO(jgruber,v8:6666): Remove this class.
class InstructionStream final { class InstructionStream final {
public: public:
explicit InstructionStream(Code* code); InstructionStream(uint8_t* bytes, size_t byte_length, int builtin_index);
~InstructionStream();
// Returns true, iff the given pc points into an off-heap instruction stream.
static bool PcIsOffHeap(Isolate* isolate, Address pc);
// Returns the corresponding Code object if it exists, and nullptr otherwise. // Returns the corresponding Code object if it exists, and nullptr otherwise.
static Code* TryLookupCode(Isolate* isolate, Address address); static Code* TryLookupCode(Isolate* isolate, Address address);
// Returns the corresponding stream if it exists, and nullptr otherwise.
static InstructionStream* TryLookupInstructionStream(Isolate* isolate,
Code* code);
bool Contains(Address address) const;
int builtin_index() const { return builtin_index_; } int builtin_index() const { return builtin_index_; }
size_t byte_length() const { return byte_length_; } size_t byte_length() const { return byte_length_; }
uint8_t* bytes() const { return bytes_; } uint8_t* bytes() const { return bytes_; }
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include "src/basic-block-profiler.h" #include "src/basic-block-profiler.h"
#include "src/bootstrapper.h" #include "src/bootstrapper.h"
#include "src/builtins/constants-table-builder.h" #include "src/builtins/constants-table-builder.h"
#include "src/callable.h"
#include "src/cancelable-task.h" #include "src/cancelable-task.h"
#include "src/code-stubs.h" #include "src/code-stubs.h"
#include "src/compilation-cache.h" #include "src/compilation-cache.h"
...@@ -35,7 +34,6 @@ ...@@ -35,7 +34,6 @@
#include "src/frames-inl.h" #include "src/frames-inl.h"
#include "src/ic/stub-cache.h" #include "src/ic/stub-cache.h"
#include "src/instruction-stream.h" #include "src/instruction-stream.h"
#include "src/interface-descriptors.h"
#include "src/interpreter/interpreter.h" #include "src/interpreter/interpreter.h"
#include "src/isolate-inl.h" #include "src/isolate-inl.h"
#include "src/libsampler/sampler.h" #include "src/libsampler/sampler.h"
...@@ -2680,11 +2678,6 @@ void Isolate::Deinit() { ...@@ -2680,11 +2678,6 @@ void Isolate::Deinit() {
root_index_map_ = nullptr; root_index_map_ = nullptr;
ClearSerializerData(); ClearSerializerData();
for (InstructionStream* stream : off_heap_code_) {
delete stream;
}
off_heap_code_.clear();
} }
...@@ -2894,8 +2887,11 @@ void LogInstructionStream(Isolate* isolate, Code* code, ...@@ -2894,8 +2887,11 @@ void LogInstructionStream(Isolate* isolate, Code* code,
} }
} }
void MoveBuiltinsOffHeap(Isolate* isolate) { void CreateOnHeapTrampolines(Isolate* isolate) {
DCHECK(FLAG_stress_off_heap_code); DCHECK(FLAG_stress_off_heap_code);
DCHECK(!isolate->serializer_enabled());
DCHECK_NOT_NULL(isolate->embedded_blob());
HandleScope scope(isolate); HandleScope scope(isolate);
Builtins* builtins = isolate->builtins(); Builtins* builtins = isolate->builtins();
...@@ -2904,14 +2900,26 @@ void MoveBuiltinsOffHeap(Isolate* isolate) { ...@@ -2904,14 +2900,26 @@ void MoveBuiltinsOffHeap(Isolate* isolate) {
// deserialization. // deserialization.
Snapshot::EnsureAllBuiltinsAreDeserialized(isolate); Snapshot::EnsureAllBuiltinsAreDeserialized(isolate);
EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
isolate->embedded_blob_size());
CodeSpaceMemoryModificationScope code_allocation(isolate->heap()); CodeSpaceMemoryModificationScope code_allocation(isolate->heap());
for (int i = 0; i < Builtins::builtin_count; i++) { for (int i = 0; i < Builtins::builtin_count; i++) {
if (!Builtins::IsOffHeapSafe(i)) continue; if (!Builtins::IsOffHeapSafe(i)) continue;
const uint8_t* instruction_start = d.InstructionStartOfBuiltin(i);
size_t instruction_size = d.InstructionSizeOfBuiltin(i);
InstructionStream stream(const_cast<uint8_t*>(instruction_start),
instruction_size, i);
Handle<Code> code(builtins->builtin(i)); Handle<Code> code(builtins->builtin(i));
InstructionStream* stream = new InstructionStream(*code); LogInstructionStream(isolate, *code, &stream);
LogInstructionStream(isolate, *code, stream);
ChangeToOffHeapTrampoline(isolate, code, stream); // TODO(jgruber,v8:6666): Create fresh trampolines instead of rewriting
isolate->PushOffHeapCode(stream); // existing ones. This could happen prior to serialization or
// post-deserialization.
ChangeToOffHeapTrampoline(isolate, code, &stream);
} }
} }
#endif // V8_EMBEDDED_BUILTINS #endif // V8_EMBEDDED_BUILTINS
...@@ -3078,11 +3086,10 @@ bool Isolate::Init(StartupDeserializer* des) { ...@@ -3078,11 +3086,10 @@ bool Isolate::Init(StartupDeserializer* des) {
if (FLAG_print_builtin_size) PrintBuiltinSizes(this); if (FLAG_print_builtin_size) PrintBuiltinSizes(this);
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
if (FLAG_stress_off_heap_code && !serializer_enabled()) { if (FLAG_stress_off_heap_code && !serializer_enabled() &&
// Artificially move code off-heap to help find & verify related code embedded_blob() != nullptr) {
// paths. Lazy deserialization should be off to avoid confusion around // Create the on-heap trampolines that jump into embedded code.
// replacing just the kDeserializeLazy code object. CreateOnHeapTrampolines(this);
MoveBuiltinsOffHeap(this);
} }
#endif #endif
......
...@@ -1246,10 +1246,6 @@ class Isolate { ...@@ -1246,10 +1246,6 @@ class Isolate {
return &partial_snapshot_cache_; return &partial_snapshot_cache_;
} }
void PushOffHeapCode(InstructionStream* stream) {
off_heap_code_.emplace_back(stream);
}
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
BuiltinsConstantsTableBuilder* builtins_constants_table_builder() const { BuiltinsConstantsTableBuilder* builtins_constants_table_builder() const {
return builtins_constants_table_builder_; return builtins_constants_table_builder_;
...@@ -1628,12 +1624,6 @@ class Isolate { ...@@ -1628,12 +1624,6 @@ class Isolate {
std::vector<Object*> partial_snapshot_cache_; std::vector<Object*> partial_snapshot_cache_;
// Stores off-heap instruction streams. Only used if --stress-off-heap-code
// is enabled.
// TODO(jgruber,v8:6666): Remove once isolate-independent builtins are
// implemented. Also remove friend class below.
std::vector<InstructionStream*> off_heap_code_;
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
// Used during builtins compilation to build the builtins constants table, // Used during builtins compilation to build the builtins constants table,
// which is stored on the root list prior to serialization. // which is stored on the root list prior to serialization.
...@@ -1668,7 +1658,6 @@ class Isolate { ...@@ -1668,7 +1658,6 @@ class Isolate {
friend class ExecutionAccess; friend class ExecutionAccess;
friend class HandleScopeImplementer; friend class HandleScopeImplementer;
friend class heap::HeapTester; friend class heap::HeapTester;
friend class InstructionStream;
friend class OptimizingCompileDispatcher; friend class OptimizingCompileDispatcher;
friend class Simulator; friend class Simulator;
friend class StackGuard; friend class StackGuard;
......
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
#include "src/regexp/jsregexp.h" #include "src/regexp/jsregexp.h"
#include "src/safepoint-table.h" #include "src/safepoint-table.h"
#include "src/snapshot/code-serializer.h" #include "src/snapshot/code-serializer.h"
#include "src/snapshot/snapshot.h"
#include "src/source-position-table.h" #include "src/source-position-table.h"
#include "src/string-builder.h" #include "src/string-builder.h"
#include "src/string-search.h" #include "src/string-search.h"
...@@ -13973,23 +13974,29 @@ SafepointEntry Code::GetSafepointEntry(Address pc) { ...@@ -13973,23 +13974,29 @@ SafepointEntry Code::GetSafepointEntry(Address pc) {
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
int Code::OffHeapInstructionSize() { int Code::OffHeapInstructionSize() {
DCHECK(Builtins::IsOffHeapBuiltin(this)); DCHECK(Builtins::IsOffHeapBuiltin(this));
InstructionStream* stream = Isolate* isolate = GetIsolate();
InstructionStream::TryLookupInstructionStream(GetIsolate(), this); EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
return static_cast<int>(stream->byte_length()); isolate->embedded_blob_size());
return d.InstructionSizeOfBuiltin(builtin_index());
} }
Address Code::OffHeapInstructionStart() { Address Code::OffHeapInstructionStart() {
DCHECK(Builtins::IsOffHeapBuiltin(this)); DCHECK(Builtins::IsOffHeapBuiltin(this));
InstructionStream* stream = Isolate* isolate = GetIsolate();
InstructionStream::TryLookupInstructionStream(GetIsolate(), this); EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
return stream->bytes(); isolate->embedded_blob_size());
return reinterpret_cast<Address>(
const_cast<uint8_t*>(d.InstructionStartOfBuiltin(builtin_index())));
} }
Address Code::OffHeapInstructionEnd() { Address Code::OffHeapInstructionEnd() {
DCHECK(Builtins::IsOffHeapBuiltin(this)); DCHECK(Builtins::IsOffHeapBuiltin(this));
InstructionStream* stream = Isolate* isolate = GetIsolate();
InstructionStream::TryLookupInstructionStream(GetIsolate(), this); EmbeddedData d = EmbeddedData::FromBlob(isolate->embedded_blob(),
return stream->bytes() + stream->byte_length(); isolate->embedded_blob_size());
return reinterpret_cast<Address>(
const_cast<uint8_t*>(d.InstructionStartOfBuiltin(builtin_index()) +
d.InstructionSizeOfBuiltin(builtin_index())));
} }
#endif #endif
......
...@@ -124,6 +124,16 @@ ...@@ -124,6 +124,16 @@
'test-serialize/CustomSnapshotDataBlobImmortalImmovableRoots': [PASS, ['mode == debug', SKIP]], 'test-serialize/CustomSnapshotDataBlobImmortalImmovableRoots': [PASS, ['mode == debug', SKIP]],
'test-parsing/ObjectRestNegativeTestSlow': [PASS, ['mode == debug', SKIP]], 'test-parsing/ObjectRestNegativeTestSlow': [PASS, ['mode == debug', SKIP]],
# Temporary for https://crrev.com/c/947969 until https://crrev.com/c/950775
# lands. Tests build a new snapshot, in which the constants list doesn't
# match what's expected by embedded builtins. This will become irrelevant
# once the serialization process changes to pack trampolines into the
# snapshot iff explicitly requested.
'test-serialize/StartupSerializerOnce': [SKIP],
'test-serialize/StartupSerializerTwice': [SKIP],
'test-serialize/StartupSerializerOnceRunScript': [SKIP],
'test-serialize/StartupSerializerTwiceRunScript': [SKIP],
}], # ALWAYS }], # ALWAYS
############################################################################## ##############################################################################
......
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