[ptr-compr] Make on-heap JSTypedArrays smi-corrupting friendly
On-heap typed arrays contain HeapObject value in |base_pointer| field and an offset in |external_pointer| field. When pointer compression is enabled we want to combine decompression with the offset addition. In order to do that we add an isolate root to the external_pointer value and therefore the data pointer computation can is a simple addition of a (potentially sign-extended) |base_pointer| loaded as Tagged_t value and an |external_pointer| value. Bug: v8:9706 Change-Id: Id5c546c353c81fb25e3598921bc78165d10a9c44 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1807369 Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Commit-Queue: Igor Sheludko <ishell@chromium.org> Cr-Commit-Position: refs/heads/master@{#63874}
This commit is contained in:
parent
c271cb7436
commit
6f9b2bd48a
@ -1329,9 +1329,6 @@ const kStrictReadOnlyProperty: constexpr MessageTemplate
|
||||
const kString: constexpr PrimitiveType
|
||||
generates 'PrimitiveType::kString';
|
||||
|
||||
const kExternalPointerForOnHeapArray: constexpr RawPtr
|
||||
generates 'JSTypedArray::ExternalPointerForOnHeapArray()';
|
||||
|
||||
const kNameDictionaryInitialCapacity:
|
||||
constexpr int32 generates 'NameDictionary::kInitialCapacity';
|
||||
|
||||
@ -2870,8 +2867,10 @@ extern macro IsMockArrayBufferAllocatorFlag(): bool;
|
||||
extern macro IsPrototypeTypedArrayPrototype(implicit context: Context)(Map):
|
||||
bool;
|
||||
|
||||
extern operator '.data_ptr' macro LoadJSTypedArrayBackingStore(JSTypedArray):
|
||||
RawPtr;
|
||||
extern operator '.data_ptr' macro LoadJSTypedArrayDataPtr(JSTypedArray): RawPtr;
|
||||
extern macro SetJSTypedArrayOnHeapDataPtr(
|
||||
JSTypedArray, ByteArray, uintptr): void;
|
||||
extern macro SetJSTypedArrayOffHeapDataPtr(JSTypedArray, RawPtr, uintptr): void;
|
||||
|
||||
extern operator '.elements_kind' macro LoadMapElementsKind(Map): ElementsKind;
|
||||
extern operator '.elements_kind' macro LoadElementsKind(JSTypedArray):
|
||||
|
@ -212,7 +212,7 @@ void ArrayBuiltinsAssembler::VisitAllTypedArrayElements(
|
||||
list, start, end,
|
||||
[&](TNode<Smi> index) {
|
||||
GotoIf(IsDetachedBuffer(array_buffer), detached);
|
||||
TNode<RawPtrT> data_ptr = LoadJSTypedArrayBackingStore(typed_array);
|
||||
TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(typed_array);
|
||||
TNode<Object> value = LoadFixedTypedArrayElementAsTagged(
|
||||
data_ptr, index, source_elements_kind_, SMI_PARAMETERS);
|
||||
k_ = index;
|
||||
@ -1579,7 +1579,7 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
|
||||
&allocate_iterator_result);
|
||||
|
||||
TNode<Int32T> elements_kind = LoadMapElementsKind(array_map);
|
||||
TNode<RawPtrT> data_ptr = LoadJSTypedArrayBackingStore(CAST(array));
|
||||
TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(CAST(array));
|
||||
var_value = LoadFixedTypedArrayElementAsTagged(data_ptr, CAST(index),
|
||||
elements_kind);
|
||||
Goto(&allocate_entry_if_needed);
|
||||
|
@ -316,8 +316,8 @@ void TypedArrayBuiltinsAssembler::SetTypedArraySource(
|
||||
|
||||
// Grab pointers and byte lengths we need later on.
|
||||
|
||||
TNode<RawPtrT> target_data_ptr = LoadJSTypedArrayBackingStore(target);
|
||||
TNode<RawPtrT> source_data_ptr = LoadJSTypedArrayBackingStore(source);
|
||||
TNode<RawPtrT> target_data_ptr = LoadJSTypedArrayDataPtr(target);
|
||||
TNode<RawPtrT> source_data_ptr = LoadJSTypedArrayDataPtr(source);
|
||||
|
||||
TNode<Int32T> source_el_kind = LoadElementsKind(source);
|
||||
TNode<Int32T> target_el_kind = LoadElementsKind(target);
|
||||
@ -749,10 +749,9 @@ TF_BUILTIN(TypedArrayOf, TypedArrayBuiltinsAssembler) {
|
||||
|
||||
// GC may move backing store in ToNumber, thus load backing
|
||||
// store everytime in this loop.
|
||||
TNode<RawPtrT> backing_store =
|
||||
LoadJSTypedArrayBackingStore(new_typed_array);
|
||||
StoreElement(backing_store, kind, index, value,
|
||||
INTPTR_PARAMETERS);
|
||||
TNode<RawPtrT> data_ptr =
|
||||
LoadJSTypedArrayDataPtr(new_typed_array);
|
||||
StoreElement(data_ptr, kind, index, value, INTPTR_PARAMETERS);
|
||||
},
|
||||
1, IndexAdvanceMode::kPost);
|
||||
});
|
||||
@ -971,10 +970,9 @@ TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
|
||||
|
||||
// GC may move backing store in map_fn, thus load backing
|
||||
// store in each iteration of this loop.
|
||||
TNode<RawPtrT> backing_store =
|
||||
LoadJSTypedArrayBackingStore(target_obj.value());
|
||||
StoreElement(backing_store, kind, index, final_value,
|
||||
SMI_PARAMETERS);
|
||||
TNode<RawPtrT> data_ptr =
|
||||
LoadJSTypedArrayDataPtr(target_obj.value());
|
||||
StoreElement(data_ptr, kind, index, final_value, SMI_PARAMETERS);
|
||||
});
|
||||
},
|
||||
1, IndexAdvanceMode::kPost);
|
||||
|
@ -27,21 +27,16 @@ namespace typed_array_createtypedarray {
|
||||
isOnHeap: constexpr bool, map: Map, buffer: JSArrayBuffer,
|
||||
byteOffset: uintptr, byteLength: uintptr, length: uintptr): JSTypedArray {
|
||||
let elements: ByteArray;
|
||||
let externalPointer: RawPtr;
|
||||
let basePointer: ByteArray | Smi;
|
||||
if constexpr (isOnHeap) {
|
||||
elements = AllocateByteArray(byteLength);
|
||||
basePointer = elements;
|
||||
externalPointer = PointerConstant(kExternalPointerForOnHeapArray);
|
||||
} else {
|
||||
basePointer = Convert<Smi>(0);
|
||||
elements = kEmptyByteArray;
|
||||
|
||||
// The max byteOffset is 8 * MaxSmi on the particular platform. 32 bit
|
||||
// platforms are self-limiting, because we can't allocate an array bigger
|
||||
// than our 32-bit arithmetic range anyway. 64 bit platforms could
|
||||
// theoretically have an offset up to 2^35 - 1.
|
||||
const backingStore: RawPtr = buffer.backing_store;
|
||||
externalPointer = backingStore + Convert<intptr>(byteOffset);
|
||||
const backingStore: uintptr = Convert<uintptr>(buffer.backing_store);
|
||||
|
||||
// Assert no overflow has occurred. Only assert if the mock array buffer
|
||||
// allocator is NOT used. When the mock array buffer is used, impossibly
|
||||
@ -49,9 +44,7 @@ namespace typed_array_createtypedarray {
|
||||
// and this assertion to fail.
|
||||
assert(
|
||||
IsMockArrayBufferAllocatorFlag() ||
|
||||
Convert<uintptr>(externalPointer) >= Convert<uintptr>(backingStore));
|
||||
|
||||
elements = kEmptyByteArray;
|
||||
(backingStore + byteOffset) >= backingStore);
|
||||
}
|
||||
|
||||
// We can't just build the new object with "new JSTypedArray" here because
|
||||
@ -64,8 +57,15 @@ namespace typed_array_createtypedarray {
|
||||
typedArray.byte_offset = byteOffset;
|
||||
typedArray.byte_length = byteLength;
|
||||
typedArray.length = length;
|
||||
typedArray.external_pointer = externalPointer;
|
||||
typedArray.base_pointer = basePointer;
|
||||
if constexpr (isOnHeap) {
|
||||
SetJSTypedArrayOnHeapDataPtr(typedArray, elements, byteOffset);
|
||||
} else {
|
||||
SetJSTypedArrayOffHeapDataPtr(
|
||||
typedArray, buffer.backing_store, byteOffset);
|
||||
assert(
|
||||
typedArray.data_ptr ==
|
||||
(buffer.backing_store + Convert<intptr>(byteOffset)));
|
||||
}
|
||||
SetupTypedArrayEmbedderFields(typedArray);
|
||||
return typedArray;
|
||||
}
|
||||
|
@ -2242,16 +2242,60 @@ TNode<IntPtrT> CodeStubAssembler::LoadPropertyArrayLength(
|
||||
return Signed(DecodeWord<PropertyArray::LengthField>(value));
|
||||
}
|
||||
|
||||
TNode<RawPtrT> CodeStubAssembler::LoadJSTypedArrayBackingStore(
|
||||
TNode<RawPtrT> CodeStubAssembler::LoadJSTypedArrayDataPtr(
|
||||
TNode<JSTypedArray> typed_array) {
|
||||
// Backing store = external_pointer + base_pointer.
|
||||
Node* external_pointer =
|
||||
LoadObjectField(typed_array, JSTypedArray::kExternalPointerOffset,
|
||||
MachineType::Pointer());
|
||||
TNode<Object> base_pointer =
|
||||
LoadObjectField(typed_array, JSTypedArray::kBasePointerOffset);
|
||||
return UncheckedCast<RawPtrT>(
|
||||
IntPtrAdd(external_pointer, BitcastTaggedToWord(base_pointer)));
|
||||
// Data pointer = external_pointer + static_cast<Tagged_t>(base_pointer).
|
||||
TNode<RawPtrT> external_pointer = LoadObjectField<RawPtrT>(
|
||||
typed_array, JSTypedArray::kExternalPointerOffset);
|
||||
|
||||
TNode<IntPtrT> base_pointer;
|
||||
#ifdef V8_COMPRESS_POINTERS
|
||||
TNode<TaggedT> compressed_base =
|
||||
LoadObjectField<TaggedT>(typed_array, JSTypedArray::kBasePointerOffset);
|
||||
// Sign extend TaggedT to IntPtrT according to current compression scheme
|
||||
// so that the addition with |external_pointer| (which already contains
|
||||
// compensated offset value) below will decompress the tagged value.
|
||||
// See JSTypedArray::ExternalPointerCompensationForOnHeapArray() for details.
|
||||
base_pointer = ChangeInt32ToIntPtr(compressed_base);
|
||||
#else
|
||||
base_pointer =
|
||||
LoadObjectField<IntPtrT>(typed_array, JSTypedArray::kBasePointerOffset);
|
||||
#endif
|
||||
return RawPtrAdd(external_pointer, base_pointer);
|
||||
}
|
||||
|
||||
void CodeStubAssembler::SetJSTypedArrayOffHeapDataPtr(
|
||||
TNode<JSTypedArray> holder, TNode<RawPtrT> base, TNode<UintPtrT> offset) {
|
||||
StoreObjectFieldNoWriteBarrier(holder, JSTypedArray::kBasePointerOffset,
|
||||
SmiConstant(0));
|
||||
|
||||
base = RawPtrAdd(base, Signed(offset));
|
||||
StoreObjectFieldNoWriteBarrier<RawPtrT>(
|
||||
holder, JSTypedArray::kExternalPointerOffset, base);
|
||||
}
|
||||
|
||||
void CodeStubAssembler::SetJSTypedArrayOnHeapDataPtr(TNode<JSTypedArray> holder,
|
||||
TNode<ByteArray> base,
|
||||
TNode<UintPtrT> offset) {
|
||||
offset = UintPtrAdd(UintPtrConstant(ByteArray::kHeaderSize - kHeapObjectTag),
|
||||
offset);
|
||||
if (COMPRESS_POINTERS_BOOL) {
|
||||
TNode<IntPtrT> full_base = Signed(BitcastTaggedToWord(base));
|
||||
TNode<Int32T> compressed_base = TruncateIntPtrToInt32(full_base);
|
||||
// TODO(v8:9706): Add a way to directly use kRootRegister value.
|
||||
TNode<IntPtrT> isolate_root =
|
||||
IntPtrSub(full_base, ChangeInt32ToIntPtr(compressed_base));
|
||||
// Add JSTypedArray::ExternalPointerCompensationForOnHeapArray() to offset.
|
||||
DCHECK_EQ(
|
||||
isolate()->isolate_root(),
|
||||
JSTypedArray::ExternalPointerCompensationForOnHeapArray(isolate()));
|
||||
// See JSTypedArray::SetOnHeapDataPtr() for details.
|
||||
offset = Unsigned(IntPtrAdd(offset, isolate_root));
|
||||
}
|
||||
|
||||
StoreObjectField(holder, JSTypedArray::kBasePointerOffset, base);
|
||||
StoreObjectFieldNoWriteBarrier<UintPtrT>(
|
||||
holder, JSTypedArray::kExternalPointerOffset, offset);
|
||||
}
|
||||
|
||||
TNode<BigInt> CodeStubAssembler::LoadFixedBigInt64ArrayElementAsTagged(
|
||||
@ -2537,33 +2581,33 @@ TNode<Numeric> CodeStubAssembler::LoadFixedTypedArrayElementAsTagged(
|
||||
void CodeStubAssembler::StoreJSTypedArrayElementFromTagged(
|
||||
TNode<Context> context, TNode<JSTypedArray> typed_array,
|
||||
TNode<Smi> index_node, TNode<Object> value, ElementsKind elements_kind) {
|
||||
TNode<RawPtrT> data_pointer = LoadJSTypedArrayBackingStore(typed_array);
|
||||
TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(typed_array);
|
||||
switch (elements_kind) {
|
||||
case UINT8_ELEMENTS:
|
||||
case UINT8_CLAMPED_ELEMENTS:
|
||||
case INT8_ELEMENTS:
|
||||
case UINT16_ELEMENTS:
|
||||
case INT16_ELEMENTS:
|
||||
StoreElement(data_pointer, elements_kind, index_node,
|
||||
SmiToInt32(CAST(value)), SMI_PARAMETERS);
|
||||
StoreElement(data_ptr, elements_kind, index_node, SmiToInt32(CAST(value)),
|
||||
SMI_PARAMETERS);
|
||||
break;
|
||||
case UINT32_ELEMENTS:
|
||||
case INT32_ELEMENTS:
|
||||
StoreElement(data_pointer, elements_kind, index_node,
|
||||
StoreElement(data_ptr, elements_kind, index_node,
|
||||
TruncateTaggedToWord32(context, value), SMI_PARAMETERS);
|
||||
break;
|
||||
case FLOAT32_ELEMENTS:
|
||||
StoreElement(data_pointer, elements_kind, index_node,
|
||||
StoreElement(data_ptr, elements_kind, index_node,
|
||||
TruncateFloat64ToFloat32(LoadHeapNumberValue(CAST(value))),
|
||||
SMI_PARAMETERS);
|
||||
break;
|
||||
case FLOAT64_ELEMENTS:
|
||||
StoreElement(data_pointer, elements_kind, index_node,
|
||||
StoreElement(data_ptr, elements_kind, index_node,
|
||||
LoadHeapNumberValue(CAST(value)), SMI_PARAMETERS);
|
||||
break;
|
||||
case BIGUINT64_ELEMENTS:
|
||||
case BIGINT64_ELEMENTS:
|
||||
StoreElement(data_pointer, elements_kind, index_node,
|
||||
StoreElement(data_ptr, elements_kind, index_node,
|
||||
UncheckedCast<BigInt>(value), SMI_PARAMETERS);
|
||||
break;
|
||||
default:
|
||||
@ -10873,8 +10917,8 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
|
||||
GotoIfNot(UintPtrLessThan(intptr_key, length), &update_value_and_bailout);
|
||||
}
|
||||
|
||||
TNode<RawPtrT> backing_store = LoadJSTypedArrayBackingStore(CAST(object));
|
||||
StoreElement(backing_store, elements_kind, intptr_key, converted_value,
|
||||
TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(CAST(object));
|
||||
StoreElement(data_ptr, elements_kind, intptr_key, converted_value,
|
||||
parameter_mode);
|
||||
Goto(&done);
|
||||
|
||||
|
@ -3536,7 +3536,13 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
|
||||
// JSTypedArray helpers
|
||||
TNode<UintPtrT> LoadJSTypedArrayLength(TNode<JSTypedArray> typed_array);
|
||||
TNode<RawPtrT> LoadJSTypedArrayBackingStore(TNode<JSTypedArray> typed_array);
|
||||
TNode<RawPtrT> LoadJSTypedArrayDataPtr(TNode<JSTypedArray> typed_array);
|
||||
void SetJSTypedArrayOnHeapDataPtr(TNode<JSTypedArray> holder,
|
||||
TNode<ByteArray> base,
|
||||
TNode<UintPtrT> offset);
|
||||
void SetJSTypedArrayOffHeapDataPtr(TNode<JSTypedArray> holder,
|
||||
TNode<RawPtrT> base,
|
||||
TNode<UintPtrT> offset);
|
||||
|
||||
template <typename TIndex>
|
||||
TNode<IntPtrT> ElementOffsetFromIndex(TNode<TIndex> index, ElementsKind kind,
|
||||
|
@ -114,6 +114,10 @@ class MachineType {
|
||||
constexpr bool IsCompressedPointer() const {
|
||||
return representation() == MachineRepresentation::kCompressedPointer;
|
||||
}
|
||||
constexpr static MachineRepresentation TaggedRepresentation() {
|
||||
return (kTaggedSize == 4) ? MachineRepresentation::kWord32
|
||||
: MachineRepresentation::kWord64;
|
||||
}
|
||||
constexpr static MachineRepresentation PointerRepresentation() {
|
||||
return (kSystemPointerSize == 4) ? MachineRepresentation::kWord32
|
||||
: MachineRepresentation::kWord64;
|
||||
@ -260,6 +264,14 @@ class MachineType {
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr static MachineType TypeRawTagged() {
|
||||
#ifdef V8_COMPRESS_POINTERS
|
||||
return MachineType::Int32();
|
||||
#else
|
||||
return MachineType::Pointer();
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr static MachineType TypeCompressedTagged() {
|
||||
#ifdef V8_COMPRESS_POINTERS
|
||||
return MachineType::AnyCompressed();
|
||||
|
@ -426,11 +426,10 @@ FieldAccess AccessBuilder::ForJSTypedArrayLength() {
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSTypedArrayBasePointer() {
|
||||
FieldAccess access = {
|
||||
kTaggedBase, JSTypedArray::kBasePointerOffset,
|
||||
MaybeHandle<Name>(), MaybeHandle<Map>(),
|
||||
Type::OtherInternal(), MachineType::TypeCompressedTagged(),
|
||||
kFullWriteBarrier, LoadSensitivity::kCritical};
|
||||
FieldAccess access = {kTaggedBase, JSTypedArray::kBasePointerOffset,
|
||||
MaybeHandle<Name>(), MaybeHandle<Map>(),
|
||||
Type::OtherInternal(), MachineType::TypeRawTagged(),
|
||||
kFullWriteBarrier, LoadSensitivity::kCritical};
|
||||
return access;
|
||||
}
|
||||
|
||||
|
@ -227,6 +227,8 @@ class EffectControlLinearizer {
|
||||
Node* LowerStringComparison(Callable const& callable, Node* node);
|
||||
Node* IsElementsKindGreaterThan(Node* kind, ElementsKind reference_kind);
|
||||
|
||||
Node* BuildTypedArrayDataPointer(Node* base, Node* external);
|
||||
|
||||
Node* ChangeInt32ToCompressedSmi(Node* value);
|
||||
Node* ChangeInt32ToSmi(Node* value);
|
||||
Node* ChangeInt32ToIntPtr(Node* value);
|
||||
@ -5003,6 +5005,25 @@ void EffectControlLinearizer::LowerStoreDataViewElement(Node* node) {
|
||||
done.PhiAt(0));
|
||||
}
|
||||
|
||||
// Compute the data pointer, handling the case where the {external} pointer
|
||||
// is the effective data pointer (i.e. the {base} is Smi zero).
|
||||
Node* EffectControlLinearizer::BuildTypedArrayDataPointer(Node* base,
|
||||
Node* external) {
|
||||
if (IntPtrMatcher(base).Is(0)) {
|
||||
return external;
|
||||
} else {
|
||||
if (COMPRESS_POINTERS_BOOL) {
|
||||
// Sign-extend Tagged_t to IntPtr according to current compression
|
||||
// scheme so that the addition with |external_pointer| (which already
|
||||
// contains compensated offset value) will decompress the tagged value.
|
||||
// See JSTypedArray::ExternalPointerCompensationForOnHeapArray() for
|
||||
// details.
|
||||
base = ChangeInt32ToIntPtr(base);
|
||||
}
|
||||
return __ UnsafePointerAdd(base, external);
|
||||
}
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::LowerLoadTypedElement(Node* node) {
|
||||
ExternalArrayType array_type = ExternalArrayTypeOf(node->op());
|
||||
Node* buffer = node->InputAt(0);
|
||||
@ -5014,17 +5035,12 @@ Node* EffectControlLinearizer::LowerLoadTypedElement(Node* node) {
|
||||
// ArrayBuffer (if there's any) as long as we are still operating on it.
|
||||
__ Retain(buffer);
|
||||
|
||||
// Compute the effective storage pointer, handling the case where the
|
||||
// {external} pointer is the effective storage pointer (i.e. the {base}
|
||||
// is Smi zero).
|
||||
Node* storage = IntPtrMatcher(base).Is(0)
|
||||
? external
|
||||
: __ UnsafePointerAdd(base, external);
|
||||
Node* data_ptr = BuildTypedArrayDataPointer(base, external);
|
||||
|
||||
// Perform the actual typed element access.
|
||||
return __ LoadElement(AccessBuilder::ForTypedArrayElement(
|
||||
array_type, true, LoadSensitivity::kCritical),
|
||||
storage, index);
|
||||
data_ptr, index);
|
||||
}
|
||||
|
||||
void EffectControlLinearizer::LowerStoreTypedElement(Node* node) {
|
||||
@ -5039,16 +5055,11 @@ void EffectControlLinearizer::LowerStoreTypedElement(Node* node) {
|
||||
// ArrayBuffer (if there's any) as long as we are still operating on it.
|
||||
__ Retain(buffer);
|
||||
|
||||
// Compute the effective storage pointer, handling the case where the
|
||||
// {external} pointer is the effective storage pointer (i.e. the {base}
|
||||
// is Smi zero).
|
||||
Node* storage = IntPtrMatcher(base).Is(0)
|
||||
? external
|
||||
: __ UnsafePointerAdd(base, external);
|
||||
Node* data_ptr = BuildTypedArrayDataPointer(base, external);
|
||||
|
||||
// Perform the actual typed element access.
|
||||
__ StoreElement(AccessBuilder::ForTypedArrayElement(array_type, true),
|
||||
storage, index, value);
|
||||
data_ptr, index, value);
|
||||
}
|
||||
|
||||
void EffectControlLinearizer::TransitionElementsTo(Node* node, Node* array,
|
||||
|
@ -827,7 +827,7 @@ class JSTypedArrayRef : public JSObjectRef {
|
||||
|
||||
bool is_on_heap() const;
|
||||
size_t length() const;
|
||||
void* external_pointer() const;
|
||||
void* data_ptr() const;
|
||||
|
||||
void Serialize();
|
||||
bool serialized() const;
|
||||
|
@ -420,7 +420,7 @@ class JSTypedArrayData : public JSObjectData {
|
||||
|
||||
bool is_on_heap() const { return is_on_heap_; }
|
||||
size_t length() const { return length_; }
|
||||
void* external_pointer() const { return external_pointer_; }
|
||||
void* data_ptr() const { return data_ptr_; }
|
||||
|
||||
void Serialize(JSHeapBroker* broker);
|
||||
bool serialized() const { return serialized_; }
|
||||
@ -430,7 +430,7 @@ class JSTypedArrayData : public JSObjectData {
|
||||
private:
|
||||
bool const is_on_heap_;
|
||||
size_t const length_;
|
||||
void* const external_pointer_;
|
||||
void* const data_ptr_;
|
||||
|
||||
bool serialized_ = false;
|
||||
HeapObjectData* buffer_ = nullptr;
|
||||
@ -441,7 +441,7 @@ JSTypedArrayData::JSTypedArrayData(JSHeapBroker* broker, ObjectData** storage,
|
||||
: JSObjectData(broker, storage, object),
|
||||
is_on_heap_(object->is_on_heap()),
|
||||
length_(object->length()),
|
||||
external_pointer_(object->external_pointer()) {}
|
||||
data_ptr_(object->DataPtr()) {}
|
||||
|
||||
void JSTypedArrayData::Serialize(JSHeapBroker* broker) {
|
||||
if (serialized_) return;
|
||||
@ -3383,12 +3383,12 @@ base::Optional<MapRef> MapRef::FindRootMap() const {
|
||||
return base::nullopt;
|
||||
}
|
||||
|
||||
void* JSTypedArrayRef::external_pointer() const {
|
||||
void* JSTypedArrayRef::data_ptr() const {
|
||||
if (broker()->mode() == JSHeapBroker::kDisabled) {
|
||||
AllowHandleDereference allow_handle_dereference;
|
||||
return object()->external_pointer();
|
||||
return object()->DataPtr();
|
||||
}
|
||||
return data()->AsJSTypedArray()->external_pointer();
|
||||
return data()->AsJSTypedArray()->data_ptr();
|
||||
}
|
||||
|
||||
bool MapRef::IsInobjectSlackTrackingInProgress() const {
|
||||
|
@ -2591,12 +2591,14 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
if (typed_array.has_value()) {
|
||||
length = jsgraph()->Constant(static_cast<double>(typed_array->length()));
|
||||
|
||||
// Load the (known) base and external pointer for the {receiver}. The
|
||||
// {external_pointer} might be invalid if the {buffer} was detached, so
|
||||
// we need to make sure that any access is properly guarded.
|
||||
DCHECK(!typed_array->is_on_heap());
|
||||
// Load the (known) data pointer for the {receiver} and set {base_pointer}
|
||||
// and {external_pointer} to the values that will allow to generate typed
|
||||
// element accesses using the known data pointer.
|
||||
// The data pointer might be invalid if the {buffer} was detached,
|
||||
// so we need to make sure that any access is properly guarded.
|
||||
base_pointer = jsgraph()->ZeroConstant();
|
||||
external_pointer =
|
||||
jsgraph()->PointerConstant(typed_array->external_pointer());
|
||||
external_pointer = jsgraph()->PointerConstant(typed_array->data_ptr());
|
||||
} else {
|
||||
// Load the {receiver}s length.
|
||||
length = effect = graph()->NewNode(
|
||||
|
@ -187,6 +187,9 @@ class UseInfo {
|
||||
static UseInfo Word() {
|
||||
return UseInfo(MachineType::PointerRepresentation(), Truncation::Any());
|
||||
}
|
||||
static UseInfo TaggedWord() {
|
||||
return UseInfo(MachineType::TaggedRepresentation(), Truncation::Any());
|
||||
}
|
||||
static UseInfo Bool() {
|
||||
return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
|
||||
}
|
||||
|
@ -3020,10 +3020,10 @@ class RepresentationSelector {
|
||||
case IrOpcode::kLoadTypedElement: {
|
||||
MachineRepresentation const rep =
|
||||
MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
|
||||
ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
|
||||
ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
|
||||
ProcessInput(node, 2, UseInfo::Word()); // external pointer
|
||||
ProcessInput(node, 3, UseInfo::Word()); // index
|
||||
ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
|
||||
ProcessInput(node, 1, UseInfo::TaggedWord()); // base pointer
|
||||
ProcessInput(node, 2, UseInfo::Word()); // external pointer
|
||||
ProcessInput(node, 3, UseInfo::Word()); // index
|
||||
ProcessRemainingInputs(node, 4);
|
||||
SetOutput(node, rep);
|
||||
return;
|
||||
@ -3042,10 +3042,10 @@ class RepresentationSelector {
|
||||
case IrOpcode::kStoreTypedElement: {
|
||||
MachineRepresentation const rep =
|
||||
MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
|
||||
ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
|
||||
ProcessInput(node, 1, UseInfo::AnyTagged()); // base pointer
|
||||
ProcessInput(node, 2, UseInfo::Word()); // external pointer
|
||||
ProcessInput(node, 3, UseInfo::Word()); // index
|
||||
ProcessInput(node, 0, UseInfo::AnyTagged()); // buffer
|
||||
ProcessInput(node, 1, UseInfo::TaggedWord()); // base pointer
|
||||
ProcessInput(node, 2, UseInfo::Word()); // external pointer
|
||||
ProcessInput(node, 3, UseInfo::Word()); // index
|
||||
ProcessInput(node, 4,
|
||||
TruncatingUseInfoFromRepresentation(rep)); // value
|
||||
ProcessRemainingInputs(node, 5);
|
||||
|
@ -1388,6 +1388,12 @@ void JSTypedArray::JSTypedArrayPrint(std::ostream& os) { // NOLINT
|
||||
os << "\n - byte_offset: " << byte_offset();
|
||||
os << "\n - byte_length: " << byte_length();
|
||||
os << "\n - length: " << length();
|
||||
os << "\n - data_ptr: " << DataPtr();
|
||||
Tagged_t base_pointer = static_cast<Tagged_t>(base_pointer_raw().ptr());
|
||||
os << "\n - base_pointer: "
|
||||
<< reinterpret_cast<void*>(static_cast<Address>(base_pointer));
|
||||
os << "\n - external_pointer: "
|
||||
<< reinterpret_cast<void*>(external_pointer_raw());
|
||||
if (!buffer().IsJSArrayBuffer()) {
|
||||
os << "\n <invalid buffer>\n";
|
||||
return;
|
||||
|
@ -3252,9 +3252,7 @@ Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type,
|
||||
Handle<JSTypedArray>::cast(NewJSArrayBufferView(
|
||||
map, empty_byte_array(), buffer, byte_offset, byte_length));
|
||||
typed_array->set_length(length);
|
||||
typed_array->set_external_pointer(
|
||||
reinterpret_cast<byte*>(buffer->backing_store()) + byte_offset);
|
||||
typed_array->set_base_pointer(Smi::kZero);
|
||||
typed_array->SetOffHeapDataPtr(buffer->backing_store(), byte_offset);
|
||||
return typed_array;
|
||||
}
|
||||
|
||||
|
@ -2096,8 +2096,7 @@ void AccessorAssembler::EmitElementLoad(
|
||||
if (access_mode == LoadAccessMode::kHas) {
|
||||
exit_point->Return(TrueConstant());
|
||||
} else {
|
||||
TNode<RawPtrT> backing_store =
|
||||
LoadJSTypedArrayBackingStore(CAST(object));
|
||||
TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(CAST(object));
|
||||
|
||||
Label uint8_elements(this), int8_elements(this), uint16_elements(this),
|
||||
int16_elements(this), uint32_elements(this), int32_elements(this),
|
||||
@ -2123,50 +2122,48 @@ void AccessorAssembler::EmitElementLoad(
|
||||
BIND(&uint8_elements);
|
||||
{
|
||||
Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
|
||||
Node* element =
|
||||
Load(MachineType::Uint8(), backing_store, intptr_index);
|
||||
Node* element = Load(MachineType::Uint8(), data_ptr, intptr_index);
|
||||
exit_point->Return(SmiFromInt32(element));
|
||||
}
|
||||
BIND(&int8_elements);
|
||||
{
|
||||
Comment("INT8_ELEMENTS");
|
||||
Node* element =
|
||||
Load(MachineType::Int8(), backing_store, intptr_index);
|
||||
Node* element = Load(MachineType::Int8(), data_ptr, intptr_index);
|
||||
exit_point->Return(SmiFromInt32(element));
|
||||
}
|
||||
BIND(&uint16_elements);
|
||||
{
|
||||
Comment("UINT16_ELEMENTS");
|
||||
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
|
||||
Node* element = Load(MachineType::Uint16(), backing_store, index);
|
||||
Node* element = Load(MachineType::Uint16(), data_ptr, index);
|
||||
exit_point->Return(SmiFromInt32(element));
|
||||
}
|
||||
BIND(&int16_elements);
|
||||
{
|
||||
Comment("INT16_ELEMENTS");
|
||||
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
|
||||
Node* element = Load(MachineType::Int16(), backing_store, index);
|
||||
Node* element = Load(MachineType::Int16(), data_ptr, index);
|
||||
exit_point->Return(SmiFromInt32(element));
|
||||
}
|
||||
BIND(&uint32_elements);
|
||||
{
|
||||
Comment("UINT32_ELEMENTS");
|
||||
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
|
||||
Node* element = Load(MachineType::Uint32(), backing_store, index);
|
||||
Node* element = Load(MachineType::Uint32(), data_ptr, index);
|
||||
exit_point->Return(ChangeUint32ToTagged(element));
|
||||
}
|
||||
BIND(&int32_elements);
|
||||
{
|
||||
Comment("INT32_ELEMENTS");
|
||||
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
|
||||
Node* element = Load(MachineType::Int32(), backing_store, index);
|
||||
Node* element = Load(MachineType::Int32(), data_ptr, index);
|
||||
exit_point->Return(ChangeInt32ToTagged(element));
|
||||
}
|
||||
BIND(&float32_elements);
|
||||
{
|
||||
Comment("FLOAT32_ELEMENTS");
|
||||
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
|
||||
Node* element = Load(MachineType::Float32(), backing_store, index);
|
||||
Node* element = Load(MachineType::Float32(), data_ptr, index);
|
||||
var_double_value->Bind(ChangeFloat32ToFloat64(element));
|
||||
Goto(rebox_double);
|
||||
}
|
||||
@ -2174,7 +2171,7 @@ void AccessorAssembler::EmitElementLoad(
|
||||
{
|
||||
Comment("FLOAT64_ELEMENTS");
|
||||
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(3));
|
||||
Node* element = Load(MachineType::Float64(), backing_store, index);
|
||||
Node* element = Load(MachineType::Float64(), data_ptr, index);
|
||||
var_double_value->Bind(element);
|
||||
Goto(rebox_double);
|
||||
}
|
||||
@ -2182,15 +2179,13 @@ void AccessorAssembler::EmitElementLoad(
|
||||
{
|
||||
Comment("BIGINT64_ELEMENTS");
|
||||
exit_point->Return(LoadFixedTypedArrayElementAsTagged(
|
||||
backing_store, intptr_index, BIGINT64_ELEMENTS,
|
||||
INTPTR_PARAMETERS));
|
||||
data_ptr, intptr_index, BIGINT64_ELEMENTS, INTPTR_PARAMETERS));
|
||||
}
|
||||
BIND(&biguint64_elements);
|
||||
{
|
||||
Comment("BIGUINT64_ELEMENTS");
|
||||
exit_point->Return(LoadFixedTypedArrayElementAsTagged(
|
||||
backing_store, intptr_index, BIGUINT64_ELEMENTS,
|
||||
INTPTR_PARAMETERS));
|
||||
data_ptr, intptr_index, BIGUINT64_ELEMENTS, INTPTR_PARAMETERS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,31 +114,63 @@ void JSTypedArray::set_length(size_t value) {
|
||||
WriteField<size_t>(kLengthOffset, value);
|
||||
}
|
||||
|
||||
void* JSTypedArray::external_pointer() const {
|
||||
return reinterpret_cast<void*>(ReadField<Address>(kExternalPointerOffset));
|
||||
Address JSTypedArray::external_pointer_raw() const {
|
||||
return ReadField<Address>(kExternalPointerOffset);
|
||||
}
|
||||
|
||||
void JSTypedArray::set_external_pointer(void* value) {
|
||||
WriteField<Address>(kExternalPointerOffset, reinterpret_cast<Address>(value));
|
||||
void JSTypedArray::set_external_pointer_raw(Address value) {
|
||||
WriteField<Address>(kExternalPointerOffset, value);
|
||||
}
|
||||
|
||||
ACCESSORS(JSTypedArray, base_pointer, Object, kBasePointerOffset)
|
||||
Address JSTypedArray::ExternalPointerCompensationForOnHeapArray(
|
||||
Isolate* isolate) {
|
||||
#ifdef V8_COMPRESS_POINTERS
|
||||
return GetIsolateRoot(isolate);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void JSTypedArray::RemoveExternalPointerCompensationForSerialization() {
|
||||
DCHECK(is_on_heap());
|
||||
Isolate* isolate = GetIsolateForPtrCompr(*this);
|
||||
set_external_pointer_raw(external_pointer_raw() -
|
||||
ExternalPointerCompensationForOnHeapArray(isolate));
|
||||
}
|
||||
|
||||
ACCESSORS(JSTypedArray, base_pointer_raw, Object, kBasePointerOffset)
|
||||
|
||||
void* JSTypedArray::DataPtr() {
|
||||
// Sign extend Tagged_t to intptr_t according to current compression scheme
|
||||
// so that the addition with |external_pointer| (which already contains
|
||||
// compensated offset value) will decompress the tagged value.
|
||||
// See JSTypedArray::ExternalPointerCompensationForOnHeapArray() for details.
|
||||
return reinterpret_cast<void*>(
|
||||
base_pointer().ptr() + reinterpret_cast<intptr_t>(external_pointer()));
|
||||
external_pointer_raw() +
|
||||
static_cast<Address>(static_cast<intptr_t>(
|
||||
static_cast<Tagged_t>(base_pointer_raw().ptr()))));
|
||||
}
|
||||
|
||||
void JSTypedArray::SetOffHeapDataPtr(void* base, Address offset) {
|
||||
set_base_pointer_raw(Smi::kZero, SKIP_WRITE_BARRIER);
|
||||
Address address = reinterpret_cast<Address>(base) + offset;
|
||||
set_external_pointer_raw(address);
|
||||
DCHECK_EQ(address, reinterpret_cast<Address>(DataPtr()));
|
||||
}
|
||||
|
||||
void JSTypedArray::SetOnHeapDataPtr(HeapObject base, Address offset) {
|
||||
set_base_pointer_raw(base);
|
||||
Isolate* isolate = GetIsolateForPtrCompr(*this);
|
||||
set_external_pointer_raw(offset +
|
||||
ExternalPointerCompensationForOnHeapArray(isolate));
|
||||
DCHECK_EQ(base.ptr() + offset, reinterpret_cast<Address>(DataPtr()));
|
||||
}
|
||||
|
||||
bool JSTypedArray::is_on_heap() const {
|
||||
DisallowHeapAllocation no_gc;
|
||||
// Checking that buffer()->backing_store() is not nullptr is not sufficient;
|
||||
// it will be nullptr when byte_length is 0 as well.
|
||||
return base_pointer().ptr() == elements().ptr();
|
||||
}
|
||||
|
||||
// static
|
||||
void* JSTypedArray::ExternalPointerForOnHeapArray() {
|
||||
return reinterpret_cast<void*>(ByteArray::kHeaderSize - kHeapObjectTag);
|
||||
return base_pointer_raw() == elements();
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -123,8 +123,7 @@ Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
|
||||
|
||||
// Clear the elements of the typed array.
|
||||
self->set_elements(ReadOnlyRoots(isolate).empty_byte_array());
|
||||
self->set_external_pointer(array_buffer->backing_store());
|
||||
self->set_base_pointer(Smi::kZero);
|
||||
self->SetOffHeapDataPtr(array_buffer->backing_store(), 0);
|
||||
DCHECK(!self->is_on_heap());
|
||||
|
||||
return array_buffer;
|
||||
|
@ -177,12 +177,6 @@ class JSTypedArray : public JSArrayBufferView {
|
||||
// [length]: length of typed array in elements.
|
||||
DECL_PRIMITIVE_ACCESSORS(length, size_t)
|
||||
|
||||
// [external_pointer]: TODO(v8:4153)
|
||||
DECL_PRIMITIVE_ACCESSORS(external_pointer, void*)
|
||||
|
||||
// [base_pointer]: TODO(v8:4153)
|
||||
DECL_ACCESSORS(base_pointer, Object)
|
||||
|
||||
// ES6 9.4.5.3
|
||||
V8_WARN_UNUSED_RESULT static Maybe<bool> DefineOwnProperty(
|
||||
Isolate* isolate, Handle<JSTypedArray> o, Handle<Object> key,
|
||||
@ -198,10 +192,26 @@ class JSTypedArray : public JSArrayBufferView {
|
||||
// Use with care: returns raw pointer into heap.
|
||||
inline void* DataPtr();
|
||||
|
||||
inline void SetOffHeapDataPtr(void* base, Address offset);
|
||||
inline void SetOnHeapDataPtr(HeapObject base, Address offset);
|
||||
|
||||
// Whether the buffer's backing store is on-heap or off-heap.
|
||||
inline bool is_on_heap() const;
|
||||
|
||||
static inline void* ExternalPointerForOnHeapArray();
|
||||
// Note: this is a pointer compression specific optimization.
|
||||
// Normally, on-heap typed arrays contain HeapObject value in |base_pointer|
|
||||
// field and an offset in |external_pointer|.
|
||||
// When pointer compression is enabled we want to combine decompression with
|
||||
// the offset addition. In order to do that we add an isolate root to the
|
||||
// |external_pointer| value and therefore the data pointer computation can
|
||||
// is a simple addition of a (potentially sign-extended) |base_pointer| loaded
|
||||
// as Tagged_t value and an |external_pointer| value.
|
||||
// For full-pointer mode the compensation value is zero.
|
||||
static inline Address ExternalPointerCompensationForOnHeapArray(
|
||||
Isolate* isolate);
|
||||
|
||||
// Subtracts external pointer compensation from the external pointer value.
|
||||
inline void RemoveExternalPointerCompensationForSerialization();
|
||||
|
||||
static inline MaybeHandle<JSTypedArray> Validate(Isolate* isolate,
|
||||
Handle<Object> receiver,
|
||||
@ -240,6 +250,14 @@ class JSTypedArray : public JSArrayBufferView {
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class Deserializer;
|
||||
|
||||
// [base_pointer]: TODO(v8:4153)
|
||||
DECL_ACCESSORS(base_pointer_raw, Object)
|
||||
|
||||
// [external_pointer]: TODO(v8:4153)
|
||||
DECL_PRIMITIVE_ACCESSORS(external_pointer_raw, Address)
|
||||
|
||||
OBJECT_CONSTRUCTORS(JSTypedArray, JSArrayBufferView);
|
||||
};
|
||||
|
||||
|
@ -607,15 +607,13 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> {
|
||||
// For use with std::unordered_set.
|
||||
struct Hasher {
|
||||
size_t operator()(const Object o) const {
|
||||
return std::hash<v8::internal::Address>{}(o.ptr());
|
||||
return std::hash<v8::internal::Address>{}(static_cast<Tagged_t>(o.ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
// For use with std::map.
|
||||
struct Comparer {
|
||||
bool operator()(const Object a, const Object b) const {
|
||||
return a.ptr() < b.ptr();
|
||||
}
|
||||
bool operator()(const Object a, const Object b) const { return a < b; }
|
||||
};
|
||||
|
||||
template <class T, typename std::enable_if<std::is_arithmetic<T>::value,
|
||||
|
@ -291,22 +291,27 @@ HeapObject Deserializer::PostProcessNewObject(HeapObject obj,
|
||||
data_view.byte_offset());
|
||||
} else if (obj.IsJSTypedArray()) {
|
||||
JSTypedArray typed_array = JSTypedArray::cast(obj);
|
||||
// Only fixup for the off-heap case.
|
||||
if (!typed_array.is_on_heap()) {
|
||||
Smi store_index(
|
||||
reinterpret_cast<Address>(typed_array.external_pointer()));
|
||||
auto backing_store = backing_stores_[store_index.value()];
|
||||
// Fixup typed array pointers.
|
||||
if (typed_array.is_on_heap()) {
|
||||
typed_array.SetOnHeapDataPtr(
|
||||
HeapObject::cast(typed_array.base_pointer_raw()),
|
||||
typed_array.external_pointer_raw());
|
||||
} else {
|
||||
// Serializer writes backing store ref as a DataPtr() value.
|
||||
size_t store_index = reinterpret_cast<size_t>(typed_array.DataPtr());
|
||||
auto backing_store = backing_stores_[store_index];
|
||||
auto start = backing_store
|
||||
? reinterpret_cast<byte*>(backing_store->buffer_start())
|
||||
: nullptr;
|
||||
typed_array.set_external_pointer(start + typed_array.byte_offset());
|
||||
typed_array.SetOffHeapDataPtr(start, typed_array.byte_offset());
|
||||
}
|
||||
} else if (obj.IsJSArrayBuffer()) {
|
||||
JSArrayBuffer buffer = JSArrayBuffer::cast(obj);
|
||||
// Only fixup for the off-heap case.
|
||||
if (buffer.backing_store() != nullptr) {
|
||||
Smi store_index(reinterpret_cast<Address>(buffer.backing_store()));
|
||||
auto backing_store = backing_stores_[store_index.value()];
|
||||
// Serializer writes backing store ref in |backing_store| field.
|
||||
size_t store_index = reinterpret_cast<size_t>(buffer.backing_store());
|
||||
auto backing_store = backing_stores_[store_index];
|
||||
if (backing_store) {
|
||||
buffer.Attach(backing_store);
|
||||
} else {
|
||||
|
@ -342,7 +342,7 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space,
|
||||
serializer_->SerializeObject(map);
|
||||
}
|
||||
|
||||
int32_t Serializer::ObjectSerializer::SerializeBackingStore(
|
||||
uint32_t Serializer::ObjectSerializer::SerializeBackingStore(
|
||||
void* backing_store, int32_t byte_length) {
|
||||
SerializerReference reference =
|
||||
serializer_->reference_map()->LookupReference(backing_store);
|
||||
@ -358,13 +358,15 @@ int32_t Serializer::ObjectSerializer::SerializeBackingStore(
|
||||
serializer_->reference_map()->Add(backing_store, reference);
|
||||
}
|
||||
|
||||
return static_cast<int32_t>(reference.off_heap_backing_store_index());
|
||||
return reference.off_heap_backing_store_index();
|
||||
}
|
||||
|
||||
void Serializer::ObjectSerializer::SerializeJSTypedArray() {
|
||||
JSTypedArray typed_array = JSTypedArray::cast(object_);
|
||||
if (!typed_array.WasDetached()) {
|
||||
if (!typed_array.is_on_heap()) {
|
||||
if (typed_array.is_on_heap()) {
|
||||
typed_array.RemoveExternalPointerCompensationForSerialization();
|
||||
} else {
|
||||
if (!typed_array.WasDetached()) {
|
||||
// Explicitly serialize the backing store now.
|
||||
JSArrayBuffer buffer = JSArrayBuffer::cast(typed_array.buffer());
|
||||
CHECK_LE(buffer.byte_length(), Smi::kMaxValue);
|
||||
@ -372,21 +374,20 @@ void Serializer::ObjectSerializer::SerializeJSTypedArray() {
|
||||
int32_t byte_length = static_cast<int32_t>(buffer.byte_length());
|
||||
int32_t byte_offset = static_cast<int32_t>(typed_array.byte_offset());
|
||||
|
||||
// We need to calculate the backing store from the external pointer
|
||||
// We need to calculate the backing store from the data pointer
|
||||
// because the ArrayBuffer may already have been serialized.
|
||||
void* backing_store = reinterpret_cast<void*>(
|
||||
reinterpret_cast<intptr_t>(typed_array.external_pointer()) -
|
||||
byte_offset);
|
||||
int32_t ref = SerializeBackingStore(backing_store, byte_length);
|
||||
reinterpret_cast<Address>(typed_array.DataPtr()) - byte_offset);
|
||||
|
||||
// The external_pointer is the backing_store + typed_array->byte_offset.
|
||||
// To properly share the buffer, we set the backing store ref here. On
|
||||
// deserialization we re-add the byte_offset to external_pointer.
|
||||
typed_array.set_external_pointer(
|
||||
reinterpret_cast<void*>(Smi::FromInt(ref).ptr()));
|
||||
uint32_t ref = SerializeBackingStore(backing_store, byte_length);
|
||||
// To properly share the buffer, we set the backing store ref as an
|
||||
// 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 {
|
||||
typed_array.SetOffHeapDataPtr(nullptr, 0);
|
||||
}
|
||||
} else {
|
||||
typed_array.set_external_pointer(nullptr);
|
||||
}
|
||||
SerializeObject();
|
||||
}
|
||||
@ -400,8 +401,11 @@ void Serializer::ObjectSerializer::SerializeJSArrayBuffer() {
|
||||
|
||||
// The embedder-allocated backing store only exists for the off-heap case.
|
||||
if (backing_store != nullptr) {
|
||||
int32_t ref = SerializeBackingStore(backing_store, byte_length);
|
||||
buffer.set_backing_store(reinterpret_cast<void*>(Smi::FromInt(ref).ptr()));
|
||||
uint32_t ref = SerializeBackingStore(backing_store, byte_length);
|
||||
// To properly share the buffer, we set the backing store ref as an
|
||||
// a backing store address. On deserialization we re-set data pointer
|
||||
// to proper value.
|
||||
buffer.set_backing_store(reinterpret_cast<void*>(static_cast<size_t>(ref)));
|
||||
}
|
||||
SerializeObject();
|
||||
buffer.set_backing_store(backing_store);
|
||||
|
@ -328,7 +328,7 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
|
||||
void SerializeContent(Map map, int size);
|
||||
void OutputRawData(Address up_to);
|
||||
void OutputCode(int size);
|
||||
int32_t SerializeBackingStore(void* backing_store, int32_t byte_length);
|
||||
uint32_t SerializeBackingStore(void* backing_store, int32_t byte_length);
|
||||
void SerializeJSTypedArray();
|
||||
void SerializeJSArrayBuffer();
|
||||
void SerializeExternalString();
|
||||
|
Loading…
Reference in New Issue
Block a user