diff --git a/common.gypi b/common.gypi index 6af75f45839f6e..0d3cdb81b8dd7c 100644 --- a/common.gypi +++ b/common.gypi @@ -36,7 +36,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.57', + 'v8_embedder_string': '-node.58', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/common/checks.h b/deps/v8/src/common/checks.h index ef9eb27ca07e9f..eef59701d1d4a9 100644 --- a/deps/v8/src/common/checks.h +++ b/deps/v8/src/common/checks.h @@ -18,9 +18,11 @@ namespace internal { #ifdef ENABLE_SLOW_DCHECKS #define SLOW_DCHECK(condition) \ CHECK(!v8::internal::FLAG_enable_slow_asserts || (condition)) +#define SLOW_DCHECK_IMPLIES(lhs, rhs) SLOW_DCHECK(!(lhs) || (rhs)) V8_EXPORT_PRIVATE extern bool FLAG_enable_slow_asserts; #else #define SLOW_DCHECK(condition) ((void)0) +#define SLOW_DCHECK_IMPLIES(v1, v2) ((void)0) static const bool FLAG_enable_slow_asserts = false; #endif diff --git a/deps/v8/src/objects/descriptor-array-inl.h b/deps/v8/src/objects/descriptor-array-inl.h index 74f984d6bd2581..a7c6443a05fa7d 100644 --- a/deps/v8/src/objects/descriptor-array-inl.h +++ b/deps/v8/src/objects/descriptor-array-inl.h @@ -55,17 +55,19 @@ void DescriptorArray::CopyEnumCacheFrom(DescriptorArray array) { set_enum_cache(array.enum_cache()); } -InternalIndex DescriptorArray::Search(Name name, int valid_descriptors) { +InternalIndex DescriptorArray::Search(Name name, int valid_descriptors, + bool concurrent_search) { DCHECK(name.IsUniqueName()); - return InternalIndex( - internal::Search(this, name, valid_descriptors, nullptr)); + return InternalIndex(internal::Search( + this, name, valid_descriptors, nullptr, concurrent_search)); } -InternalIndex DescriptorArray::Search(Name name, Map map) { +InternalIndex DescriptorArray::Search(Name name, Map map, + bool concurrent_search) { DCHECK(name.IsUniqueName()); int number_of_own_descriptors = map.NumberOfOwnDescriptors(); if (number_of_own_descriptors == 0) return InternalIndex::NotFound(); - return Search(name, number_of_own_descriptors); + return Search(name, number_of_own_descriptors, concurrent_search); } InternalIndex DescriptorArray::SearchWithCache(Isolate* isolate, Name name, diff --git a/deps/v8/src/objects/descriptor-array.h b/deps/v8/src/objects/descriptor-array.h index d752ca20b1101f..3d505ad57695e0 100644 --- a/deps/v8/src/objects/descriptor-array.h +++ b/deps/v8/src/objects/descriptor-array.h @@ -115,9 +115,13 @@ class DescriptorArray // Sort the instance descriptors by the hash codes of their keys. V8_EXPORT_PRIVATE void Sort(); - // Search the instance descriptors for given name. - V8_INLINE InternalIndex Search(Name name, int number_of_own_descriptors); - V8_INLINE InternalIndex Search(Name name, Map map); + // Search the instance descriptors for given name. {concurrent_search} signals + // if we are doing the search on a background thread. If so, we will sacrifice + // speed for thread-safety. + V8_INLINE InternalIndex Search(Name name, int number_of_own_descriptors, + bool concurrent_search = false); + V8_INLINE InternalIndex Search(Name name, Map map, + bool concurrent_search = false); // As the above, but uses DescriptorLookupCache and updates it when // necessary. diff --git a/deps/v8/src/objects/fixed-array-inl.h b/deps/v8/src/objects/fixed-array-inl.h index b89486d38116a4..df741310c7036b 100644 --- a/deps/v8/src/objects/fixed-array-inl.h +++ b/deps/v8/src/objects/fixed-array-inl.h @@ -284,8 +284,9 @@ int LinearSearch(T* array, Name name, int valid_entries, } template -int Search(T* array, Name name, int valid_entries, int* out_insertion_index) { - SLOW_DCHECK(array->IsSortedNoDuplicates()); +int Search(T* array, Name name, int valid_entries, int* out_insertion_index, + bool concurrent_search) { + SLOW_DCHECK_IMPLIES(!concurrent_search, array->IsSortedNoDuplicates()); if (valid_entries == 0) { if (search_mode == ALL_ENTRIES && out_insertion_index != nullptr) { @@ -294,14 +295,14 @@ int Search(T* array, Name name, int valid_entries, int* out_insertion_index) { return T::kNotFound; } - // Fast case: do linear search for small arrays. + // Do linear search for small arrays, and for searches in the background + // thread. const int kMaxElementsForLinearSearch = 8; - if (valid_entries <= kMaxElementsForLinearSearch) { + if (valid_entries <= kMaxElementsForLinearSearch || concurrent_search) { return LinearSearch(array, name, valid_entries, out_insertion_index); } - // Slow case: perform binary search. return BinarySearch(array, name, valid_entries, out_insertion_index); } diff --git a/deps/v8/src/objects/fixed-array.h b/deps/v8/src/objects/fixed-array.h index 63c3c5360b96aa..ccb954c6e2517f 100644 --- a/deps/v8/src/objects/fixed-array.h +++ b/deps/v8/src/objects/fixed-array.h @@ -465,7 +465,8 @@ enum SearchMode { ALL_ENTRIES, VALID_ENTRIES }; template inline int Search(T* array, Name name, int valid_entries = 0, - int* out_insertion_index = nullptr); + int* out_insertion_index = nullptr, + bool concurrent_search = false); // ByteArray represents fixed sized byte arrays. Used for the relocation info // that is attached to code objects. diff --git a/deps/v8/src/objects/map.h b/deps/v8/src/objects/map.h index 9876d85d3eccf6..a4f563f6a17390 100644 --- a/deps/v8/src/objects/map.h +++ b/deps/v8/src/objects/map.h @@ -594,6 +594,7 @@ class Map : public HeapObject { WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // [instance descriptors]: describes the object. + DECL_GETTER(synchronized_instance_descriptors, DescriptorArray) DECL_GETTER(instance_descriptors, DescriptorArray) V8_EXPORT_PRIVATE void SetInstanceDescriptors(Isolate* isolate, DescriptorArray descriptors, @@ -976,7 +977,8 @@ class Map : public HeapObject { MaybeHandle new_value); // Use the high-level instance_descriptors/SetInstanceDescriptors instead. - DECL_ACCESSORS(synchronized_instance_descriptors, DescriptorArray) + inline void set_synchronized_instance_descriptors( + DescriptorArray value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); static const int kFastPropertiesSoftLimit = 12; static const int kMaxFastProperties = 128; diff --git a/deps/v8/test/cctest/BUILD.gn b/deps/v8/test/cctest/BUILD.gn index 94e9e73c0e6083..66e1473ed28d3a 100644 --- a/deps/v8/test/cctest/BUILD.gn +++ b/deps/v8/test/cctest/BUILD.gn @@ -196,6 +196,7 @@ v8_source_set("cctest_sources") { "test-code-pages.cc", "test-code-stub-assembler.cc", "test-compiler.cc", + "test-concurrent-descriptor-array.cc", "test-constantpool.cc", "test-conversions.cc", "test-cpu-profiler.cc", diff --git a/deps/v8/test/cctest/test-concurrent-descriptor-array.cc b/deps/v8/test/cctest/test-concurrent-descriptor-array.cc new file mode 100644 index 00000000000000..43c686d4e0d4ec --- /dev/null +++ b/deps/v8/test/cctest/test-concurrent-descriptor-array.cc @@ -0,0 +1,128 @@ +// Copyright 2020 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/api/api.h" +#include "src/base/platform/semaphore.h" +#include "src/handles/handles-inl.h" +#include "src/handles/local-handles-inl.h" +#include "src/handles/persistent-handles.h" +#include "src/heap/heap.h" +#include "src/heap/local-heap.h" +#include "test/cctest/cctest.h" +#include "test/cctest/heap/heap-utils.h" + +namespace v8 { +namespace internal { + +static constexpr int kNumHandles = kHandleBlockSize * 2 + kHandleBlockSize / 2; + +namespace { + +class PersistentHandlesThread final : public v8::base::Thread { + public: + PersistentHandlesThread(Heap* heap, std::vector> handles, + std::unique_ptr ph, + Handle name, base::Semaphore* sema_started) + : v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")), + heap_(heap), + handles_(std::move(handles)), + ph_(std::move(ph)), + name_(name), + sema_started_(sema_started) {} + + void Run() override { + LocalHeap local_heap(heap_, std::move(ph_)); + LocalHandleScope scope(&local_heap); + Address object = handles_[0]->ptr(); + + for (int i = 0; i < kNumHandles; i++) { + handles_.push_back( + Handle::cast(local_heap.NewPersistentHandle(object))); + } + + sema_started_->Signal(); + + for (Handle handle : handles_) { + // Lookup the named property on the {map}. + CHECK(name_->IsUniqueName()); + Handle map(handle->map(), &local_heap); + + Handle descriptors( + map->synchronized_instance_descriptors(), &local_heap); + bool is_background_thread = true; + InternalIndex const number = + descriptors->Search(*name_, *map, is_background_thread); + CHECK(number.is_found()); + } + + CHECK_EQ(handles_.size(), kNumHandles * 2); + + CHECK(!ph_); + ph_ = local_heap.DetachPersistentHandles(); + } + + Heap* heap_; + std::vector> handles_; + std::unique_ptr ph_; + Handle name_; + base::Semaphore* sema_started_; +}; + +// Uses linear search on a flat object, with up to 8 elements. +TEST(LinearSearchFlatObject) { + CcTest::InitializeVM(); + FLAG_local_heaps = true; + Isolate* isolate = CcTest::i_isolate(); + + std::unique_ptr ph = isolate->NewPersistentHandles(); + std::vector> handles; + + auto factory = isolate->factory(); + HandleScope handle_scope(isolate); + + Handle function = + factory->NewFunctionForTest(factory->empty_string()); + Handle js_object = factory->NewJSObject(function); + Handle name = CcTest::MakeString("property"); + Handle value = CcTest::MakeString("dummy_value"); + // For the default constructor function no in-object properties are reserved + // hence adding a single property will initialize the property-array. + JSObject::DefinePropertyOrElementIgnoreAttributes(js_object, name, value, + NONE) + .Check(); + + Address object = js_object->ptr(); + for (int i = 0; i < kNumHandles; i++) { + handles.push_back(Handle::cast(ph->NewHandle(object))); + } + + Handle persistent_name = Handle::cast(ph->NewHandle(name->ptr())); + + base::Semaphore sema_started(0); + + // Pass persistent handles to background thread. + std::unique_ptr thread(new PersistentHandlesThread( + isolate->heap(), std::move(handles), std::move(ph), persistent_name, + &sema_started)); + CHECK(thread->Start()); + + sema_started.Wait(); + + // Exercise descriptor in main thread too. + for (int i = 0; i < 7; ++i) { + Handle filler_name = CcTest::MakeName("filler_property_", i); + Handle filler_value = CcTest::MakeString("dummy_value"); + JSObject::DefinePropertyOrElementIgnoreAttributes(js_object, filler_name, + filler_value, NONE) + .Check(); + } + CHECK_EQ(js_object->map().NumberOfOwnDescriptors(), 8); + + thread->Join(); +} + +} // anonymous namespace + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/test-local-handles.cc b/deps/v8/test/cctest/test-local-handles.cc index 0e4fc5c7d18237..f4fdaebd0d9c27 100644 --- a/deps/v8/test/cctest/test-local-handles.cc +++ b/deps/v8/test/cctest/test-local-handles.cc @@ -20,6 +20,8 @@ namespace v8 { namespace internal { +namespace { + class LocalHandlesThread final : public v8::base::Thread { public: LocalHandlesThread(Heap* heap, Address object, base::Semaphore* sema_started, @@ -92,5 +94,7 @@ TEST(CreateLocalHandles) { thread->Join(); } +} // anonymous namespace + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/test-persistent-handles.cc b/deps/v8/test/cctest/test-persistent-handles.cc index 0bb2990d178cf3..b40b3eb0443df3 100644 --- a/deps/v8/test/cctest/test-persistent-handles.cc +++ b/deps/v8/test/cctest/test-persistent-handles.cc @@ -23,6 +23,8 @@ namespace internal { static constexpr int kNumHandles = kHandleBlockSize * 2 + kHandleBlockSize / 2; +namespace { + class PersistentHandlesThread final : public v8::base::Thread { public: PersistentHandlesThread(Heap* heap, std::vector> handles, @@ -110,5 +112,7 @@ TEST(CreatePersistentHandles) { ph->NewHandle(number->ptr()); } +} // anonymous namespace + } // namespace internal } // namespace v8