Rework promise internal structures (#3985)

- Capabilities
- Promise all resolver

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
This commit is contained in:
Robert Fancsik
2020-07-10 16:08:34 +02:00
committed by GitHub
parent dfabfe7a56
commit 37906baa25
7 changed files with 308 additions and 390 deletions
+43
View File
@@ -633,6 +633,24 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
ecma_gc_mark_executable_object (object_p); ecma_gc_mark_executable_object (object_p);
break; break;
} }
case LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY:
{
ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) object_p;
if (ecma_is_value_object (capability_p->header.u.class_prop.u.promise))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (capability_p->header.u.class_prop.u.promise));
}
if (ecma_is_value_object (capability_p->resolve))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (capability_p->resolve));
}
if (ecma_is_value_object (capability_p->reject))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (capability_p->reject));
}
break;
}
#endif /* ENABLED (JERRY_ESNEXT) */ #endif /* ENABLED (JERRY_ESNEXT) */
default: default:
{ {
@@ -765,6 +783,18 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
ecma_gc_set_object_visited (ecma_get_object_from_value (rev_proxy_p->proxy)); ecma_gc_set_object_visited (ecma_get_object_from_value (rev_proxy_p->proxy));
} }
} }
else if (ext_func_p->u.external_handler_cb == ecma_op_get_capabilities_executor_cb)
{
ecma_promise_capability_executor_t *executor_p = (ecma_promise_capability_executor_t *) object_p;
ecma_gc_set_object_visited (ecma_get_object_from_value (executor_p->capability));
}
else if (ext_func_p->u.external_handler_cb == ecma_promise_all_handler_cb)
{
ecma_promise_all_executor_t *executor_p = (ecma_promise_all_executor_t *) object_p;
ecma_gc_set_object_visited (ecma_get_object_from_value (executor_p->capability));
ecma_gc_set_object_visited (ecma_get_object_from_value (executor_p->values));
ecma_gc_set_object_visited (ecma_get_object_from_value (executor_p->remaining_elements));
}
break; break;
} }
#endif /* ENABLED (JERRY_ESNEXT) */ #endif /* ENABLED (JERRY_ESNEXT) */
@@ -1124,6 +1154,14 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
{ {
ext_object_size = sizeof (ecma_revocable_proxy_object_t); ext_object_size = sizeof (ecma_revocable_proxy_object_t);
} }
else if (ext_func_p->u.external_handler_cb == ecma_op_get_capabilities_executor_cb)
{
ext_object_size = sizeof (ecma_promise_capability_executor_t);
}
else if (ext_func_p->u.external_handler_cb == ecma_promise_all_handler_cb)
{
ext_object_size = sizeof (ecma_promise_all_executor_t);
}
#endif /* ENABLED (JERRY_ESNEXT) */ #endif /* ENABLED (JERRY_ESNEXT) */
break; break;
} }
@@ -1234,6 +1272,11 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
ext_object_size = ecma_gc_free_executable_object (object_p); ext_object_size = ecma_gc_free_executable_object (object_p);
break; break;
} }
case LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY:
{
ext_object_size = sizeof (ecma_promise_capabality_t);
break;
}
#endif /* ENABLED (JERRY_ESNEXT) */ #endif /* ENABLED (JERRY_ESNEXT) */
default: default:
{ {
+34
View File
@@ -880,6 +880,7 @@ typedef struct
uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */ uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */
ecma_value_t target; /**< [[ProxyTarget]] internal property */ ecma_value_t target; /**< [[ProxyTarget]] internal property */
ecma_value_t head; /**< points to the async generator task queue head item */ ecma_value_t head; /**< points to the async generator task queue head item */
ecma_value_t promise; /**< PromiseCapability[[Promise]] internal slot */
} u; } u;
} class_prop; } class_prop;
@@ -1933,6 +1934,39 @@ typedef struct
uint8_t operation_type; /**< type of operation (see ecma_async_generator_operation_type_t) */ uint8_t operation_type; /**< type of operation (see ecma_async_generator_operation_type_t) */
} ecma_async_generator_task_t; } ecma_async_generator_task_t;
/**
* Definition of PromiseCapability Records
*/
typedef struct
{
ecma_extended_object_t header; /**< object header, and [[Promise]] internal slot */
ecma_value_t resolve; /**< [[Resolve]] internal slot */
ecma_value_t reject; /**< [[Reject]] internal slot */
} ecma_promise_capabality_t;
/**
* Definition of GetCapabilitiesExecutor Functions
*/
typedef struct
{
ecma_extended_object_t header; /**< object header */
ecma_value_t capability; /**< [[Capability]] internal slot */
} ecma_promise_capability_executor_t;
/**
* Definition of Promise.all Resolve Element Functions
*/
typedef struct
{
ecma_extended_object_t header; /**< object header */
ecma_value_t remaining_elements; /**< [[Remaining elements]] internal slot */
ecma_value_t capability; /**< [[Capabilities]] internal slot */
ecma_value_t values; /**< [[Values]] internal slot */
uint32_t index; /**< [[Index]] and [[AlreadyCalled]] internal slot
* 0 - if the element has been resolved
* real index + 1 in the [[Values]] list - otherwise */
} ecma_promise_all_executor_t;
#endif /* ENABLED (JERRY_ESNEXT) */ #endif /* ENABLED (JERRY_ESNEXT) */
#if ENABLED (JERRY_BUILTIN_DATAVIEW) #if ENABLED (JERRY_BUILTIN_DATAVIEW)
@@ -13,6 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
#include "ecma-alloc.h"
#include "ecma-array-object.h" #include "ecma-array-object.h"
#include "ecma-builtin-helpers.h" #include "ecma-builtin-helpers.h"
#include "ecma-exceptions.h" #include "ecma-exceptions.h"
@@ -54,22 +55,22 @@
*/ */
inline static ecma_value_t inline static ecma_value_t
ecma_builtin_promise_reject_abrupt (ecma_value_t value, /**< value */ ecma_builtin_promise_reject_abrupt (ecma_value_t value, /**< value */
ecma_value_t capability) /**< capability */ ecma_object_t *capability_obj_p) /**< capability */
{ {
JERRY_ASSERT (ecma_object_class_is (capability_obj_p, LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY));
if (!ECMA_IS_VALUE_ERROR (value)) if (!ECMA_IS_VALUE_ERROR (value))
{ {
return value; return value;
} }
ecma_value_t reason = jcontext_take_exception (); ecma_value_t reason = jcontext_take_exception ();
ecma_value_t reject = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (capability),
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (reject), ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) capability_obj_p;
ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (capability_p->reject),
ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED,
&reason, &reason,
1); 1);
ecma_free_value (reject);
ecma_free_value (reason); ecma_free_value (reason);
if (ECMA_IS_VALUE_ERROR (call_ret)) if (ECMA_IS_VALUE_ERROR (call_ret))
@@ -79,8 +80,7 @@ ecma_builtin_promise_reject_abrupt (ecma_value_t value, /**< value */
ecma_free_value (call_ret); ecma_free_value (call_ret);
return ecma_op_object_get_by_magic_id (ecma_get_object_from_value (capability), return ecma_copy_value (capability_p->header.u.class_prop.u.promise);
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
} /* ecma_builtin_promise_reject_abrupt */ } /* ecma_builtin_promise_reject_abrupt */
/** /**
@@ -127,14 +127,15 @@ ecma_builtin_promise_resolve (ecma_value_t this_arg, /**< 'this' argument */
inline static ecma_value_t inline static ecma_value_t
ecma_builtin_promise_perform_race (ecma_value_t iterator, /**< the iterator for race */ ecma_builtin_promise_perform_race (ecma_value_t iterator, /**< the iterator for race */
ecma_value_t next_method, /**< next method */ ecma_value_t next_method, /**< next method */
ecma_value_t capability, /**< PromiseCapability record */ ecma_object_t *capability_obj_p, /**< PromiseCapability record */
ecma_value_t ctor, /**< Constructor value */ ecma_value_t ctor, /**< Constructor value */
bool *done_p) /**< [out] iteratorRecord[[done]] */ bool *done_p) /**< [out] iteratorRecord[[done]] */
{ {
JERRY_ASSERT (ecma_is_value_object (iterator) JERRY_ASSERT (ecma_is_value_object (iterator));
&& ecma_is_value_object (capability)); JERRY_ASSERT (ecma_object_class_is (capability_obj_p, LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY));
ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) capability_obj_p;
ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability);
/* 1. */ /* 1. */
while (true) while (true)
{ {
@@ -153,7 +154,7 @@ ecma_builtin_promise_perform_race (ecma_value_t iterator, /**< the iterator for
/* i. */ /* i. */
*done_p = true; *done_p = true;
/* ii. */ /* ii. */
return ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); return ecma_copy_value (capability_p->header.u.class_prop.u.promise);
} }
/* e. */ /* e. */
@@ -178,17 +179,10 @@ ecma_builtin_promise_perform_race (ecma_value_t iterator, /**< the iterator for
} }
/* j. */ /* j. */
ecma_value_t args[2]; ecma_value_t args[2] = {capability_p->resolve, capability_p->reject};
args[0] = ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
args[1] = ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
ecma_value_t result = ecma_op_invoke_by_magic_id (next_promise, LIT_MAGIC_STRING_THEN, args, 2); ecma_value_t result = ecma_op_invoke_by_magic_id (next_promise, LIT_MAGIC_STRING_THEN, args, 2);
ecma_free_value (next_promise); ecma_free_value (next_promise);
for (uint8_t i = 0; i < 2; i++)
{
ecma_free_value (args[i]);
}
/* k. */ /* k. */
if (ECMA_IS_VALUE_ERROR (result)) if (ECMA_IS_VALUE_ERROR (result))
{ {
@@ -201,116 +195,6 @@ ecma_builtin_promise_perform_race (ecma_value_t iterator, /**< the iterator for
JERRY_UNREACHABLE (); JERRY_UNREACHABLE ();
} /* ecma_builtin_promise_perform_race */ } /* ecma_builtin_promise_perform_race */
/**
* Helper function for increase or decrease the remaining count.
*
* @return the current remaining count after increase or decrease.
*/
static ecma_length_t
ecma_builtin_promise_remaining_inc_or_dec (ecma_value_t remaining, /**< the remaining count */
bool is_inc) /**< whether to increase the count */
{
JERRY_ASSERT (ecma_is_value_object (remaining));
ecma_object_t *remaining_p = ecma_get_object_from_value (remaining);
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) remaining_p;
JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_NUMBER_UL);
JERRY_ASSERT (ecma_is_value_integer_number (ext_object_p->u.class_prop.u.value));
ecma_length_t current = (ecma_length_t) ecma_get_integer_from_value (ext_object_p->u.class_prop.u.value);
if (is_inc)
{
current++;
}
else
{
current--;
}
ext_object_p->u.class_prop.u.value = ecma_make_uint32_value (current);
return current;
} /* ecma_builtin_promise_remaining_inc_or_dec */
/**
* Native handler for Promise.all Resolve Element Function.
*
* See also:
* ES2015 25.4.4.1.2
*
* @return ecma value of undefined.
*/
static ecma_value_t
ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function itself */
const ecma_value_t this, /**< this_arg of the function */
const ecma_value_t argv[], /**< argument list */
const ecma_length_t argc) /**< argument number */
{
JERRY_UNUSED (this);
JERRY_UNUSED (argc);
/* 1. */
ecma_object_t *function_p = ecma_get_object_from_value (function);
ecma_string_t *already_called_str_p;
already_called_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_ALREADY_CALLED);
ecma_value_t already_called = ecma_op_object_get (function_p, already_called_str_p);
JERRY_ASSERT (ecma_is_value_boolean (already_called));
/* 2. */
if (ecma_is_value_true (already_called))
{
return ECMA_VALUE_UNDEFINED;
}
/* 3. */
ecma_op_object_put (function_p,
already_called_str_p,
ECMA_VALUE_TRUE,
false);
ecma_string_t *str_index_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_INDEX);
ecma_string_t *str_value_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_VALUE);
ecma_string_t *str_capability_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
ecma_string_t *str_remaining_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT);
/* 4-7. */
ecma_value_t index_val = ecma_op_object_get (function_p, str_index_p);
ecma_value_t values_array = ecma_op_object_get (function_p, str_value_p);
ecma_value_t capability = ecma_op_object_get (function_p, str_capability_p);
ecma_value_t remaining = ecma_op_object_get (function_p, str_remaining_p);
JERRY_ASSERT (ecma_is_value_integer_number (index_val));
/* 8. */
ecma_op_object_put_by_uint32_index (ecma_get_object_from_value (values_array),
(uint32_t) ecma_get_integer_from_value (index_val),
argv[0],
false);
/* 9-10. */
ecma_value_t ret = ECMA_VALUE_UNDEFINED;
if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0)
{
ecma_value_t resolve = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (capability),
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
ret = ecma_op_function_call (ecma_get_object_from_value (resolve),
ECMA_VALUE_UNDEFINED,
&values_array,
1);
ecma_free_value (resolve);
}
ecma_free_value (remaining);
ecma_free_value (capability);
ecma_free_value (values_array);
ecma_free_value (index_val);
return ret;
} /* ecma_builtin_promise_all_handler */
/** /**
* Runtime Semantics: PerformPromiseAll. * Runtime Semantics: PerformPromiseAll.
* *
@@ -323,12 +207,15 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function
inline static ecma_value_t inline static ecma_value_t
ecma_builtin_promise_perform_all (ecma_value_t iterator, /**< iteratorRecord */ ecma_builtin_promise_perform_all (ecma_value_t iterator, /**< iteratorRecord */
ecma_value_t next_method, /**< next method */ ecma_value_t next_method, /**< next method */
ecma_value_t capability, /**< PromiseCapability record */ ecma_object_t *capability_obj_p, /**< PromiseCapability record */
ecma_value_t ctor, /**< the caller of Promise.race */ ecma_value_t ctor, /**< the caller of Promise.race */
bool *done_p) /**< [out] iteratorRecord[[done]] */ bool *done_p) /**< [out] iteratorRecord[[done]] */
{ {
/* 1. - 2. */ /* 1. - 2. */
JERRY_ASSERT (ecma_is_value_object (capability) && ecma_is_constructor (ctor)); JERRY_ASSERT (ecma_object_class_is (capability_obj_p, LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY));
JERRY_ASSERT (ecma_is_constructor (ctor));
ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) capability_obj_p;
/* 3. */ /* 3. */
ecma_object_t *values_array_obj_p = ecma_op_new_fast_array_object (0); ecma_object_t *values_array_obj_p = ecma_op_new_fast_array_object (0);
@@ -339,14 +226,6 @@ ecma_builtin_promise_perform_all (ecma_value_t iterator, /**< iteratorRecord */
uint32_t idx = 0; uint32_t idx = 0;
ecma_value_t ret_value = ECMA_VALUE_ERROR; ecma_value_t ret_value = ECMA_VALUE_ERROR;
ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability);
ecma_string_t *already_called_str_p;
already_called_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_ALREADY_CALLED);
ecma_string_t *index_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_INDEX);
ecma_string_t *value_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_VALUE);
ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
ecma_string_t *remaining_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT);
/* 6. */ /* 6. */
while (true) while (true)
@@ -367,17 +246,13 @@ ecma_builtin_promise_perform_all (ecma_value_t iterator, /**< iteratorRecord */
*done_p = true; *done_p = true;
/* ii. - iii. */ /* ii. - iii. */
if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0) if (ecma_promise_remaining_inc_or_dec (remaining, false) == 0)
{ {
/* 2. */ /* 2. */
ecma_value_t resolve = ecma_op_object_get_by_magic_id (capability_obj_p, ecma_value_t resolve_result = ecma_op_function_call (ecma_get_object_from_value (capability_p->resolve),
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
ecma_value_t resolve_result = ecma_op_function_call (ecma_get_object_from_value (resolve),
ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED,
&values_array, &values_array,
1); 1);
ecma_free_value (resolve);
/* 3. */ /* 3. */
if (ECMA_IS_VALUE_ERROR (resolve_result)) if (ECMA_IS_VALUE_ERROR (resolve_result))
{ {
@@ -388,8 +263,7 @@ ecma_builtin_promise_perform_all (ecma_value_t iterator, /**< iteratorRecord */
} }
/* iv. */ /* iv. */
ret_value = ecma_op_object_get_by_magic_id (capability_obj_p, ret_value = ecma_copy_value (capability_p->header.u.class_prop.u.promise);
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
break; break;
} }
@@ -421,52 +295,43 @@ ecma_builtin_promise_perform_all (ecma_value_t iterator, /**< iteratorRecord */
} }
/* k. */ /* k. */
ecma_object_t *res_ele_p; ecma_object_t *executor_func_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE),
res_ele_p = ecma_op_create_external_function_object (ecma_builtin_promise_all_handler); sizeof (ecma_promise_all_executor_t),
ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
ecma_promise_all_executor_t *executor_p = (ecma_promise_all_executor_t *) executor_func_p;
executor_p->header.u.external_handler_cb = ecma_promise_all_handler_cb;
/* l. */ /* l. */
ecma_op_object_put (res_ele_p, if (JERRY_UNLIKELY (idx == UINT32_MAX - 1))
already_called_str_p, {
ECMA_VALUE_FALSE, ecma_deref_object (executor_func_p);
false); ecma_raise_range_error (ECMA_ERR_MSG ("Promise.all remaining elements limit reached."));
/* m. */ break;
ecma_value_t idx_value = ecma_make_uint32_value (idx); }
ecma_op_object_put (res_ele_p,
index_str_p, /* m. + t. */
idx_value, executor_p->index = ++idx;
false);
ecma_free_value (idx_value);
/* n. */ /* n. */
ecma_op_object_put (res_ele_p, executor_p->values = values_array;
value_str_p,
values_array,
false);
/* o. */ /* o. */
ecma_op_object_put (res_ele_p, executor_p->capability = ecma_make_object_value (capability_obj_p);
capability_str_p,
capability,
false);
/* p. */ /* p. */
ecma_op_object_put (res_ele_p, executor_p->remaining_elements = remaining;
remaining_str_p,
remaining,
false);
/* q. */ /* q. */
ecma_builtin_promise_remaining_inc_or_dec (remaining, true); ecma_promise_remaining_inc_or_dec (remaining, true);
/* r. */ /* r. */
ecma_value_t args[2]; ecma_value_t args[2];
args[0] = ecma_make_object_value (res_ele_p); args[0] = ecma_make_object_value (executor_func_p);
args[1] = ecma_op_object_get_by_magic_id (capability_obj_p, LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); args[1] = capability_p->reject;
ecma_value_t result = ecma_op_invoke_by_magic_id (next_promise, LIT_MAGIC_STRING_THEN, args, 2); ecma_value_t result = ecma_op_invoke_by_magic_id (next_promise, LIT_MAGIC_STRING_THEN, args, 2);
ecma_free_value (next_promise); ecma_free_value (next_promise);
ecma_deref_object (executor_func_p);
for (uint8_t i = 0; i < 2; i++)
{
ecma_free_value (args[i]);
}
/* s. */ /* s. */
if (ECMA_IS_VALUE_ERROR (result)) if (ECMA_IS_VALUE_ERROR (result))
@@ -475,13 +340,11 @@ ecma_builtin_promise_perform_all (ecma_value_t iterator, /**< iteratorRecord */
} }
ecma_free_value (result); ecma_free_value (result);
/* t. */
idx++;
} }
ecma_free_value (remaining); ecma_free_value (remaining);
ecma_deref_object (values_array_obj_p); ecma_deref_object (values_array_obj_p);
return ret_value; return ret_value;
} /* ecma_builtin_promise_perform_all */ } /* ecma_builtin_promise_perform_all */
@@ -501,20 +364,20 @@ ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */
return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object."));
} }
ecma_value_t capability = ecma_promise_new_capability (this_arg); ecma_object_t *capability_obj_p = ecma_promise_new_capability (this_arg);
if (ECMA_IS_VALUE_ERROR (capability)) if (JERRY_UNLIKELY (capability_obj_p == NULL))
{ {
return capability; return ECMA_VALUE_ERROR;
} }
ecma_value_t next_method; ecma_value_t next_method;
ecma_value_t iterator = ecma_op_get_iterator (iterable, ECMA_VALUE_SYNC_ITERATOR, &next_method); ecma_value_t iterator = ecma_op_get_iterator (iterable, ECMA_VALUE_SYNC_ITERATOR, &next_method);
iterator = ecma_builtin_promise_reject_abrupt (iterator, capability); iterator = ecma_builtin_promise_reject_abrupt (iterator, capability_obj_p);
if (ECMA_IS_VALUE_ERROR (iterator)) if (ECMA_IS_VALUE_ERROR (iterator))
{ {
ecma_free_value (capability); ecma_deref_object (capability_obj_p);
return iterator; return iterator;
} }
@@ -523,11 +386,11 @@ ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */
if (is_race) if (is_race)
{ {
ret = ecma_builtin_promise_perform_race (iterator, next_method, capability, this_arg, &is_done); ret = ecma_builtin_promise_perform_race (iterator, next_method, capability_obj_p, this_arg, &is_done);
} }
else else
{ {
ret = ecma_builtin_promise_perform_all (iterator, next_method, capability, this_arg, &is_done); ret = ecma_builtin_promise_perform_all (iterator, next_method, capability_obj_p, this_arg, &is_done);
} }
if (ECMA_IS_VALUE_ERROR (ret)) if (ECMA_IS_VALUE_ERROR (ret))
@@ -537,12 +400,12 @@ ecma_builtin_promise_race_or_all (ecma_value_t this_arg, /**< 'this' argument */
ret = ecma_op_iterator_close (iterator); ret = ecma_op_iterator_close (iterator);
} }
ret = ecma_builtin_promise_reject_abrupt (ret, capability); ret = ecma_builtin_promise_reject_abrupt (ret, capability_obj_p);
} }
ecma_free_value (iterator); ecma_free_value (iterator);
ecma_free_value (next_method); ecma_free_value (next_method);
ecma_free_value (capability); ecma_deref_object (capability_obj_p);
return ret; return ret;
} /* ecma_builtin_promise_race_or_all */ } /* ecma_builtin_promise_race_or_all */
+6 -16
View File
@@ -181,11 +181,11 @@ ecma_free_promise_resolve_thenable_job (ecma_job_promise_resolve_thenable_t *job
static ecma_value_t static ecma_value_t
ecma_process_promise_reaction_job (ecma_job_promise_reaction_t *job_p) /**< the job to be operated */ ecma_process_promise_reaction_job (ecma_job_promise_reaction_t *job_p) /**< the job to be operated */
{ {
ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
/* 2. */ /* 2. */
ecma_value_t capability = job_p->capability; JERRY_ASSERT (ecma_object_class_is (ecma_get_object_from_value (job_p->capability),
LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY));
ecma_promise_capabality_t *capability_p;
capability_p = (ecma_promise_capabality_t *) ecma_get_object_from_value (job_p->capability);
/* 3. */ /* 3. */
ecma_value_t handler = job_p->handler; ecma_value_t handler = job_p->handler;
@@ -217,28 +217,18 @@ ecma_process_promise_reaction_job (ecma_job_promise_reaction_t *job_p) /**< the
} }
/* 7. */ /* 7. */
ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p); status = ecma_op_function_call (ecma_get_object_from_value (capability_p->reject),
JERRY_ASSERT (ecma_op_is_callable (reject));
status = ecma_op_function_call (ecma_get_object_from_value (reject),
ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED,
&handler_result, &handler_result,
1); 1);
ecma_free_value (reject);
} }
else else
{ {
/* 8. */ /* 8. */
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), resolve_str_p); status = ecma_op_function_call (ecma_get_object_from_value (capability_p->resolve),
JERRY_ASSERT (ecma_op_is_callable (resolve));
status = ecma_op_function_call (ecma_get_object_from_value (resolve),
ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED,
&handler_result, &handler_result,
1); 1);
ecma_free_value (resolve);
} }
ecma_free_value (handler_result); ecma_free_value (handler_result);
+160 -171
View File
@@ -13,6 +13,8 @@
* limitations under the License. * limitations under the License.
*/ */
#include "ecma-alloc.h"
#include "ecma-array-object.h"
#include "ecma-boolean-object.h" #include "ecma-boolean-object.h"
#include "ecma-builtins.h" #include "ecma-builtins.h"
#include "ecma-exceptions.h" #include "ecma-exceptions.h"
@@ -361,63 +363,6 @@ ecma_promise_resolve_handler (const ecma_value_t function, /**< the function its
return ECMA_VALUE_UNDEFINED; return ECMA_VALUE_UNDEFINED;
} /* ecma_promise_resolve_handler */ } /* ecma_promise_resolve_handler */
/**
* CapabilitiesExecutor Function.
*
* See also: ES2015 25.4.1.5.1
*
* @return ecma value of undefined or typerror.
* Returned value must be freed with ecma_free_value
*/
static ecma_value_t
ecma_call_builtin_executor (ecma_object_t *executor_p, /**< the executor object */
ecma_value_t resolve_func, /**< the resolve function */
ecma_value_t reject_func) /**< the reject function */
{
ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
/* 2. */
ecma_value_t capability = ecma_op_object_get (executor_p, capability_str_p);
/* 3. */
ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), resolve_str_p);
if (resolve != ECMA_VALUE_UNDEFINED)
{
ecma_free_value (resolve);
ecma_free_value (capability);
return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' function should be undefined."));
}
/* 4. */
ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p);
if (reject != ECMA_VALUE_UNDEFINED)
{
ecma_free_value (reject);
ecma_free_value (capability);
return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' function should be undefined."));
}
/* 5. */
ecma_op_object_put (ecma_get_object_from_value (capability),
resolve_str_p,
resolve_func,
false);
/* 6. */
ecma_op_object_put (ecma_get_object_from_value (capability),
reject_str_p,
reject_func,
false);
ecma_free_value (capability);
return ECMA_VALUE_UNDEFINED;
} /* ecma_call_builtin_executor */
/** /**
* Helper function for PromiseCreateResovingFucntions. * Helper function for PromiseCreateResovingFucntions.
* *
@@ -561,14 +506,6 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function
argv, argv,
2); 2);
} }
else if (type == ECMA_PROMISE_EXECUTOR_OBJECT)
{
JERRY_ASSERT (ecma_is_value_object (executor));
completion = ecma_call_builtin_executor (ecma_get_object_from_value (executor),
funcs.resolve,
funcs.reject);
}
else else
{ {
JERRY_ASSERT (type == ECMA_PROMISE_EXECUTOR_EMPTY); JERRY_ASSERT (type == ECMA_PROMISE_EXECUTOR_EMPTY);
@@ -603,6 +540,86 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function
return ecma_make_object_value (object_p); return ecma_make_object_value (object_p);
} /* ecma_op_create_promise_object */ } /* ecma_op_create_promise_object */
/**
* Helper function for increase or decrease the remaining count.
*
* @return the current remaining count after increase or decrease.
*/
ecma_length_t
ecma_promise_remaining_inc_or_dec (ecma_value_t remaining, /**< the remaining count */
bool is_inc) /**< whether to increase the count */
{
JERRY_ASSERT (ecma_is_value_object (remaining));
ecma_object_t *remaining_p = ecma_get_object_from_value (remaining);
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) remaining_p;
JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_NUMBER_UL);
JERRY_ASSERT (ecma_is_value_integer_number (ext_object_p->u.class_prop.u.value));
ecma_length_t current = (ecma_length_t) ecma_get_integer_from_value (ext_object_p->u.class_prop.u.value);
if (is_inc)
{
current++;
}
else
{
current--;
}
ext_object_p->u.class_prop.u.value = ecma_make_uint32_value (current);
return current;
} /* ecma_promise_remaining_inc_or_dec */
/**
* Native handler for Promise.all Resolve Element Function.
*
* See also:
* ES2015 25.4.4.1.2
*
* @return ecma value of undefined.
*/
ecma_value_t
ecma_promise_all_handler_cb (const ecma_value_t function_obj, /**< the function itself */
const ecma_value_t this_val, /**< this_arg of the function */
const ecma_value_t args_p[], /**< argument list */
const ecma_length_t args_count) /**< argument number */
{
JERRY_UNUSED (this_val);
JERRY_UNUSED (args_count);
ecma_promise_all_executor_t *executor_p = (ecma_promise_all_executor_t *) ecma_get_object_from_value (function_obj);
/* 1 - 2. */
if (executor_p->index == 0)
{
return ECMA_VALUE_UNDEFINED;
}
/* 8. */
ecma_op_object_put_by_uint32_index (ecma_get_object_from_value (executor_p->values),
(uint32_t) (executor_p->index - 1),
args_p[0],
false);
/* 3. */
executor_p->index = 0;
/* 9-10. */
ecma_value_t ret = ECMA_VALUE_UNDEFINED;
if (ecma_promise_remaining_inc_or_dec (executor_p->remaining_elements, false) == 0)
{
ecma_value_t capability = executor_p->capability;
ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) ecma_get_object_from_value (capability);
ret = ecma_op_function_call (ecma_get_object_from_value (capability_p->resolve),
ECMA_VALUE_UNDEFINED,
&executor_p->values,
1);
}
return ret;
} /* ecma_promise_all_handler_cb */
/** /**
* 25.4.1.5.1 GetCapabilitiesExecutor Functions * 25.4.1.5.1 GetCapabilitiesExecutor Functions
* *
@@ -611,58 +628,39 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function
* @return ECMA_VALUE_UNDEFINED or TypeError * @return ECMA_VALUE_UNDEFINED or TypeError
* returned value must be freed with ecma_free_value * returned value must be freed with ecma_free_value
*/ */
static ecma_value_t ecma_value_t
ecma_op_get_capabilities_executor_cb (const ecma_value_t function_obj, /**< the function itself */ ecma_op_get_capabilities_executor_cb (const ecma_value_t function_obj, /**< the function itself */
const ecma_value_t this_val, /**< this_arg of the function */ const ecma_value_t this_val, /**< this_arg of the function */
const ecma_value_t args_p[], /**< argument list */ const ecma_value_t args_p[], /**< argument list */
const ecma_length_t args_count) /**< argument number */ const ecma_length_t args_count) /**< argument number */
{ {
JERRY_UNUSED (this_val); JERRY_UNUSED (this_val);
/* 1. */ JERRY_ASSERT (args_count >= 2);
ecma_value_t capability = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (function_obj),
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); ecma_promise_capability_executor_t *executor_p;
JERRY_ASSERT (ecma_is_value_object (capability)); executor_p = (ecma_promise_capability_executor_t *) ecma_get_object_from_value (function_obj);
/* 2. */ /* 2. */
ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability); ecma_object_t *capability_obj_p = ecma_get_object_from_value (executor_p->capability);
JERRY_ASSERT (ecma_object_class_is (capability_obj_p, LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY));
ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) capability_obj_p;
/* 3. */ /* 3. */
ecma_value_t resolve = ecma_op_object_get_by_magic_id (capability_obj_p, if (!ecma_is_value_undefined (capability_p->resolve))
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
if (!ecma_is_value_undefined (resolve))
{ {
ecma_free_value (resolve);
ecma_deref_object (capability_obj_p);
return ecma_raise_type_error (ECMA_ERR_MSG ("Resolve must be undefined")); return ecma_raise_type_error (ECMA_ERR_MSG ("Resolve must be undefined"));
} }
/* 4. */ /* 4. */
ecma_value_t reject = ecma_op_object_get_by_magic_id (capability_obj_p, if (!ecma_is_value_undefined (capability_p->reject))
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
if (!ecma_is_value_undefined (reject))
{ {
ecma_free_value (reject);
ecma_deref_object (capability_obj_p);
return ecma_raise_type_error (ECMA_ERR_MSG ("Reject must be undefined")); return ecma_raise_type_error (ECMA_ERR_MSG ("Reject must be undefined"));
} }
/* 5. */ /* 5. */
ecma_op_object_put (capability_obj_p, capability_p->resolve = args_p[0];
ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE),
args_count > 0 ? args_p[0] : ECMA_VALUE_UNDEFINED,
false);
/* 6. */ /* 6. */
ecma_op_object_put (capability_obj_p, capability_p->reject = args_p[1];
ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT),
args_count > 1 ? args_p[1] : ECMA_VALUE_UNDEFINED,
false);
ecma_deref_object (capability_obj_p);
/* 7. */ /* 7. */
return ECMA_VALUE_UNDEFINED; return ECMA_VALUE_UNDEFINED;
@@ -673,34 +671,44 @@ ecma_op_get_capabilities_executor_cb (const ecma_value_t function_obj, /**< the
* *
* See also: ES2015 25.4.1.5 * See also: ES2015 25.4.1.5
* *
* @return ecma value of the new PromiseCapability * @return NULL - if the operation raises error
* Returned value must be freed with ecma_free_value * new PromiseCapability object - otherwise
*/ */
ecma_value_t ecma_object_t *
ecma_promise_new_capability (ecma_value_t constructor) ecma_promise_new_capability (ecma_value_t constructor)
{ {
/* 1. */ /* 1. */
if (!ecma_is_constructor (constructor)) if (!ecma_is_constructor (constructor))
{ {
return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid capability")); ecma_raise_type_error (ECMA_ERR_MSG ("Invalid capability"));
return NULL;
} }
ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor); ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor);
/* 3. */
ecma_object_t *capability_p = ecma_op_create_object_object_noarg ();
ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY); /* 3. */
ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); ecma_object_t *capability_obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE),
sizeof (ecma_promise_capabality_t),
ECMA_OBJECT_TYPE_CLASS);
ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) capability_obj_p;
capability_p->header.u.class_prop.class_id = LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY;
capability_p->header.u.class_prop.u.promise = ECMA_VALUE_UNDEFINED;
capability_p->resolve = ECMA_VALUE_UNDEFINED;
capability_p->reject = ECMA_VALUE_UNDEFINED;
/* 4. */ /* 4. */
ecma_object_t *executor_p = ecma_op_create_external_function_object (ecma_op_get_capabilities_executor_cb); ecma_object_t *executor_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE),
ecma_value_t executor = ecma_make_object_value (executor_p); sizeof (ecma_promise_capability_executor_t),
ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
/* 5. */ /* 5. */
ecma_op_object_put (executor_p, ecma_promise_capability_executor_t *executor_func_p = (ecma_promise_capability_executor_t *) executor_p;
capability_str_p, executor_func_p->header.u.external_handler_cb = ecma_op_get_capabilities_executor_cb;
ecma_make_object_value (capability_p), executor_func_p->capability = ecma_make_object_value (capability_obj_p);
false);
/* 6. */ /* 6. */
ecma_value_t executor = ecma_make_object_value (executor_p);
ecma_value_t promise = ecma_op_function_construct (constructor_obj_p, ecma_value_t promise = ecma_op_function_construct (constructor_obj_p,
constructor_obj_p, constructor_obj_p,
&executor, &executor,
@@ -710,44 +718,35 @@ ecma_promise_new_capability (ecma_value_t constructor)
/* 7. */ /* 7. */
if (ECMA_IS_VALUE_ERROR (promise)) if (ECMA_IS_VALUE_ERROR (promise))
{ {
ecma_deref_object (capability_p); ecma_deref_object (capability_obj_p);
return promise; return NULL;
}
/* 8. */
if (!ecma_op_is_callable (capability_p->resolve))
{
ecma_free_value (promise);
ecma_deref_object (capability_obj_p);
ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' parameter must be callable."));
return NULL;
}
/* 9. */
if (!ecma_op_is_callable (capability_p->reject))
{
ecma_free_value (promise);
ecma_deref_object (capability_obj_p);
ecma_raise_type_error (ECMA_ERR_MSG ("'reject' parameter must be callable."));
return NULL;
} }
/* 10. */ /* 10. */
ecma_op_object_put (capability_p, capability_p->header.u.class_prop.u.promise = promise;
promise_str_p,
promise,
false);
ecma_free_value (promise); ecma_free_value (promise);
/* 8. */
ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
ecma_value_t resolve = ecma_op_object_get (capability_p, resolve_str_p);
if (!ecma_op_is_callable (resolve))
{
ecma_free_value (resolve);
ecma_deref_object (capability_p);
return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' parameter must be callable."));
}
ecma_free_value (resolve);
/* 9. */
ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
ecma_value_t reject = ecma_op_object_get (capability_p, reject_str_p);
if (!ecma_op_is_callable (reject))
{
ecma_free_value (reject);
ecma_deref_object (capability_p);
return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' parameter must be callable."));
}
ecma_free_value (reject);
/* 11. */ /* 11. */
return ecma_make_object_value (capability_p); return capability_obj_p;
} /* ecma_promise_new_capability */ } /* ecma_promise_new_capability */
/** /**
@@ -788,33 +787,22 @@ ecma_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argument */
} }
} }
ecma_value_t capability = ecma_promise_new_capability (this_arg); ecma_object_t *capability_obj_p = ecma_promise_new_capability (this_arg);
if (ECMA_IS_VALUE_ERROR (capability)) if (JERRY_UNLIKELY (capability_obj_p == NULL))
{ {
return capability; return ECMA_VALUE_ERROR;
} }
ecma_string_t *property_str_p; ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) capability_obj_p;
if (is_resolve) ecma_value_t func = is_resolve ? capability_p->resolve : capability_p->reject;
{
property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
}
else
{
property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
}
ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), property_str_p);
ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (func), ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (func),
ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED,
&value, &value,
1); 1);
ecma_free_value (func);
if (ECMA_IS_VALUE_ERROR (call_ret)) if (ECMA_IS_VALUE_ERROR (call_ret))
{ {
return call_ret; return call_ret;
@@ -822,9 +810,8 @@ ecma_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argument */
ecma_free_value (call_ret); ecma_free_value (call_ret);
ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); ecma_value_t promise = ecma_copy_value (capability_p->header.u.class_prop.u.promise);
ecma_value_t promise = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); ecma_deref_object (capability_obj_p);
ecma_free_value (capability);
return promise; return promise;
} /* ecma_promise_reject_or_resolve */ } /* ecma_promise_reject_or_resolve */
@@ -842,9 +829,11 @@ static ecma_value_t
ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' */ ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' */
ecma_value_t on_fulfilled, /**< on_fulfilled function */ ecma_value_t on_fulfilled, /**< on_fulfilled function */
ecma_value_t on_rejected, /**< on_rejected function */ ecma_value_t on_rejected, /**< on_rejected function */
ecma_value_t result_capability) /**< promise capability */ ecma_object_t *result_capability_obj_p) /**< promise capability */
{ {
ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); JERRY_ASSERT (ecma_object_class_is (result_capability_obj_p, LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY));
ecma_promise_capabality_t *capability_p = (ecma_promise_capabality_t *) result_capability_obj_p;
/* 3. boolean true indicates "indentity" */ /* 3. boolean true indicates "indentity" */
if (!ecma_op_is_callable (on_fulfilled)) if (!ecma_op_is_callable (on_fulfilled))
@@ -867,7 +856,7 @@ ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' *
{ {
/* 7. */ /* 7. */
ecma_value_t capability_with_tag; ecma_value_t capability_with_tag;
ECMA_SET_NON_NULL_POINTER_TAG (capability_with_tag, ecma_get_object_from_value (result_capability), 0); ECMA_SET_NON_NULL_POINTER_TAG (capability_with_tag, result_capability_obj_p, 0);
if (on_fulfilled != ECMA_VALUE_TRUE) if (on_fulfilled != ECMA_VALUE_TRUE)
{ {
@@ -895,19 +884,19 @@ ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' *
{ {
/* 8. */ /* 8. */
ecma_value_t value = ecma_promise_get_result (promise_obj_p); ecma_value_t value = ecma_promise_get_result (promise_obj_p);
ecma_enqueue_promise_reaction_job (result_capability, on_fulfilled, value); ecma_enqueue_promise_reaction_job (ecma_make_object_value (result_capability_obj_p), on_fulfilled, value);
ecma_free_value (value); ecma_free_value (value);
} }
else else
{ {
/* 9. */ /* 9. */
ecma_value_t reason = ecma_promise_get_result (promise_obj_p); ecma_value_t reason = ecma_promise_get_result (promise_obj_p);
ecma_enqueue_promise_reaction_job (result_capability, on_rejected, reason); ecma_enqueue_promise_reaction_job (ecma_make_object_value (result_capability_obj_p), on_rejected, reason);
ecma_free_value (reason); ecma_free_value (reason);
} }
/* 10. */ /* 10. */
return ecma_op_object_get (ecma_get_object_from_value (result_capability), promise_str_p); return ecma_copy_value (capability_p->header.u.class_prop.u.promise);
} /* ecma_promise_do_then */ } /* ecma_promise_do_then */
/** /**
@@ -940,16 +929,16 @@ ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */
return species; return species;
} }
ecma_value_t result_capability = ecma_promise_new_capability (species); ecma_object_t *result_capability_obj_p = ecma_promise_new_capability (species);
ecma_free_value (species); ecma_free_value (species);
if (ECMA_IS_VALUE_ERROR (result_capability)) if (JERRY_UNLIKELY (result_capability_obj_p == NULL))
{ {
return result_capability; return ECMA_VALUE_ERROR;
} }
ecma_value_t ret = ecma_promise_do_then (promise, on_fulfilled, on_rejected, result_capability); ecma_value_t ret = ecma_promise_do_then (promise, on_fulfilled, on_rejected, result_capability_obj_p);
ecma_free_value (result_capability); ecma_deref_object (result_capability_obj_p);
return ret; return ret;
} /* ecma_promise_then */ } /* ecma_promise_then */
@@ -42,7 +42,6 @@ typedef enum
typedef enum typedef enum
{ {
ECMA_PROMISE_EXECUTOR_FUNCTION, /**< the executor is a function, it is for the usual constructor */ ECMA_PROMISE_EXECUTOR_FUNCTION, /**< the executor is a function, it is for the usual constructor */
ECMA_PROMISE_EXECUTOR_OBJECT, /**< the executor is an object, it is for the `then` routine */
ECMA_PROMISE_EXECUTOR_EMPTY /**< the executor is empty, it is for external C API */ ECMA_PROMISE_EXECUTOR_EMPTY /**< the executor is empty, it is for external C API */
} ecma_promise_executor_type_t; } ecma_promise_executor_type_t;
@@ -88,7 +87,7 @@ uint16_t ecma_promise_get_flags (ecma_object_t *promise_p);
ecma_value_t ecma_promise_get_result (ecma_object_t *promise_p); ecma_value_t ecma_promise_get_result (ecma_object_t *promise_p);
void ecma_reject_promise (ecma_value_t promise, ecma_value_t reason); void ecma_reject_promise (ecma_value_t promise, ecma_value_t reason);
void ecma_fulfill_promise (ecma_value_t promise, ecma_value_t value); void ecma_fulfill_promise (ecma_value_t promise, ecma_value_t value);
ecma_value_t ecma_promise_new_capability (ecma_value_t constructor); ecma_object_t *ecma_promise_new_capability (ecma_value_t constructor);
ecma_value_t ecma_promise_reject_or_resolve (ecma_value_t this_arg, ecma_value_t value, bool is_resolve); ecma_value_t ecma_promise_reject_or_resolve (ecma_value_t this_arg, ecma_value_t value, bool is_resolve);
ecma_value_t ecma_promise_then (ecma_value_t promise, ecma_value_t on_fulfilled, ecma_value_t on_rejected); ecma_value_t ecma_promise_then (ecma_value_t promise, ecma_value_t on_fulfilled, ecma_value_t on_rejected);
void ecma_promise_async_then (ecma_value_t promise, ecma_value_t executable_object); void ecma_promise_async_then (ecma_value_t promise, ecma_value_t executable_object);
@@ -97,6 +96,13 @@ void ecma_promise_create_resolving_functions (ecma_object_t *object_p, ecma_prom
bool create_already_resolved); bool create_already_resolved);
void ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs); void ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs);
ecma_length_t ecma_promise_remaining_inc_or_dec (ecma_value_t remaining, bool is_inc);
ecma_value_t ecma_promise_all_handler_cb (const ecma_value_t function_obj, const ecma_value_t this_val,
const ecma_value_t args_p[], const ecma_length_t args_count);
ecma_value_t ecma_op_get_capabilities_executor_cb (const ecma_value_t function_obj, const ecma_value_t this_val,
const ecma_value_t args_p[], const ecma_length_t args_count);
/** /**
* @} * @}
* @} * @}
+1 -8
View File
@@ -37,20 +37,13 @@ typedef enum
LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED, /**< [[AlreadyResolved]] of promise reject or resolve functions */ LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED, /**< [[AlreadyResolved]] of promise reject or resolve functions */
LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION, /**< the resolve funtion of the promise object */ LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION, /**< the resolve funtion of the promise object */
LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION, /**< the reject function of the promise object */ LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION, /**< the reject function of the promise object */
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE, /**< [[Promise]] property */
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE, /**< [[Resolve]] property */
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT, /**< [[Reject]] property */
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY, /**< [[Capability]] property */
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_ALREADY_CALLED, /**< [[AlreadyCalled]] property */
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_INDEX, /**< [[Index]] property */
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_VALUE, /**< [[Values]] property */
LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REMAINING_ELEMENT, /**< [[RemainingElement]] property */
LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX, /**< [[%Iterator%NextIndex]] property */ LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX, /**< [[%Iterator%NextIndex]] property */
LIT_INTERNAL_MAGIC_STRING_MAP_KEY, /**< Property key used when an object is a key in a map object */ LIT_INTERNAL_MAGIC_STRING_MAP_KEY, /**< Property key used when an object is a key in a map object */
LIT_INTERNAL_MAGIC_API_INTERNAL, /**< Property key used to add non-visible JS properties from the public API */ LIT_INTERNAL_MAGIC_API_INTERNAL, /**< Property key used to add non-visible JS properties from the public API */
LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES, /**< %ArrayProto_values% intrinsic routine */ LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES, /**< %ArrayProto_values% intrinsic routine */
LIT_INTERNAL_MAGIC_STRING_SET_PROTOTYPE_KEYS, /**< Set.prototype values, keys and [@@iterator] routines */ LIT_INTERNAL_MAGIC_STRING_SET_PROTOTYPE_KEYS, /**< Set.prototype values, keys and [@@iterator] routines */
LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE, /**< FunctionEnvironmentRecord [[ThisBindingValue]] internal slot */ LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE, /**< FunctionEnvironmentRecord [[ThisBindingValue]] internal slot */
LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY, /**< PromiseCapability record */
/* List of well known symbols */ /* List of well known symbols */
LIT_GLOBAL_SYMBOL_HAS_INSTANCE, /**< @@hasInstance well known symbol */ LIT_GLOBAL_SYMBOL_HAS_INSTANCE, /**< @@hasInstance well known symbol */
LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE, /**< @@isConcatSpreadable well known symbol */ LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE, /**< @@isConcatSpreadable well known symbol */