• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright JS Foundation and other contributors, http://js.foundation
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecma-boolean-object.h"
17 #include "ecma-builtins.h"
18 #include "ecma-exceptions.h"
19 #include "ecma-function-object.h"
20 #include "ecma-gc.h"
21 #include "ecma-globals.h"
22 #include "ecma-helpers.h"
23 #include "ecma-jobqueue.h"
24 #include "ecma-objects.h"
25 #include "ecma-objects-general.h"
26 #include "ecma-promise-object.h"
27 #include "jcontext.h"
28 
29 #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
30 
31 /** \addtogroup ecma ECMA
32  * @{
33  *
34  * \addtogroup ecmapromiseobject ECMA Promise object related routines
35  * @{
36  */
37 
38 /**
39  * Check if an object is promise.
40  *
41  * @return true - if the object is a promise.
42  *         false - otherwise.
43  */
44 inline bool JERRY_ATTR_ALWAYS_INLINE
ecma_is_promise(ecma_object_t * obj_p)45 ecma_is_promise (ecma_object_t *obj_p) /**< points to object */
46 {
47   return ecma_object_class_is (obj_p, LIT_MAGIC_STRING_PROMISE_UL);
48 } /* ecma_is_promise */
49 
50 /**
51  * Get the result of the promise.
52  *
53  * @return ecma value of the promise result.
54  *         Returned value must be freed with ecma_free_value
55  */
56 ecma_value_t
ecma_promise_get_result(ecma_object_t * obj_p)57 ecma_promise_get_result (ecma_object_t *obj_p) /**< points to promise object */
58 {
59   JERRY_ASSERT (ecma_is_promise (obj_p));
60 
61   ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
62 
63   return ecma_copy_value (ext_object_p->u.class_prop.u.value);
64 } /* ecma_promise_get_result */
65 
66 /**
67  * Set the PromiseResult of promise.
68  */
69 static inline void JERRY_ATTR_ALWAYS_INLINE
ecma_promise_set_result(ecma_object_t * obj_p,ecma_value_t result)70 ecma_promise_set_result (ecma_object_t *obj_p, /**< points to promise object */
71                          ecma_value_t result) /**< the result value */
72 {
73   JERRY_ASSERT (ecma_is_promise (obj_p));
74 
75   ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
76 
77   JERRY_ASSERT (ext_object_p->u.class_prop.u.value == ECMA_VALUE_UNDEFINED);
78 
79   ext_object_p->u.class_prop.u.value = result;
80 } /* ecma_promise_set_result */
81 
82 /**
83  * Get the PromiseState of promise.
84  *
85  * @return the state's enum value
86  */
87 uint16_t
ecma_promise_get_flags(ecma_object_t * obj_p)88 ecma_promise_get_flags (ecma_object_t *obj_p) /**< points to promise object */
89 {
90   JERRY_ASSERT (ecma_is_promise (obj_p));
91 
92   return ((ecma_extended_object_t *) obj_p)->u.class_prop.extra_info;
93 } /* ecma_promise_get_flags */
94 
95 /**
96  * Set the PromiseState of promise.
97  */
98 static inline void JERRY_ATTR_ALWAYS_INLINE
ecma_promise_set_state(ecma_object_t * obj_p,bool is_fulfilled)99 ecma_promise_set_state (ecma_object_t *obj_p, /**< points to promise object */
100                         bool is_fulfilled) /**< new flags */
101 {
102   JERRY_ASSERT (ecma_is_promise (obj_p));
103   JERRY_ASSERT (ecma_promise_get_flags (obj_p) & ECMA_PROMISE_IS_PENDING);
104 
105   uint16_t flags_to_invert = (is_fulfilled ? (ECMA_PROMISE_IS_PENDING | ECMA_PROMISE_IS_FULFILLED)
106                                            : ECMA_PROMISE_IS_PENDING);
107 
108   ((ecma_extended_object_t *) obj_p)->u.class_prop.extra_info ^= flags_to_invert;
109 } /* ecma_promise_set_state */
110 
111 /**
112  * Take a collection of Reactions and enqueue a new PromiseReactionJob for each Reaction.
113  *
114  * See also: ES2015 25.4.1.8
115  */
116 static void
ecma_promise_trigger_reactions(ecma_collection_t * reactions,ecma_value_t value,bool is_reject)117 ecma_promise_trigger_reactions (ecma_collection_t *reactions, /**< lists of reactions */
118                                 ecma_value_t value, /**< value for resolve or reject */
119                                 bool is_reject) /**< true if promise is rejected, false otherwise */
120 {
121   ecma_value_t *buffer_p = reactions->buffer_p;
122   ecma_value_t *buffer_end_p = buffer_p + reactions->item_count;
123 
124   while (buffer_p < buffer_end_p)
125   {
126     ecma_value_t capability_with_tag = *buffer_p++;
127     ecma_object_t *capability_obj_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, capability_with_tag);
128     ecma_value_t capability = ecma_make_object_value (capability_obj_p);
129 
130     if (!is_reject)
131     {
132       ecma_value_t handler = ECMA_VALUE_TRUE;
133 
134       if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (capability_with_tag))
135       {
136         handler = *buffer_p++;
137       }
138 
139       ecma_enqueue_promise_reaction_job (capability, handler, value);
140     }
141     else if (JMEM_CP_GET_FIRST_BIT_FROM_POINTER_TAG (capability_with_tag))
142     {
143       buffer_p++;
144     }
145 
146     if (is_reject)
147     {
148       ecma_value_t handler = ECMA_VALUE_FALSE;
149 
150       if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (capability_with_tag))
151       {
152         handler = *buffer_p++;
153       }
154 
155       ecma_enqueue_promise_reaction_job (capability, handler, value);
156     }
157     else if (JMEM_CP_GET_SECOND_BIT_FROM_POINTER_TAG (capability_with_tag))
158     {
159       buffer_p++;
160     }
161   }
162 } /* ecma_promise_trigger_reactions */
163 
164 /**
165  * Checks whether a resolver is called before.
166  *
167  * @return true if it was called before, false otherwise
168  */
169 static bool
ecma_is_resolver_already_called(ecma_object_t * resolver_p,ecma_object_t * promise_obj_p)170 ecma_is_resolver_already_called (ecma_object_t *resolver_p, /**< resolver */
171                                  ecma_object_t *promise_obj_p) /**< promise */
172 {
173   ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED);
174   ecma_property_t *property_p = ecma_find_named_property (resolver_p, str_already_resolved_p);
175 
176   if (property_p == NULL)
177   {
178     return (ecma_promise_get_flags (promise_obj_p) & ECMA_PROMISE_ALREADY_RESOLVED) != 0;
179   }
180 
181   JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
182 
183   ecma_value_t already_resolved = ECMA_PROPERTY_VALUE_PTR (property_p)->value;
184   ecma_object_t *object_p = ecma_get_object_from_value (already_resolved);
185   JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_CLASS);
186 
187   ecma_extended_object_t *already_resolved_p = (ecma_extended_object_t *) object_p;
188   JERRY_ASSERT (already_resolved_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL);
189 
190   ecma_value_t current_value = already_resolved_p->u.class_prop.u.value;
191   already_resolved_p->u.class_prop.u.value = ECMA_VALUE_TRUE;
192 
193   return current_value == ECMA_VALUE_TRUE;
194 } /* ecma_is_resolver_already_called */
195 
196 /**
197  * Reject a Promise with a reason.
198  *
199  * See also: ES2015 25.4.1.7
200  */
201 static void
ecma_reject_promise(ecma_value_t promise,ecma_value_t reason)202 ecma_reject_promise (ecma_value_t promise, /**< promise */
203                      ecma_value_t reason) /**< reason for reject */
204 {
205   ecma_object_t *obj_p = ecma_get_object_from_value (promise);
206 
207   JERRY_ASSERT (ecma_promise_get_flags (obj_p) & ECMA_PROMISE_IS_PENDING);
208 
209   ecma_promise_set_state (obj_p, false);
210   ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (reason));
211   ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p;
212 
213   /* GC can be triggered by ecma_new_collection so freeing the collection
214      first and creating a new one might cause a heap after use event. */
215   ecma_collection_t *reactions = promise_p->reactions;
216 
217   /* Fulfill reactions will never be triggered. */
218   ecma_promise_trigger_reactions (reactions, reason, true);
219 
220   promise_p->reactions = ecma_new_collection ();
221 
222   ecma_collection_destroy (reactions);
223 } /* ecma_reject_promise */
224 
225 /**
226  * Fulfill a Promise with a value.
227  *
228  * See also: ES2015 25.4.1.4
229  */
230 static void
ecma_fulfill_promise(ecma_value_t promise,ecma_value_t value)231 ecma_fulfill_promise (ecma_value_t promise, /**< promise */
232                       ecma_value_t value) /**< fulfilled value */
233 {
234   ecma_object_t *obj_p = ecma_get_object_from_value (promise);
235 
236   JERRY_ASSERT (ecma_promise_get_flags (obj_p) & ECMA_PROMISE_IS_PENDING);
237 
238   ecma_promise_set_state (obj_p, true);
239   ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (value));
240   ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p;
241 
242   /* GC can be triggered by ecma_new_collection so freeing the collection
243      first and creating a new one might cause a heap after use event. */
244   ecma_collection_t *reactions = promise_p->reactions;
245 
246   /* Reject reactions will never be triggered. */
247   ecma_promise_trigger_reactions (reactions, value, false);
248 
249   promise_p->reactions = ecma_new_collection ();
250 
251   ecma_collection_destroy (reactions);
252 } /* ecma_fulfill_promise */
253 
254 /**
255  * Native handler for Promise Reject Function.
256  *
257  * See also: ES2015 25.4.1.3.1
258  *
259  * @return ecma value of undefined.
260  */
261 static ecma_value_t
ecma_promise_reject_handler(const ecma_value_t function,const ecma_value_t this,const ecma_value_t argv[],const ecma_length_t argc)262 ecma_promise_reject_handler (const ecma_value_t function, /**< the function itself */
263                              const ecma_value_t this, /**< this_arg of the function */
264                              const ecma_value_t argv[], /**< argument list */
265                              const ecma_length_t argc) /**< argument number */
266 {
267   JERRY_UNUSED (this);
268 
269   ecma_object_t *function_p = ecma_get_object_from_value (function);
270   /* 2. */
271   ecma_value_t promise = ecma_op_object_get_by_magic_id (function_p, LIT_INTERNAL_MAGIC_STRING_PROMISE);
272   /* 1. */
273   ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise);
274   JERRY_ASSERT (ecma_is_promise (promise_obj_p));
275 
276   /* 3., 4. */
277   if (!ecma_is_resolver_already_called (function_p, promise_obj_p))
278   {
279     /* 5. */
280     ((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_ALREADY_RESOLVED;
281 
282     /* 6. */
283     ecma_value_t reject_value = (argc == 0) ? ECMA_VALUE_UNDEFINED : argv[0];
284     ecma_reject_promise (promise, reject_value);
285   }
286 
287   ecma_free_value (promise);
288   return ECMA_VALUE_UNDEFINED;
289 } /* ecma_promise_reject_handler */
290 
291 /**
292  * Native handler for Promise Resolve Function.
293  *
294  * See also: ES2015 25.4.1.3.2
295  *
296  * @return ecma value of undefined.
297  */
298 static ecma_value_t
ecma_promise_resolve_handler(const ecma_value_t function,const ecma_value_t this,const ecma_value_t argv[],const ecma_length_t argc)299 ecma_promise_resolve_handler (const ecma_value_t function, /**< the function itself */
300                               const ecma_value_t this, /**< this_arg of the function */
301                               const ecma_value_t argv[], /**< argument list */
302                               const ecma_length_t argc) /**< argument number */
303 {
304   JERRY_UNUSED (this);
305 
306   ecma_object_t *function_p = ecma_get_object_from_value (function);
307   /* 2. */
308   ecma_value_t promise = ecma_op_object_get_by_magic_id (function_p, LIT_INTERNAL_MAGIC_STRING_PROMISE);
309   /* 1. */
310   ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise);
311   JERRY_ASSERT (ecma_is_promise (promise_obj_p));
312 
313   /* 3., 4. */
314   if (ecma_is_resolver_already_called (function_p, promise_obj_p))
315   {
316     goto end_of_resolve_function;
317   }
318 
319   /* 5. */
320   ((ecma_extended_object_t *) promise_obj_p)->u.class_prop.extra_info |= ECMA_PROMISE_ALREADY_RESOLVED;
321 
322   /* If the argc is 0, then fulfill the `undefined`. */
323   if (argc == 0)
324   {
325     ecma_fulfill_promise (promise, ECMA_VALUE_UNDEFINED);
326     goto end_of_resolve_function;
327   }
328 
329   /* 6. */
330   if (argv[0] == promise)
331   {
332     ecma_object_t *error_p = ecma_new_standard_error (ECMA_ERROR_TYPE);
333     ecma_reject_promise (promise, ecma_make_object_value (error_p));
334     ecma_deref_object (error_p);
335     goto end_of_resolve_function;
336   }
337 
338   /* 7. */
339   if (!ecma_is_value_object (argv[0]))
340   {
341     ecma_fulfill_promise (promise, argv[0]);
342     goto end_of_resolve_function;
343   }
344 
345   /* 8. */
346   ecma_value_t then = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (argv[0]),
347                                                       LIT_MAGIC_STRING_THEN);
348 
349   if (ECMA_IS_VALUE_ERROR (then))
350   {
351     /* 9. */
352     then = jcontext_take_exception ();
353     ecma_reject_promise (promise, then);
354   }
355   else if (!ecma_op_is_callable (then))
356   {
357     /* 11 .*/
358     ecma_fulfill_promise (promise, argv[0]);
359   }
360   else
361   {
362     /* 12 */
363     ecma_enqueue_promise_resolve_thenable_job (promise, argv[0], then);
364   }
365 
366   ecma_free_value (then);
367 
368 end_of_resolve_function:
369   ecma_free_value (promise);
370   return ECMA_VALUE_UNDEFINED;
371 } /* ecma_promise_resolve_handler */
372 
373 /**
374  * CapabilitiesExecutor Function.
375  *
376  * See also: ES2015 25.4.1.5.1
377  *
378  * @return ecma value of undefined or typerror.
379  *         Returned value must be freed with ecma_free_value
380  */
381 static ecma_value_t
ecma_call_builtin_executor(ecma_object_t * executor_p,ecma_value_t resolve_func,ecma_value_t reject_func)382 ecma_call_builtin_executor (ecma_object_t *executor_p, /**< the executor object */
383                             ecma_value_t resolve_func, /**< the resolve function */
384                             ecma_value_t reject_func) /**< the reject function */
385 {
386   ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
387   ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
388   ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
389 
390   /* 2. */
391   ecma_value_t capability = ecma_op_object_get (executor_p, capability_str_p);
392   /* 3. */
393   ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), resolve_str_p);
394 
395   if (resolve != ECMA_VALUE_UNDEFINED)
396   {
397     ecma_free_value (resolve);
398     ecma_free_value (capability);
399 
400     return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' function should be undefined."));
401   }
402 
403   /* 4. */
404   ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p);
405 
406   if (reject != ECMA_VALUE_UNDEFINED)
407   {
408     ecma_free_value (reject);
409     ecma_free_value (capability);
410 
411     return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' function should be undefined."));
412   }
413 
414   /* 5. */
415   ecma_op_object_put (ecma_get_object_from_value (capability),
416                       resolve_str_p,
417                       resolve_func,
418                       false);
419   /* 6. */
420   ecma_op_object_put (ecma_get_object_from_value (capability),
421                       reject_str_p,
422                       reject_func,
423                       false);
424 
425   ecma_free_value (capability);
426 
427   return ECMA_VALUE_UNDEFINED;
428 } /* ecma_call_builtin_executor */
429 
430 /**
431  * Helper function for PromiseCreateResovingFucntions.
432  *
433  * See also: ES2015 25.4.1.3 2. - 7.
434  *
435  * @return pointer to the resolving function
436  */
437 static ecma_value_t
ecma_promise_create_resolving_functions_helper(ecma_object_t * obj_p,ecma_external_handler_t handler_cb)438 ecma_promise_create_resolving_functions_helper (ecma_object_t *obj_p, /**< Promise Object */
439                                                 ecma_external_handler_t handler_cb) /**< Callback handler */
440 {
441   ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE);
442   ecma_object_t *func_obj_p = ecma_op_create_external_function_object (handler_cb);
443 
444   ecma_op_object_put (func_obj_p,
445                       str_promise_p,
446                       ecma_make_object_value (obj_p),
447                       false);
448 
449   return ecma_make_object_value (func_obj_p);
450 } /* ecma_promise_create_resolving_functions_helper */
451 
452 /**
453  * Create a PromiseCreateResovingFucntions.
454  *
455  * See also: ES2015 25.4.1.3
456  *
457  * @return pointer to the resolving functions
458  */
459 void
ecma_promise_create_resolving_functions(ecma_object_t * object_p,ecma_promise_resolving_functions_t * funcs,bool create_already_resolved)460 ecma_promise_create_resolving_functions (ecma_object_t *object_p, /**< the promise object */
461                                          ecma_promise_resolving_functions_t *funcs, /**< [out] resolving functions */
462                                          bool create_already_resolved) /**< create already resolved flag */
463 {
464   /* 2. - 4. */
465   funcs->resolve = ecma_promise_create_resolving_functions_helper (object_p,
466                                                                    ecma_promise_resolve_handler);
467 
468   /* 5. - 7. */
469   funcs->reject = ecma_promise_create_resolving_functions_helper (object_p,
470                                                                   ecma_promise_reject_handler);
471   if (!create_already_resolved)
472   {
473     return;
474   }
475 
476   ecma_value_t already_resolved = ecma_op_create_boolean_object (ECMA_VALUE_FALSE);
477   ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED);
478   ecma_property_value_t *value_p;
479 
480   value_p = ecma_create_named_data_property (ecma_get_object_from_value (funcs->resolve),
481                                              str_already_resolved_p,
482                                              ECMA_PROPERTY_FIXED,
483                                              NULL);
484   value_p->value = already_resolved;
485 
486   value_p = ecma_create_named_data_property (ecma_get_object_from_value (funcs->reject),
487                                              str_already_resolved_p,
488                                              ECMA_PROPERTY_FIXED,
489                                              NULL);
490   value_p->value = already_resolved;
491 
492   ecma_free_value (already_resolved);
493 } /* ecma_promise_create_resolving_functions */
494 
495 /**
496  * Free the heap and the member of the resolving functions.
497  */
498 void
ecma_promise_free_resolving_functions(ecma_promise_resolving_functions_t * funcs)499 ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs) /**< points to the functions */
500 {
501   ecma_free_value (funcs->resolve);
502   ecma_free_value (funcs->reject);
503 } /* ecma_promise_free_resolving_functions */
504 
505 /**
506  * Create a promise object.
507  *
508  * See also: ES2015 25.4.3.1
509  *
510  * @return ecma value of the new promise object
511  *         Returned value must be freed with ecma_free_value
512  */
513 ecma_value_t
ecma_op_create_promise_object(ecma_value_t executor,ecma_promise_executor_type_t type)514 ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function or object */
515                                ecma_promise_executor_type_t type) /**< indicates the type of executor */
516 {
517   JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != NULL);
518   /* 3. */
519   ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target),
520                                                                    ECMA_BUILTIN_ID_PROMISE_PROTOTYPE);
521 
522   if (JERRY_UNLIKELY (proto_p == NULL))
523   {
524     return ECMA_VALUE_ERROR;
525   }
526 
527   /* Calling ecma_new_collection might trigger a GC call, so this
528    * allocation is performed before the object is constructed. */
529   ecma_collection_t *reactions = ecma_new_collection ();
530 
531   ecma_object_t *object_p = ecma_create_object (proto_p,
532                                                 sizeof (ecma_promise_object_t),
533                                                 ECMA_OBJECT_TYPE_CLASS);
534   ecma_deref_object (proto_p);
535   ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
536   ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_PROMISE_UL;
537   /* 5 */
538   ext_object_p->u.class_prop.extra_info = ECMA_PROMISE_IS_PENDING;
539   ext_object_p->u.class_prop.u.value = ECMA_VALUE_UNDEFINED;
540   ecma_promise_object_t *promise_object_p = (ecma_promise_object_t *) object_p;
541 
542   /* 6-7. */
543   promise_object_p->reactions = reactions;
544   /* 8. */
545   ecma_promise_resolving_functions_t funcs;
546   ecma_promise_create_resolving_functions (object_p, &funcs, false);
547 
548   ecma_string_t *str_resolve_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION);
549   ecma_string_t *str_reject_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION);
550 
551   ecma_op_object_put (object_p,
552                       str_resolve_p,
553                       funcs.resolve,
554                       false);
555   ecma_op_object_put (object_p,
556                       str_reject_p,
557                       funcs.reject,
558                       false);
559 
560   /* 9. */
561   ecma_value_t completion = ECMA_VALUE_UNDEFINED;
562 
563   if (type == ECMA_PROMISE_EXECUTOR_FUNCTION)
564   {
565     JERRY_ASSERT (ecma_op_is_callable (executor));
566 
567     ecma_value_t argv[] = { funcs.resolve, funcs.reject };
568     completion = ecma_op_function_call (ecma_get_object_from_value (executor),
569                                         ECMA_VALUE_UNDEFINED,
570                                         argv,
571                                         2);
572   }
573   else if (type == ECMA_PROMISE_EXECUTOR_OBJECT)
574   {
575     JERRY_ASSERT (ecma_is_value_object (executor));
576 
577     completion = ecma_call_builtin_executor (ecma_get_object_from_value (executor),
578                                              funcs.resolve,
579                                              funcs.reject);
580   }
581   else
582   {
583     JERRY_ASSERT (type == ECMA_PROMISE_EXECUTOR_EMPTY);
584     JERRY_UNUSED (executor);
585   }
586 
587   ecma_value_t status = ECMA_VALUE_EMPTY;
588 
589   if (ECMA_IS_VALUE_ERROR (completion))
590   {
591     /* 10.a. */
592     completion = jcontext_take_exception ();
593     status = ecma_op_function_call (ecma_get_object_from_value (funcs.reject),
594                                     ECMA_VALUE_UNDEFINED,
595                                     &completion,
596                                     1);
597   }
598 
599   ecma_promise_free_resolving_functions (&funcs);
600   ecma_free_value (completion);
601 
602   /* 10.b. */
603   if (ECMA_IS_VALUE_ERROR (status))
604   {
605     ecma_deref_object (object_p);
606     return status;
607   }
608 
609   /* 11. */
610   ecma_free_value (status);
611 
612   return ecma_make_object_value (object_p);
613 } /* ecma_op_create_promise_object */
614 
615 /**
616  * 25.4.1.5.1 GetCapabilitiesExecutor Functions
617  *
618  * Checks and sets a promiseCapability's resolve and reject properties.
619  *
620  * @return ECMA_VALUE_UNDEFINED or TypeError
621  *         returned value must be freed with ecma_free_value
622  */
623 static 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)624 ecma_op_get_capabilities_executor_cb (const ecma_value_t function_obj, /**< the function itself */
625                                       const ecma_value_t this_val, /**< this_arg of the function */
626                                       const ecma_value_t args_p[], /**< argument list */
627                                       const ecma_length_t args_count) /**< argument number */
628 {
629   JERRY_UNUSED (this_val);
630   /* 1. */
631   ecma_value_t capability = ecma_op_object_get_by_magic_id (ecma_get_object_from_value (function_obj),
632                                                             LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
633   JERRY_ASSERT (ecma_is_value_object (capability));
634 
635   /* 2. */
636   ecma_object_t *capability_obj_p = ecma_get_object_from_value (capability);
637 
638   /* 3. */
639   ecma_value_t resolve = ecma_op_object_get_by_magic_id (capability_obj_p,
640                                                          LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
641 
642   if (!ecma_is_value_undefined (resolve))
643   {
644     ecma_free_value (resolve);
645     ecma_deref_object (capability_obj_p);
646 
647     return ecma_raise_type_error (ECMA_ERR_MSG ("Resolve must be undefined"));
648   }
649 
650   /* 4. */
651   ecma_value_t reject = ecma_op_object_get_by_magic_id (capability_obj_p,
652                                                         LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
653 
654   if (!ecma_is_value_undefined (reject))
655   {
656     ecma_free_value (reject);
657     ecma_deref_object (capability_obj_p);
658 
659     return ecma_raise_type_error (ECMA_ERR_MSG ("Reject must be undefined"));
660   }
661 
662   /* 5. */
663   ecma_op_object_put (capability_obj_p,
664                       ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE),
665                       args_count > 0 ? args_p[0] : ECMA_VALUE_UNDEFINED,
666                       false);
667 
668   /* 6. */
669   ecma_op_object_put (capability_obj_p,
670                       ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT),
671                       args_count > 1 ? args_p[1] : ECMA_VALUE_UNDEFINED,
672                       false);
673 
674   ecma_deref_object (capability_obj_p);
675 
676   /* 7. */
677   return ECMA_VALUE_UNDEFINED;
678 } /* ecma_op_get_capabilities_executor_cb */
679 
680 /**
681  * Create a new PromiseCapability.
682  *
683  * See also: ES2015 25.4.1.5
684  *
685  * @return ecma value of the new PromiseCapability
686  *         Returned value must be freed with ecma_free_value
687  */
688 ecma_value_t
ecma_promise_new_capability(ecma_value_t constructor)689 ecma_promise_new_capability (ecma_value_t constructor)
690 {
691   /* 1. */
692   if (!ecma_is_constructor (constructor))
693   {
694     return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid capability"));
695   }
696 
697   ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor);
698   /* 3. */
699   ecma_object_t *capability_p = ecma_op_create_object_object_noarg ();
700 
701   ecma_string_t *capability_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_CAPABILITY);
702   ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
703   /* 4. */
704   ecma_object_t *executor_p = ecma_op_create_external_function_object (ecma_op_get_capabilities_executor_cb);
705   ecma_value_t executor = ecma_make_object_value (executor_p);
706   /* 5. */
707   ecma_op_object_put (executor_p,
708                       capability_str_p,
709                       ecma_make_object_value (capability_p),
710                       false);
711 
712   /* 6. */
713   ecma_value_t promise = ecma_op_function_construct (constructor_obj_p,
714                                                      constructor_obj_p,
715                                                      &executor,
716                                                      1);
717   ecma_deref_object (executor_p);
718 
719   /* 7. */
720   if (ECMA_IS_VALUE_ERROR (promise))
721   {
722     ecma_deref_object (capability_p);
723     return promise;
724   }
725 
726   /* 10. */
727   ecma_op_object_put (capability_p,
728                       promise_str_p,
729                       promise,
730                       false);
731 
732   ecma_free_value (promise);
733 
734   /* 8. */
735   ecma_string_t *resolve_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
736   ecma_value_t resolve = ecma_op_object_get (capability_p, resolve_str_p);
737 
738   if (!ecma_op_is_callable (resolve))
739   {
740     ecma_free_value (resolve);
741     ecma_deref_object (capability_p);
742     return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' parameter must be callable."));
743   }
744 
745   ecma_free_value (resolve);
746   /* 9. */
747   ecma_string_t *reject_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
748   ecma_value_t reject = ecma_op_object_get (capability_p, reject_str_p);
749 
750   if (!ecma_op_is_callable (reject))
751   {
752     ecma_free_value (reject);
753     ecma_deref_object (capability_p);
754     return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' parameter must be callable."));
755   }
756 
757   ecma_free_value (reject);
758   /* 11. */
759   return ecma_make_object_value (capability_p);
760 } /* ecma_promise_new_capability */
761 
762 /**
763  * The common function for 'reject' and 'resolve'.
764  *
765  * @return ecma value
766  *         Returned value must be freed with ecma_free_value.
767  */
768 ecma_value_t
ecma_promise_reject_or_resolve(ecma_value_t this_arg,ecma_value_t value,bool is_resolve)769 ecma_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argument */
770                                 ecma_value_t value, /**< rejected or resolved value */
771                                 bool is_resolve) /**< the operation is resolve */
772 {
773   if (!ecma_is_value_object (this_arg))
774   {
775     return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object."));
776   }
777 
778   if (is_resolve
779       && ecma_is_value_object (value)
780       && ecma_is_promise (ecma_get_object_from_value (value)))
781   {
782     ecma_object_t *object_p = ecma_get_object_from_value (value);
783     ecma_value_t constructor = ecma_op_object_get_by_magic_id (object_p, LIT_MAGIC_STRING_CONSTRUCTOR);
784 
785     if (ECMA_IS_VALUE_ERROR (constructor))
786     {
787       return constructor;
788     }
789 
790     /* The this_arg must be an object. */
791     bool is_same_value = (constructor == this_arg);
792     ecma_free_value (constructor);
793 
794     if (is_same_value)
795     {
796       return ecma_copy_value (value);
797     }
798   }
799 
800   ecma_value_t capability = ecma_promise_new_capability (this_arg);
801 
802   if (ECMA_IS_VALUE_ERROR (capability))
803   {
804     return capability;
805   }
806 
807   ecma_string_t *property_str_p;
808 
809   if (is_resolve)
810   {
811     property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE);
812   }
813   else
814   {
815     property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT);
816   }
817 
818   ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), property_str_p);
819 
820   ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (func),
821                                                  ECMA_VALUE_UNDEFINED,
822                                                  &value,
823                                                  1);
824 
825   ecma_free_value (func);
826 
827   if (ECMA_IS_VALUE_ERROR (call_ret))
828   {
829     return call_ret;
830   }
831 
832   ecma_free_value (call_ret);
833 
834   ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
835   ecma_value_t promise = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p);
836   ecma_free_value (capability);
837 
838   return promise;
839 } /* ecma_promise_reject_or_resolve */
840 
841 /**
842  * It performs the "then" operation on promiFulfilled
843  * and onRejected as its settlement actions.
844  *
845  * See also: 25.4.5.3.1
846  *
847  * @return ecma value of the new promise object
848  *         Returned value must be freed with ecma_free_value
849  */
850 static ecma_value_t
ecma_promise_do_then(ecma_value_t promise,ecma_value_t on_fulfilled,ecma_value_t on_rejected,ecma_value_t result_capability)851 ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' */
852                       ecma_value_t on_fulfilled, /**< on_fulfilled function */
853                       ecma_value_t on_rejected, /**< on_rejected function */
854                       ecma_value_t result_capability) /**< promise capability */
855 {
856   ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE);
857 
858   /* 3. boolean true indicates "indentity" */
859   if (!ecma_op_is_callable (on_fulfilled))
860   {
861     on_fulfilled = ECMA_VALUE_TRUE;
862   }
863 
864   /* 4. boolean false indicates "thrower" */
865   if (!ecma_op_is_callable (on_rejected))
866   {
867     on_rejected = ECMA_VALUE_FALSE;
868   }
869 
870   ecma_object_t *promise_obj_p = ecma_get_object_from_value (promise);
871   ecma_promise_object_t *promise_p = (ecma_promise_object_t *) promise_obj_p;
872 
873   uint16_t flags = ecma_promise_get_flags (promise_obj_p);
874 
875   if (flags & ECMA_PROMISE_IS_PENDING)
876   {
877     /* 7. */
878     ecma_value_t capability_with_tag;
879     ECMA_SET_NON_NULL_POINTER_TAG (capability_with_tag, ecma_get_object_from_value (result_capability), 0);
880 
881     if (on_fulfilled != ECMA_VALUE_TRUE)
882     {
883       ECMA_SET_FIRST_BIT_TO_POINTER_TAG (capability_with_tag);
884     }
885 
886     if (on_rejected != ECMA_VALUE_FALSE)
887     {
888       ECMA_SET_SECOND_BIT_TO_POINTER_TAG (capability_with_tag);
889     }
890 
891     ecma_collection_push_back (promise_p->reactions, capability_with_tag);
892 
893     if (on_fulfilled != ECMA_VALUE_TRUE)
894     {
895       ecma_collection_push_back (promise_p->reactions, on_fulfilled);
896     }
897 
898     if (on_rejected != ECMA_VALUE_FALSE)
899     {
900       ecma_collection_push_back (promise_p->reactions, on_rejected);
901     }
902   }
903   else if (flags & ECMA_PROMISE_IS_FULFILLED)
904   {
905     /* 8. */
906     ecma_value_t value = ecma_promise_get_result (promise_obj_p);
907     ecma_enqueue_promise_reaction_job (result_capability, on_fulfilled, value);
908     ecma_free_value (value);
909   }
910   else
911   {
912     /* 9. */
913     ecma_value_t reason = ecma_promise_get_result (promise_obj_p);
914     ecma_enqueue_promise_reaction_job (result_capability, on_rejected, reason);
915     ecma_free_value (reason);
916   }
917 
918   /* 10. */
919   return ecma_op_object_get (ecma_get_object_from_value (result_capability), promise_str_p);
920 } /* ecma_promise_do_then */
921 
922 /**
923  * The common function for ecma_builtin_promise_prototype_then
924  * and ecma_builtin_promise_prototype_catch.
925  *
926  * @return ecma value of a new promise object.
927  *         Returned value must be freed with ecma_free_value.
928  */
929 ecma_value_t
ecma_promise_then(ecma_value_t promise,ecma_value_t on_fulfilled,ecma_value_t on_rejected)930 ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */
931                    ecma_value_t on_fulfilled, /**< on_fulfilled function */
932                    ecma_value_t on_rejected) /**< on_rejected function */
933 {
934   if (!ecma_is_value_object (promise))
935   {
936     return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object."));
937   }
938 
939   ecma_object_t *obj = ecma_get_object_from_value (promise);
940 
941   if (!ecma_is_promise (obj))
942   {
943     return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a Promise."));
944   }
945 
946   ecma_value_t species = ecma_op_species_constructor (obj, ECMA_BUILTIN_ID_PROMISE);
947   if (ECMA_IS_VALUE_ERROR (species))
948   {
949     return species;
950   }
951 
952   ecma_value_t result_capability = ecma_promise_new_capability (species);
953   ecma_free_value (species);
954 
955   if (ECMA_IS_VALUE_ERROR (result_capability))
956   {
957     return result_capability;
958   }
959 
960   ecma_value_t ret = ecma_promise_do_then (promise, on_fulfilled, on_rejected, result_capability);
961   ecma_free_value (result_capability);
962 
963   return ret;
964 } /* ecma_promise_then */
965 
966 /**
967  * @}
968  * @}
969  */
970 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
971