From 4a331b2edc0b2d009b4ecf665b6b408491b00e81 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Wed, 15 Jan 2020 12:01:58 +0100 Subject: [PATCH] Add builtin GeneratorFunction support (#3499) JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- jerry-core/api/jerry-snapshot.c | 3 +- jerry-core/api/jerry.c | 6 +- jerry-core/ecma/base/ecma-globals.h | 1 + jerry-core/ecma/base/ecma-init-finalize.c | 2 + .../builtin-objects/ecma-builtin-function.c | 117 +------- .../ecma-builtin-generator-function.c | 72 +++++ .../ecma-builtin-generator-function.inc.h | 41 +++ .../ecma-builtin-generator-prototype.c | 2 +- .../ecma-builtin-generator-prototype.inc.h | 5 + .../builtin-objects/ecma-builtin-generator.c | 43 +++ .../ecma-builtin-generator.inc.h | 41 +++ .../ecma/builtin-objects/ecma-builtins.inc.h | 15 + .../ecma/operations/ecma-function-object.c | 279 +++++++++++++++++- .../ecma/operations/ecma-function-object.h | 15 +- jerry-core/ecma/operations/ecma-objects.c | 6 + jerry-core/jcontext/jcontext.h | 2 + jerry-core/lit/lit-magic-strings.inc.h | 8 + jerry-core/lit/lit-magic-strings.ini | 1 + jerry-core/parser/js/js-parser.c | 15 +- jerry-core/parser/js/js-scanner.c | 1 - jerry-core/vm/opcodes.c | 7 +- jerry-core/vm/vm.c | 28 +- tests/jerry/es2015/generator-function.js | 97 ++++++ tests/jerry/function-construct.js | 4 + 24 files changed, 659 insertions(+), 152 deletions(-) create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-generator.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-generator.inc.h create mode 100644 tests/jerry/es2015/generator-function.js diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index 85e034725..30d112e30 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -990,8 +990,7 @@ jerry_snapshot_result (const uint32_t *snapshot_p, /**< snapshot */ if (as_function) { ecma_object_t *lex_env_p = ecma_get_global_environment (); - ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p, - bytecode_p); + ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_p); if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) { diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index a08bcc18e..e7dbfa153 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -457,8 +457,7 @@ jerry_parse (const jerry_char_t *resource_name_p, /**< resource name (usually a ecma_free_value (parse_status); ecma_object_t *lex_env_p = ecma_get_global_environment (); - ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p, - bytecode_data_p); + ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_data_p); ecma_bytecode_deref (bytecode_data_p); return ecma_make_object_value (func_obj_p); @@ -539,8 +538,7 @@ jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (u ecma_free_value (parse_status); ecma_object_t *lex_env_p = ecma_get_global_environment (); - ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p, - bytecode_data_p); + ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_data_p); ecma_bytecode_deref (bytecode_data_p); return ecma_make_object_value (func_obj_p); diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index f9a035c3d..454fd3c44 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -108,6 +108,7 @@ typedef enum ECMA_PARSE_EVAL = (1u << 6), /**< eval is called */ ECMA_PARSE_MODULE = (1u << 7), /**< module is parsed */ ECMA_PARSE_FUNCTION = (1u << 8), /**< a function body is parsed or the code is inside a function */ + ECMA_PARSE_GENERATOR_FUNCTION = (1u << 9), /**< generator function is parsed */ } ecma_parse_opts_t; /** diff --git a/jerry-core/ecma/base/ecma-init-finalize.c b/jerry-core/ecma/base/ecma-init-finalize.c index 1e43aad0d..d7c454851 100644 --- a/jerry-core/ecma/base/ecma-init-finalize.c +++ b/jerry-core/ecma/base/ecma-init-finalize.c @@ -57,6 +57,7 @@ ecma_init (void) #if ENABLED (JERRY_ES2015) JERRY_CONTEXT (current_new_target) = JERRY_CONTEXT_INVALID_NEW_TARGET; + JERRY_CONTEXT (current_function_obj_p) = NULL; #endif /* ENABLED (JERRY_ES2015) */ } /* ecma_init */ @@ -68,6 +69,7 @@ ecma_finalize (void) { #if ENABLED (JERRY_ES2015) JERRY_ASSERT (JERRY_CONTEXT (current_new_target) == JERRY_CONTEXT_INVALID_NEW_TARGET); + JERRY_ASSERT (JERRY_CONTEXT (current_function_obj_p) == NULL); #endif /* ENABLED (JERRY_ES2015) */ ecma_finalize_global_lex_env (); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function.c b/jerry-core/ecma/builtin-objects/ecma-builtin-function.c index b0ed4649c..e9499168a 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function.c @@ -59,58 +59,6 @@ ecma_builtin_function_dispatch_call (const ecma_value_t *arguments_list_p, /**< return ecma_builtin_function_dispatch_construct (arguments_list_p, arguments_list_len); } /* ecma_builtin_function_dispatch_call */ -/** - * Helper method to count and convert the arguments for the Function constructor call. - * - * Performs the operation described in ECMA 262 v5.1 15.3.2.1 steps 5.a-d - * - * - * @return ecma value - concatenated arguments as a string. - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_function_helper_get_function_arguments (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 <= 1) - { - return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); - } - - ecma_string_t *final_str_p = ecma_op_to_string (arguments_list_p[0]); - - if (JERRY_UNLIKELY (final_str_p == NULL)) - { - return ECMA_VALUE_ERROR; - } - - if (arguments_list_len == 2) - { - return ecma_make_string_value (final_str_p); - } - - for (ecma_length_t idx = 1; idx < arguments_list_len - 1; idx++) - { - ecma_string_t *new_str_p = ecma_op_to_string (arguments_list_p[idx]); - - if (JERRY_UNLIKELY (new_str_p == NULL)) - { - ecma_deref_ecma_string (final_str_p); - return ECMA_VALUE_ERROR; - } - - final_str_p = ecma_append_magic_string_to_string (final_str_p, - LIT_MAGIC_STRING_COMMA_CHAR); - - final_str_p = ecma_concat_ecma_strings (final_str_p, new_str_p); - ecma_deref_ecma_string (new_str_p); - } - - return ecma_make_string_value (final_str_p); -} /* ecma_builtin_function_helper_get_function_arguments */ - /** * Handle calling [[Construct]] of built-in Function object * @@ -123,70 +71,7 @@ ecma_value_t ecma_builtin_function_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); - - ecma_value_t arguments_value = ecma_builtin_function_helper_get_function_arguments (arguments_list_p, - arguments_list_len); - - if (ECMA_IS_VALUE_ERROR (arguments_value)) - { - return arguments_value; - } - - ecma_string_t *function_body_str_p; - - if (arguments_list_len > 0) - { - function_body_str_p = ecma_op_to_string (arguments_list_p[arguments_list_len - 1]); - - if (JERRY_UNLIKELY (function_body_str_p == NULL)) - { - ecma_free_value (arguments_value); - return ECMA_VALUE_ERROR; - } - } - else - { - /* Very unlikely code path, not optimized. */ - function_body_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - } - - ecma_string_t *arguments_str_p = ecma_get_string_from_value (arguments_value); - - ECMA_STRING_TO_UTF8_STRING (arguments_str_p, arguments_buffer_p, arguments_buffer_size); - ECMA_STRING_TO_UTF8_STRING (function_body_str_p, function_body_buffer_p, function_body_buffer_size); - -#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) - JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING_RESOURCE_ANON); -#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - - ecma_compiled_code_t *bytecode_data_p = NULL; - - ecma_value_t ret_value = parser_parse_script (arguments_buffer_p, - arguments_buffer_size, - function_body_buffer_p, - function_body_buffer_size, - ECMA_PARSE_NO_OPTS, - &bytecode_data_p); - - if (!ECMA_IS_VALUE_ERROR (ret_value)) - { - JERRY_ASSERT (ecma_is_value_true (ret_value)); - - ecma_object_t *func_obj_p = ecma_op_create_function_object (ecma_get_global_environment (), - bytecode_data_p); - - ecma_bytecode_deref (bytecode_data_p); - ret_value = ecma_make_object_value (func_obj_p); - } - - ECMA_FINALIZE_UTF8_STRING (function_body_buffer_p, function_body_buffer_size); - ECMA_FINALIZE_UTF8_STRING (arguments_buffer_p, arguments_buffer_size); - - ecma_deref_ecma_string (arguments_str_p); - ecma_deref_ecma_string (function_body_str_p); - - return ret_value; + return ecma_op_create_dynamic_function (arguments_list_p, arguments_list_len, ECMA_PARSE_NO_OPTS); } /* ecma_builtin_function_dispatch_construct */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.c b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.c new file mode 100644 index 000000000..258ce9b80 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.c @@ -0,0 +1,72 @@ +/* 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_ES2015) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" +#include "ecma-function-object.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-generator-function.inc.h" +#define BUILTIN_UNDERSCORED_ID generator_function +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup generator ECMA GeneratorFunction object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in GeneratorFunction object + * + * @return constructed generator function object - if success + * raised error otherwise + */ +ecma_value_t +ecma_builtin_generator_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_GENERATOR_FUNCTION); +} /* ecma_builtin_generator_function_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in GeneratorFunction object + * +* @return constructed generator function object - if success + * raised error otherwise + */ +ecma_value_t +ecma_builtin_generator_function_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_builtin_generator_function_dispatch_call (arguments_list_p, arguments_list_len); +} /* ecma_builtin_generator_function_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-function.inc.h new file mode 100644 index 000000000..bbae8b2d0 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-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. + */ + +/* + * %GeneratorFunction% built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015) + +/* ECMA-262 v6, 25.2.2 */ +STRING_VALUE (LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_GENERATOR_FUNCTION_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 25.2.2 */ +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 1, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 25.2.2.2 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_GENERATOR, + ECMA_PROPERTY_FIXED) + +#endif /* ENABLED (JERRY_ES2015) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c index d59a874c8..a09deba35 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.c @@ -38,7 +38,7 @@ * \addtogroup ecmabuiltins * @{ * - * \addtogroup generator ECMA Generator object built-in + * \addtogroup generator ECMA Generator.prototype object built-in * @{ */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.inc.h index 588de23c0..e21878fef 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator-prototype.inc.h @@ -29,6 +29,11 @@ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_GENERATOR_UL, ECMA_PROPERTY_FLAG_CONFIGURABLE) +/* ECMA-262 v6, 25.2.3.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_GENERATOR, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ ROUTINE (LIT_MAGIC_STRING_NEXT, ecma_builtin_generator_prototype_object_next, 1, 1) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator.c b/jerry-core/ecma/builtin-objects/ecma-builtin-generator.c new file mode 100644 index 000000000..663659b2e --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator.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_ES2015) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-generator.inc.h" +#define BUILTIN_UNDERSCORED_ID generator +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup generator ECMA Generator object built-in + * @{ + */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-generator.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-generator.inc.h new file mode 100644 index 000000000..8d38bc0c7 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-generator.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. + */ + +/* + * %Generator% built-in description (GeneratorFunction.prototype) + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015) + +/* ECMA-262 v6, 25.3.2.3.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_GENERATOR_FUNCTION, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 25.3.2.3.2 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* ECMA-262 v6, 25.3.2.3.3 */ +STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_GENERATOR_FUNCTION_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +#endif /* ENABLED (JERRY_ES2015) */ + +#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 2fd2faba4..b2b4c6be9 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -552,6 +552,21 @@ BUILTIN (ECMA_BUILTIN_ID_STRING_ITERATOR_PROTOTYPE, true, string_iterator_prototype) +/* The %(GeneratorFunction)% object */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_GENERATOR_FUNCTION, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION, + true, + generator_function) + +/* The %(Generator)% object */ +BUILTIN (ECMA_BUILTIN_ID_GENERATOR, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + generator) + +/* The %(Generator).prototype% object */ BUILTIN (ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_ITERATOR_PROTOTYPE, diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 24c16a666..7539f9d61 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -15,11 +15,11 @@ #include "ecma-alloc.h" #include "ecma-builtin-helpers.h" -#include "ecma-builtins.h" #include "ecma-exceptions.h" #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-helpers.h" +#include "lit-char-helpers.h" #include "ecma-lex-env.h" #include "ecma-objects.h" #include "ecma-objects-general.h" @@ -143,6 +143,152 @@ ecma_is_constructor (ecma_value_t value) /**< ecma value */ && ecma_object_is_constructor (ecma_get_object_from_value (value))); } /* ecma_is_constructor */ +/** + * Helper method to count and convert the arguments for the Function/GeneratorFunction constructor call. + * + * See also: + * ECMA 262 v5.1 15.3.2.1 steps 5.a-d + * ECMA 262 v6 19.2.1.1.1 steps 8 + * + * @return ecma value - concatenated arguments as a string. + * Returned value must be freed with ecma_free_value. + */ +static ecma_string_t * +ecma_op_create_dynamic_function_arguments_helper (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 <= 1) + { + return ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); + } + + ecma_string_t *str_p = ecma_op_to_string (arguments_list_p[0]); + + if (JERRY_UNLIKELY (str_p == NULL)) + { + return str_p; + } + + if (arguments_list_len == 2) + { + return str_p; + } + + ecma_stringbuilder_t builder = ecma_stringbuilder_create_from (str_p); + ecma_deref_ecma_string (str_p); + + for (ecma_length_t idx = 1; idx < arguments_list_len - 1; idx++) + { + str_p = ecma_op_to_string (arguments_list_p[idx]); + + if (JERRY_UNLIKELY (str_p == NULL)) + { + ecma_stringbuilder_destroy (&builder); + return str_p; + } + + ecma_stringbuilder_append_char (&builder, LIT_CHAR_COMMA); + ecma_stringbuilder_append (&builder, str_p); + ecma_deref_ecma_string (str_p); + } + + return ecma_stringbuilder_finalize (&builder); +} /* ecma_op_create_dynamic_function_arguments_helper */ + +/** + * CreateDynamicFunction operation + * + * See also: + * ECMA-262 v5, 15.3. + * ECMA-262 v6, 19.2.1.1 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * constructed function object - otherwise + */ +ecma_value_t +ecma_op_create_dynamic_function (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len, /**< number of arguments */ + ecma_parse_opts_t parse_opts) /**< parse options */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + ecma_string_t *arguments_str_p = ecma_op_create_dynamic_function_arguments_helper (arguments_list_p, + arguments_list_len); + + if (JERRY_UNLIKELY (arguments_str_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ecma_string_t *function_body_str_p; + + if (arguments_list_len > 0) + { + function_body_str_p = ecma_op_to_string (arguments_list_p[arguments_list_len - 1]); + + if (JERRY_UNLIKELY (function_body_str_p == NULL)) + { + ecma_deref_ecma_string (arguments_str_p); + return ECMA_VALUE_ERROR; + } + } + else + { + /* Very unlikely code path, not optimized. */ + function_body_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); + } + + ECMA_STRING_TO_UTF8_STRING (arguments_str_p, arguments_buffer_p, arguments_buffer_size); + ECMA_STRING_TO_UTF8_STRING (function_body_str_p, function_body_buffer_p, function_body_buffer_size); + +#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) + JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING_RESOURCE_ANON); +#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + + ecma_compiled_code_t *bytecode_data_p = NULL; + + ecma_value_t ret_value = parser_parse_script (arguments_buffer_p, + arguments_buffer_size, + function_body_buffer_p, + function_body_buffer_size, + parse_opts, + &bytecode_data_p); + + if (!ECMA_IS_VALUE_ERROR (ret_value)) + { + JERRY_ASSERT (ecma_is_value_true (ret_value)); + + ecma_object_t *func_obj_p; + ecma_object_t *global_env_p = ecma_get_global_environment (); + +#if ENABLED (JERRY_ES2015) + if (parse_opts & ECMA_PARSE_GENERATOR_FUNCTION) + { + func_obj_p = ecma_op_create_generator_function_object (global_env_p, bytecode_data_p); + } + else + { +#endif /* ENABLED (JERRY_ES2015) */ + func_obj_p = ecma_op_create_simple_function_object (global_env_p, bytecode_data_p); +#if ENABLED (JERRY_ES2015) + } +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_bytecode_deref (bytecode_data_p); + ret_value = ecma_make_object_value (func_obj_p); + } + + ECMA_FINALIZE_UTF8_STRING (function_body_buffer_p, function_body_buffer_size); + ECMA_FINALIZE_UTF8_STRING (arguments_buffer_p, arguments_buffer_size); + + ecma_deref_ecma_string (arguments_str_p); + ecma_deref_ecma_string (function_body_str_p); + + return ret_value; +} /* ecma_op_create_dynamic_function */ + /** * Function object creation operation. * @@ -150,14 +296,15 @@ ecma_is_constructor (ecma_value_t value) /**< ecma value */ * * @return pointer to newly created Function object */ -ecma_object_t * +static ecma_object_t * ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ - const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */ + const ecma_compiled_code_t *bytecode_data_p, /**< byte-code array */ + ecma_builtin_id_t proto_id) /**< builtin id of the prototype object */ { JERRY_ASSERT (ecma_is_lexical_environment (scope_p)); /* 1., 4., 13. */ - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + ecma_object_t *prototype_obj_p = ecma_builtin_get (proto_id); size_t function_object_size = sizeof (ecma_extended_object_t); @@ -219,8 +366,36 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ return func_p; } /* ecma_op_create_function_object */ +/** + * Function object creation operation. + * + * See also: ECMA-262 v5, 13.2 + * + * @return pointer to newly created Function object + */ +ecma_object_t * +ecma_op_create_simple_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_FUNCTION_PROTOTYPE); +} /* ecma_op_create_simple_function_object */ + #if ENABLED (JERRY_ES2015) +/** + * GeneratorFunction object creation operation. + * + * See also: ECMA-262 v5, 13.2 + * + * @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 */ +{ + return ecma_op_create_function_object (scope_p, bytecode_data_p, ECMA_BUILTIN_ID_GENERATOR); +} /* ecma_op_create_generator_function_object */ + /** * Arrow function object creation operation. * @@ -722,6 +897,43 @@ ecma_op_set_class_prototype (ecma_value_t completion_value, /**< completion_valu completion_obj_p->u2.prototype_cp = prototype_obj_cp; } /* ecma_op_set_class_prototype */ + +/** + * Ordinary internal method: GetPrototypeFromConstructor (constructor, intrinsicDefaultProto) + * + * See also: ECMAScript v6, 9.1.15 + * + * @return NULL - if the operation fail (exception on the global context is raised) + * pointer to the prototype object - otherwise + */ +ecma_object_t * +ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, /**< constructor to get prototype from */ + ecma_builtin_id_t default_proto_id) /**< intrinsicDefaultProto */ +{ + JERRY_ASSERT (ecma_object_is_constructor (ctor_obj_p)); + JERRY_ASSERT (default_proto_id < ECMA_BUILTIN_ID__COUNT); + + ecma_value_t proto = ecma_op_object_get_by_magic_id (ctor_obj_p, LIT_MAGIC_STRING_PROTOTYPE); + + if (ECMA_IS_VALUE_ERROR (proto)) + { + return NULL; + } + + ecma_object_t *proto_obj_p; + + if (!ecma_is_value_object (proto)) + { + proto_obj_p = ecma_builtin_get (default_proto_id); + ecma_ref_object (proto_obj_p); + } + else + { + proto_obj_p = ecma_get_object_from_value (proto); + } + + return proto_obj_p; +} /* ecma_op_get_prototype_from_constructor */ #endif /* ENABLED (JERRY_ES2015) */ /** @@ -776,9 +988,15 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ { return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); } - if (is_construct_call && (status_flags & CBC_CODE_FLAGS_GENERATOR)) + + if (status_flags & CBC_CODE_FLAGS_GENERATOR) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Generator functions cannot be invoked with 'new'.")); + if (is_construct_call) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Generator functions cannot be invoked with 'new'.")); + } + + JERRY_CONTEXT (current_function_obj_p) = func_obj_p; } } #endif /* ENABLED (JERRY_ES2015) */ @@ -835,6 +1053,13 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ arguments_list_p, arguments_list_len); +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (status_flags & CBC_CODE_FLAGS_GENERATOR)) + { + JERRY_CONTEXT (current_function_obj_p) = NULL; + } +#endif /* ENABLED (JERRY_ES2015) */ + if (!(status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED)) { ecma_deref_object (local_env_p); @@ -1320,21 +1545,45 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ static ecma_property_t * ecma_op_lazy_instantiate_prototype_object (ecma_object_t *object_p) /**< the function object */ { - JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION + JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION || ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); /* ECMA-262 v5, 13.2, 16-18 */ - /* 16. */ - ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg (); + + ecma_object_t *proto_object_p = NULL; + bool init_constructor = true; + +#if ENABLED (JERRY_ES2015) + if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) + { + const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p); + + if (byte_code_p->status_flags & CBC_CODE_FLAGS_GENERATOR) + { + proto_object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE), + 0, + ECMA_OBJECT_TYPE_GENERAL); + init_constructor = false; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + + if (proto_object_p == NULL) + { + proto_object_p = ecma_op_create_object_object_noarg (); + } /* 17. */ - ecma_property_value_t *constructor_prop_value_p; - constructor_prop_value_p = ecma_create_named_data_property (proto_object_p, - ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR), - ECMA_PROPERTY_CONFIGURABLE_WRITABLE, - NULL); + if (init_constructor) + { + ecma_property_value_t *constructor_prop_value_p; + constructor_prop_value_p = ecma_create_named_data_property (proto_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR), + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + NULL); - constructor_prop_value_p->value = ecma_make_object_value (object_p); + constructor_prop_value_p->value = ecma_make_object_value (object_p); + } /* 18. */ ecma_property_t *prototype_prop_p; diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index 62230138b..b7dc12102 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -17,6 +17,7 @@ #define ECMA_FUNCTION_OBJECT_H #include "ecma-globals.h" +#include "ecma-builtins.h" #include "vm.h" /** \addtogroup ecma ECMA @@ -38,8 +39,7 @@ bool ecma_is_constructor (ecma_value_t value); bool ecma_object_is_constructor (ecma_object_t *obj_p); ecma_object_t * -ecma_op_create_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p); - +ecma_op_create_simple_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p); ecma_object_t * ecma_op_create_external_function_object (ecma_external_handler_t handler_cb); @@ -47,6 +47,11 @@ ecma_op_create_external_function_object (ecma_external_handler_t handler_cb); const ecma_compiled_code_t * ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p); +ecma_value_t +ecma_op_create_dynamic_function (const ecma_value_t *arguments_list_p, + ecma_length_t arguments_list_len, + ecma_parse_opts_t opts); + #if ENABLED (JERRY_ES2015) void ecma_op_set_super_called (ecma_object_t *lex_env_p); @@ -69,6 +74,12 @@ ecma_op_function_implicit_constructor_handler_cb (const ecma_value_t function_ob void ecma_op_set_class_prototype (ecma_value_t completion_value, ecma_value_t this_arg); +ecma_object_t * +ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, ecma_builtin_id_t default_proto_id); + +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_arrow_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p, ecma_value_t this_binding); diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 49eee003b..613d62d9a 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -2471,6 +2471,12 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ return LIT_MAGIC_STRING_REFLECT_UL; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_REFLECT) */ +#if ENABLED (JERRY_ES2015) + case ECMA_BUILTIN_ID_GENERATOR: + { + return LIT_MAGIC_STRING_GENERATOR_UL; + } +#endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_BUILTIN_JSON) case ECMA_BUILTIN_ID_JSON: { diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 619ce29d7..a2ce3b49f 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -229,6 +229,8 @@ struct jerry_context_t * * Any other valid function object pointer: the current "new.target" is valid and it is constructor call. */ ecma_object_t *current_new_target; + ecma_object_t *current_function_obj_p; /** currently invoked function object + (Note: currently used only in generator functions) */ #endif /* ENABLED (JERRY_ES2015) */ }; diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 04602f36d..4918a0118 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -25,7 +25,10 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RIGHT_PAREN, ")") #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASTERIX_CHAR, "*") #endif +#if ENABLED (JERRY_BUILTIN_ARRAY) \ +|| ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMMA_CHAR, ",") +#endif #if ENABLED (JERRY_LINE_INFO) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COLON_CHAR, ":") #endif @@ -772,6 +775,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DEFINE_PROPERTIES_UL, "defineProperties") #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U, "BYTES_PER_ELEMENT") #endif +#if ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GENERATOR_FUNCTION_UL, "GeneratorFunction") +#endif #if ENABLED (JERRY_BUILTIN_NUMBER) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NEGATIVE_INFINITY_U, "NEGATIVE_INFINITY") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_POSITIVE_INFINITY_U, "POSITIVE_INFINITY") @@ -916,6 +922,8 @@ LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (16, LIT_MAGIC_STRING_DEFINE_PROPERTIES_ #endif #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (17, LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U) +#elif ENABLED (JERRY_ES2015) +LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (17, LIT_MAGIC_STRING_GENERATOR_FUNCTION_UL) #elif ENABLED (JERRY_BUILTIN_NUMBER) LIT_MAGIC_STRING_FIRST_STRING_WITH_SIZE (17, LIT_MAGIC_STRING_NEGATIVE_INFINITY_U) #elif ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index a2042c314..f19030a33 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -325,6 +325,7 @@ LIT_MAGIC_STRING_MIN_SAFE_INTEGER_U = "MIN_SAFE_INTEGER" LIT_MAGIC_STRING_BYTES_PER_ELEMENT_U = "BYTES_PER_ELEMENT" LIT_MAGIC_STRING_NEGATIVE_INFINITY_U = "NEGATIVE_INFINITY" LIT_MAGIC_STRING_POSITIVE_INFINITY_U = "POSITIVE_INFINITY" +LIT_MAGIC_STRING_GENERATOR_FUNCTION_UL = "GeneratorFunction" LIT_MAGIC_STRING_UINT8_CLAMPED_ARRAY_UL = "Uint8ClampedArray" LIT_MAGIC_STRING_GET_TIMEZONE_OFFSET_UL = "getTimezoneOffset" LIT_MAGIC_STRING_PREVENT_EXTENSIONS_UL = "preventExtensions" diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 3f9f599af..f385eee56 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1915,7 +1915,20 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ error_location_p->error = PARSER_ERR_NO_ERROR; } - context.status_flags = (arg_list_p == NULL) ? 0 : PARSER_IS_FUNCTION; + if (arg_list_p == NULL) + { + context.status_flags = 0; + } + else + { + context.status_flags = PARSER_IS_FUNCTION; +#if ENABLED (JERRY_ES2015) + if (parse_opts & ECMA_PARSE_GENERATOR_FUNCTION) + { + context.status_flags |= PARSER_IS_GENERATOR_FUNCTION; + } +#endif /* ENABLED (JERRY_ES2015) */ + } #if ENABLED (JERRY_ES2015) context.status_flags |= PARSER_GET_CLASS_PARSER_OPTS (parse_opts); diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index dc4cc652a..a0f8cbf27 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -3071,7 +3071,6 @@ scan_completed: #if ENABLED (JERRY_ES2015) JERRY_ASSERT (scanner_context.active_binding_list_p == NULL); - JERRY_ASSERT (!(context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION)); #endif /* ENABLED (JERRY_ES2015) */ JERRY_ASSERT (scanner_context.active_literal_pool_p == NULL); diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index fd5de8da8..1c60c8db4 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -571,10 +571,15 @@ opfunc_create_executable_object (vm_frame_ctx_t *frame_ctx_p) /**< frame context size_t total_size = JERRY_ALIGNUP (sizeof (vm_executable_object_t) + size, sizeof (uintptr_t)); - ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE), + ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_function_obj_p), + ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE); + + ecma_object_t *object_p = ecma_create_object (proto_p, total_size, ECMA_OBJECT_TYPE_CLASS); + ecma_deref_object (proto_p); + vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p; executable_object_p->extended_object.u.class_prop.class_id = LIT_MAGIC_STRING_GENERATOR_UL; diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index e8c153e0f..a5d0ede13 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -414,19 +414,22 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ ecma_object_t *func_obj_p; #if ENABLED (JERRY_ES2015) - if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION)) - { -#endif /* ENABLED (JERRY_ES2015) */ - func_obj_p = ecma_op_create_function_object (frame_ctx_p->lex_env_p, - bytecode_p); -#if ENABLED (JERRY_ES2015) - } - else + if (bytecode_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) { func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p, bytecode_p, frame_ctx_p->this_binding); } + else if (bytecode_p->status_flags & CBC_CODE_FLAGS_GENERATOR) + { + func_obj_p = ecma_op_create_generator_function_object (frame_ctx_p->lex_env_p, bytecode_p); + } + else + { +#endif /* ENABLED (JERRY_ES2015) */ + func_obj_p = ecma_op_create_simple_function_object (frame_ctx_p->lex_env_p, bytecode_p); +#if ENABLED (JERRY_ES2015) + } #endif /* ENABLED (JERRY_ES2015) */ return ecma_make_object_value (func_obj_p); @@ -2077,7 +2080,14 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ frame_ctx_p->call_operation = VM_EXEC_RETURN; frame_ctx_p->byte_code_p = byte_code_p; frame_ctx_p->stack_top_p = stack_top_p; - return opfunc_create_executable_object (frame_ctx_p); + result = opfunc_create_executable_object (frame_ctx_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + + return result; } case VM_OC_YIELD: { diff --git a/tests/jerry/es2015/generator-function.js b/tests/jerry/es2015/generator-function.js new file mode 100644 index 000000000..0342dc41e --- /dev/null +++ b/tests/jerry/es2015/generator-function.js @@ -0,0 +1,97 @@ +// 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. + + +// Test %GeneratorPrototype% +(function () { + function* generatorFn(){} + var ownProto = Object.getPrototypeOf(generatorFn()); + var sharedProto = Object.getPrototypeOf(ownProto); + + assert(ownProto === generatorFn.prototype); + assert(sharedProto !== Object.prototype); + assert(sharedProto === Object.getPrototypeOf(function*(){}.prototype)); + assert(sharedProto.hasOwnProperty('next')); +})(); + +// Test %GeneratorPrototype% prototype chain +(function () { + function* generatorFn(){} + var g = generatorFn(); + var ownProto = Object.getPrototypeOf(g); + var sharedProto = Object.getPrototypeOf(ownProto); + var iterProto = Object.getPrototypeOf(sharedProto); + + assert(ownProto === generatorFn.prototype); + assert(iterProto.hasOwnProperty(Symbol.iterator)); + assert(!sharedProto.hasOwnProperty(Symbol.iterator)); + assert(!ownProto.hasOwnProperty(Symbol.iterator)); + assert(g[Symbol.iterator]() === g); +})(); + +// Test %GeneratorPrototype% prototype chain +(function () { + function* g(){} + var iterator = new g.constructor("a","b","c","yield a; yield b; yield c;")(1,2,3); + + var item = iterator.next(); + assert(item.value === 1); + assert(item.done === false); + + item = iterator.next(); + assert(item.value === 2); + assert(item.done === false); + + item = iterator.next(); + assert(item.value === 3); + assert(item.done === false); + + item = iterator.next(); + assert(item.value === undefined); + assert(item.done === true); + + assert(g.constructor === (function*(){}).constructor); +})(); + +// Test GeneratorFunction parsing +(function () { + function *f() {}; + + try { + Object.getPrototypeOf(f).constructor("yield", ""); + } catch (e) { + assert(e instanceof SyntaxError); + } +})(); + +// Test correct property membership +(function () { + function *f() {}; + + Object.getPrototypeOf(f).xx = 5; + assert(Object.getPrototypeOf(f).prototype.constructor.xx === 5); +})(); + +// Test GetPrototypeFromConstructor +(function () { + function *f() {}; + + var originalProto = f.prototype; + f.prototype = 5; + assert(Object.getPrototypeOf(f()) === Object.getPrototypeOf(originalProto)); + var fakeProto = { x : 6 }; + f.prototype = fakeProto; + assert(Object.getPrototypeOf(f()) === fakeProto); + assert(f.next === undefined); +})(); diff --git a/tests/jerry/function-construct.js b/tests/jerry/function-construct.js index d04935a6b..5239429c0 100644 --- a/tests/jerry/function-construct.js +++ b/tests/jerry/function-construct.js @@ -29,6 +29,10 @@ catch (e) assert (e instanceof ReferenceError); } +var singleArgFunction = new Function ('arg', 'return arg'); + +assert (singleArgFunction (5) === 5); + for (i = 1; i < 10; i ++) { var f = new Function ('a', 'b', 'var q = a; b++; function f (k) {return q + k + b++;}; return f;');