Add filters and more events to Promise callback. (#4605)
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
@@ -908,6 +908,19 @@ Possible values:
|
||||
- JERRY_PROMISE_EVENT_REJECT - Called when a Promise is about to be rejected.
|
||||
- object - the Promise object
|
||||
- value - value for rejecting.
|
||||
- JERRY_PROMISE_EVENT_RESOLVE_FULFILLED - Called when a resolve is called on a fulfilled Promise.
|
||||
- object - the Promise object
|
||||
- value - value for resolving
|
||||
- JERRY_PROMISE_EVENT_REJECT_FULFILLED - Called when a reject is called on a fulfilled Promise.
|
||||
- object - the Promise object
|
||||
- value - value for rejecting
|
||||
- JERRY_PROMISE_EVENT_REJECT_WITHOUT_HANDLER - Called when a Promise is rejected without a handler.
|
||||
- object - the Promise object
|
||||
- value - value for rejecting
|
||||
- JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED - Called when a catch handler is added to a rejected
|
||||
Promise which did not have a catch handler before.
|
||||
- object - the Promise object
|
||||
- value - undefined
|
||||
- JERRY_PROMISE_EVENT_BEFORE_REACTION_JOB - Called before executing a Promise reaction job.
|
||||
- object - the Promise object
|
||||
- value - undefined
|
||||
@@ -938,6 +951,43 @@ Possible values:
|
||||
- [jerry_promise_set_callback](#jerry_promise_set_callback)
|
||||
|
||||
|
||||
## jerry_promise_event_filter_t
|
||||
|
||||
Filter types for [jerry_promise_set_callback](#jerry_promise_set_callback) callback function.
|
||||
The callback is only called for those events which are enabled by the filters. The events are
|
||||
described in [jerry_promise_event_type_t](#jerry_promise_event_type_t).
|
||||
|
||||
Possible values:
|
||||
|
||||
- JERRY_PROMISE_EVENT_FILTER_DISABLE - Disable reporting of all events.
|
||||
- JERRY_PROMISE_EVENT_FILTER_MAIN - Enables the following events:
|
||||
- JERRY_PROMISE_EVENT_CREATE
|
||||
- JERRY_PROMISE_EVENT_RESOLVE
|
||||
- JERRY_PROMISE_EVENT_REJECT
|
||||
- JERRY_PROMISE_EVENT_FILTER_ERROR - Enables the following events:
|
||||
- JERRY_PROMISE_EVENT_RESOLVE_FULFILLED
|
||||
- JERRY_PROMISE_EVENT_REJECT_FULFILLED
|
||||
- JERRY_PROMISE_EVENT_REJECT_WITHOUT_HANDLER
|
||||
- JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED
|
||||
- JERRY_PROMISE_EVENT_FILTER_REACTION_JOB - Enables the following events:
|
||||
- JERRY_PROMISE_EVENT_BEFORE_REACTION_JOB
|
||||
- JERRY_PROMISE_EVENT_AFTER_REACTION_JOB
|
||||
- JERRY_PROMISE_EVENT_FILTER_ASYNC_MAIN - Enables the following events:
|
||||
- JERRY_PROMISE_EVENT_ASYNC_AWAIT
|
||||
- JERRY_PROMISE_EVENT_FILTER_ASYNC_REACTION_JOB - Enables the following events:
|
||||
- JERRY_PROMISE_EVENT_ASYNC_BEFORE_RESOLVE
|
||||
- JERRY_PROMISE_EVENT_ASYNC_BEFORE_REJECT
|
||||
- JERRY_PROMISE_EVENT_ASYNC_AFTER_RESOLVE
|
||||
- JERRY_PROMISE_EVENT_ASYNC_AFTER_REJECT
|
||||
|
||||
*New in version [[NEXT_RELEASE]]*.
|
||||
|
||||
**See also**
|
||||
|
||||
- [jerry_promise_event_type_t](#jerry_promise_event_type_t)
|
||||
- [jerry_promise_set_callback](#jerry_promise_set_callback)
|
||||
|
||||
|
||||
## jerry_promise_callback_t
|
||||
|
||||
**Summary**
|
||||
@@ -4311,9 +4361,11 @@ Sets a callback for tracking Promise and async operations.
|
||||
**Prototype**
|
||||
|
||||
```c
|
||||
void jerry_promise_set_callback (jerry_promise_callback_t callback, void *user_p);
|
||||
void jerry_promise_set_callback (jerry_promise_event_filter_t filters, jerry_promise_callback_t callback,
|
||||
void *user_p);
|
||||
```
|
||||
|
||||
- `filters` - combination of [jerry_promise_event_filter_t](#jerry_promise_event_filter_t) options
|
||||
- `callback` - callback function, the previously set value is overwritten,
|
||||
and setting NULL disables the tracking
|
||||
- `user_p` - pointer passed to the callback function, can be NULL
|
||||
@@ -4351,7 +4403,7 @@ main (void)
|
||||
{
|
||||
jerry_init (JERRY_INIT_EMPTY);
|
||||
|
||||
jerry_promise_set_callback (promise_callback, NULL);
|
||||
jerry_promise_set_callback (JERRY_PROMISE_EVENT_FILTER_MAIN, promise_callback, NULL);
|
||||
|
||||
const char *source_p = "var p = Promise.resolve(0)\n"
|
||||
"p.then(function (v) { return v; })";
|
||||
|
||||
+10
-1
@@ -4358,15 +4358,24 @@ jerry_get_promise_state (const jerry_value_t promise) /**< promise object to get
|
||||
* Note:
|
||||
* the previous callback is overwritten
|
||||
*/
|
||||
void jerry_promise_set_callback (jerry_promise_callback_t callback, /**< notification callback */
|
||||
void jerry_promise_set_callback (jerry_promise_event_filter_t filters, /**< combination of event filters */
|
||||
jerry_promise_callback_t callback, /**< notification callback */
|
||||
void *user_p) /**< user pointer passed to the callback */
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
|
||||
#if JERRY_BUILTIN_PROMISE && JERRY_PROMISE_CALLBACK
|
||||
if (filters == JERRY_PROMISE_EVENT_FILTER_DISABLE || callback == NULL)
|
||||
{
|
||||
JERRY_CONTEXT (promise_callback_filters) = JERRY_PROMISE_EVENT_FILTER_DISABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
JERRY_CONTEXT (promise_callback_filters) = (uint32_t) filters;
|
||||
JERRY_CONTEXT (promise_callback) = callback;
|
||||
JERRY_CONTEXT (promise_callback_user_p) = user_p;
|
||||
#else /* !JERRY_BUILTIN_PROMISE && !JERRY_PROMISE_CALLBACK */
|
||||
JERRY_UNUSED (filters);
|
||||
JERRY_UNUSED (callback);
|
||||
JERRY_UNUSED (user_p);
|
||||
#endif /* JERRY_BUILTIN_PROMISE && JERRY_PROMISE_CALLBACK */
|
||||
|
||||
@@ -188,8 +188,9 @@ ecma_process_promise_reaction_job (ecma_job_promise_reaction_t *job_p) /**< the
|
||||
capability_p = (ecma_promise_capabality_t *) ecma_get_object_from_value (job_p->capability);
|
||||
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback) != NULL))
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_REACTION_JOB))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_BEFORE_REACTION_JOB,
|
||||
capability_p->header.u.class_prop.u.promise,
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
@@ -245,8 +246,9 @@ ecma_process_promise_reaction_job (ecma_job_promise_reaction_t *job_p) /**< the
|
||||
ecma_free_value (handler_result);
|
||||
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback) != NULL))
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_REACTION_JOB))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_AFTER_REACTION_JOB,
|
||||
capability_p->header.u.class_prop.u.promise,
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
@@ -269,7 +271,7 @@ static ecma_value_t
|
||||
ecma_process_promise_async_reaction_job (ecma_job_promise_async_reaction_t *job_p) /**< the job to be operated */
|
||||
{
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback) != NULL))
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_ASYNC_REACTION_JOB))
|
||||
{
|
||||
jerry_promise_event_type_t type = JERRY_PROMISE_EVENT_ASYNC_BEFORE_RESOLVE;
|
||||
|
||||
@@ -278,6 +280,7 @@ ecma_process_promise_async_reaction_job (ecma_job_promise_async_reaction_t *job_
|
||||
type = JERRY_PROMISE_EVENT_ASYNC_BEFORE_REJECT;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (type,
|
||||
job_p->executable_object,
|
||||
job_p->argument,
|
||||
@@ -370,7 +373,7 @@ ecma_process_promise_async_reaction_job (ecma_job_promise_async_reaction_t *job_
|
||||
free_job:
|
||||
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback) != NULL))
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_ASYNC_REACTION_JOB))
|
||||
{
|
||||
jerry_promise_event_type_t type = JERRY_PROMISE_EVENT_ASYNC_AFTER_RESOLVE;
|
||||
|
||||
@@ -379,6 +382,7 @@ free_job:
|
||||
type = JERRY_PROMISE_EVENT_ASYNC_AFTER_REJECT;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (type,
|
||||
job_p->executable_object,
|
||||
job_p->argument,
|
||||
|
||||
@@ -115,14 +115,18 @@ ecma_promise_set_state (ecma_object_t *obj_p, /**< points to promise object */
|
||||
* Take a collection of Reactions and enqueue a new PromiseReactionJob for each Reaction.
|
||||
*
|
||||
* See also: ES2015 25.4.1.8
|
||||
*
|
||||
* @return true - if JERRY_PROMISE_CALLBACK define is 1, and at least one handler is found
|
||||
* false - otherwise
|
||||
*/
|
||||
static void
|
||||
static bool
|
||||
ecma_promise_trigger_reactions (ecma_collection_t *reactions, /**< lists of reactions */
|
||||
ecma_value_t value, /**< value for resolve or reject */
|
||||
bool is_reject) /**< true if promise is rejected, false otherwise */
|
||||
{
|
||||
ecma_value_t *buffer_p = reactions->buffer_p;
|
||||
ecma_value_t *buffer_end_p = buffer_p + reactions->item_count;
|
||||
bool handler_found = false;
|
||||
|
||||
while (buffer_p < buffer_end_p)
|
||||
{
|
||||
@@ -133,6 +137,9 @@ ecma_promise_trigger_reactions (ecma_collection_t *reactions, /**< lists of reac
|
||||
if (JMEM_CP_GET_THIRD_BIT_FROM_POINTER_TAG (object_with_tag))
|
||||
{
|
||||
ecma_enqueue_promise_async_reaction_job (object, value, is_reject);
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
handler_found = true;
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -143,6 +150,9 @@ ecma_promise_trigger_reactions (ecma_collection_t *reactions, /**< lists of reac
|
||||
if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (object_with_tag))
|
||||
{
|
||||
handler = *buffer_p++;
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
handler_found = true;
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
}
|
||||
|
||||
ecma_enqueue_promise_reaction_job (object, handler, value);
|
||||
@@ -159,6 +169,9 @@ ecma_promise_trigger_reactions (ecma_collection_t *reactions, /**< lists of reac
|
||||
if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (object_with_tag))
|
||||
{
|
||||
handler = *buffer_p++;
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
handler_found = true;
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
}
|
||||
|
||||
ecma_enqueue_promise_reaction_job (object, handler, value);
|
||||
@@ -168,6 +181,8 @@ ecma_promise_trigger_reactions (ecma_collection_t *reactions, /**< lists of reac
|
||||
buffer_p++;
|
||||
}
|
||||
}
|
||||
|
||||
return handler_found;
|
||||
} /* ecma_promise_trigger_reactions */
|
||||
|
||||
/**
|
||||
@@ -212,8 +227,9 @@ ecma_reject_promise (ecma_value_t promise, /**< promise */
|
||||
JERRY_ASSERT (ecma_promise_get_flags (obj_p) & ECMA_PROMISE_IS_PENDING);
|
||||
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback) != NULL))
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_MAIN))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_REJECT,
|
||||
promise,
|
||||
reason,
|
||||
@@ -230,7 +246,23 @@ ecma_reject_promise (ecma_value_t promise, /**< promise */
|
||||
ecma_collection_t *reactions = promise_p->reactions;
|
||||
|
||||
/* Fulfill reactions will never be triggered. */
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (!ecma_promise_trigger_reactions (reactions, reason, true))
|
||||
{
|
||||
((ecma_extended_object_t *) obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_UNHANDLED_REJECT;
|
||||
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_ERROR))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_REJECT_WITHOUT_HANDLER,
|
||||
promise,
|
||||
reason,
|
||||
JERRY_CONTEXT (promise_callback_user_p));
|
||||
}
|
||||
}
|
||||
#else /* !JERRY_PROMISE_CALLBACK */
|
||||
ecma_promise_trigger_reactions (reactions, reason, true);
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
|
||||
promise_p->reactions = ecma_new_collection ();
|
||||
|
||||
@@ -283,8 +315,9 @@ ecma_fulfill_promise (ecma_value_t promise, /**< promise */
|
||||
}
|
||||
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback) != NULL))
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_MAIN))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_RESOLVE,
|
||||
promise,
|
||||
value,
|
||||
@@ -324,15 +357,27 @@ ecma_reject_promise_with_checks (ecma_value_t promise, /**< promise */
|
||||
JERRY_ASSERT (ecma_is_promise (promise_obj_p));
|
||||
|
||||
/* 3., 4. */
|
||||
if (!ecma_is_resolver_already_called (promise_obj_p))
|
||||
if (JERRY_UNLIKELY (ecma_is_resolver_already_called (promise_obj_p)))
|
||||
{
|
||||
/* 5. */
|
||||
((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_ALREADY_RESOLVED;
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_ERROR))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_REJECT_FULFILLED,
|
||||
promise,
|
||||
reason,
|
||||
JERRY_CONTEXT (promise_callback_user_p));
|
||||
}
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
|
||||
/* 6. */
|
||||
ecma_reject_promise (promise, reason);
|
||||
return ECMA_VALUE_UNDEFINED;
|
||||
}
|
||||
|
||||
/* 5. */
|
||||
((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_ALREADY_RESOLVED;
|
||||
|
||||
/* 6. */
|
||||
ecma_reject_promise (promise, reason);
|
||||
return ECMA_VALUE_UNDEFINED;
|
||||
} /* ecma_reject_promise_with_checks */
|
||||
|
||||
@@ -352,14 +397,26 @@ ecma_fulfill_promise_with_checks (ecma_value_t promise, /**< promise */
|
||||
JERRY_ASSERT (ecma_is_promise (promise_obj_p));
|
||||
|
||||
/* 3., 4. */
|
||||
if (!ecma_is_resolver_already_called (promise_obj_p))
|
||||
if (JERRY_UNLIKELY (ecma_is_resolver_already_called (promise_obj_p)))
|
||||
{
|
||||
/* 5. */
|
||||
((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_ALREADY_RESOLVED;
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_ERROR))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_RESOLVE_FULFILLED,
|
||||
promise,
|
||||
value,
|
||||
JERRY_CONTEXT (promise_callback_user_p));
|
||||
}
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
|
||||
ecma_fulfill_promise (promise, value);
|
||||
return ECMA_VALUE_UNDEFINED;
|
||||
}
|
||||
|
||||
/* 5. */
|
||||
((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_ALREADY_RESOLVED;
|
||||
|
||||
ecma_fulfill_promise (promise, value);
|
||||
return ECMA_VALUE_UNDEFINED;
|
||||
} /* ecma_fulfill_promise_with_checks */
|
||||
|
||||
@@ -490,8 +547,9 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function
|
||||
promise_object_p->reactions = reactions;
|
||||
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback) != NULL))
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_MAIN))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_CREATE,
|
||||
ecma_make_object_value (object_p),
|
||||
parent,
|
||||
@@ -886,6 +944,23 @@ ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' *
|
||||
ecma_track_promise_rejection (promise_obj_p, JERRY_PROMISE_REJECTION_OPERATION_HANDLE);
|
||||
ecma_enqueue_promise_reaction_job (ecma_make_object_value (result_capability_obj_p), on_rejected, reason);
|
||||
ecma_free_value (reason);
|
||||
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (on_rejected != ECMA_VALUE_FALSE
|
||||
&& ecma_promise_get_flags (promise_obj_p) & ECMA_PROMISE_UNHANDLED_REJECT)
|
||||
{
|
||||
promise_p->header.u.class_prop.extra_info &= (uint16_t) ~ECMA_PROMISE_UNHANDLED_REJECT;
|
||||
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_ERROR))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED,
|
||||
promise,
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
JERRY_CONTEXT (promise_callback_user_p));
|
||||
}
|
||||
}
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
}
|
||||
|
||||
/* ES11: 11. */
|
||||
@@ -1162,8 +1237,9 @@ ecma_promise_async_then (ecma_value_t promise, /**< promise object */
|
||||
ecma_value_t executable_object) /**< executable object of the async function */
|
||||
{
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback) != NULL))
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_ASYNC_MAIN))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_ASYNC_AWAIT,
|
||||
executable_object,
|
||||
promise,
|
||||
@@ -1187,6 +1263,22 @@ ecma_promise_async_then (ecma_value_t promise, /**< promise object */
|
||||
ecma_value_t value = ecma_promise_get_result (promise_obj_p);
|
||||
ecma_enqueue_promise_async_reaction_job (executable_object, value, !(flags & ECMA_PROMISE_IS_FULFILLED));
|
||||
ecma_free_value (value);
|
||||
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
if (ecma_promise_get_flags (promise_obj_p) & ECMA_PROMISE_UNHANDLED_REJECT)
|
||||
{
|
||||
((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info &= (uint16_t) ~ECMA_PROMISE_UNHANDLED_REJECT;
|
||||
|
||||
if (JERRY_UNLIKELY (JERRY_CONTEXT (promise_callback_filters) & JERRY_PROMISE_EVENT_FILTER_ERROR))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_CONTEXT (promise_callback) != NULL);
|
||||
JERRY_CONTEXT (promise_callback) (JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED,
|
||||
promise,
|
||||
ECMA_VALUE_UNDEFINED,
|
||||
JERRY_CONTEXT (promise_callback_user_p));
|
||||
}
|
||||
}
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
} /* ecma_promise_async_then */
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,6 +35,9 @@ typedef enum
|
||||
ECMA_PROMISE_IS_FULFILLED = (1 << 1), /**< fulfilled state */
|
||||
ECMA_PROMISE_ALREADY_RESOLVED = (1 << 2), /**< already resolved */
|
||||
ECMA_PROMISE_HANDLED = (1 << 3), /**< ES11: 25.6.6 [[PromiseIsHandled]] internal slot */
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
ECMA_PROMISE_UNHANDLED_REJECT = (1 << 4), /**< a Promise is rejected without a catch handler */
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
} ecma_promise_flags_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -766,6 +766,19 @@ typedef enum
|
||||
JERRY_PROMISE_EVENT_REJECT, /**< called when a Promise is about to be rejected
|
||||
* object: the Promise object
|
||||
* value: value for rejecting */
|
||||
JERRY_PROMISE_EVENT_RESOLVE_FULFILLED, /**< called when a resolve is called on a fulfilled Promise
|
||||
* object: the Promise object
|
||||
* value: value for resolving */
|
||||
JERRY_PROMISE_EVENT_REJECT_FULFILLED, /**< called when a reject is called on a fulfilled Promise
|
||||
* object: the Promise object
|
||||
* value: value for rejecting */
|
||||
JERRY_PROMISE_EVENT_REJECT_WITHOUT_HANDLER, /**< called when a Promise is rejected without a handler
|
||||
* object: the Promise object
|
||||
* value: value for rejecting */
|
||||
JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED, /**< called when a catch handler is added to a rejected
|
||||
* Promise which did not have a catch handler before
|
||||
* object: the Promise object
|
||||
* value: undefined */
|
||||
JERRY_PROMISE_EVENT_BEFORE_REACTION_JOB, /**< called before executing a Promise reaction job
|
||||
* object: the Promise object
|
||||
* value: undefined */
|
||||
@@ -789,6 +802,34 @@ typedef enum
|
||||
* value: value for rejecting */
|
||||
} jerry_promise_event_type_t;
|
||||
|
||||
/**
|
||||
* Filter types for jerry_promise_set_callback callback function.
|
||||
* The callback is only called for those events which are enabled by the filters.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
JERRY_PROMISE_EVENT_FILTER_DISABLE = 0, /**< disable reporting of all events */
|
||||
JERRY_PROMISE_EVENT_FILTER_MAIN = (1 << 0), /**< enables the following events:
|
||||
* JERRY_PROMISE_EVENT_CREATE
|
||||
* JERRY_PROMISE_EVENT_RESOLVE
|
||||
* JERRY_PROMISE_EVENT_REJECT */
|
||||
JERRY_PROMISE_EVENT_FILTER_ERROR = (1 << 1), /**< enables the following events:
|
||||
* JERRY_PROMISE_EVENT_RESOLVE_FULFILLED
|
||||
* JERRY_PROMISE_EVENT_REJECT_FULFILLED
|
||||
* JERRY_PROMISE_EVENT_REJECT_WITHOUT_HANDLER
|
||||
* JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED */
|
||||
JERRY_PROMISE_EVENT_FILTER_REACTION_JOB = (1 << 2), /**< enables the following events:
|
||||
* JERRY_PROMISE_EVENT_BEFORE_REACTION_JOB
|
||||
* JERRY_PROMISE_EVENT_AFTER_REACTION_JOB */
|
||||
JERRY_PROMISE_EVENT_FILTER_ASYNC_MAIN = (1 << 3), /**< enables the following events:
|
||||
* JERRY_PROMISE_EVENT_ASYNC_AWAIT */
|
||||
JERRY_PROMISE_EVENT_FILTER_ASYNC_REACTION_JOB = (1 << 4), /**< enables the following events:
|
||||
* JERRY_PROMISE_EVENT_ASYNC_BEFORE_RESOLVE
|
||||
* JERRY_PROMISE_EVENT_ASYNC_BEFORE_REJECT
|
||||
* JERRY_PROMISE_EVENT_ASYNC_AFTER_RESOLVE
|
||||
* JERRY_PROMISE_EVENT_ASYNC_AFTER_REJECT */
|
||||
} jerry_promise_event_filter_t;
|
||||
|
||||
/**
|
||||
* Notification callback for tracking Promise and async function operations.
|
||||
*/
|
||||
@@ -796,7 +837,8 @@ typedef void (*jerry_promise_callback_t) (jerry_promise_event_type_t event_type,
|
||||
const jerry_value_t object, const jerry_value_t value,
|
||||
void *user_p);
|
||||
|
||||
void jerry_promise_set_callback (jerry_promise_callback_t callback, void *user_p);
|
||||
void jerry_promise_set_callback (jerry_promise_event_filter_t filters, jerry_promise_callback_t callback,
|
||||
void *user_p);
|
||||
|
||||
/**
|
||||
* Symbol functions.
|
||||
|
||||
@@ -184,6 +184,7 @@ struct jerry_context_t
|
||||
ecma_job_queue_item_t *job_queue_head_p; /**< points to the head item of the job queue */
|
||||
ecma_job_queue_item_t *job_queue_tail_p; /**< points to the tail item of the job queue */
|
||||
#if JERRY_PROMISE_CALLBACK
|
||||
uint32_t promise_callback_filters; /**< reported event types for promise callback */
|
||||
void *promise_callback_user_p; /**< user pointer for promise callback */
|
||||
jerry_promise_callback_t promise_callback; /**< user function for tracking Promise object operations */
|
||||
#endif /* JERRY_PROMISE_CALLBACK */
|
||||
|
||||
@@ -23,6 +23,10 @@ typedef enum
|
||||
C = JERRY_PROMISE_EVENT_CREATE, /**< same as JERRY_PROMISE_CALLBACK_CREATE with undefined value */
|
||||
RS = JERRY_PROMISE_EVENT_RESOLVE, /**< same as JERRY_PROMISE_CALLBACK_RESOLVE */
|
||||
RJ = JERRY_PROMISE_EVENT_REJECT, /**< same as JERRY_PROMISE_CALLBACK_REJECT */
|
||||
RSF = JERRY_PROMISE_EVENT_RESOLVE_FULFILLED, /**< same as JERRY_PROMISE_EVENT_RESOLVE_FULFILLED */
|
||||
RJF = JERRY_PROMISE_EVENT_REJECT_FULFILLED, /**< same as JERRY_PROMISE_EVENT_REJECT_FULFILLED */
|
||||
RWH = JERRY_PROMISE_EVENT_REJECT_WITHOUT_HANDLER, /**< same as JERRY_PROMISE_EVENT_REJECT_WITHOUT_HANDLER */
|
||||
CHA = JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED, /**< same as JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED */
|
||||
BR = JERRY_PROMISE_EVENT_BEFORE_REACTION_JOB, /**< same as JERRY_PROMISE_CALLBACK_BEFORE_REACTION_JOB */
|
||||
AR = JERRY_PROMISE_EVENT_AFTER_REACTION_JOB, /**< same as JERRY_PROMISE_CALLBACK_AFTER_REACTION_JOB */
|
||||
A = JERRY_PROMISE_EVENT_ASYNC_AWAIT, /**< same as JERRY_PROMISE_CALLBACK_ASYNC_AWAIT */
|
||||
@@ -61,10 +65,14 @@ promise_callback (jerry_promise_event_type_t event_type, /**< event type */
|
||||
}
|
||||
case JERRY_PROMISE_EVENT_RESOLVE:
|
||||
case JERRY_PROMISE_EVENT_REJECT:
|
||||
case JERRY_PROMISE_EVENT_RESOLVE_FULFILLED:
|
||||
case JERRY_PROMISE_EVENT_REJECT_FULFILLED:
|
||||
case JERRY_PROMISE_EVENT_REJECT_WITHOUT_HANDLER:
|
||||
{
|
||||
TEST_ASSERT (jerry_value_is_promise (object));
|
||||
break;
|
||||
}
|
||||
case JERRY_PROMISE_EVENT_CATCH_HANDLER_ADDED:
|
||||
case JERRY_PROMISE_EVENT_BEFORE_REACTION_JOB:
|
||||
case JERRY_PROMISE_EVENT_AFTER_REACTION_JOB:
|
||||
{
|
||||
@@ -126,7 +134,13 @@ main (void)
|
||||
|
||||
jerry_init (JERRY_INIT_EMPTY);
|
||||
|
||||
jerry_promise_set_callback (promise_callback, (void *) &user);
|
||||
jerry_promise_event_filter_t filters = (JERRY_PROMISE_EVENT_FILTER_MAIN
|
||||
| JERRY_PROMISE_EVENT_FILTER_ERROR
|
||||
| JERRY_PROMISE_EVENT_FILTER_REACTION_JOB
|
||||
| JERRY_PROMISE_EVENT_FILTER_ASYNC_MAIN
|
||||
| JERRY_PROMISE_EVENT_FILTER_ASYNC_REACTION_JOB);
|
||||
|
||||
jerry_promise_set_callback (filters, promise_callback, (void *) &user);
|
||||
|
||||
/* Test promise creation. */
|
||||
static uint8_t events1[] = { C, C, C, E };
|
||||
@@ -155,7 +169,7 @@ main (void)
|
||||
"promise.then(() => {})\n");
|
||||
|
||||
/* Test resolve and reject calls. */
|
||||
static uint8_t events4[] = { C, C, RS, RJ, E };
|
||||
static uint8_t events4[] = { C, C, RS, RJ, RWH, E };
|
||||
|
||||
run_eval (events4,
|
||||
"'use strict'\n"
|
||||
@@ -191,10 +205,10 @@ main (void)
|
||||
"Promise.resolve(4).then(() => {})\n");
|
||||
|
||||
/* Test Promise.reject. */
|
||||
static uint8_t events8[] = { C, RJ, CP, BR, RJ, AR, E };
|
||||
static uint8_t events8[] = { C, RJ, RWH, CP, CHA, BR, RJ, RWH, AR, E };
|
||||
|
||||
run_eval (events8,
|
||||
"Promise.reject(4).then(() => {})\n");
|
||||
"Promise.reject(4).catch(() => { throw 'Error' })\n");
|
||||
|
||||
/* Test Promise.race without resolve */
|
||||
static uint8_t events9[] = { C, C, C, CP, CP, E };
|
||||
@@ -206,7 +220,7 @@ main (void)
|
||||
"Promise.race([p1,p2])\n");
|
||||
|
||||
/* Test Promise.race with resolve. */
|
||||
static uint8_t events10[] = { C, RS, C, RJ, C, CP, CP, BR, RS, RS, AR, BR, RS, AR, E };
|
||||
static uint8_t events10[] = { C, RS, C, RJ, RWH, C, CP, CP, CHA, BR, RS, RS, AR, BR, RJF, RS, AR, E };
|
||||
|
||||
run_eval (events10,
|
||||
"'use strict'\n"
|
||||
@@ -224,7 +238,7 @@ main (void)
|
||||
"Promise.all([p1,p2])\n");
|
||||
|
||||
/* Test Promise.all with resolve. */
|
||||
static uint8_t events12[] = { C, RS, C, RJ, C, CP, CP, BR, RS, AR, BR, RJ, RS, AR, E };
|
||||
static uint8_t events12[] = { C, RS, C, RJ, RWH, C, CP, CP, CHA, BR, RS, AR, BR, RJ, RWH, RS, AR, E };
|
||||
|
||||
run_eval (events12,
|
||||
"'use strict'\n"
|
||||
@@ -257,7 +271,7 @@ main (void)
|
||||
"f(Promise.resolve(1))\n");
|
||||
|
||||
/* Test await with rejected Promise. */
|
||||
static uint8_t events16[] = { C, RJ, A, C, BRJ, C, RS, RS, ARJ, E };
|
||||
static uint8_t events16[] = { C, RJ, RWH, A, CHA, C, BRJ, C, RS, RS, ARJ, E };
|
||||
|
||||
run_eval (events16,
|
||||
"'use strict'\n"
|
||||
@@ -281,6 +295,67 @@ main (void)
|
||||
"async function *g() { yield* f() }\n"
|
||||
"g().next()\n");
|
||||
|
||||
/* Test multiple fulfill operations. */
|
||||
static uint8_t events19[] = { C, RS, RSF, RJF, E };
|
||||
|
||||
run_eval (events19,
|
||||
"'use strict'\n"
|
||||
"var resolve, reject\n"
|
||||
"var p1 = new Promise((res, rej) => { resolve = res, reject = rej })\n"
|
||||
"resolve(1)\n"
|
||||
"resolve(2)\n"
|
||||
"reject(3)\n");
|
||||
|
||||
/* Test multiple fulfill operations. */
|
||||
static uint8_t events20[] = { C, RJ, RWH, RSF, RJF, E };
|
||||
|
||||
run_eval (events20,
|
||||
"'use strict'\n"
|
||||
"var resolve, reject\n"
|
||||
"var p1 = new Promise((res, rej) => { resolve = res, reject = rej })\n"
|
||||
"reject(1)\n"
|
||||
"resolve(2)\n"
|
||||
"reject(3)\n");
|
||||
|
||||
/* Test catch handler added later is reported only once. */
|
||||
static uint8_t events21[] = { C, RJ, RWH, CP, CHA, CP, CP, BR, RS, AR, BR, RS, AR, BR, RS, AR, E };
|
||||
|
||||
run_eval (events21,
|
||||
"'use strict'\n"
|
||||
"var rej = Promise.reject(4)\n"
|
||||
"rej.catch(() => {})\n"
|
||||
"rej.catch(() => {})\n"
|
||||
"rej.catch(() => {})\n");
|
||||
|
||||
/* Test catch handler added later is reported only once. */
|
||||
static uint8_t events22[] = { C, RJ, RWH, A, CHA, C, BRJ, A, ARJ, BRJ, RJ, RWH, ARJ, E };
|
||||
|
||||
run_eval (events22,
|
||||
"'use strict'\n"
|
||||
"async function f(p) { try { await p; } catch(e) { await p; } }"
|
||||
"f(Promise.reject(4))\n");
|
||||
|
||||
/* Test disabled filters. */
|
||||
jerry_promise_set_callback (JERRY_PROMISE_EVENT_FILTER_DISABLE, promise_callback, (void *) &user);
|
||||
|
||||
static uint8_t events23[] = { E };
|
||||
|
||||
run_eval (events23,
|
||||
"'use strict'\n"
|
||||
"async function f(p) { await p }"
|
||||
"f(Promise.resolve(1))\n");
|
||||
|
||||
/* Test filtered events. */
|
||||
filters = JERRY_PROMISE_EVENT_FILTER_REACTION_JOB | JERRY_PROMISE_EVENT_FILTER_ASYNC_REACTION_JOB;
|
||||
jerry_promise_set_callback (filters, promise_callback, (void *) &user);
|
||||
|
||||
static uint8_t events24[] = { BR, AR, BRS, ARS, E };
|
||||
|
||||
run_eval (events24,
|
||||
"'use strict'\n"
|
||||
"async function f(p) { await p }"
|
||||
"f(Promise.resolve(1).then(() => {}))\n");
|
||||
|
||||
jerry_cleanup ();
|
||||
return 0;
|
||||
} /* main */
|
||||
|
||||
Reference in New Issue
Block a user