From eb8dd4602b981d1b9c490536df431d5d9b612b1e Mon Sep 17 00:00:00 2001 From: Zidong Jiang Date: Wed, 12 Apr 2017 22:10:08 +0800 Subject: [PATCH] Implement the basic Promise (#1695) Implement the Promise Constructor and routine: 'then' JerryScript-DCO-1.0-Signed-off-by: Zidong Jiang zidong.jiang@intel.com --- jerry-core/ecma/base/ecma-gc.c | 55 +- .../builtin-objects/ecma-builtin-global.inc.h | 6 + .../ecma-builtin-promise-prototype.c | 79 ++ .../ecma-builtin-promise-prototype.inc.h | 31 + .../builtin-objects/ecma-builtin-promise.c | 83 ++ .../ecma-builtin-promise.inc.h | 39 + .../ecma/builtin-objects/ecma-builtins.inc.h | 18 + jerry-core/ecma/operations/ecma-jobqueue.c | 248 +++++- jerry-core/ecma/operations/ecma-jobqueue.h | 3 + .../ecma/operations/ecma-promise-object.c | 718 ++++++++++++++++++ .../ecma/operations/ecma-promise-object.h | 83 ++ jerry-core/jerry-port.h | 2 + jerry-core/lit/lit-magic-strings.h | 10 +- jerry-core/lit/lit-magic-strings.inc.h | 2 + jerry-main/main-unix.c | 24 + targets/default/jerry-port-default-jobqueue.c | 30 +- targets/default/jerry-port-default.h | 4 +- .../es2015/25/25.04/25.04.03/25.04.03-001.js | 20 + .../es2015/25/25.04/25.04.03/25.04.03-002.js | 50 ++ .../es2015/25/25.04/25.04.04/25.04.04-001.js | 16 + .../es2015/25/25.04/25.04.04/25.04.04-002.js | 36 + .../es2015/25/25.04/25.04.04/25.04.04-003.js | 36 + .../es2015/25/25.04/25.04.04/25.04.04-004.js | 26 + 23 files changed, 1579 insertions(+), 40 deletions(-) create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-promise.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h create mode 100644 jerry-core/ecma/operations/ecma-promise-object.c create mode 100644 jerry-core/ecma/operations/ecma-promise-object.h create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.03/25.04.03-001.js create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.03/25.04.03-002.js create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-001.js create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-002.js create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-003.js create mode 100644 tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-004.js diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 976b7e168..77269092e 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -34,6 +34,9 @@ #ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN #include "ecma-typedarray-object.h" #endif +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN +#include "ecma-promise-object.h" +#endif #define JERRY_INTERNAL #include "jerry-internal.h" @@ -177,7 +180,7 @@ ecma_gc_mark_property (ecma_property_pair_t *property_pair_p, /**< property pair case ECMA_PROPERTY_TYPE_NAMEDDATA: { if (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_STRING_CONTAINER_MAGIC_STRING - && property_pair_p->names_cp[index] >= LIT_NON_INTERNAL_MAGIC_STRING__COUNT) + && property_pair_p->names_cp[index] >= LIT_NEED_MARK_MAGIC_STRING__COUNT) { break; } @@ -260,6 +263,41 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ switch (ecma_get_object_type (object_p)) { +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + case ECMA_OBJECT_TYPE_CLASS: + { + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + + if (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_PROMISE_UL) + { + /* Mark promise result. */ + ecma_value_t result = ext_object_p->u.class_prop.u.value; + + if (ecma_is_value_object (result)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (result), true); + } + + /* Mark all reactions. */ + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, ((ecma_promise_object_t *) ext_object_p)->fulfill_reactions); + + while (ecma_collection_iterator_next (&iter)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (*iter.current_value_p), true); + } + + ecma_collection_iterator_init (&iter, ((ecma_promise_object_t *) ext_object_p)->reject_reactions); + + while (ecma_collection_iterator_next (&iter)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (*iter.current_value_p), true); + } + } + + break; + } +#endif /*! CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; @@ -274,14 +312,14 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ ecma_gc_set_object_visited (lex_env_p, true); break; } - #ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN case ECMA_PSEUDO_ARRAY_TYPEDARRAY: case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO: { ecma_gc_set_object_visited (ecma_typedarray_get_arraybuffer (object_p), true); break; } - #endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ default: { JERRY_UNREACHABLE (); @@ -528,7 +566,18 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p, size); return; } + #endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + case LIT_MAGIC_STRING_PROMISE_UL: + { + ecma_free_value_if_not_object (ext_object_p->u.class_prop.u.value); + ecma_free_values_collection (((ecma_promise_object_t *) object_p)->fulfill_reactions, false); + ecma_free_values_collection (((ecma_promise_object_t *) object_p)->reject_reactions, false); + ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p, sizeof (ecma_promise_object_t)); + return; + } +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ default: { JERRY_UNREACHABLE (); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h index f4b2e8363..724098d53 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h @@ -191,6 +191,12 @@ OBJECT_VALUE (LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) #endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN +OBJECT_VALUE (LIT_MAGIC_STRING_PROMISE_UL, + ECMA_BUILTIN_ID_PROMISE, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ + /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.c new file mode 100644 index 000000000..caefd386b --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.c @@ -0,0 +1,79 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-exceptions.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-promise-object.h" + +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-promise-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID promise_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup promiseprototype ECMA Promise.prototype object built-in + * @{ + */ + +/** + * Promise routine: then. + * + * See also: 25.4.5.3 + * + * @return ecma value of a new promise object + * Returned value must be freed with ecma_free_value + */ +static ecma_value_t +ecma_builtin_promise_prototype_then (ecma_value_t this_arg, /**< this argument */ + ecma_value_t on_fulfilled, /**< on_fulfilled function */ + ecma_value_t on_rejected) /**< on_rejected function */ +{ + ecma_object_t *obj = ecma_get_object_from_value (this_arg); + + if (!ecma_is_promise (obj)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not a Promise.")); + } + + ecma_value_t result_capability = ecma_promise_new_capability (); + + if (ECMA_IS_VALUE_ERROR (result_capability)) + { + return result_capability; + } + + ecma_value_t ret = ecma_promise_then (this_arg, on_fulfilled, on_rejected, result_capability); + ecma_free_value (result_capability); + + return ret; +} /* ecma_builtin_promise_prototype_then */ + +/** + * @} + * @} + * @} + */ + +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h new file mode 100644 index 000000000..2ff629068 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise-prototype.inc.h @@ -0,0 +1,31 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +/* Object properties: + * (property name, object pointer getter) */ + +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_PROMISE, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) + +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 1, + ECMA_PROPERTY_FLAG_WRITABLE) + +ROUTINE (LIT_MAGIC_STRING_THEN, ecma_builtin_promise_prototype_then, 2, 2) + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c new file mode 100644 index 000000000..47a6bf2b8 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c @@ -0,0 +1,83 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-exceptions.h" +#include "ecma-function-object.h" +#include "ecma-globals.h" +#include "ecma-promise-object.h" + +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-promise.inc.h" +#define BUILTIN_UNDERSCORED_ID promise +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup promise ECMA Promise object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in Promise object. + * + * ES2015 25.4.3 Promise is not intended to be called + * as a function and will throw an exception when called + * in that manner. + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_promise_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor Promise requires 'new'.")); +} /* ecma_builtin_promise_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in Promise object. + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_promise_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + if (arguments_list_len == 0 || !ecma_op_is_callable (arguments_list_p[0])) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("First parameter must be callable.")); + } + + return ecma_op_create_promise_object (arguments_list_p[0], true); +} /* ecma_builtin_promise_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h new file mode 100644 index 000000000..9e77f1e7e --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.inc.h @@ -0,0 +1,39 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Promose built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +/* Number properties: + * (property name, number value, writable, enumerable, configurable) */ + +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 1, + ECMA_PROPERTY_FIXED) + +/* Object properties: + * (property name, object pointer getter) */ + +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_PROMISE_PROTOTYPE, + ECMA_PROPERTY_FIXED) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h index 4629f881c..fdc68eb7c 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -462,6 +462,24 @@ BUILTIN (ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY, #endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + +BUILTIN (ECMA_BUILTIN_ID_PROMISE_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + true, + promise_prototype) + +BUILTIN (ECMA_BUILTIN_ID_PROMISE, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + true, + promise) + +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ + /* The Global object (15.1) */ BUILTIN (ECMA_BUILTIN_ID_GLOBAL, ECMA_OBJECT_TYPE_GENERAL, diff --git a/jerry-core/ecma/operations/ecma-jobqueue.c b/jerry-core/ecma/operations/ecma-jobqueue.c index b4dc230b8..1d13457ae 100644 --- a/jerry-core/ecma/operations/ecma-jobqueue.c +++ b/jerry-core/ecma/operations/ecma-jobqueue.c @@ -13,9 +13,12 @@ * limitations under the License. */ +#include "ecma-function-object.h" #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-jobqueue.h" +#include "ecma-objects.h" +#include "ecma-promise-object.h" #include "jerry-port.h" #ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN @@ -28,26 +31,243 @@ */ /** - * The processor for PromiseReactionJob + * Description of the PromiseReactionJob */ -static ecma_value_t __attribute__ ((unused)) -ecma_job_process_promise_reaction_job (void *job_p) /**< the job to be operated */ +typedef struct { - JERRY_UNUSED (job_p); - /** TODO: implement the function body */ - return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); -} /* ecma_job_process_promise_reaction_job */ + ecma_value_t reaction; /**< the PromiseReaction */ + ecma_value_t argument; /**< argument for the reaction */ +} ecma_job_promise_reaction_t; /** - * The processor for PromiseResolveThenableJob + * Description of the PromiseResolveThenableJob */ -static ecma_value_t __attribute__ ((unused)) -ecma_job_process_promise_thenable_job (void *job_p) /**< the job to be operated */ +typedef struct { - JERRY_UNUSED (job_p); - /** TODO: implement the function body */ - return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); -} /* ecma_job_process_promise_thenable_job */ + ecma_value_t promise; /**< promise to be resolved */ + ecma_value_t thenable; /**< thenbale object */ + ecma_value_t then; /** 'then' function */ +} ecma_job_promise_resolve_thenable_t; + +/** + * Create a PromiseReactionJob. + * + * @return pointer to the PromiseReactionJob + */ +static ecma_job_promise_reaction_t * +ecma_create_promise_reaction_job (ecma_value_t reaction, /**< PromiseReaction */ + ecma_value_t argument) /**< argument for the reaction */ +{ + JERRY_ASSERT (ecma_is_value_object (reaction)); + + ecma_job_promise_reaction_t *job_p; + job_p = (ecma_job_promise_reaction_t *) jmem_heap_alloc_block (sizeof (ecma_job_promise_reaction_t)); + job_p->reaction = ecma_copy_value (reaction); + job_p->argument = ecma_copy_value (argument); + + return job_p; +} /* ecma_create_promise_reaction_job */ + +/** + * Free the heap and the member of the PromiseReactionJob. + */ +static void +ecma_free_promise_reaction_job (ecma_job_promise_reaction_t *job_p) /**< points to the PromiseReactionJob */ +{ + JERRY_ASSERT (job_p != NULL); + + ecma_free_value (job_p->reaction); + ecma_free_value (job_p->argument); + + jmem_heap_free_block (job_p, sizeof (ecma_job_promise_reaction_t)); +} /* ecma_free_promise_reaction_job */ + +/** + * Create a PromiseResolveThenableJob + * + * @return pointer to the PromiseResolveThenableJob + */ +static ecma_job_promise_resolve_thenable_t * +ecma_create_promise_resolve_thenable_job (ecma_value_t promise, /**< promise to be resolved */ + ecma_value_t thenable, /**< thenable object */ + ecma_value_t then) /**< 'then' function */ +{ + JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); + JERRY_ASSERT (ecma_is_value_object (thenable)); + JERRY_ASSERT (ecma_op_is_callable (then)); + + ecma_job_promise_resolve_thenable_t *job_p; + job_p = (ecma_job_promise_resolve_thenable_t *) jmem_heap_alloc_block (sizeof (ecma_job_promise_resolve_thenable_t)); + + job_p->promise = ecma_copy_value (promise); + job_p->thenable = ecma_copy_value (thenable); + job_p->then = ecma_copy_value (then); + + return job_p; +} /* ecma_create_promise_resolve_thenable_job */ + +/** + * Free the heap and the member of the PromiseResolveThenableJob. + */ +static void +ecma_free_promise_resolve_thenable_job (ecma_job_promise_resolve_thenable_t *job_p) /**< points to the + * PromiseResolveThenableJob */ +{ + JERRY_ASSERT (job_p != NULL); + + ecma_free_value (job_p->promise); + ecma_free_value (job_p->thenable); + ecma_free_value (job_p->then); + + jmem_heap_free_block (job_p, sizeof (ecma_job_promise_resolve_thenable_t)); +} /* ecma_free_promise_resolve_thenable_job */ + +/** + * The processor for PromiseReactionJob. + * + * See also: ES2015 25.4.2.1 + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +static ecma_value_t +ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ +{ + ecma_job_promise_reaction_t *job_p = (ecma_job_promise_reaction_t *) obj_p; + ecma_object_t *reaction_p = ecma_get_object_from_value (job_p->reaction); + + ecma_string_t *str_0 = ecma_new_ecma_string_from_uint32 (0); + ecma_string_t *str_1 = ecma_new_ecma_string_from_uint32 (1); + ecma_string_t *str_2 = ecma_new_ecma_string_from_uint32 (2); + /* 2. string '0' indicates the [[Capability]] of reaction. */ + ecma_value_t capability = ecma_op_object_get (reaction_p, str_0); + /* 3. string '1' indicates the [[Handler]] of reaction. */ + ecma_value_t handler = ecma_op_object_get (reaction_p, str_1); + + JERRY_ASSERT (ecma_is_value_boolean (handler) || ecma_op_is_callable (handler)); + + ecma_value_t handler_result; + + if (ecma_is_value_boolean (handler)) + { + /* 4-5. True indicates "identity" and false indicates "thrower" */ + handler_result = ecma_copy_value (job_p->argument); + } + else + { + /* 6. */ + handler_result = ecma_op_function_call (ecma_get_object_from_value (handler), + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + &(job_p->argument), + 1); + } + + ecma_value_t status; + + if (ecma_is_value_false (handler) || ECMA_IS_VALUE_ERROR (handler_result)) + { + /* 7. String '2' indicates [[Reject]] of Capability. */ + handler_result = ecma_get_value_from_error_value (handler_result); + ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_2); + + JERRY_ASSERT (ecma_op_is_callable (reject)); + + status = ecma_op_function_call (ecma_get_object_from_value (reject), + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + &handler_result, + 1); + ecma_free_value (reject); + } + else + { + /* 8. String '1' indicates [[Resolve]] of Capability. */ + ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), str_1); + + JERRY_ASSERT (ecma_op_is_callable (resolve)); + + status = ecma_op_function_call (ecma_get_object_from_value (resolve), + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + &handler_result, + 1); + ecma_free_value (resolve); + } + + ecma_free_value (handler_result); + ecma_free_value (handler); + ecma_free_value (capability); + ecma_deref_ecma_string (str_0); + ecma_deref_ecma_string (str_1); + ecma_deref_ecma_string (str_2); + ecma_free_promise_reaction_job (job_p); + + return status; +} /* ecma_process_promise_reaction_job */ + +/** + * Process the PromiseResolveThenableJob. + * + * See also: ES2015 25.4.2.2 + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +static ecma_value_t +ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be operated */ +{ + ecma_job_promise_resolve_thenable_t *job_p = (ecma_job_promise_resolve_thenable_t *) obj_p; + ecma_object_t *promise_p = ecma_get_object_from_value (job_p->promise); + ecma_promise_resolving_functions_t *funcs; + funcs = ecma_promise_create_resolving_functions (promise_p); + + ecma_value_t argv[] = { funcs->resolve, funcs->reject }; + ecma_value_t ret; + ecma_value_t then_call_result = ecma_op_function_call (ecma_get_object_from_value (job_p->then), + job_p->thenable, + argv, + 2); + + ret = then_call_result; + + if (ECMA_IS_VALUE_ERROR (then_call_result)) + { + ret = ecma_op_function_call (ecma_get_object_from_value (funcs->reject), + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + &then_call_result, + 1); + + ecma_free_value (then_call_result); + } + + ecma_promise_free_resolving_functions (funcs); + ecma_free_promise_resolve_thenable_job (job_p); + + return ret; +} /* ecma_process_promise_resolve_thenable_job */ + +/** + * Enqueue a PromiseReactionJob into a jobqueue. + */ +void +ecma_enqueue_promise_reaction_job (ecma_value_t reaction, /**< PromiseReaction */ + ecma_value_t argument) /**< argument for the reaction */ +{ + ecma_job_promise_reaction_t *job_p = ecma_create_promise_reaction_job (reaction, argument); + jerry_port_jobqueue_enqueue (ecma_process_promise_reaction_job, job_p); +} /* ecma_enqueue_promise_reaction_job */ + +/** + * Enqueue a PromiseResolveThenableJob into a jobqueue. + */ +void +ecma_enqueue_promise_resolve_thenable_job (ecma_value_t promise, /**< promise to be resolved */ + ecma_value_t thenable, /**< thenable object */ + ecma_value_t then) /**< 'then' function */ +{ + ecma_job_promise_resolve_thenable_t *job_p = ecma_create_promise_resolve_thenable_job (promise, + thenable, + then); + jerry_port_jobqueue_enqueue (ecma_process_promise_resolve_thenable_job, job_p); +} /* ecma_enqueue_promise_resolve_thenable_job */ /** * @} diff --git a/jerry-core/ecma/operations/ecma-jobqueue.h b/jerry-core/ecma/operations/ecma-jobqueue.h index 6464503e9..41f61585a 100644 --- a/jerry-core/ecma/operations/ecma-jobqueue.h +++ b/jerry-core/ecma/operations/ecma-jobqueue.h @@ -25,6 +25,9 @@ * @{ */ +void ecma_enqueue_promise_reaction_job (ecma_value_t reaction, ecma_value_t argument); +void ecma_enqueue_promise_resolve_thenable_job (ecma_value_t promise, ecma_value_t thenable, ecma_value_t then); + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-promise-object.c b/jerry-core/ecma/operations/ecma-promise-object.c new file mode 100644 index 000000000..9e67f0051 --- /dev/null +++ b/jerry-core/ecma/operations/ecma-promise-object.c @@ -0,0 +1,718 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-boolean-object.h" +#include "ecma-builtins.h" +#include "ecma-exceptions.h" +#include "ecma-function-object.h" +#include "ecma-gc.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-jobqueue.h" +#include "ecma-objects.h" +#include "ecma-objects-general.h" +#include "ecma-promise-object.h" + +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmapromiseobject ECMA Promise object related routines + * @{ + */ + +/** + * Check if an object is promise. + * + * @return true - if the object is a promise. + * false - otherwise. + */ +inline bool __attr_always_inline___ +ecma_is_promise (ecma_object_t *obj_p) /**< points to object */ +{ + return ecma_object_class_is (obj_p, LIT_MAGIC_STRING_PROMISE_UL); +} /* ecma_is_promise */ + +/** + * Get the result of the promise. + * + * @return ecma value of the promise result. + * Returned value must be freed with ecma_free_value + */ +inline ecma_value_t +ecma_promise_get_result (ecma_object_t *obj_p) /**< points to promise object */ +{ + JERRY_ASSERT (ecma_is_promise (obj_p)); + + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; + + return ecma_copy_value (ext_object_p->u.class_prop.u.value); +} /* ecma_promise_get_result */ + +/** + * Set the PromiseResult of promise. + */ +inline void __attr_always_inline___ +ecma_promise_set_result (ecma_object_t *obj_p, /**< points to promise object */ + ecma_value_t result) /**< the result value */ +{ + JERRY_ASSERT (ecma_is_promise (obj_p)); + + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; + + JERRY_ASSERT (ext_object_p->u.class_prop.u.value == ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)); + + ext_object_p->u.class_prop.u.value = result; +} /* ecma_promise_set_result */ + +/** + * Get the PromiseState of promise. + * + * @return the state's enum value + */ +inline uint8_t __attr_always_inline___ +ecma_promise_get_state (ecma_object_t *obj_p) /**< points to promise object */ +{ + JERRY_ASSERT (ecma_is_promise (obj_p)); + + return ((ecma_promise_object_t *) obj_p)->state; +} /* ecma_promise_get_state */ + +/** + * Set the PromiseState of promise. + */ +inline void __attr_always_inline___ +ecma_promise_set_state (ecma_object_t *obj_p, /**< points to promise object */ + uint8_t state) /**< the state */ +{ + JERRY_ASSERT (ecma_is_promise (obj_p)); + + ((ecma_promise_object_t *) obj_p)->state = state; +} /* ecma_promise_set_state */ + +/** + * Get the bool value of alreadyResolved. + * + * @return bool value of alreadyResolved. + */ +static bool +ecma_get_already_resolved_bool_value (ecma_value_t already_resolved) /**< the alreadyResolved */ +{ + JERRY_ASSERT (ecma_is_value_object (already_resolved)); + + ecma_object_t *already_resolved_p = ecma_get_object_from_value (already_resolved); + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) already_resolved_p; + + JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL); + + return ext_object_p->u.class_prop.u.value == ecma_make_boolean_value (true); +} /* ecma_get_already_resolved_bool_value */ + +/** + * Set the value of alreadyResolved. + */ +static void +ecma_set_already_resolved_value (ecma_value_t already_resolved, /**< the alreadyResolved */ + bool value) /**< the value to set */ +{ + JERRY_ASSERT (ecma_is_value_object (already_resolved)); + + ecma_object_t *already_resolved_p = ecma_get_object_from_value (already_resolved); + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) already_resolved_p; + + JERRY_ASSERT (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_BOOLEAN_UL); + + ext_object_p->u.class_prop.u.value = ecma_make_boolean_value (value); +} /* ecma_set_already_resolved_value */ + +/** + * Take a collection of Reactions and enqueue a new PromiseReactionJob for each Reaction. + * + * See also: ES2015 25.4.1.8 + */ +static void +ecma_promise_trigger_reactions (ecma_collection_header_t *reactions, /**< lists of reactions */ + ecma_value_t value) /**< value for resolve or reject */ +{ + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, reactions); + + while (ecma_collection_iterator_next (&iter)) + { + ecma_enqueue_promise_reaction_job (*iter.current_value_p, value); + } + + ecma_free_values_collection (reactions, false); +} /* ecma_promise_trigger_reactions */ + +/** + * Reject a Promise with a reason. + * + * See also: ES2015 25.4.1.7 + */ +static void +ecma_reject_promise (ecma_value_t promise, /**< promise */ + ecma_value_t reason) /**< reason for reject */ +{ + ecma_object_t *obj_p = ecma_get_object_from_value (promise); + + JERRY_ASSERT (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_PENDING); + + ecma_promise_set_state (obj_p, ECMA_PROMISE_STATE_REJECTED); + ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (reason)); + ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; + ecma_promise_trigger_reactions (promise_p->reject_reactions, reason); + promise_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); + /* Free all fullfill_reactions. */ + ecma_free_values_collection (promise_p->fulfill_reactions, false); + promise_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); +} /* ecma_reject_promise */ + +/** + * Fulfill a Promise with a value. + * + * See also: ES2015 25.4.1.4 + */ +static void +ecma_fulfill_promise (ecma_value_t promise, /**< promise */ + ecma_value_t value) /**< fulfilled value */ +{ + ecma_object_t *obj_p = ecma_get_object_from_value (promise); + + JERRY_ASSERT (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_PENDING); + + ecma_promise_set_state (obj_p, ECMA_PROMISE_STATE_FULFILLED); + ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (value)); + ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; + ecma_promise_trigger_reactions (promise_p->fulfill_reactions, value); + promise_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); + /* Free all reject_reactions. */ + ecma_free_values_collection (promise_p->reject_reactions, false); + promise_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); +} /* ecma_fulfill_promise */ + +/** + * Native handler for Promise Reject Function. + * + * See also: ES2015 25.4.1.3.1 + * + * @return ecma value of undefined. + */ +static ecma_value_t +ecma_promise_reject_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); + + ecma_string_t str_promise; + ecma_string_t str_already_resolved; + ecma_init_ecma_magic_string (&str_promise, LIT_INTERNAL_MAGIC_STRING_PROMISE); + ecma_init_ecma_magic_string (&str_already_resolved, LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + ecma_object_t *function_p = ecma_get_object_from_value (function); + /* 2. */ + ecma_value_t promise = ecma_op_object_get (function_p, &str_promise); + /* 1. */ + JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); + /* 3. */ + ecma_value_t already_resolved = ecma_op_object_get (function_p, &str_already_resolved); + + /* 4. */ + if (ecma_get_already_resolved_bool_value (already_resolved)) + { + ecma_free_value (promise); + ecma_free_value (already_resolved); + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + } + + /* 5. */ + ecma_set_already_resolved_value (already_resolved, true); + /* 6. */ + ecma_reject_promise (promise, argv[0]); + ecma_free_value (promise); + ecma_free_value (already_resolved); + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); +} /* ecma_promise_reject_handler */ + +/** + * Native handler for Promise Resolve Function. + * + * See also: ES2015 25.4.1.3.2 + * + * @return ecma value of undefined. + */ +static ecma_value_t +ecma_promise_resolve_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); + + ecma_string_t str_promise; + ecma_string_t str_already_resolved; + ecma_init_ecma_magic_string (&str_promise, LIT_INTERNAL_MAGIC_STRING_PROMISE); + ecma_init_ecma_magic_string (&str_already_resolved, LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + ecma_object_t *function_p = ecma_get_object_from_value (function); + /* 2. */ + ecma_value_t promise = ecma_op_object_get (function_p, &str_promise); + /* 1. */ + JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); + /* 3. */ + ecma_value_t already_resolved = ecma_op_object_get (function_p, &str_already_resolved); + + /* 4. */ + if (ecma_get_already_resolved_bool_value (already_resolved)) + { + goto end_of_resolve_function; + } + + /* 5. */ + ecma_set_already_resolved_value (already_resolved, true); + + /* 6. */ + if (argv[0] == promise) + { + ecma_object_t *error_p = ecma_new_standard_error (ECMA_ERROR_TYPE); + ecma_reject_promise (promise, ecma_make_object_value (error_p)); + ecma_deref_object (error_p); + goto end_of_resolve_function; + } + + /* 7. */ + if (!ecma_is_value_object (argv[0])) + { + ecma_fulfill_promise (promise, argv[0]); + goto end_of_resolve_function; + } + + /* 8. */ + ecma_string_t *str_then = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING_THEN); + ecma_value_t then = ecma_op_object_get (ecma_get_object_from_value (argv[0]), str_then); + + if (ECMA_IS_VALUE_ERROR (then)) + { + /* 9. */ + ecma_reject_promise (promise, then); + } + else if (!ecma_op_is_callable (then)) + { + /* 11 .*/ + ecma_fulfill_promise (promise, argv[0]); + } + else + { + /* 12 */ + ecma_enqueue_promise_resolve_thenable_job (promise, argv[0], then); + } + + ecma_deref_ecma_string (str_then); + ecma_free_value (then); + +end_of_resolve_function: + ecma_free_value (promise); + ecma_free_value (already_resolved); + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); +} /* ecma_promise_resolve_handler */ + +/** + * CapabilityiesExecutor 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 *str_0 = ecma_new_ecma_string_from_uint32 (0); + ecma_string_t *str_1 = ecma_new_ecma_string_from_uint32 (1); + ecma_string_t *str_2 = ecma_new_ecma_string_from_uint32 (2); + /* 2. String '0' indicates [[Capability]] of the executor. */ + ecma_value_t capability = ecma_op_object_get (executor_p, str_0); + /* 3. String '1' indicates [[Resolve]] of the capability. */ + ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), str_1); + + if (resolve != ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)) + { + ecma_free_value (resolve); + ecma_free_value (capability); + ecma_deref_ecma_string (str_0); + ecma_deref_ecma_string (str_1); + ecma_deref_ecma_string (str_2); + + return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' function should be undefined.")); + } + + /* 4. String '2' indicates [[Reject]] of the capability. */ + ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_2); + + if (reject != ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED)) + { + ecma_free_value (reject); + ecma_free_value (capability); + ecma_deref_ecma_string (str_0); + ecma_deref_ecma_string (str_1); + ecma_deref_ecma_string (str_2); + + return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' function should be undefined.")); + } + + /* 5. */ + ecma_op_object_put (ecma_get_object_from_value (capability), + str_1, + resolve_func, + false); + /* 6. */ + ecma_op_object_put (ecma_get_object_from_value (capability), + str_2, + reject_func, + false); + + ecma_free_value (capability); + ecma_deref_ecma_string (str_0); + ecma_deref_ecma_string (str_1); + ecma_deref_ecma_string (str_2); + + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); +} /* ecma_call_builtin_executor */ + +/** + * Create a PromiseCreateResovingFucntions. + * + * See also: ES2015 25.4.1.3 + * + * @return pointer to the resolving functions + */ +ecma_promise_resolving_functions_t * +ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promise object */ +{ + /* 1. */ + ecma_value_t already_resolved = ecma_op_create_boolean_object (ecma_make_boolean_value (false)); + + ecma_string_t str_promise; + ecma_string_t str_already_resolved; + ecma_init_ecma_magic_string (&str_promise, LIT_INTERNAL_MAGIC_STRING_PROMISE); + ecma_init_ecma_magic_string (&str_already_resolved, LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + /* 2. */ + ecma_object_t *resolve_p; + resolve_p = ecma_op_create_external_function_object ((ecma_external_pointer_t) ecma_promise_resolve_handler); + + /* 3. */ + ecma_op_object_put (resolve_p, + &str_promise, + ecma_make_object_value (object_p), + false); + /* 4. */ + ecma_op_object_put (resolve_p, + &str_already_resolved, + already_resolved, + false); + /* 5. */ + ecma_object_t *reject_p; + reject_p = ecma_op_create_external_function_object ((ecma_external_pointer_t) ecma_promise_reject_handler); + /* 6. */ + ecma_op_object_put (reject_p, + &str_promise, + ecma_make_object_value (object_p), + false); + /* 7. */ + ecma_op_object_put (reject_p, + &str_already_resolved, + already_resolved, + false); + + /* 8. */ + ecma_promise_resolving_functions_t *funcs = jmem_heap_alloc_block (sizeof (ecma_promise_resolving_functions_t)); + funcs->resolve = ecma_make_object_value (resolve_p); + funcs->reject = ecma_make_object_value (reject_p); + + ecma_free_value (already_resolved); + + return funcs; +} /* ecma_promise_create_resolving_functions */ + +/** + * Free the heap and the member of the resolving functions. + */ +void +ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs) /**< points to the functions */ +{ + ecma_free_value (funcs->resolve); + ecma_free_value (funcs->reject); + jmem_heap_free_block (funcs, sizeof (ecma_promise_resolving_functions_t)); +} /* ecma_promise_free_resolving_functions */ + +/** + * Create a promise object. + * + * See also: ES2015 25.4.3.1 + * + * @return ecma value of the new promise object + * Returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function or object */ + bool is_func) /**< indicates whether executor is a function */ +{ + /* 3. */ + ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE_PROTOTYPE); + ecma_object_t *object_p = ecma_create_object (prototype_obj_p, + sizeof (ecma_promise_object_t), + ECMA_OBJECT_TYPE_CLASS); + ecma_deref_object (prototype_obj_p); + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_PROMISE_UL; + ext_object_p->u.class_prop.u.value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED); + ecma_promise_object_t *promise_object_p = (ecma_promise_object_t *) object_p; + promise_object_p->fulfill_reactions = NULL; + promise_object_p->reject_reactions = NULL; + + /* 5 */ + ecma_promise_set_state (object_p, ECMA_PROMISE_STATE_PENDING); + /* 6-7. */ + promise_object_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); + promise_object_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); + /* 8. */ + ecma_promise_resolving_functions_t *funcs = ecma_promise_create_resolving_functions (object_p); + + /* 9. */ + ecma_value_t completion; + + if (is_func) + { + JERRY_ASSERT (ecma_op_is_callable (executor)); + + ecma_value_t argv[] = { funcs->resolve, funcs->reject }; + completion = ecma_op_function_call (ecma_get_object_from_value (executor), + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + argv, + 2); + } + else + { + JERRY_ASSERT (ecma_is_value_object (executor)); + + completion = ecma_call_builtin_executor (ecma_get_object_from_value (executor), + funcs->resolve, + funcs->reject); + } + + ecma_value_t status = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); + + if (ECMA_IS_VALUE_ERROR (completion)) + { + /* 10.a. */ + completion = ecma_get_value_from_error_value (completion); + status = ecma_op_function_call (ecma_get_object_from_value (funcs->reject), + ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), + &completion, + 1); + } + + ecma_promise_free_resolving_functions (funcs); + ecma_free_value (completion); + + /* 10.b. */ + if (ECMA_IS_VALUE_ERROR (status)) + { + ecma_deref_object (object_p); + return status; + } + + /* 11. */ + ecma_free_value (status); + + return ecma_make_object_value (object_p); +} /* ecma_op_create_promise_object */ + +/** + * Create a new PromiseCapability. + * + * See also: ES2015 25.4.1.5 + * + * @return ecma value of the new PromiseCapability + * Returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_promise_new_capability (void) +{ + /* 3. */ + ecma_object_t *capability_p = ecma_op_create_object_object_noarg (); + ecma_string_t *str_0 = ecma_new_ecma_string_from_uint32 (0); + + /* 4. */ + ecma_object_t *executor_p; + executor_p = ecma_op_create_object_object_noarg (); + ecma_value_t executor = ecma_make_object_value (executor_p); + /* 5. String '0' here indicates the [[Capability]] of executor. */ + ecma_op_object_put (executor_p, + str_0, + ecma_make_object_value (capability_p), + false); + + /* 6. */ + ecma_value_t promise = ecma_op_create_promise_object (executor, false); + + /* 10. String '0' here indicates the [[Promise]] of Capability. */ + ecma_op_object_put (capability_p, + str_0, + promise, + false); + + ecma_deref_object (executor_p); + ecma_deref_ecma_string (str_0); + /* 7. */ + if (ECMA_IS_VALUE_ERROR (promise)) + { + ecma_free_value (promise); + ecma_deref_object (capability_p); + return promise; + } + + ecma_free_value (promise); + /* 8. str '1' indicates [[Resolve]] of Capability. */ + ecma_string_t *str_1 = ecma_new_ecma_string_from_uint32 (1); + ecma_value_t resolve = ecma_op_object_get (capability_p, str_1); + ecma_deref_ecma_string (str_1); + + 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. str '2' indicates [[Reject]] of Capability. */ + ecma_string_t *str_2 = ecma_new_ecma_string_from_uint32 (2); + ecma_value_t reject = ecma_op_object_get (capability_p, str_2); + ecma_deref_ecma_string (str_2); + + 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. */ + return ecma_make_object_value (capability_p); +} /* ecma_promise_new_capability */ + +/** + * It performs the "then" operation on promiFulfilled + * and onRejected as its settlement actions. + * + * See also: 25.4.5.3.1 + * + * @return ecma value of the new promise object + * Returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_promise_then (ecma_value_t promise, /**< the promise which call 'then' */ + ecma_value_t on_fulfilled, /**< on_fulfilled function */ + ecma_value_t on_rejected, /**< on_rejected function */ + ecma_value_t result_capability) /**< promise capability */ +{ + ecma_string_t *str_0 = ecma_new_ecma_string_from_uint32 (0); + ecma_string_t *str_1 = ecma_new_ecma_string_from_uint32 (1); + + /* 3. boolean true indicates "indentity" */ + if (!ecma_op_is_callable (on_fulfilled)) + { + on_fulfilled = ecma_make_boolean_value (true); + } + + /* 4. boolean false indicates "thrower" */ + if (!ecma_op_is_callable (on_rejected)) + { + on_rejected = ecma_make_boolean_value (false); + } + + /* 5-6. String '0' indicates [[Capability]] of a PromiseReaction, '1' indicates [[Handler]]. */ + ecma_object_t *fulfill_reaction_p = ecma_op_create_object_object_noarg (); + ecma_object_t *reject_reaction_p = ecma_op_create_object_object_noarg (); + ecma_op_object_put (fulfill_reaction_p, + str_0, + result_capability, + false); + ecma_op_object_put (fulfill_reaction_p, + str_1, + on_fulfilled, + false); + + ecma_op_object_put (reject_reaction_p, + str_0, + result_capability, + false); + ecma_op_object_put (reject_reaction_p, + str_1, + on_rejected, + false); + + ecma_object_t *obj_p = ecma_get_object_from_value (promise); + ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; + + if (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_PENDING) + { + /* 7. */ + ecma_append_to_values_collection (promise_p->fulfill_reactions, + ecma_make_object_value (fulfill_reaction_p), + false); + + ecma_append_to_values_collection (promise_p->reject_reactions, + ecma_make_object_value (reject_reaction_p), + false); + } + else if (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_FULFILLED) + { + /* 8. */ + ecma_value_t value = ecma_promise_get_result (obj_p); + ecma_enqueue_promise_reaction_job (ecma_make_object_value (fulfill_reaction_p), value); + ecma_free_value (value); + } + else + { + /* 9. */ + ecma_value_t reason = ecma_promise_get_result (obj_p); + ecma_enqueue_promise_reaction_job (ecma_make_object_value (reject_reaction_p), reason); + ecma_free_value (reason); + } + + /* 10. String '0' indicates [[Promise]] of a Capability. */ + ecma_value_t ret = ecma_op_object_get (ecma_get_object_from_value (result_capability), str_0); + + ecma_deref_object (fulfill_reaction_p); + ecma_deref_object (reject_reaction_p); + ecma_deref_ecma_string (str_0); + ecma_deref_ecma_string (str_1); + + return ret; +} /* ecma_promise_then */ + +/** + * @} + * @} + */ +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ diff --git a/jerry-core/ecma/operations/ecma-promise-object.h b/jerry-core/ecma/operations/ecma-promise-object.h new file mode 100644 index 000000000..b11c19e3e --- /dev/null +++ b/jerry-core/ecma/operations/ecma-promise-object.h @@ -0,0 +1,83 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMA_PROMISE_OBJECT_H +#define ECMA_PROMISE_OBJECT_H + +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN +#include "ecma-globals.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmaarraybufferobject ECMA ArrayBuffer object related routines + * @{ + */ + +/** + * The PromiseState of promise object. + */ +typedef enum +{ + ECMA_PROMISE_STATE_PENDING, /**< pending state */ + ECMA_PROMISE_STATE_FULFILLED, /**< fulfilled state */ + ECMA_PROMISE_STATE_REJECTED, /** rejected state */ + ECMA_PROMISE_STATE__COUNT /**< number of states */ +} ecma_promise_state_t; + +/** + * Description of the promise resolving functions. + */ +typedef struct +{ + ecma_value_t resolve; /**< the resolve function */ + ecma_value_t reject; /**< the reject function */ +} ecma_promise_resolving_functions_t; + +/** + * Description of the promise object. + * It need more space than normal object to store builtin properties. + */ +typedef struct +{ + ecma_extended_object_t ecma_extended_object_t; /**< extended object part */ + uint8_t state; /**< promise state, see ecma_promise_state_t */ + ecma_collection_header_t *fulfill_reactions; /**< list of PromiseFullfillReactions */ + ecma_collection_header_t *reject_reactions; /**< list of PromiseRejectReactions */ +} ecma_promise_object_t; + +bool ecma_is_promise (ecma_object_t *obj_p); +ecma_value_t ecma_promise_get_result (ecma_object_t *obj_p); +void ecma_promise_set_result (ecma_object_t *obj_p, ecma_value_t result); +uint8_t ecma_promise_get_state (ecma_object_t *obj_p); +void ecma_promise_set_state (ecma_object_t *obj_p, uint8_t state); +ecma_value_t +ecma_op_create_promise_object (ecma_value_t executor, bool is_func); +ecma_promise_resolving_functions_t * +ecma_promise_create_resolving_functions (ecma_object_t *obj_p); +void ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs); +ecma_value_t ecma_promise_new_capability (void); +ecma_value_t +ecma_promise_then (ecma_value_t promise, + ecma_value_t on_fulfilled, + ecma_value_t on_rejected, + ecma_value_t result_capability); +/** + * @} + * @} + */ + +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ +#endif /* !ECMA_PROMISE_OBJECT_H */ diff --git a/jerry-core/jerry-port.h b/jerry-core/jerry-port.h index 011a5d741..466d04c7f 100644 --- a/jerry-core/jerry-port.h +++ b/jerry-core/jerry-port.h @@ -142,6 +142,8 @@ double jerry_port_get_current_time (void); #ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN +#define JERRY_PORT_ENABLE_JOBQUEUE + typedef uint32_t (*jerry_job_handler_t) (void *); void jerry_port_jobqueue_enqueue (jerry_job_handler_t handler, void *job_p); diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h index 6b5ea17cf..fc1752c32 100644 --- a/jerry-core/lit/lit-magic-strings.h +++ b/jerry-core/lit/lit-magic-strings.h @@ -35,9 +35,13 @@ typedef enum #undef LIT_MAGIC_STRING_DEF #undef LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE LIT_NON_INTERNAL_MAGIC_STRING__COUNT, /**< number of non-internal magic strings */ - - LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE = LIT_NON_INTERNAL_MAGIC_STRING__COUNT, /**< native handle package - * associated with an object */ + LIT_INTERNAL_MAGIC_STRING_PROMISE = LIT_NON_INTERNAL_MAGIC_STRING__COUNT, /**< [[Promise]] of promise + * reject or resolve functions */ + LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED, /**< [[AlreadyResolved]] of promise reject or resolve functions */ + LIT_NEED_MARK_MAGIC_STRING__COUNT, /**< number of internal magic strings which will be used as properties' names, + * and the properties need to be marked during gc. */ + LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE = LIT_NEED_MARK_MAGIC_STRING__COUNT, /**< native handle package + * associated with an object */ LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< native pointer package associated with an object */ LIT_MAGIC_STRING__COUNT /**< number of magic strings */ } lit_magic_string_id_t; diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index c5d9ed2ff..966e390c9 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -92,6 +92,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SOME, "some") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SORT, "sort") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SQRT, "sqrt") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TEST, "test") +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_THEN, "then") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TRIM, "trim") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TRUE, "true") LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (5, LIT_MAGIC_STRING_ARRAY_UL) @@ -148,6 +149,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SUBSTR, "substr") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_JSON_UL, "toJSON") LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (7, LIT_MAGIC_STRING_BOOLEAN_UL) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BOOLEAN_UL, "Boolean") +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PROMISE_UL, "Promise") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SQRT1_2_U, "SQRT1_2") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BOOLEAN, "boolean") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMPILE, "compile") diff --git a/jerry-main/main-unix.c b/jerry-main/main-unix.c index 9a762b499..144fd5deb 100644 --- a/jerry-main/main-unix.c +++ b/jerry-main/main-unix.c @@ -648,6 +648,9 @@ main (int argc, is_repl_mode = true; } +#ifdef JERRY_PORT_ENABLE_JOBQUEUE + jerry_port_jobqueue_init (); +#endif /* JERRY_PORT_ENABLE_JOBQUEUE */ jerry_init (flags); register_js_function ("assert", assert_handler); @@ -828,6 +831,15 @@ main (int argc, args, 1); jerry_release_value (ret_val_print); +#ifdef JERRY_PORT_ENABLE_JOBQUEUE + jerry_release_value (ret_val_eval); + ret_val_eval = jerry_port_jobqueue_run (); + + if (jerry_value_has_error_flag (ret_value)) + { + print_unhandled_exception (ret_value); + } +#endif /* JERRY_PORT_ENABLE_JOBQUEUE */ } else { @@ -850,7 +862,19 @@ main (int argc, ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL; } +#ifdef JERRY_PORT_ENABLE_JOBQUEUE + else + { + jerry_release_value (ret_value); + ret_value = jerry_port_jobqueue_run (); + if (jerry_value_has_error_flag (ret_value)) + { + print_unhandled_exception (ret_value); + ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL; + } + } +#endif /* JERRY_PORT_ENABLE_JOBQUEUE */ jerry_release_value (ret_value); jerry_cleanup (); diff --git a/targets/default/jerry-port-default-jobqueue.c b/targets/default/jerry-port-default-jobqueue.c index 354904bb3..183239177 100644 --- a/targets/default/jerry-port-default-jobqueue.c +++ b/targets/default/jerry-port-default-jobqueue.c @@ -19,7 +19,7 @@ #include "jmem.h" #include "jrt.h" -#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN +#ifdef JERRY_PORT_ENABLE_JOBQUEUE typedef struct jerry_port_queueitem_t jerry_port_queueitem_t; @@ -34,7 +34,7 @@ struct jerry_port_queueitem_t }; /** - * Description of a job queue (FIFO) + * Description of a job queue (FIFO). */ typedef struct { @@ -45,7 +45,7 @@ typedef struct static jerry_port_jobqueue_t queue; /** - * Initialize the job queue + * Initialize the job queue. */ void jerry_port_jobqueue_init (void) { @@ -54,7 +54,7 @@ void jerry_port_jobqueue_init (void) } /* jerry_port_jobqueue_init */ /** - * Enqueue a job + * Enqueue a job. */ void jerry_port_jobqueue_enqueue (jerry_job_handler_t handler, /**< the handler for the job */ void *job_p) /**< the job */ @@ -62,41 +62,34 @@ void jerry_port_jobqueue_enqueue (jerry_job_handler_t handler, /**< the handler jerry_port_queueitem_t *item_p = jmem_heap_alloc_block (sizeof (jerry_port_queueitem_t)); item_p->job_p = job_p; item_p->handler = handler; + item_p->next_p = NULL; if (queue.head_p == NULL) { - JERRY_ASSERT (queue.tail_p == NULL); - queue.head_p = item_p; - item_p->next_p = NULL; queue.tail_p = item_p; return; } - JERRY_ASSERT (queue.tail_p != NULL); - queue.tail_p->next_p = item_p; queue.tail_p = item_p; } /* jerry_port_jobqueue_enqueue */ /** * Dequeue and get the job. - * @return pointer to jerry_port_queueitem_t - * It should be freed with jmem_heap_free_block + * + * @return pointer to jerry_port_queueitem_t. + * It should be freed with jmem_heap_free_block. */ static jerry_port_queueitem_t * jerry_port_jobqueue_dequeue (void) { if (queue.head_p == NULL) { - JERRY_ASSERT (queue.tail_p == NULL); - return NULL; } - JERRY_ASSERT (queue.tail_p != NULL); - jerry_port_queueitem_t *item_p = queue.head_p; queue.head_p = queue.head_p->next_p; @@ -105,10 +98,11 @@ jerry_port_jobqueue_dequeue (void) /** * Start the jobqueue. - * @return jerry value + * + * @return jerry value. * If exception happens in the handler, stop the queue * and return the exception. - * Otherwise, return undefined + * Otherwise, return undefined. */ jerry_value_t jerry_port_jobqueue_run (void) @@ -138,4 +132,4 @@ jerry_port_jobqueue_run (void) } } /* jerry_port_jobqueue_run */ -#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ +#endif /* JERRY_PORT_ENABLE_JOBQUEUE */ diff --git a/targets/default/jerry-port-default.h b/targets/default/jerry-port-default.h index 2126208a1..e614c5c69 100644 --- a/targets/default/jerry-port-default.h +++ b/targets/default/jerry-port-default.h @@ -37,10 +37,10 @@ bool jerry_port_default_is_abort_on_fail (void); jerry_log_level_t jerry_port_default_get_log_level (void); void jerry_port_default_set_log_level (jerry_log_level_t level); -#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN +#ifdef JERRY_PORT_ENABLE_JOBQUEUE void jerry_port_jobqueue_init (void); jerry_value_t jerry_port_jobqueue_run (void); -#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ +#endif /* JERRY_PORT_ENABLE_JOBQUEUE */ /** * @} diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.03/25.04.03-001.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.03/25.04.03-001.js new file mode 100644 index 000000000..6605999de --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.03/25.04.03-001.js @@ -0,0 +1,20 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function foo() {}; + +var a = new Promise(foo); + +assert (a instanceof Promise); diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.03/25.04.03-002.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.03/25.04.03-002.js new file mode 100644 index 000000000..37aad0072 --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.03/25.04.03-002.js @@ -0,0 +1,50 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var name1 = ""; +var name2 = ""; +var name3 = ""; +function foo() {}; + +try +{ + new Promise(); +} +catch (e) +{ + name1 = e.name; +} + +try +{ + Promise(foo); +} +catch (e) +{ + name2 = e.name; +} + +try +{ + new Promise("string"); +} +catch (e) +{ + name3 = e.name; +} + +assert (name1 === "TypeError"); +assert (name2 === "TypeError"); +assert (name3 === "TypeError"); diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-001.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-001.js new file mode 100644 index 000000000..0b3218aa6 --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-001.js @@ -0,0 +1,16 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +assert (Promise.prototype.length === 1); diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-002.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-002.js new file mode 100644 index 000000000..c1e7584f9 --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-002.js @@ -0,0 +1,36 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var obj = {name:""}; + +var a = new Promise(function(f, r){ + obj.name = obj.name + "a"; + f(obj); +}); + +a.then(function(x) { + x.name = x.name + "b"; + return x; +}).then(null, function(x) { + x.name = x.name + "c"; // unreachable + return x; +}).then(function(x) { + x.name = x.name + "d"; + assert (obj.name === "aebd"); +}); + +obj.name = obj.name + "e"; + +assert (obj.name === "ae") diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-003.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-003.js new file mode 100644 index 000000000..6b4b90fb8 --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-003.js @@ -0,0 +1,36 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var a = new Promise(function(f, r){ + r(0); +}); + +a +.then(function f1(x) { + return x + 1; // unreachable +}, function r1(x){ + return x + 10; +}) +.then(function f2(x) { + throw x + 100 +}) +.then(function f3(x) { + return x + 1000 //unreachable +}, function r3(x) { + return x + 10000 +}) +.then(function(x) { + assert (x === 10110); +}) diff --git a/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-004.js b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-004.js new file mode 100644 index 000000000..ce47a9aa6 --- /dev/null +++ b/tests/jerry-test-suite/es2015/25/25.04/25.04.04/25.04.04-004.js @@ -0,0 +1,26 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var a = new Promise(function(f, r){ + f("a"); +}); + +var b = new Promise(function(f, r){ + f(a); +}) + +b.then(function(x) { + assert (x === "a"); +})