Skip to content

Commit 643f17d

Browse files
committed
add JS promise test, fix possible bugs in event loop handling
1 parent 4532e91 commit 643f17d

File tree

7 files changed

+66
-23
lines changed

7 files changed

+66
-23
lines changed

backend/QuickJs/QjsEngine.cc

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,10 @@ void QjsEngine::destroy() noexcept {
191191
delete this;
192192
}
193193

194-
void QjsEngine::scheduleTick() {
194+
void QjsEngine::triggerTick() {
195195
bool no = false;
196-
if (tickScheduled_.compare_exchange_strong(no, true)) {
196+
if (!isDestroying() && JS_IsJobPending(runtime_) &&
197+
tickScheduled_.compare_exchange_strong(no, true)) {
197198
utils::Message tick(
198199
[](auto& m) {
199200
auto eng = static_cast<QjsEngine*>(m.ptr0);
@@ -203,9 +204,7 @@ void QjsEngine::scheduleTick() {
203204
}
204205
eng->tickScheduled_ = false;
205206
},
206-
[](auto& m) {
207-
208-
});
207+
nullptr);
209208
tick.ptr0 = this;
210209
tick.tag = this;
211210
queue_->postMessage(tick);
@@ -263,7 +262,7 @@ Local<Value> QjsEngine::eval(const Local<String>& script, const Local<Value>& so
263262
}
264263
qjs_backend::checkException(ret);
265264

266-
scheduleTick();
265+
triggerTick();
267266

268267
return Local<Value>(ret);
269268
}

backend/QuickJs/QjsEngine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class QjsEngine : public ScriptEngine {
140140
/**
141141
* similar to js_std_loop
142142
*/
143-
void scheduleTick();
143+
void triggerTick();
144144

145145
void extendLifeTimeToNextLoop(JSValue value);
146146

backend/QuickJs/QjsLocalReference.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ Local<Value> Local<Function>::callImpl(const Local<Value>& thiz, size_t size,
332332
qjs_backend::checkException(ret);
333333
});
334334

335-
engine.scheduleTick();
335+
engine.triggerTick();
336336
return qjs_interop::makeLocal<Value>(ret);
337337
}
338338

backend/QuickJs/QjsScope.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ EngineScopeImpl::EngineScopeImpl(QjsEngine &current, QjsEngine *prev)
3030
}
3131

3232
EngineScopeImpl::~EngineScopeImpl() {
33+
current_->triggerTick();
3334
current_->runtimeLock_.unlock();
3435
if (previous_) {
3536
previous_->runtimeLock_.lock();

backend/QuickJs/QjsValue.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Local<Object> Object::newObjectImpl(const Local<Value>& type, size_t size,
4747
qjs_backend::checkException(ret);
4848
});
4949

50-
engine.scheduleTick();
50+
engine.triggerTick();
5151
return qjs_interop::makeLocal<Object>(ret);
5252
}
5353

backend/V8/V8Platform.cc

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,21 @@ class MessageQueueTaskRunner : public v8::TaskRunner {
102102

103103
private:
104104
void scheduleTask(std::unique_ptr<v8::Task> task, double delay_in_seconds = 0) {
105-
script::utils::Message s([](auto& msg) { static_cast<v8::Task*>(msg.ptr0)->Run(); },
106-
[](auto& msg) {
107-
using deleter = std::unique_ptr<v8::Task>::deleter_type;
108-
deleter{}(static_cast<v8::Task*>(msg.ptr0));
109-
});
105+
script::utils::Message s(
106+
[](auto& msg) {
107+
auto engine = static_cast<V8Engine*>(msg.tag);
108+
EngineScope scope(engine);
109+
try {
110+
static_cast<v8::Task*>(msg.ptr0)->Run();
111+
} catch (const Exception& e) {
112+
// this should not happen, all JS exceptions should be handled by V8
113+
abort();
114+
}
115+
},
116+
[](auto& msg) {
117+
using deleter = std::unique_ptr<v8::Task>::deleter_type;
118+
deleter{}(static_cast<v8::Task*>(msg.ptr0));
119+
});
110120
s.name = "SchedulePump";
111121
s.ptr0 = task.release();
112122
s.tag = engine_;

test/src/EngineTest.cc

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -137,24 +137,57 @@ TEST_F(EngineTest, LuaBuiltIns) {
137137
TEST_F(EngineTest, JsPromiseTest) {
138138
EngineScope scope(engine);
139139

140-
int value = 0;
141-
auto setValue = Function::newFunction([&value](int val) { value = val; });
142-
engine->set("setValue", setValue);
143-
engine->eval(
144-
u8R"(
145-
const promise = new Promise((resolve, reject) => {
140+
int value = -1;
141+
try {
142+
auto setValue = Function::newFunction([&value](int val) { value = val; });
143+
engine->set("setValue", setValue);
144+
engine->eval(
145+
u8R"(
146+
new Promise((resolve, reject) => {
147+
resolve(0);
148+
}).then(() => {
149+
setValue(0);
150+
new Promise((resolve, reject) => {
146151
resolve(1);
147-
});
148-
149-
promise.then(num => {
152+
}).then(num => {
150153
setValue(num);
154+
});
151155
});
152156
)");
157+
} catch (const Exception& e) {
158+
FAIL() << e;
159+
}
153160

154161
engine->messageQueue()->shutdown(true);
155162
engine->messageQueue()->loopQueue(utils::MessageQueue::LoopType::kLoopAndWait);
156163
EXPECT_EQ(value, 1);
157164
}
165+
166+
TEST_F(EngineTest, JsPromiseTest2) {
167+
EngineScope scope(engine);
168+
169+
int value = -1;
170+
try {
171+
auto setValue = Function::newFunction([&value](int val) { value = val; });
172+
engine->set("setValue", setValue);
173+
engine->eval(
174+
u8R"(
175+
new Promise((resolve, reject) => {
176+
resolve(0);
177+
}).then(() => {
178+
setValue(0);
179+
throw error();
180+
setValue(1);
181+
});
182+
)");
183+
} catch (const Exception& e) {
184+
FAIL() << e;
185+
}
186+
187+
engine->messageQueue()->shutdown(true);
188+
engine->messageQueue()->loopQueue(utils::MessageQueue::LoopType::kLoopAndWait);
189+
EXPECT_EQ(value, 0);
190+
}
158191
#endif
159192

160193
} // namespace script::test

0 commit comments

Comments
 (0)