Commit a881300a authored by Igor Sheludko's avatar Igor Sheludko Committed by V8 LUCI CQ

[ext-code-space] Add cage base fields to Code and CodeDataContainer

... which will be used for decompressing Code <-> CDC references
when external code space is enabled.

Bug: v8:11880
Change-Id: I142f635c7cc91cdb79ed51755271fad0223ade0d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3208814
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77320}
parent b54f1360
......@@ -2091,9 +2091,13 @@ void TurboAssembler::LoadCodeDataContainerEntry(
void TurboAssembler::LoadCodeDataContainerCodeNonBuiltin(
Register destination, Register code_data_container_object) {
ASM_CODE_COMMENT(this);
LoadTaggedPointerField(destination,
FieldMemOperand(code_data_container_object,
CodeDataContainer::kCodeOffset));
CHECK(V8_EXTERNAL_CODE_SPACE_BOOL);
// Given the fields layout we can read the Code reference as a full word.
STATIC_ASSERT(!V8_EXTERNAL_CODE_SPACE_BOOL ||
(CodeDataContainer::kCodeCageBaseUpper32BitsOffset ==
CodeDataContainer::kCodeOffset + kTaggedSize));
Ldr(destination, FieldMemOperand(code_data_container_object,
CodeDataContainer::kCodeOffset));
}
void TurboAssembler::CallCodeDataContainerObject(
......
......@@ -804,7 +804,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<Code> FromCodeT(TNode<CodeT> code) {
#ifdef V8_EXTERNAL_CODE_SPACE
return LoadObjectField<Code>(code, CodeDataContainer::kCodeOffset);
#if V8_TARGET_BIG_ENDIAN
#error "This code requires updating for big-endian architectures"
#endif
// Given the fields layout we can read the Code reference as a full word.
STATIC_ASSERT(CodeDataContainer::kCodeCageBaseUpper32BitsOffset ==
CodeDataContainer::kCodeOffset + kTaggedSize);
TNode<Object> o = BitcastWordToTagged(Load<RawPtrT>(
code, IntPtrConstant(CodeDataContainer::kCodeOffset - kHeapObjectTag)));
return CAST(o);
#else
return code;
#endif
......
......@@ -2044,9 +2044,13 @@ void TurboAssembler::LoadCodeDataContainerEntry(
void TurboAssembler::LoadCodeDataContainerCodeNonBuiltin(
Register destination, Register code_data_container_object) {
ASM_CODE_COMMENT(this);
LoadTaggedPointerField(
destination,
FieldOperand(code_data_container_object, CodeDataContainer::kCodeOffset));
CHECK(V8_EXTERNAL_CODE_SPACE_BOOL);
// Given the fields layout we can read the Code reference as a full word.
STATIC_ASSERT(!V8_EXTERNAL_CODE_SPACE_BOOL ||
(CodeDataContainer::kCodeCageBaseUpper32BitsOffset ==
CodeDataContainer::kCodeOffset + kTaggedSize));
movq(destination, FieldOperand(code_data_container_object,
CodeDataContainer::kCodeOffset));
}
void TurboAssembler::CallCodeDataContainerObject(
......
......@@ -397,9 +397,16 @@ size_t Isolate::HashIsolateForEmbeddedBlob() {
reinterpret_cast<uint8_t*>(code.ptr() - kHeapObjectTag);
// These static asserts ensure we don't miss relevant fields. We don't hash
// instruction/metadata size and flags since they change when creating the
// off-heap trampolines. Other data fields must remain the same.
// pointer compression base, instruction/metadata size value and flags since
// they change when creating the off-heap trampolines. Other data fields
// must remain the same.
#ifdef V8_EXTERNAL_CODE_SPACE
STATIC_ASSERT(Code::kMainCageBaseUpper32BitsOffset == Code::kDataStart);
STATIC_ASSERT(Code::kInstructionSizeOffset ==
Code::kMainCageBaseUpper32BitsOffsetEnd + 1);
#else
STATIC_ASSERT(Code::kInstructionSizeOffset == Code::kDataStart);
#endif // V8_EXTERNAL_CODE_SPACE
STATIC_ASSERT(Code::kMetadataSizeOffset ==
Code::kInstructionSizeOffsetEnd + 1);
STATIC_ASSERT(Code::kFlagsOffset == Code::kMetadataSizeOffsetEnd + 1);
......
......@@ -202,6 +202,7 @@ MaybeHandle<Code> Factory::CodeBuilder::BuildInternal(
raw_code.clear_padding();
if (V8_EXTERNAL_CODE_SPACE_BOOL) {
raw_code.set_main_cage_base(isolate_->cage_base());
data_container->SetCodeAndEntryPoint(isolate_, raw_code);
}
#ifdef VERIFY_HEAP
......@@ -2091,6 +2092,7 @@ Handle<CodeDataContainer> Factory::NewCodeDataContainer(
data_container.set_kind_specific_flags(flags, kRelaxedStore);
if (V8_EXTERNAL_CODE_SPACE_BOOL) {
data_container.AllocateExternalPointerEntries(isolate());
data_container.set_code_cage_base(isolate()->code_cage_base());
data_container.set_raw_code(Smi::zero(), SKIP_WRITE_BARRIER);
data_container.set_code_entry_point(isolate(), kNullAddress);
}
......
This diff is collapsed.
......@@ -54,6 +54,17 @@ class CodeDataContainer : public HeapObject {
DECL_GETTER(code, Code)
DECL_RELAXED_GETTER(code, Code)
// When V8_EXTERNAL_CODE_SPACE is enabled, Code objects are allocated in
// a separate pointer compression cage instead of the cage where all the
// other objects are allocated.
// This field contains code cage base value which is used for decompressing
// the reference to respective Code. Basically, |code_cage_base| and |code|
// fields together form a full pointer. The reason why they are split is that
// the code field must also support atomic access and the word alignment of
// the full value is not guaranteed.
inline PtrComprCageBase code_cage_base() const;
inline void set_code_cage_base(Address code_cage_base);
// Cached value of code().InstructionStart().
// Available only when V8_EXTERNAL_CODE_SPACE is defined.
DECL_GETTER(code_entry_point, Address)
......@@ -87,6 +98,8 @@ class CodeDataContainer : public HeapObject {
V(kCodeOffset, V8_EXTERNAL_CODE_SPACE_BOOL ? kTaggedSize : 0) \
V(kCodePointerFieldsStrongEndOffset, 0) \
/* Raw data fields. */ \
V(kCodeCageBaseUpper32BitsOffset, \
V8_EXTERNAL_CODE_SPACE_BOOL ? kTaggedSize : 0) \
V(kCodeEntryPointOffset, \
V8_EXTERNAL_CODE_SPACE_BOOL ? kExternalPointerSize : 0) \
V(kKindSpecificFlagsOffset, kInt32Size) \
......@@ -101,7 +114,7 @@ class CodeDataContainer : public HeapObject {
private:
DECL_ACCESSORS(raw_code, Object)
DECL_RELAXED_ACCESSORS(raw_code, Object)
DECL_RELAXED_GETTER(raw_code, Object)
inline void set_code_entry_point(Isolate* isolate, Address value);
friend Factory;
......@@ -405,6 +418,14 @@ class Code : public HeapObject {
// out the to-be-overwritten header data for reproducible snapshots.
inline void WipeOutHeader();
// When V8_EXTERNAL_CODE_SPACE is enabled, Code objects are allocated in
// a separate pointer compression cage instead of the cage where all the
// other objects are allocated.
// This field contains cage base value which is used for decompressing
// the references to non-Code objects (map, deoptimization_data, etc.).
inline PtrComprCageBase main_cage_base() const;
inline void set_main_cage_base(Address cage_base);
// Clear uninitialized padding space. This ensures that the snapshot content
// is deterministic. Depending on the V8 build mode there could be no padding.
inline void clear_padding();
......@@ -515,6 +536,8 @@ class Code : public HeapObject {
/* The serializer needs to copy bytes starting from here verbatim. */ \
/* Objects embedded into code is visited via reloc info. */ \
V(kDataStart, 0) \
V(kMainCageBaseUpper32BitsOffset, \
V8_EXTERNAL_CODE_SPACE_BOOL ? kTaggedSize : 0) \
V(kInstructionSizeOffset, kIntSize) \
V(kMetadataSizeOffset, kIntSize) \
V(kFlagsOffset, kInt32Size) \
......@@ -538,13 +561,15 @@ class Code : public HeapObject {
// This documents the amount of free space we have in each Code object header
// due to padding for code alignment.
#if V8_TARGET_ARCH_ARM64
static constexpr int kHeaderPaddingSize = COMPRESS_POINTERS_BOOL ? 12 : 24;
static constexpr int kHeaderPaddingSize =
V8_EXTERNAL_CODE_SPACE_BOOL ? 8 : (COMPRESS_POINTERS_BOOL ? 12 : 24);
#elif V8_TARGET_ARCH_MIPS64
static constexpr int kHeaderPaddingSize = 24;
#elif V8_TARGET_ARCH_LOONG64
static constexpr int kHeaderPaddingSize = 24;
#elif V8_TARGET_ARCH_X64
static constexpr int kHeaderPaddingSize = COMPRESS_POINTERS_BOOL ? 12 : 56;
static constexpr int kHeaderPaddingSize =
V8_EXTERNAL_CODE_SPACE_BOOL ? 8 : (COMPRESS_POINTERS_BOOL ? 12 : 56);
#elif V8_TARGET_ARCH_ARM
static constexpr int kHeaderPaddingSize = 12;
#elif V8_TARGET_ARCH_IA32
......
......@@ -462,6 +462,7 @@ void Deserializer<IsolateT>::PostProcessNewObject(Handle<Map> map,
} else if (V8_EXTERNAL_CODE_SPACE_BOOL &&
InstanceTypeChecker::IsCodeDataContainer(instance_type)) {
auto code_data_container = Handle<CodeDataContainer>::cast(obj);
code_data_container->set_code_cage_base(isolate()->code_cage_base());
code_data_container->AllocateExternalPointerEntries(main_thread_isolate());
code_data_container->UpdateCodeEntryPoint(main_thread_isolate(),
code_data_container->code());
......@@ -557,7 +558,7 @@ Handle<HeapObject> Deserializer<IsolateT>::GetBackReferencedObject() {
// We don't allow ThinStrings in backreferences -- if internalization produces
// a thin string, then it should also update the backref handle.
DCHECK(!obj->IsThinString());
DCHECK(!obj->IsThinString(isolate()));
hot_objects_.Add(obj);
DCHECK(!HasWeakHeapObjectTag(*obj));
......@@ -647,8 +648,9 @@ Handle<HeapObject> Deserializer<IsolateT>::ReadObject(SnapshotSpace space) {
}
#ifdef DEBUG
PtrComprCageBase cage_base(isolate());
// We want to make sure that all embedder pointers are initialized to null.
if (raw_obj.IsJSObject() && JSObject::cast(raw_obj).IsApiWrapper()) {
if (raw_obj.IsJSObject(cage_base) && JSObject::cast(raw_obj).IsApiWrapper()) {
JSObject js_obj = JSObject::cast(raw_obj);
for (int i = 0; i < js_obj.GetEmbedderFieldCount(); ++i) {
void* pointer;
......@@ -656,7 +658,7 @@ Handle<HeapObject> Deserializer<IsolateT>::ReadObject(SnapshotSpace space) {
main_thread_isolate(), &pointer));
CHECK_NULL(pointer);
}
} else if (raw_obj.IsEmbedderDataArray()) {
} else if (raw_obj.IsEmbedderDataArray(cage_base)) {
EmbedderDataArray array = EmbedderDataArray::cast(raw_obj);
EmbedderDataSlot start(array, 0);
EmbedderDataSlot end(array, array.length());
......@@ -675,7 +677,7 @@ Handle<HeapObject> Deserializer<IsolateT>::ReadObject(SnapshotSpace space) {
PostProcessNewObject(map, obj, space);
#ifdef DEBUG
if (obj->IsCode()) {
if (obj->IsCode(cage_base)) {
DCHECK(space == SnapshotSpace::kCode ||
space == SnapshotSpace::kReadOnlyHeap);
} else {
......@@ -1112,6 +1114,9 @@ int Deserializer<IsolateT>::ReadSingleBytecodeData(byte data,
DisallowGarbageCollection no_gc;
Code code = Code::cast(*slot_accessor.object());
if (V8_EXTERNAL_CODE_SPACE_BOOL) {
code.set_main_cage_base(isolate()->cage_base());
}
DeserializerRelocInfoVisitor visitor(this, &preserialized_objects);
for (RelocIterator it(code, Code::BodyDescriptor::kRelocModeMask);
!it.done(); it.next()) {
......
......@@ -126,7 +126,7 @@ void Serializer::SerializeObject(Handle<HeapObject> obj) {
// indirection and serialize the actual string directly.
if (obj->IsThinString(isolate())) {
obj = handle(ThinString::cast(*obj).actual(isolate()), isolate());
} else if (obj->IsCodeT()) {
} else if (obj->IsCodeT(isolate())) {
Code code = FromCodeT(CodeT::cast(*obj));
if (code.kind() == CodeKind::BASELINE) {
// For now just serialize the BytecodeArray instead of baseline code.
......@@ -633,13 +633,13 @@ void Serializer::ObjectSerializer::SerializeExternalStringAsSequentialString() {
class V8_NODISCARD UnlinkWeakNextScope {
public:
explicit UnlinkWeakNextScope(Heap* heap, Handle<HeapObject> object) {
if (object->IsAllocationSite() &&
Isolate* isolate = heap->isolate();
if (object->IsAllocationSite(isolate) &&
Handle<AllocationSite>::cast(object)->HasWeakNext()) {
object_ = object;
next_ =
handle(AllocationSite::cast(*object).weak_next(), heap->isolate());
next_ = handle(AllocationSite::cast(*object).weak_next(), isolate);
Handle<AllocationSite>::cast(object)->set_weak_next(
ReadOnlyRoots(heap).undefined_value());
ReadOnlyRoots(isolate).undefined_value());
}
}
......
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