Commit 46573e51 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[es2015] Introduce JSDataView::external_pointer.

This adds a new external_pointer field to every JSDataView instance
which points directly into the backing store at the given view's
byte_offset. This was the DataView performance is now almost on
par with the TypedArray performance for accessing aligned memory
(with appropriate endianess). This also serves as prepatory work
to enable full 64-bit addressing of DataView backing stores in
optimized code (soonish).

This change optimizes the bounds checking sequence in TurboFan in
such a way that it further improves the DataView set/get performance
by around 10%, almost closing the remaining gap between DataViews
and TypedArrays.

Drive-by-fix: Get rid of the code duplication around DataView inlining
in the JSCallReducer and have only a single bottleneck method now.

Bug: chromium:225811, v8:4153, v8:7881, v8:8171
Change-Id: I9118efd4d19e93f0e51c931a9bec1a56a0f4593e
Reviewed-on: https://chromium-review.googlesource.com/1231994
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56042}
parent 8f30ab32
......@@ -101,6 +101,8 @@ BUILTIN(DataViewConstructor) {
// 13. Set O's [[ByteOffset]] internal slot to offset.
Handle<JSDataView>::cast(result)->set_byte_offset(view_byte_offset);
Handle<JSDataView>::cast(result)->set_external_pointer(
static_cast<uint8_t*>(array_buffer->backing_store()) + view_byte_offset);
// 14. Return O.
return *result;
......
This diff is collapsed.
......@@ -12263,6 +12263,12 @@ TNode<UintPtrT> CodeStubAssembler::LoadJSArrayBufferViewByteOffset(
JSArrayBufferView::kByteOffsetOffset);
}
TNode<RawPtrT> CodeStubAssembler::LoadJSDataViewExternalPointer(
TNode<JSDataView> data_view) {
return LoadObjectField<RawPtrT>(data_view,
JSDataView::kExternalPointerOffset);
}
TNode<Smi> CodeStubAssembler::LoadJSTypedArrayLength(
TNode<JSTypedArray> typed_array) {
return LoadObjectField<Smi>(typed_array, JSTypedArray::kLengthOffset);
......
......@@ -2789,6 +2789,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
SloppyTNode<Context> context, TNode<JSArrayBufferView> array_buffer_view,
const char* method_name);
// JSDataView helpers
TNode<RawPtrT> LoadJSDataViewExternalPointer(TNode<JSDataView> data_view);
// JSTypedArray helpers
TNode<Smi> LoadJSTypedArrayLength(TNode<JSTypedArray> typed_array);
......
......@@ -375,6 +375,18 @@ FieldAccess AccessBuilder::ForJSArrayBufferViewByteOffset() {
return access;
}
// static
FieldAccess AccessBuilder::ForJSDataViewExternalPointer() {
FieldAccess access = {kTaggedBase,
JSDataView::kExternalPointerOffset,
MaybeHandle<Name>(),
MaybeHandle<Map>(),
Type::ExternalPointer(),
MachineType::Pointer(),
kNoWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForJSTypedArrayLength() {
FieldAccess access = {kTaggedBase,
......
......@@ -130,6 +130,9 @@ class V8_EXPORT_PRIVATE AccessBuilder final
// Provides access to JSArrayBufferView::byteOffset() field.
static FieldAccess ForJSArrayBufferViewByteOffset();
// Provides access to JSDataView::external_pointer() field.
static FieldAccess ForJSDataViewExternalPointer();
// Provides access to JSTypedArray::length() field.
static FieldAccess ForJSTypedArrayLength();
......
This diff is collapsed.
......@@ -182,6 +182,9 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
InstanceType instance_type,
FieldAccess const& access);
enum class DataViewAccess { kGet, kSet };
Reduction ReduceDataViewAccess(Node* node, DataViewAccess access,
ExternalArrayType element_type);
Reduction ReduceDataViewPrototypeGet(Node* node,
ExternalArrayType element_type);
Reduction ReduceDataViewPrototypeSet(Node* node,
......
......@@ -184,7 +184,11 @@ class ConcurrentMarkingVisitor final
return VisitJSObjectSubclass(map, object);
}
int VisitJSArrayBufferView(Map* map, JSArrayBufferView* object) {
int VisitJSDataView(Map* map, JSDataView* object) {
return VisitJSObjectSubclass(map, object);
}
int VisitJSTypedArray(Map* map, JSTypedArray* object) {
return VisitJSObjectSubclass(map, object);
}
......
......@@ -21,8 +21,9 @@ class BigInt;
class BytecodeArray;
class DataHandler;
class JSArrayBuffer;
class JSArrayBufferView;
class JSDataView;
class JSRegExp;
class JSTypedArray;
class JSWeakCollection;
class UncompiledDataWithoutPreParsedScope;
class UncompiledDataWithPreParsedScope;
......@@ -45,8 +46,9 @@ class UncompiledDataWithPreParsedScope;
V(FixedFloat64Array) \
V(FixedTypedArrayBase) \
V(JSArrayBuffer) \
V(JSArrayBufferView) \
V(JSDataView) \
V(JSObject) \
V(JSTypedArray) \
V(JSWeakCollection) \
V(Map) \
V(Oddball) \
......
......@@ -228,24 +228,51 @@ class JSArrayBuffer::BodyDescriptor final : public BodyDescriptorBase {
}
};
class JSArrayBufferView::BodyDescriptor final : public BodyDescriptorBase {
class JSDataView::BodyDescriptor final : public BodyDescriptorBase {
public:
STATIC_ASSERT(kBufferOffset + kPointerSize == kByteOffsetOffset);
STATIC_ASSERT(kByteOffsetOffset + kUIntptrSize == kByteLengthOffset);
STATIC_ASSERT(kByteLengthOffset + kUIntptrSize == kHeaderSize);
STATIC_ASSERT(kByteLengthOffset + kUIntptrSize == kExternalPointerOffset);
STATIC_ASSERT(kExternalPointerOffset + kPointerSize == kSize);
static bool IsValidSlot(Map* map, HeapObject* obj, int offset) {
if (offset < kByteOffsetOffset) return true;
if (offset < kHeaderSize) return false;
if (offset < kSize) return false;
return IsValidSlotImpl(map, obj, offset);
}
template <typename ObjectVisitor>
static inline void IterateBody(Map* map, HeapObject* obj, int object_size,
ObjectVisitor* v) {
// JSDataView instances contain raw data that the GC does not know about.
IteratePointers(obj, kPropertiesOrHashOffset, kByteOffsetOffset, v);
IterateBodyImpl(map, obj, kSize, object_size, v);
}
static inline int SizeOf(Map* map, HeapObject* object) {
return map->instance_size();
}
};
class JSTypedArray::BodyDescriptor final : public BodyDescriptorBase {
public:
STATIC_ASSERT(kBufferOffset + kPointerSize == kByteOffsetOffset);
STATIC_ASSERT(kByteOffsetOffset + kUIntptrSize == kByteLengthOffset);
STATIC_ASSERT(kByteLengthOffset + kUIntptrSize == kLengthOffset);
STATIC_ASSERT(kLengthOffset + kPointerSize == kSize);
static bool IsValidSlot(Map* map, HeapObject* obj, int offset) {
if (offset < kByteOffsetOffset) return true;
if (offset < kSize) return false;
return IsValidSlotImpl(map, obj, offset);
}
template <typename ObjectVisitor>
static inline void IterateBody(Map* map, HeapObject* obj, int object_size,
ObjectVisitor* v) {
// JSArrayBufferView contains raw data that the GC does not know about.
// JSTypedArray instances contain raw data that the GC does not know about.
IteratePointers(obj, kPropertiesOrHashOffset, kByteOffsetOffset, v);
IterateBodyImpl(map, obj, kHeaderSize, object_size, v);
IterateBodyImpl(map, obj, kSize, object_size, v);
}
static inline int SizeOf(Map* map, HeapObject* object) {
......
......@@ -3161,8 +3161,10 @@ VisitorId Map::GetVisitorId(Map* map) {
return kVisitJSArrayBuffer;
case JS_DATA_VIEW_TYPE:
return kVisitJSDataView;
case JS_TYPED_ARRAY_TYPE:
return kVisitJSArrayBufferView;
return kVisitJSTypedArray;
case SMALL_ORDERED_HASH_MAP_TYPE:
return kVisitSmallOrderedHashMap;
......
......@@ -33,7 +33,7 @@ void* JSArrayBuffer::backing_store() const {
return reinterpret_cast<void*>(ptr);
}
void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) {
void JSArrayBuffer::set_backing_store(void* value) {
intptr_t ptr = reinterpret_cast<intptr_t>(value);
WRITE_INTPTR_FIELD(this, kBackingStoreOffset, ptr);
}
......@@ -184,6 +184,16 @@ MaybeHandle<JSTypedArray> JSTypedArray::Validate(Isolate* isolate,
ACCESSORS(JSTypedArray, raw_length, Object, kLengthOffset)
#endif
void* JSDataView::external_pointer() const {
intptr_t ptr = READ_INTPTR_FIELD(this, kExternalPointerOffset);
return reinterpret_cast<void*>(ptr);
}
void JSDataView::set_external_pointer(void* value) {
intptr_t ptr = reinterpret_cast<intptr_t>(value);
WRITE_INTPTR_FIELD(this, kExternalPointerOffset, ptr);
}
} // namespace internal
} // namespace v8
......
......@@ -32,7 +32,7 @@ class JSArrayBuffer : public JSObject {
DECL_PRIMITIVE_ACCESSORS(byte_length, size_t)
// [backing_store]: backing memory for this array
DECL_ACCESSORS(backing_store, void)
DECL_PRIMITIVE_ACCESSORS(backing_store, void*)
// For non-wasm, allocation_length and allocation_base are byte_length and
// backing_store, respectively.
......@@ -156,10 +156,6 @@ class JSArrayBufferView : public JSObject {
static const int kByteLengthOffset = kByteOffsetOffset + kUIntptrSize;
static const int kHeaderSize = kByteLengthOffset + kUIntptrSize;
// Iterates all fields in the object including internal ones except
// kByteOffset and kByteLengthOffset.
class BodyDescriptor;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBufferView);
};
......@@ -198,6 +194,10 @@ class JSTypedArray : public JSArrayBufferView {
static const int kSizeWithEmbedderFields =
kSize + v8::ArrayBufferView::kEmbedderFieldCount * kPointerSize;
// Iterates all fields in the object including internal ones except
// kByteOffsetOffset, kByteLengthOffset and kLengthOffset.
class BodyDescriptor;
private:
static Handle<JSArrayBuffer> MaterializeArrayBuffer(
Handle<JSTypedArray> typed_array);
......@@ -210,16 +210,25 @@ class JSTypedArray : public JSArrayBufferView {
class JSDataView : public JSArrayBufferView {
public:
// [external_pointer]: Points into the actual backing store at the
// byte offset of this data view.
DECL_PRIMITIVE_ACCESSORS(external_pointer, void*)
DECL_CAST(JSDataView)
// Dispatched behavior.
DECL_PRINTER(JSDataView)
DECL_VERIFIER(JSDataView)
static const int kSize = JSArrayBufferView::kHeaderSize;
static const int kExternalPointerOffset = JSArrayBufferView::kHeaderSize;
static const int kSize = kExternalPointerOffset + kPointerSize;
static const int kSizeWithEmbedderFields =
kSize + v8::ArrayBufferView::kEmbedderFieldCount * kPointerSize;
// Iterates all fields in the object including internal ones except
// kByteOffsetOffset, kByteLengthOffset and kExternalPointerOffset.
class BodyDescriptor;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSDataView);
};
......
......@@ -37,9 +37,10 @@ namespace internal {
V(FreeSpace) \
V(JSApiObject) \
V(JSArrayBuffer) \
V(JSArrayBufferView) \
V(JSDataView) \
V(JSObject) \
V(JSObjectFast) \
V(JSTypedArray) \
V(JSWeakCollection) \
V(Map) \
V(NativeContext) \
......
......@@ -241,6 +241,13 @@ HeapObject* Deserializer<AllocatorT>::PostProcessNewObject(HeapObject* obj,
buffer->set_backing_store(backing_store);
isolate_->heap()->RegisterNewArrayBuffer(buffer);
}
} else if (obj->IsJSDataView()) {
// Fixup the JSDataView::external_pointer field.
JSDataView* data_view = JSDataView::cast(obj);
JSArrayBuffer* buffer = JSArrayBuffer::cast(data_view->buffer());
data_view->set_external_pointer(
reinterpret_cast<uint8_t*>(buffer->backing_store()) +
data_view->byte_offset());
} else if (obj->IsFixedTypedArrayBase()) {
FixedTypedArrayBase* fta = FixedTypedArrayBase::cast(obj);
// Only fixup for the off-heap case.
......
......@@ -708,6 +708,15 @@ void Serializer<AllocatorT>::ObjectSerializer::SerializeContent(Map* map,
object_->IterateBody(map, size, this);
// Finally skip to the end.
serializer_->FlushSkip(SkipTo(object_->address() + size));
} else if (object_->IsJSDataView()) {
// JSDataView::external_pointer() contains a raw pointer. Change it
// to nullptr for serialization to keep the snapshot predictable.
JSDataView* data_view = JSDataView::cast(object_);
void* external_pointer = data_view->external_pointer();
data_view->set_external_pointer(nullptr);
object_->IterateBody(map, size, this);
OutputRawData(object_->address() + size);
data_view->set_external_pointer(external_pointer);
} else {
// For other objects, iterate references first.
object_->IterateBody(map, size, this);
......
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