Skip to content

Commit de964db

Browse files
mtrofinCommit Bot
authored andcommitted
Introducing an event loop mechanism for d8.
This mechanism ensures APIs like wasm async complete their work, without requiring use of natives (%APIs). The mechanism is similar to the one used in content_shell, which should allow us to easily port tests in that environment. Review-Url: https://codereview.chromium.org/2842843005 Cr-Original-Commit-Position: refs/heads/master@{#44908} Bug: Change-Id: I9deee0d256a600c60b42902fc8ef8478e5546344 Reviewed-on: https://chromium-review.googlesource.com/494968 Commit-Queue: Mircea Trofin <mtrofin@google.com> Reviewed-by: Jochen Eisinger <jochen@chromium.org> Cr-Commit-Position: refs/heads/master@{#45165}
1 parent 4d81f7f commit de964db

15 files changed

Lines changed: 153 additions & 89 deletions

include/libplatform/libplatform.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ namespace platform {
1515
enum class IdleTaskSupport { kDisabled, kEnabled };
1616
enum class InProcessStackDumping { kDisabled, kEnabled };
1717

18+
enum class MessageLoopBehavior : bool {
19+
kDoNotWait = false,
20+
kWaitForWork = true
21+
};
22+
1823
/**
1924
* Returns a new instance of the default v8::Platform implementation.
2025
*
@@ -36,12 +41,16 @@ V8_PLATFORM_EXPORT v8::Platform* CreateDefaultPlatform(
3641
* Pumps the message loop for the given isolate.
3742
*
3843
* The caller has to make sure that this is called from the right thread.
39-
* Returns true if a task was executed, and false otherwise. This call does
40-
* not block if no task is pending. The |platform| has to be created using
41-
* |CreateDefaultPlatform|.
44+
* Returns true if a task was executed, and false otherwise. Unless requested
45+
* through the |behavior| parameter, this call does not block if no task is
46+
* pending. The |platform| has to be created using |CreateDefaultPlatform|.
4247
*/
43-
V8_PLATFORM_EXPORT bool PumpMessageLoop(v8::Platform* platform,
44-
v8::Isolate* isolate);
48+
V8_PLATFORM_EXPORT bool PumpMessageLoop(
49+
v8::Platform* platform, v8::Isolate* isolate,
50+
MessageLoopBehavior behavior = MessageLoopBehavior::kDoNotWait);
51+
52+
V8_PLATFORM_EXPORT void EnsureEventLoopInitialized(v8::Platform* platform,
53+
v8::Isolate* isolate);
4554

4655
/**
4756
* Runs pending idle tasks for at most |idle_time_in_seconds| seconds.

src/d8.cc

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ base::LazyMutex Shell::workers_mutex_;
422422
bool Shell::allow_new_workers_ = true;
423423
i::List<Worker*> Shell::workers_;
424424
std::vector<ExternalizedContents> Shell::externalized_contents_;
425+
std::map<v8::Isolate*, bool> Shell::isolate_status;
425426

426427
Global<Context> Shell::evaluation_context_;
427428
ArrayBuffer::Allocator* Shell::array_buffer_allocator;
@@ -1345,6 +1346,18 @@ void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
13451346
const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
13461347
}
13471348

1349+
void Shell::WaitUntilDone(const v8::FunctionCallbackInfo<v8::Value>& args) {
1350+
if (isolate_status.count(args.GetIsolate()) == 0) {
1351+
isolate_status.insert(std::make_pair(args.GetIsolate(), true));
1352+
} else {
1353+
isolate_status[args.GetIsolate()] = true;
1354+
}
1355+
}
1356+
1357+
void Shell::NotifyDone(const v8::FunctionCallbackInfo<v8::Value>& args) {
1358+
DCHECK_EQ(isolate_status.count(args.GetIsolate()), 1);
1359+
isolate_status[args.GetIsolate()] = false;
1360+
}
13481361

13491362
void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
13501363
args.GetReturnValue().Set(
@@ -1582,6 +1595,19 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
15821595
.ToLocalChecked(),
15831596
FunctionTemplate::New(isolate, Quit));
15841597
}
1598+
Local<ObjectTemplate> test_template = ObjectTemplate::New(isolate);
1599+
global_template->Set(
1600+
String::NewFromUtf8(isolate, "testRunner", NewStringType::kNormal)
1601+
.ToLocalChecked(),
1602+
test_template);
1603+
test_template->Set(
1604+
String::NewFromUtf8(isolate, "notifyDone", NewStringType::kNormal)
1605+
.ToLocalChecked(),
1606+
FunctionTemplate::New(isolate, NotifyDone));
1607+
test_template->Set(
1608+
String::NewFromUtf8(isolate, "waitUntilDone", NewStringType::kNormal)
1609+
.ToLocalChecked(),
1610+
FunctionTemplate::New(isolate, WaitUntilDone));
15851611
global_template->Set(
15861612
String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
15871613
.ToLocalChecked(),
@@ -2266,6 +2292,8 @@ void SourceGroup::ExecuteInThread() {
22662292
create_params.host_import_module_dynamically_callback_ =
22672293
Shell::HostImportModuleDynamically;
22682294
Isolate* isolate = Isolate::New(create_params);
2295+
2296+
v8::platform::EnsureEventLoopInitialized(g_platform, isolate);
22692297
D8Console console(isolate);
22702298
debug::SetConsoleDelegate(isolate, &console);
22712299
for (int i = 0; i < Shell::options.stress_runs; ++i) {
@@ -2290,6 +2318,8 @@ void SourceGroup::ExecuteInThread() {
22902318
done_semaphore_.Signal();
22912319
}
22922320

2321+
Shell::CompleteMessageLoop(isolate);
2322+
22932323
isolate->Dispose();
22942324
}
22952325

@@ -2646,6 +2676,7 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
26462676
options.isolate_sources[i].StartExecuteInThread();
26472677
}
26482678
{
2679+
v8::platform::EnsureEventLoopInitialized(g_platform, isolate);
26492680
if (options.lcov_file) {
26502681
debug::Coverage::SelectMode(isolate, debug::Coverage::kPreciseCount);
26512682
}
@@ -2668,6 +2699,7 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
26682699
WriteLcovData(isolate, options.lcov_file);
26692700
}
26702701
CollectGarbage(isolate);
2702+
CompleteMessageLoop(isolate);
26712703
for (int i = 1; i < options.num_isolates; ++i) {
26722704
if (last_run) {
26732705
options.isolate_sources[i].JoinThread();
@@ -2695,24 +2727,28 @@ void Shell::CollectGarbage(Isolate* isolate) {
26952727
}
26962728
}
26972729

2730+
void Shell::CompleteMessageLoop(Isolate* isolate) {
2731+
while (v8::platform::PumpMessageLoop(
2732+
g_platform, isolate,
2733+
Shell::isolate_status[isolate]
2734+
? platform::MessageLoopBehavior::kWaitForWork
2735+
: platform::MessageLoopBehavior::kDoNotWait)) {
2736+
isolate->RunMicrotasks();
2737+
}
2738+
v8::platform::RunIdleTasks(g_platform, isolate,
2739+
50.0 / base::Time::kMillisecondsPerSecond);
2740+
}
2741+
26982742
void Shell::EmptyMessageQueues(Isolate* isolate) {
26992743
if (i::FLAG_verify_predictable) return;
2700-
while (true) {
2701-
// Pump the message loop until it is empty.
2702-
while (v8::platform::PumpMessageLoop(g_platform, isolate)) {
2703-
isolate->RunMicrotasks();
2704-
}
2705-
// Run the idle tasks.
2706-
v8::platform::RunIdleTasks(g_platform, isolate,
2707-
50.0 / base::Time::kMillisecondsPerSecond);
2708-
// If there are still outstanding waiters, sleep a little (to wait for
2709-
// background tasks) and then try everything again.
2710-
if (reinterpret_cast<i::Isolate*>(isolate)->GetWaitCountForTesting() > 0) {
2711-
base::OS::Sleep(base::TimeDelta::FromMilliseconds(1));
2712-
} else {
2713-
break;
2714-
}
2715-
}
2744+
// Pump the message loop until it is empty.
2745+
while (v8::platform::PumpMessageLoop(
2746+
g_platform, isolate, platform::MessageLoopBehavior::kDoNotWait)) {
2747+
isolate->RunMicrotasks();
2748+
}
2749+
// Run the idle tasks.
2750+
v8::platform::RunIdleTasks(g_platform, isolate,
2751+
50.0 / base::Time::kMillisecondsPerSecond);
27162752
}
27172753

27182754
class Serializer : public ValueSerializer::Delegate {

src/d8.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define V8_D8_H_
77

88
#include <iterator>
9+
#include <map>
910
#include <memory>
1011
#include <string>
1112
#include <vector>
@@ -356,6 +357,7 @@ class Shell : public i::AllStatic {
356357
static void OnExit(Isolate* isolate);
357358
static void CollectGarbage(Isolate* isolate);
358359
static void EmptyMessageQueues(Isolate* isolate);
360+
static void CompleteMessageLoop(Isolate* isolate);
359361

360362
static std::unique_ptr<SerializationData> SerializeValue(
361363
Isolate* isolate, Local<Value> value, Local<Value> transfer);
@@ -391,6 +393,8 @@ class Shell : public i::AllStatic {
391393
static void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
392394
static void PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args);
393395
static void Write(const v8::FunctionCallbackInfo<v8::Value>& args);
396+
static void WaitUntilDone(const v8::FunctionCallbackInfo<v8::Value>& args);
397+
static void NotifyDone(const v8::FunctionCallbackInfo<v8::Value>& args);
394398
static void QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args);
395399
static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args);
396400
static void Version(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -454,6 +458,7 @@ class Shell : public i::AllStatic {
454458
static const char* kPrompt;
455459
static ShellOptions options;
456460
static ArrayBuffer::Allocator* array_buffer_allocator;
461+
static std::map<Isolate*, bool> isolate_status;
457462

458463
private:
459464
static Global<Context> evaluation_context_;

src/isolate.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,11 +1291,6 @@ class Isolate {
12911291
// reset to nullptr.
12921292
void UnregisterFromReleaseAtTeardown(ManagedObjectFinalizer** finalizer_ptr);
12931293

1294-
// Used by mjsunit tests to force d8 to wait for certain things to run.
1295-
inline void IncrementWaitCountForTesting() { wait_count_++; }
1296-
inline void DecrementWaitCountForTesting() { wait_count_--; }
1297-
inline int GetWaitCountForTesting() { return wait_count_; }
1298-
12991294
protected:
13001295
explicit Isolate(bool enable_serializer);
13011296
bool IsArrayOrObjectPrototype(Object* object);
@@ -1582,8 +1577,6 @@ class Isolate {
15821577

15831578
size_t total_regexp_code_generated_;
15841579

1585-
int wait_count_ = 0;
1586-
15871580
friend class ExecutionAccess;
15881581
friend class HandleScopeImplementer;
15891582
friend class HeapTester;

src/libplatform/default-platform.cc

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,15 @@ v8::Platform* CreateDefaultPlatform(
4141
return platform;
4242
}
4343

44+
bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate,
45+
MessageLoopBehavior behavior) {
46+
return reinterpret_cast<DefaultPlatform*>(platform)->PumpMessageLoop(
47+
isolate, behavior);
48+
}
4449

45-
bool PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate) {
46-
return reinterpret_cast<DefaultPlatform*>(platform)->PumpMessageLoop(isolate);
50+
void EnsureEventLoopInitialized(v8::Platform* platform, v8::Isolate* isolate) {
51+
return reinterpret_cast<DefaultPlatform*>(platform)
52+
->EnsureEventLoopInitialized(isolate);
4753
}
4854

4955
void RunIdleTasks(v8::Platform* platform, v8::Isolate* isolate,
@@ -158,22 +164,38 @@ IdleTask* DefaultPlatform::PopTaskInMainThreadIdleQueue(v8::Isolate* isolate) {
158164
return task;
159165
}
160166

161-
bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate) {
167+
void DefaultPlatform::EnsureEventLoopInitialized(v8::Isolate* isolate) {
168+
if (event_loop_control_.count(isolate) == 0) {
169+
event_loop_control_.insert(std::make_pair(
170+
isolate, std::unique_ptr<base::Semaphore>(new base::Semaphore(0))));
171+
}
172+
}
173+
174+
void DefaultPlatform::WaitForForegroundWork(v8::Isolate* isolate) {
175+
DCHECK_EQ(event_loop_control_.count(isolate), 1);
176+
event_loop_control_[isolate]->Wait();
177+
}
178+
179+
bool DefaultPlatform::PumpMessageLoop(v8::Isolate* isolate,
180+
MessageLoopBehavior behavior) {
181+
if (behavior == MessageLoopBehavior::kWaitForWork) {
182+
WaitForForegroundWork(isolate);
183+
}
162184
Task* task = NULL;
163185
{
164186
base::LockGuard<base::Mutex> guard(&lock_);
165187

166188
// Move delayed tasks that hit their deadline to the main queue.
167189
task = PopTaskInMainThreadDelayedQueue(isolate);
168190
while (task != NULL) {
169-
main_thread_queue_[isolate].push(task);
191+
ScheduleOnForegroundThread(isolate, task);
170192
task = PopTaskInMainThreadDelayedQueue(isolate);
171193
}
172194

173195
task = PopTaskInMainThreadQueue(isolate);
174196

175197
if (task == NULL) {
176-
return false;
198+
return behavior == MessageLoopBehavior::kWaitForWork;
177199
}
178200
}
179201
task->Run();
@@ -206,10 +228,17 @@ void DefaultPlatform::CallOnBackgroundThread(Task* task,
206228
queue_.Append(task);
207229
}
208230

231+
void DefaultPlatform::ScheduleOnForegroundThread(v8::Isolate* isolate,
232+
Task* task) {
233+
main_thread_queue_[isolate].push(task);
234+
if (event_loop_control_.count(isolate) != 0) {
235+
event_loop_control_[isolate]->Signal();
236+
}
237+
}
209238

210239
void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
211240
base::LockGuard<base::Mutex> guard(&lock_);
212-
main_thread_queue_[isolate].push(task);
241+
ScheduleOnForegroundThread(isolate, task);
213242
}
214243

215244

src/libplatform/default-platform.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ class V8_PLATFORM_EXPORT DefaultPlatform : public NON_EXPORTED_BASE(Platform) {
4141

4242
void EnsureInitialized();
4343

44-
bool PumpMessageLoop(v8::Isolate* isolate);
44+
bool PumpMessageLoop(
45+
v8::Isolate* isolate,
46+
MessageLoopBehavior behavior = MessageLoopBehavior::kDoNotWait);
47+
void EnsureEventLoopInitialized(v8::Isolate* isolate);
4548

4649
void RunIdleTasks(v8::Isolate* isolate, double idle_time_in_seconds);
4750

@@ -81,6 +84,9 @@ class V8_PLATFORM_EXPORT DefaultPlatform : public NON_EXPORTED_BASE(Platform) {
8184
Task* PopTaskInMainThreadDelayedQueue(v8::Isolate* isolate);
8285
IdleTask* PopTaskInMainThreadIdleQueue(v8::Isolate* isolate);
8386

87+
void WaitForForegroundWork(v8::Isolate* isolate);
88+
void ScheduleOnForegroundThread(v8::Isolate* isolate, Task* task);
89+
8490
base::Mutex lock_;
8591
bool initialized_;
8692
int thread_pool_size_;
@@ -89,6 +95,7 @@ class V8_PLATFORM_EXPORT DefaultPlatform : public NON_EXPORTED_BASE(Platform) {
8995
TaskQueue queue_;
9096
std::map<v8::Isolate*, std::queue<Task*>> main_thread_queue_;
9197
std::map<v8::Isolate*, std::queue<IdleTask*>> main_thread_idle_queue_;
98+
std::map<v8::Isolate*, std::unique_ptr<base::Semaphore>> event_loop_control_;
9299

93100
typedef std::pair<double, Task*> DelayedEntry;
94101
std::map<v8::Isolate*,

src/runtime/runtime-test.cc

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,15 +1019,5 @@ RUNTIME_FUNCTION(Runtime_RedirectToWasmInterpreter) {
10191019
return isolate->heap()->undefined_value();
10201020
}
10211021

1022-
RUNTIME_FUNCTION(Runtime_IncrementWaitCount) {
1023-
isolate->IncrementWaitCountForTesting();
1024-
return isolate->heap()->undefined_value();
1025-
}
1026-
1027-
RUNTIME_FUNCTION(Runtime_DecrementWaitCount) {
1028-
isolate->DecrementWaitCountForTesting();
1029-
return isolate->heap()->undefined_value();
1030-
}
1031-
10321022
} // namespace internal
10331023
} // namespace v8

src/runtime/runtime.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,9 +471,7 @@ namespace internal {
471471
F(PromiseRevokeReject, 1, 1) \
472472
F(PromiseResult, 1, 1) \
473473
F(PromiseStatus, 1, 1) \
474-
F(ReportPromiseReject, 2, 1) \
475-
F(IncrementWaitCount, 0, 1) \
476-
F(DecrementWaitCount, 0, 1)
474+
F(ReportPromiseReject, 2, 1)
477475

478476
#define FOR_EACH_INTRINSIC_PROXY(F) \
479477
F(IsJSProxy, 1, 1) \

test/debugger/debug/debug-stepin-accessor.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ function testProtoSetter1_2() {
233233
}
234234

235235
for (var n in this) {
236-
if (n.substr(0, 4) != 'test') {
236+
if (n.substr(0, 4) != 'test' ||
237+
n == 'testRunner') {
237238
continue;
238239
}
239240
state = 1;

test/mjsunit/basic-promise.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,14 @@
88
// exceptions which are swallowed in a then clause.
99
failWithMessage = (msg) => %AbortJS(msg);
1010

11-
let decrement = () => { %DecrementWaitCount(); }
12-
let increment = () => { %IncrementWaitCount(); }
13-
14-
function WaitForPromise(p) {
15-
increment();
16-
p.then(decrement, decrement);
17-
}
18-
1911
function newPromise() {
2012
var outerResolve;
2113
var outerReject;
2214
let promise = new Promise((resolve, reject) => {
2315
outerResolve = resolve;
2416
outerReject = reject;
2517
});
26-
WaitForPromise(promise); // explicitly wait for promise to resolve.
18+
Promise.resolve(promise);
2719
return {
2820
resolve: outerResolve,
2921
reject: outerReject,

0 commit comments

Comments
 (0)