Commit 806ef9ac authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[sandbox] Access external pointer in JSTypedArray via bottlenecks

Bug: v8:10391
Change-Id: If1db52dc74f9027f06104ce719514b751b4d9504
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2149417
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67515}
parent 35655a8e
...@@ -397,8 +397,8 @@ void TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr( ...@@ -397,8 +397,8 @@ void TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr(
} }
StoreObjectField(holder, JSTypedArray::kBasePointerOffset, base); StoreObjectField(holder, JSTypedArray::kBasePointerOffset, base);
StoreObjectFieldNoWriteBarrier<UintPtrT>( StoreJSTypedArrayExternalPointer(
holder, JSTypedArray::kExternalPointerOffset, offset); holder, EncodeExternalPointer(ReinterpretCast<RawPtrT>(offset)));
} }
void TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr( void TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr(
...@@ -407,8 +407,7 @@ void TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr( ...@@ -407,8 +407,7 @@ void TypedArrayBuiltinsAssembler::SetJSTypedArrayOffHeapDataPtr(
SmiConstant(0)); SmiConstant(0));
base = RawPtrAdd(base, Signed(offset)); base = RawPtrAdd(base, Signed(offset));
StoreObjectFieldNoWriteBarrier<RawPtrT>( StoreJSTypedArrayExternalPointer(holder, EncodeExternalPointer(base));
holder, JSTypedArray::kExternalPointerOffset, base);
} }
void TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric( void TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric(
......
...@@ -2228,9 +2228,10 @@ TNode<IntPtrT> CodeStubAssembler::LoadPropertyArrayLength( ...@@ -2228,9 +2228,10 @@ TNode<IntPtrT> CodeStubAssembler::LoadPropertyArrayLength(
TNode<RawPtrT> CodeStubAssembler::LoadJSTypedArrayDataPtr( TNode<RawPtrT> CodeStubAssembler::LoadJSTypedArrayDataPtr(
TNode<JSTypedArray> typed_array) { TNode<JSTypedArray> typed_array) {
// Data pointer = external_pointer + static_cast<Tagged_t>(base_pointer). // Data pointer = DecodeExternalPointer(external_pointer) +
TNode<RawPtrT> external_pointer = LoadObjectField<RawPtrT>( // static_cast<Tagged_t>(base_pointer).
typed_array, JSTypedArray::kExternalPointerOffset); TNode<RawPtrT> external_pointer =
DecodeExternalPointer(LoadJSTypedArrayExternalPointer(typed_array));
TNode<IntPtrT> base_pointer; TNode<IntPtrT> base_pointer;
if (COMPRESS_POINTERS_BOOL) { if (COMPRESS_POINTERS_BOOL) {
......
...@@ -1079,6 +1079,18 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -1079,6 +1079,18 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
return value; return value;
} }
// Convert external pointer value to on-V8-heap representation.
// This should eventually become a call to a non-allocating runtime function.
TNode<ExternalPointerT> EncodeExternalPointer(TNode<RawPtrT> pointer) {
STATIC_ASSERT(kExternalPointerSize == kSystemPointerSize);
TNode<RawPtrT> encoded_pointer = pointer;
if (V8_HEAP_SANDBOX_BOOL) {
encoded_pointer = UncheckedCast<RawPtrT>(
WordXor(encoded_pointer, UintPtrConstant(kExternalPointerSalt)));
}
return ReinterpretCast<ExternalPointerT>(encoded_pointer);
}
// Load value from current parent frame by given offset in bytes. // Load value from current parent frame by given offset in bytes.
TNode<Object> LoadFromParentFrame(int offset); TNode<Object> LoadFromParentFrame(int offset);
......
...@@ -420,7 +420,8 @@ FieldAccess AccessBuilder::ForJSTypedArrayExternalPointer() { ...@@ -420,7 +420,8 @@ FieldAccess AccessBuilder::ForJSTypedArrayExternalPointer() {
JSTypedArray::kExternalPointerOffset, JSTypedArray::kExternalPointerOffset,
MaybeHandle<Name>(), MaybeHandle<Name>(),
MaybeHandle<Map>(), MaybeHandle<Map>(),
Type::ExternalPointer(), V8_HEAP_SANDBOX_BOOL ? Type::SandboxedExternalPointer()
: Type::ExternalPointer(),
MachineType::Pointer(), MachineType::Pointer(),
kNoWriteBarrier, kNoWriteBarrier,
LoadSensitivity::kCritical}; LoadSensitivity::kCritical};
......
...@@ -2675,7 +2675,8 @@ Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type, ...@@ -2675,7 +2675,8 @@ Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type,
Handle<JSTypedArray>::cast(NewJSArrayBufferView( Handle<JSTypedArray>::cast(NewJSArrayBufferView(
map, empty_byte_array(), buffer, byte_offset, byte_length)); map, empty_byte_array(), buffer, byte_offset, byte_length));
typed_array->set_length(length); typed_array->set_length(length);
typed_array->SetOffHeapDataPtr(buffer->backing_store(), byte_offset); typed_array->SetOffHeapDataPtr(isolate(), buffer->backing_store(),
byte_offset);
return typed_array; return typed_array;
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "src/objects/js-array-buffer.h" #include "src/objects/js-array-buffer.h"
#include "src/common/external-pointer-inl.h"
#include "src/heap/heap-write-barrier-inl.h" #include "src/heap/heap-write-barrier-inl.h"
#include "src/objects/js-objects-inl.h" #include "src/objects/js-objects-inl.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
...@@ -185,12 +186,15 @@ void JSTypedArray::set_length(size_t value) { ...@@ -185,12 +186,15 @@ void JSTypedArray::set_length(size_t value) {
WriteField<size_t>(kLengthOffset, value); WriteField<size_t>(kLengthOffset, value);
} }
Address JSTypedArray::external_pointer() const { DEF_GETTER(JSTypedArray, external_pointer, Address) {
return ReadField<Address>(kExternalPointerOffset); ExternalPointer_t encoded_value =
ReadField<ExternalPointer_t>(kExternalPointerOffset);
return DecodeExternalPointer(isolate, encoded_value);
} }
void JSTypedArray::set_external_pointer(Address value) { void JSTypedArray::set_external_pointer(Isolate* isolate, Address value) {
WriteField<Address>(kExternalPointerOffset, value); ExternalPointer_t encoded_value = EncodeExternalPointer(isolate, value);
WriteField<ExternalPointer_t>(kExternalPointerOffset, encoded_value);
} }
Address JSTypedArray::ExternalPointerCompensationForOnHeapArray( Address JSTypedArray::ExternalPointerCompensationForOnHeapArray(
...@@ -202,11 +206,29 @@ Address JSTypedArray::ExternalPointerCompensationForOnHeapArray( ...@@ -202,11 +206,29 @@ Address JSTypedArray::ExternalPointerCompensationForOnHeapArray(
#endif #endif
} }
void JSTypedArray::RemoveExternalPointerCompensationForSerialization() { uint32_t JSTypedArray::GetExternalBackingStoreRefForDeserialization() const {
DCHECK(!is_on_heap());
ExternalPointer_t encoded_value =
ReadField<ExternalPointer_t>(kExternalPointerOffset);
return static_cast<uint32_t>(encoded_value);
}
void JSTypedArray::SetExternalBackingStoreRefForSerialization(uint32_t ref) {
DCHECK(!is_on_heap());
ExternalPointer_t encoded_value = ref;
WriteField<ExternalPointer_t>(kExternalPointerOffset, encoded_value);
}
void JSTypedArray::RemoveExternalPointerCompensationForSerialization(
Isolate* isolate) {
DCHECK(is_on_heap()); DCHECK(is_on_heap());
const Isolate* isolate = GetIsolateForPtrCompr(*this); // TODO(v8:10391): once we have an external table, avoid the need for
set_external_pointer(external_pointer() - // compensation by replacing external_pointer and base_pointer fields
ExternalPointerCompensationForOnHeapArray(isolate)); // with one data_pointer field which can point to either external data
// backing store or into on-heap backing store.
set_external_pointer(
isolate,
external_pointer() - ExternalPointerCompensationForOnHeapArray(isolate));
} }
ACCESSORS(JSTypedArray, base_pointer, Object, kBasePointerOffset) ACCESSORS(JSTypedArray, base_pointer, Object, kBasePointerOffset)
...@@ -220,18 +242,19 @@ void* JSTypedArray::DataPtr() { ...@@ -220,18 +242,19 @@ void* JSTypedArray::DataPtr() {
static_cast<Tagged_t>(base_pointer().ptr())); static_cast<Tagged_t>(base_pointer().ptr()));
} }
void JSTypedArray::SetOffHeapDataPtr(void* base, Address offset) { void JSTypedArray::SetOffHeapDataPtr(Isolate* isolate, void* base,
Address offset) {
set_base_pointer(Smi::zero(), SKIP_WRITE_BARRIER); set_base_pointer(Smi::zero(), SKIP_WRITE_BARRIER);
Address address = reinterpret_cast<Address>(base) + offset; Address address = reinterpret_cast<Address>(base) + offset;
set_external_pointer(address); set_external_pointer(isolate, address);
DCHECK_EQ(address, reinterpret_cast<Address>(DataPtr())); DCHECK_EQ(address, reinterpret_cast<Address>(DataPtr()));
} }
void JSTypedArray::SetOnHeapDataPtr(HeapObject base, Address offset) { void JSTypedArray::SetOnHeapDataPtr(Isolate* isolate, HeapObject base,
Address offset) {
set_base_pointer(base); set_base_pointer(base);
const Isolate* isolate = GetIsolateForPtrCompr(*this); set_external_pointer(
set_external_pointer(offset + isolate, offset + ExternalPointerCompensationForOnHeapArray(isolate));
ExternalPointerCompensationForOnHeapArray(isolate));
DCHECK_EQ(base.ptr() + offset, reinterpret_cast<Address>(DataPtr())); DCHECK_EQ(base.ptr() + offset, reinterpret_cast<Address>(DataPtr()));
} }
......
...@@ -193,7 +193,7 @@ Handle<JSArrayBuffer> JSTypedArray::GetBuffer() { ...@@ -193,7 +193,7 @@ Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
// Clear the elements of the typed array. // Clear the elements of the typed array.
self->set_elements(ReadOnlyRoots(isolate).empty_byte_array()); self->set_elements(ReadOnlyRoots(isolate).empty_byte_array());
self->SetOffHeapDataPtr(array_buffer->backing_store(), 0); self->SetOffHeapDataPtr(isolate, array_buffer->backing_store(), 0);
DCHECK(!self->is_on_heap()); DCHECK(!self->is_on_heap());
return array_buffer; return array_buffer;
......
...@@ -270,8 +270,9 @@ class JSTypedArray : public JSArrayBufferView { ...@@ -270,8 +270,9 @@ class JSTypedArray : public JSArrayBufferView {
// Use with care: returns raw pointer into heap. // Use with care: returns raw pointer into heap.
inline void* DataPtr(); inline void* DataPtr();
inline void SetOffHeapDataPtr(void* base, Address offset); inline void SetOffHeapDataPtr(Isolate* isolate, void* base, Address offset);
inline void SetOnHeapDataPtr(HeapObject base, Address offset); inline void SetOnHeapDataPtr(Isolate* isolate, HeapObject base,
Address offset);
// Whether the buffer's backing store is on-heap or off-heap. // Whether the buffer's backing store is on-heap or off-heap.
inline bool is_on_heap() const; inline bool is_on_heap() const;
...@@ -288,8 +289,21 @@ class JSTypedArray : public JSArrayBufferView { ...@@ -288,8 +289,21 @@ class JSTypedArray : public JSArrayBufferView {
static inline Address ExternalPointerCompensationForOnHeapArray( static inline Address ExternalPointerCompensationForOnHeapArray(
const Isolate* isolate); const Isolate* isolate);
//
// Serializer/deserializer support.
//
// External backing stores are serialized/deserialized separately.
// During serialization the backing store reference is stored in the typed
// array object and upon deserialization it is converted back to actual
// external (off-heap) pointer value.
// The backing store reference is stored in the external_pointer field.
inline uint32_t GetExternalBackingStoreRefForDeserialization() const;
inline void SetExternalBackingStoreRefForSerialization(uint32_t ref);
// Subtracts external pointer compensation from the external pointer value. // Subtracts external pointer compensation from the external pointer value.
inline void RemoveExternalPointerCompensationForSerialization(); inline void RemoveExternalPointerCompensationForSerialization(
Isolate* isolate);
static inline MaybeHandle<JSTypedArray> Validate(Isolate* isolate, static inline MaybeHandle<JSTypedArray> Validate(Isolate* isolate,
Handle<Object> receiver, Handle<Object> receiver,
...@@ -300,12 +314,12 @@ class JSTypedArray : public JSArrayBufferView { ...@@ -300,12 +314,12 @@ class JSTypedArray : public JSArrayBufferView {
DECL_VERIFIER(JSTypedArray) DECL_VERIFIER(JSTypedArray)
// Layout description. // Layout description.
#define JS_TYPED_ARRAY_FIELDS(V) \ #define JS_TYPED_ARRAY_FIELDS(V) \
/* Raw data fields. */ \ /* Raw data fields. */ \
V(kLengthOffset, kUIntptrSize) \ V(kLengthOffset, kUIntptrSize) \
V(kExternalPointerOffset, kSystemPointerSize) \ V(kExternalPointerOffset, kExternalPointerSize) \
V(kBasePointerOffset, kTaggedSize) \ V(kBasePointerOffset, kTaggedSize) \
/* Header size. */ \ /* Header size. */ \
V(kHeaderSize, 0) V(kHeaderSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSArrayBufferView::kHeaderSize, DEFINE_FIELD_OFFSET_CONSTANTS(JSArrayBufferView::kHeaderSize,
...@@ -334,7 +348,8 @@ class JSTypedArray : public JSArrayBufferView { ...@@ -334,7 +348,8 @@ class JSTypedArray : public JSArrayBufferView {
DECL_ACCESSORS(base_pointer, Object) DECL_ACCESSORS(base_pointer, Object)
// [external_pointer]: TODO(v8:4153) // [external_pointer]: TODO(v8:4153)
DECL_PRIMITIVE_ACCESSORS(external_pointer, Address) DECL_GETTER(external_pointer, Address)
inline void set_external_pointer(Isolate* isolate, Address value);
OBJECT_CONSTRUCTORS(JSTypedArray, JSArrayBufferView); OBJECT_CONSTRUCTORS(JSTypedArray, JSArrayBufferView);
}; };
......
...@@ -39,7 +39,7 @@ extern class JSArrayBufferView extends JSObject { ...@@ -39,7 +39,7 @@ extern class JSArrayBufferView extends JSObject {
extern class JSTypedArray extends JSArrayBufferView { extern class JSTypedArray extends JSArrayBufferView {
length: uintptr; length: uintptr;
external_pointer: RawPtr; external_pointer: ExternalPointer;
base_pointer: ByteArray|Smi; base_pointer: ByteArray|Smi;
} }
......
...@@ -300,16 +300,19 @@ HeapObject Deserializer::PostProcessNewObject(HeapObject obj, ...@@ -300,16 +300,19 @@ HeapObject Deserializer::PostProcessNewObject(HeapObject obj,
JSTypedArray typed_array = JSTypedArray::cast(obj); JSTypedArray typed_array = JSTypedArray::cast(obj);
// Fixup typed array pointers. // Fixup typed array pointers.
if (typed_array.is_on_heap()) { if (typed_array.is_on_heap()) {
typed_array.SetOnHeapDataPtr(HeapObject::cast(typed_array.base_pointer()), typed_array.SetOnHeapDataPtr(isolate(),
HeapObject::cast(typed_array.base_pointer()),
typed_array.external_pointer()); typed_array.external_pointer());
} else { } else {
// Serializer writes backing store ref as a DataPtr() value. // Serializer writes backing store ref as a DataPtr() value.
size_t store_index = reinterpret_cast<size_t>(typed_array.DataPtr()); uint32_t store_index =
typed_array.GetExternalBackingStoreRefForDeserialization();
auto backing_store = backing_stores_[store_index]; auto backing_store = backing_stores_[store_index];
auto start = backing_store auto start = backing_store
? reinterpret_cast<byte*>(backing_store->buffer_start()) ? reinterpret_cast<byte*>(backing_store->buffer_start())
: nullptr; : nullptr;
typed_array.SetOffHeapDataPtr(start, typed_array.byte_offset()); typed_array.SetOffHeapDataPtr(isolate(), start,
typed_array.byte_offset());
} }
} else if (obj.IsJSArrayBuffer()) { } else if (obj.IsJSArrayBuffer()) {
JSArrayBuffer buffer = JSArrayBuffer::cast(obj); JSArrayBuffer buffer = JSArrayBuffer::cast(obj);
......
...@@ -353,7 +353,8 @@ uint32_t Serializer::ObjectSerializer::SerializeBackingStore( ...@@ -353,7 +353,8 @@ uint32_t Serializer::ObjectSerializer::SerializeBackingStore(
void Serializer::ObjectSerializer::SerializeJSTypedArray() { void Serializer::ObjectSerializer::SerializeJSTypedArray() {
JSTypedArray typed_array = JSTypedArray::cast(object_); JSTypedArray typed_array = JSTypedArray::cast(object_);
if (typed_array.is_on_heap()) { if (typed_array.is_on_heap()) {
typed_array.RemoveExternalPointerCompensationForSerialization(); typed_array.RemoveExternalPointerCompensationForSerialization(
serializer_->isolate());
} else { } else {
if (!typed_array.WasDetached()) { if (!typed_array.WasDetached()) {
// Explicitly serialize the backing store now. // Explicitly serialize the backing store now.
...@@ -369,13 +370,9 @@ void Serializer::ObjectSerializer::SerializeJSTypedArray() { ...@@ -369,13 +370,9 @@ void Serializer::ObjectSerializer::SerializeJSTypedArray() {
reinterpret_cast<Address>(typed_array.DataPtr()) - byte_offset); reinterpret_cast<Address>(typed_array.DataPtr()) - byte_offset);
uint32_t ref = SerializeBackingStore(backing_store, byte_length); uint32_t ref = SerializeBackingStore(backing_store, byte_length);
// To properly share the buffer, we set the backing store ref as an typed_array.SetExternalBackingStoreRefForSerialization(ref);
// off-heap offset from nullptr. On deserialization we re-set data
// pointer to proper value.
typed_array.SetOffHeapDataPtr(nullptr, ref);
DCHECK_EQ(ref, reinterpret_cast<Address>(typed_array.DataPtr()));
} else { } else {
typed_array.SetOffHeapDataPtr(nullptr, 0); typed_array.SetExternalBackingStoreRefForSerialization(0);
} }
} }
SerializeObject(); SerializeObject();
......
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