[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:
parent
5065c20a7e
commit
ea9f847d36
2
BUILD.gn
2
BUILD.gn
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
16
src/api.cc
16
src/api.cc
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
86
src/objects/embedder-data-slot-inl.h
Normal file
86
src/objects/embedder-data-slot-inl.h
Normal 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_
|
83
src/objects/embedder-data-slot.h
Normal file
83
src/objects/embedder-data-slot.h
Normal 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_
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user