Skip to content

Commit 1105b43

Browse files
authored
Optimize Promise data structures. (#3768)
This patch reworks several structures: - Fulfill and reject reactions are combined into one collection. The values in this collection are compressed: a capability followed by an optional fulfill and reject functions. - Fulfill and reject reactions are directly stored, no need to allocate an object for them. - The job queue directly stores its items, this saves a pointer to the value, and the callback is replaced by an uint8 type. - Promise status and already resolved is stored in extra_info. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
1 parent 1774cca commit 1105b43

8 files changed

Lines changed: 298 additions & 300 deletions

File tree

jerry-core/api/jerry.c

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,8 @@ JERRY_STATIC_ASSERT ((int) RE_FLAG_GLOBAL == (int) JERRY_REGEXP_FLAG_GLOBAL
7676

7777
#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
7878
/* The internal ECMA_PROMISE_STATE_* values are "one byte away" from the API values */
79-
JERRY_STATIC_ASSERT (((ECMA_PROMISE_STATE_PENDING + 1) == JERRY_PROMISE_STATE_PENDING)
80-
&& ((ECMA_PROMISE_STATE_FULFILLED + 1) == JERRY_PROMISE_STATE_FULFILLED)
81-
&& ((ECMA_PROMISE_STATE_REJECTED + 1) == JERRY_PROMISE_STATE_REJECTED),
79+
JERRY_STATIC_ASSERT ((int) ECMA_PROMISE_IS_PENDING == (int) JERRY_PROMISE_STATE_PENDING
80+
&& (int) ECMA_PROMISE_IS_FULFILLED == (int) JERRY_PROMISE_STATE_FULFILLED,
8281
promise_internal_state_matches_external);
8382
#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
8483

@@ -1616,14 +1615,14 @@ jerry_create_promise (void)
16161615
jerry_assert_api_available ();
16171616

16181617
#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
1619-
ecma_object_t * old_new_target_p = JERRY_CONTEXT (current_new_target);
1618+
ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target);
16201619

16211620
if (old_new_target_p == NULL)
16221621
{
16231622
JERRY_CONTEXT (current_new_target) = ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE);
16241623
}
16251624

1626-
ecma_value_t promise_value = ecma_op_create_promise_object (ECMA_VALUE_EMPTY, ECMA_PROMISE_EXECUTOR_EMPTY);
1625+
ecma_value_t promise_value = ecma_op_create_promise_object (ECMA_VALUE_EMPTY, ECMA_PROMISE_EXECUTOR_EMPTY);
16271626

16281627
JERRY_CONTEXT (current_new_target) = old_new_target_p;
16291628
return promise_value;
@@ -3331,12 +3330,10 @@ jerry_get_promise_state (const jerry_value_t promise) /**< promise object to get
33313330
return JERRY_PROMISE_STATE_NONE;
33323331
}
33333332

3334-
uint8_t state = ecma_promise_get_state (ecma_get_object_from_value (promise));
3335-
3336-
JERRY_ASSERT (state < ECMA_PROMISE_STATE__COUNT);
3333+
uint16_t flags = ecma_promise_get_flags (ecma_get_object_from_value (promise));
3334+
flags &= (ECMA_PROMISE_IS_PENDING | ECMA_PROMISE_IS_FULFILLED);
33373335

3338-
/* Static assert above guarantees the mapping from internal type to external type. */
3339-
return (jerry_promise_state_t) (state + 1);
3336+
return (flags ? flags : JERRY_PROMISE_STATE_REJECTED);
33403337
#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
33413338
JERRY_UNUSED (promise);
33423339
return JERRY_PROMISE_STATE_NONE;

jerry-core/ecma/base/ecma-gc.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -268,27 +268,28 @@ ecma_gc_mark_promise_object (ecma_extended_object_t *ext_object_p) /**< extended
268268

269269
/* Mark all reactions. */
270270
ecma_promise_object_t *promise_object_p = (ecma_promise_object_t *) ext_object_p;
271-
ecma_collection_t *collection_p = promise_object_p->fulfill_reactions;
271+
ecma_collection_t *collection_p = promise_object_p->reactions;
272272

273273
if (collection_p != NULL)
274274
{
275275
ecma_value_t *buffer_p = collection_p->buffer_p;
276+
ecma_value_t *buffer_end_p = buffer_p + collection_p->item_count;
276277

277-
for (uint32_t i = 0; i < collection_p->item_count; i++)
278+
while (buffer_p < buffer_end_p)
278279
{
279-
ecma_gc_set_object_visited (ecma_get_object_from_value (buffer_p[i]));
280-
}
281-
}
280+
ecma_value_t value = *buffer_p++;
282281

283-
collection_p = promise_object_p->reject_reactions;
282+
ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, value));
284283

285-
if (collection_p != NULL)
286-
{
287-
ecma_value_t *buffer_p = collection_p->buffer_p;
284+
if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (value))
285+
{
286+
ecma_gc_set_object_visited (ecma_get_object_from_value (*buffer_p++));
287+
}
288288

289-
for (uint32_t i = 0; i < collection_p->item_count; i++)
290-
{
291-
ecma_gc_set_object_visited (ecma_get_object_from_value (buffer_p[i]));
289+
if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (value))
290+
{
291+
ecma_gc_set_object_visited (ecma_get_object_from_value (*buffer_p++));
292+
}
292293
}
293294
}
294295
} /* ecma_gc_mark_promise_object */
@@ -1145,8 +1146,10 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
11451146
case LIT_MAGIC_STRING_PROMISE_UL:
11461147
{
11471148
ecma_free_value_if_not_object (ext_object_p->u.class_prop.u.value);
1148-
ecma_collection_free_if_not_object (((ecma_promise_object_t *) object_p)->fulfill_reactions);
1149-
ecma_collection_free_if_not_object (((ecma_promise_object_t *) object_p)->reject_reactions);
1149+
1150+
/* Reactions only contains objects. */
1151+
ecma_collection_destroy (((ecma_promise_object_t *) object_p)->reactions);
1152+
11501153
ext_object_size = sizeof (ecma_promise_object_t);
11511154
break;
11521155
}

0 commit comments

Comments
 (0)