[shared-struct] Prototype JS shared structs
Unlike the Stage 1 proposal, for simplicity the prototype does not add any new syntax, instead opting for exposing a SharedStructType constructor which takes an array of field names. This type constructor returns constructors for shared structs. Shared structs can be shared across Isolates, are fixed layout, have no prototype, have no .constructor, and can only store primitives and other shared structs. The initial prototype does not have TurboFan support. Bug: v8:12547 Change-Id: I23bdd819940b42139692bcdb53d372099b0d4426 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3390643 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Reviewed-by: Marja Hölttä <marja@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Commit-Queue: Shu-yu Guo <syg@chromium.org> Cr-Commit-Position: refs/heads/main@{#79156}
This commit is contained in:
parent
3ecb92e3b7
commit
1025bf26e3
@ -855,6 +855,7 @@ filegroup(
|
||||
"src/objects/js-regexp-string-iterator.tq",
|
||||
"src/objects/js-regexp.tq",
|
||||
"src/objects/js-shadow-realms.tq",
|
||||
"src/objects/js-struct.tq",
|
||||
"src/objects/js-temporal-objects.tq",
|
||||
"src/objects/js-weak-refs.tq",
|
||||
"src/objects/literal-objects.tq",
|
||||
@ -1054,6 +1055,7 @@ filegroup(
|
||||
"src/builtins/builtins-shadow-realms.cc",
|
||||
"src/builtins/builtins-sharedarraybuffer.cc",
|
||||
"src/builtins/builtins-string.cc",
|
||||
"src/builtins/builtins-struct.cc",
|
||||
"src/builtins/builtins-symbol.cc",
|
||||
"src/builtins/builtins-temporal.cc",
|
||||
"src/builtins/builtins-trace.cc",
|
||||
@ -1644,6 +1646,8 @@ filegroup(
|
||||
"src/objects/js-regexp.h",
|
||||
"src/objects/js-shadow-realms.h",
|
||||
"src/objects/js-shadow-realms-inl.h",
|
||||
"src/objects/js-struct.h",
|
||||
"src/objects/js-struct-inl.h",
|
||||
"src/objects/js-temporal-objects.h",
|
||||
"src/objects/js-temporal-objects-inl.h",
|
||||
"src/objects/js-temporal-objects.cc",
|
||||
|
4
BUILD.gn
4
BUILD.gn
@ -1779,6 +1779,7 @@ torque_files = [
|
||||
"src/objects/js-regexp-string-iterator.tq",
|
||||
"src/objects/js-regexp.tq",
|
||||
"src/objects/js-shadow-realms.tq",
|
||||
"src/objects/js-struct.tq",
|
||||
"src/objects/js-temporal-objects.tq",
|
||||
"src/objects/js-weak-refs.tq",
|
||||
"src/objects/literal-objects.tq",
|
||||
@ -3190,6 +3191,8 @@ v8_header_set("v8_internal_headers") {
|
||||
"src/objects/js-segments.h",
|
||||
"src/objects/js-shadow-realms-inl.h",
|
||||
"src/objects/js-shadow-realms.h",
|
||||
"src/objects/js-struct-inl.h",
|
||||
"src/objects/js-struct.h",
|
||||
"src/objects/js-temporal-objects-inl.h",
|
||||
"src/objects/js-temporal-objects.h",
|
||||
"src/objects/js-weak-refs-inl.h",
|
||||
@ -4064,6 +4067,7 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"src/builtins/builtins-shadow-realms.cc",
|
||||
"src/builtins/builtins-sharedarraybuffer.cc",
|
||||
"src/builtins/builtins-string.cc",
|
||||
"src/builtins/builtins-struct.cc",
|
||||
"src/builtins/builtins-symbol.cc",
|
||||
"src/builtins/builtins-temporal.cc",
|
||||
"src/builtins/builtins-trace.cc",
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include 'src/objects/js-promise.h'
|
||||
#include 'src/objects/js-regexp-string-iterator.h'
|
||||
#include 'src/objects/js-shadow-realms.h'
|
||||
#include 'src/objects/js-struct.h'
|
||||
#include 'src/objects/js-weak-refs.h'
|
||||
#include 'src/objects/objects.h'
|
||||
#include 'src/objects/source-text-module.h'
|
||||
|
@ -123,7 +123,8 @@ class BaseCollectionsAssembler : public CodeStubAssembler {
|
||||
TNode<IntPtrT> EstimatedInitialSize(TNode<Object> initial_entries,
|
||||
TNode<BoolT> is_fast_jsarray);
|
||||
|
||||
void GotoIfNotJSReceiver(const TNode<Object> obj, Label* if_not_receiver);
|
||||
void GotoIfCannotBeWeakKey(const TNode<Object> obj,
|
||||
Label* if_cannot_be_weak_key);
|
||||
|
||||
// Determines whether the collection's prototype has been modified.
|
||||
TNode<BoolT> HasInitialCollectionPrototype(Variant variant,
|
||||
@ -522,10 +523,14 @@ TNode<IntPtrT> BaseCollectionsAssembler::EstimatedInitialSize(
|
||||
[=] { return IntPtrConstant(0); });
|
||||
}
|
||||
|
||||
void BaseCollectionsAssembler::GotoIfNotJSReceiver(const TNode<Object> obj,
|
||||
Label* if_not_receiver) {
|
||||
GotoIf(TaggedIsSmi(obj), if_not_receiver);
|
||||
GotoIfNot(IsJSReceiver(CAST(obj)), if_not_receiver);
|
||||
void BaseCollectionsAssembler::GotoIfCannotBeWeakKey(
|
||||
const TNode<Object> obj, Label* if_cannot_be_weak_key) {
|
||||
GotoIf(TaggedIsSmi(obj), if_cannot_be_weak_key);
|
||||
TNode<Uint16T> instance_type = LoadMapInstanceType(LoadMap(CAST(obj)));
|
||||
GotoIfNot(IsJSReceiverInstanceType(instance_type), if_cannot_be_weak_key);
|
||||
// TODO(v8:12547) Shared structs should only be able to point to shared values
|
||||
// in weak collections. For now, disallow them as weak collection keys.
|
||||
GotoIf(IsJSSharedStructInstanceType(instance_type), if_cannot_be_weak_key);
|
||||
}
|
||||
|
||||
TNode<Map> BaseCollectionsAssembler::GetInitialCollectionPrototype(
|
||||
@ -2723,17 +2728,18 @@ TF_BUILTIN(WeakMapLookupHashIndex, WeakCollectionsBuiltinsAssembler) {
|
||||
auto table = Parameter<EphemeronHashTable>(Descriptor::kTable);
|
||||
auto key = Parameter<Object>(Descriptor::kKey);
|
||||
|
||||
Label if_not_found(this);
|
||||
Label if_cannot_be_weak_key(this);
|
||||
|
||||
GotoIfNotJSReceiver(key, &if_not_found);
|
||||
GotoIfCannotBeWeakKey(key, &if_cannot_be_weak_key);
|
||||
|
||||
TNode<IntPtrT> hash = LoadJSReceiverIdentityHash(CAST(key), &if_not_found);
|
||||
TNode<IntPtrT> hash =
|
||||
LoadJSReceiverIdentityHash(CAST(key), &if_cannot_be_weak_key);
|
||||
TNode<IntPtrT> capacity = LoadTableCapacity(table);
|
||||
TNode<IntPtrT> key_index =
|
||||
FindKeyIndexForKey(table, key, hash, EntryMask(capacity), &if_not_found);
|
||||
TNode<IntPtrT> key_index = FindKeyIndexForKey(
|
||||
table, key, hash, EntryMask(capacity), &if_cannot_be_weak_key);
|
||||
Return(SmiTag(ValueIndexFromKeyIndex(key_index)));
|
||||
|
||||
BIND(&if_not_found);
|
||||
BIND(&if_cannot_be_weak_key);
|
||||
Return(SmiConstant(-1));
|
||||
}
|
||||
|
||||
@ -2788,22 +2794,23 @@ TF_BUILTIN(WeakCollectionDelete, WeakCollectionsBuiltinsAssembler) {
|
||||
auto collection = Parameter<JSWeakCollection>(Descriptor::kCollection);
|
||||
auto key = Parameter<Object>(Descriptor::kKey);
|
||||
|
||||
Label call_runtime(this), if_not_found(this);
|
||||
Label call_runtime(this), if_cannot_be_weak_key(this);
|
||||
|
||||
GotoIfNotJSReceiver(key, &if_not_found);
|
||||
GotoIfCannotBeWeakKey(key, &if_cannot_be_weak_key);
|
||||
|
||||
TNode<IntPtrT> hash = LoadJSReceiverIdentityHash(CAST(key), &if_not_found);
|
||||
TNode<IntPtrT> hash =
|
||||
LoadJSReceiverIdentityHash(CAST(key), &if_cannot_be_weak_key);
|
||||
TNode<EphemeronHashTable> table = LoadTable(collection);
|
||||
TNode<IntPtrT> capacity = LoadTableCapacity(table);
|
||||
TNode<IntPtrT> key_index =
|
||||
FindKeyIndexForKey(table, key, hash, EntryMask(capacity), &if_not_found);
|
||||
TNode<IntPtrT> key_index = FindKeyIndexForKey(
|
||||
table, key, hash, EntryMask(capacity), &if_cannot_be_weak_key);
|
||||
TNode<IntPtrT> number_of_elements = LoadNumberOfElements(table, -1);
|
||||
GotoIf(ShouldShrink(capacity, number_of_elements), &call_runtime);
|
||||
|
||||
RemoveEntry(table, key_index, number_of_elements);
|
||||
Return(TrueConstant());
|
||||
|
||||
BIND(&if_not_found);
|
||||
BIND(&if_cannot_be_weak_key);
|
||||
Return(FalseConstant());
|
||||
|
||||
BIND(&call_runtime);
|
||||
@ -2884,7 +2891,7 @@ TF_BUILTIN(WeakMapPrototypeSet, WeakCollectionsBuiltinsAssembler) {
|
||||
"WeakMap.prototype.set");
|
||||
|
||||
Label throw_invalid_key(this);
|
||||
GotoIfNotJSReceiver(key, &throw_invalid_key);
|
||||
GotoIfCannotBeWeakKey(key, &throw_invalid_key);
|
||||
|
||||
Return(
|
||||
CallBuiltin(Builtin::kWeakCollectionSet, context, receiver, key, value));
|
||||
@ -2902,7 +2909,7 @@ TF_BUILTIN(WeakSetPrototypeAdd, WeakCollectionsBuiltinsAssembler) {
|
||||
"WeakSet.prototype.add");
|
||||
|
||||
Label throw_invalid_value(this);
|
||||
GotoIfNotJSReceiver(value, &throw_invalid_value);
|
||||
GotoIfCannotBeWeakKey(value, &throw_invalid_value);
|
||||
|
||||
Return(CallBuiltin(Builtin::kWeakCollectionSet, context, receiver, value,
|
||||
TrueConstant()));
|
||||
|
@ -985,6 +985,10 @@ namespace internal {
|
||||
TFS(WeakCollectionDelete, kCollection, kKey) \
|
||||
TFS(WeakCollectionSet, kCollection, kKey, kValue) \
|
||||
\
|
||||
/* JS Structs */ \
|
||||
CPP(SharedStructTypeConstructor) \
|
||||
CPP(SharedStructConstructor) \
|
||||
\
|
||||
/* AsyncGenerator */ \
|
||||
\
|
||||
TFS(AsyncGeneratorResolve, kGenerator, kValue, kDone) \
|
||||
|
123
src/builtins/builtins-struct.cc
Normal file
123
src/builtins/builtins-struct.cc
Normal file
@ -0,0 +1,123 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/builtins/builtins-utils-inl.h"
|
||||
#include "src/objects/js-struct-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
constexpr int kMaxJSStructFields = 999;
|
||||
|
||||
#ifdef V8_ENABLE_WEBASSEMBLY
|
||||
#include "src/wasm/wasm-limits.h"
|
||||
static_assert(wasm::kV8MaxWasmStructFields == kMaxJSStructFields,
|
||||
"Max number of fields should be the same for both JS and "
|
||||
"WebAssembly structs");
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
|
||||
BUILTIN(SharedStructTypeConstructor) {
|
||||
DCHECK(FLAG_shared_string_table);
|
||||
|
||||
HandleScope scope(isolate);
|
||||
static const char method_name[] = "SharedStructType";
|
||||
auto* factory = isolate->factory();
|
||||
|
||||
Handle<JSReceiver> field_names_arg;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, field_names_arg,
|
||||
Object::ToObject(isolate, args.atOrUndefined(isolate, 1), method_name));
|
||||
|
||||
// Treat field_names_arg as arraylike.
|
||||
Handle<Object> raw_length_number;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, raw_length_number,
|
||||
Object::GetLengthFromArrayLike(isolate, field_names_arg));
|
||||
double num_properties_double = raw_length_number->Number();
|
||||
if (num_properties_double < 0 || num_properties_double > kMaxJSStructFields) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewRangeError(MessageTemplate::kStructFieldCountOutOfRange));
|
||||
}
|
||||
int num_properties = static_cast<int>(num_properties_double);
|
||||
|
||||
Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(
|
||||
num_properties, 0, AllocationType::kSharedOld);
|
||||
|
||||
// Build up the descriptor array.
|
||||
for (int i = 0; i < num_properties; ++i) {
|
||||
Handle<Object> raw_field_name;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, raw_field_name,
|
||||
JSReceiver::GetElement(isolate, field_names_arg, i));
|
||||
Handle<Name> field_name;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, field_name,
|
||||
Object::ToName(isolate, raw_field_name));
|
||||
field_name = factory->InternalizeName(field_name);
|
||||
|
||||
// Shared structs' fields need to be aligned, so make it all tagged.
|
||||
PropertyDetails details(
|
||||
PropertyKind::kData, SEALED, PropertyLocation::kField,
|
||||
PropertyConstness::kMutable, Representation::Tagged(), i);
|
||||
descriptors->Set(InternalIndex(i), *field_name,
|
||||
MaybeObject::FromObject(FieldType::Any()), details);
|
||||
}
|
||||
descriptors->Sort();
|
||||
|
||||
Handle<SharedFunctionInfo> info =
|
||||
isolate->factory()->NewSharedFunctionInfoForBuiltin(
|
||||
isolate->factory()->empty_string(), Builtin::kSharedStructConstructor,
|
||||
FunctionKind::kNormalFunction);
|
||||
info->set_internal_formal_parameter_count(JSParameterCount(0));
|
||||
info->set_length(0);
|
||||
|
||||
Handle<JSFunction> constructor =
|
||||
Factory::JSFunctionBuilder{isolate, info, isolate->native_context()}
|
||||
.set_map(isolate->strict_function_map())
|
||||
.Build();
|
||||
|
||||
int instance_size;
|
||||
int in_object_properties;
|
||||
JSFunction::CalculateInstanceSizeHelper(JS_SHARED_STRUCT_TYPE, false, 0,
|
||||
num_properties, &instance_size,
|
||||
&in_object_properties);
|
||||
Handle<Map> instance_map = factory->NewMap(
|
||||
JS_SHARED_STRUCT_TYPE, instance_size, TERMINAL_FAST_ELEMENTS_KIND,
|
||||
in_object_properties, AllocationType::kSharedMap);
|
||||
|
||||
instance_map->InitializeDescriptors(isolate, *descriptors);
|
||||
// Structs have fixed layout ahead of time, so there's no slack.
|
||||
instance_map->SetInObjectUnusedPropertyFields(0);
|
||||
instance_map->set_is_extensible(false);
|
||||
JSFunction::SetInitialMap(isolate, constructor, instance_map,
|
||||
factory->null_value());
|
||||
|
||||
// The constructor is not a shared object, so the shared map should not point
|
||||
// to it.
|
||||
instance_map->set_constructor_or_back_pointer(*factory->null_value());
|
||||
|
||||
return *constructor;
|
||||
}
|
||||
|
||||
BUILTIN(SharedStructConstructor) {
|
||||
HandleScope scope(isolate);
|
||||
auto* factory = isolate->factory();
|
||||
|
||||
Handle<JSObject> instance =
|
||||
factory->NewJSObject(args.target(), AllocationType::kSharedOld);
|
||||
|
||||
Handle<Map> instance_map(instance->map(), isolate);
|
||||
if (instance_map->HasOutOfObjectProperties()) {
|
||||
int num_oob_fields =
|
||||
instance_map->NumberOfFields(ConcurrencyMode::kNotConcurrent) -
|
||||
instance_map->GetInObjectProperties();
|
||||
Handle<PropertyArray> property_array =
|
||||
factory->NewPropertyArray(num_oob_fields, AllocationType::kSharedOld);
|
||||
instance->SetProperties(*property_array);
|
||||
}
|
||||
|
||||
return *instance;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -3042,6 +3042,25 @@ void CodeStubAssembler::UnsafeStoreObjectFieldNoWriteBarrier(
|
||||
object, offset, value);
|
||||
}
|
||||
|
||||
void CodeStubAssembler::StoreJSSharedStructInObjectField(
|
||||
TNode<HeapObject> object, TNode<IntPtrT> offset, TNode<Object> value) {
|
||||
CSA_DCHECK(this, IsJSSharedStruct(object));
|
||||
// JSSharedStructs are allocated in the shared old space, which is currently
|
||||
// collected by stopping the world, so the incremental write barrier is not
|
||||
// needed. They can only store Smis and other HeapObjects in the shared old
|
||||
// space, so the generational write barrier is also not needed.
|
||||
// TODO(v8:12547): Add a safer, shared variant of NoWriteBarrier instead of
|
||||
// using Unsafe.
|
||||
int const_offset;
|
||||
if (TryToInt32Constant(offset, &const_offset)) {
|
||||
UnsafeStoreObjectFieldNoWriteBarrier(object, const_offset, value);
|
||||
} else {
|
||||
UnsafeStoreNoWriteBarrier(MachineRepresentation::kTagged, object,
|
||||
IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)),
|
||||
value);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeStubAssembler::StoreMap(TNode<HeapObject> object, TNode<Map> map) {
|
||||
OptimizedStoreMap(object, map);
|
||||
DcheckHasValidMap(object);
|
||||
@ -6540,6 +6559,19 @@ TNode<BoolT> CodeStubAssembler::IsJSArrayIterator(TNode<HeapObject> object) {
|
||||
return HasInstanceType(object, JS_ARRAY_ITERATOR_TYPE);
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsJSSharedStructInstanceType(
|
||||
TNode<Int32T> instance_type) {
|
||||
return InstanceTypeEqual(instance_type, JS_SHARED_STRUCT_TYPE);
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsJSSharedStructMap(TNode<Map> map) {
|
||||
return IsJSSharedStructInstanceType(LoadMapInstanceType(map));
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsJSSharedStruct(TNode<HeapObject> object) {
|
||||
return IsJSSharedStructMap(LoadMap(object));
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsJSAsyncGeneratorObject(
|
||||
TNode<HeapObject> object) {
|
||||
return HasInstanceType(object, JS_ASYNC_GENERATOR_OBJECT_TYPE);
|
||||
@ -6668,6 +6700,19 @@ TNode<BoolT> CodeStubAssembler::IsInternalizedStringInstanceType(
|
||||
Int32Constant(kStringTag | kInternalizedTag));
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsSharedStringInstanceType(
|
||||
TNode<Int32T> instance_type) {
|
||||
TNode<BoolT> is_shared = Word32Equal(
|
||||
Word32And(instance_type,
|
||||
Int32Constant(kIsNotStringMask | kSharedStringMask)),
|
||||
Int32Constant(kStringTag | kSharedStringTag));
|
||||
// TODO(v8:12007): Internalized strings do not have kSharedStringTag until
|
||||
// the shared string table ships.
|
||||
return Word32Or(is_shared,
|
||||
Word32And(HasSharedStringTableFlag(),
|
||||
IsInternalizedStringInstanceType(instance_type)));
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsUniqueName(TNode<HeapObject> object) {
|
||||
TNode<Uint16T> instance_type = LoadInstanceType(object);
|
||||
return Select<BoolT>(
|
||||
@ -6941,6 +6986,17 @@ TNode<BoolT> CodeStubAssembler::IsNumberArrayIndex(TNode<Number> number) {
|
||||
[=] { return IsHeapNumberUint32(CAST(number)); });
|
||||
}
|
||||
|
||||
TNode<BoolT> CodeStubAssembler::IsReadOnlyHeapObject(TNode<HeapObject> object) {
|
||||
TNode<IntPtrT> object_word = BitcastTaggedToWord(object);
|
||||
TNode<IntPtrT> page = PageFromAddress(object_word);
|
||||
TNode<IntPtrT> flags = UncheckedCast<IntPtrT>(
|
||||
Load(MachineType::Pointer(), page,
|
||||
IntPtrConstant(BasicMemoryChunk::kFlagsOffset)));
|
||||
return WordNotEqual(
|
||||
WordAnd(flags, IntPtrConstant(BasicMemoryChunk::READ_ONLY_HEAP)),
|
||||
IntPtrConstant(0));
|
||||
}
|
||||
|
||||
template <typename TIndex>
|
||||
TNode<BoolT> CodeStubAssembler::FixedArraySizeDoesntFitInNewSpace(
|
||||
TNode<TIndex> element_count, int base_size) {
|
||||
@ -15794,5 +15850,35 @@ void CodeStubAssembler::SwissNameDictionaryAdd(TNode<SwissNameDictionary> table,
|
||||
}
|
||||
}
|
||||
|
||||
void CodeStubAssembler::SharedValueBarrier(
|
||||
TNode<Context> context, TNode<Object> value,
|
||||
TVariable<Object>* var_shared_value) {
|
||||
// The barrier ensures that the value can be shared across Isolates.
|
||||
// The fast paths should be kept in sync with Object::Share.
|
||||
|
||||
Label skip_barrier(this);
|
||||
|
||||
// Fast path: Smis are trivially shared.
|
||||
GotoIf(TaggedIsSmi(value), &skip_barrier);
|
||||
// Fast path: Shared memory features imply shared RO space, so RO objects are
|
||||
// trivially shared.
|
||||
DCHECK(ReadOnlyHeap::IsReadOnlySpaceShared());
|
||||
GotoIf(IsReadOnlyHeapObject(CAST(value)), &skip_barrier);
|
||||
|
||||
// Fast path: Check if the HeapObject is already shared.
|
||||
TNode<Uint16T> value_instance_type =
|
||||
LoadMapInstanceType(LoadMap(CAST(value)));
|
||||
GotoIf(IsSharedStringInstanceType(value_instance_type), &skip_barrier);
|
||||
GotoIf(IsJSSharedStructInstanceType(value_instance_type), &skip_barrier);
|
||||
|
||||
// Slow path: Call out to runtime to share primitives and to throw on
|
||||
// non-shared JS objects.
|
||||
*var_shared_value =
|
||||
CallRuntime(Runtime::kSharedValueBarrierSlow, context, value);
|
||||
Goto(&skip_barrier);
|
||||
|
||||
BIND(&skip_barrier);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -1807,6 +1807,22 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
int additional_offset = 0);
|
||||
|
||||
void StoreJSSharedStructInObjectField(TNode<HeapObject> object,
|
||||
TNode<IntPtrT> offset,
|
||||
TNode<Object> value);
|
||||
|
||||
void StoreJSSharedStructPropertyArrayElement(TNode<PropertyArray> array,
|
||||
TNode<IntPtrT> index,
|
||||
TNode<Object> value) {
|
||||
// JSSharedStructs are allocated in the shared old space, which is currently
|
||||
// collected by stopping the world, so the incremental write barrier is not
|
||||
// needed. They can only store Smis and other HeapObjects in the shared old
|
||||
// space, so the generational write barrier is also not needed.
|
||||
// TODO(v8:12547): Add a safer, shared variant of SKIP_WRITE_BARRIER.
|
||||
StoreFixedArrayOrPropertyArrayElement(array, index, value,
|
||||
UNSAFE_SKIP_WRITE_BARRIER);
|
||||
}
|
||||
|
||||
// EnsureArrayPushable verifies that receiver with this map is:
|
||||
// 1. Is not a prototype.
|
||||
// 2. Is not a dictionary.
|
||||
@ -2427,6 +2443,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
TVariable<Numeric>* var_numeric,
|
||||
TVariable<Smi>* var_feedback);
|
||||
|
||||
// Ensures that {value} is shareable across Isolates, and throws if not.
|
||||
void SharedValueBarrier(TNode<Context> context, TNode<Object> value,
|
||||
TVariable<Object>* var_shared_value);
|
||||
|
||||
TNode<WordT> TimesSystemPointerSize(TNode<WordT> value);
|
||||
TNode<IntPtrT> TimesSystemPointerSize(TNode<IntPtrT> value) {
|
||||
return Signed(TimesSystemPointerSize(implicit_cast<TNode<WordT>>(value)));
|
||||
@ -2570,6 +2590,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
TNode<BoolT> IsJSPrimitiveWrapperInstanceType(TNode<Int32T> instance_type);
|
||||
TNode<BoolT> IsJSPrimitiveWrapperMap(TNode<Map> map);
|
||||
TNode<BoolT> IsJSPrimitiveWrapper(TNode<HeapObject> object);
|
||||
TNode<BoolT> IsJSSharedStructInstanceType(TNode<Int32T> instance_type);
|
||||
TNode<BoolT> IsJSSharedStructMap(TNode<Map> map);
|
||||
TNode<BoolT> IsJSSharedStruct(TNode<HeapObject> object);
|
||||
TNode<BoolT> IsMap(TNode<HeapObject> object);
|
||||
TNode<BoolT> IsName(TNode<HeapObject> object);
|
||||
TNode<BoolT> IsNameInstanceType(TNode<Int32T> instance_type);
|
||||
@ -2609,6 +2632,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
|
||||
TNode<BoolT> IsSymbolInstanceType(TNode<Int32T> instance_type);
|
||||
TNode<BoolT> IsInternalizedStringInstanceType(TNode<Int32T> instance_type);
|
||||
TNode<BoolT> IsSharedStringInstanceType(TNode<Int32T> instance_type);
|
||||
TNode<BoolT> IsTemporalInstantInstanceType(TNode<Int32T> instance_type);
|
||||
TNode<BoolT> IsUniqueName(TNode<HeapObject> object);
|
||||
TNode<BoolT> IsUniqueNameNoIndex(TNode<HeapObject> object);
|
||||
@ -2616,6 +2640,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
TNode<BoolT> IsUndetectableMap(TNode<Map> map);
|
||||
TNode<BoolT> IsNotWeakFixedArraySubclass(TNode<HeapObject> object);
|
||||
TNode<BoolT> IsZeroOrContext(TNode<Object> object);
|
||||
TNode<BoolT> IsReadOnlyHeapObject(TNode<HeapObject> object);
|
||||
|
||||
TNode<BoolT> IsPromiseResolveProtectorCellInvalid();
|
||||
TNode<BoolT> IsPromiseThenProtectorCellInvalid();
|
||||
@ -2642,6 +2667,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
ExternalReference::address_of_builtin_subclassing_flag());
|
||||
}
|
||||
|
||||
TNode<BoolT> HasSharedStringTableFlag() {
|
||||
return LoadRuntimeFlag(
|
||||
ExternalReference::address_of_shared_string_table_flag());
|
||||
}
|
||||
|
||||
// True iff |object| is a Smi or a HeapNumber or a BigInt.
|
||||
TNode<BoolT> IsNumeric(TNode<Object> object);
|
||||
|
||||
|
@ -558,6 +558,10 @@ ExternalReference ExternalReference::address_of_runtime_stats_flag() {
|
||||
return ExternalReference(&TracingFlags::runtime_stats);
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::address_of_shared_string_table_flag() {
|
||||
return ExternalReference(&FLAG_shared_string_table);
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::address_of_load_from_stack_count(
|
||||
const char* function_name) {
|
||||
return ExternalReference(
|
||||
|
@ -104,6 +104,7 @@ class StatsCounter;
|
||||
"FLAG_mock_arraybuffer_allocator") \
|
||||
V(address_of_one_half, "LDoubleConstant::one_half") \
|
||||
V(address_of_runtime_stats_flag, "TracingFlags::runtime_stats") \
|
||||
V(address_of_shared_string_table_flag, "FLAG_shared_string_table") \
|
||||
V(address_of_the_hole_nan, "the_hole_nan") \
|
||||
V(address_of_uint32_bias, "uint32_bias") \
|
||||
V(baseline_pc_for_bytecode_offset, "BaselinePCForBytecodeOffset") \
|
||||
|
@ -60,6 +60,7 @@ namespace internal {
|
||||
"CallSite expects wasm object as first or function as second argument, " \
|
||||
"got <%, %>") \
|
||||
T(CallSiteMethod, "CallSite method % expects CallSite as receiver") \
|
||||
T(CannotBeShared, "% cannot be shared") \
|
||||
T(CannotConvertToPrimitive, "Cannot convert object to primitive value") \
|
||||
T(CannotPreventExt, "Cannot prevent extensions") \
|
||||
T(CannotFreeze, "Cannot freeze") \
|
||||
@ -385,6 +386,8 @@ namespace internal {
|
||||
T(ToPrecisionFormatRange, \
|
||||
"toPrecision() argument must be between 1 and 100") \
|
||||
T(ToRadixFormatRange, "toString() radix argument must be between 2 and 36") \
|
||||
T(StructFieldCountOutOfRange, \
|
||||
"Struct field count out of range (maximum of 999 allowed)") \
|
||||
T(TypedArraySetOffsetOutOfBounds, "offset is out of bounds") \
|
||||
T(TypedArraySetSourceTooLarge, "Source is too large") \
|
||||
T(TypedArrayTooLargeToSort, \
|
||||
|
@ -1162,6 +1162,14 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
||||
ZoneVector<PropertyAccessInfo> access_infos_for_feedback(zone());
|
||||
for (const MapRef& map : inferred_maps) {
|
||||
if (map.is_deprecated()) continue;
|
||||
|
||||
// TODO(v8:12547): Support writing to shared structs, which needs a write
|
||||
// barrier that calls Object::Share to ensure the RHS is shared.
|
||||
if (InstanceTypeChecker::IsJSSharedStruct(map.instance_type()) &&
|
||||
access_mode == AccessMode::kStore) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
|
||||
map, feedback.name(), access_mode, dependencies());
|
||||
access_infos_for_feedback.push_back(access_info);
|
||||
@ -1732,6 +1740,13 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
||||
&prototype_maps)) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// TODO(v8:12547): Support writing to shared structs, which needs a
|
||||
// write barrier that calls Object::Share to ensure the RHS is shared.
|
||||
if (InstanceTypeChecker::IsJSSharedStruct(
|
||||
receiver_map.instance_type())) {
|
||||
return NoChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
for (MapRef const& prototype_map : prototype_maps) {
|
||||
|
@ -258,6 +258,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
|
||||
case JS_WEAK_SET_TYPE:
|
||||
case JS_PROMISE_TYPE:
|
||||
case JS_SHADOW_REALM_TYPE:
|
||||
case JS_SHARED_STRUCT_TYPE:
|
||||
case JS_TEMPORAL_CALENDAR_TYPE:
|
||||
case JS_TEMPORAL_DURATION_TYPE:
|
||||
case JS_TEMPORAL_INSTANT_TYPE:
|
||||
|
@ -5148,7 +5148,9 @@ void Shell::WaitForRunningWorkers() {
|
||||
|
||||
namespace {
|
||||
|
||||
bool HasFlagThatRequiresSharedIsolate() { return i::FLAG_shared_string_table; }
|
||||
bool HasFlagThatRequiresSharedIsolate() {
|
||||
return i::FLAG_shared_string_table || i::FLAG_harmony_struct;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -61,6 +61,7 @@
|
||||
#include "src/objects/js-segmenter-inl.h"
|
||||
#include "src/objects/js-segments-inl.h"
|
||||
#endif // V8_INTL_SUPPORT
|
||||
#include "src/objects/js-struct-inl.h"
|
||||
#include "src/objects/js-temporal-objects-inl.h"
|
||||
#include "src/objects/js-weak-refs-inl.h"
|
||||
#include "src/objects/literal-objects-inl.h"
|
||||
@ -98,7 +99,7 @@ namespace internal {
|
||||
// every encountered tagged pointer.
|
||||
// - Verification should be pushed down to the specific instance type if its
|
||||
// integrity is independent of an outer object.
|
||||
// - In cases where the InstanceType is too genernic (e.g. FixedArray) the
|
||||
// - In cases where the InstanceType is too generic (e.g. FixedArray) the
|
||||
// XXXVerify of the outer method has to do recursive verification.
|
||||
// - If the corresponding objects have inheritence the parent's Verify method
|
||||
// is called as well.
|
||||
@ -1182,6 +1183,33 @@ void JSMapIterator::JSMapIteratorVerify(Isolate* isolate) {
|
||||
|
||||
USE_TORQUE_VERIFIER(JSShadowRealm)
|
||||
|
||||
void JSSharedStruct::JSSharedStructVerify(Isolate* isolate) {
|
||||
CHECK(IsJSSharedStruct());
|
||||
JSObjectVerify(isolate);
|
||||
CHECK(HasFastProperties());
|
||||
// Shared structs can only point to primitives or other shared HeapObjects,
|
||||
// even internally.
|
||||
// TODO(v8:12547): Generalize shared -> shared pointer verification.
|
||||
Map struct_map = map();
|
||||
CHECK(struct_map.InSharedHeap());
|
||||
CHECK(struct_map.GetBackPointer().IsUndefined(isolate));
|
||||
Object maybe_cell = struct_map.prototype_validity_cell();
|
||||
if (maybe_cell.IsCell()) CHECK(maybe_cell.InSharedHeap());
|
||||
CHECK(!struct_map.is_extensible());
|
||||
CHECK(!struct_map.is_prototype_map());
|
||||
CHECK(property_array().InSharedHeap());
|
||||
DescriptorArray descriptors = struct_map.instance_descriptors(isolate);
|
||||
CHECK(descriptors.InSharedHeap());
|
||||
for (InternalIndex i : struct_map.IterateOwnDescriptors()) {
|
||||
PropertyDetails details = descriptors.GetDetails(i);
|
||||
CHECK_EQ(PropertyKind::kData, details.kind());
|
||||
CHECK_EQ(PropertyLocation::kField, details.location());
|
||||
CHECK(details.representation().IsTagged());
|
||||
CHECK(
|
||||
RawFastPropertyAt(FieldIndex::ForDescriptor(struct_map, i)).IsShared());
|
||||
}
|
||||
}
|
||||
|
||||
void WeakCell::WeakCellVerify(Isolate* isolate) {
|
||||
CHECK(IsWeakCell());
|
||||
|
||||
|
@ -1425,6 +1425,14 @@ void JSFinalizationRegistry::JSFinalizationRegistryPrint(std::ostream& os) {
|
||||
JSObjectPrintBody(os, *this);
|
||||
}
|
||||
|
||||
void JSSharedStruct::JSSharedStructPrint(std::ostream& os) {
|
||||
JSObjectPrintHeader(os, *this, "JSSharedStruct");
|
||||
Isolate* isolate = GetIsolateFromWritableObject(*this);
|
||||
os << "\n - isolate: " << isolate;
|
||||
if (isolate->is_shared()) os << " (shared)";
|
||||
JSObjectPrintBody(os, *this);
|
||||
}
|
||||
|
||||
void JSWeakMap::JSWeakMapPrint(std::ostream& os) {
|
||||
JSObjectPrintHeader(os, *this, "JSWeakMap");
|
||||
os << "\n - table: " << Brief(table());
|
||||
|
@ -308,7 +308,8 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
|
||||
"harmony ResizableArrayBuffer / GrowableSharedArrayBuffer") \
|
||||
V(harmony_temporal, "Temporal") \
|
||||
V(harmony_shadow_realm, "harmony ShadowRealm") \
|
||||
V(harmony_array_grouping, "harmony array grouping")
|
||||
V(harmony_array_grouping, "harmony array grouping") \
|
||||
V(harmony_struct, "harmony structs and shared structs")
|
||||
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
#define HARMONY_INPROGRESS(V) \
|
||||
@ -716,6 +717,7 @@ DEFINE_BOOL(trace_baseline_concurrent_compilation, false,
|
||||
|
||||
// Internalize into a shared string table in the shared isolate
|
||||
DEFINE_BOOL(shared_string_table, false, "internalize strings into shared table")
|
||||
DEFINE_IMPLICATION(harmony_struct, shared_string_table)
|
||||
|
||||
#if !defined(V8_OS_MACOSX) || !defined(V8_HOST_ARCH_ARM64)
|
||||
DEFINE_BOOL(write_code_using_rwx, true,
|
||||
|
@ -47,6 +47,8 @@ template V8_EXPORT_PRIVATE Handle<HeapNumber>
|
||||
FactoryBase<Factory>::NewHeapNumber<AllocationType::kOld>();
|
||||
template V8_EXPORT_PRIVATE Handle<HeapNumber>
|
||||
FactoryBase<Factory>::NewHeapNumber<AllocationType::kReadOnly>();
|
||||
template V8_EXPORT_PRIVATE Handle<HeapNumber>
|
||||
FactoryBase<Factory>::NewHeapNumber<AllocationType::kSharedOld>();
|
||||
|
||||
template V8_EXPORT_PRIVATE Handle<HeapNumber>
|
||||
FactoryBase<LocalFactory>::NewHeapNumber<AllocationType::kOld>();
|
||||
|
@ -444,10 +444,11 @@ Handle<Oddball> Factory::NewBasicBlockCountersMarker() {
|
||||
Oddball::kBasicBlockCountersMarker);
|
||||
}
|
||||
|
||||
Handle<PropertyArray> Factory::NewPropertyArray(int length) {
|
||||
Handle<PropertyArray> Factory::NewPropertyArray(int length,
|
||||
AllocationType allocation) {
|
||||
DCHECK_LE(0, length);
|
||||
if (length == 0) return empty_property_array();
|
||||
HeapObject result = AllocateRawFixedArray(length, AllocationType::kYoung);
|
||||
HeapObject result = AllocateRawFixedArray(length, allocation);
|
||||
DisallowGarbageCollection no_gc;
|
||||
result.set_map_after_allocation(*property_array_map(), SKIP_WRITE_BARRIER);
|
||||
PropertyArray array = PropertyArray::cast(result);
|
||||
@ -1850,15 +1851,19 @@ Handle<Map> Factory::NewMap(InstanceType type, int instance_size,
|
||||
HeapObject result = isolate()->heap()->AllocateRawWith<Heap::kRetryOrFail>(
|
||||
Map::kSize, allocation_type);
|
||||
DisallowGarbageCollection no_gc;
|
||||
result.set_map_after_allocation(*meta_map(), SKIP_WRITE_BARRIER);
|
||||
Heap* roots = allocation_type == AllocationType::kMap
|
||||
? isolate()->heap()
|
||||
: isolate()->shared_isolate()->heap();
|
||||
result.set_map_after_allocation(ReadOnlyRoots(roots).meta_map(),
|
||||
SKIP_WRITE_BARRIER);
|
||||
return handle(InitializeMap(Map::cast(result), type, instance_size,
|
||||
elements_kind, inobject_properties),
|
||||
elements_kind, inobject_properties, roots),
|
||||
isolate());
|
||||
}
|
||||
|
||||
Map Factory::InitializeMap(Map map, InstanceType type, int instance_size,
|
||||
ElementsKind elements_kind,
|
||||
int inobject_properties) {
|
||||
ElementsKind elements_kind, int inobject_properties,
|
||||
Heap* roots) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
map.set_bit_field(0);
|
||||
map.set_bit_field2(Map::Bits2::NewTargetIsBaseBit::encode(true));
|
||||
@ -1869,7 +1874,8 @@ Map Factory::InitializeMap(Map map, InstanceType type, int instance_size,
|
||||
Map::Bits3::IsExtensibleBit::encode(true);
|
||||
map.set_bit_field3(bit_field3);
|
||||
map.set_instance_type(type);
|
||||
HeapObject raw_null_value = *null_value();
|
||||
ReadOnlyRoots ro_roots(roots);
|
||||
HeapObject raw_null_value = ro_roots.null_value();
|
||||
map.set_prototype(raw_null_value, SKIP_WRITE_BARRIER);
|
||||
map.set_constructor_or_back_pointer(raw_null_value, SKIP_WRITE_BARRIER);
|
||||
map.set_instance_size(instance_size);
|
||||
@ -1878,20 +1884,19 @@ Map Factory::InitializeMap(Map map, InstanceType type, int instance_size,
|
||||
map.SetInObjectPropertiesStartInWords(instance_size / kTaggedSize -
|
||||
inobject_properties);
|
||||
DCHECK_EQ(map.GetInObjectProperties(), inobject_properties);
|
||||
map.set_prototype_validity_cell(*invalid_prototype_validity_cell());
|
||||
map.set_prototype_validity_cell(roots->invalid_prototype_validity_cell());
|
||||
} else {
|
||||
DCHECK_EQ(inobject_properties, 0);
|
||||
map.set_inobject_properties_start_or_constructor_function_index(0);
|
||||
map.set_prototype_validity_cell(Smi::FromInt(Map::kPrototypeChainValid),
|
||||
SKIP_WRITE_BARRIER);
|
||||
}
|
||||
map.set_dependent_code(
|
||||
DependentCode::empty_dependent_code(ReadOnlyRoots(isolate())),
|
||||
map.set_dependent_code(DependentCode::empty_dependent_code(ro_roots),
|
||||
SKIP_WRITE_BARRIER);
|
||||
map.set_raw_transitions(MaybeObject::FromSmi(Smi::zero()),
|
||||
SKIP_WRITE_BARRIER);
|
||||
map.SetInObjectUnusedPropertyFields(inobject_properties);
|
||||
map.SetInstanceDescriptors(isolate(), *empty_descriptor_array(), 0);
|
||||
map.SetInstanceDescriptors(isolate(), ro_roots.empty_descriptor_array(), 0);
|
||||
// Must be called only after |instance_type| and |instance_size| are set.
|
||||
map.set_visitor_id(Map::GetVisitorId(map));
|
||||
DCHECK(!map.is_in_retained_map_list());
|
||||
|
@ -128,7 +128,8 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
Handle<Oddball> NewBasicBlockCountersMarker();
|
||||
|
||||
// Allocates a property array initialized with undefined values.
|
||||
Handle<PropertyArray> NewPropertyArray(int length);
|
||||
Handle<PropertyArray> NewPropertyArray(
|
||||
int length, AllocationType allocation = AllocationType::kYoung);
|
||||
// Tries allocating a fixed array initialized with undefined values.
|
||||
// In case of an allocation failure (OOM) an empty handle is returned.
|
||||
// The caller has to manually signal an
|
||||
@ -445,10 +446,12 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND,
|
||||
int inobject_properties = 0,
|
||||
AllocationType allocation_type = AllocationType::kMap);
|
||||
// Initializes the fields of a newly created Map. Exposed for tests and
|
||||
// heap setup; other code should just call NewMap which takes care of it.
|
||||
// Initializes the fields of a newly created Map using roots from the
|
||||
// passed-in Heap. Exposed for tests and heap setup; other code should just
|
||||
// call NewMap which takes care of it.
|
||||
Map InitializeMap(Map map, InstanceType type, int instance_size,
|
||||
ElementsKind elements_kind, int inobject_properties);
|
||||
ElementsKind elements_kind, int inobject_properties,
|
||||
Heap* roots);
|
||||
|
||||
// Allocate a block of memory of the given AllocationType (filled with a
|
||||
// filler). Used as a fall-back for generated code when the space is full.
|
||||
|
@ -6364,7 +6364,7 @@ void Heap::CompactWeakArrayLists() {
|
||||
}
|
||||
|
||||
void Heap::AddRetainedMap(Handle<NativeContext> context, Handle<Map> map) {
|
||||
if (map->is_in_retained_map_list()) {
|
||||
if (map->is_in_retained_map_list() || map->InSharedWritableHeap()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -422,7 +422,7 @@ void IncrementalMarking::FinalizeIncrementally() {
|
||||
// 2) Age and retain maps embedded in optimized code.
|
||||
MarkRoots();
|
||||
|
||||
// Map retaining is needed for perfromance, not correctness,
|
||||
// Map retaining is needed for performance, not correctness,
|
||||
// so we can do it only once at the beginning of the finalization.
|
||||
RetainMaps();
|
||||
|
||||
|
@ -151,7 +151,7 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
|
||||
SKIP_WRITE_BARRIER);
|
||||
Map map = isolate()->factory()->InitializeMap(
|
||||
Map::cast(result), instance_type, instance_size, elements_kind,
|
||||
inobject_properties);
|
||||
inobject_properties, this);
|
||||
|
||||
return AllocationResult::FromObject(map);
|
||||
}
|
||||
|
@ -1186,6 +1186,37 @@ void AccessorAssembler::HandleStoreICNativeDataProperty(
|
||||
holder, accessor_info, p->name(), p->value());
|
||||
}
|
||||
|
||||
void AccessorAssembler::HandleStoreICSmiHandlerJSSharedStructFieldCase(
|
||||
TNode<Context> context, TNode<Word32T> handler_word, TNode<JSObject> holder,
|
||||
TNode<Object> value) {
|
||||
CSA_DCHECK(this,
|
||||
Word32Equal(DecodeWord32<StoreHandler::KindBits>(handler_word),
|
||||
STORE_KIND(kSharedStructField)));
|
||||
CSA_DCHECK(
|
||||
this,
|
||||
Word32Equal(DecodeWord32<StoreHandler::RepresentationBits>(handler_word),
|
||||
Int32Constant(Representation::kTagged)));
|
||||
|
||||
TVARIABLE(Object, shared_value, value);
|
||||
SharedValueBarrier(context, value, &shared_value);
|
||||
|
||||
TNode<BoolT> is_inobject =
|
||||
IsSetWord32<StoreHandler::IsInobjectBits>(handler_word);
|
||||
TNode<HeapObject> property_storage = Select<HeapObject>(
|
||||
is_inobject, [&]() { return holder; },
|
||||
[&]() { return LoadFastProperties(holder); });
|
||||
|
||||
TNode<UintPtrT> index =
|
||||
DecodeWordFromWord32<StoreHandler::FieldIndexBits>(handler_word);
|
||||
TNode<IntPtrT> offset = Signed(TimesTaggedSize(index));
|
||||
|
||||
StoreJSSharedStructInObjectField(property_storage, offset,
|
||||
shared_value.value());
|
||||
|
||||
// Return the original value.
|
||||
Return(value);
|
||||
}
|
||||
|
||||
void AccessorAssembler::HandleStoreICHandlerCase(
|
||||
const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
|
||||
ICMode ic_mode, ElementSupport support_elements) {
|
||||
@ -1269,10 +1300,13 @@ void AccessorAssembler::HandleStoreICHandlerCase(
|
||||
|
||||
BIND(&if_fast_smi);
|
||||
{
|
||||
Label data(this), accessor(this), native_data_property(this);
|
||||
Label data(this), accessor(this), shared_struct_field(this),
|
||||
native_data_property(this);
|
||||
GotoIf(Word32Equal(handler_kind, STORE_KIND(kAccessor)), &accessor);
|
||||
Branch(Word32Equal(handler_kind, STORE_KIND(kNativeDataProperty)),
|
||||
&native_data_property, &data);
|
||||
GotoIf(Word32Equal(handler_kind, STORE_KIND(kNativeDataProperty)),
|
||||
&native_data_property);
|
||||
Branch(Word32Equal(handler_kind, STORE_KIND(kSharedStructField)),
|
||||
&shared_struct_field, &data);
|
||||
|
||||
BIND(&accessor);
|
||||
HandleStoreAccessor(p, CAST(holder), handler_word);
|
||||
@ -1280,6 +1314,10 @@ void AccessorAssembler::HandleStoreICHandlerCase(
|
||||
BIND(&native_data_property);
|
||||
HandleStoreICNativeDataProperty(p, CAST(holder), handler_word);
|
||||
|
||||
BIND(&shared_struct_field);
|
||||
HandleStoreICSmiHandlerJSSharedStructFieldCase(p->context(), handler_word,
|
||||
CAST(holder), p->value());
|
||||
|
||||
BIND(&data);
|
||||
// Handle non-transitioning field stores.
|
||||
HandleStoreICSmiHandlerCase(handler_word, CAST(holder), p->value(), miss);
|
||||
@ -1663,6 +1701,55 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
|
||||
BIND(&done);
|
||||
}
|
||||
|
||||
void AccessorAssembler::StoreJSSharedStructField(
|
||||
TNode<Context> context, TNode<HeapObject> shared_struct,
|
||||
TNode<Map> shared_struct_map, TNode<DescriptorArray> descriptors,
|
||||
TNode<IntPtrT> descriptor_name_index, TNode<Uint32T> details,
|
||||
TNode<Object> maybe_local_value) {
|
||||
CSA_DCHECK(this, IsJSSharedStruct(shared_struct));
|
||||
|
||||
Label done(this);
|
||||
|
||||
TNode<UintPtrT> field_index =
|
||||
DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
|
||||
field_index = Unsigned(IntPtrAdd(
|
||||
field_index,
|
||||
Unsigned(LoadMapInobjectPropertiesStartInWords(shared_struct_map))));
|
||||
|
||||
TNode<IntPtrT> instance_size_in_words =
|
||||
LoadMapInstanceSizeInWords(shared_struct_map);
|
||||
|
||||
TVARIABLE(Object, shared_value, maybe_local_value);
|
||||
SharedValueBarrier(context, maybe_local_value, &shared_value);
|
||||
|
||||
Label inobject(this), backing_store(this);
|
||||
Branch(UintPtrLessThan(field_index, instance_size_in_words), &inobject,
|
||||
&backing_store);
|
||||
|
||||
BIND(&inobject);
|
||||
{
|
||||
TNode<IntPtrT> field_offset = Signed(TimesTaggedSize(field_index));
|
||||
StoreJSSharedStructInObjectField(shared_struct, field_offset,
|
||||
shared_value.value());
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&backing_store);
|
||||
{
|
||||
TNode<IntPtrT> backing_store_index =
|
||||
Signed(IntPtrSub(field_index, instance_size_in_words));
|
||||
|
||||
Label tagged_rep(this), double_rep(this);
|
||||
TNode<PropertyArray> properties =
|
||||
CAST(LoadFastProperties(CAST(shared_struct)));
|
||||
StoreJSSharedStructPropertyArrayElement(properties, backing_store_index,
|
||||
shared_value.value());
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&done);
|
||||
}
|
||||
|
||||
void AccessorAssembler::CheckPrototypeValidityCell(
|
||||
TNode<Object> maybe_validity_cell, Label* miss) {
|
||||
Label done(this);
|
||||
|
@ -273,6 +273,13 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
|
||||
TNode<Object> value, Label* slow,
|
||||
bool do_transitioning_store);
|
||||
|
||||
void StoreJSSharedStructField(TNode<Context> context,
|
||||
TNode<HeapObject> shared_struct,
|
||||
TNode<Map> shared_struct_map,
|
||||
TNode<DescriptorArray> descriptors,
|
||||
TNode<IntPtrT> descriptor_name_index,
|
||||
TNode<Uint32T> details, TNode<Object> value);
|
||||
|
||||
TNode<BoolT> IsPropertyDetailsConst(TNode<Uint32T> details);
|
||||
|
||||
void CheckFieldType(TNode<DescriptorArray> descriptors,
|
||||
@ -435,6 +442,9 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
|
||||
void HandleStoreICSmiHandlerCase(TNode<Word32T> handler_word,
|
||||
TNode<JSObject> holder, TNode<Object> value,
|
||||
Label* miss);
|
||||
void HandleStoreICSmiHandlerJSSharedStructFieldCase(
|
||||
TNode<Context> context, TNode<Word32T> handler_word,
|
||||
TNode<JSObject> holder, TNode<Object> value);
|
||||
void HandleStoreFieldAndReturn(TNode<Word32T> handler_word,
|
||||
TNode<JSObject> holder, TNode<Object> value,
|
||||
base::Optional<TNode<Float64T>> double_value,
|
||||
|
@ -225,7 +225,8 @@ Handle<Smi> StoreHandler::StoreField(Isolate* isolate, Kind kind,
|
||||
int descriptor, FieldIndex field_index,
|
||||
Representation representation) {
|
||||
DCHECK(!representation.IsNone());
|
||||
DCHECK(kind == Kind::kField || kind == Kind::kConstField);
|
||||
DCHECK(kind == Kind::kField || kind == Kind::kConstField ||
|
||||
kind == Kind::kSharedStructField);
|
||||
|
||||
int config = KindBits::encode(kind) |
|
||||
IsInobjectBits::encode(field_index.is_inobject()) |
|
||||
@ -244,6 +245,14 @@ Handle<Smi> StoreHandler::StoreField(Isolate* isolate, int descriptor,
|
||||
return StoreField(isolate, kind, descriptor, field_index, representation);
|
||||
}
|
||||
|
||||
Handle<Smi> StoreHandler::StoreSharedStructField(
|
||||
Isolate* isolate, int descriptor, FieldIndex field_index,
|
||||
Representation representation) {
|
||||
DCHECK(representation.Equals(Representation::Tagged()));
|
||||
return StoreField(isolate, Kind::kSharedStructField, descriptor, field_index,
|
||||
representation);
|
||||
}
|
||||
|
||||
Handle<Smi> StoreHandler::StoreNativeDataProperty(Isolate* isolate,
|
||||
int descriptor) {
|
||||
int config = KindBits::encode(Kind::kNativeDataProperty) |
|
||||
|
@ -250,6 +250,7 @@ class StoreHandler final : public DataHandler {
|
||||
kConstField,
|
||||
kAccessor,
|
||||
kNativeDataProperty,
|
||||
kSharedStructField,
|
||||
kApiSetter,
|
||||
kApiSetterHolderIsPrototype,
|
||||
kGlobalProxy,
|
||||
@ -301,6 +302,11 @@ class StoreHandler final : public DataHandler {
|
||||
PropertyConstness constness,
|
||||
Representation representation);
|
||||
|
||||
// Creates a Smi-handler for storing a field to a JSSharedStruct.
|
||||
static inline Handle<Smi> StoreSharedStructField(
|
||||
Isolate* isolate, int descriptor, FieldIndex field_index,
|
||||
Representation representation);
|
||||
|
||||
// Create a store transition handler which doesn't check prototype chain.
|
||||
static MaybeObjectHandle StoreOwnTransition(Isolate* isolate,
|
||||
Handle<Map> transition_map);
|
||||
|
@ -2147,6 +2147,10 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
|
||||
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
|
||||
int descriptor = lookup->GetFieldDescriptorIndex();
|
||||
FieldIndex index = lookup->GetFieldIndex();
|
||||
if (V8_UNLIKELY(holder->IsJSSharedStruct())) {
|
||||
return MaybeObjectHandle(StoreHandler::StoreSharedStructField(
|
||||
isolate(), descriptor, index, lookup->representation()));
|
||||
}
|
||||
PropertyConstness constness = lookup->constness();
|
||||
if (constness == PropertyConstness::kConst &&
|
||||
IsStoreOwnICKind(nexus()->kind())) {
|
||||
|
@ -83,16 +83,18 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
|
||||
// kind.
|
||||
void EmitGenericPropertyStore(TNode<JSReceiver> receiver,
|
||||
TNode<Map> receiver_map,
|
||||
TNode<Uint16T> instance_type,
|
||||
const StoreICParameters* p,
|
||||
ExitPoint* exit_point, Label* slow,
|
||||
Maybe<LanguageMode> maybe_language_mode);
|
||||
|
||||
void EmitGenericPropertyStore(TNode<JSReceiver> receiver,
|
||||
TNode<Map> receiver_map,
|
||||
TNode<Uint16T> instance_type,
|
||||
const StoreICParameters* p, Label* slow) {
|
||||
ExitPoint direct_exit(this);
|
||||
EmitGenericPropertyStore(receiver, receiver_map, p, &direct_exit, slow,
|
||||
Nothing<LanguageMode>());
|
||||
EmitGenericPropertyStore(receiver, receiver_map, instance_type, p,
|
||||
&direct_exit, slow, Nothing<LanguageMode>());
|
||||
}
|
||||
|
||||
void BranchIfPrototypesMayHaveReadOnlyElements(
|
||||
@ -792,7 +794,8 @@ TNode<Map> KeyedStoreGenericAssembler::FindCandidateStoreICTransitionMapHandler(
|
||||
|
||||
void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
|
||||
TNode<JSReceiver> receiver, TNode<Map> receiver_map,
|
||||
const StoreICParameters* p, ExitPoint* exit_point, Label* slow,
|
||||
TNode<Uint16T> instance_type, const StoreICParameters* p,
|
||||
ExitPoint* exit_point, Label* slow,
|
||||
Maybe<LanguageMode> maybe_language_mode) {
|
||||
CSA_DCHECK(this, IsSimpleObjectMap(receiver_map));
|
||||
// TODO(rmcilroy) Type as Struct once we use a trimmed down
|
||||
@ -841,11 +844,22 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
|
||||
|
||||
BIND(&data_property);
|
||||
{
|
||||
Label shared(this);
|
||||
GotoIf(IsJSSharedStructInstanceType(instance_type), &shared);
|
||||
|
||||
CheckForAssociatedProtector(name, slow);
|
||||
OverwriteExistingFastDataProperty(receiver, receiver_map, descriptors,
|
||||
name_index, details, p->value(), slow,
|
||||
false);
|
||||
exit_point->Return(p->value());
|
||||
|
||||
BIND(&shared);
|
||||
{
|
||||
StoreJSSharedStructField(p->context(), receiver, receiver_map,
|
||||
descriptors, name_index, details,
|
||||
p->value());
|
||||
exit_point->Return(p->value());
|
||||
}
|
||||
}
|
||||
}
|
||||
BIND(&lookup_transition);
|
||||
@ -1068,8 +1082,8 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(
|
||||
StoreICParameters p(context, receiver, var_unique.value(), value, {},
|
||||
UndefinedConstant(), StoreICMode::kDefault);
|
||||
ExitPoint direct_exit(this);
|
||||
EmitGenericPropertyStore(CAST(receiver), receiver_map, &p, &direct_exit,
|
||||
&slow, language_mode);
|
||||
EmitGenericPropertyStore(CAST(receiver), receiver_map, instance_type, &p,
|
||||
&direct_exit, &slow, language_mode);
|
||||
}
|
||||
|
||||
BIND(¬_internalized);
|
||||
@ -1143,7 +1157,8 @@ void KeyedStoreGenericAssembler::StoreIC_NoFeedback() {
|
||||
StoreICParameters p(
|
||||
context, receiver, name, value, slot, UndefinedConstant(),
|
||||
IsKeyedStoreOwn() ? StoreICMode::kStoreOwn : StoreICMode::kDefault);
|
||||
EmitGenericPropertyStore(CAST(receiver), receiver_map, &p, &miss);
|
||||
EmitGenericPropertyStore(CAST(receiver), receiver_map, instance_type, &p,
|
||||
&miss);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1172,7 +1187,9 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
|
||||
IsSimpleObjectMap(LoadMap(receiver))));
|
||||
GotoIfNot(is_simple_receiver, &slow);
|
||||
|
||||
EmitGenericPropertyStore(receiver, LoadMap(receiver), &p, &exit_point, &slow,
|
||||
TNode<Map> map = LoadMap(receiver);
|
||||
TNode<Uint16T> instance_type = LoadMapInstanceType(map);
|
||||
EmitGenericPropertyStore(receiver, map, instance_type, &p, &exit_point, &slow,
|
||||
Just(language_mode));
|
||||
|
||||
BIND(&slow);
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include "src/objects/js-segments.h"
|
||||
#endif // V8_INTL_SUPPORT
|
||||
#include "src/codegen/script-details.h"
|
||||
#include "src/objects/js-struct.h"
|
||||
#include "src/objects/js-temporal-objects-inl.h"
|
||||
#include "src/objects/js-weak-refs.h"
|
||||
#include "src/objects/ordered-hash-table.h"
|
||||
@ -4444,6 +4445,24 @@ void Genesis::InitializeGlobal_harmony_shadow_realm() {
|
||||
Builtin::kShadowRealmPrototypeImportValue, 2, true);
|
||||
}
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_struct() {
|
||||
if (!FLAG_harmony_struct) return;
|
||||
|
||||
Handle<JSGlobalObject> global(native_context()->global_object(), isolate());
|
||||
Handle<String> name =
|
||||
isolate()->factory()->InternalizeUtf8String("SharedStructType");
|
||||
Handle<JSFunction> shared_struct_type_fun = CreateFunctionForBuiltin(
|
||||
isolate(), name, isolate()->strict_function_with_readonly_prototype_map(),
|
||||
Builtin::kSharedStructTypeConstructor);
|
||||
JSObject::MakePrototypesFast(shared_struct_type_fun, kStartAtReceiver,
|
||||
isolate());
|
||||
shared_struct_type_fun->shared().set_native(true);
|
||||
shared_struct_type_fun->shared().DontAdaptArguments();
|
||||
shared_struct_type_fun->shared().set_length(1);
|
||||
JSObject::AddProperty(isolate(), global, "SharedStructType",
|
||||
shared_struct_type_fun, DONT_ENUM);
|
||||
}
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_array_find_last() {
|
||||
if (!FLAG_harmony_array_find_last) return;
|
||||
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "src/objects/js-regexp-inl.h"
|
||||
#include "src/objects/js-regexp-string-iterator-inl.h"
|
||||
#include "src/objects/js-shadow-realms-inl.h"
|
||||
#include "src/objects/js-struct-inl.h"
|
||||
#include "src/objects/js-temporal-objects-inl.h"
|
||||
#include "src/objects/js-weak-refs-inl.h"
|
||||
#include "src/objects/literal-objects-inl.h"
|
||||
|
@ -334,7 +334,7 @@ Object JSObject::RawFastPropertyAt(FieldIndex index) const {
|
||||
Object JSObject::RawFastPropertyAt(PtrComprCageBase cage_base,
|
||||
FieldIndex index) const {
|
||||
if (index.is_inobject()) {
|
||||
return TaggedField<Object>::load(cage_base, *this, index.offset());
|
||||
return TaggedField<Object>::Relaxed_Load(cage_base, *this, index.offset());
|
||||
} else {
|
||||
return property_array(cage_base).get(cage_base,
|
||||
index.outobject_array_index());
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "src/objects/js-segmenter.h"
|
||||
#include "src/objects/js-segments.h"
|
||||
#endif // V8_INTL_SUPPORT
|
||||
#include "src/objects/js-struct-inl.h"
|
||||
#include "src/objects/js-temporal-objects-inl.h"
|
||||
#include "src/objects/js-weak-refs.h"
|
||||
#include "src/objects/map-inl.h"
|
||||
@ -2342,6 +2343,8 @@ int JSObject::GetHeaderSize(InstanceType type,
|
||||
return JSStringIterator::kHeaderSize;
|
||||
case JS_MODULE_NAMESPACE_TYPE:
|
||||
return JSModuleNamespace::kHeaderSize;
|
||||
case JS_SHARED_STRUCT_TYPE:
|
||||
return JSSharedStruct::kHeaderSize;
|
||||
case JS_TEMPORAL_CALENDAR_TYPE:
|
||||
return JSTemporalCalendar::kHeaderSize;
|
||||
case JS_TEMPORAL_DURATION_TYPE:
|
||||
|
30
src/objects/js-struct-inl.h
Normal file
30
src/objects/js-struct-inl.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_OBJECTS_JS_STRUCT_INL_H_
|
||||
#define V8_OBJECTS_JS_STRUCT_INL_H_
|
||||
|
||||
#include "src/api/api-inl.h"
|
||||
#include "src/heap/heap-write-barrier-inl.h"
|
||||
#include "src/objects/js-struct.h"
|
||||
#include "src/objects/smi-inl.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
#include "src/objects/object-macros.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#include "torque-generated/src/objects/js-struct-tq-inl.inc"
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(JSSharedStruct)
|
||||
|
||||
CAST_ACCESSOR(JSSharedStruct)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#include "src/objects/object-macros-undef.h"
|
||||
|
||||
#endif // V8_OBJECTS_JS_STRUCT_INL_H_
|
35
src/objects/js-struct.h
Normal file
35
src/objects/js-struct.h
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_OBJECTS_JS_STRUCT_H_
|
||||
#define V8_OBJECTS_JS_STRUCT_H_
|
||||
|
||||
#include "src/objects/js-objects.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
#include "src/objects/object-macros.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#include "torque-generated/src/objects/js-struct-tq.inc"
|
||||
|
||||
class JSSharedStruct
|
||||
: public TorqueGeneratedJSSharedStruct<JSSharedStruct, JSObject> {
|
||||
public:
|
||||
DECL_CAST(JSSharedStruct)
|
||||
DECL_PRINTER(JSSharedStruct)
|
||||
EXPORT_DECL_VERIFIER(JSSharedStruct)
|
||||
|
||||
class BodyDescriptor;
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS(JSSharedStruct)
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#include "src/objects/object-macros-undef.h"
|
||||
|
||||
#endif // V8_OBJECTS_JS_STRUCT_H_
|
7
src/objects/js-struct.tq
Normal file
7
src/objects/js-struct.tq
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
extern class JSSharedStruct extends JSObject {
|
||||
// escaped_local_thread: Smi;
|
||||
}
|
@ -1061,6 +1061,7 @@ void LookupIterator::WriteDataValue(Handle<Object> value,
|
||||
// WasmObjects.
|
||||
DCHECK(!holder_->IsWasmObject(isolate_));
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
DCHECK_IMPLIES(holder_->IsJSSharedStruct(), value->IsShared());
|
||||
|
||||
Handle<JSReceiver> holder = GetHolder<JSReceiver>();
|
||||
if (IsElement(*holder)) {
|
||||
|
@ -273,6 +273,7 @@ VisitorId Map::GetVisitorId(Map map) {
|
||||
case JS_SET_TYPE:
|
||||
case JS_SET_VALUE_ITERATOR_TYPE:
|
||||
case JS_SHADOW_REALM_TYPE:
|
||||
case JS_SHARED_STRUCT_TYPE:
|
||||
case JS_STRING_ITERATOR_PROTOTYPE_TYPE:
|
||||
case JS_STRING_ITERATOR_TYPE:
|
||||
case JS_TEMPORAL_CALENDAR_TYPE:
|
||||
|
@ -159,6 +159,7 @@ class ZoneForwardList;
|
||||
V(JSSet) \
|
||||
V(JSSetIterator) \
|
||||
V(JSShadowRealm) \
|
||||
V(JSSharedStruct) \
|
||||
V(JSSpecialObject) \
|
||||
V(JSStringIterator) \
|
||||
V(JSTemporalCalendar) \
|
||||
|
@ -1157,6 +1157,7 @@ auto BodyDescriptorApply(InstanceType type, Args&&... args) {
|
||||
case JS_SET_VALUE_ITERATOR_TYPE:
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
case JS_SHADOW_REALM_TYPE:
|
||||
case JS_SHARED_STRUCT_TYPE:
|
||||
case JS_STRING_ITERATOR_PROTOTYPE_TYPE:
|
||||
case JS_STRING_ITERATOR_TYPE:
|
||||
case JS_TEMPORAL_CALENDAR_TYPE:
|
||||
|
@ -1164,6 +1164,46 @@ Object Object::GetHash() {
|
||||
return receiver.GetIdentityHash();
|
||||
}
|
||||
|
||||
bool Object::IsShared() const {
|
||||
// Smis are trivially shared.
|
||||
if (IsSmi()) return true;
|
||||
|
||||
HeapObject object = HeapObject::cast(*this);
|
||||
|
||||
// RO objects are shared when the RO space is shared.
|
||||
if (IsReadOnlyHeapObject(object)) {
|
||||
return ReadOnlyHeap::IsReadOnlySpaceShared();
|
||||
}
|
||||
|
||||
// Check if this object is already shared.
|
||||
switch (object.map().instance_type()) {
|
||||
case SHARED_STRING_TYPE:
|
||||
case SHARED_ONE_BYTE_STRING_TYPE:
|
||||
case JS_SHARED_STRUCT_TYPE:
|
||||
DCHECK(object.InSharedHeap());
|
||||
return true;
|
||||
case INTERNALIZED_STRING_TYPE:
|
||||
case ONE_BYTE_INTERNALIZED_STRING_TYPE:
|
||||
if (FLAG_shared_string_table) {
|
||||
DCHECK(object.InSharedHeap());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
MaybeHandle<Object> Object::Share(Isolate* isolate, Handle<Object> value,
|
||||
ShouldThrow throw_if_cannot_be_shared) {
|
||||
// Sharing values requires the RO space be shared.
|
||||
DCHECK(ReadOnlyHeap::IsReadOnlySpaceShared());
|
||||
if (value->IsShared()) return value;
|
||||
return ShareSlow(isolate, Handle<HeapObject>::cast(value),
|
||||
throw_if_cannot_be_shared);
|
||||
}
|
||||
|
||||
Handle<Object> ObjectHashTableShape::AsHandle(Handle<Object> key) {
|
||||
return key;
|
||||
}
|
||||
|
@ -2823,7 +2823,16 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
|
||||
|
||||
} else // NOLINT(readability/braces)
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
{
|
||||
// clang-format off
|
||||
if (V8_UNLIKELY(receiver->IsJSSharedStruct(isolate))) {
|
||||
// clang-format on
|
||||
|
||||
// Shared structs can only point to primitives or shared values.
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, to_assign, Object::Share(isolate, to_assign, kThrowOnError),
|
||||
Nothing<bool>());
|
||||
it->WriteDataValue(to_assign, false);
|
||||
} else {
|
||||
// Possibly migrate to the most up-to-date map that will be able to store
|
||||
// |value| under it->name().
|
||||
it->PrepareForDataProperty(to_assign);
|
||||
@ -2915,6 +2924,30 @@ Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
|
||||
return Just(true);
|
||||
}
|
||||
|
||||
// static
|
||||
MaybeHandle<Object> Object::ShareSlow(Isolate* isolate,
|
||||
Handle<HeapObject> value,
|
||||
ShouldThrow throw_if_cannot_be_shared) {
|
||||
// Use Object::Share() if value might already be shared.
|
||||
DCHECK(!value->IsShared());
|
||||
|
||||
if (value->IsString()) {
|
||||
return String::Share(isolate, Handle<String>::cast(value));
|
||||
}
|
||||
|
||||
if (value->IsHeapNumber()) {
|
||||
uint64_t bits = HeapNumber::cast(*value).value_as_bits(kRelaxedLoad);
|
||||
return isolate->factory()
|
||||
->NewHeapNumberFromBits<AllocationType::kSharedOld>(bits);
|
||||
}
|
||||
|
||||
if (throw_if_cannot_be_shared == kThrowOnError) {
|
||||
THROW_NEW_ERROR(
|
||||
isolate, NewTypeError(MessageTemplate::kCannotBeShared, value), Object);
|
||||
}
|
||||
return MaybeHandle<Object>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static int AppendUniqueCallbacks(Isolate* isolate,
|
||||
Handle<TemplateList> callbacks,
|
||||
|
@ -66,6 +66,7 @@
|
||||
// - JSRegExp
|
||||
// - JSSetIterator
|
||||
// - JSShadowRealm
|
||||
// - JSSharedStruct
|
||||
// - JSStringIterator
|
||||
// - JSTemporalCalendar
|
||||
// - JSTemporalDuration
|
||||
@ -729,6 +730,27 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> {
|
||||
static bool CheckContextualStoreToJSGlobalObject(
|
||||
LookupIterator* it, Maybe<ShouldThrow> should_throw);
|
||||
|
||||
// Returns whether the object is safe to share across Isolates.
|
||||
//
|
||||
// Currently, the following kinds of values can be safely shared across
|
||||
// Isolates:
|
||||
// - Smis
|
||||
// - Objects in RO space when the RO space is shared
|
||||
// - HeapNumbers in the shared old space
|
||||
// - Strings for which String::IsShared() is true
|
||||
// - JSSharedStructs
|
||||
inline bool IsShared() const;
|
||||
|
||||
// Returns an equivalent value that's safe to share across Isolates if
|
||||
// possible. Acts as the identity function when value->IsShared().
|
||||
static inline MaybeHandle<Object> Share(
|
||||
Isolate* isolate, Handle<Object> value,
|
||||
ShouldThrow throw_if_cannot_be_shared);
|
||||
|
||||
static MaybeHandle<Object> ShareSlow(Isolate* isolate,
|
||||
Handle<HeapObject> value,
|
||||
ShouldThrow throw_if_cannot_be_shared);
|
||||
|
||||
protected:
|
||||
inline Address field_address(size_t offset) const {
|
||||
return ptr() + offset - kHeapObjectTag;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "src/objects/js-array-inl.h"
|
||||
#include "src/objects/js-collection-inl.h"
|
||||
#include "src/objects/js-regexp-inl.h"
|
||||
#include "src/objects/js-struct-inl.h"
|
||||
#include "src/objects/map-updater.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/objects/objects.h"
|
||||
@ -590,6 +591,8 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
|
||||
return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver));
|
||||
case JS_ERROR_TYPE:
|
||||
return WriteJSError(Handle<JSObject>::cast(receiver));
|
||||
case JS_SHARED_STRUCT_TYPE:
|
||||
return WriteJSSharedStruct(Handle<JSSharedStruct>::cast(receiver));
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
case WASM_MODULE_OBJECT_TYPE:
|
||||
return WriteWasmModule(Handle<WasmModuleObject>::cast(receiver));
|
||||
@ -1025,6 +1028,12 @@ Maybe<bool> ValueSerializer::WriteJSError(Handle<JSObject> error) {
|
||||
return ThrowIfOutOfMemory();
|
||||
}
|
||||
|
||||
Maybe<bool> ValueSerializer::WriteJSSharedStruct(
|
||||
Handle<JSSharedStruct> shared_struct) {
|
||||
// TODO(v8:12547): Support copying serialization for shared structs as well.
|
||||
return WriteSharedObject(shared_struct);
|
||||
}
|
||||
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) {
|
||||
if (delegate_ == nullptr) {
|
||||
@ -1061,8 +1070,7 @@ Maybe<bool> ValueSerializer::WriteWasmMemory(Handle<WasmMemoryObject> object) {
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
|
||||
Maybe<bool> ValueSerializer::WriteSharedObject(Handle<HeapObject> object) {
|
||||
// Currently only strings are shareable.
|
||||
DCHECK(String::cast(*object).IsShared());
|
||||
DCHECK(object->IsShared());
|
||||
DCHECK(supports_shared_values_);
|
||||
DCHECK_NOT_NULL(delegate_);
|
||||
DCHECK(delegate_->SupportsSharedValues());
|
||||
@ -2144,8 +2152,7 @@ MaybeHandle<HeapObject> ValueDeserializer::ReadSharedObject() {
|
||||
}
|
||||
Handle<HeapObject> shared_object =
|
||||
Handle<HeapObject>::cast(Utils::OpenHandle(*shared_value));
|
||||
// Currently only strings are shareable.
|
||||
DCHECK(String::cast(*shared_object).IsShared());
|
||||
DCHECK(shared_object->IsShared());
|
||||
return shared_object;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ class JSMap;
|
||||
class JSPrimitiveWrapper;
|
||||
class JSRegExp;
|
||||
class JSSet;
|
||||
class JSSharedStruct;
|
||||
class Object;
|
||||
class Oddball;
|
||||
class Smi;
|
||||
@ -131,6 +132,8 @@ class ValueSerializer {
|
||||
V8_WARN_UNUSED_RESULT;
|
||||
Maybe<bool> WriteJSArrayBufferView(JSArrayBufferView array_buffer);
|
||||
Maybe<bool> WriteJSError(Handle<JSObject> error) V8_WARN_UNUSED_RESULT;
|
||||
Maybe<bool> WriteJSSharedStruct(Handle<JSSharedStruct> shared_struct)
|
||||
V8_WARN_UNUSED_RESULT;
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
Maybe<bool> WriteWasmModule(Handle<WasmModuleObject> object)
|
||||
V8_WARN_UNUSED_RESULT;
|
||||
|
@ -737,5 +737,15 @@ RUNTIME_FUNCTION(Runtime_DoubleToStringWithRadix) {
|
||||
return *result;
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_SharedValueBarrierSlow) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(HeapObject, value, 0);
|
||||
Handle<Object> shared_value;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, shared_value, Object::ShareSlow(isolate, value, kThrowOnError));
|
||||
return *shared_value;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -233,6 +233,7 @@ namespace internal {
|
||||
F(ReThrowWithMessage, 2, 1) \
|
||||
F(RunMicrotaskCallback, 2, 1) \
|
||||
F(PerformMicrotaskCheckpoint, 0, 1) \
|
||||
F(SharedValueBarrierSlow, 1, 1) \
|
||||
F(StackGuard, 0, 1) \
|
||||
F(StackGuardWithGap, 1, 1) \
|
||||
F(Throw, 1, 1) \
|
||||
|
@ -84,7 +84,7 @@ AllocationResult HeapTester::AllocateMapForTest(Isolate* isolate) {
|
||||
SKIP_WRITE_BARRIER);
|
||||
return AllocationResult::FromObject(isolate->factory()->InitializeMap(
|
||||
Map::cast(obj), JS_OBJECT_TYPE, JSObject::kHeaderSize,
|
||||
TERMINAL_FAST_ELEMENTS_KIND, 0));
|
||||
TERMINAL_FAST_ELEMENTS_KIND, 0, heap));
|
||||
}
|
||||
|
||||
// This is the same as Factory::NewFixedArray, except it doesn't retry
|
||||
|
@ -83,7 +83,7 @@ bytecodes: [
|
||||
/* 48 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
|
||||
/* 53 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
|
||||
/* 58 E> */ B(LdaKeyedProperty), R(this), U8(2),
|
||||
B(Wide), B(LdaSmi), I16(291),
|
||||
B(Wide), B(LdaSmi), I16(293),
|
||||
B(Star2),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star3),
|
||||
@ -115,7 +115,7 @@ bytecodes: [
|
||||
/* 41 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
|
||||
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
|
||||
/* 51 E> */ B(LdaKeyedProperty), R(this), U8(2),
|
||||
B(Wide), B(LdaSmi), I16(290),
|
||||
B(Wide), B(LdaSmi), I16(292),
|
||||
B(Star2),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star3),
|
||||
@ -147,7 +147,7 @@ bytecodes: [
|
||||
/* 48 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
|
||||
/* 53 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
|
||||
/* 58 E> */ B(LdaKeyedProperty), R(this), U8(2),
|
||||
B(Wide), B(LdaSmi), I16(291),
|
||||
B(Wide), B(LdaSmi), I16(293),
|
||||
B(Star2),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star3),
|
||||
@ -179,7 +179,7 @@ bytecodes: [
|
||||
/* 41 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
|
||||
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
|
||||
/* 51 E> */ B(LdaKeyedProperty), R(this), U8(2),
|
||||
B(Wide), B(LdaSmi), I16(290),
|
||||
B(Wide), B(LdaSmi), I16(292),
|
||||
B(Star2),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star3),
|
||||
|
@ -56,7 +56,7 @@ bytecodes: [
|
||||
/* 44 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
|
||||
/* 49 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
|
||||
/* 54 E> */ B(LdaKeyedProperty), R(this), U8(2),
|
||||
B(Wide), B(LdaSmi), I16(289),
|
||||
B(Wide), B(LdaSmi), I16(291),
|
||||
B(Star2),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star3),
|
||||
@ -89,7 +89,7 @@ bytecodes: [
|
||||
/* 44 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
|
||||
/* 49 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
|
||||
/* 54 E> */ B(LdaKeyedProperty), R(this), U8(2),
|
||||
B(Wide), B(LdaSmi), I16(289),
|
||||
B(Wide), B(LdaSmi), I16(291),
|
||||
B(Star2),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star3),
|
||||
|
@ -24,7 +24,7 @@ bytecodes: [
|
||||
B(TestReferenceEqual), R(this),
|
||||
B(Mov), R(this), R(1),
|
||||
B(JumpIfTrue), U8(16),
|
||||
B(Wide), B(LdaSmi), I16(283),
|
||||
B(Wide), B(LdaSmi), I16(285),
|
||||
B(Star2),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star3),
|
||||
@ -59,13 +59,13 @@ bytecodes: [
|
||||
B(TestReferenceEqual), R(this),
|
||||
B(Mov), R(this), R(0),
|
||||
B(JumpIfTrue), U8(16),
|
||||
B(Wide), B(LdaSmi), I16(283),
|
||||
B(Wide), B(LdaSmi), I16(285),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star2),
|
||||
/* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
|
||||
B(Throw),
|
||||
B(Wide), B(LdaSmi), I16(289),
|
||||
B(Wide), B(LdaSmi), I16(291),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(1),
|
||||
B(Star2),
|
||||
@ -97,13 +97,13 @@ bytecodes: [
|
||||
B(TestReferenceEqual), R(this),
|
||||
B(Mov), R(this), R(0),
|
||||
B(JumpIfTrue), U8(16),
|
||||
B(Wide), B(LdaSmi), I16(283),
|
||||
B(Wide), B(LdaSmi), I16(285),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star2),
|
||||
/* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
|
||||
B(Throw),
|
||||
B(Wide), B(LdaSmi), I16(289),
|
||||
B(Wide), B(LdaSmi), I16(291),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(1),
|
||||
B(Star2),
|
||||
@ -143,7 +143,7 @@ bytecodes: [
|
||||
B(TestReferenceEqual), R(this),
|
||||
B(Mov), R(this), R(0),
|
||||
B(JumpIfTrue), U8(16),
|
||||
B(Wide), B(LdaSmi), I16(283),
|
||||
B(Wide), B(LdaSmi), I16(285),
|
||||
B(Star2),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star3),
|
||||
@ -165,7 +165,7 @@ bytecodes: [
|
||||
B(TestReferenceEqual), R(this),
|
||||
B(Mov), R(this), R(0),
|
||||
B(JumpIfTrue), U8(16),
|
||||
B(Wide), B(LdaSmi), I16(283),
|
||||
B(Wide), B(LdaSmi), I16(285),
|
||||
B(Star3),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star4),
|
||||
@ -180,7 +180,7 @@ bytecodes: [
|
||||
B(TestReferenceEqual), R(this),
|
||||
B(Mov), R(this), R(0),
|
||||
B(JumpIfTrue), U8(16),
|
||||
B(Wide), B(LdaSmi), I16(283),
|
||||
B(Wide), B(LdaSmi), I16(285),
|
||||
B(Star2),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star3),
|
||||
@ -214,13 +214,13 @@ bytecodes: [
|
||||
B(TestReferenceEqual), R(this),
|
||||
B(Mov), R(this), R(0),
|
||||
B(JumpIfTrue), U8(16),
|
||||
B(Wide), B(LdaSmi), I16(283),
|
||||
B(Wide), B(LdaSmi), I16(285),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star2),
|
||||
/* 65 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
|
||||
B(Throw),
|
||||
B(Wide), B(LdaSmi), I16(291),
|
||||
B(Wide), B(LdaSmi), I16(293),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(1),
|
||||
B(Star2),
|
||||
@ -251,13 +251,13 @@ bytecodes: [
|
||||
B(TestReferenceEqual), R(this),
|
||||
B(Mov), R(this), R(0),
|
||||
B(JumpIfTrue), U8(16),
|
||||
B(Wide), B(LdaSmi), I16(283),
|
||||
B(Wide), B(LdaSmi), I16(285),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star2),
|
||||
/* 58 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
|
||||
B(Throw),
|
||||
B(Wide), B(LdaSmi), I16(290),
|
||||
B(Wide), B(LdaSmi), I16(292),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(1),
|
||||
B(Star2),
|
||||
@ -288,13 +288,13 @@ bytecodes: [
|
||||
B(TestReferenceEqual), R(this),
|
||||
B(Mov), R(this), R(0),
|
||||
B(JumpIfTrue), U8(16),
|
||||
B(Wide), B(LdaSmi), I16(283),
|
||||
B(Wide), B(LdaSmi), I16(285),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star2),
|
||||
/* 65 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
|
||||
B(Throw),
|
||||
B(Wide), B(LdaSmi), I16(291),
|
||||
B(Wide), B(LdaSmi), I16(293),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(1),
|
||||
B(Star2),
|
||||
@ -323,7 +323,7 @@ bytecode array length: 19
|
||||
bytecodes: [
|
||||
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
|
||||
/* 51 E> */ B(LdaKeyedProperty), R(this), U8(0),
|
||||
B(Wide), B(LdaSmi), I16(290),
|
||||
B(Wide), B(LdaSmi), I16(292),
|
||||
B(Star1),
|
||||
B(LdaConstant), U8(0),
|
||||
B(Star2),
|
||||
|
52
test/mjsunit/shared-memory/shared-struct-surface.js
Normal file
52
test/mjsunit/shared-memory/shared-struct-surface.js
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --shared-string-table --harmony-struct
|
||||
|
||||
"use strict";
|
||||
|
||||
let S = new SharedStructType(['field']);
|
||||
|
||||
(function TestNoPrototype() {
|
||||
// For now the experimental shared structs don't have a prototype, unlike the
|
||||
// proposal explainer which says accessing the prototype throws.
|
||||
assertNull(S.prototype);
|
||||
assertNull(Object.getPrototypeOf(new S()));
|
||||
})();
|
||||
|
||||
(function TestPrimitives() {
|
||||
// All primitives can be stored in fields.
|
||||
let s = new S();
|
||||
for (let prim of [42, -0, undefined, null, true, false, "foo"]) {
|
||||
s.field = prim;
|
||||
assertEquals(s.field, prim);
|
||||
}
|
||||
})();
|
||||
|
||||
(function TestObjects() {
|
||||
let s = new S();
|
||||
// Shared objects cannot point to non-shared objects.
|
||||
assertThrows(() => { s.field = []; });
|
||||
assertThrows(() => { s.field = {}; });
|
||||
// Shared objects can point to other shared objects.
|
||||
let shared_rhs = new S();
|
||||
s.field = shared_rhs;
|
||||
assertEquals(s.field, shared_rhs);
|
||||
})();
|
||||
|
||||
(function TestNotExtensible() {
|
||||
let s = new S();
|
||||
// Shared structs are non-extensible.
|
||||
assertThrows(() => { s.nonExistent = 42; });
|
||||
assertThrows(() => { Object.setPrototypeOf(s, {}); });
|
||||
assertThrows(() => { Object.defineProperty(s, 'nonExistent', { value: 42 }); });
|
||||
})();
|
||||
|
||||
(function TestTooManyFields() {
|
||||
let field_names = [];
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
field_names.push('field' + i);
|
||||
}
|
||||
assertThrows(() => { new SharedStructType(field_names); });
|
||||
})();
|
39
test/mjsunit/shared-memory/shared-struct-workers.js
Normal file
39
test/mjsunit/shared-memory/shared-struct-workers.js
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --shared-string-table --harmony-struct --allow-natives-syntax
|
||||
|
||||
"use strict";
|
||||
|
||||
if (this.Worker) {
|
||||
|
||||
(function TestSharedStructPostMessage() {
|
||||
let workerScript =
|
||||
`onmessage = function(struct) {
|
||||
struct.struct_field.payload = 42;
|
||||
struct.string_field = "worker";
|
||||
postMessage("done");
|
||||
};
|
||||
postMessage("started");`;
|
||||
|
||||
let worker = new Worker(workerScript, { type: 'string' });
|
||||
let started = worker.getMessage();
|
||||
assertEquals("started", started);
|
||||
|
||||
let OuterStruct = new SharedStructType(['string_field', 'struct_field']);
|
||||
let InnerStruct = new SharedStructType(['payload']);
|
||||
let struct = new OuterStruct();
|
||||
struct.struct_field = new InnerStruct();
|
||||
struct.string_field = "main";
|
||||
assertEquals("main", struct.string_field);
|
||||
assertEquals(undefined, struct.struct_field.payload);
|
||||
worker.postMessage(struct);
|
||||
assertEquals("done", worker.getMessage());
|
||||
assertEquals("worker", struct.string_field);
|
||||
assertEquals(42, struct.struct_field.payload);
|
||||
|
||||
worker.terminate();
|
||||
})();
|
||||
|
||||
}
|
@ -244,27 +244,28 @@ INSTANCE_TYPES = {
|
||||
2122: "JS_SEGMENTER_TYPE",
|
||||
2123: "JS_SEGMENTS_TYPE",
|
||||
2124: "JS_SHADOW_REALM_TYPE",
|
||||
2125: "JS_STRING_ITERATOR_TYPE",
|
||||
2126: "JS_TEMPORAL_CALENDAR_TYPE",
|
||||
2127: "JS_TEMPORAL_DURATION_TYPE",
|
||||
2128: "JS_TEMPORAL_INSTANT_TYPE",
|
||||
2129: "JS_TEMPORAL_PLAIN_DATE_TYPE",
|
||||
2130: "JS_TEMPORAL_PLAIN_DATE_TIME_TYPE",
|
||||
2131: "JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE",
|
||||
2132: "JS_TEMPORAL_PLAIN_TIME_TYPE",
|
||||
2133: "JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE",
|
||||
2134: "JS_TEMPORAL_TIME_ZONE_TYPE",
|
||||
2135: "JS_TEMPORAL_ZONED_DATE_TIME_TYPE",
|
||||
2136: "JS_V8_BREAK_ITERATOR_TYPE",
|
||||
2137: "JS_WEAK_REF_TYPE",
|
||||
2138: "WASM_GLOBAL_OBJECT_TYPE",
|
||||
2139: "WASM_INSTANCE_OBJECT_TYPE",
|
||||
2140: "WASM_MEMORY_OBJECT_TYPE",
|
||||
2141: "WASM_MODULE_OBJECT_TYPE",
|
||||
2142: "WASM_SUSPENDER_OBJECT_TYPE",
|
||||
2143: "WASM_TABLE_OBJECT_TYPE",
|
||||
2144: "WASM_TAG_OBJECT_TYPE",
|
||||
2145: "WASM_VALUE_OBJECT_TYPE",
|
||||
2125: "JS_SHARED_STRUCT_TYPE",
|
||||
2126: "JS_STRING_ITERATOR_TYPE",
|
||||
2127: "JS_TEMPORAL_CALENDAR_TYPE",
|
||||
2128: "JS_TEMPORAL_DURATION_TYPE",
|
||||
2129: "JS_TEMPORAL_INSTANT_TYPE",
|
||||
2130: "JS_TEMPORAL_PLAIN_DATE_TYPE",
|
||||
2131: "JS_TEMPORAL_PLAIN_DATE_TIME_TYPE",
|
||||
2132: "JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE",
|
||||
2133: "JS_TEMPORAL_PLAIN_TIME_TYPE",
|
||||
2134: "JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE",
|
||||
2135: "JS_TEMPORAL_TIME_ZONE_TYPE",
|
||||
2136: "JS_TEMPORAL_ZONED_DATE_TIME_TYPE",
|
||||
2137: "JS_V8_BREAK_ITERATOR_TYPE",
|
||||
2138: "JS_WEAK_REF_TYPE",
|
||||
2139: "WASM_GLOBAL_OBJECT_TYPE",
|
||||
2140: "WASM_INSTANCE_OBJECT_TYPE",
|
||||
2141: "WASM_MEMORY_OBJECT_TYPE",
|
||||
2142: "WASM_MODULE_OBJECT_TYPE",
|
||||
2143: "WASM_SUSPENDER_OBJECT_TYPE",
|
||||
2144: "WASM_TABLE_OBJECT_TYPE",
|
||||
2145: "WASM_TAG_OBJECT_TYPE",
|
||||
2146: "WASM_VALUE_OBJECT_TYPE",
|
||||
}
|
||||
|
||||
# List of known V8 maps.
|
||||
|
Loading…
Reference in New Issue
Block a user