[ext-code-space] Support embedding of CodeT references

In order to avoid some of the unnecessary Code <-> CodeDataContainer
conversions in builtins we need to be able to embed CodeDataContainer
references to builtins.

This CL makes it possible by introducing a table of builtins' CDCs.
Eventually, usages of the builtins table containing Code objects will
be replaced by usages of this table.

Bug: v8:11880
Change-Id: Iffffd1507d5c7b38af34c42071a4577a8d18e8eb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3257710
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Auto-Submit: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77678}
This commit is contained in:
Igor Sheludko 2021-11-03 11:15:31 +01:00 committed by V8 LUCI CQ
parent 725654b353
commit 7119b05321
11 changed files with 124 additions and 5 deletions

View File

@ -194,6 +194,37 @@ Handle<Code> Builtins::code_handle(Builtin builtin) {
return Handle<Code>(location);
}
FullObjectSlot Builtins::builtin_code_data_container_slot(Builtin builtin) {
CHECK(V8_EXTERNAL_CODE_SPACE_BOOL);
Address* location =
&isolate_->builtin_code_data_container_table()[Builtins::ToInt(builtin)];
return FullObjectSlot(location);
}
void Builtins::set_codet(Builtin builtin, CodeT code) {
CHECK(V8_EXTERNAL_CODE_SPACE_BOOL);
// TODO(v8:11880): add DCHECK_EQ(builtin, code.builtin_id()); once CodeT
// has respective field.
DCHECK(Internals::HasHeapObjectTag(code.ptr()));
// The given builtin may be uninitialized thus we cannot check its type here.
isolate_->builtin_code_data_container_table()[Builtins::ToInt(builtin)] =
code.ptr();
}
CodeT Builtins::codet(Builtin builtin) {
CHECK(V8_EXTERNAL_CODE_SPACE_BOOL);
Address ptr =
isolate_->builtin_code_data_container_table()[Builtins::ToInt(builtin)];
return CodeT::cast(Object(ptr));
}
Handle<CodeT> Builtins::codet_handle(Builtin builtin) {
CHECK(V8_EXTERNAL_CODE_SPACE_BOOL);
Address* location =
&isolate_->builtin_code_data_container_table()[Builtins::ToInt(builtin)];
return Handle<CodeT>(location);
}
// static
int Builtins::GetStackParameterCount(Builtin builtin) {
DCHECK(Builtins::KindOf(builtin) == TFJ);
@ -296,6 +327,17 @@ bool Builtins::IsBuiltinHandle(Handle<HeapObject> maybe_code,
return true;
}
bool Builtins::IsBuiltinCodeDataContainerHandle(Handle<HeapObject> maybe_code,
Builtin* builtin) const {
Address* handle_location = maybe_code.location();
Address* builtins_table = isolate_->builtin_code_data_container_table();
if (handle_location < builtins_table) return false;
Address* builtins_table_end = &builtins_table[Builtins::kBuiltinCount];
if (handle_location >= builtins_table_end) return false;
*builtin = FromInt(static_cast<int>(handle_location - builtins_table));
return true;
}
// static
bool Builtins::IsIsolateIndependentBuiltin(const Code code) {
const Builtin builtin = code.builtin_id();

View File

@ -36,6 +36,13 @@ static constexpr T FirstFromVarArgs(T x, ...) noexcept {
#define BUILTIN_CODE(isolate, name) \
(isolate)->builtins()->code_handle(i::Builtin::k##name)
#if V8_EXTERNAL_CODE_SPACE
#define BUILTIN_CODET(isolate, name) \
(isolate)->builtins()->codet_handle(i::Builtin::k##name)
#else
#define BUILTIN_CODET(isolate, name) BUILTIN_CODE(isolate, name)
#endif // V8_EXTERNAL_CODE_SPACE
enum class Builtin : int32_t {
kNoBuiltinId = -1,
#define DEF_ENUM(Name, ...) k##Name,
@ -158,10 +165,14 @@ class Builtins {
// Used by CreateOffHeapTrampolines in isolate.cc.
void set_code(Builtin builtin, Code code);
void set_codet(Builtin builtin, CodeT code);
V8_EXPORT_PRIVATE Code code(Builtin builtin);
V8_EXPORT_PRIVATE Handle<Code> code_handle(Builtin builtin);
V8_EXPORT_PRIVATE CodeT codet(Builtin builtin);
V8_EXPORT_PRIVATE Handle<CodeT> codet_handle(Builtin builtin);
static CallInterfaceDescriptor CallInterfaceDescriptorFor(Builtin builtin);
V8_EXPORT_PRIVATE static Callable CallableFor(Isolate* isolate,
Builtin builtin);
@ -192,6 +203,11 @@ class Builtins {
// by handle location. Similar to Heap::IsRootHandle.
bool IsBuiltinHandle(Handle<HeapObject> maybe_code, Builtin* index) const;
// Similar to IsBuiltinHandle but for respective CodeDataContainer handle.
// Can be used only when external code space is enabled.
bool IsBuiltinCodeDataContainerHandle(Handle<HeapObject> maybe_code,
Builtin* index) const;
// True, iff the given code object is a builtin with off-heap embedded code.
static bool IsIsolateIndependentBuiltin(const Code code);
@ -280,6 +296,8 @@ class Builtins {
FullObjectSlot builtin_slot(Builtin builtin);
// Returns given builtin's slot in the tier0 builtin table.
FullObjectSlot builtin_tier0_slot(Builtin builtin);
// Returns given builtin's slot in the builtin code data container table.
FullObjectSlot builtin_code_data_container_slot(Builtin builtin);
private:
static void Generate_CallFunction(MacroAssembler* masm,

View File

@ -199,6 +199,9 @@ void SetupIsolateDelegate::AddBuiltin(Builtins* builtins, Builtin builtin,
Code code) {
DCHECK_EQ(builtin, code.builtin_id());
builtins->set_code(builtin, code);
if (V8_EXTERNAL_CODE_SPACE_BOOL) {
builtins->set_codet(builtin, ToCodeT(code));
}
}
// static

View File

@ -50,6 +50,12 @@ void TurboAssemblerBase::IndirectLoadConstant(Register destination,
if (isolate()->roots_table().IsRootHandle(object, &root_index)) {
// Roots are loaded relative to the root register.
LoadRoot(destination, root_index);
} else if (V8_EXTERNAL_CODE_SPACE_BOOL &&
isolate()->builtins()->IsBuiltinCodeDataContainerHandle(
object, &builtin)) {
// Similar to roots, builtins may be loaded from the builtins table.
LoadRootRelative(destination,
RootRegisterOffsetForBuiltinCodeDataContainer(builtin));
} else if (isolate()->builtins()->IsBuiltinHandle(object, &builtin)) {
// Similar to roots, builtins may be loaded from the builtins table.
LoadRootRelative(destination, RootRegisterOffsetForBuiltin(builtin));
@ -100,6 +106,12 @@ int32_t TurboAssemblerBase::RootRegisterOffsetForBuiltin(Builtin builtin) {
return IsolateData::BuiltinSlotOffset(builtin);
}
// static
int32_t TurboAssemblerBase::RootRegisterOffsetForBuiltinCodeDataContainer(
Builtin builtin) {
return IsolateData::BuiltinCodeDataContainerSlotOffset(builtin);
}
// static
intptr_t TurboAssemblerBase::RootRegisterOffsetForExternalReference(
Isolate* isolate, const ExternalReference& reference) {

View File

@ -80,6 +80,7 @@ class V8_EXPORT_PRIVATE TurboAssemblerBase : public Assembler {
static int32_t RootRegisterOffsetForRootIndex(RootIndex root_index);
static int32_t RootRegisterOffsetForBuiltin(Builtin builtin);
static int32_t RootRegisterOffsetForBuiltinCodeDataContainer(Builtin builtin);
// Returns the root-relative offset to reference.address().
static intptr_t RootRegisterOffsetForExternalReference(

View File

@ -48,9 +48,19 @@ class Isolate;
builtin_entry_table) \
V(kBuiltinTableOffset, Builtins::kBuiltinCount* kSystemPointerSize, \
builtin_table) \
ISOLATE_DATA_FIELDS_EXTERNAL_CODE_SPACE(V) \
ISOLATE_DATA_FIELDS_HEAP_SANDBOX(V) \
V(kStackIsIterableOffset, kUInt8Size, stack_is_iterable)
#ifdef V8_EXTERNAL_CODE_SPACE
#define ISOLATE_DATA_FIELDS_EXTERNAL_CODE_SPACE(V) \
V(kBuiltinCodeDataContainerTableOffset, \
Builtins::kBuiltinCount* kSystemPointerSize, \
builtin_code_data_container_table)
#else
#define ISOLATE_DATA_FIELDS_EXTERNAL_CODE_SPACE(V)
#endif // V8_EXTERNAL_CODE_SPACE
#ifdef V8_HEAP_SANDBOX
#define ISOLATE_DATA_FIELDS_HEAP_SANDBOX(V) \
V(kExternalPointerTableOffset, kSystemPointerSize * 3, external_pointer_table)
@ -104,6 +114,17 @@ class IsolateData final {
Builtins::ToInt(id) * kSystemPointerSize;
}
static int BuiltinCodeDataContainerSlotOffset(Builtin id) {
#ifdef V8_EXTERNAL_CODE_SPACE
// TODO(v8:11880): implement table tiering once the builtin table containing
// Code objects is no longer used.
return builtin_code_data_container_table_offset() +
Builtins::ToInt(id) * kSystemPointerSize;
#else
UNREACHABLE();
#endif // V8_EXTERNAL_CODE_SPACE
}
#define V(Offset, Size, Name) \
Address Name##_address() { return reinterpret_cast<Address>(&Name##_); }
ISOLATE_DATA_FIELDS(V)
@ -126,6 +147,13 @@ class IsolateData final {
ThreadLocalTop const& thread_local_top() const { return thread_local_top_; }
Address* builtin_entry_table() { return builtin_entry_table_; }
Address* builtin_table() { return builtin_table_; }
Address* builtin_code_data_container_table() {
#ifdef V8_EXTERNAL_CODE_SPACE
return builtin_code_data_container_table_;
#else
UNREACHABLE();
#endif
}
uint8_t stack_is_iterable() const { return stack_is_iterable_; }
// Returns true if this address points to data stored in this instance. If
@ -201,6 +229,10 @@ class IsolateData final {
// The entries in this array are tagged pointers to Code objects.
Address builtin_table_[Builtins::kBuiltinCount] = {};
#ifdef V8_EXTERNAL_CODE_SPACE
Address builtin_code_data_container_table_[Builtins::kBuiltinCount] = {};
#endif
// Table containing pointers to external objects.
#ifdef V8_HEAP_SANDBOX
ExternalPointerTable external_pointer_table_;

View File

@ -3426,6 +3426,9 @@ void CreateOffHeapTrampolines(Isolate* isolate) {
// From this point onwards, the old builtin code object is unreachable and
// will be collected by the next GC.
builtins->set_code(builtin, *trampoline);
if (V8_EXTERNAL_CODE_SPACE_BOOL) {
builtins->set_codet(builtin, ToCodeT(*trampoline));
}
}
}

View File

@ -1146,6 +1146,9 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
V8_INLINE Address* builtin_tier0_table() {
return isolate_data_.builtin_tier0_table();
}
V8_INLINE Address* builtin_code_data_container_table() {
return isolate_data_.builtin_code_data_container_table();
}
bool IsBuiltinTableHandleLocation(Address* handle_location);

View File

@ -4886,8 +4886,12 @@ void Heap::IterateBuiltins(RootVisitor* v) {
Builtins* builtins = isolate()->builtins();
for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
++builtin) {
v->VisitRootPointer(Root::kBuiltins, Builtins::name(builtin),
builtins->builtin_slot(builtin));
const char* name = Builtins::name(builtin);
v->VisitRootPointer(Root::kBuiltins, name, builtins->builtin_slot(builtin));
if (V8_EXTERNAL_CODE_SPACE_BOOL) {
v->VisitRootPointer(Root::kBuiltins, name,
builtins->builtin_code_data_container_slot(builtin));
}
}
for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLastTier0;

View File

@ -1216,7 +1216,8 @@ void V8HeapExplorer::ExtractAccessorPairReferences(HeapEntry* entry,
AccessorPair::kSetterOffset);
}
void V8HeapExplorer::TagBuiltinCodeObject(Code code, const char* name) {
void V8HeapExplorer::TagBuiltinCodeObject(Object code, const char* name) {
DCHECK(code.IsCode() || (V8_EXTERNAL_CODE_SPACE_BOOL && code.IsCodeT()));
TagObject(code, names_->GetFormatted("(%s builtin)", name));
}
@ -1577,7 +1578,7 @@ class RootsReferencesExtractor : public RootVisitor {
void VisitRootPointer(Root root, const char* description,
FullObjectSlot object) override {
if (root == Root::kBuiltins) {
explorer_->TagBuiltinCodeObject(Code::cast(*object), description);
explorer_->TagBuiltinCodeObject(*object, description);
}
explorer_->SetGcSubrootReference(root, description, visiting_weak_roots_,
*object);

View File

@ -358,7 +358,7 @@ class V8_EXPORT_PRIVATE V8HeapExplorer : public HeapEntriesAllocator {
bool IterateAndExtractReferences(HeapSnapshotGenerator* generator);
void CollectGlobalObjectsTags();
void MakeGlobalObjectTagMap(const SafepointScope& safepoint_scope);
void TagBuiltinCodeObject(Code code, const char* name);
void TagBuiltinCodeObject(Object code, const char* name);
HeapEntry* AddEntry(Address address,
HeapEntry::Type type,
const char* name,