Commit 82c4c977 authored by Shu-yu Guo's avatar Shu-yu Guo Committed by V8 LUCI CQ

[shared-struct] Handle HeapNumbers in Object::IsShared

HeapNumbers that are in the shared heap were incorrectly considered
!IsShared().

TBR=jkummerow@chromium.org

Bug: v8:12547
Change-Id: Ie4b9575445d841a7045c947ff4439bf53a22869d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3504085
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79372}
parent b9af6604
...@@ -6991,15 +6991,13 @@ TNode<BoolT> CodeStubAssembler::IsNumberArrayIndex(TNode<Number> number) { ...@@ -6991,15 +6991,13 @@ TNode<BoolT> CodeStubAssembler::IsNumberArrayIndex(TNode<Number> number) {
[=] { return IsHeapNumberUint32(CAST(number)); }); [=] { return IsHeapNumberUint32(CAST(number)); });
} }
TNode<BoolT> CodeStubAssembler::IsReadOnlyHeapObject(TNode<HeapObject> object) { TNode<IntPtrT> CodeStubAssembler::LoadBasicMemoryChunkFlags(
TNode<HeapObject> object) {
TNode<IntPtrT> object_word = BitcastTaggedToWord(object); TNode<IntPtrT> object_word = BitcastTaggedToWord(object);
TNode<IntPtrT> page = PageFromAddress(object_word); TNode<IntPtrT> page = PageFromAddress(object_word);
TNode<IntPtrT> flags = UncheckedCast<IntPtrT>( return UncheckedCast<IntPtrT>(
Load(MachineType::Pointer(), page, Load(MachineType::Pointer(), page,
IntPtrConstant(BasicMemoryChunk::kFlagsOffset))); IntPtrConstant(BasicMemoryChunk::kFlagsOffset)));
return WordNotEqual(
WordAnd(flags, IntPtrConstant(BasicMemoryChunk::READ_ONLY_HEAP)),
IntPtrConstant(0));
} }
template <typename TIndex> template <typename TIndex>
...@@ -15935,33 +15933,63 @@ void CodeStubAssembler::SwissNameDictionaryAdd(TNode<SwissNameDictionary> table, ...@@ -15935,33 +15933,63 @@ void CodeStubAssembler::SwissNameDictionaryAdd(TNode<SwissNameDictionary> table,
} }
void CodeStubAssembler::SharedValueBarrier( void CodeStubAssembler::SharedValueBarrier(
TNode<Context> context, TNode<Object> value, TNode<Context> context, TVariable<Object>* var_shared_value) {
TVariable<Object>* var_shared_value) {
// The barrier ensures that the value can be shared across Isolates. // The barrier ensures that the value can be shared across Isolates.
// The fast paths should be kept in sync with Object::Share. // The fast paths should be kept in sync with Object::Share.
Label skip_barrier(this); TNode<Object> value = var_shared_value->value();
Label check_in_shared_heap(this), slow(this), skip_barrier(this), done(this);
// Fast path: Smis are trivially shared. // Fast path: Smis are trivially shared.
GotoIf(TaggedIsSmi(value), &skip_barrier); GotoIf(TaggedIsSmi(value), &done);
// Fast path: Shared memory features imply shared RO space, so RO objects are // Fast path: Shared memory features imply shared RO space, so RO objects are
// trivially shared. // trivially shared.
DCHECK(ReadOnlyHeap::IsReadOnlySpaceShared()); DCHECK(ReadOnlyHeap::IsReadOnlySpaceShared());
GotoIf(IsReadOnlyHeapObject(CAST(value)), &skip_barrier); TNode<IntPtrT> page_flags = LoadBasicMemoryChunkFlags(CAST(value));
GotoIf(WordNotEqual(WordAnd(page_flags,
IntPtrConstant(BasicMemoryChunk::READ_ONLY_HEAP)),
IntPtrConstant(0)),
&skip_barrier);
// Fast path: Check if the HeapObject is already shared. // Fast path: Check if the HeapObject is already shared.
TNode<Uint16T> value_instance_type = TNode<Uint16T> value_instance_type =
LoadMapInstanceType(LoadMap(CAST(value))); LoadMapInstanceType(LoadMap(CAST(value)));
GotoIf(IsSharedStringInstanceType(value_instance_type), &skip_barrier); GotoIf(IsSharedStringInstanceType(value_instance_type), &skip_barrier);
GotoIf(IsJSSharedStructInstanceType(value_instance_type), &skip_barrier); GotoIf(IsJSSharedStructInstanceType(value_instance_type), &skip_barrier);
GotoIf(IsHeapNumberInstanceType(value_instance_type), &check_in_shared_heap);
Goto(&slow);
BIND(&check_in_shared_heap);
{
Branch(
WordNotEqual(WordAnd(page_flags,
IntPtrConstant(BasicMemoryChunk::IN_SHARED_HEAP)),
IntPtrConstant(0)),
&skip_barrier, &slow);
}
// Slow path: Call out to runtime to share primitives and to throw on // Slow path: Call out to runtime to share primitives and to throw on
// non-shared JS objects. // non-shared JS objects.
*var_shared_value = BIND(&slow);
CallRuntime(Runtime::kSharedValueBarrierSlow, context, value); {
Goto(&skip_barrier); *var_shared_value =
CallRuntime(Runtime::kSharedValueBarrierSlow, context, value);
Goto(&skip_barrier);
}
BIND(&skip_barrier); BIND(&skip_barrier);
{
CSA_DCHECK(
this,
WordNotEqual(
WordAnd(LoadBasicMemoryChunkFlags(CAST(var_shared_value->value())),
IntPtrConstant(BasicMemoryChunk::READ_ONLY_HEAP |
BasicMemoryChunk::IN_SHARED_HEAP)),
IntPtrConstant(0)));
Goto(&done);
}
BIND(&done);
} }
} // namespace internal } // namespace internal
......
...@@ -2446,8 +2446,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -2446,8 +2446,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TVariable<Numeric>* var_numeric, TVariable<Numeric>* var_numeric,
TVariable<Smi>* var_feedback); TVariable<Smi>* var_feedback);
// Ensures that {value} is shareable across Isolates, and throws if not. // Ensures that {var_shared_value} is shareable across Isolates, and throws if
void SharedValueBarrier(TNode<Context> context, TNode<Object> value, // not.
void SharedValueBarrier(TNode<Context> context,
TVariable<Object>* var_shared_value); TVariable<Object>* var_shared_value);
TNode<WordT> TimesSystemPointerSize(TNode<WordT> value); TNode<WordT> TimesSystemPointerSize(TNode<WordT> value);
...@@ -2644,7 +2645,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -2644,7 +2645,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsUndetectableMap(TNode<Map> map); TNode<BoolT> IsUndetectableMap(TNode<Map> map);
TNode<BoolT> IsNotWeakFixedArraySubclass(TNode<HeapObject> object); TNode<BoolT> IsNotWeakFixedArraySubclass(TNode<HeapObject> object);
TNode<BoolT> IsZeroOrContext(TNode<Object> object); TNode<BoolT> IsZeroOrContext(TNode<Object> object);
TNode<BoolT> IsReadOnlyHeapObject(TNode<HeapObject> object);
TNode<BoolT> IsPromiseResolveProtectorCellInvalid(); TNode<BoolT> IsPromiseResolveProtectorCellInvalid();
TNode<BoolT> IsPromiseThenProtectorCellInvalid(); TNode<BoolT> IsPromiseThenProtectorCellInvalid();
...@@ -2654,6 +2654,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler ...@@ -2654,6 +2654,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsRegExpSpeciesProtectorCellInvalid(); TNode<BoolT> IsRegExpSpeciesProtectorCellInvalid();
TNode<BoolT> IsPromiseSpeciesProtectorCellInvalid(); TNode<BoolT> IsPromiseSpeciesProtectorCellInvalid();
TNode<IntPtrT> LoadBasicMemoryChunkFlags(TNode<HeapObject> object);
TNode<BoolT> LoadRuntimeFlag(ExternalReference address_of_flag) { TNode<BoolT> LoadRuntimeFlag(ExternalReference address_of_flag) {
TNode<Word32T> flag_value = UncheckedCast<Word32T>( TNode<Word32T> flag_value = UncheckedCast<Word32T>(
Load(MachineType::Uint8(), ExternalConstant(address_of_flag))); Load(MachineType::Uint8(), ExternalConstant(address_of_flag)));
......
...@@ -1198,7 +1198,7 @@ void AccessorAssembler::HandleStoreICSmiHandlerJSSharedStructFieldCase( ...@@ -1198,7 +1198,7 @@ void AccessorAssembler::HandleStoreICSmiHandlerJSSharedStructFieldCase(
Int32Constant(Representation::kTagged))); Int32Constant(Representation::kTagged)));
TVARIABLE(Object, shared_value, value); TVARIABLE(Object, shared_value, value);
SharedValueBarrier(context, value, &shared_value); SharedValueBarrier(context, &shared_value);
TNode<BoolT> is_inobject = TNode<BoolT> is_inobject =
IsSetWord32<StoreHandler::IsInobjectBits>(handler_word); IsSetWord32<StoreHandler::IsInobjectBits>(handler_word);
...@@ -1720,7 +1720,7 @@ void AccessorAssembler::StoreJSSharedStructField( ...@@ -1720,7 +1720,7 @@ void AccessorAssembler::StoreJSSharedStructField(
LoadMapInstanceSizeInWords(shared_struct_map); LoadMapInstanceSizeInWords(shared_struct_map);
TVARIABLE(Object, shared_value, maybe_local_value); TVARIABLE(Object, shared_value, maybe_local_value);
SharedValueBarrier(context, maybe_local_value, &shared_value); SharedValueBarrier(context, &shared_value);
Label inobject(this), backing_store(this); Label inobject(this), backing_store(this);
Branch(UintPtrLessThan(field_index, instance_size_in_words), &inobject, Branch(UintPtrLessThan(field_index, instance_size_in_words), &inobject,
......
...@@ -1162,6 +1162,9 @@ Object Object::GetHash() { ...@@ -1162,6 +1162,9 @@ Object Object::GetHash() {
} }
bool Object::IsShared() const { bool Object::IsShared() const {
// This logic should be kept in sync with fast paths in
// CodeStubAssembler::SharedValueBarrier.
// Smis are trivially shared. // Smis are trivially shared.
if (IsSmi()) return true; if (IsSmi()) return true;
...@@ -1186,6 +1189,8 @@ bool Object::IsShared() const { ...@@ -1186,6 +1189,8 @@ bool Object::IsShared() const {
return true; return true;
} }
return false; return false;
case HEAP_NUMBER_TYPE:
return object.InSharedWritableHeap();
default: default:
return false; return false;
} }
......
...@@ -18,7 +18,9 @@ let S = new SharedStructType(['field']); ...@@ -18,7 +18,9 @@ let S = new SharedStructType(['field']);
(function TestPrimitives() { (function TestPrimitives() {
// All primitives can be stored in fields. // All primitives can be stored in fields.
let s = new S(); let s = new S();
for (let prim of [42, -0, undefined, null, true, false, "foo"]) { for (let prim of [42, -0, Math.random(),
undefined, null, true, false,
"foo"]) {
s.field = prim; s.field = prim;
assertEquals(s.field, prim); assertEquals(s.field, prim);
} }
......
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