Commit f86365dc authored by jgruber's avatar jgruber Committed by Commit Bot

[builtins] Properly handle cctest heap creation in embedded builds

Some cctests force fresh creation of heap constants, even though the
cctest binary itself is an embedded snapshot build (i.e.: a snapshot
blob exists, and a binary-embedded blob exists). This breaks a few
assumptions, for example that off-heap builtins have a single,
canonical off-heap code range.

Unfortunately this isn't that easy to fix. I see a few alternatives:

1. In builtins setup, if an embedded blob exists, regenerate the
builtins for their metadata (things like the safepoint table offset),
and then replace them by off-heap trampolines.

2. As above, but deserialize the trampolines from the snapshot blob.

3. As above, but pack required metadata into the embedded blob and
create trampolines from there.

4. Act as if the embedded blob does not exist.

Alternative 1 does not work because the generated code can be slightly
different at at runtime vs. mksnapshot-time. Alternative 2 is out
because we do not have access to the snapshot blob in TestIsolate
setup. Alternative 3 is probably the preferred option but would be a
more involved change.

This CL takes path 4. It's not an optimal solution, but it can be
replace by alternative 3 later.

TBR=ulan@chromium.org

Bug: v8:7718, v8:7751
Change-Id: I36c024cb0179615011c886ed3978bc95f0d197ac
Reviewed-on: https://chromium-review.googlesource.com/1098924Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53886}
parent 007e183e
...@@ -200,8 +200,10 @@ bool Builtins::IsBuiltinHandle(Handle<HeapObject> maybe_code, ...@@ -200,8 +200,10 @@ bool Builtins::IsBuiltinHandle(Handle<HeapObject> maybe_code,
// static // static
bool Builtins::IsEmbeddedBuiltin(const Code* code) { bool Builtins::IsEmbeddedBuiltin(const Code* code) {
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
return Builtins::IsBuiltinId(code->builtin_index()) && const int builtin_index = code->builtin_index();
Builtins::IsIsolateIndependent(code->builtin_index()); return Isolate::CurrentEmbeddedBlob() != nullptr &&
Builtins::IsBuiltinId(builtin_index) &&
Builtins::IsIsolateIndependent(builtin_index);
#else #else
return false; return false;
#endif #endif
......
...@@ -152,12 +152,14 @@ Code* BuildWithCodeStubAssemblerCS(Isolate* isolate, int32_t builtin_index, ...@@ -152,12 +152,14 @@ Code* BuildWithCodeStubAssemblerCS(Isolate* isolate, int32_t builtin_index,
} }
} // anonymous namespace } // anonymous namespace
// static
void SetupIsolateDelegate::AddBuiltin(Builtins* builtins, int index, void SetupIsolateDelegate::AddBuiltin(Builtins* builtins, int index,
Code* code) { Code* code) {
DCHECK_EQ(index, code->builtin_index()); DCHECK_EQ(index, code->builtin_index());
builtins->set_builtin(index, code); builtins->set_builtin(index, code);
} }
// static
void SetupIsolateDelegate::PopulateWithPlaceholders(Isolate* isolate) { void SetupIsolateDelegate::PopulateWithPlaceholders(Isolate* isolate) {
// Fill the builtins list with placeholders. References to these placeholder // Fill the builtins list with placeholders. References to these placeholder
// builtins are eventually replaced by the actual builtins. This is to // builtins are eventually replaced by the actual builtins. This is to
...@@ -170,6 +172,7 @@ void SetupIsolateDelegate::PopulateWithPlaceholders(Isolate* isolate) { ...@@ -170,6 +172,7 @@ void SetupIsolateDelegate::PopulateWithPlaceholders(Isolate* isolate) {
} }
} }
// static
void SetupIsolateDelegate::ReplacePlaceholders(Isolate* isolate) { void SetupIsolateDelegate::ReplacePlaceholders(Isolate* isolate) {
// Replace references from all code objects to placeholders. // Replace references from all code objects to placeholders.
Builtins* builtins = isolate->builtins(); Builtins* builtins = isolate->builtins();
...@@ -209,6 +212,7 @@ void SetupIsolateDelegate::ReplacePlaceholders(Isolate* isolate) { ...@@ -209,6 +212,7 @@ void SetupIsolateDelegate::ReplacePlaceholders(Isolate* isolate) {
} }
} }
// static
void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) { void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) {
Builtins* builtins = isolate->builtins(); Builtins* builtins = isolate->builtins();
DCHECK(!builtins->initialized_); DCHECK(!builtins->initialized_);
......
...@@ -134,7 +134,8 @@ static void PrintRelocInfo(StringBuilder* out, Isolate* isolate, ...@@ -134,7 +134,8 @@ static void PrintRelocInfo(StringBuilder* out, Isolate* isolate,
out->AddFormatted(" ;; external reference (%s)", reference_name); out->AddFormatted(" ;; external reference (%s)", reference_name);
} else if (RelocInfo::IsCodeTarget(rmode)) { } else if (RelocInfo::IsCodeTarget(rmode)) {
out->AddFormatted(" ;; code:"); out->AddFormatted(" ;; code:");
Code* code = Code::GetCodeFromTargetAddress(relocinfo->target_address()); Code* code = isolate->heap()->GcSafeFindCodeForInnerPointer(
relocinfo->target_address());
Code::Kind kind = code->kind(); Code::Kind kind = code->kind();
if (kind == Code::STUB) { if (kind == Code::STUB) {
// Get the STUB key and extract major and minor key. // Get the STUB key and extract major and minor key.
......
...@@ -2583,10 +2583,10 @@ Handle<Code> Factory::NewCodeForDeserialization(uint32_t size) { ...@@ -2583,10 +2583,10 @@ Handle<Code> Factory::NewCodeForDeserialization(uint32_t size) {
#ifdef V8_EMBEDDED_BUILTINS #ifdef V8_EMBEDDED_BUILTINS
Handle<Code> Factory::NewOffHeapTrampolineFor(Handle<Code> code, Handle<Code> Factory::NewOffHeapTrampolineFor(Handle<Code> code,
Address off_heap_entry) { Address off_heap_entry) {
DCHECK(isolate()->serializer_enabled()); CHECK(isolate()->serializer_enabled());
DCHECK_NOT_NULL(isolate()->embedded_blob()); CHECK_NOT_NULL(isolate()->embedded_blob());
DCHECK_NE(0, isolate()->embedded_blob_size()); CHECK_NE(0, isolate()->embedded_blob_size());
DCHECK(Builtins::IsEmbeddedBuiltin(*code)); CHECK(Builtins::IsEmbeddedBuiltin(*code));
Handle<Code> result = Handle<Code> result =
Builtins::GenerateOffHeapTrampolineFor(isolate(), off_heap_entry); Builtins::GenerateOffHeapTrampolineFor(isolate(), off_heap_entry);
......
...@@ -2577,6 +2577,18 @@ Isolate::Isolate() ...@@ -2577,6 +2577,18 @@ Isolate::Isolate()
tracing_cpu_profiler_.reset(new TracingCpuProfilerImpl(this)); tracing_cpu_profiler_.reset(new TracingCpuProfilerImpl(this));
init_memcopy_functions(this); init_memcopy_functions(this);
#ifdef V8_EMBEDDED_BUILTINS
#ifdef V8_MULTI_SNAPSHOTS
if (FLAG_untrusted_code_mitigations) {
SetEmbeddedBlob(DefaultEmbeddedBlob(), DefaultEmbeddedBlobSize());
} else {
SetEmbeddedBlob(TrustedEmbeddedBlob(), TrustedEmbeddedBlobSize());
}
#else
SetEmbeddedBlob(DefaultEmbeddedBlob(), DefaultEmbeddedBlobSize());
#endif
#endif // V8_EMBEDDED_BUILTINS
} }
...@@ -2963,18 +2975,6 @@ bool Isolate::Init(StartupDeserializer* des) { ...@@ -2963,18 +2975,6 @@ bool Isolate::Init(StartupDeserializer* des) {
compiler_dispatcher_ = compiler_dispatcher_ =
new CompilerDispatcher(this, V8::GetCurrentPlatform(), FLAG_stack_size); new CompilerDispatcher(this, V8::GetCurrentPlatform(), FLAG_stack_size);
#ifdef V8_EMBEDDED_BUILTINS
#ifdef V8_MULTI_SNAPSHOTS
if (FLAG_untrusted_code_mitigations) {
SetEmbeddedBlob(DefaultEmbeddedBlob(), DefaultEmbeddedBlobSize());
} else {
SetEmbeddedBlob(TrustedEmbeddedBlob(), TrustedEmbeddedBlobSize());
}
#else
SetEmbeddedBlob(DefaultEmbeddedBlob(), DefaultEmbeddedBlobSize());
#endif
#endif
// Enable logging before setting up the heap // Enable logging before setting up the heap
logger_->SetUp(this); logger_->SetUp(this);
......
...@@ -530,6 +530,14 @@ Address Code::constant_pool() const { ...@@ -530,6 +530,14 @@ Address Code::constant_pool() const {
} }
Code* Code::GetCodeFromTargetAddress(Address address) { Code* Code::GetCodeFromTargetAddress(Address address) {
#ifdef V8_EMBEDDED_BUILTINS
// TODO(jgruber,v8:6666): Support embedded builtins here. We'd need to pass in
// the current isolate.
Address start = reinterpret_cast<Address>(Isolate::CurrentEmbeddedBlob());
Address end = start + Isolate::CurrentEmbeddedBlobSize();
CHECK(address < start || address >= end);
#endif // V8_EMBEDDED_BUILTINS
HeapObject* code = HeapObject::FromAddress(address - Code::kHeaderSize); HeapObject* code = HeapObject::FromAddress(address - Code::kHeaderSize);
// GetCodeFromTargetAddress might be called when marking objects during mark // GetCodeFromTargetAddress might be called when marking objects during mark
// sweep. reinterpret_cast is therefore used instead of the more appropriate // sweep. reinterpret_cast is therefore used instead of the more appropriate
......
...@@ -71,6 +71,7 @@ SafepointEntry SafepointTable::FindEntry(Address pc) const { ...@@ -71,6 +71,7 @@ SafepointEntry SafepointTable::FindEntry(Address pc) const {
// We use kMaxUInt32 as sentinel value, so check that we don't hit that. // We use kMaxUInt32 as sentinel value, so check that we don't hit that.
DCHECK_NE(kMaxUInt32, pc_offset); DCHECK_NE(kMaxUInt32, pc_offset);
unsigned len = length(); unsigned len = length();
CHECK_GT(len, 0);
// If pc == kMaxUInt32, then this entry covers all call sites in the function. // If pc == kMaxUInt32, then this entry covers all call sites in the function.
if (len == 1 && GetPcOffset(0) == kMaxUInt32) return GetEntry(0); if (len == 1 && GetPcOffset(0) == kMaxUInt32) return GetEntry(0);
for (unsigned i = 0; i < len; i++) { for (unsigned i = 0; i < len; i++) {
......
...@@ -134,13 +134,6 @@ ...@@ -134,13 +134,6 @@
'test-strings/StringOOM*': [PASS, ['mode == debug', SKIP]], 'test-strings/StringOOM*': [PASS, ['mode == debug', SKIP]],
'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]],
# Until https://crbug.com/v8/7718 is fixed.
'test-serialize/PartialSerializerCustomContext': [SKIP],
'test-serialize/StartupSerializerOnce': [SKIP],
'test-serialize/StartupSerializerOnceRunScript': [SKIP],
'test-serialize/StartupSerializerTwice': [SKIP],
'test-serialize/StartupSerializerTwiceRunScript': [SKIP],
}], # ALWAYS }], # ALWAYS
############################################################################## ##############################################################################
......
...@@ -75,9 +75,10 @@ void DisableAlwaysOpt() { ...@@ -75,9 +75,10 @@ void DisableAlwaysOpt() {
// TestIsolate is used for testing isolate serialization. // TestIsolate is used for testing isolate serialization.
class TestIsolate : public Isolate { class TestIsolate : public Isolate {
public: public:
static v8::Isolate* NewInitialized(bool enable_serializer) { static v8::Isolate* NewInitialized() {
i::Isolate* isolate = new TestIsolate(enable_serializer); const bool kEnableSerializer = true;
isolate->setup_delegate_ = new SetupIsolateDelegateForTests(true); const bool kGenerateHeap = true;
i::Isolate* isolate = new TestIsolate(kEnableSerializer, kGenerateHeap);
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
v8::Isolate::Scope isolate_scope(v8_isolate); v8::Isolate::Scope isolate_scope(v8_isolate);
isolate->Init(nullptr); isolate->Init(nullptr);
...@@ -88,23 +89,37 @@ class TestIsolate : public Isolate { ...@@ -88,23 +89,37 @@ class TestIsolate : public Isolate {
// Allows flexibility to bootstrap with or without snapshot even when // Allows flexibility to bootstrap with or without snapshot even when
// the production Isolate class has one or the other behavior baked in. // the production Isolate class has one or the other behavior baked in.
static v8::Isolate* New(const v8::Isolate::CreateParams& params) { static v8::Isolate* New(const v8::Isolate::CreateParams& params) {
i::Isolate* isolate = new TestIsolate(false); const bool kEnableSerializer = false;
bool create_heap_objects = params.snapshot_blob == nullptr; const bool kGenerateHeap = params.snapshot_blob == nullptr;
isolate->setup_delegate_ = i::Isolate* isolate = new TestIsolate(kEnableSerializer, kGenerateHeap);
new SetupIsolateDelegateForTests(create_heap_objects);
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
v8::Isolate::Initialize(v8_isolate, params); v8::Isolate::Initialize(v8_isolate, params);
return v8_isolate; return v8_isolate;
} }
explicit TestIsolate(bool with_serializer) : Isolate() { explicit TestIsolate(bool with_serializer, bool generate_heap) : Isolate() {
if (with_serializer) enable_serializer(); if (with_serializer) enable_serializer();
set_array_buffer_allocator(CcTest::array_buffer_allocator()); set_array_buffer_allocator(CcTest::array_buffer_allocator());
setup_delegate_ = new SetupIsolateDelegateForTests(generate_heap);
#ifdef V8_EMBEDDED_BUILTINS
if (generate_heap || clear_embedded_blob_) {
// We're generating the heap, including new builtins. Act as if we don't
// have an embedded blob.
clear_embedded_blob_ = true;
SetEmbeddedBlob(nullptr, 0);
} }
void SetDeserializeFromSnapshot() { #endif // V8_EMBEDDED_BUILTINS
setup_delegate_ = new SetupIsolateDelegateForTests(false);
} }
private:
// A sticky flag that ensures the embedded blob is remains cleared after it
// has been cleared once. E.g.: after creating & serializing a complete heap
// snapshot, future isolates also expect the embedded blob to be cleared.
static bool clear_embedded_blob_;
}; };
bool TestIsolate::clear_embedded_blob_ = false;
static Vector<const byte> WritePayload(const Vector<const byte>& payload) { static Vector<const byte> WritePayload(const Vector<const byte>& payload) {
int length = payload.length(); int length = payload.length();
byte* blob = NewArray<byte>(length); byte* blob = NewArray<byte>(length);
...@@ -256,10 +271,11 @@ v8::Isolate* InitializeFromBlob(StartupBlobs& blobs) { ...@@ -256,10 +271,11 @@ v8::Isolate* InitializeFromBlob(StartupBlobs& blobs) {
SnapshotData startup_snapshot(blobs.startup); SnapshotData startup_snapshot(blobs.startup);
BuiltinSnapshotData builtin_snapshot(blobs.builtin); BuiltinSnapshotData builtin_snapshot(blobs.builtin);
StartupDeserializer deserializer(&startup_snapshot, &builtin_snapshot); StartupDeserializer deserializer(&startup_snapshot, &builtin_snapshot);
TestIsolate* isolate = new TestIsolate(false); const bool kEnableSerializer = false;
const bool kGenerateHeap = false;
TestIsolate* isolate = new TestIsolate(kEnableSerializer, kGenerateHeap);
v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
v8::Isolate::Scope isolate_scope(v8_isolate); v8::Isolate::Scope isolate_scope(v8_isolate);
isolate->SetDeserializeFromSnapshot();
isolate->Init(&deserializer); isolate->Init(&deserializer);
} }
return v8_isolate; return v8_isolate;
...@@ -286,7 +302,7 @@ static void SanityCheck(v8::Isolate* v8_isolate) { ...@@ -286,7 +302,7 @@ static void SanityCheck(v8::Isolate* v8_isolate) {
UNINITIALIZED_TEST(StartupSerializerOnce) { UNINITIALIZED_TEST(StartupSerializerOnce) {
DisableLazyDeserialization(); DisableLazyDeserialization();
DisableAlwaysOpt(); DisableAlwaysOpt();
v8::Isolate* isolate = TestIsolate::NewInitialized(true); v8::Isolate* isolate = TestIsolate::NewInitialized();
StartupBlobs blobs = Serialize(isolate); StartupBlobs blobs = Serialize(isolate);
isolate->Dispose(); isolate->Dispose();
isolate = Deserialize(blobs); isolate = Deserialize(blobs);
...@@ -354,7 +370,7 @@ UNINITIALIZED_TEST(StartupSerializerRootMapDependencies) { ...@@ -354,7 +370,7 @@ UNINITIALIZED_TEST(StartupSerializerRootMapDependencies) {
UNINITIALIZED_TEST(StartupSerializerTwice) { UNINITIALIZED_TEST(StartupSerializerTwice) {
DisableLazyDeserialization(); DisableLazyDeserialization();
DisableAlwaysOpt(); DisableAlwaysOpt();
v8::Isolate* isolate = TestIsolate::NewInitialized(true); v8::Isolate* isolate = TestIsolate::NewInitialized();
StartupBlobs blobs1 = Serialize(isolate); StartupBlobs blobs1 = Serialize(isolate);
StartupBlobs blobs2 = Serialize(isolate); StartupBlobs blobs2 = Serialize(isolate);
isolate->Dispose(); isolate->Dispose();
...@@ -376,7 +392,7 @@ UNINITIALIZED_TEST(StartupSerializerTwice) { ...@@ -376,7 +392,7 @@ UNINITIALIZED_TEST(StartupSerializerTwice) {
UNINITIALIZED_TEST(StartupSerializerOnceRunScript) { UNINITIALIZED_TEST(StartupSerializerOnceRunScript) {
DisableLazyDeserialization(); DisableLazyDeserialization();
DisableAlwaysOpt(); DisableAlwaysOpt();
v8::Isolate* isolate = TestIsolate::NewInitialized(true); v8::Isolate* isolate = TestIsolate::NewInitialized();
StartupBlobs blobs = Serialize(isolate); StartupBlobs blobs = Serialize(isolate);
isolate->Dispose(); isolate->Dispose();
isolate = Deserialize(blobs); isolate = Deserialize(blobs);
...@@ -402,7 +418,7 @@ UNINITIALIZED_TEST(StartupSerializerOnceRunScript) { ...@@ -402,7 +418,7 @@ UNINITIALIZED_TEST(StartupSerializerOnceRunScript) {
UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) { UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) {
DisableLazyDeserialization(); DisableLazyDeserialization();
DisableAlwaysOpt(); DisableAlwaysOpt();
v8::Isolate* isolate = TestIsolate::NewInitialized(true); v8::Isolate* isolate = TestIsolate::NewInitialized();
StartupBlobs blobs1 = Serialize(isolate); StartupBlobs blobs1 = Serialize(isolate);
StartupBlobs blobs2 = Serialize(isolate); StartupBlobs blobs2 = Serialize(isolate);
isolate->Dispose(); isolate->Dispose();
...@@ -429,7 +445,7 @@ UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) { ...@@ -429,7 +445,7 @@ UNINITIALIZED_TEST(StartupSerializerTwiceRunScript) {
static void PartiallySerializeContext(Vector<const byte>* startup_blob_out, static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
Vector<const byte>* builtin_blob_out, Vector<const byte>* builtin_blob_out,
Vector<const byte>* partial_blob_out) { Vector<const byte>* partial_blob_out) {
v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); v8::Isolate* v8_isolate = TestIsolate::NewInitialized();
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
Heap* heap = isolate->heap(); Heap* heap = isolate->heap();
{ {
...@@ -533,7 +549,7 @@ UNINITIALIZED_TEST(PartialSerializerContext) { ...@@ -533,7 +549,7 @@ UNINITIALIZED_TEST(PartialSerializerContext) {
static void PartiallySerializeCustomContext( static void PartiallySerializeCustomContext(
Vector<const byte>* startup_blob_out, Vector<const byte>* builtin_blob_out, Vector<const byte>* startup_blob_out, Vector<const byte>* builtin_blob_out,
Vector<const byte>* partial_blob_out) { Vector<const byte>* partial_blob_out) {
v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); v8::Isolate* v8_isolate = TestIsolate::NewInitialized();
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
{ {
v8::Isolate::Scope isolate_scope(v8_isolate); v8::Isolate::Scope isolate_scope(v8_isolate);
......
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