Commit 2e96276c authored by Nico Hartmann's avatar Nico Hartmann Committed by Commit Bot

[turbofan] More ScriptContextTable concurrency

Add synchronized accessors for ScriptContextTable on NativeContext.
Add corresponding cctest.

Bug: v8:7790
Change-Id: If390f3d4a72441a8b4323e9413d7627cd15514c0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2299372
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarSantiago Aboy Solanes <solanes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68981}
parent 8fcf7cb0
......@@ -233,7 +233,8 @@ MaybeHandle<Context> NewScriptContext(Isolate* isolate,
Handle<ScriptContextTable> new_script_context_table =
ScriptContextTable::Extend(script_context, result);
native_context->set_script_context_table(*new_script_context_table);
native_context->synchronized_set_script_context_table(
*new_script_context_table);
return result;
}
......
......@@ -86,6 +86,25 @@ void Context::set_scope_info(ScopeInfo scope_info) {
set(SCOPE_INFO_INDEX, scope_info);
}
Object Context::synchronized_get(int index) const {
const Isolate* isolate = GetIsolateForPtrCompr(*this);
return synchronized_get(isolate, index);
}
Object Context::synchronized_get(const Isolate* isolate, int index) const {
DCHECK_LT(static_cast<unsigned int>(index),
static_cast<unsigned int>(this->length()));
return ACQUIRE_READ_FIELD(*this, OffsetOfElementAt(index));
}
void Context::synchronized_set(int index, Object value) {
DCHECK_LT(static_cast<unsigned int>(index),
static_cast<unsigned int>(this->length()));
const int offset = OffsetOfElementAt(index);
RELEASE_WRITE_FIELD(*this, offset, value);
WRITE_BARRIER(*this, offset, value);
}
Object Context::unchecked_previous() { return get(PREVIOUS_INDEX); }
Context Context::previous() {
......@@ -261,6 +280,15 @@ void NativeContext::set_microtask_queue(Isolate* isolate,
WriteField<ExternalPointer_t>(kMicrotaskQueueOffset, encoded_value);
}
void NativeContext::synchronized_set_script_context_table(
ScriptContextTable script_context_table) {
synchronized_set(SCRIPT_CONTEXT_TABLE_INDEX, script_context_table);
}
ScriptContextTable NativeContext::synchronized_script_context_table() const {
return ScriptContextTable::cast(synchronized_get(SCRIPT_CONTEXT_TABLE_INDEX));
}
OSROptimizedCodeCache NativeContext::GetOSROptimizedCodeCache() {
return OSROptimizedCodeCache::cast(osr_code_cache());
}
......
......@@ -441,6 +441,10 @@ class Context : public HeapObject {
V8_INLINE void set(int index, Object value);
// Setter with explicit barrier mode.
V8_INLINE void set(int index, Object value, WriteBarrierMode mode);
// Setter and getter with synchronization semantics.
V8_INLINE Object synchronized_get(int index) const;
V8_INLINE Object synchronized_get(const Isolate* isolate, int index) const;
V8_INLINE void synchronized_set(int index, Object value);
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
TORQUE_GENERATED_CONTEXT_FIELDS)
......@@ -661,6 +665,10 @@ class NativeContext : public Context {
DECL_GETTER(microtask_queue, MicrotaskQueue*)
inline void set_microtask_queue(Isolate* isolate, MicrotaskQueue* queue);
inline void synchronized_set_script_context_table(
ScriptContextTable script_context_table);
inline ScriptContextTable synchronized_script_context_table() const;
// Dispatched behavior.
DECL_PRINTER(NativeContext)
DECL_VERIFIER(NativeContext)
......
......@@ -18,6 +18,8 @@ namespace internal {
namespace {
std::atomic<int> g_initialized_entries;
class ScriptContextTableAccessUsedThread final : public v8::base::Thread {
public:
ScriptContextTableAccessUsedThread(
......@@ -54,6 +56,49 @@ class ScriptContextTableAccessUsedThread final : public v8::base::Thread {
Handle<ScriptContextTable> script_context_table_;
};
class AccessScriptContextTableThread final : public v8::base::Thread {
public:
AccessScriptContextTableThread(Isolate* isolate, Heap* heap,
base::Semaphore* sema_started,
std::unique_ptr<PersistentHandles> ph,
Handle<NativeContext> native_context)
: v8::base::Thread(
base::Thread::Options("AccessScriptContextTableThread")),
isolate_(isolate),
heap_(heap),
sema_started_(sema_started),
ph_(std::move(ph)),
native_context_(native_context) {}
void Run() override {
LocalHeap local_heap(heap_, std::move(ph_));
LocalHandleScope scope(&local_heap);
sema_started_->Signal();
for (int i = 0; i < 1000; ++i) {
// Read upper bound with relaxed semantics to not add any ordering
// constraints.
while (i >= g_initialized_entries.load(std::memory_order_relaxed)) {
}
auto script_context_table = Handle<ScriptContextTable>(
native_context_->synchronized_script_context_table(), &local_heap);
Handle<Context> context(script_context_table->get_context(i),
&local_heap);
CHECK(!context.is_null());
}
CHECK(!ph_);
ph_ = local_heap.DetachPersistentHandles();
}
Isolate* isolate_;
Heap* heap_;
base::Semaphore* sema_started_;
std::unique_ptr<PersistentHandles> ph_;
Handle<NativeContext> native_context_;
};
TEST(ScriptContextTable_Extend) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
......@@ -94,12 +139,66 @@ TEST(ScriptContextTable_Extend) {
sema_started.Wait();
for (int i = 0; i < 10; ++i) {
for (int i = 0; i < 100; ++i) {
Handle<Context> context =
factory->NewScriptContext(native_context, scope_info);
script_context_table =
ScriptContextTable::Extend(script_context_table, context);
}
thread->Join();
}
TEST(ScriptContextTable_AccessScriptContextTable) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
Factory* factory = isolate->factory();
Handle<NativeContext> native_context = factory->NewNativeContext();
Handle<Map> script_context_map =
factory->NewMap(SCRIPT_CONTEXT_TYPE, kVariableSizeSentinel);
script_context_map->set_native_context(*native_context);
native_context->set_script_context_map(*script_context_map);
Handle<ScopeInfo> scope_info =
ReadOnlyRoots(isolate).global_this_binding_scope_info_handle();
Handle<ScriptContextTable> script_context_table =
factory->NewScriptContextTable();
Handle<Context> context =
factory->NewScriptContext(native_context, scope_info);
script_context_table =
ScriptContextTable::Extend(script_context_table, context);
int initialized_entries = 1;
g_initialized_entries.store(initialized_entries, std::memory_order_release);
native_context->set_script_context_table(*script_context_table);
std::unique_ptr<PersistentHandles> ph = isolate->NewPersistentHandles();
Handle<NativeContext> persistent_native_context =
ph->NewHandle(native_context);
base::Semaphore sema_started(0);
auto thread = std::make_unique<AccessScriptContextTableThread>(
isolate, isolate->heap(), &sema_started, std::move(ph),
persistent_native_context);
CHECK(thread->Start());
sema_started.Wait();
for (; initialized_entries < 1000; ++initialized_entries) {
Handle<Context> context =
factory->NewScriptContext(native_context, scope_info);
script_context_table =
ScriptContextTable::Extend(script_context_table, context);
native_context->synchronized_set_script_context_table(
*script_context_table);
// Update with relaxed semantics to not introduce ordering constraints.
g_initialized_entries.store(initialized_entries, std::memory_order_relaxed);
}
g_initialized_entries.store(initialized_entries, std::memory_order_relaxed);
thread->Join();
}
......
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