[nojit] Add a builtins entry table to IsolateData

In preparation for upcoming work on Torque function pointers.

This table will be used to look up the entry address in order to call
there directly without going through the (on-heap) trampoline.

Bug: v8:7777
Change-Id: If713430c843e85371a5aaef8a3bfb5da9e0ea903
Reviewed-on: https://chromium-review.googlesource.com/c/1378172
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58245}
diff --git a/src/builtins/builtins.cc b/src/builtins/builtins.cc
index 8b8665f..e6ce0c1 100644
--- a/src/builtins/builtins.cc
+++ b/src/builtins/builtins.cc
@@ -253,6 +253,15 @@
   UNREACHABLE();
 }
 
+// static
+void Builtins::UpdateBuiltinEntryTable(Isolate* isolate) {
+  Heap* heap = isolate->heap();
+  Address* builtin_entry_table = isolate->builtin_entry_table();
+  for (int i = 0; i < builtin_count; i++) {
+    builtin_entry_table[i] = heap->builtin(i)->InstructionStart();
+  }
+}
+
 namespace {
 
 class OffHeapTrampolineGenerator {
diff --git a/src/builtins/builtins.h b/src/builtins/builtins.h
index f984401..7ea440e 100644
--- a/src/builtins/builtins.h
+++ b/src/builtins/builtins.h
@@ -125,13 +125,24 @@
 
   // True, iff the given builtin contains no isolate-specific code and can be
   // embedded into the binary.
-  static bool IsIsolateIndependent(int index) { return true; }
+  static constexpr bool kAllBuiltinsAreIsolateIndependent = true;
+  static constexpr bool AllBuiltinsAreIsolateIndependent() {
+    return kAllBuiltinsAreIsolateIndependent;
+  }
+  static constexpr bool IsIsolateIndependent(int index) {
+    STATIC_ASSERT(kAllBuiltinsAreIsolateIndependent);
+    return kAllBuiltinsAreIsolateIndependent;
+  }
 
   // Wasm runtime stubs are treated specially by wasm. To guarantee reachability
   // through near jumps, their code is completely copied into a fresh off-heap
   // area.
   static bool IsWasmRuntimeStub(int index);
 
+  // Updates the table of builtin entry points based on the current contents of
+  // the builtins table.
+  static void UpdateBuiltinEntryTable(Isolate* isolate);
+
   bool is_initialized() const { return initialized_; }
 
   // Used by SetupIsolateDelegate and Deserializer.
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
index f7631d4..73025fc 100644
--- a/src/heap/heap.cc
+++ b/src/heap/heap.cc
@@ -3905,6 +3905,15 @@
     v->VisitRootPointer(Root::kBuiltins, Builtins::name(i),
                         FullObjectSlot(builtin_address(i)));
   }
+#ifdef V8_EMBEDDED_BUILTINS
+  // The entry table does not need to be updated if all builtins are embedded.
+  STATIC_ASSERT(Builtins::AllBuiltinsAreIsolateIndependent());
+#else
+  // If builtins are not embedded, they may move and thus the entry table must
+  // be updated.
+  // TODO(v8:6666): Remove once builtins are embedded unconditionally.
+  Builtins::UpdateBuiltinEntryTable(isolate());
+#endif  // V8_EMBEDDED_BUILTINS
 }
 
 // TODO(1236194): Since the heap size is configurable on the command line
diff --git a/src/isolate-data.h b/src/isolate-data.h
index 08704ed..c14abff 100644
--- a/src/isolate-data.h
+++ b/src/isolate-data.h
@@ -93,25 +93,27 @@
     return &external_reference_table_;
   }
 
+  Address* builtin_entry_table() { return builtin_entry_table_; }
   Address* builtins() { return builtins_; }
 
  private:
 // Static layout definition.
