[ptr-compr] Introduce EmbedderDataSlot

an abstraction that hides the details about how embedder data fields are
encoded in EmbedderDataArrays and JSObjects.

Bug: v8:7703
Change-Id: Ic9f6d9511bec557c6671aa6488b9545e353f968c
Reviewed-on: https://chromium-review.googlesource.com/c/1344155
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57679}
This commit is contained in:
Igor Sheludko 2018-11-21 12:30:49 +01:00 committed by Commit Bot
parent 5065c20a7e
commit ea9f847d36
11 changed files with 211 additions and 46 deletions

View File

@ -2222,6 +2222,8 @@ v8_source_set("v8_base") {
"src/objects/embedder-data-array-inl.h",
"src/objects/embedder-data-array.cc",
"src/objects/embedder-data-array.h",
"src/objects/embedder-data-slot-inl.h",
"src/objects/embedder-data-slot.h",
"src/objects/fixed-array-inl.h",
"src/objects/fixed-array.h",
"src/objects/frame-array-inl.h",

View File

@ -125,7 +125,7 @@ class Internals {
static const int kJSObjectHeaderSize = 3 * kApiTaggedSize;
static const int kFixedArrayHeaderSize = 2 * kApiTaggedSize;
static const int kEmbedderDataArrayHeaderSize = 2 * kApiTaggedSize;
static const int kEmbedderSlotSize = kApiSystemPointerSize;
static const int kEmbedderDataSlotSize = kApiSystemPointerSize;
static const int kContextHeaderSize = 2 * kApiTaggedSize;
static const int kContextEmbedderDataIndex = 5;
static const int kFullStringRepresentationMask = 0x0f;
@ -276,7 +276,7 @@ class Internals {
(internal::kApiTaggedSize * I::kContextEmbedderDataIndex);
A embedder_data = I::ReadField<A>(ctx, embedder_data_offset);
int value_offset =
I::kEmbedderDataArrayHeaderSize + (I::kEmbedderSlotSize * index);
I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index);
return I::ReadField<T>(embedder_data, value_offset);
}
#endif

View File

@ -9828,7 +9828,7 @@ Local<Value> Object::GetInternalField(int index) {
if (instance_type == I::kJSObjectType ||
instance_type == I::kJSApiObjectType ||
instance_type == I::kJSSpecialApiObjectType) {
int offset = I::kJSObjectHeaderSize + (I::kEmbedderSlotSize * index);
int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index);
A value = I::ReadField<A>(obj, offset);
A* result = HandleScope::CreateHandle(
reinterpret_cast<internal::NeverReadOnlySpaceObject*>(obj), value);
@ -9850,7 +9850,7 @@ void* Object::GetAlignedPointerFromInternalField(int index) {
if (V8_LIKELY(instance_type == I::kJSObjectType ||
instance_type == I::kJSApiObjectType ||
instance_type == I::kJSSpecialApiObjectType)) {
int offset = I::kJSObjectHeaderSize + (I::kEmbedderSlotSize * index);
int offset = I::kJSObjectHeaderSize + (I::kEmbedderDataSlotSize * index);
return I::ReadField<void*>(obj, offset);
}
#endif

View File

@ -52,6 +52,7 @@
#include "src/objects-inl.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/embedder-data-array-inl.h"
#include "src/objects/embedder-data-slot-inl.h"
#include "src/objects/hash-table-inl.h"
#include "src/objects/heap-object.h"
#include "src/objects/js-array-inl.h"
@ -1198,6 +1199,8 @@ static i::Smi EncodeAlignedAsSmi(void* value, const char* location) {
return smi;
}
STATIC_ASSERT(i::Internals::kEmbedderDataSlotSize == i::kEmbedderDataSlotSize);
static i::Handle<i::EmbedderDataArray> EmbedderDataFor(Context* context,
int index, bool can_grow,
const char* location) {
@ -1236,7 +1239,8 @@ v8::Local<v8::Value> Context::SlowGetEmbedderData(int index) {
EmbedderDataFor(this, index, false, location);
if (data.is_null()) return Local<Value>();
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
i::Handle<i::Object> result(data->get(index), isolate);
i::Handle<i::Object> result(i::EmbedderDataSlot(*data, index).load_tagged(),
isolate);
return Utils::ToLocal(result);
}
@ -1247,7 +1251,7 @@ void Context::SetEmbedderData(int index, v8::Local<Value> value) {
EmbedderDataFor(this, index, true, location);
if (data.is_null()) return;
i::Handle<i::Object> val = Utils::OpenHandle(*value);
data->set(index, *val);
i::EmbedderDataSlot::store_tagged(*data, index, *val);
DCHECK_EQ(*Utils::OpenHandle(*value),
*Utils::OpenHandle(*GetEmbedderData(index)));
}
@ -1258,7 +1262,10 @@ void* Context::SlowGetAlignedPointerFromEmbedderData(int index) {
i::Handle<i::EmbedderDataArray> data =
EmbedderDataFor(this, index, false, location);
if (data.is_null()) return nullptr;
return DecodeSmiToAligned(data->get(index), location);
void* result;
Utils::ApiCheck(i::EmbedderDataSlot(*data, index).ToAlignedPointer(&result),
location, "Pointer is not aligned");
return result;
}
@ -1266,7 +1273,8 @@ void Context::SetAlignedPointerInEmbedderData(int index, void* value) {
const char* location = "v8::Context::SetAlignedPointerInEmbedderData()";
i::Handle<i::EmbedderDataArray> data =
EmbedderDataFor(this, index, true, location);
data->set(index, EncodeAlignedAsSmi(value, location));
bool ok = i::EmbedderDataSlot(*data, index).store_aligned_pointer(value);
Utils::ApiCheck(ok, location, "Pointer is not aligned");
DCHECK_EQ(value, GetAlignedPointerFromEmbedderData(index));
}

View File

@ -18,6 +18,7 @@
#include "src/objects/data-handler-inl.h"
#include "src/objects/debug-objects-inl.h"
#include "src/objects/embedder-data-array-inl.h"
#include "src/objects/embedder-data-slot-inl.h"
#include "src/objects/hash-table-inl.h"
#include "src/objects/js-array-inl.h"
#ifdef V8_INTL_SUPPORT
@ -680,8 +681,10 @@ void AliasedArgumentsEntry::AliasedArgumentsEntryVerify(Isolate* isolate) {
}
void EmbedderDataArray::EmbedderDataArrayVerify(Isolate* isolate) {
for (int i = 0; i < length(); i++) {
Object* e = get(i);
EmbedderDataSlot start(*this, 0);
EmbedderDataSlot end(*this, length());
for (EmbedderDataSlot slot = start; slot < end; ++slot) {
Object* e = slot.load_tagged();
Object::VerifyPointer(isolate, e);
}
}

View File

@ -16,6 +16,7 @@
#include "src/objects/data-handler-inl.h"
#include "src/objects/debug-objects-inl.h"
#include "src/objects/embedder-data-array-inl.h"
#include "src/objects/embedder-data-slot-inl.h"
#include "src/objects/hash-table-inl.h"
#include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h"
@ -635,6 +636,16 @@ void PrintEmbedderData(std::ostream& os, ObjectSlot slot) {
}
}
void PrintEmbedderData(std::ostream& os, EmbedderDataSlot slot) {
DisallowHeapAllocation no_gc;
Object* value = slot.load_tagged();
os << Brief(value);
void* raw_pointer;
if (slot.ToAlignedPointer(&raw_pointer)) {
os << ", aligned pointer: " << raw_pointer;
}
}
} // namespace
void JSObject::PrintElements(std::ostream& os) { // NOLINT
@ -728,9 +739,8 @@ static void JSObjectPrintBody(std::ostream& os,
if (embedder_fields > 0) {
os << " - embedder fields = {";
for (int i = 0; i < embedder_fields; i++) {
ObjectSlot embedder_data_slot = obj->GetEmbedderFieldSlot(i);
os << "\n ";
PrintEmbedderData(os, embedder_data_slot);
PrintEmbedderData(os, obj->GetEmbedderFieldSlot(i));
}
os << "\n }\n";
}
@ -994,9 +1004,9 @@ void PrintWeakArrayElements(std::ostream& os, T* array) {
void EmbedderDataArray::EmbedderDataArrayPrint(std::ostream& os) {
PrintHeader(os, "EmbedderDataArray");
os << "\n - length: " << length();
ObjectSlot start(slots_start());
ObjectSlot end(slots_end());
for (ObjectSlot slot = start; slot < end; ++slot) {
EmbedderDataSlot start(*this, 0);
EmbedderDataSlot end(*this, length());
for (EmbedderDataSlot slot = start; slot < end; ++slot) {
os << "\n ";
PrintEmbedderData(os, slot);
}

View File

@ -31,27 +31,6 @@ Address EmbedderDataArray::slots_end() {
return FIELD_ADDR(this, OffsetOfElementAt(length()));
}
Object* EmbedderDataArray::get(int index) const {
DCHECK_LT(static_cast<unsigned>(index),
static_cast<unsigned>(this->length()));
return RELAXED_READ_FIELD(this, OffsetOfElementAt(index));
}
void EmbedderDataArray::set(int index, Smi value) {
DCHECK_LT(static_cast<unsigned>(index),
static_cast<unsigned>(this->length()));
DCHECK(ObjectPtr(value).IsSmi());
RELAXED_WRITE_FIELD(this, OffsetOfElementAt(index), value);
}
void EmbedderDataArray::set(int index, Object* value) {
DCHECK_LT(static_cast<unsigned>(index),
static_cast<unsigned>(this->length()));
int offset = OffsetOfElementAt(index);
RELAXED_WRITE_FIELD(this, offset, value);
WRITE_BARRIER(this, offset, value);
}
} // namespace internal
} // namespace v8

View File

@ -7,6 +7,7 @@
#include "src/maybe-handles.h"
#include "src/objects.h"
#include "src/objects/embedder-data-slot.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@ -47,12 +48,6 @@ class EmbedderDataArray : public HeapObjectPtr {
// Code Generation support.
static constexpr int OffsetOfElementAt(int index) { return SizeFor(index); }
// TODO(ishell): remove these accessors once EmbedderDataSlot is introduced.
// Setter and getter for elements.
V8_INLINE Object* get(int index) const;
V8_INLINE void set(int index, Object* value);
V8_INLINE void set(int index, Smi value);
// Address of the first slot.
V8_INLINE Address slots_start();
@ -65,8 +60,6 @@ class EmbedderDataArray : public HeapObjectPtr {
class BodyDescriptor;
static constexpr int kEmbedderDataSlotSize = kPointerSize;
static const int kMaxSize = kMaxNewSpaceHeapObjectSize;
static constexpr int kMaxLength =
(kMaxSize - kHeaderSize) / kEmbedderDataSlotSize;

View File

@ -0,0 +1,86 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_OBJECTS_EMBEDDER_DATA_SLOT_INL_H_
#define V8_OBJECTS_EMBEDDER_DATA_SLOT_INL_H_
#include "src/heap/heap-write-barrier-inl.h"
#include "src/objects/embedder-data-array.h"
#include "src/objects/embedder-data-slot.h"
#include "src/objects/js-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
EmbedderDataSlot::EmbedderDataSlot(EmbedderDataArray array, int entry_index)
: SlotBase(FIELD_ADDR(array,
EmbedderDataArray::OffsetOfElementAt(entry_index))) {}
EmbedderDataSlot::EmbedderDataSlot(JSObject* object, int embedder_field_index)
: SlotBase(FIELD_ADDR(
object, object->GetEmbedderFieldOffset(embedder_field_index))) {}
Object* EmbedderDataSlot::load_tagged() const {
return ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Load();
}
void EmbedderDataSlot::store_smi(Smi value) {
ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Store(value);
}
// static
void EmbedderDataSlot::store_tagged(EmbedderDataArray array, int entry_index,
Object* value) {
int slot_offset = EmbedderDataArray::OffsetOfElementAt(entry_index);
ObjectSlot(FIELD_ADDR(array, slot_offset + kTaggedPayloadOffset))
.Relaxed_Store(ObjectPtr(value->ptr()));
WRITE_BARRIER(array, slot_offset, value);
}
// static
void EmbedderDataSlot::store_tagged(JSObject* object, int embedder_field_index,
Object* value) {
int slot_offset = object->GetEmbedderFieldOffset(embedder_field_index);
ObjectSlot(FIELD_ADDR(object, slot_offset + kTaggedPayloadOffset))
.Relaxed_Store(ObjectPtr(value->ptr()));
WRITE_BARRIER(object, slot_offset, value);
}
bool EmbedderDataSlot::ToAlignedPointer(void** out_pointer) const {
Object* tagged_value =
ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Load();
if (!tagged_value->IsSmi()) return false;
*out_pointer = reinterpret_cast<void*>(tagged_value);
return true;
}
bool EmbedderDataSlot::store_aligned_pointer(void* ptr) {
Address value = reinterpret_cast<Address>(ptr);
if (!HAS_SMI_TAG(value)) return false;
ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Store(Smi(value));
return true;
}
EmbedderDataSlot::RawData EmbedderDataSlot::load_raw(
const DisallowHeapAllocation& no_gc) const {
return RawData{
ObjectSlot(address() + kTaggedPayloadOffset).Relaxed_Load()->ptr(),
};
}
void EmbedderDataSlot::store_raw(const EmbedderDataSlot::RawData& data,
const DisallowHeapAllocation& no_gc) {
ObjectSlot(address() + kTaggedPayloadOffset)
.Relaxed_Store(ObjectPtr(data.data_[0]));
}
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_EMBEDDER_DATA_SLOT_INL_H_

View File

@ -0,0 +1,83 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_OBJECTS_EMBEDDER_DATA_SLOT_H_
#define V8_OBJECTS_EMBEDDER_DATA_SLOT_H_
#include <utility>
#include "src/objects/fixed-array.h"
#include "src/objects/heap-object.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
static constexpr int kEmbedderDataSlotSize = kTaggedSize;
static constexpr int kEmbedderDataSlotSizeInTaggedSlots =
kEmbedderDataSlotSize / kTaggedSize;
class EmbedderDataArray;
// An EmbedderDataSlot instance describes a kEmbedderDataSlotSize field ("slot")
// holding an embedder data which may contain raw aligned pointer or a tagged
// pointer (smi or heap object).
// Its address() is the address of the slot.
// The slot's contents can be read and written using respective load_XX() and
// store_XX() methods.
// Storing heap object through this slot may require triggering write barriers
// so this operation must be done via static store_tagged() methods.
class EmbedderDataSlot
: public SlotBase<EmbedderDataSlot, kEmbedderDataSlotSize> {
public:
EmbedderDataSlot() : SlotBase(kNullAddress) {}
V8_INLINE EmbedderDataSlot(EmbedderDataArray array, int entry_index);
V8_INLINE EmbedderDataSlot(JSObject* object, int embedder_field_index);
#ifdef V8_COMPRESS_POINTERS
static constexpr int kRawPayloadOffset = kTaggedSize;
#endif
static constexpr int kTaggedPayloadOffset = 0;
static constexpr int kRequiredPtrAlignment = kSmiTagSize;
// Opaque type used for storing raw embedder data.
struct RawData {
const Address data_[kEmbedderDataSlotSizeInTaggedSlots];
};
V8_INLINE Object* load_tagged() const;
V8_INLINE void store_smi(Smi value);
// Setting an arbitrary tagged value requires triggering a write barrier
// which requires separate object and offset values, therefore these static
// functions a
static V8_INLINE void store_tagged(EmbedderDataArray array, int entry_index,
Object* value);
static V8_INLINE void store_tagged(JSObject* object, int embedder_field_index,
Object* value);
// Tries reinterpret the value as an aligned pointer and on success sets
// *out_result to the pointer-like value and returns true. Note, that some
// Smis could still look like an aligned pointers.
// Returns false otherwise.
V8_INLINE bool ToAlignedPointer(void** out_result) const;
// Returns true if the pointer was successfully stored or false it the pointer
// was improperly aligned.
V8_INLINE V8_WARN_UNUSED_RESULT bool store_aligned_pointer(void* ptr);
V8_INLINE RawData load_raw(const DisallowHeapAllocation& no_gc) const;
V8_INLINE void store_raw(const RawData& data,
const DisallowHeapAllocation& no_gc);
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_EMBEDDER_DATA_SLOT_H_

View File

@ -2760,7 +2760,8 @@ TEST(InternalFieldsSubclassing) {
.FromJust());
// Create various levels of subclasses to stress instance size calculation.
const int kMaxNofProperties =
i::JSObject::kMaxInObjectProperties - nof_embedder_fields;
i::JSObject::kMaxInObjectProperties -
nof_embedder_fields * i::kEmbedderDataSlotSizeInTaggedSlots;
// Select only a few values to speed up the test.
int sizes[] = {0,
1,
@ -2869,7 +2870,7 @@ THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
static void CheckAlignedPointerInInternalField(Local<v8::Object> obj,
void* value) {
CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
CHECK(HAS_SMI_TAG(reinterpret_cast<i::Address>(value)));
obj->SetAlignedPointerInInternalField(0, value);
CcTest::CollectAllGarbage();
CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));