[VM/AOT] Make trampolines look like free list elements to enable heap walking

Issue https://github.com/dart-lang/sdk/issues/33274

Change-Id: Ib6afdbc80012326134d409c4065a680d67de3ed8
Reviewed-on: https://dart-review.googlesource.com/c/90064
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/runtime/vm/compiler/relocation.cc b/runtime/vm/compiler/relocation.cc
index ef2d64a..83ff87c 100644
--- a/runtime/vm/compiler/relocation.cc
+++ b/runtime/vm/compiler/relocation.cc
@@ -20,6 +20,8 @@
             false,
             "Generate always trampolines (for testing purposes).");
 
+// The trampolines will have a 1-word object header in front of them.
+const intptr_t kOffsetInTrampoline = kWordSize;
 const intptr_t kTrampolineSize = OS::kMaxPreferredCodeAlignment;
 
 CodeRelocator::CodeRelocator(Thread* thread,
@@ -382,7 +384,8 @@
       FindDestinationInText(callee, unresolved_trampoline->offset_into_target);
   const int32_t distance = destination_text - trampoline_text_offset;
 
-  PcRelativeTrampolineJumpPattern pattern(trampoline_start);
+  PcRelativeTrampolineJumpPattern pattern(trampoline_start +
+                                          kOffsetInTrampoline);
   pattern.Initialize();
   pattern.set_distance(distance);
   ASSERT(pattern.distance() == distance);
@@ -396,6 +399,20 @@
          forward_distance < PcRelativeCallPattern::kUpperCallingRange;
 }
 
+static void MarkAsFreeListElement(uint8_t* trampoline_bytes,
+                                  intptr_t trampoline_length) {
+  uint32_t tags = 0;
+  tags = RawObject::SizeTag::update(trampoline_length, tags);
+  tags = RawObject::ClassIdTag::update(kFreeListElement, tags);
+  tags = RawObject::OldBit::update(true, tags);
+  tags = RawObject::OldAndNotMarkedBit::update(true, tags);
+  tags = RawObject::OldAndNotRememberedBit::update(true, tags);
+  tags = RawObject::NewBit::update(false, tags);
+
+  auto header_word = reinterpret_cast<uintptr_t*>(trampoline_bytes);
+  *header_word = tags;
+}
+
 void CodeRelocator::BuildTrampolinesForAlmostOutOfRangeCalls() {
   while (!all_unresolved_calls_.IsEmpty()) {
     UnresolvedCall* unresolved_call = all_unresolved_calls_.First();
@@ -407,7 +424,8 @@
     const intptr_t future_boundary =
         next_text_offset_ + max_instructions_size_ +
         kTrampolineSize *
-            (unresolved_calls_by_destination_.Length() + max_calls_);
+            (unresolved_calls_by_destination_.Length() + max_calls_) +
+        kOffsetInTrampoline;
     if (IsTargetInRangeFor(unresolved_call, future_boundary) &&
         !FLAG_always_generate_trampolines_for_testing) {
       break;
@@ -440,12 +458,16 @@
       // buffer.
       auto trampoline_bytes = new uint8_t[kTrampolineSize];
       memset(trampoline_bytes, 0x00, kTrampolineSize);
+      ASSERT((kOffsetInTrampoline +
+              PcRelativeTrampolineJumpPattern::kLengthInBytes) <
+             kTrampolineSize);
       auto unresolved_trampoline = new UnresolvedTrampoline{
           unresolved_call->callee,
           unresolved_call->offset_into_target,
           trampoline_bytes,
-          next_text_offset_,
+          next_text_offset_ + kOffsetInTrampoline,
       };
+      MarkAsFreeListElement(trampoline_bytes, kTrampolineSize);
       AddTrampolineToText(callee, trampoline_bytes, kTrampolineSize);
       EnqueueUnresolvedTrampoline(unresolved_trampoline);
       trampoline_text_offset = unresolved_trampoline->text_offset;
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 8cc2add..e2848d3 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -639,15 +639,6 @@
 }
 
 bool Heap::Verify(MarkExpectation mark_expectation) const {
-#if defined(DART_PRECOMPILED_RUNTIME)
-  // We cannot simply walk the heap pages which contain instructions, because
-  // they also contain trampolines inserted during AOT compilation time.
-  const bool have_bare_trampolines =
-      FLAG_precompiled_mode && FLAG_use_bare_instructions;
-  if (have_bare_trampolines) {
-    return true;
-  }
-#endif
   HeapIterationScope heap_iteration_scope(Thread::Current());
   return VerifyGC(mark_expectation);
 }
diff --git a/runtime/vm/instructions_x64.h b/runtime/vm/instructions_x64.h
index b41a95d..056f48f 100644
--- a/runtime/vm/instructions_x64.h
+++ b/runtime/vm/instructions_x64.h
@@ -157,6 +157,8 @@
 // allow testing of trampolines on X64 we have it nonetheless)
 class PcRelativeTrampolineJumpPattern : public ValueObject {
  public:
+  static const int kLengthInBytes = 5;
+
   explicit PcRelativeTrampolineJumpPattern(uword pattern_start)
       : pattern_start_(pattern_start) {}
 
@@ -181,8 +183,6 @@
   }
 
  private:
-  static const int kLengthInBytes = 5;
-
   uword pattern_start_;
 };