-#define FIELDS(V)                                                        \
-  V(kEmbedderDataOffset, Internals::kNumIsolateDataSlots* kPointerSize)  \
-  V(kExternalMemoryOffset, kInt64Size)                                   \
-  V(kExternalMemoryLlimitOffset, kInt64Size)                             \
-  V(kExternalMemoryAtLastMarkCompactOffset, kInt64Size)                  \
-  V(kRootsTableOffset, RootsTable::kEntriesCount* kPointerSize)          \
-  V(kExternalReferenceTableOffset, ExternalReferenceTable::kSizeInBytes) \
-  V(kBuiltinsTableOffset, Builtins::builtin_count* kPointerSize)         \
-  V(kVirtualCallTargetRegisterOffset, kPointerSize)                      \
-  V(kFastCCallCallerFPOffset, kPointerSize)                              \
-  V(kFastCCallCallerPCOffset, kPointerSize)                              \
-  /* This padding aligns IsolateData size by 8 bytes. */                 \
-  V(kPaddingOffset,                                                      \
-    8 + RoundUp<8>(static_cast<int>(kPaddingOffset)) - kPaddingOffset)   \
-  /* Total size. */                                                      \
+#define FIELDS(V)                                                          \
+  V(kEmbedderDataOffset, Internals::kNumIsolateDataSlots* kPointerSize)    \
+  V(kExternalMemoryOffset, kInt64Size)                                     \
+  V(kExternalMemoryLlimitOffset, kInt64Size)                               \
+  V(kExternalMemoryAtLastMarkCompactOffset, kInt64Size)                    \
+  V(kRootsTableOffset, RootsTable::kEntriesCount* kPointerSize)            \
+  V(kExternalReferenceTableOffset, ExternalReferenceTable::kSizeInBytes)   \
+  V(kBuiltinEntryTableOffset, Builtins::builtin_count* kSystemPointerSize) \
+  V(kBuiltinsTableOffset, Builtins::builtin_count* kPointerSize)           \
+  V(kVirtualCallTargetRegisterOffset, kPointerSize)                        \
+  V(kFastCCallCallerFPOffset, kPointerSize)                                \
+  V(kFastCCallCallerPCOffset, kPointerSize)                                \
+  /* This padding aligns IsolateData size by 8 bytes. */                   \
+  V(kPaddingOffset,                                                        \
+    8 + RoundUp<8>(static_cast<int>(kPaddingOffset)) - kPaddingOffset)     \
+  /* Total size. */                                                        \
   V(kSize, 0)
 
   DEFINE_FIELD_OFFSET_CONSTANTS(0, FIELDS)
@@ -138,6 +140,11 @@
 
   ExternalReferenceTable external_reference_table_;
 
+  // The entry points for all builtins. This corresponds to
+  // Code::InstructionStart() for each Code object in the builtins table below.
+  // The entry table is in IsolateData for easy access through kRootRegister.
+  Address builtin_entry_table_[Builtins::builtin_count] = {};
+
   // The entries in this array are tagged pointers to Code objects.
   Address builtins_[Builtins::builtin_count] = {};
 
diff --git a/src/isolate.cc b/src/isolate.cc
index 08674f3c..f4ad2ed 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -3320,6 +3320,9 @@
   delete setup_delegate_;
   setup_delegate_ = nullptr;
 
+  // Initialize the builtin entry table.
+  Builtins::UpdateBuiltinEntryTable(this);
+
   if (FLAG_print_builtin_code) builtins()->PrintBuiltinCode();
   if (FLAG_print_builtin_size) builtins()->PrintBuiltinSize();
 
diff --git a/src/isolate.h b/src/isolate.h
index f5cda88..2a68be5 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -1020,6 +1020,7 @@
     return isolate_data()->external_reference_table();
   }
 
+  Address* builtin_entry_table() { return isolate_data_.builtin_entry_table(); }
   V8_INLINE Address* builtins_table() { return isolate_data_.builtins(); }
 
   StubCache* load_stub_cache() { return load_stub_cache_; }