Commit 123ca158 authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[ptr-compr][ubsan] Introduce UnalignedSlot<T> - unaligned pointer adapter

... which can be used with STL algorithms.

When pointer compression is enabled the [u]intptr_t and double fields are
only kTaggedSize aligned so in order to avoid undefined behavior in C++ code
we have to access these values in an unaligned pointer friendly way although
both x64 and arm64 architectures (where pointer compression is supported)
allow unaligned access.

These changes will be removed once v8:8875 is fixed and all the
kSystemPointerSize fields are properly aligned.

Bug: v8:7703
Change-Id: If581fc00d63ae759c73b2a0f115331eea336605f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1528995Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Michael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60319}
parent d6a60a0e
......@@ -2975,7 +2975,13 @@ class TypedElementsAccessor
DisallowHeapAllocation no_gc;
BackingStore elements = BackingStore::cast(receiver->elements());
ctype* data = static_cast<ctype*>(elements->DataPtr());
#ifdef V8_COMPRESS_POINTERS
// TODO(ishell, v8:8875): See UnalignedSlot<T> for details.
std::fill(UnalignedSlot<ctype>(data + start),
UnalignedSlot<ctype>(data + end), value);
#else
std::fill(data + start, data + end, value);
#endif
return *array;
}
......@@ -3148,7 +3154,12 @@ class TypedElementsAccessor
if (len == 0) return;
ctype* data = static_cast<ctype*>(elements->DataPtr());
#ifdef V8_COMPRESS_POINTERS
// TODO(ishell, v8:8875): See UnalignedSlot<T> for details.
std::reverse(UnalignedSlot<ctype>(data), UnalignedSlot<ctype>(data + len));
#else
std::reverse(data, data + len);
#endif
}
static Handle<FixedArray> CreateListFromArrayLikeImpl(Isolate* isolate,
......
......@@ -23,7 +23,7 @@ namespace internal {
// // Decompress a and b if necessary.
// return my_comparison(a, b);
// });
// Note how the comparator operates on Address values, representing the raw
// Note how the comparator operates on Tagged_t values, representing the raw
// data found at the given heap location, so you probably want to construct
// an Object from it.
class AtomicSlot : public SlotBase<AtomicSlot, Tagged_t> {
......
......@@ -6,6 +6,7 @@
#define V8_OBJECTS_SLOTS_H_
#include "src/globals.h"
#include "src/v8memory.h"
namespace v8 {
namespace internal {
......@@ -174,6 +175,84 @@ class FullHeapObjectSlot : public SlotBase<FullHeapObjectSlot, Address> {
inline void StoreHeapObject(HeapObject value) const;
};
// TODO(ishell, v8:8875): When pointer compression is enabled the [u]intptr_t
// and double fields are only kTaggedSize aligned so in order to avoid undefined
// behavior in C++ code we use this iterator adaptor when using STL algorithms
// with unaligned pointers.
// It will be removed once all v8:8875 is fixed and all the full pointer and
// double values in compressed V8 heap are properly aligned.
template <typename T>
class UnalignedSlot : public SlotBase<UnalignedSlot<T>, T, 1> {
public:
// This class is a stand-in for "T&" that uses custom read/write operations
// for the actual memory accesses.
class Reference {
public:
explicit Reference(Address address) : address_(address) {}
Reference(const Reference&) V8_NOEXCEPT = default;
Reference& operator=(const Reference& other) V8_NOEXCEPT {
WriteUnalignedValue<T>(address_, other.value());
return *this;
}
Reference& operator=(T value) {
WriteUnalignedValue<T>(address_, value);
return *this;
}
// Values of type UnalignedSlot::reference must be implicitly convertible
// to UnalignedSlot::value_type.
operator T() const { return value(); }
void swap(Reference& other) {
T tmp = value();
WriteUnalignedValue<T>(address_, other.value());
WriteUnalignedValue<T>(other.address_, tmp);
}
bool operator<(const Reference& other) const {
return value() < other.value();
}
bool operator==(const Reference& other) const {
return value() == other.value();
}
private:
T value() const { return ReadUnalignedValue<T>(address_); }
Address address_;
};
// The rest of this class follows C++'s "RandomAccessIterator" requirements.
// Most of the heavy lifting is inherited from SlotBase.
typedef int difference_type;
typedef T value_type;
typedef Reference reference;
typedef T* pointer;
typedef std::random_access_iterator_tag iterator_category;
UnalignedSlot() : SlotBase<UnalignedSlot<T>, T, 1>(kNullAddress) {}
explicit UnalignedSlot(Address address)
: SlotBase<UnalignedSlot<T>, T, 1>(address) {}
explicit UnalignedSlot(T* address)
: SlotBase<UnalignedSlot<T>, T, 1>(reinterpret_cast<Address>(address)) {}
Reference operator*() const {
return Reference(SlotBase<UnalignedSlot<T>, T, 1>::address());
}
Reference operator[](difference_type i) const {
return Reference(SlotBase<UnalignedSlot<T>, T, 1>::address() +
i * sizeof(T));
}
friend void swap(Reference lhs, Reference rhs) { lhs.swap(rhs); }
friend difference_type operator-(UnalignedSlot a, UnalignedSlot b) {
return static_cast<int>(a.address() - b.address()) / sizeof(T);
}
};
} // namespace internal
} // namespace v8
......
......@@ -125,15 +125,21 @@ RUNTIME_FUNCTION(Runtime_TypedArraySortFast) {
Handle<FixedTypedArrayBase> elements(
FixedTypedArrayBase::cast(array->elements()), isolate);
switch (array->type()) {
#define TYPED_ARRAY_SORT(Type, type, TYPE, ctype) \
case kExternal##Type##Array: { \
ctype* data = static_cast<ctype*>(elements->DataPtr()); \
if (kExternal##Type##Array == kExternalFloat64Array || \
kExternal##Type##Array == kExternalFloat32Array) \
std::sort(data, data + length, CompareNum<ctype>); \
else \
std::sort(data, data + length); \
break; \
#define TYPED_ARRAY_SORT(Type, type, TYPE, ctype) \
case kExternal##Type##Array: { \
ctype* data = static_cast<ctype*>(elements->DataPtr()); \
if (COMPRESS_POINTERS_BOOL && \
kExternal##Type##Array == kExternalFloat64Array) { \
/* TODO(ishell, v8:8875): See UnalignedSlot<T> for details. */ \
std::sort(UnalignedSlot<ctype>(data), \
UnalignedSlot<ctype>(data + length), CompareNum<ctype>); \
} else if (kExternal##Type##Array == kExternalFloat64Array || \
kExternal##Type##Array == kExternalFloat32Array) { \
std::sort(data, data + length, CompareNum<ctype>); \
} else { \
std::sort(data, data + length); \
} \
break; \
}
TYPED_ARRAYS(TYPED_ARRAY_SORT)
......
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