Undo "Don't include an object header for instructions in the text section."
This undoes most of b2f3e8efe1f32bacad99ddbedbc434a6102d8be2.
This optimization prevents precompiled code from being disabled and re-enabled, because disabling causes the code to lose its only reference to its own instructions. This was okay for precompilated code that ran without a JIT because it is never disabled, but precompiled code that runs in a JIT will become disabled when corresponding optimized code is compiled and re-abled after a deopt.
R=fschneider@google.com
Review URL: https://codereview.chromium.org/1925153003 .
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 3fe6df5..cd7dbde 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -207,6 +207,9 @@
if (vm_isolate_snapshot != NULL) {
NOT_IN_PRODUCT(TimelineDurationScope tds(Timeline::GetVMStream(),
"VMIsolateSnapshot"));
+ if (instructions_snapshot != NULL) {
+ vm_isolate_->SetupInstructionsSnapshotPage(instructions_snapshot);
+ }
if (data_snapshot != NULL) {
vm_isolate_->SetupDataSnapshotPage(data_snapshot);
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index dc52613..44127c5 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -934,6 +934,23 @@
}
+void Isolate::SetupInstructionsSnapshotPage(
+ const uint8_t* instructions_snapshot_buffer) {
+ InstructionsSnapshot snapshot(instructions_snapshot_buffer);
+#if defined(DEBUG)
+ if (FLAG_trace_isolates) {
+ OS::Print("Precompiled instructions are at [0x%" Px ", 0x%" Px ")\n",
+ reinterpret_cast<uword>(snapshot.instructions_start()),
+ reinterpret_cast<uword>(snapshot.instructions_start()) +
+ snapshot.instructions_size());
+ }
+#endif
+ heap_->SetupExternalPage(snapshot.instructions_start(),
+ snapshot.instructions_size(),
+ /* is_executable = */ true);
+}
+
+
void Isolate::SetupDataSnapshotPage(const uint8_t* data_snapshot_buffer) {
DataSnapshot snapshot(data_snapshot_buffer);
#if defined(DEBUG)
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 8061619..c2fc955 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -228,6 +228,8 @@
library_tag_handler_ = value;
}
+ void SetupInstructionsSnapshotPage(
+ const uint8_t* instructions_snapshot_buffer);
void SetupDataSnapshotPage(
const uint8_t* instructions_snapshot_buffer);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 7d8acc3..6f48c92 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -13525,26 +13525,6 @@
}
-uword Code::EntryPoint() const {
- RawObject* instr = instructions();
- if (!instr->IsHeapObject()) {
- return active_entry_point();
- } else {
- return Instructions::EntryPoint(instructions());
- }
-}
-
-
-intptr_t Code::Size() const {
- RawObject* instr = instructions();
- if (!instr->IsHeapObject()) {
- return Smi::Value(raw_ptr()->precompiled_instructions_size_);
- } else {
- return instructions()->ptr()->size_;
- }
-}
-
-
bool Code::HasBreakpoint() const {
if (!FLAG_support_debugger) {
return false;
@@ -13890,13 +13870,10 @@
}
// Hook up Code and Instructions objects.
- code.set_instructions(instrs.raw());
code.SetActiveInstructions(instrs.raw());
+ code.set_instructions(instrs.raw());
code.set_is_alive(true);
- ASSERT(code.EntryPoint() == instrs.EntryPoint());
- ASSERT(code.Size() == instrs.size());
-
// Set object pool in Instructions object.
INC_STAT(Thread::Current(),
total_code_size, object_pool.Length() * sizeof(uintptr_t));
@@ -14099,10 +14076,9 @@
void Code::DisableDartCode() const {
DEBUG_ASSERT(IsMutatorOrAtSafepoint());
ASSERT(IsFunctionCode());
- ASSERT(!IsDisabled());
+ ASSERT(instructions() == active_instructions());
const Code& new_code =
Code::Handle(StubCode::FixCallersTarget_entry()->code());
- ASSERT(new_code.instructions()->IsVMHeapObject());
SetActiveInstructions(new_code.instructions());
}
@@ -14111,10 +14087,9 @@
#if !defined(TARGET_ARCH_DBC)
ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(IsAllocationStubCode());
- ASSERT(!IsDisabled());
+ ASSERT(instructions() == active_instructions());
const Code& new_code =
Code::Handle(StubCode::FixAllocationStubTarget_entry()->code());
- ASSERT(new_code.instructions()->IsVMHeapObject());
SetActiveInstructions(new_code.instructions());
#else
// DBC does not use allocation stubs.
@@ -14127,6 +14102,7 @@
DEBUG_ASSERT(IsMutatorOrAtSafepoint() || !is_alive());
// RawInstructions are never allocated in New space and hence a
// store buffer update is not needed here.
+ StorePointer(&raw_ptr()->active_instructions_, instructions);
StoreNonPointer(&raw_ptr()->entry_point_,
reinterpret_cast<uword>(instructions->ptr()) +
Instructions::HeaderSize());
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 7243d0f..564db72 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3964,7 +3964,8 @@
FINAL_HEAP_OBJECT_IMPLEMENTATION(Instructions, Object);
friend class Class;
friend class Code;
- friend class InstructionsWriter;
+ friend class AssemblyInstructionsWriter;
+ friend class BlobInstructionsWriter;
};
@@ -4377,7 +4378,9 @@
class Code : public Object {
public:
- uword active_entry_point() const { return raw_ptr()->entry_point_; }
+ RawInstructions* active_instructions() const {
+ return raw_ptr()->active_instructions_;
+ }
RawInstructions* instructions() const { return raw_ptr()->instructions_; }
@@ -4407,15 +4410,20 @@
}
void set_is_alive(bool value) const;
- uword EntryPoint() const;
- intptr_t Size() const;
-
+ uword EntryPoint() const {
+ return Instructions::Handle(instructions()).EntryPoint();
+ }
+ intptr_t Size() const {
+ const Instructions& instr = Instructions::Handle(instructions());
+ return instr.size();
+ }
RawObjectPool* GetObjectPool() const {
return object_pool();
}
bool ContainsInstructionAt(uword addr) const {
- const uword offset = addr - EntryPoint();
- return offset < static_cast<uword>(Size());
+ const Instructions& instr = Instructions::Handle(instructions());
+ const uword offset = addr - instr.EntryPoint();
+ return offset < static_cast<uword>(instr.size());
}
// Returns true if there is a debugger breakpoint set in this code object.
@@ -4654,11 +4662,12 @@
void Enable() const {
if (!IsDisabled()) return;
ASSERT(Thread::Current()->IsMutatorThread());
+ ASSERT(instructions() != active_instructions());
SetActiveInstructions(instructions());
}
bool IsDisabled() const {
- return active_entry_point() != EntryPoint();
+ return instructions() != active_instructions();
}
private:
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 9f1f4fc..12d5234 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1120,12 +1120,10 @@
uword entry_point_;
RawObject** from() {
- return reinterpret_cast<RawObject**>(&ptr()->instructions_);
+ return reinterpret_cast<RawObject**>(&ptr()->active_instructions_);
}
- union {
- RawInstructions* instructions_;
- RawSmi* precompiled_instructions_size_;
- };
+ RawInstructions* active_instructions_;
+ RawInstructions* instructions_;
RawObjectPool* object_pool_;
// If owner_ is Function::null() the owner is a regular stub.
// If owner_ is a Class the owner is the allocation stub for that class.
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 1a90c2c..eec2523 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1361,20 +1361,24 @@
result.set_lazy_deopt_pc_offset(-1);
int32_t text_offset = reader->Read<int32_t>();
- int32_t instructions_size = reader->Read<int32_t>();
- uword entry_point = reader->GetInstructionsAt(text_offset);
+ RawInstructions* instr = reinterpret_cast<RawInstructions*>(
+ reader->GetInstructionsAt(text_offset) + kHeapObjectTag);
+ uword entry_point = Instructions::EntryPoint(instr);
#if defined(DEBUG)
+ ASSERT(instr->IsMarked());
+ ASSERT(instr->IsVMHeapObject());
uword expected_check = reader->Read<uword>();
+ intptr_t instructions_size = Utils::RoundUp(instr->size_,
+ OS::PreferredCodeAlignment());
uword actual_check = Checksum(entry_point, instructions_size);
ASSERT(expected_check == actual_check);
#endif
result.StoreNonPointer(&result.raw_ptr()->entry_point_, entry_point);
- result.StorePointer(reinterpret_cast<RawSmi*const*>(
- &result.raw_ptr()->instructions_),
- Smi::New(instructions_size));
+ result.StorePointer(&result.raw_ptr()->active_instructions_, instr);
+ result.StorePointer(&result.raw_ptr()->instructions_, instr);
(*reader->PassiveObjectHandle()) ^= reader->ReadObjectImpl(kAsReference);
result.StorePointer(reinterpret_cast<RawObject*const*>(
@@ -1418,9 +1422,6 @@
result.StorePointer(&result.raw_ptr()->return_address_metadata_,
Object::null());
- ASSERT(result.Size() == instructions_size);
- ASSERT(result.EntryPoint() == entry_point);
-
return result.raw();
}
@@ -1449,14 +1450,18 @@
// Write out all the non object fields.
writer->Write<int32_t>(ptr()->state_bits_);
+ // No disabled code in precompilation.
+ ASSERT(ptr()->instructions_ == ptr()->active_instructions_);
+
RawInstructions* instr = ptr()->instructions_;
- intptr_t size = instr->ptr()->size_;
int32_t text_offset = writer->GetInstructionsId(instr, this);
writer->Write<int32_t>(text_offset);
- writer->Write<int32_t>(size);
+
#if defined(DEBUG)
uword entry = ptr()->entry_point_;
- uword check = Checksum(entry, size);
+ intptr_t instructions_size = Utils::RoundUp(instr->size_,
+ OS::PreferredCodeAlignment());
+ uword check = Checksum(entry, instructions_size);
writer->Write<uword>(check);
#endif
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 6107c53..2f2ca6a 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -1160,13 +1160,9 @@
}
#endif
- intptr_t payload_size = instructions->ptr()->size_;
- payload_size = Utils::RoundUp(payload_size, OS::PreferredCodeAlignment());
-
+ intptr_t heap_size = instructions->Size();
intptr_t offset = next_offset_;
- ASSERT(Utils::IsAligned(next_offset_, OS::PreferredCodeAlignment()));
- next_offset_ += payload_size;
- ASSERT(Utils::IsAligned(next_offset_, OS::PreferredCodeAlignment()));
+ next_offset_ += heap_size;
instructions_.Add(InstructionsData(instructions, code, offset));
return offset;
@@ -1235,7 +1231,32 @@
ASSERT(insns.raw()->Size() % sizeof(uint64_t) == 0);
- // 1. Write a label at the entry point.
+ // 1. Write from the header to the entry point.
+ {
+ NoSafepointScope no_safepoint;
+
+ uword beginning = reinterpret_cast<uword>(insns.raw_ptr());
+ uword entry = beginning + Instructions::HeaderSize();
+
+ ASSERT(Utils::IsAligned(beginning, sizeof(uint64_t)));
+ ASSERT(Utils::IsAligned(entry, sizeof(uint64_t)));
+
+ // Write Instructions with the mark and VM heap bits set.
+ uword marked_tags = insns.raw_ptr()->tags_;
+ marked_tags = RawObject::VMHeapObjectTag::update(true, marked_tags);
+ marked_tags = RawObject::MarkBit::update(true, marked_tags);
+
+ WriteWordLiteral(marked_tags);
+ beginning += sizeof(uword);
+
+ for (uword* cursor = reinterpret_cast<uword*>(beginning);
+ cursor < reinterpret_cast<uword*>(entry);
+ cursor++) {
+ WriteWordLiteral(*cursor);
+ }
+ }
+
+ // 2. Write a label at the entry point.
owner = code.owner();
if (owner.IsNull()) {
const char* name = StubCode::NameOfStub(insns.EntryPoint());
@@ -1255,7 +1276,7 @@
}
{
- // 2. Write from the entry point to the end.
+ // 3. Write from the entry point to the end.
NoSafepointScope no_safepoint;
uword beginning = reinterpret_cast<uword>(insns.raw()) - kHeapObjectTag;
uword entry = beginning + Instructions::HeaderSize();
@@ -1342,8 +1363,33 @@
for (intptr_t i = 0; i < instructions_.length(); i++) {
const Instructions& insns = *instructions_[i].insns_;
+ // 1. Write from the header to the entry point.
{
- // 2. Write from the entry point to the end.
+ NoSafepointScope no_safepoint;
+
+ uword beginning = reinterpret_cast<uword>(insns.raw_ptr());
+ uword entry = beginning + Instructions::HeaderSize();
+
+ ASSERT(Utils::IsAligned(beginning, sizeof(uint64_t)));
+ ASSERT(Utils::IsAligned(entry, sizeof(uint64_t)));
+
+ // Write Instructions with the mark and VM heap bits set.
+ uword marked_tags = insns.raw_ptr()->tags_;
+ marked_tags = RawObject::VMHeapObjectTag::update(true, marked_tags);
+ marked_tags = RawObject::MarkBit::update(true, marked_tags);
+
+ instructions_blob_stream_.WriteWord(marked_tags);
+ beginning += sizeof(uword);
+
+ for (uword* cursor = reinterpret_cast<uword*>(beginning);
+ cursor < reinterpret_cast<uword*>(entry);
+ cursor++) {
+ instructions_blob_stream_.WriteWord(*cursor);
+ }
+ }
+
+ // 2. Write from the entry point to the end.
+ {
NoSafepointScope no_safepoint;
uword beginning = reinterpret_cast<uword>(insns.raw()) - kHeapObjectTag;
uword entry = beginning + Instructions::HeaderSize();
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index a537026..28636b8 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -109,7 +109,8 @@
Array maps;
maps = Array::null();
Stackmap map;
- const uword entry = code.EntryPoint();
+ const uword entry = reinterpret_cast<uword>(code.instructions()->ptr()) +
+ Instructions::HeaderSize();
map = code.GetStackmap(pc() - entry, &maps, &map);
if (!map.IsNull()) {
RawObject** first = reinterpret_cast<RawObject**>(sp());