240422.1 · 5c4cb3f889156fd378268063fb9fbc6ecd1617f9
Add support for JSI queue microtask (#9)
reading declarations
@@ -11,6 +11,8 @@ https://github.com/facebook/hermes repo. | Version | Commit Hash | Commit Description |--------:|:-------------------------------------------|------------------------------------------------------+| 12 | `de9dfe408bc3f8715aef161c5fcec291fc6dacb2` | Add queueMicrotask method to JSI+| | `a699e87f995bc2f7193990ff36a57ec9cad940e5` | Make queueMicrotask pure virtual | 11 | `a1c168705f609c8f1ae800c60d88eb199154264b` | Add JSI method for setting external memory size | 10 | `b81666598672cb5f8b365fe6548d3273f216322e` | Clarify const-ness of JSI references | 9 | `e6d887ae96bef5c71032f11ed1a9fb9fecec7b46` | Add external ArrayBuffers to JSI
@@ -126,6 +126,11 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { const std::shared_ptr<const PreparedJavaScript>& js) override { return plain().evaluatePreparedJavaScript(js); }+#if JSI_VERSION >= 12+ void queueMicrotask(const jsi::Function& callback) override {+ return plain().queueMicrotask(callback);+ }+#endif #if JSI_VERSION >= 4 bool drainMicrotasks(int maxMicrotasksHint) override { return plain().drainMicrotasks(maxMicrotasksHint);
@@ -30,7 +30,7 @@ // JSI version defines set of features available in the API. // Each significant API change must be under a new version. #ifndef JSI_VERSION-#define JSI_VERSION 11+#define JSI_VERSION 12 #endif #if JSI_VERSION >= 3@@ -233,6 +233,14 @@ class JSI_EXPORT Runtime { virtual Value evaluatePreparedJavaScript( const std::shared_ptr<const PreparedJavaScript>& js) = 0; +#if JSI_VERSION >= 12+ /// Queues a microtask in the JavaScript VM internal Microtask (a.k.a. Job in+ /// ECMA262) queue, to be executed when the host drains microtasks in+ /// its event loop implementation.+ ///+ /// \param callback a function to be executed as a microtask.+ virtual void queueMicrotask(const jsi::Function& callback) = 0;+#endif #if JSI_VERSION >= 4 /// Drain the JavaScript VM internal Microtask (a.k.a. Job in ECMA262) queue. ///
@@ -1358,6 +1358,40 @@ TEST_P(JSITest, JSErrorTest) { JSIException); } +#if defined(JSI_SUPPORT_MICROTASKS) && JSI_VERSION >= 12+TEST_P(JSITest, MicrotasksTest) {+ try {+ rt.global().setProperty(rt, "globalValue", String::createFromAscii(rt, ""));++ auto microtask1 =+ function("function microtask1() { globalValue += 'hello'; }");+ auto microtask2 =+ function("function microtask2() { globalValue += ' world' }");++ rt.queueMicrotask(microtask1);+ rt.queueMicrotask(microtask2);++ EXPECT_EQ(+ rt.global().getProperty(rt, "globalValue").asString(rt).utf8(rt), "");++ rt.drainMicrotasks();++ EXPECT_EQ(+ rt.global().getProperty(rt, "globalValue").asString(rt).utf8(rt),+ "hello world");++ // Microtasks shouldn't run again+ rt.drainMicrotasks();++ EXPECT_EQ(+ rt.global().getProperty(rt, "globalValue").asString(rt).utf8(rt),+ "hello world");+ } catch (const JSINativeException& ex) {+ // queueMicrotask() is unimplemented by some runtimes, ignore such failures.+ }+}+#endif+ //---------------------------------------------------------------------- // Test that multiple levels of delegation in DecoratedHostObjects works.
@@ -127,6 +127,10 @@ JSR_API jsr_close_napi_env_scope(napi_env env, jsr_napi_env_scope scope); // To implement JSI description() JSR_API jsr_get_description(napi_env env, const char** result); +// To implement JSI queueMicrotask()+JSR_API+jsr_queue_microtask(napi_env env, napi_value callback);+ // To implement JSI drainMicrotasks() JSR_API jsr_drain_microtasks(napi_env env, int32_t max_count_hint, bool* result);
src/ApiLoaders/JSRuntimeApi.cpp
@@ -9,6 +9,7 @@ EXTERN_C_START extern napi_status NAPI_CDECL default_jsr_open_napi_env_scope(napi_env env, jsr_napi_env_scope *scope); extern napi_status NAPI_CDECL default_jsr_close_napi_env_scope(napi_env env, jsr_napi_env_scope scope); extern napi_status NAPI_CDECL default_jsr_get_description(napi_env env, const char **result);+extern napi_status NAPI_CDECL default_jsr_queue_microtask(napi_env env, napi_value callback); extern napi_status NAPI_CDECL default_jsr_drain_microtasks(napi_env env, int32_t max_count_hint, bool *result); extern napi_status NAPI_CDECL default_jsr_is_inspectable(napi_env env, bool *result);
src/ApiLoaders/JSRuntimeApi.inc
@@ -33,6 +33,7 @@ JSR_FUNC(jsr_runtime_get_node_api_env) // The JS runtime functions needed for JSI. JSR_JSI_FUNC(jsr_close_napi_env_scope)+JSR_JSI_FUNC(jsr_queue_microtask) JSR_JSI_FUNC(jsr_drain_microtasks) JSR_JSI_FUNC(jsr_get_description) JSR_JSI_FUNC(jsr_is_inspectable)
@@ -188,6 +188,9 @@ class NodeApiJsiRuntime : public jsi::Runtime { const std::shared_ptr<const jsi::Buffer> &buffer, std::string sourceURL) override; jsi::Value evaluatePreparedJavaScript(const std::shared_ptr<const jsi::PreparedJavaScript> &js) override;+#if JSI_VERSION >= 12+ void queueMicrotask(const jsi::Function& callback) override;+#endif #if JSI_VERSION >= 4 bool drainMicrotasks(int maxMicrotasksHint = -1) override; #endif@@ -940,6 +943,14 @@ jsi::Value NodeApiJsiRuntime::evaluatePreparedJavaScript(const std::shared_ptr<c return toJsiValue(result); } +#if JSI_VERSION >= 12+void NodeApiJsiRuntime::queueMicrotask(const jsi::Function& callback) {+ NodeApiScope scope{*this};+ napi_value callbackValue = getNodeApiValue(callback);+ CHECK_NAPI(jsrApi_->jsr_queue_microtask(env_, callbackValue));+}+#endif+ #if JSI_VERSION >= 4 bool NodeApiJsiRuntime::drainMicrotasks(int maxMicrotasksHint) { bool result{};@@ -1573,7 +1584,7 @@ bool NodeApiJsiRuntime::instanceOf(const jsi::Object &obj, const jsi::Function & } #if JSI_VERSION >= 11-void NodeApiJsiRuntime::setExternalMemoryPressure(const jsi::Object &/*obj*/, size_t /*amount*/) {+void NodeApiJsiRuntime::setExternalMemoryPressure(const jsi::Object & /*obj*/, size_t /*amount*/) { // TODO: implement } #endif@@ -2803,8 +2814,14 @@ napi_status NAPI_CDECL default_jsr_get_description(napi_env /*env*/, const char return napi_ok; } +// Default implementation of jsr_queue_microtask if it is not provided by JS engine.+// It does nothing.+napi_status NAPI_CDECL default_jsr_queue_microtask(napi_env /*env*/, napi_value /*callback*/) {+ return napi_generic_failure;+}+ // Default implementation of jsr_drain_microtasks if it is not provided by JS engine.-// It does nothing+// It does nothing. napi_status NAPI_CDECL default_jsr_drain_microtasks(napi_env /*env*/, int32_t /*max_count_hint*/, bool *result) { if (result != nullptr) { *result = true; // All tasks are drained