From 80716cca909836a0cd096b0e278164b1aab782f3 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Fri, 3 Jul 2020 11:04:27 +0200 Subject: [PATCH] Implement missing async function and async iterator prototypes. (#3962) JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/ecma/base/ecma-gc.c | 4 +- .../ecma-builtin-async-function-prototype.c | 43 +++++++++++ ...cma-builtin-async-function-prototype.inc.h | 36 +++++++++ .../ecma-builtin-async-function.c | 74 +++++++++++++++++++ .../ecma-builtin-async-function.inc.h | 41 ++++++++++ .../ecma-builtin-async-iterator-prototype.c | 63 ++++++++++++++++ ...cma-builtin-async-iterator-prototype.inc.h | 30 ++++++++ .../ecma/builtin-objects/ecma-builtins.inc.h | 23 +++++- .../operations/ecma-async-generator-object.c | 10 ++- .../operations/ecma-async-generator-object.h | 2 +- .../ecma/operations/ecma-function-object.c | 69 +++++++++++------ .../ecma/operations/ecma-function-object.h | 5 +- jerry-core/ecma/operations/ecma-jobqueue.c | 10 ++- jerry-core/lit/lit-magic-strings.inc.h | 3 +- jerry-core/lit/lit-magic-strings.ini | 1 + jerry-core/parser/js/byte-code.h | 17 ++++- jerry-core/parser/js/js-parser.c | 18 ++++- jerry-core/vm/opcodes.c | 3 +- jerry-core/vm/vm.c | 35 +++------ .../es.next/for-await-of-iterator-close.js | 28 ++++++- tests/jerry/es.next/for-await-of.js | 34 ++++++++- tests/jerry/es.next/function-async3.js | 32 ++++++++ 22 files changed, 509 insertions(+), 72 deletions(-) create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-async-function-prototype.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-async-function-prototype.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-async-function.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-async-function.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-async-iterator-prototype.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-async-iterator-prototype.inc.h create mode 100644 tests/jerry/es.next/function-async3.js diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 8cc88d7d1..e293538b4 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -733,7 +733,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ #if ENABLED (JERRY_ESNEXT) const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_p); - if (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_ARROW) + if (CBC_FUNCTION_IS_ARROW (byte_code_p->status_flags)) { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; @@ -1269,7 +1269,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ ext_func_p->u.function.bytecode_cp)); #if ENABLED (JERRY_ESNEXT) - if (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_ARROW) + if (CBC_FUNCTION_IS_ARROW (byte_code_p->status_flags)) { ecma_free_value_if_not_object (((ecma_arrow_function_t *) object_p)->this_binding); ecma_free_value_if_not_object (((ecma_arrow_function_t *) object_p)->new_target); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-async-function-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-async-function-prototype.c new file mode 100644 index 000000000..6076eb28b --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-async-function-prototype.c @@ -0,0 +1,43 @@ +/* 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-globals.h" + +#if ENABLED (JERRY_ESNEXT) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-async-function-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID async_function_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup asyncfunctionprototype ECMA AsyncFunction.prototype object built-in + * @{ + */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ESNEXT) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-async-function-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-async-function-prototype.inc.h new file mode 100644 index 000000000..6dfde9efa --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-async-function-prototype.inc.h @@ -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. + */ + +/* + * %AsyncFunctionPrototype% built-in description (AsyncFunction.prototype) + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ESNEXT) + +/* ECMA-262 v11, 25.7.3.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_ASYNC_FUNCTION, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v11, 25.7.3.2 */ +STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_ASYNC_FUNCTION_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +#endif /* ENABLED (JERRY_ESNEXT) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-async-function.c b/jerry-core/ecma/builtin-objects/ecma-builtin-async-function.c new file mode 100644 index 000000000..6ce08afbb --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-async-function.c @@ -0,0 +1,74 @@ +/* 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-globals.h" + +#if ENABLED (JERRY_ESNEXT) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" +#include "ecma-function-object.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-async-function.inc.h" +#define BUILTIN_UNDERSCORED_ID async_function +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup asyncfunction ECMA AsyncFunction object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in AsyncFunction object + * + * @return constructed async function object - if success + * raised error otherwise + */ +ecma_value_t +ecma_builtin_async_function_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_op_create_dynamic_function (arguments_list_p, + arguments_list_len, + ECMA_PARSE_ASYNC_FUNCTION); +} /* ecma_builtin_async_function_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in AsyncFunction object + * + * @return constructed async function object - if success + * raised error otherwise + */ +ecma_value_t +ecma_builtin_async_function_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_builtin_async_function_dispatch_call (arguments_list_p, arguments_list_len); +} /* ecma_builtin_async_function_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ESNEXT) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-async-function.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-async-function.inc.h new file mode 100644 index 000000000..104e07a9d --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-async-function.inc.h @@ -0,0 +1,41 @@ +/* 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. + */ + +/* + * %AsyncFunction% built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ESNEXT) + +/* ECMA-262 v11, 25.7.2 */ +STRING_VALUE (LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_ASYNC_FUNCTION_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v11, 25.7.2.1 */ +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 1, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v10, 25.7.2.2 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_ASYNC_FUNCTION, + ECMA_PROPERTY_FIXED) + +#endif /* ENABLED (JERRY_ESNEXT) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-async-iterator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-async-iterator-prototype.c new file mode 100644 index 000000000..8d64b81d1 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-async-iterator-prototype.c @@ -0,0 +1,63 @@ +/* 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.h" +#include "ecma-builtins.h" +#include "ecma-iterator-object.h" + +#if ENABLED (JERRY_ESNEXT) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-async-iterator-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID async_iterator_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup %asynciteratorprototype% ECMA %AsyncIteratorPrototype% object built-in + * @{ + */ + +/** + * The %AsyncIteratorPrototype% object's '@@asyncIterator' routine + * + * See also: + * ECMA-262 v10, 25.1.3.1 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return the given this value + */ +static ecma_value_t +ecma_builtin_async_iterator_prototype_object_async_iterator (ecma_value_t this_val) /**< this argument */ +{ + /* 1. */ + return ecma_copy_value (this_val); +} /* ecma_builtin_async_iterator_prototype_object_async_iterator */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ESNEXT) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-async-iterator-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-async-iterator-prototype.inc.h new file mode 100644 index 000000000..5a49127c7 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-async-iterator-prototype.inc.h @@ -0,0 +1,30 @@ +/* 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. + */ + +/* + * %AsyncIteratorPrototype% built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ESNEXT) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_GLOBAL_SYMBOL_ASYNC_ITERATOR, ecma_builtin_async_iterator_prototype_object_async_iterator, 0, 0) + +#endif /* ENABLED (JERRY_ESNEXT) */ + +#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 f94190fb8..a3b4a0054 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -576,6 +576,20 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_SYMBOL, true, symbol) +/* The %AsyncFunction% object (ECMA-262 v11, 25.7.2) */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_ASYNC_FUNCTION, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION, + true, + async_function) + +/* The %AsyncFunctionPrototype% object (ECMA-262 v11, 25.7.3) */ +BUILTIN (ECMA_BUILTIN_ID_ASYNC_FUNCTION_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + async_function_prototype) + /* The %IteratorPrototype% object (ECMA-262 v6, 25.1.2) */ BUILTIN (ECMA_BUILTIN_ID_ITERATOR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, @@ -597,6 +611,13 @@ BUILTIN (ECMA_BUILTIN_ID_STRING_ITERATOR_PROTOTYPE, true, string_iterator_prototype) +/* The %AsyncIteratorPrototype% object (ECMA-262 v10, 25.1.3) */ +BUILTIN (ECMA_BUILTIN_ID_ASYNC_ITERATOR_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + async_iterator_prototype) + /* The %(GeneratorFunction)% object */ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_GENERATOR_FUNCTION, ECMA_OBJECT_TYPE_FUNCTION, @@ -635,7 +656,7 @@ BUILTIN (ECMA_BUILTIN_ID_ASYNC_GENERATOR, /* The %(AsyncGenerator).prototype% object */ BUILTIN (ECMA_BUILTIN_ID_ASYNC_GENERATOR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, - ECMA_BUILTIN_ID_ITERATOR_PROTOTYPE, + ECMA_BUILTIN_ID_ASYNC_ITERATOR_PROTOTYPE, true, async_generator_prototype) diff --git a/jerry-core/ecma/operations/ecma-async-generator-object.c b/jerry-core/ecma/operations/ecma-async-generator-object.c index 65761432c..336e6043b 100644 --- a/jerry-core/ecma/operations/ecma-async-generator-object.c +++ b/jerry-core/ecma/operations/ecma-async-generator-object.c @@ -186,8 +186,11 @@ ecma_async_yield_throw (vm_executable_object_t *async_generator_object_p, /**< a /** * Execute the next task in the command queue of the async generator + * + * @return ecma value + * Returned value must be freed with ecma_free_value. */ -void +ecma_value_t ecma_async_generator_run (vm_executable_object_t *async_generator_object_p) /**< async generator */ { JERRY_ASSERT (async_generator_object_p->extended_object.u.class_prop.class_id @@ -250,7 +253,7 @@ ecma_async_generator_run (vm_executable_object_t *async_generator_object_p) /**< if (result == ECMA_VALUE_UNDEFINED) { - return; + return ECMA_VALUE_UNDEFINED; } JERRY_ASSERT (ECMA_IS_VALUE_ERROR (result)); @@ -287,7 +290,10 @@ ecma_async_generator_run (vm_executable_object_t *async_generator_object_p) /**< { JERRY_ASSERT (head == async_generator_object_p->extended_object.u.class_prop.u.head); ecma_async_generator_finalize (async_generator_object_p, result); + result = ECMA_VALUE_UNDEFINED; } + + return result; } /* ecma_async_generator_run */ /** diff --git a/jerry-core/ecma/operations/ecma-async-generator-object.h b/jerry-core/ecma/operations/ecma-async-generator-object.h index 081727c9d..153754a7b 100644 --- a/jerry-core/ecma/operations/ecma-async-generator-object.h +++ b/jerry-core/ecma/operations/ecma-async-generator-object.h @@ -78,7 +78,7 @@ typedef enum ecma_value_t ecma_async_generator_enqueue (vm_executable_object_t *async_generator_object_p, ecma_async_generator_operation_type_t operation, ecma_value_t value); -void ecma_async_generator_run (vm_executable_object_t *async_generator_object_p); +ecma_value_t ecma_async_generator_run (vm_executable_object_t *async_generator_object_p); void ecma_async_generator_finalize (vm_executable_object_t *async_generator_object_p, ecma_value_t value); ecma_value_t ecma_await_continue (vm_executable_object_t *async_generator_object_p, ecma_value_t value); diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 289e1b22d..ece44fd33 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -442,32 +442,42 @@ ecma_op_create_simple_function_object (ecma_object_t *scope_p, /**< function's s #if ENABLED (JERRY_ESNEXT) /** - * GeneratorFunction object creation operation. - * - * See also: ECMA-262 v5, 13.2 + * Create a function object with the appropriate prototype. * * @return pointer to newly created Function object */ ecma_object_t * -ecma_op_create_generator_function_object (ecma_object_t *scope_p, /**< function's scope */ - const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */ +ecma_op_create_any_function_object (ecma_object_t *scope_p, /**< function's scope */ + const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */ { - return ecma_op_create_function_object (scope_p, bytecode_data_p, ECMA_BUILTIN_ID_GENERATOR); -} /* ecma_op_create_generator_function_object */ + ecma_builtin_id_t proto_id; -/** - * AsyncGeneratorFunction object creation operation. - * - * See also: ECMA-262 v10, 25.3 - * - * @return pointer to newly created Function object - */ -ecma_object_t * -ecma_op_create_async_generator_function_object (ecma_object_t *scope_p, /**< function's scope */ - const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */ -{ - return ecma_op_create_function_object (scope_p, bytecode_data_p, ECMA_BUILTIN_ID_ASYNC_GENERATOR); -} /* ecma_op_create_async_generator_function_object */ + switch (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags)) + { + case CBC_FUNCTION_GENERATOR: + { + proto_id = ECMA_BUILTIN_ID_GENERATOR; + break; + } + case CBC_FUNCTION_ASYNC: + { + proto_id = ECMA_BUILTIN_ID_ASYNC_FUNCTION_PROTOTYPE; + break; + } + case CBC_FUNCTION_ASYNC_GENERATOR: + { + proto_id = ECMA_BUILTIN_ID_ASYNC_GENERATOR; + break; + } + default: + { + proto_id = ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE; + break; + } + } + + return ecma_op_create_function_object (scope_p, bytecode_data_p, proto_id); +} /* ecma_op_create_any_function_object */ /** * Arrow function object creation operation. @@ -481,7 +491,17 @@ ecma_op_create_arrow_function_object (ecma_object_t *scope_p, /**< function's sc const ecma_compiled_code_t *bytecode_data_p, /**< byte-code array */ ecma_value_t this_binding) /**< value of 'this' binding */ { - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + ecma_object_t *prototype_obj_p; + + if (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) == CBC_FUNCTION_ARROW) + { + prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + } + else + { + JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) == CBC_FUNCTION_ASYNC_ARROW); + prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ASYNC_FUNCTION_PROTOTYPE); + } size_t arrow_function_object_size = sizeof (ecma_arrow_function_t); @@ -851,7 +871,7 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ #if ENABLED (JERRY_ESNEXT) ecma_object_t *old_function_object_p = JERRY_CONTEXT (current_function_obj_p); - if (JERRY_UNLIKELY (function_type == CBC_FUNCTION_ARROW)) + if (JERRY_UNLIKELY (CBC_FUNCTION_IS_ARROW (status_flags))) { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_obj_p; @@ -1298,6 +1318,11 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ message_p = ECMA_ERR_MSG ("Arrow functions cannot be invoked with 'new'."); break; } + case CBC_FUNCTION_ASYNC_ARROW: + { + message_p = ECMA_ERR_MSG ("Async arrow functions cannot be invoked with 'new'."); + break; + } default: { JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_ACCESSOR); diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index e060d1e1a..6411dcd65 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -55,10 +55,7 @@ ecma_value_t ecma_op_function_get_super_constructor (ecma_object_t *func_obj_p); ecma_object_t * -ecma_op_create_generator_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p); - -ecma_object_t * -ecma_op_create_async_generator_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p); +ecma_op_create_any_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p); ecma_object_t * ecma_op_create_arrow_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p, diff --git a/jerry-core/ecma/operations/ecma-jobqueue.c b/jerry-core/ecma/operations/ecma-jobqueue.c index 8b41af355..9036b7ea2 100644 --- a/jerry-core/ecma/operations/ecma-jobqueue.c +++ b/jerry-core/ecma/operations/ecma-jobqueue.c @@ -343,16 +343,20 @@ ecma_process_promise_async_reaction_job (ecma_job_promise_async_reaction_t *job_ /** * The processor for PromiseAsyncGeneratorJob. + * + * @return ecma value + * Returned value must be freed with ecma_free_value */ -static void +static ecma_value_t ecma_process_promise_async_generator_job (ecma_job_promise_async_generator_t *job_p) /**< the job to be operated */ { ecma_object_t *object_p = ecma_get_object_from_value (job_p->executable_object); - ecma_async_generator_run ((vm_executable_object_t *) object_p); + ecma_value_t result = ecma_async_generator_run ((vm_executable_object_t *) object_p); ecma_free_value (job_p->executable_object); jmem_heap_free_block (job_p, sizeof (ecma_job_promise_async_generator_t)); + return result; } /* ecma_process_promise_async_generator_job */ /** @@ -537,7 +541,7 @@ ecma_process_all_enqueued_jobs (void) } case ECMA_JOB_PROMISE_ASYNC_GENERATOR: { - ecma_process_promise_async_generator_job ((ecma_job_promise_async_generator_t *) job_p); + ret = ecma_process_promise_async_generator_job ((ecma_job_promise_async_generator_t *) job_p); break; } default: diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index a024b740e..7aead58ee 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -795,6 +795,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_DATE_STRING_UL, "toDateString") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TO_TIME_STRING_UL, "toTimeString") #endif #if ENABLED (JERRY_ESNEXT) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASYNC_FUNCTION_UL, "AsyncFunction") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASYNC_ITERATOR, "asyncIterator") #endif #if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ESNEXT) @@ -1006,7 +1007,7 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_SET_ITERATOR_UL) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (12, LIT_MAGIC_STRING_CONFIGURABLE) #endif #if ENABLED (JERRY_ESNEXT) -LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_ASYNC_ITERATOR) +LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_ASYNC_FUNCTION_UL) #elif ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ESNEXT) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (13, LIT_MAGIC_STRING_FROM_CODE_POINT_UL) #elif ENABLED (JERRY_BUILTIN_DATE) diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index bc9ac6a39..e2757cfc9 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -319,6 +319,7 @@ LIT_MAGIC_STRING_FROM_CODE_POINT_UL = "fromCodePoint" LIT_MAGIC_STRING_IS_EXTENSIBLE = "isExtensible" LIT_MAGIC_STRING_TO_DATE_STRING_UL = "toDateString" LIT_MAGIC_STRING_TO_TIME_STRING_UL = "toTimeString" +LIT_MAGIC_STRING_ASYNC_FUNCTION_UL = "AsyncFunction" LIT_MAGIC_STRING_ASYNC_ITERATOR = "asyncIterator" LIT_MAGIC_STRING_GET_UTC_MINUTES_UL = "getUTCMinutes" LIT_MAGIC_STRING_GET_UTC_SECONDS_UL = "getUTCSeconds" diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 8ba94a292..6bdbd38a4 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -846,7 +846,7 @@ typedef enum CBC_CODE_FLAGS_HAS_TAGGED_LITERALS = (1u << 9), /**< this function has tagged template literal list */ CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED = (1u << 10), /**< compiled code needs a lexical block */ - /* Bits from bit 13 is reserved for function types (see CBC_FUNCTION_TYPE_SHIFT). + /* Bits from bit 12 is reserved for function types (see CBC_FUNCTION_TYPE_SHIFT). * Note: the last bits are used for type flags because < and >= operators can be used to check a range of types without decoding the actual type. */ } cbc_code_flags_t; @@ -867,14 +867,17 @@ typedef enum CBC_FUNCTION_ASYNC_GENERATOR, /**< async generator function */ /* The following functions has no prototype (see CBC_FUNCTION_HAS_PROTOTYPE) */ - CBC_FUNCTION_ARROW, /**< arrow function */ CBC_FUNCTION_ACCESSOR, /**< property accessor function */ + + /* The following functions are arrow function (see CBC_FUNCTION_IS_ARROW) */ + CBC_FUNCTION_ARROW, /**< arrow function */ + CBC_FUNCTION_ASYNC_ARROW, /**< arrow function */ } cbc_code_function_types_t; /** * Shift for getting / setting the function type of a byte code. */ -#define CBC_FUNCTION_TYPE_SHIFT 13 +#define CBC_FUNCTION_TYPE_SHIFT 12 /** * Compute function type bits in code flags. @@ -904,7 +907,13 @@ typedef enum * Checks whether the function has prototype property. */ #define CBC_FUNCTION_HAS_PROTOTYPE(flags) \ - ((flags) < (CBC_FUNCTION_ARROW << CBC_FUNCTION_TYPE_SHIFT)) + ((flags) < (CBC_FUNCTION_ACCESSOR << CBC_FUNCTION_TYPE_SHIFT)) + +/** + * Checks whether the function is an arrow function. + */ +#define CBC_FUNCTION_IS_ARROW(flags) \ + ((flags) >= (CBC_FUNCTION_ARROW << CBC_FUNCTION_TYPE_SHIFT)) /** * Any arguments object is needed diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 6c2e38c9f..9573a828e 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -713,14 +713,19 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code JERRY_DEBUG_MSG (",async_generator"); break; } + case CBC_FUNCTION_ACCESSOR: + { + JERRY_DEBUG_MSG (",accessor"); + break; + } case CBC_FUNCTION_ARROW: { JERRY_DEBUG_MSG (",arrow"); break; } - case CBC_FUNCTION_ACCESSOR: + case CBC_FUNCTION_ASYNC_ARROW: { - JERRY_DEBUG_MSG (",accessor"); + JERRY_DEBUG_MSG (",async_arrow"); break; } } @@ -1372,7 +1377,14 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } else if (context_p->status_flags & PARSER_IS_ARROW_FUNCTION) { - function_type = CBC_FUNCTION_TO_TYPE_BITS (CBC_FUNCTION_ARROW); + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) + { + function_type = CBC_FUNCTION_TO_TYPE_BITS (CBC_FUNCTION_ASYNC_ARROW); + } + else + { + function_type = CBC_FUNCTION_TO_TYPE_BITS (CBC_FUNCTION_ARROW); + } } else if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) { diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index e19f70c5a..d433bb3d2 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -893,9 +893,8 @@ opfunc_async_create_and_await (vm_frame_ctx_t *frame_ctx_p, /**< frame context * uint16_t extra_flags) /**< extra flags */ { JERRY_ASSERT (frame_ctx_p->block_result == ECMA_VALUE_UNDEFINED); - /* TODO: An CBC_FUNCTION_ASYNC_ARROW should be defined. */ JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (frame_ctx_p->bytecode_header_p->status_flags) == CBC_FUNCTION_ASYNC - || CBC_FUNCTION_GET_TYPE (frame_ctx_p->bytecode_header_p->status_flags) == CBC_FUNCTION_ARROW); + || CBC_FUNCTION_GET_TYPE (frame_ctx_p->bytecode_header_p->status_flags) == CBC_FUNCTION_ASYNC_ARROW); ecma_object_t *promise_p = ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE); ecma_value_t result = ecma_promise_reject_or_resolve (ecma_make_object_value (promise_p), value, true); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 7ac2af6ef..db541b916 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -475,33 +475,18 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ ecma_object_t *func_obj_p; #if ENABLED (JERRY_ESNEXT) - switch (CBC_FUNCTION_GET_TYPE (bytecode_p->status_flags)) + if (JERRY_UNLIKELY (CBC_FUNCTION_IS_ARROW (bytecode_p->status_flags))) { - case CBC_FUNCTION_GENERATOR: - { - func_obj_p = ecma_op_create_generator_function_object (frame_ctx_p->lex_env_p, bytecode_p); - break; - } - case CBC_FUNCTION_ASYNC_GENERATOR: - { - func_obj_p = ecma_op_create_async_generator_function_object (frame_ctx_p->lex_env_p, bytecode_p); - break; - } - case CBC_FUNCTION_ARROW: - { - func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p, - bytecode_p, - frame_ctx_p->this_binding); - break; - } - default: - { -#endif /* ENABLED (JERRY_ESNEXT) */ - func_obj_p = ecma_op_create_simple_function_object (frame_ctx_p->lex_env_p, bytecode_p); -#if ENABLED (JERRY_ESNEXT) - break; - } + func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p, + bytecode_p, + frame_ctx_p->this_binding); } + else + { + func_obj_p = ecma_op_create_any_function_object (frame_ctx_p->lex_env_p, bytecode_p); + } +#else /* !ENABLED (JERRY_ESNEXT) */ + func_obj_p = ecma_op_create_simple_function_object (frame_ctx_p->lex_env_p, bytecode_p); #endif /* ENABLED (JERRY_ESNEXT) */ return ecma_make_object_value (func_obj_p); diff --git a/tests/jerry/es.next/for-await-of-iterator-close.js b/tests/jerry/es.next/for-await-of-iterator-close.js index f576da339..9d8c23ee2 100644 --- a/tests/jerry/es.next/for-await-of-iterator-close.js +++ b/tests/jerry/es.next/for-await-of-iterator-close.js @@ -615,9 +615,35 @@ async function f11() { f11() +// Test 12 + +var o12 = {} +async function *gen12() +{ + try { + yield 9.5 + assert(false) + } finally { + successCount++ + } + assert(false) +} + +async function f12() +{ + for await (var v of gen12()) + { + assert(v === 9.5) + break; + } + successCount++ +} + +f12() + // END function __checkAsync() { assert(returnCount2 === 5) - assert(successCount === 34) + assert(successCount === 36) } diff --git a/tests/jerry/es.next/for-await-of.js b/tests/jerry/es.next/for-await-of.js index e042a9083..a1994ab86 100644 --- a/tests/jerry/es.next/for-await-of.js +++ b/tests/jerry/es.next/for-await-of.js @@ -190,9 +190,41 @@ async function f2b() { f2b(); +// Test 3 + +var o3 = {} +async function* gen3() +{ + yield o3 + yield "Res" +} + +async function f3() +{ + var idx = 0 + + for await (var v of gen3()) + { + idx++ + + if (idx === 1) + { + assert(v === o3) + } + else + { + assert(idx === 2) + assert(v === "Res") + } + } + successCount++ +} + +f3() + // END function __checkAsync() { assert(state2 === 8) - assert(successCount === 23) + assert(successCount === 24) } diff --git a/tests/jerry/es.next/function-async3.js b/tests/jerry/es.next/function-async3.js new file mode 100644 index 000000000..3eb842779 --- /dev/null +++ b/tests/jerry/es.next/function-async3.js @@ -0,0 +1,32 @@ +// 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. + +/* This test async prototype. */ + +var proto1 = Object.getPrototypeOf(async () => {}) +var proto2 = Object.getPrototypeOf(async function () {}) + +assert(proto1 === proto2) +assert(typeof proto1 === "object") +assert(proto1[Symbol.toStringTag] === "AsyncFunction") +assert(typeof proto1.constructor === "function") +assert(proto1.constructor.name === "AsyncFunction") + +var successCount = 0 +var f = proto1.constructor("p", "assert(await p === 'Res'); successCount++") +f(Promise.resolve("Res")) + +function __checkAsync() { + assert(successCount === 1) +}