From bfd2639634bf47330719b0ff4ca48ce2b3123398 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Mon, 16 Mar 2020 14:37:47 +0100 Subject: [PATCH] Rework the core of class parsing/runtime semantic (#3598) Changes: - Use the pre-scanner to provide information for the parser about the existence of the class constructor - The allocation of the super declarative environment is no longer needed - The VM frame context holds the information about the this binding status - Reduce the number of class related VM/CBC instructions - Improve ecma_op_function_{construct, call} to properly set new.target JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- jerry-core/api/jerry-snapshot.c | 2 +- jerry-core/api/jerry.c | 2 +- jerry-core/ecma/base/ecma-gc.c | 6 + jerry-core/ecma/base/ecma-globals.h | 36 +- .../ecma/base/ecma-helpers-collection.c | 39 + jerry-core/ecma/base/ecma-helpers.c | 4 +- jerry-core/ecma/base/ecma-helpers.h | 12 +- .../ecma/builtin-objects/ecma-builtin-array.c | 6 +- .../builtin-objects/ecma-builtin-global.c | 2 +- .../ecma-builtin-helpers-error.c | 8 +- .../builtin-objects/ecma-builtin-reflect.c | 4 +- .../ecma/builtin-objects/ecma-builtins.c | 60 +- .../ecma/builtin-objects/ecma-builtins.h | 2 +- .../ecma/operations/ecma-array-object.c | 4 +- jerry-core/ecma/operations/ecma-eval.c | 2 +- .../ecma/operations/ecma-function-object.c | 1020 ++++++----------- .../ecma/operations/ecma-function-object.h | 31 +- .../ecma/operations/ecma-get-put-value.c | 4 +- jerry-core/ecma/operations/ecma-lex-env.c | 138 +++ jerry-core/ecma/operations/ecma-lex-env.h | 19 + .../ecma/operations/ecma-promise-object.c | 2 +- .../ecma/operations/ecma-proxy-object.c | 6 +- .../ecma/operations/ecma-proxy-object.h | 4 +- jerry-core/ecma/operations/ecma-reference.c | 53 +- jerry-core/ecma/operations/ecma-reference.h | 2 +- .../ecma/operations/ecma-regexp-object.c | 2 +- .../ecma/operations/ecma-typedarray-object.c | 2 +- jerry-core/lit/lit-magic-strings.h | 2 +- jerry-core/parser/js/byte-code.h | 74 +- jerry-core/parser/js/js-lexer.c | 6 +- jerry-core/parser/js/js-parser-expr.c | 339 +++--- jerry-core/parser/js/js-parser-internal.h | 50 +- jerry-core/parser/js/js-parser-statm.c | 101 +- jerry-core/parser/js/js-parser-util.c | 4 +- jerry-core/parser/js/js-parser.c | 26 +- jerry-core/parser/js/js-parser.h | 2 +- jerry-core/parser/js/js-scanner-internal.h | 4 + jerry-core/parser/js/js-scanner-util.c | 22 + jerry-core/parser/js/js-scanner.c | 60 +- jerry-core/parser/js/js-scanner.h | 1 + jerry-core/vm/opcodes.c | 461 ++++++++ jerry-core/vm/opcodes.h | 19 + jerry-core/vm/vm-stack.c | 4 - jerry-core/vm/vm-stack.h | 1 - jerry-core/vm/vm.c | 392 ++----- jerry-core/vm/vm.h | 42 +- .../es2015/class-inheritance-has-instance.js | 2 +- .../es2015/class-inheritance-inner-class.js | 3 + tests/jerry/es2015/class.js | 74 ++ 49 files changed, 1671 insertions(+), 1490 deletions(-) diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index 0ea8da89f..c25cfc5cc 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -168,7 +168,7 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled return 0; } - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR) { globals_p->class_found = true; } diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 7dd8da276..7b58433b5 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -2782,7 +2782,7 @@ jerry_invoke_function (bool is_invoke_as_constructor, /**< true - invoke functio JERRY_ASSERT (jerry_value_is_constructor (func_obj_val)); return jerry_return (ecma_op_function_construct (ecma_get_object_from_value (func_obj_val), - ECMA_VALUE_UNDEFINED, + ecma_get_object_from_value (func_obj_val), args_p, args_count)); } diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 259df53fc..7cdda2e0c 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -670,6 +670,11 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { ecma_gc_set_object_visited (ecma_get_object_from_value (arrow_func_p->this_binding)); } + + if (ecma_is_value_object (arrow_func_p->new_target)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (arrow_func_p->new_target)); + } } #endif /* ENABLED (JERRY_ES2015) */ } @@ -1218,6 +1223,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) { 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); ext_object_size = sizeof (ecma_arrow_function_t); } #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 4def4805c..8317f2258 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -111,15 +111,14 @@ typedef enum ECMA_PARSE_EVAL = (1u << 2), /**< eval is called */ ECMA_PARSE_DIRECT_EVAL = (1u << 3), /**< eval is called directly (ECMA-262 v5, 15.1.2.1.1) */ - /* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */ + /* These three status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */ ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 4), /**< a class constructor is being parsed (this value must be kept in * in sync with PARSER_CLASS_CONSTRUCTOR) */ - ECMA_PARSE_HAS_SUPER = (1u << 5), /**< the current context has super reference */ - ECMA_PARSE_HAS_IMPL_SUPER = (1u << 6), /**< the current context has implicit parent class */ - ECMA_PARSE_HAS_STATIC_SUPER = (1u << 7), /**< the current context is a static class method */ + ECMA_PARSE_ALLOW_SUPER = (1u << 5), /**< allow super property access */ + ECMA_PARSE_ALLOW_SUPER_CALL = (1u << 6), /**< allow super constructor call */ - ECMA_PARSE_CALLED_FROM_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_CALLED_FROM_FUNCTION = (1u << 7), /**< a function body is parsed or the code is inside a function */ + ECMA_PARSE_GENERATOR_FUNCTION = (1u << 8), /**< generator function is parsed */ /* These flags are internally used by the parser. */ } ecma_parse_opts_t; @@ -195,7 +194,8 @@ enum * ecma_op_object_find */ ECMA_VALUE_REGISTER_REF = ECMA_MAKE_VALUE (8), /**< register reference, * a special "base" value for vm */ - ECMA_VALUE_IMPLICIT_CONSTRUCTOR = ECMA_MAKE_VALUE (9), /**< special value for bound class constructors */ + ECMA_VALUE_RELEASE_LEX_ENV = ECMA_MAKE_VALUE (9), /**< if this error remains on the stack when an exception occours + the top lexical environment of the VM frame should be popped */ ECMA_VALUE_UNINITIALIZED = ECMA_MAKE_VALUE (10), /**< a special value for uninitialized let/const declarations */ ECMA_VALUE_SPREAD_ELEMENT = ECMA_MAKE_VALUE (11), /**< a special value for spread elements in array initialization * or function call argument list */ @@ -661,12 +661,12 @@ typedef enum ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE = 13, /**< declarative lexical environment */ ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND = 14, /**< object-bound lexical environment * with provideThis flag */ - ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND = 15, /**< object-bound lexical environment - * with provided super reference */ + ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND = 15, /**< object-bound lexical environment + * with provided home object reference */ ECMA_LEXICAL_ENVIRONMENT_TYPE_START = ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE, /**< first lexical * environment type */ - ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX = ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND /**< maximum value */ + ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX = ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND /**< maximum value */ } ecma_lexical_environment_type_t; #if ENABLED (JERRY_ES2015) @@ -686,29 +686,29 @@ typedef enum /** * Offset for JERRY_CONTEXT (status_flags) top 8 bits. */ -#define ECMA_SUPER_EVAL_OPTS_OFFSET (32 - 8) +#define ECMA_LOCAL_PARSE_OPTS_OFFSET ((sizeof (uint32_t) - sizeof (uint8_t)) * JERRY_BITSINBYTE) /** * Set JERRY_CONTEXT (status_flags) top 8 bits to the specified 'opts'. */ -#define ECMA_SET_SUPER_EVAL_PARSER_OPTS(opts) \ +#define ECMA_SET_LOCAL_PARSE_OPTS(opts) \ do \ { \ - JERRY_CONTEXT (status_flags) |= ((uint32_t) opts << ECMA_SUPER_EVAL_OPTS_OFFSET) | ECMA_STATUS_DIRECT_EVAL; \ + JERRY_CONTEXT (status_flags) |= ((uint32_t) opts << ECMA_LOCAL_PARSE_OPTS_OFFSET) | ECMA_STATUS_DIRECT_EVAL; \ } while (0) /** * Get JERRY_CONTEXT (status_flags) top 8 bits. */ -#define ECMA_GET_SUPER_EVAL_PARSER_OPTS() (JERRY_CONTEXT (status_flags) >> ECMA_SUPER_EVAL_OPTS_OFFSET) +#define ECMA_GET_LOCAL_PARSE_OPTS() (JERRY_CONTEXT (status_flags) >> ECMA_LOCAL_PARSE_OPTS_OFFSET) /** * Clear JERRY_CONTEXT (status_flags) top 8 bits. */ -#define ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS() \ +#define ECMA_CLEAR_LOCAL_PARSE_OPTS() \ do \ { \ - JERRY_CONTEXT (status_flags) &= ((1 << ECMA_SUPER_EVAL_OPTS_OFFSET) - 1); \ + JERRY_CONTEXT (status_flags) &= ((1 << ECMA_LOCAL_PARSE_OPTS_OFFSET) - 1); \ } while (0) /** @@ -778,8 +778,9 @@ typedef struct union { jmem_cpointer_t property_list_cp; /**< compressed pointer to object's - * or declerative lexical environments's property list */ + * or declerative lexical environments's property list */ jmem_cpointer_t bound_object_cp; /**< compressed pointer to lexical environments's the bound object */ + jmem_cpointer_t home_object_cp; /**< compressed pointer to lexical environments's the home object */ } u1; /** object prototype or outer reference */ @@ -961,6 +962,7 @@ typedef struct { ecma_extended_object_t header; /**< extended object header */ ecma_value_t this_binding; /**< value of 'this' binding */ + ecma_value_t new_target; /**< value of new.target */ } ecma_arrow_function_t; #if ENABLED (JERRY_SNAPSHOT_EXEC) diff --git a/jerry-core/ecma/base/ecma-helpers-collection.c b/jerry-core/ecma/base/ecma-helpers-collection.c index 56850cb27..1ac9fa84f 100644 --- a/jerry-core/ecma/base/ecma-helpers-collection.c +++ b/jerry-core/ecma/base/ecma-helpers-collection.c @@ -144,6 +144,45 @@ ecma_collection_push_back (ecma_collection_t *collection_p, /**< value collectio collection_p->buffer_p = buffer_p; } /* ecma_collection_push_back */ +/** + * Reserve space for the given amount of ecma_values in the collection + */ +void +ecma_collection_reserve (ecma_collection_t *collection_p, /**< value collection */ + uint32_t count) /**< number of ecma values to reserve */ +{ + JERRY_ASSERT (collection_p != NULL); + JERRY_ASSERT (UINT32_MAX - count > collection_p->capacity); + + const uint32_t new_capacity = collection_p->capacity + count; + const uint32_t old_size = ECMA_COLLECTION_ALLOCATED_SIZE (collection_p->capacity); + const uint32_t new_size = ECMA_COLLECTION_ALLOCATED_SIZE (new_capacity); + + ecma_value_t *buffer_p = collection_p->buffer_p; + buffer_p = jmem_heap_realloc_block (buffer_p, old_size, new_size); + + collection_p->capacity = new_capacity; + collection_p->buffer_p = buffer_p; +} /* ecma_collection_reserve */ + +/** + * Append a list of values to the end of the collection + */ +void +ecma_collection_append (ecma_collection_t *collection_p, /**< value collection */ + const ecma_value_t *buffer_p, /**< values to append */ + uint32_t count) /**< number of ecma values to append */ +{ + JERRY_ASSERT (collection_p != NULL); + if (collection_p->capacity - collection_p->item_count > count) + { + ecma_collection_reserve (collection_p, count); + } + + memcpy (collection_p->buffer_p + collection_p->item_count, buffer_p, count * sizeof (ecma_value_t)); + collection_p->item_count += count; +} /* ecma_collection_append */ + /** * @} * @} diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 7b26d6f41..5ea26922b 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -141,7 +141,7 @@ ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, /**< out { #if ENABLED (JERRY_ES2015) JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND - || type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); + || type == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); #else /* !ENABLED (JERRY_ES2015) */ JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); #endif /* ENABLED (JERRY_ES2015) */ @@ -288,7 +288,7 @@ ecma_get_lex_env_binding_object (const ecma_object_t *object_p) /**< object-boun JERRY_ASSERT (ecma_is_lexical_environment (object_p)); #if ENABLED (JERRY_ES2015) JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND - || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); + || ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); #else /* !ENABLED (JERRY_ES2015) */ JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index c4e35fdd5..46b7b3f29 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -192,13 +192,20 @@ typedef enum #define ECMA_ASSERT_VALUE_IS_SYMBOL(value) (false) #endif /* ENABLED (JERRY_ES2015) */ +/** + * Check whether the given type is ECMA_OBJECT_TYPE_PROXY + * + * @param type object type + */ +#define ECMA_OBJECT_TYPE_IS_PROXY(type) (JERRY_UNLIKELY ((type) == ECMA_OBJECT_TYPE_PROXY)) + /** * Check whether the given object has [[ProxyHandler]] and [[ProxyTarger]] internal slots * * @param obj_p ecma-object */ #if ENABLED (JERRY_ES2015_BUILTIN_PROXY) -#define ECMA_OBJECT_IS_PROXY(obj_p) (JERRY_UNLIKELY (ecma_get_object_type ((obj_p)) == ECMA_OBJECT_TYPE_PROXY)) +#define ECMA_OBJECT_IS_PROXY(obj_p) (ECMA_OBJECT_TYPE_IS_PROXY (ecma_get_object_type ((obj_p)))) #else /* !ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ #define ECMA_OBJECT_IS_PROXY(obj_p) (false) #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ @@ -402,6 +409,8 @@ lit_utf8_size_t ecma_number_to_binary_floating_point_number (ecma_number_t num, /* ecma-helpers-collection.c */ ecma_collection_t *ecma_new_collection (void); void ecma_collection_push_back (ecma_collection_t *collection_p, ecma_value_t value); +void ecma_collection_reserve (ecma_collection_t *collection_p, uint32_t count); +void ecma_collection_append (ecma_collection_t *collection_p, const ecma_value_t *buffer_p, uint32_t count); void ecma_collection_destroy (ecma_collection_t *collection_p); void ecma_collection_free (ecma_collection_t *collection_p); void ecma_collection_free_if_not_object (ecma_collection_t *collection_p); @@ -419,7 +428,6 @@ bool JERRY_ATTR_PURE ecma_get_object_is_builtin (const ecma_object_t *object_p); void ecma_set_object_is_builtin (ecma_object_t *object_p); uint8_t ecma_get_object_builtin_id (ecma_object_t *object_p); ecma_lexical_environment_type_t JERRY_ATTR_PURE ecma_get_lex_env_type (const ecma_object_t *object_p); -ecma_object_t JERRY_ATTR_PURE *ecma_get_lex_env_outer_reference (const ecma_object_t *object_p); ecma_object_t JERRY_ATTR_PURE *ecma_get_lex_env_binding_object (const ecma_object_t *object_p); ecma_object_t *ecma_clone_decl_lexical_environment (ecma_object_t *lex_env_p, bool copy_values); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array.c index b37457bfc..86f8a411f 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array.c @@ -128,7 +128,7 @@ ecma_builtin_array_object_from (ecma_value_t this_arg, /**< 'this' argument */ { ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor); - array = ecma_op_function_construct (constructor_obj_p, ECMA_VALUE_UNDEFINED, NULL, 0); + array = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, NULL, 0); if (ecma_is_value_undefined (array) || ecma_is_value_null (array)) { @@ -289,7 +289,7 @@ iterator_cleanup: { ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor); - array = ecma_op_function_construct (constructor_obj_p, ECMA_VALUE_UNDEFINED, &len_value, 1); + array = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, &len_value, 1); if (ecma_is_value_undefined (array) || ecma_is_value_null (array)) { @@ -414,7 +414,7 @@ ecma_builtin_array_object_of (ecma_value_t this_arg, /**< 'this' argument */ ecma_value_t len = ecma_make_uint32_value (arguments_list_len); ecma_value_t ret_val = ecma_op_function_construct (ecma_get_object_from_value (this_arg), - ECMA_VALUE_UNDEFINED, + ecma_get_object_from_value (this_arg), &len, 1); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.c b/jerry-core/ecma/builtin-objects/ecma-builtin-global.c index b7692d642..9f3728994 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.c @@ -103,7 +103,7 @@ ecma_builtin_global_object_eval (ecma_value_t x) /**< routine's first argument * #if ENABLED (JERRY_ES2015) if (vm_is_direct_eval_form_call ()) { - parse_opts |= ECMA_GET_SUPER_EVAL_PARSER_OPTS (); + parse_opts |= ECMA_GET_LOCAL_PARSE_OPTS (); } #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-error.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-error.c index 25239bd28..52e87910b 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-error.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-error.c @@ -60,12 +60,10 @@ ecma_builtin_helper_error_dispatch_call (ecma_standard_error_t error_type, /**< ecma_deref_ecma_string (message_string_p); return ecma_make_object_value (new_error_object_p); } - else - { - ecma_object_t *new_error_object_p = ecma_new_standard_error (error_type); - return ecma_make_object_value (new_error_object_p); - } + ecma_object_t *new_error_object_p = ecma_new_standard_error (error_type); + + return ecma_make_object_value (new_error_object_p); } /* ecma_builtin_helper_error_dispatch_call */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c index 4734da96d..63faa2475 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c @@ -205,10 +205,8 @@ ecma_builtin_reflect_dispatch_routine (uint16_t builtin_routine_id, /**< built-i return ECMA_VALUE_ERROR; } - // TODO: add new_target_p to construct when it'll be supported - JERRY_UNUSED (new_target_p); ecma_value_t ret_value = ecma_op_function_construct (target_p, - ECMA_VALUE_UNDEFINED, + new_target_p, coll_p->buffer_p, coll_p->item_count); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.c b/jerry-core/ecma/builtin-objects/ecma-builtins.c index 197eab2c1..5c239362a 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.c @@ -15,6 +15,7 @@ #include "ecma-alloc.h" #include "ecma-builtins.h" +#include "ecma-exceptions.h" #include "ecma-gc.h" #include "ecma-globals.h" #include "ecma-helpers.h" @@ -1020,15 +1021,12 @@ ecma_builtin_list_lazy_property_names (ecma_object_t *object_p, /**< a built-in * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_dispatch_routine (ecma_builtin_id_t builtin_object_id, /**< built-in object' identifier */ - uint16_t builtin_routine_id, /**< builtin-wide identifier - * of the built-in object's - * routine property */ +ecma_builtin_dispatch_routine (ecma_extended_object_t *func_obj_p, /**< builtin object */ ecma_value_t this_arg_value, /**< 'this' argument value */ const ecma_value_t *arguments_list_p, /**< list of arguments passed to routine */ ecma_length_t arguments_list_len) /**< length of arguments' list */ { - JERRY_ASSERT (builtin_object_id < ECMA_BUILTIN_ID__COUNT); + JERRY_ASSERT (ecma_builtin_function_is_routine ((ecma_object_t *) func_obj_p)); ecma_value_t padded_arguments_list_p[3] = { ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED, ECMA_VALUE_UNDEFINED }; @@ -1055,10 +1053,10 @@ ecma_builtin_dispatch_routine (ecma_builtin_id_t builtin_object_id, /**< built-i arguments_list_p = padded_arguments_list_p; } - return ecma_builtin_routines[builtin_object_id] (builtin_routine_id, - this_arg_value, - arguments_list_p, - arguments_list_len); + return ecma_builtin_routines[func_obj_p->u.built_in.id] (func_obj_p->u.built_in.routine_id, + this_arg_value, + arguments_list_p, + arguments_list_len); } /* ecma_builtin_dispatch_routine */ /** @@ -1075,27 +1073,19 @@ ecma_builtin_dispatch_call (ecma_object_t *obj_p, /**< built-in object */ JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION); JERRY_ASSERT (ecma_get_object_is_builtin (obj_p)); - ecma_value_t ret_value = ECMA_VALUE_EMPTY; ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; if (ecma_builtin_function_is_routine (obj_p)) { - ret_value = ecma_builtin_dispatch_routine (ext_obj_p->u.built_in.id, - ext_obj_p->u.built_in.routine_id, - this_arg_value, - arguments_list_p, - arguments_list_len); - } - else - { - ecma_builtin_id_t builtin_object_id = ext_obj_p->u.built_in.id; - JERRY_ASSERT (builtin_object_id < sizeof (ecma_builtin_call_functions) / sizeof (ecma_builtin_dispatch_call_t)); - return ecma_builtin_call_functions[builtin_object_id] (arguments_list_p, arguments_list_len); + return ecma_builtin_dispatch_routine (ext_obj_p, + this_arg_value, + arguments_list_p, + arguments_list_len); } - JERRY_ASSERT (!ecma_is_value_empty (ret_value)); - - return ret_value; + ecma_builtin_id_t builtin_object_id = ext_obj_p->u.built_in.id; + JERRY_ASSERT (builtin_object_id < sizeof (ecma_builtin_call_functions) / sizeof (ecma_builtin_dispatch_call_t)); + return ecma_builtin_call_functions[builtin_object_id] (arguments_list_p, arguments_list_len); } /* ecma_builtin_dispatch_call */ /** @@ -1105,16 +1095,36 @@ ecma_builtin_dispatch_call (ecma_object_t *obj_p, /**< built-in object */ */ ecma_value_t ecma_builtin_dispatch_construct (ecma_object_t *obj_p, /**< built-in object */ + ecma_object_t *new_target_p, /**< new target */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< arguments list length */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION); JERRY_ASSERT (ecma_get_object_is_builtin (obj_p)); + if (ecma_builtin_function_is_routine (obj_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Built-in routines have no constructor.")); + } + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; ecma_builtin_id_t builtin_object_id = ext_obj_p->u.built_in.id; JERRY_ASSERT (builtin_object_id < sizeof (ecma_builtin_construct_functions) / sizeof (ecma_builtin_dispatch_call_t)); - return ecma_builtin_construct_functions[builtin_object_id] (arguments_list_p, arguments_list_len); + +#if ENABLED (JERRY_ES2015) + ecma_object_t *old_new_target = JERRY_CONTEXT (current_new_target); + JERRY_CONTEXT (current_new_target) = new_target_p; +#else /* !ENABLED (JERRY_ES2015) */ + JERRY_UNUSED (new_target_p); +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_value_t ret_value = ecma_builtin_construct_functions[builtin_object_id] (arguments_list_p, arguments_list_len); + +#if ENABLED (JERRY_ES2015) + JERRY_CONTEXT (current_new_target) = old_new_target; +#endif /* ENABLED (JERRY_ES2015) */ + + return ret_value; } /* ecma_builtin_dispatch_construct */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.h b/jerry-core/ecma/builtin-objects/ecma-builtins.h index 6d0228cde..e5a0ab594 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.h @@ -85,7 +85,7 @@ ecma_value_t ecma_builtin_dispatch_call (ecma_object_t *obj_p, ecma_value_t this_arg_value, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); ecma_value_t -ecma_builtin_dispatch_construct (ecma_object_t *obj_p, +ecma_builtin_dispatch_construct (ecma_object_t *obj_p, ecma_object_t *new_target_p, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); ecma_property_t * ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, ecma_string_t *string_p); diff --git a/jerry-core/ecma/operations/ecma-array-object.c b/jerry-core/ecma/operations/ecma-array-object.c index 3e537729e..ba3168334 100644 --- a/jerry-core/ecma/operations/ecma-array-object.c +++ b/jerry-core/ecma/operations/ecma-array-object.c @@ -73,7 +73,7 @@ ecma_op_new_array_object (ecma_length_t length) /**< length of the new array */ ecma_object_t *array_prototype_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE); #else /* !ENABLED (JERRY_BUILTIN_ARRAY) */ ecma_object_t *array_prototype_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); -#endif /* (ENABLED (JERRY_BUILTIN_ARRAY)) */ +#endif /* ENABLED (JERRY_BUILTIN_ARRAY) */ ecma_object_t *object_p = ecma_create_object (array_prototype_object_p, sizeof (ecma_extended_object_t), @@ -733,7 +733,7 @@ ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object f ecma_value_t len_val = ecma_make_uint32_value (length); ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor); ecma_value_t ret_val = ecma_op_function_construct (ctor_object_p, - ECMA_VALUE_UNDEFINED, + ctor_object_p, &len_val, 1); diff --git a/jerry-core/ecma/operations/ecma-eval.c b/jerry-core/ecma/operations/ecma-eval.c index 308af65e5..2759236db 100644 --- a/jerry-core/ecma/operations/ecma-eval.c +++ b/jerry-core/ecma/operations/ecma-eval.c @@ -98,7 +98,7 @@ ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters b #endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) */ #if ENABLED (JERRY_ES2015) - ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS (); + ECMA_CLEAR_LOCAL_PARSE_OPTS (); /* If a direct eval is used inside the function the info should be propagated. */ if (JERRY_CONTEXT (current_new_target) != JERRY_CONTEXT_INVALID_NEW_TARGET diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 9a5a7b425..b2bcda531 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -76,14 +76,16 @@ ecma_op_object_is_callable (ecma_object_t *obj_p) /**< ecma object */ { JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); + const ecma_object_type_t type = ecma_get_object_type (obj_p); + #if ENABLED (JERRY_ES2015_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (obj_p)) + if (ECMA_OBJECT_TYPE_IS_PROXY (type)) { return ecma_op_is_callable (((ecma_proxy_object_t *) obj_p)->target); } #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ - return ecma_get_object_type (obj_p) >= ECMA_OBJECT_TYPE_FUNCTION; + return type >= ECMA_OBJECT_TYPE_FUNCTION; } /* ecma_op_object_is_callable */ /** @@ -112,15 +114,15 @@ ecma_object_is_constructor (ecma_object_t *obj_p) /**< ecma object */ { JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); + const ecma_object_type_t type = ecma_get_object_type (obj_p); + #if ENABLED (JERRY_ES2015_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (obj_p)) + if (ECMA_OBJECT_TYPE_IS_PROXY (type)) { return ecma_is_constructor (((ecma_proxy_object_t *) obj_p)->target); } #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ - ecma_object_type_t type = ecma_get_object_type (obj_p); - if (type == ECMA_OBJECT_TYPE_FUNCTION) { return (!ecma_get_object_is_builtin (obj_p) || !ecma_builtin_function_is_routine (obj_p)); @@ -441,6 +443,16 @@ ecma_op_create_arrow_function_object (ecma_object_t *scope_p, /**< function's sc #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ arrow_func_p->this_binding = ecma_copy_value_if_not_object (this_binding); + arrow_func_p->new_target = ECMA_VALUE_UNDEFINED; + + if (JERRY_CONTEXT (current_new_target) == JERRY_CONTEXT_INVALID_NEW_TARGET) + { + arrow_func_p->new_target = ECMA_VALUE_EMPTY; + } + else if (JERRY_CONTEXT (current_new_target) != NULL) + { + arrow_func_p->new_target = ecma_make_object_value (JERRY_CONTEXT (current_new_target)); + } return func_p; } /* ecma_op_create_arrow_function_object */ @@ -503,88 +515,26 @@ ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p) /**< fun #if ENABLED (JERRY_ES2015) /** - * Helper function for implicit class constructors [[HasInstance]] check. + * Check whether the given object [[FunctionKind]] internal slot value is "generator". * - * @return ecma value - * Returned value must be freed with ecma_free_value + * @return true - if the given object is a generator function + * false - otherwise */ -static ecma_value_t -ecma_op_implicit_class_constructor_has_instance (ecma_object_t *func_obj_p, /**< Function object */ - ecma_value_t value) /**< argument 'V' */ +bool +ecma_op_function_is_generator (ecma_object_t *obj_p) /**< object */ { - JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); - - /* Since bound functions represents individual class constructor functions, we should check - that the given value is instance of either of the bound function chain elements. */ - do + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION + && !ecma_get_object_is_builtin (obj_p)) { - ecma_object_t *v_obj_p = ecma_get_object_from_value (value); + ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) obj_p; + const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_obj_p); - ecma_value_t prototype_obj_value = ecma_op_object_get_by_magic_id (func_obj_p, - LIT_MAGIC_STRING_PROTOTYPE); - - if (ECMA_IS_VALUE_ERROR (prototype_obj_value)) - { - return prototype_obj_value; - } - - if (!ecma_is_value_object (prototype_obj_value)) - { - ecma_free_value (prototype_obj_value); - return ecma_raise_type_error (ECMA_ERR_MSG ("Object expected.")); - } - - ecma_object_t *prototype_obj_p = ecma_get_object_from_value (prototype_obj_value); - - while (true) - { - jmem_cpointer_t v_obj_cp; -#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (v_obj_p)) - { - ecma_value_t parent = ecma_proxy_object_get_prototype_of (v_obj_p); - - if (ECMA_IS_VALUE_ERROR (parent)) - { - ecma_deref_object (prototype_obj_p); - return parent; - } - - v_obj_cp = ecma_proxy_object_prototype_to_cp (parent); - } - else - { -#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ - v_obj_cp = ecma_op_ordinary_object_get_prototype_of (v_obj_p); -#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ - - if (v_obj_cp == JMEM_CP_NULL) - { - break; - } - - v_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, v_obj_cp); - - if (v_obj_p == prototype_obj_p) - { - ecma_deref_object (prototype_obj_p); - return ECMA_VALUE_TRUE; - } - } - - ecma_deref_object (prototype_obj_p); - - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p; - - func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_function_p->u.bound_function.target_function); + return (bytecode_data_p->status_flags & CBC_CODE_FLAGS_GENERATOR) != 0; } - while (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); - return ECMA_VALUE_FALSE; -} /* ecma_op_implicit_class_constructor_has_instance */ + return false; +} /* ecma_op_function_is_generator */ + #endif /* ENABLED (JERRY_ES2015) */ /** @@ -613,13 +563,6 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object * /* 1. 3. */ ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p; -#if ENABLED (JERRY_ES2015) - if (JERRY_UNLIKELY (ext_function_p->u.bound_function.args_len_or_this == ECMA_VALUE_IMPLICIT_CONSTRUCTOR)) - { - return ecma_op_implicit_class_constructor_has_instance (func_obj_p, value); - } -#endif /* ENABLED (JERRY_ES2015) */ - func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_function_p->u.bound_function.target_function); } @@ -696,231 +639,59 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object * return result; } /* ecma_op_function_has_instance */ -/** - * Indicates whether the function has been invoked with 'new'. - */ -#define ECMA_FUNC_ARG_FLAG_CONSTRUCT ((uintptr_t) 0x01u) - -/** - * Indicates whether 'super' is called from the class constructor. - */ -#define ECMA_FUNC_ARG_FLAG_SUPER ((uintptr_t) 0x02u) - -/** - * Combination of ECMA_FUNC_ARG_FLAG_CONSTRUCT and ECMA_FUNC_ARG_FLAG_SUPER - */ -#define ECMA_FUNC_ARG_FLAG_CONSTRUCT_SUPER ((uintptr_t) (ECMA_FUNC_ARG_FLAG_CONSTRUCT | ECMA_FUNC_ARG_FLAG_SUPER)) - -/** - * Sets the given flag in the arguments list pointer. - * - * @return arguments list pointer with the given flag - */ -static inline const ecma_value_t * JERRY_ATTR_ALWAYS_INLINE -ecma_op_function_args_set_flag (const ecma_value_t *arguments_list_p, /**< original arguments list pointer */ - uintptr_t flag) /**< flag to set */ -{ #if ENABLED (JERRY_ES2015) - arguments_list_p = (const ecma_value_t *) (((uintptr_t) arguments_list_p) | flag); -#else /* !ENABLED (JERRY_ES2015) */ - JERRY_UNUSED (flag); -#endif /* ENABLED (JERRY_ES2015) */ - - return arguments_list_p; -} /* ecma_op_function_args_set_flag */ /** - * Clears all flags in the arguments list pointer. + * GetSuperConstructor operation for class methods * - * @return arguments list pointer without the construct flag - */ -static inline const ecma_value_t * JERRY_ATTR_ALWAYS_INLINE -ecma_op_function_args_clear_flags (const ecma_value_t *arguments_list_p) /**< modified arguments list pointer */ -{ -#if ENABLED (JERRY_ES2015) - arguments_list_p = (const ecma_value_t *) (((uintptr_t) arguments_list_p) & ~(ECMA_FUNC_ARG_FLAG_CONSTRUCT - | ECMA_FUNC_ARG_FLAG_SUPER)); -#endif /* ENABLED (JERRY_ES2015) */ - - return arguments_list_p; -} /* ecma_op_function_args_clear_flags */ - -/** - * Returns true if the given flag is set. + * See also: ECMAScript v6, 12.3.5.2 * - * @return true, if the given flag is set, false otherwise + * @return ECMA_VALUE_ERROR - if the operation fails + * super constructor - otherwise */ -static inline bool JERRY_ATTR_ALWAYS_INLINE -ecma_op_function_args_has_flag (const ecma_value_t *arguments_list_p, /**< modified arguments list pointer */ - uintptr_t flag) /**< flag to test */ +ecma_value_t +ecma_op_function_get_super_constructor (ecma_object_t *func_obj_p) /**< function object */ { -#if ENABLED (JERRY_ES2015) - return (((uintptr_t) arguments_list_p) & flag); -#else /* !ENABLED (JERRY_ES2015) */ - JERRY_UNUSED_2 (arguments_list_p, flag); - return false; -#endif /* ENABLED (JERRY_ES2015) */ -} /* ecma_op_function_args_has_flag */ + ecma_object_t *super_ctor_p; -#if ENABLED (JERRY_ES2015) -/** - * Returns the closest declarative lexical enviroment to the super object bound lexical enviroment. - * - * @return the found lexical enviroment - */ -static ecma_object_t * -ecma_op_find_super_declerative_lex_env (ecma_object_t *lex_env_p) /**< starting lexical enviroment */ -{ - JERRY_ASSERT (lex_env_p != NULL); - JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) != ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); - - while (true) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (func_obj_p)) { - jmem_cpointer_t lex_env_outer_cp = lex_env_p->u2.outer_reference_cp; + ecma_value_t super_ctor = ecma_proxy_object_get_prototype_of (func_obj_p); - if (lex_env_outer_cp != JMEM_CP_NULL) + if (ECMA_IS_VALUE_ERROR (super_ctor)) { - ecma_object_t *lex_env_outer_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_outer_cp); - - if (ecma_get_lex_env_type (lex_env_outer_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND) - { - JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); - return lex_env_p; - } - - lex_env_p = lex_env_outer_p; + return super_ctor; } - else - { - return NULL; - } - } -} /* ecma_op_find_super_declerative_lex_env */ -/** - * Returns with the current class this_binding property - * - * @return NULL - if the property was not found - * the found property - otherwise - */ -static ecma_property_t * -ecma_op_get_class_this_binding_property (ecma_object_t *lex_env_p) /**< starting lexical enviroment */ -{ - JERRY_ASSERT (lex_env_p); - JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p)); - - lex_env_p = ecma_op_find_super_declerative_lex_env (lex_env_p); - ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING); - - return lex_env_p == NULL ? NULL : ecma_find_named_property (lex_env_p, name_p); -} /* ecma_op_get_class_this_binding_property */ - -/** - * Checks whether the 'super(...)' has been called. - * - * @return true - if the 'super (...)' has been called - * false - otherwise - */ -inline bool JERRY_ATTR_PURE -ecma_op_is_super_called (ecma_object_t *lex_env_p) /**< starting lexical enviroment */ -{ - ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p); - - JERRY_ASSERT (property_p); - return (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); -} /* ecma_op_is_super_called */ - -/** - * Sets the value of 'super(...)' has been called. - */ -inline void -ecma_op_set_super_called (ecma_object_t *lex_env_p) /**< starting lexical enviroment */ -{ - ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p); - - JERRY_ASSERT (property_p); - - JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL); - ECMA_CONVERT_INTERNAL_PROPERTY_TO_DATA_PROPERTY (property_p); -} /* ecma_op_set_super_called */ - -/** - * Sets the class context this_binding value. - */ -void -ecma_op_set_class_this_binding (ecma_object_t *lex_env_p, /**< starting lexical enviroment */ - ecma_value_t this_binding) /**< 'this' argument's value */ -{ - JERRY_ASSERT (ecma_is_value_object (this_binding)); - ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p); - - ecma_property_value_t *value_p; - - if (property_p) - { - JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); - value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + super_ctor_p = ecma_is_value_null (super_ctor) ? NULL : ecma_get_object_from_value (super_ctor); } else { - ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING); - value_p = ecma_create_named_data_property (lex_env_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p); - ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (func_obj_p); + if (proto_cp == JMEM_CP_NULL) + { + super_ctor_p = NULL; + } + else + { + super_ctor_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + ecma_ref_object (super_ctor_p); + } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (super_ctor_p == NULL || !ecma_object_is_constructor (super_ctor_p)) + { + ecma_deref_object (super_ctor_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("Super binding must be a constructor.")); } - value_p->value = this_binding; -} /* ecma_op_set_class_this_binding */ - -/** - * Gets the class context this binding value. - * - * @return the class context this binding value - */ -ecma_value_t -ecma_op_get_class_this_binding (ecma_object_t *lex_env_p) /**< starting lexical enviroment */ -{ - ecma_property_t *property_p = ecma_op_get_class_this_binding_property (lex_env_p); - - JERRY_ASSERT (property_p); - - ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p); - - JERRY_ASSERT (ecma_is_value_object (value_p->value)); - return value_p->value; -} /* ecma_op_get_class_this_binding */ - -/** - * Dummy external function for implicit constructor call. - * - * @return ECMA_VALUE_ERROR - TypeError - */ -ecma_value_t -ecma_op_function_implicit_constructor_handler_cb (const ecma_value_t function_obj, /**< the function itself */ - const ecma_value_t this_val, /**< this_arg of the function */ - const ecma_value_t args_p[], /**< argument list */ - const ecma_length_t args_count) /**< argument number */ -{ - JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count); - return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); -} /* ecma_op_function_implicit_constructor_handler_cb */ - -/** - * Sets the completion value [[Prototype]] based on the this_arg value - */ -void -ecma_op_set_class_prototype (ecma_value_t completion_value, /**< completion_value */ - ecma_value_t this_arg) /**< this argument*/ -{ - JERRY_ASSERT (ecma_is_value_object (completion_value)); - JERRY_ASSERT (ecma_is_value_object (this_arg)); - - ecma_object_t *completion_obj_p = ecma_get_object_from_value (completion_value); - jmem_cpointer_t prototype_obj_cp = ecma_get_object_from_value (this_arg)->u2.prototype_cp; - - JERRY_ASSERT (prototype_obj_cp != JMEM_CP_NULL); - - completion_obj_p->u2.prototype_cp = prototype_obj_cp; -} /* ecma_op_set_class_prototype */ + return ecma_make_object_value (super_ctor_p); +} /* ecma_op_function_get_super_constructor */ +#endif /* ENABLED (JERRY_ES2015) */ /** * Ordinary internal method: GetPrototypeFromConstructor (constructor, intrinsicDefaultProto) @@ -948,6 +719,7 @@ ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, /**< construc if (!ecma_is_value_object (proto)) { + ecma_free_value (proto); proto_obj_p = ecma_builtin_get (default_proto_id); ecma_ref_object (proto_obj_p); } @@ -958,16 +730,11 @@ ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, /**< construc return proto_obj_p; } /* ecma_op_get_prototype_from_constructor */ -#endif /* ENABLED (JERRY_ES2015) */ /** * Perform a JavaScript function object method call. * - * The input function object should be a pure JavaScript method or - * a builtin function implemented in C. - * - * In case of JERRY_ES2015 the arguments_list_p contains the information - * wheter if the function was invoked with "new" or not. + * The input function object should be a pure JavaScript method * * @return the result of the function call. */ @@ -981,13 +748,7 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ if (JERRY_UNLIKELY (ecma_get_object_is_builtin (func_obj_p))) { - JERRY_ASSERT (!ecma_op_function_args_has_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_CONSTRUCT_SUPER)); - ecma_value_t ret_value = ecma_builtin_dispatch_call (func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); - - return ret_value; + return ecma_builtin_dispatch_call (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); } /* Entering Function Code (ECMA-262 v5, 10.4.3) */ @@ -1004,55 +765,42 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ uint16_t status_flags = bytecode_data_p->status_flags; #if ENABLED (JERRY_ES2015) - bool is_construct_call = ecma_op_function_args_has_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_CONSTRUCT); - if (JERRY_UNLIKELY (status_flags & (CBC_CODE_FLAGS_CONSTRUCTOR | CBC_CODE_FLAGS_GENERATOR))) + bool is_construct_call = JERRY_CONTEXT (current_new_target) != NULL; + if (JERRY_UNLIKELY (status_flags & (CBC_CODE_FLAGS_CLASS_CONSTRUCTOR | CBC_CODE_FLAGS_GENERATOR))) { - - if (!is_construct_call && (status_flags & CBC_CODE_FLAGS_CONSTRUCTOR)) + if (!is_construct_call && (status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); } - if (status_flags & CBC_CODE_FLAGS_GENERATOR) + if ((status_flags & CBC_CODE_FLAGS_GENERATOR) && is_construct_call) { - 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; + return ecma_raise_type_error (ECMA_ERR_MSG ("Generator functions cannot be invoked with 'new'.")); } } #endif /* ENABLED (JERRY_ES2015) */ /* 1. */ #if ENABLED (JERRY_ES2015) - ecma_object_t *old_new_target = JERRY_CONTEXT (current_new_target); + ecma_object_t *old_function_object_p = JERRY_CONTEXT (current_function_obj_p); - if (is_construct_call) + if (JERRY_UNLIKELY (status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION)) { - if (!ecma_op_function_args_has_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_SUPER)) - { - JERRY_CONTEXT (current_new_target) = func_obj_p; - } - } - else - { - /* - Arrow functions do not have [[Construct]] internal method -> new.target should not be updated - - If the current function is not a direct eval call the "new.target" must be updated. */ - if (!(status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) && - (JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL) == 0) + ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_obj_p; + + if (ecma_is_value_undefined (arrow_func_p->new_target)) { JERRY_CONTEXT (current_new_target) = NULL; } - } - - if (status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) - { - this_binding = ((ecma_arrow_function_t *) ext_func_p)->this_binding; + else if (ecma_is_value_object (arrow_func_p->new_target)) + { + JERRY_CONTEXT (current_new_target) = ecma_get_object_from_value (arrow_func_p->new_target); + } + this_binding = arrow_func_p->this_binding; } else { + JERRY_CONTEXT (current_function_obj_p) = func_obj_p; #endif /* ENABLED (JERRY_ES2015) */ if (!(status_flags & CBC_CODE_FLAGS_STRICT_MODE)) { @@ -1075,8 +823,6 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ } #endif /* ENABLED (JERRY_ES2015) */ - arguments_list_p = ecma_op_function_args_clear_flags (arguments_list_p); - /* 5. */ ecma_object_t *local_env_p; if (status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) @@ -1095,9 +841,13 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ bytecode_data_p); } #if ENABLED (JERRY_ES2015) - if (JERRY_UNLIKELY (status_flags & CBC_CODE_FLAGS_CONSTRUCTOR)) + // ECMAScript v6, 9.2.2.8 + if (JERRY_UNLIKELY (status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR)) { - ecma_op_set_class_this_binding (local_env_p, this_binding); + ecma_value_t lexical_this; + lexical_this = (ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp) ? ECMA_VALUE_UNINITIALIZED + : this_binding); + ecma_op_init_this_binding (local_env_p, lexical_this); } #endif /* ENABLED (JERRY_ES2015) */ } @@ -1109,12 +859,25 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ arguments_list_len); #if ENABLED (JERRY_ES2015) - if (JERRY_UNLIKELY (status_flags & CBC_CODE_FLAGS_GENERATOR)) + JERRY_CONTEXT (current_function_obj_p) = old_function_object_p; + + /* ECMAScript v6, 9.2.2.13 */ + if (ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp)) { - JERRY_CONTEXT (current_function_obj_p) = NULL; + if (!ECMA_IS_VALUE_ERROR (ret_value) && !ecma_is_value_object (ret_value)) + { + if (!ecma_is_value_undefined (ret_value)) + { + ecma_free_value (ret_value); + ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Derived constructors may only return object or undefined.")); + } + else + { + ret_value = ecma_op_get_this_binding (local_env_p); + } + } } - JERRY_CONTEXT (current_new_target) = old_new_target; #endif /* ENABLED (JERRY_ES2015) */ if (!(status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED)) @@ -1135,14 +898,14 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ * * @return the result of the function call. */ -static ecma_value_t +static ecma_value_t JERRY_ATTR_NOINLINE ecma_op_function_call_external (ecma_object_t *func_obj_p, /**< Function object */ ecma_value_t this_arg_value, /**< 'this' argument's value */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< length of arguments list */ { - JERRY_ASSERT (!ecma_op_function_args_has_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_CONSTRUCT_SUPER)); + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p; JERRY_ASSERT (ext_func_obj_p->u.external_handler_cb != NULL); @@ -1162,6 +925,89 @@ ecma_op_function_call_external (ecma_object_t *func_obj_p, /**< Function object return ret_value; } /* ecma_op_function_call_external */ +/** + * Append the bound arguments into the given collection + * + * Note: + * - The whole bound chain is resolved + * - The first element of the collection contains the bounded this value + * + * @return target function of the bound function + */ +JERRY_ATTR_NOINLINE static ecma_object_t * +ecma_op_bound_function_get_argument_list (ecma_object_t *func_obj_p, /**< bound bunction object */ + ecma_collection_t *list_p) /**< list of arguments */ +{ + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + + ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p; + + func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + ext_function_p->u.bound_function.target_function); + + ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this; + + ecma_length_t args_length = 1; + + if (ecma_is_value_integer_number (args_len_or_this)) + { + args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this); + } + + /* 5. */ + if (args_length != 1) + { + const ecma_value_t *args_p = (const ecma_value_t *) (ext_function_p + 1); + list_p->buffer_p[0] = *args_p; + + if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION) + { + func_obj_p = ecma_op_bound_function_get_argument_list (func_obj_p, list_p); + } + ecma_collection_append (list_p, args_p + 1, args_length - 1); + } + else + { + list_p->buffer_p[0] = args_len_or_this; + } + + return func_obj_p; +} /* ecma_op_bound_function_get_argument_list */ + +/** + * [[Call]] internal method for bound function objects + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +static ecma_value_t JERRY_ATTR_NOINLINE +ecma_op_function_call_bound (ecma_object_t *func_obj_p, /**< Function object */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< length of arguments list */ +{ + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL; + + ecma_collection_t *bound_arg_list_p = ecma_new_collection (); + ecma_collection_push_back (bound_arg_list_p, ECMA_VALUE_EMPTY); + + ecma_object_t *target_obj_p = ecma_op_bound_function_get_argument_list (func_obj_p, bound_arg_list_p); + + ecma_collection_append (bound_arg_list_p, arguments_list_p, arguments_list_len); + + JERRY_ASSERT (!ecma_is_value_empty (bound_arg_list_p->buffer_p[0])); + + ecma_value_t ret_value = ecma_op_function_call (target_obj_p, + bound_arg_list_p->buffer_p[0], + bound_arg_list_p->buffer_p + 1, + (ecma_length_t) (bound_arg_list_p->item_count - 1)); + + ecma_collection_destroy (bound_arg_list_p); + + return ret_value; +} /* ecma_op_function_call_bound */ + /** * [[Call]] implementation for Function objects, * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) @@ -1182,396 +1028,238 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ && !ecma_is_lexical_environment (func_obj_p)); JERRY_ASSERT (ecma_op_object_is_callable (func_obj_p)); + ECMA_CHECK_STACK_USAGE (); + + const ecma_object_type_t type = ecma_get_object_type (func_obj_p); + #if ENABLED (JERRY_ES2015_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (func_obj_p)) + if (ECMA_OBJECT_TYPE_IS_PROXY (type)) { - return ecma_proxy_object_call (func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); + return ecma_proxy_object_call (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); } #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ - JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION - || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION - || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION - || !ecma_op_function_args_has_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_CONSTRUCT_SUPER)); - - ECMA_CHECK_STACK_USAGE (); - - switch (ecma_get_object_type (func_obj_p)) +#if ENABLED (JERRY_ES2015) + ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target); + if (JERRY_UNLIKELY (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL))) { - case ECMA_OBJECT_TYPE_FUNCTION: - { - jerry_value_t result = ecma_op_function_call_simple (func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); - - return result; - } - case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: - { -#if ENABLED (JERRY_ES2015) - ecma_object_t *old_new_target = JERRY_CONTEXT (current_new_target); - JERRY_CONTEXT (current_new_target) = NULL; + JERRY_CONTEXT (current_new_target) = NULL; + } #endif /* ENABLED (JERRY_ES2015) */ - jerry_value_t result = ecma_op_function_call_external (func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); + ecma_value_t result; -#if ENABLED (JERRY_ES2015) - JERRY_CONTEXT (current_new_target) = old_new_target; -#endif /* ENABLED (JERRY_ES2015) */ - return result; - } - default: - { - JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); - break; - } + if (JERRY_LIKELY (type == ECMA_OBJECT_TYPE_FUNCTION)) + { + result = ecma_op_function_call_simple (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); + } + else if (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) + { + result = ecma_op_function_call_external (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); + } + else + { + result = ecma_op_function_call_bound (func_obj_p, arguments_list_p, arguments_list_len); } - JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL; - - ecma_extended_object_t *ext_function_p; - ecma_object_t *target_func_obj_p; - ecma_length_t args_length; - - do - { - /* 2-3. */ - ext_function_p = (ecma_extended_object_t *) func_obj_p; - target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_function_p->u.bound_function.target_function); - - /* 4. */ - ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this; - - if (!ecma_is_value_integer_number (args_len_or_this)) - { #if ENABLED (JERRY_ES2015) - if (JERRY_UNLIKELY (args_len_or_this == ECMA_VALUE_IMPLICIT_CONSTRUCTOR)) - { - if (!ecma_op_function_args_has_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_CONSTRUCT)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); - } - if (ecma_get_object_is_builtin (target_func_obj_p)) - { - arguments_list_p = ecma_op_function_args_clear_flags (arguments_list_p); - } - } - else - { -#endif /* ENABLED (JERRY_ES2015) */ - this_arg_value = args_len_or_this; -#if ENABLED (JERRY_ES2015) - } + JERRY_CONTEXT (current_new_target) = old_new_target_p; #endif /* ENABLED (JERRY_ES2015) */ - args_length = 1; - } - else - { - this_arg_value = *(ecma_value_t *) (ext_function_p + 1); - args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this); - } - - JERRY_ASSERT (args_length > 0); - - if (args_length == 1) - { - func_obj_p = target_func_obj_p; - } - else - { -#if ENABLED (JERRY_ES2015) - arguments_list_p = ecma_op_function_args_clear_flags (arguments_list_p); -#endif /* ENABLED (JERRY_ES2015) */ - - JERRY_ASSERT (!ecma_op_function_args_has_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_CONSTRUCT_SUPER)); - args_length--; - - ecma_length_t merged_args_list_len = args_length + arguments_list_len; - ecma_value_t ret_value; - - JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t); - - ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1); - - memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t)); - memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t)); - - /* 5. */ - ret_value = ecma_op_function_call (target_func_obj_p, - this_arg_value, - merged_args_list_p, - merged_args_list_len); - - JMEM_FINALIZE_LOCAL_ARRAY (merged_args_list_p); - - return ret_value; - } - } - while (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); - - return ecma_op_function_call (func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); + return result; } /* ecma_op_function_call */ /** - * [[Construct]] implementation: - * 13.2.2 - for Function objects, created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION), - * and externally defined host functions (ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); - * 15.3.4.5.1 - for Function objects, created through 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION). + * [[Construct]] internal method for bound function objects + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +static ecma_value_t JERRY_ATTR_NOINLINE +ecma_op_function_construct_bound (ecma_object_t *func_obj_p, /**< Function object */ + ecma_object_t *new_target_p, /**< new target */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< length of arguments list */ +{ + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + + ecma_collection_t *bound_arg_list_p = ecma_new_collection (); + ecma_collection_push_back (bound_arg_list_p, ECMA_VALUE_EMPTY); + + ecma_object_t *target_obj_p = ecma_op_bound_function_get_argument_list (func_obj_p, bound_arg_list_p); + + ecma_collection_append (bound_arg_list_p, arguments_list_p, arguments_list_len); + + if (func_obj_p == new_target_p) + { + new_target_p = target_obj_p; + } + + ecma_value_t ret_value = ecma_op_function_construct (target_obj_p, + new_target_p, + bound_arg_list_p->buffer_p + 1, + (ecma_length_t) (bound_arg_list_p->item_count - 1)); + + ecma_collection_destroy (bound_arg_list_p); + + return ret_value; +} /* ecma_op_function_construct_bound */ + +/** + * [[Construct]] internal method for external function objects + * + * @return ecma value + * Returned value must be freed with ecma_free_value + */ +static ecma_value_t JERRY_ATTR_NOINLINE +ecma_op_function_construct_external (ecma_object_t *func_obj_p, /**< Function object */ + ecma_object_t *new_target_p, /**< new target */ + const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< length of arguments list */ +{ + JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + + ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (new_target_p, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); + + if (JERRY_UNLIKELY (proto_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + ecma_object_t *new_this_obj_p = ecma_create_object (proto_p, 0, ECMA_OBJECT_TYPE_GENERAL); + ecma_value_t this_arg = ecma_make_object_value (new_this_obj_p); + ecma_deref_object (proto_p); + +#if ENABLED (JERRY_ES2015) + ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target); + JERRY_CONTEXT (current_new_target) = new_target_p; +#endif /* ENABLED (JERRY_ES2015) */ + + ecma_value_t ret_value = ecma_op_function_call_external (func_obj_p, this_arg, arguments_list_p, arguments_list_len); + +#if ENABLED (JERRY_ES2015) + JERRY_CONTEXT (current_new_target) = old_new_target_p; +#endif /* ENABLED (JERRY_ES2015) */ + + if (ECMA_IS_VALUE_ERROR (ret_value) || ecma_is_value_object (ret_value)) + { + ecma_deref_object (new_this_obj_p); + return ret_value; + } + + ecma_free_value (ret_value); + + return this_arg; +} /* ecma_op_function_construct_external */ + +/** + * General [[Construct]] implementation function objects + * + * See also: ECMAScript v6, 9.2.2 * * @return ecma value * Returned value must be freed with ecma_free_value */ ecma_value_t ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ - ecma_value_t this_arg_value, /**< optional 'this' object value - * or ECMA_VALUE_UNDEFINED */ + ecma_object_t *new_target_p, /**< new target */ const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< length of arguments list */ { JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p)); - JERRY_ASSERT (ecma_is_value_object (this_arg_value) - || this_arg_value == ECMA_VALUE_UNDEFINED); + const ecma_object_type_t type = ecma_get_object_type (func_obj_p); #if ENABLED (JERRY_ES2015_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (func_obj_p)) + if (ECMA_OBJECT_TYPE_IS_PROXY (type)) { return ecma_proxy_object_construct (func_obj_p, + new_target_p, arguments_list_p, - arguments_list_len, - ecma_make_object_value (func_obj_p)); + arguments_list_len); } #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ - ecma_object_t *target_func_obj_p = NULL; - - while (JERRY_UNLIKELY (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION)) + if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_BOUND_FUNCTION)) { - /* 1-3. */ - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p; - - target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_function_p->u.bound_function.target_function); - - /* 4. */ - ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this; - - ecma_length_t args_length = 1; - - if (ecma_is_value_integer_number (args_len_or_this)) - { - args_length = (ecma_length_t) ecma_get_integer_from_value (args_len_or_this); - } - - JERRY_ASSERT (args_length > 0); - - /* 5. */ - if (args_length == 1) - { -#if ENABLED (JERRY_ES2015) - if (args_len_or_this == ECMA_VALUE_IMPLICIT_CONSTRUCTOR && ecma_is_value_undefined (this_arg_value)) - { - break; - } -#endif /* ENABLED (JERRY_ES2015) */ - func_obj_p = target_func_obj_p; - continue; - } - - ecma_value_t *args_p = (ecma_value_t *) (ext_function_p + 1); - ecma_value_t ret_value; - - args_length--; - ecma_length_t merged_args_list_len = args_length + arguments_list_len; - - JMEM_DEFINE_LOCAL_ARRAY (merged_args_list_p, merged_args_list_len, ecma_value_t); - - memcpy (merged_args_list_p, args_p + 1, args_length * sizeof (ecma_value_t)); - memcpy (merged_args_list_p + args_length, arguments_list_p, arguments_list_len * sizeof (ecma_value_t)); - - /* 5. */ - ret_value = ecma_op_function_construct (target_func_obj_p, - this_arg_value, - merged_args_list_p, - merged_args_list_len); - - JMEM_FINALIZE_LOCAL_ARRAY (merged_args_list_p); - - return ret_value; + return ecma_op_function_construct_bound (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); } - ecma_object_type_t type = ecma_get_object_type (func_obj_p); - - if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_FUNCTION)) + if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)) { - if (ecma_get_object_is_builtin (func_obj_p)) - { - if (ecma_builtin_function_is_routine (func_obj_p)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Built-in routines have no constructor.")); - } + return ecma_op_function_construct_external (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); + } - ecma_value_t ret_value = ecma_builtin_dispatch_construct (func_obj_p, - arguments_list_p, - arguments_list_len); + JERRY_ASSERT (type == ECMA_OBJECT_TYPE_FUNCTION); -#if ENABLED (JERRY_ES2015) - if (!ecma_is_value_undefined (this_arg_value) && !ECMA_IS_VALUE_ERROR (ret_value)) - { - ecma_op_set_class_prototype (ret_value, this_arg_value); - } -#endif /* ENABLED (JERRY_ES2015) */ - - return ret_value; - } - - const ecma_compiled_code_t *byte_code_p; - byte_code_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) func_obj_p); - - if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Arrow functions have no constructor.")); - } + if (JERRY_UNLIKELY (ecma_get_object_is_builtin (func_obj_p))) + { + return ecma_builtin_dispatch_construct (func_obj_p, new_target_p, arguments_list_p, arguments_list_len); } ecma_object_t *new_this_obj_p = NULL; + ecma_value_t this_arg; + ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p; + const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_obj_p); - if (JERRY_LIKELY (this_arg_value == ECMA_VALUE_UNDEFINED)) + if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) { - /* 5. */ - ecma_value_t prototype_prop_value = ecma_op_object_get_by_magic_id (func_obj_p, - LIT_MAGIC_STRING_PROTOTYPE); - - if (ECMA_IS_VALUE_ERROR (prototype_prop_value)) - { - return prototype_prop_value; - } - - /* 1., 2., 4. */ - if (ecma_is_value_object (prototype_prop_value)) - { - /* 6. */ - new_this_obj_p = ecma_create_object (ecma_get_object_from_value (prototype_prop_value), - 0, - ECMA_OBJECT_TYPE_GENERAL); - } - else - { - /* 7. */ - ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); - - new_this_obj_p = ecma_create_object (prototype_p, 0, ECMA_OBJECT_TYPE_GENERAL); - } - - ecma_free_value (prototype_prop_value); - - this_arg_value = ecma_make_object_value (new_this_obj_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("Arrow functions have no constructor.")); } - /* 8. */ - ecma_value_t ret_value; +#if ENABLED (JERRY_ES2015) + /* 6. */ + ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target); + JERRY_CONTEXT (current_new_target) = new_target_p; - switch (type) + /* 5. */ + if (!ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_obj_p->u.function.scope_cp)) { - case ECMA_OBJECT_TYPE_FUNCTION: - { - uintptr_t flag = ECMA_FUNC_ARG_FLAG_CONSTRUCT; -#if ENABLED (JERRY_ES2015) - if (JERRY_LIKELY (new_this_obj_p == NULL)) - { - flag |= ECMA_FUNC_ARG_FLAG_SUPER; - } #endif /* ENABLED (JERRY_ES2015) */ + /* 5.a */ + ecma_object_t *proto_p = ecma_op_get_prototype_from_constructor (new_target_p, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); - arguments_list_p = ecma_op_function_args_set_flag (arguments_list_p, flag); - ret_value = ecma_op_function_call_simple (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); - break; - } -#if ENABLED (JERRY_ES2015) - case ECMA_OBJECT_TYPE_BOUND_FUNCTION: + /* 5.b */ + if (JERRY_UNLIKELY (proto_p == NULL)) { - JERRY_ASSERT (!ecma_op_function_args_has_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_CONSTRUCT_SUPER)); - JERRY_ASSERT (target_func_obj_p != NULL); - - ret_value = ecma_op_function_construct (target_func_obj_p, - this_arg_value, - arguments_list_p, - arguments_list_len); - break; + return ECMA_VALUE_ERROR; } - case ECMA_OBJECT_TYPE_GENERAL: - { - /* Catch the special case when a the class extends value in null - and the class has no explicit constructor to raise TypeError.*/ - JERRY_ASSERT (!ecma_op_function_args_has_flag (arguments_list_p, ECMA_FUNC_ARG_FLAG_CONSTRUCT)); - JERRY_ASSERT (func_obj_p->u2.prototype_cp != JMEM_CP_NULL); - JERRY_ASSERT ((ECMA_GET_NON_NULL_POINTER (ecma_object_t, func_obj_p->u2.prototype_cp) \ - == ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE))); - - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Super constructor null is not a constructor.")); - break; - } -#endif /* ENABLED (JERRY_ES2015) */ - default: - { - JERRY_ASSERT (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + new_this_obj_p = ecma_create_object (proto_p, 0, ECMA_OBJECT_TYPE_GENERAL); + ecma_deref_object (proto_p); + this_arg = ecma_make_object_value (new_this_obj_p); #if ENABLED (JERRY_ES2015) - ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p; - - if (ext_func_obj_p->u.external_handler_cb == ecma_op_function_implicit_constructor_handler_cb) - { - ret_value = ECMA_VALUE_UNDEFINED; - break; - } - - ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target); - if (JERRY_LIKELY (new_this_obj_p != NULL)) - { - JERRY_CONTEXT (current_new_target) = func_obj_p; - } -#endif /* ENABLED (JERRY_ES2015) */ - - ret_value = ecma_op_function_call_external (func_obj_p, this_arg_value, arguments_list_p, arguments_list_len); - -#if ENABLED (JERRY_ES2015) - JERRY_CONTEXT (current_new_target) = old_new_target_p; -#endif /* ENABLED (JERRY_ES2015) */ - break; - } } + else + { + this_arg = ECMA_VALUE_UNDEFINED; + } +#endif /* ENABLED (JERRY_ES2015) */ - /* 9. */ + ecma_value_t ret_value = ecma_op_function_call_simple (func_obj_p, this_arg, arguments_list_p, arguments_list_len); + +#if ENABLED (JERRY_ES2015) + JERRY_CONTEXT (current_new_target) = old_new_target_p; +#endif /* ENABLED (JERRY_ES2015) */ + + /* 13.a */ if (ECMA_IS_VALUE_ERROR (ret_value) || ecma_is_value_object (ret_value)) { +#if ENABLED (JERRY_ES2015) if (new_this_obj_p != NULL) { ecma_deref_object (new_this_obj_p); } +#else /* !ENABLED (JERRY_ES2015) */ + ecma_deref_object (new_this_obj_p); +#endif /* ENABLED (JERRY_ES2015) */ return ret_value; } - ecma_fast_free_value (ret_value); - - if (JERRY_UNLIKELY (new_this_obj_p == NULL)) - { - ecma_ref_object (ecma_get_object_from_value (this_arg_value)); - } - - return this_arg_value; + /* 13.b */ + ecma_free_value (ret_value); + return this_arg; } /* ecma_op_function_construct */ /** diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index c0478bcbd..a80b6b7cc 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -51,29 +51,8 @@ ecma_op_create_dynamic_function (const ecma_value_t *arguments_list_p, ecma_parse_opts_t opts); #if ENABLED (JERRY_ES2015) -void -ecma_op_set_super_called (ecma_object_t *lex_env_p); - -bool -ecma_op_is_super_called (ecma_object_t *lex_env_p); - -void -ecma_op_set_class_this_binding (ecma_object_t *lex_env_p, ecma_value_t this_binding); - ecma_value_t -ecma_op_get_class_this_binding (ecma_object_t *lex_env_p); - -ecma_value_t -ecma_op_function_implicit_constructor_handler_cb (const ecma_value_t function_obj, - const ecma_value_t this_val, - const ecma_value_t args_p[], - const ecma_length_t args_count); - -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_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); @@ -81,9 +60,13 @@ ecma_op_create_generator_function_object (ecma_object_t *scope_p, const ecma_com 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); - +bool +ecma_op_function_is_generator (ecma_object_t *func_obj_p); #endif /* ENABLED (JERRY_ES2015) */ +ecma_object_t * +ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, ecma_builtin_id_t default_proto_id); + ecma_value_t ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value); @@ -92,7 +75,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, ecma_value_t this_arg_value, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); ecma_value_t -ecma_op_function_construct (ecma_object_t *func_obj_p, ecma_value_t this_arg_value, +ecma_op_function_construct (ecma_object_t *func_obj_p, ecma_object_t *new_target_p, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); ecma_property_t * diff --git a/jerry-core/ecma/operations/ecma-get-put-value.c b/jerry-core/ecma/operations/ecma-get-put-value.c index 9c716ec9d..9a341039d 100644 --- a/jerry-core/ecma/operations/ecma-get-put-value.c +++ b/jerry-core/ecma/operations/ecma-get-put-value.c @@ -77,7 +77,7 @@ ecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme break; } #if ENABLED (JERRY_ES2015) - case ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND: + case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND: { break; } @@ -266,7 +266,7 @@ ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme break; } #if ENABLED (JERRY_ES2015) - case ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND: + case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND: { break; } diff --git a/jerry-core/ecma/operations/ecma-lex-env.c b/jerry-core/ecma/operations/ecma-lex-env.c index 4bd0308f6..4e314e10e 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.c +++ b/jerry-core/ecma/operations/ecma-lex-env.c @@ -427,6 +427,144 @@ ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, /**< lexical environ prop_value_p->value = ecma_copy_value_if_not_object (value); } /* ecma_op_create_immutable_binding */ +#if ENABLED (JERRY_ES2015) +/** + * InitializeBinding operation. + * + * See also: ECMA-262 v6, 8.1.1.1.4 + */ +void +ecma_op_initialize_binding (ecma_object_t *lex_env_p, /**< lexical environment */ + ecma_string_t *name_p, /**< argument N */ + ecma_value_t value) /**< argument V */ +{ + JERRY_ASSERT (lex_env_p != NULL + && ecma_is_lexical_environment (lex_env_p)); + JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + + ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, name_p); + JERRY_ASSERT (prop_p != NULL); + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA); + + ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p); + JERRY_ASSERT (prop_value_p->value == ECMA_VALUE_UNINITIALIZED); + + prop_value_p->value = ecma_copy_value_if_not_object (value); +} /* ecma_op_initialize_binding */ + +/** + * BindThisValue operation for an empty lexical environment + * + * See also: ECMA-262 v6, 8.1.1.3.1 + */ +void +ecma_op_init_this_binding (ecma_object_t *lex_env_p, /**< lexical environment */ + ecma_value_t this_binding) /**< this binding value */ +{ + JERRY_ASSERT (lex_env_p != NULL); + JERRY_ASSERT (ecma_is_value_object (this_binding) || this_binding == ECMA_VALUE_UNINITIALIZED); + ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE); + + ecma_property_value_t *prop_value_p = ecma_create_named_data_property (lex_env_p, + prop_name_p, + ECMA_PROPERTY_FIXED, + NULL); + prop_value_p->value = this_binding; +} /* ecma_op_init_this_binding */ + +/** + * GetThisEnvironment operation. + * + * See also: ECMA-262 v6, 8.3.2 + * + * @return property pointer for the internal [[ThisBindingValue]] property + */ +ecma_property_t * +ecma_op_get_this_property (ecma_object_t *lex_env_p) /**< lexical environment */ +{ + JERRY_ASSERT (lex_env_p != NULL); + + ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE); + while (true) + { + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, prop_name_p); + + if (prop_p != NULL) + { + return prop_p; + } + } + + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + } +} /* ecma_op_get_this_property */ + +/** + * GetThisBinding operation. + * + * See also: ECMA-262 v6, 8.1.1.3.4 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ecma-object - otherwise + */ +ecma_value_t +ecma_op_get_this_binding (ecma_object_t *lex_env_p) /**< lexical environment */ +{ + JERRY_ASSERT (lex_env_p != NULL); + + ecma_property_t *prop_p = ecma_op_get_this_property (lex_env_p); + JERRY_ASSERT (prop_p != NULL); + + ecma_value_t this_value = ECMA_PROPERTY_VALUE_PTR (prop_p)->value; + + if (this_value == ECMA_VALUE_UNINITIALIZED) + { + return ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before " + "accessing 'this' or returning from it.")); + } + + ecma_ref_object (ecma_get_object_from_value (this_value)); + + return this_value; +} /* ecma_op_get_this_binding */ + +/** + * BindThisValue operation. + * + * See also: ECMA-262 v6, 8.1.1.3.1 + */ +void +ecma_op_bind_this_value (ecma_property_t *prop_p, /**< [[ThisBindingValue]] internal property */ + ecma_value_t this_binding) /**< this binding value */ +{ + JERRY_ASSERT (prop_p != NULL); + JERRY_ASSERT (ecma_is_value_object (this_binding)); + JERRY_ASSERT (!ecma_op_this_binding_is_initialized (prop_p)); + + ECMA_PROPERTY_VALUE_PTR (prop_p)->value = this_binding; +} /* ecma_op_bind_this_value */ + +/** + * Get the environment record [[ThisBindingStatus]] internal property. + * + * See also: ECMA-262 v6, 8.1.1.3 + * + * @return true - if the status is "initialzed" + * false - otherwise + */ +bool +ecma_op_this_binding_is_initialized (ecma_property_t *prop_p) /**< [[ThisBindingValue]] internal property */ +{ + JERRY_ASSERT (prop_p != NULL); + + return ECMA_PROPERTY_VALUE_PTR (prop_p)->value != ECMA_VALUE_UNINITIALIZED; +} /* ecma_op_this_binding_is_initialized */ + +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-lex-env.h b/jerry-core/ecma/operations/ecma-lex-env.h index e7860f5b1..6f260ad4f 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.h +++ b/jerry-core/ecma/operations/ecma-lex-env.h @@ -66,6 +66,25 @@ ecma_value_t ecma_op_implicit_this_value (ecma_object_t *lex_env_p); /* ECMA-262 v5, Table 18. Additional methods of Declarative Environment Records */ void ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, ecma_value_t value); +#if ENABLED (JERRY_ES2015) +void ecma_op_initialize_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, ecma_value_t value); + +void +ecma_op_init_this_binding (ecma_object_t *lex_env_p, ecma_value_t this_binding); + +ecma_property_t * +ecma_op_get_this_property (ecma_object_t *lex_env_p); + +bool +ecma_op_this_binding_is_initialized (ecma_property_t *prop_p); + +ecma_value_t +ecma_op_get_this_binding (ecma_object_t *lex_env_p); + +void +ecma_op_bind_this_value (ecma_property_t *prop_p, ecma_value_t this_binding); +#endif /* ENABLED (JERRY_ES2015) */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-promise-object.c b/jerry-core/ecma/operations/ecma-promise-object.c index 34f97c330..705e3fb7b 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.c +++ b/jerry-core/ecma/operations/ecma-promise-object.c @@ -679,7 +679,7 @@ ecma_promise_new_capability (ecma_value_t constructor) /* 6. */ ecma_value_t promise = ecma_op_function_construct (constructor_obj_p, - ECMA_VALUE_UNDEFINED, + constructor_obj_p, &executor, 1); ecma_deref_object (executor_p); diff --git a/jerry-core/ecma/operations/ecma-proxy-object.c b/jerry-core/ecma/operations/ecma-proxy-object.c index 5c5e167c9..7589b62cf 100644 --- a/jerry-core/ecma/operations/ecma-proxy-object.c +++ b/jerry-core/ecma/operations/ecma-proxy-object.c @@ -849,12 +849,12 @@ ecma_proxy_object_call (ecma_object_t *obj_p, /**< proxy object */ */ ecma_value_t ecma_proxy_object_construct (ecma_object_t *obj_p, /**< proxy object */ + ecma_object_t *new_target_p, /**< new target */ const ecma_value_t *args_p, /**< argument list */ - ecma_length_t argc, /**< number of arguments */ - ecma_value_t new_target) /**< this argument to invoke the function */ + ecma_length_t argc) /**< number of arguments */ { JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); - JERRY_UNUSED_4 (obj_p, args_p, argc, new_target); + JERRY_UNUSED_4 (obj_p, new_target_p, args_p, argc); return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Construct]]")); } /* ecma_proxy_object_construct */ diff --git a/jerry-core/ecma/operations/ecma-proxy-object.h b/jerry-core/ecma/operations/ecma-proxy-object.h index f8a6991f9..db8ae06c8 100644 --- a/jerry-core/ecma/operations/ecma-proxy-object.h +++ b/jerry-core/ecma/operations/ecma-proxy-object.h @@ -106,9 +106,9 @@ ecma_proxy_object_call (ecma_object_t *obj_p, ecma_value_t ecma_proxy_object_construct (ecma_object_t *obj_p, + ecma_object_t *new_target_p, const ecma_value_t *args_p, - ecma_length_t argc, - ecma_value_t new_target); + ecma_length_t argc); #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ diff --git a/jerry-core/ecma/operations/ecma-reference.c b/jerry-core/ecma/operations/ecma-reference.c index 191730f29..8851166f2 100644 --- a/jerry-core/ecma/operations/ecma-reference.c +++ b/jerry-core/ecma/operations/ecma-reference.c @@ -21,6 +21,7 @@ #include "ecma-lcache.h" #include "ecma-lex-env.h" #include "ecma-objects.h" +#include "ecma-proxy-object.h" #include "ecma-reference.h" #include "jrt.h" @@ -47,7 +48,7 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical while (true) { #if ENABLED (JERRY_ES2015) - if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND) + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND) { JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); @@ -79,27 +80,55 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical #if ENABLED (JERRY_ES2015) /** - * Resolve super reference. + * Perform GetThisEnvironment and GetSuperBase operations * - * @return value of the reference + * See also: ECMAScript v6, 8.1.1.3.5 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_UNDEFINED - if the home object is null + * value of the [[HomeObject]].[[Prototype]] internal slot - otherwise */ -ecma_object_t * -ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p) /**< starting lexical environment */ +ecma_value_t +ecma_op_resolve_super_base (ecma_object_t *lex_env_p) /**< starting lexical environment */ { + JERRY_ASSERT (lex_env_p != NULL); + while (true) { - JERRY_ASSERT (lex_env_p != NULL); - - if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND) + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND) { - return ecma_get_lex_env_binding_object (lex_env_p); + ecma_object_t *home_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u1.home_object_cp); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (home_p)) + { + return ecma_proxy_object_get_prototype_of (home_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (home_p); + + if (proto_cp == JMEM_CP_NULL) + { + return ECMA_VALUE_NULL; + } + + ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + ecma_ref_object (proto_p); + + return ecma_make_object_value (proto_p); } - JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL) + { + break; + } lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); } -} /* ecma_op_resolve_super_reference_value */ + + return ECMA_VALUE_UNDEFINED; +} /* ecma_op_resolve_super_base */ /** * Helper method for HasBindig operation @@ -262,7 +291,7 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical else { #if ENABLED (JERRY_ES2015) - JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); + JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); #else /* !ENABLED (JERRY_ES2015) */ JERRY_UNREACHABLE (); #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/operations/ecma-reference.h b/jerry-core/ecma/operations/ecma-reference.h index 8a1162f3a..4ee2d0923 100644 --- a/jerry-core/ecma/operations/ecma-reference.h +++ b/jerry-core/ecma/operations/ecma-reference.h @@ -29,7 +29,7 @@ ecma_object_t *ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, ecma_string_t *name_p); ecma_value_t ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, ecma_string_t *name_p); #if ENABLED (JERRY_ES2015) -ecma_object_t *ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p); +ecma_value_t ecma_op_resolve_super_base (ecma_object_t *lex_env_p); ecma_value_t ecma_op_is_prop_unscopable (ecma_object_t *lex_env_p, ecma_string_t *prop_name_p); #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/ecma/operations/ecma-regexp-object.c b/jerry-core/ecma/operations/ecma-regexp-object.c index f31f7a9a7..1bc6927d0 100644 --- a/jerry-core/ecma/operations/ecma-regexp-object.c +++ b/jerry-core/ecma/operations/ecma-regexp-object.c @@ -1696,7 +1696,7 @@ ecma_regexp_split_helper (ecma_value_t this_arg, /**< this value */ /* 13-14. */ ecma_value_t arguments[] = { this_arg, ecma_make_string_value (flags_str_p) }; - ecma_value_t splitter = ecma_op_function_construct (constructor_obj_p, ECMA_VALUE_UNDEFINED, arguments, 2); + ecma_value_t splitter = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, arguments, 2); ecma_deref_ecma_string (flags_str_p); ecma_deref_object (constructor_obj_p); diff --git a/jerry-core/ecma/operations/ecma-typedarray-object.c b/jerry-core/ecma/operations/ecma-typedarray-object.c index d4e6b66ae..9127bcbf3 100644 --- a/jerry-core/ecma/operations/ecma-typedarray-object.c +++ b/jerry-core/ecma/operations/ecma-typedarray-object.c @@ -536,7 +536,7 @@ ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< leng ecma_value_t byte_length_val = ecma_make_uint32_value (byte_length); ecma_value_t new_arraybuffer = ecma_op_function_construct (ctor_proto_p, - ECMA_VALUE_UNDEFINED, + ctor_proto_p, &byte_length_val, 1); ecma_deref_object (ctor_proto_p); diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h index 01f02a065..745171831 100644 --- a/jerry-core/lit/lit-magic-strings.h +++ b/jerry-core/lit/lit-magic-strings.h @@ -50,6 +50,7 @@ typedef enum LIT_INTERNAL_MAGIC_STRING_MAP_KEY, /**< Property key used when an object is a key in a map object */ LIT_INTERNAL_MAGIC_API_INTERNAL, /**< Property key used to add non-visible JS properties from the public API */ LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES, /**< %ArrayProto_values% intrinsic routine */ + LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE, /**< FunctionEnvironmentRecord [[ThisBindingValue]] internal slot */ /* List of well known symbols */ LIT_GLOBAL_SYMBOL_HAS_INSTANCE, /**< @@hasInstance well known symbol */ LIT_GLOBAL_SYMBOL_IS_CONCAT_SPREADABLE, /**< @@isConcatSpreadable well known symbol */ @@ -70,7 +71,6 @@ typedef enum LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< native pointer info associated with an object */ LIT_FIRST_INTERNAL_MAGIC_STRING = LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< first index of internal * magic strings */ - LIT_INTERNAL_MAGIC_STRING_CLASS_THIS_BINDING, /**< the this binding of the class constructor */ LIT_INTERNAL_MAGIC_STRING_WEAK_REFS, /**< Weak references to the current object */ LIT_INTERNAL_MAGIC_STRING_CONTAINER, /**< Literal ID for internal container objects */ LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT, /**< Internal object ID for internal properties */ diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 1bea29ff0..f985acc83 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -194,12 +194,10 @@ #define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4 /* PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION must be <= 3 */ #define PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION 3 -/* PARSER_BLOCK_CONTEXT_STACK_ALLOCATION must be <= 3 */ -#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 1 -/* PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION must be <= 4 */ -#define PARSER_BLOCK_CONTEXT_STACK_ALLOCATION 1 /* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */ -#define PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION 1 +#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 1 +/* PARSER_BLOCK_CONTEXT_STACK_ALLOCATION must be <= 3 */ +#define PARSER_BLOCK_CONTEXT_STACK_ALLOCATION 1 /** * Opcode definitions. @@ -540,10 +538,6 @@ VM_OC_RESOLVE_BASE_FOR_CALL) \ CBC_FORWARD_BRANCH (CBC_EXT_FINALLY, 0, \ VM_OC_FINALLY) \ - CBC_OPCODE (CBC_EXT_CLASS_EXPR_CONTEXT_END, CBC_NO_FLAG, 0, \ - VM_OC_CLASS_EXPR_CONTEXT_END) \ - CBC_FORWARD_BRANCH (CBC_EXT_SUPER_CLASS_CREATE_CONTEXT, \ - -1 + PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION, VM_OC_CLASS_HERITAGE) \ CBC_OPCODE (CBC_EXT_INITIALIZER_PUSH_PROP, CBC_NO_FLAG, 0, \ VM_OC_INITIALIZER_PUSH_PROP | VM_OC_GET_STACK) \ CBC_FORWARD_BRANCH (CBC_EXT_DEFAULT_INITIALIZER, -1, \ @@ -602,16 +596,36 @@ VM_OC_SET_SETTER | VM_OC_GET_STACK_LITERAL) \ \ /* Class related opcodes. */ \ - CBC_OPCODE (CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR, CBC_NO_FLAG, 0, \ - VM_OC_CLASS_INHERITANCE) \ - CBC_OPCODE (CBC_EXT_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE, CBC_NO_FLAG, 2, \ - VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_IMPLICIT_CONSTRUCTOR_CALL, CBC_NO_FLAG, 0, \ - VM_OC_PUSH_IMPL_CONSTRUCTOR) \ - CBC_OPCODE (CBC_EXT_SET_CLASS_LITERAL, CBC_HAS_LITERAL_ARG, 0, \ - VM_OC_SET_CLASS_CONSTRUCTOR | VM_OC_GET_LITERAL) \ - CBC_OPCODE (CBC_EXT_CLASS_EVAL, CBC_HAS_BYTE_ARG, 0, \ - VM_OC_CLASS_EVAL) \ + CBC_OPCODE (CBC_EXT_PUSH_NAMED_CLASS_ENV, CBC_HAS_LITERAL_ARG, 1, \ + VM_OC_PUSH_CLASS_ENVIRONMENT | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_PUSH_ANONYMOUS_CLASS_ENV, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_CLASS_ENVIRONMENT) \ + CBC_OPCODE (CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_IMPLICIT_CTOR | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR_HERITAGE, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_IMPLICIT_CTOR | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_INIT_CLASS, CBC_NO_FLAG, 0, \ + VM_OC_INIT_CLASS | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_FINALIZE_NAMED_CLASS, CBC_HAS_LITERAL_ARG, -2, \ + VM_OC_FINALIZE_CLASS | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_FINALIZE_ANONYMOUS_CLASS, CBC_NO_FLAG, -2, \ + VM_OC_FINALIZE_CLASS) \ + CBC_OPCODE (CBC_EXT_PUSH_SUPER, CBC_NO_FLAG, 1, \ + VM_OC_NONE) \ + CBC_OPCODE (CBC_EXT_PUSH_SUPER_CONSTRUCTOR, CBC_NO_FLAG, 1, \ + VM_OC_PUSH_SUPER_CONSTRUCTOR) \ + CBC_OPCODE (CBC_EXT_PUSH_SUPER_PROP, CBC_NO_FLAG, 0, \ + VM_OC_SUPER_REFERENCE | VM_OC_GET_STACK) \ + CBC_OPCODE (CBC_EXT_SUPER_PROP_CALL_REFERENCE, CBC_NO_FLAG, 2, \ + VM_OC_SUPER_REFERENCE | VM_OC_GET_STACK) \ + CBC_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL, CBC_HAS_LITERAL_ARG, 1, \ + VM_OC_SUPER_REFERENCE | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_SUPER_PROP_LITERAL_CALL_REFERENCE, CBC_HAS_LITERAL_ARG, 3, \ + VM_OC_SUPER_REFERENCE | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_RESOLVE_LEXICAL_THIS, CBC_NO_FLAG, 1, \ + VM_OC_RESOLVE_LEXICAL_THIS | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_LOCAL_EVAL, CBC_HAS_BYTE_ARG, 0, \ + VM_OC_LOCAL_EVAL) \ CBC_OPCODE (CBC_EXT_SUPER_CALL, CBC_HAS_POP_STACK_BYTE_ARG, -1, \ VM_OC_SUPER_CALL) \ CBC_OPCODE (CBC_EXT_SUPER_CALL_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ @@ -624,6 +638,8 @@ VM_OC_SUPER_CALL | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_EXT_SPREAD_SUPER_CALL_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -1, \ VM_OC_SUPER_CALL | VM_OC_PUT_BLOCK) \ + \ + /* Spread / rest operation related opcodes. */ \ CBC_OPCODE (CBC_EXT_SPREAD_CALL, CBC_HAS_POP_STACK_BYTE_ARG, -1, \ VM_OC_SPREAD_ARGUMENTS) \ CBC_OPCODE (CBC_EXT_SPREAD_CALL_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ @@ -636,24 +652,6 @@ VM_OC_SPREAD_ARGUMENTS | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_EXT_SPREAD_CALL_PROP_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -3, \ VM_OC_SPREAD_ARGUMENTS | VM_OC_PUT_BLOCK) \ - CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_CONSTRUCTOR_SUPER | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_CONSTRUCTOR_SUPER | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_PUSH_SUPER, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_SUPER | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_PUSH_STATIC_SUPER, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_SUPER | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_THIS, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_CONSTRUCTOR_THIS | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_SUPER_PROP_CALL, CBC_NO_FLAG, 0, \ - VM_OC_SUPER_PROP_REFERENCE) \ - CBC_OPCODE (CBC_EXT_SUPER_PROP_ASSIGN, CBC_NO_FLAG, 0, \ - VM_OC_SUPER_PROP_REFERENCE) \ - CBC_OPCODE (CBC_EXT_CONSTRUCTOR_RETURN, CBC_NO_FLAG, -1, \ - VM_OC_CONSTRUCTOR_RET | VM_OC_GET_STACK) \ - \ - /* Spread / rest operation related opcodes. */ \ CBC_OPCODE (CBC_EXT_PUSH_SPREAD_ELEMENT, CBC_NO_FLAG, 1, \ VM_OC_PUSH_SPREAD_ELEMENT) \ CBC_OPCODE (CBC_EXT_SPREAD_ARRAY_APPEND, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ @@ -782,7 +780,7 @@ typedef enum CBC_CODE_FLAGS_ARROW_FUNCTION = (1u << 7), /**< this function is an arrow function */ CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 8), /**< this function is a static snapshot function */ CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 9), /**< this function should be ignored by debugger */ - CBC_CODE_FLAGS_CONSTRUCTOR = (1u << 10), /**< this function is a constructor */ + CBC_CODE_FLAGS_CLASS_CONSTRUCTOR = (1u << 10), /**< this function is a class constructor */ CBC_CODE_FLAGS_GENERATOR = (1u << 11), /**< this function is a generator */ CBC_CODE_FLAGS_REST_PARAMETER = (1u << 12), /**< this function has rest parameter */ CBC_CODE_FLAG_HAS_TAGGED_LITERALS = (1u << 13), /**< this function has tagged template literal list */ diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index 2f591affc..9d037e411 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -2762,9 +2762,8 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */ * In this case we use a synthetic name for them. */ context_p->token.type = LEXER_LITERAL; context_p->token.keyword_type = LEXER_EOS; - context_p->token.lit_location.type = LEXER_IDENT_LITERAL; - context_p->token.lit_location.has_escape = false; - lexer_construct_literal_object (context_p, &lexer_default_literal, literal_type); + context_p->token.lit_location = lexer_default_literal; + lexer_construct_literal_object (context_p, &context_p->token.lit_location, literal_type); context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_DEFAULT_CLASS_OR_FUNC); return; } @@ -2917,6 +2916,7 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ if (is_class_method && lexer_compare_literal_to_string (context_p, "constructor", 11)) { context_p->token.type = LEXER_CLASS_CONSTRUCTOR; + context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES; return; } #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 9b171d714..c54209fc3 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -428,20 +428,56 @@ static const lexer_lit_location_t lexer_set_literal = }; /** - * Parse class as an object literal. + * Class literal parsing options. + */ +typedef enum +{ + PARSER_CLASS_LITERAL_NO_OPTS = 0, /**< no options are provided */ + PARSER_CLASS_LITERAL_CTOR_PRESENT = (1 << 0), /**< class constructor is present */ + PARSER_CLASS_LITERAL_HERTIAGE_PRESENT = (1 << 1), /**< class heritage is present */ +} parser_class_literal_opts_t; + +/** + * Parse class literal. */ static void -parser_parse_class_literal (parser_context_t *context_p) /**< context */ +parser_parse_class_literal (parser_context_t *context_p, /**< context */ + parser_class_literal_opts_t opts) /**< class literal parsing options */ { JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE); - bool super_called = false; - uint32_t status_flags = PARSER_FUNCTION_CLOSURE; - status_flags |= context_p->status_flags & (PARSER_CLASS_HAS_SUPER | PARSER_CLASS_IMPLICIT_SUPER); + uint32_t status_flags = PARSER_FUNCTION_CLOSURE | PARSER_ALLOW_SUPER; + + lexer_literal_t *ctor_literal_p = NULL; + + if (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT) + { + if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS) + { + parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); + } + + ctor_literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); + ctor_literal_p->type = LEXER_UNUSED_LITERAL; + ctor_literal_p->status_flags = 0; + parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, (uint16_t) (context_p->literal_count++)); + } + else if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT) + { + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR_HERITAGE); + } + else + { + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR); + } + + parser_emit_cbc_ext (context_p, CBC_EXT_INIT_CLASS); + + bool is_static = false; while (true) { - if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION)) + if (!is_static) { lexer_skip_empty_statements (context_p); } @@ -469,7 +505,7 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ goto parse_class_method; } - uint32_t accessor_status_flags = PARSER_FUNCTION_CLOSURE; + uint32_t accessor_status_flags = status_flags; accessor_status_flags |= (is_getter ? PARSER_IS_PROPERTY_GETTER : PARSER_IS_PROPERTY_SETTER); lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD | LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); @@ -479,7 +515,7 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ { is_computed = true; } - else if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION) + else if (!is_static && LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type) && lexer_compare_literal_to_string (context_p, "constructor", 11)) { @@ -495,7 +531,6 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); cbc_ext_opcode_t opcode; - bool is_static = (status_flags & PARSER_CLASS_STATIC_FUNCTION) != 0; if (is_computed) { @@ -525,51 +560,42 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ } context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode); - status_flags &= (uint32_t) ~PARSER_CLASS_STATIC_FUNCTION; + is_static = false; continue; } - if (!(status_flags & PARSER_CLASS_STATIC_FUNCTION)) + if (!is_static) { if (context_p->token.type == LEXER_KEYW_STATIC) { - status_flags |= PARSER_CLASS_STATIC_FUNCTION; + is_static = true; continue; } if (context_p->token.type == LEXER_CLASS_CONSTRUCTOR) { - if (super_called) + JERRY_ASSERT (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT); + JERRY_ASSERT (ctor_literal_p != NULL); + + if (ctor_literal_p->type == LEXER_FUNCTION_LITERAL) { /* 14.5.1 */ parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS); } - else + + uint32_t constructor_status_flags = (status_flags + | PARSER_CLASS_CONSTRUCTOR + | PARSER_LEXICAL_ENV_NEEDED); + + if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT) { - super_called = true; + constructor_status_flags |= PARSER_ALLOW_SUPER_CALL; } parser_flush_cbc (context_p); - uint32_t constructor_status_flags = status_flags | PARSER_CLASS_CONSTRUCTOR; - - if (context_p->status_flags & PARSER_CLASS_HAS_SUPER) - { - constructor_status_flags |= PARSER_LEXICAL_ENV_NEEDED; - } - - if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS) - { - parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED); - } - - uint16_t result_index = context_p->literal_count; - lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); - literal_p->type = LEXER_UNUSED_LITERAL; - literal_p->status_flags = 0; - literal_p->u.bytecode_p = parser_parse_function (context_p, constructor_status_flags); - literal_p->type = LEXER_FUNCTION_LITERAL; - parser_emit_cbc_literal (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_SET_CLASS_LITERAL), result_index); - context_p->literal_count++; + ecma_compiled_code_t *compiled_code_p = parser_parse_function (context_p, constructor_status_flags); + ctor_literal_p->u.bytecode_p = compiled_code_p; + ctor_literal_p->type = LEXER_FUNCTION_LITERAL; continue; } } @@ -598,7 +624,7 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ } else if (LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type)) { - if (status_flags & PARSER_CLASS_STATIC_FUNCTION) + if (is_static) { if (lexer_compare_literal_to_string (context_p, "prototype", 9)) { @@ -625,11 +651,11 @@ parse_class_method: context_p->last_cbc.value = literal_index; - if ((status_flags & PARSER_CLASS_STATIC_FUNCTION)) + if (is_static) { context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (is_computed ? CBC_EXT_SET_STATIC_COMPUTED_PROPERTY_LITERAL : CBC_EXT_SET_STATIC_PROPERTY_LITERAL); - status_flags &= (uint32_t) ~PARSER_CLASS_STATIC_FUNCTION; + is_static = false; } else { @@ -637,26 +663,8 @@ parse_class_method: : CBC_SET_LITERAL_PROPERTY); } } - - if (!super_called && (context_p->status_flags & PARSER_CLASS_HAS_SUPER)) - { - parser_emit_cbc_ext (context_p, CBC_EXT_IMPLICIT_CONSTRUCTOR_CALL); - } - - if (context_p->status_flags & PARSER_CLASS_HAS_SUPER) - { - parser_emit_cbc_ext (context_p, CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR); - } } /* parser_parse_class_literal */ -/** - * Description of "prototype" literal string. - */ -static const lexer_lit_location_t lexer_prototype_literal = -{ - (const uint8_t *) "prototype", 9, LEXER_STRING_LITERAL, false -}; - /** * Parse class statement or expression. */ @@ -668,6 +676,15 @@ parser_parse_class (parser_context_t *context_p, /**< context */ JERRY_ASSERT (context_p->token.type == LEXER_KEYW_CLASS); uint16_t class_ident_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS; + uint16_t class_name_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS; + parser_class_literal_opts_t opts = PARSER_CLASS_LITERAL_NO_OPTS; + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CLASS_CONSTRUCTOR); + scanner_release_next (context_p, sizeof (scanner_info_t)); + opts |= PARSER_CLASS_LITERAL_CTOR_PRESENT; + } if (is_statement) { @@ -681,9 +698,11 @@ parser_parse_class (parser_context_t *context_p, /**< context */ JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED); } - class_ident_index = context_p->lit_object.index; + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL); + class_name_index = context_p->lit_object.index; + #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) parser_module_append_export_name (context_p); context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT); @@ -699,16 +718,31 @@ parser_parse_class (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { /* NOTE: If 'Function.name' will be supported, the current literal object must be set to 'name' property. */ + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL); + class_name_index = context_p->lit_object.index; lexer_next_token (context_p); } } - bool create_class_env = (context_p->token.type == LEXER_KEYW_EXTENDS - || (context_p->status_flags & PARSER_CLASS_HAS_SUPER)); - - if (create_class_env) + if (class_name_index != PARSER_MAXIMUM_NUMBER_OF_LITERALS) { - parser_parse_super_class_context_start (context_p); + parser_emit_cbc_ext_literal (context_p, CBC_EXT_PUSH_NAMED_CLASS_ENV, class_name_index); + } + else + { + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_ANONYMOUS_CLASS_ENV); + } + + if (context_p->token.type == LEXER_KEYW_EXTENDS) + { + lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_LEFT_HAND_SIDE); + opts |= PARSER_CLASS_LITERAL_HERTIAGE_PRESENT; + } + else + { + /* Elisions represents that the classHeritage is not present */ + parser_emit_cbc (context_p, CBC_PUSH_ELISION); } if (context_p->token.type != LEXER_LEFT_BRACE) @@ -716,28 +750,21 @@ parser_parse_class (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED); } - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE); - bool is_strict = context_p->status_flags & PARSER_IS_STRICT; /* 14.5. A ClassBody is always strict code. */ context_p->status_flags |= PARSER_IS_STRICT; /* ClassDeclaration is parsed. Continue with class body. */ - parser_parse_class_literal (context_p); + parser_parse_class_literal (context_p, opts); - JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE); - - lexer_construct_literal_object (context_p, - (lexer_lit_location_t *) &lexer_prototype_literal, - lexer_prototype_literal.type); - - parser_emit_cbc_literal (context_p, CBC_SET_PROPERTY, context_p->lit_object.index); - - if (create_class_env) + if (class_name_index != PARSER_MAXIMUM_NUMBER_OF_LITERALS) { - parser_parse_super_class_context_end (context_p); - context_p->status_flags &= (uint32_t) ~(PARSER_CLASS_HAS_SUPER | PARSER_CLASS_IMPLICIT_SUPER); + parser_emit_cbc_ext_literal (context_p, CBC_EXT_FINALIZE_NAMED_CLASS, class_name_index); + } + else + { + parser_emit_cbc_ext (context_p, CBC_EXT_FINALIZE_ANONYMOUS_CLASS); } if (is_statement) @@ -754,6 +781,7 @@ parser_parse_class (parser_context_t *context_p, /**< context */ /* Restore flag */ context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT; } + context_p->status_flags &= (uint32_t) ~PARSER_ALLOW_SUPER; lexer_next_token (context_p); } /* parser_parse_class */ @@ -1412,7 +1440,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ /* Check if "new.target" is written here. */ if (scanner_try_scan_new_target (context_p)) { - if (!(context_p->status_flags & PARSER_IS_FUNCTION) + if (!(context_p->status_flags & PARSER_ALLOW_NEW_TARGET) && !(context_p->global_status_flags & ECMA_PARSE_CALLED_FROM_FUNCTION)) { parser_raise_error (context_p, PARSER_ERR_NEW_TARGET_NOT_ALLOWED); @@ -1478,8 +1506,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ } parser_check_assignment_expr (context_p); - parser_parse_function_expression (context_p, - PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); + parser_parse_function_expression (context_p, PARSER_IS_ARROW_FUNCTION); return parser_abort_parsing_after_arrow (context_p); } #endif /* ENABLED (JERRY_ES2015) */ @@ -1618,16 +1645,9 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ case LEXER_KEYW_THIS: { #if ENABLED (JERRY_ES2015) - if (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)) + if (context_p->status_flags & PARSER_ALLOW_SUPER_CALL) { - if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER) - { - parser_emit_cbc (context_p, CBC_PUSH_THIS); - } - else - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS); - } + parser_emit_cbc_ext (context_p, CBC_EXT_RESOLVE_LEXICAL_THIS); } else { @@ -1661,40 +1681,25 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ } case LEXER_KEYW_SUPER: { - if (lexer_check_next_characters (context_p, LIT_CHAR_DOT, LIT_CHAR_LEFT_SQUARE) - && context_p->status_flags & (PARSER_CLASS_HAS_SUPER)) + if (context_p->status_flags & PARSER_ALLOW_SUPER) { - if (!LEXER_IS_BINARY_LVALUE_TOKEN (context_p->stack_top_uint8)) + if (lexer_check_next_characters (context_p, LIT_CHAR_DOT, LIT_CHAR_LEFT_SQUARE) + && ((context_p->status_flags & PARSER_ALLOW_NEW_TARGET) + || (context_p->global_status_flags & ECMA_PARSE_CALLED_FROM_FUNCTION))) { - context_p->status_flags |= PARSER_CLASS_SUPER_PROP_REFERENCE; - } - - if (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR) - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP); + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SUPER); break; } - if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER) + if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN) + && (context_p->status_flags & PARSER_ALLOW_SUPER_CALL)) { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_STATIC_SUPER); + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SUPER_CONSTRUCTOR); break; } - - bool is_static = (context_p->status_flags & PARSER_CLASS_STATIC_FUNCTION) != 0; - parser_emit_cbc_ext (context_p, is_static ? CBC_EXT_PUSH_STATIC_SUPER : CBC_EXT_PUSH_SUPER); - break; } - if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN) - && ((context_p->status_flags & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER) - && !(context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)) - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_SUPER); - break; - } - - parser_raise_error (context_p, PARSER_ERR_UNEXPECTED_SUPER_REFERENCE); + parser_raise_error (context_p, PARSER_ERR_UNEXPECTED_SUPER_KEYWORD); } case LEXER_LEFT_PAREN: { @@ -1704,7 +1709,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ parser_check_assignment_expr (context_p); context_p->token.type = LEXER_ARROW_LEFT_PAREN; - parser_parse_function_expression (context_p, PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); + parser_parse_function_expression (context_p, PARSER_IS_ARROW_FUNCTION); return parser_abort_parsing_after_arrow (context_p); } case LEXER_KEYW_YIELD: @@ -1758,31 +1763,9 @@ static void parser_process_unary_expression (parser_context_t *context_p, /**< context */ size_t grouping_level) /**< grouping level */ { -#if ENABLED (JERRY_ES2015) - /* Track to see if a property was accessed or not */ - bool property_accessed = false; -#endif /* ENABLED (JERRY_ES2015) */ - /* Parse postfix part of a primary expression. */ while (true) { -#if ENABLED (JERRY_ES2015) - if (context_p->token.type == LEXER_DOT || context_p->token.type == LEXER_LEFT_SQUARE) - { - if (property_accessed) - { - /** - * In the case of "super.prop1.prop2(...)" the second property access should not - * generate a super prop call thus the 'PARSER_CLASS_SUPER_PROP_REFERENCE' flags should be removed. - * - * Similar case: "super[propname].prop2(...)" - */ - context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; - } - property_accessed = true; - } -#endif /* ENABLED (JERRY_ES2015) */ - /* Since break would only break the switch, we use * continue to continue this loop. Without continue, * the code abandons the loop. */ @@ -1809,6 +1792,13 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_PROP_THIS_LITERAL); } +#if ENABLED (JERRY_ES2015) + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER)) + { + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL); + context_p->last_cbc.literal_index = context_p->lit_object.index; + } +#endif /* ENABLED (JERRY_ES2015) */ else { parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_PROP_LITERAL); @@ -1821,6 +1811,15 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ { parser_push_result (context_p); +#if ENABLED (JERRY_ES2015) + uint16_t last_cbc_opcode = context_p->last_cbc_opcode; + + if (last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER)) + { + context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; + } +#endif /* ENABLED (JERRY_ES2015) */ + lexer_next_token (context_p); parser_parse_expression (context_p, PARSE_EXPR); if (context_p->token.type != LEXER_RIGHT_SQUARE) @@ -1829,6 +1828,14 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ } lexer_next_token (context_p); +#if ENABLED (JERRY_ES2015) + if (last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER)) + { + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SUPER_PROP); + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ + if (PARSER_IS_MUTABLE_PUSH_LITERAL (context_p->last_cbc_opcode)) { context_p->last_cbc_opcode = PARSER_PUSH_LITERAL_TO_PUSH_PROP_LITERAL (context_p->last_cbc_opcode); @@ -1871,10 +1878,20 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ context_p->last_cbc_opcode = PARSER_PUSH_PROP_TO_PUSH_PROP_REFERENCE (context_p->last_cbc_opcode); } #if ENABLED (JERRY_ES2015) - else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_CONSTRUCTOR_SUPER)) + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_CONSTRUCTOR)) { opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL); } + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL)) + { + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_PROP_LITERAL_CALL_REFERENCE); + opcode = CBC_CALL_PROP; + } + else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP)) + { + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_PROP_CALL_REFERENCE); + opcode = CBC_CALL_PROP; + } #endif /* ENABLED (JERRY_ES2015) */ else if (JERRY_UNLIKELY (context_p->status_flags & PARSER_INSIDE_WITH) && PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) @@ -1961,11 +1978,11 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ if (is_eval) { #if ENABLED (JERRY_ES2015) - if (context_p->status_flags & PARSER_CLASS_HAS_SUPER) + if (context_p->status_flags & (PARSER_ALLOW_SUPER_CALL | PARSER_ALLOW_SUPER)) { - parser_flush_cbc (context_p); - context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_CLASS_EVAL); - context_p->last_cbc.value = PARSER_GET_CLASS_ECMA_PARSE_OPTS (context_p->status_flags); + parser_emit_cbc_ext_call (context_p, + CBC_EXT_LOCAL_EVAL, + PARSER_SAVE_STATUS_FLAGS (context_p->status_flags)); } else { @@ -1977,12 +1994,6 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ } #if ENABLED (JERRY_ES2015) - if ((context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE) && opcode == CBC_CALL_PROP) - { - parser_emit_cbc_ext (context_p, CBC_EXT_SUPER_PROP_CALL); - context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; - } - if (has_spread_element) { uint16_t spread_opcode; @@ -2149,6 +2160,13 @@ parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< * assignment, since it has multiple forms depending on the * previous instruction. */ +#if ENABLED (JERRY_ES2015) + if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL)) + { + context_p->last_cbc_opcode = CBC_PUSH_PROP_THIS_LITERAL; + } +#endif /* ENABLED (JERRY_ES2015) */ + if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) { @@ -2199,14 +2217,6 @@ parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index); parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_LITERAL); context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; -#if ENABLED (JERRY_ES2015) - if (context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE) - { - parser_emit_cbc_ext (context_p, CBC_EXT_SUPER_PROP_ASSIGN); - parser_flush_cbc (context_p); - } - context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; -#endif /* ENABLED (JERRY_ES2015) */ } else { @@ -2708,8 +2718,7 @@ parser_pattern_process_assignment (parser_context_t *context_p, /**< context */ if (!PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode)) { - if (!PARSER_IS_PUSH_PROP (context_p->last_cbc_opcode) - && context_p->last_cbc_opcode != CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP) + if (!PARSER_IS_PUSH_PROP (context_p->last_cbc_opcode)) { parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN); } @@ -3065,16 +3074,6 @@ parser_parse_expression (parser_context_t *context_p, /**< context */ parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START); -#if ENABLED (JERRY_ES2015) - /* Parsing a new expression: - * So save, remove, and at the end restore the super prop reference indicator. - * - * If this is not done, it is possible to carry the flag over to the next expression. - */ - bool has_super_ref = (context_p->status_flags & PARSER_CLASS_SUPER_PROP_REFERENCE) != 0; - context_p->status_flags &= (uint32_t) ~PARSER_CLASS_SUPER_PROP_REFERENCE; -#endif - if (options & PARSE_EXPR_HAS_LITERAL) { JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); @@ -3164,14 +3163,6 @@ process_unary_expression: { parser_push_result (context_p); } - -#if ENABLED (JERRY_ES2015) - /* Restore the super prop ref flag. */ - if (has_super_ref) - { - context_p->status_flags |= (uint32_t) PARSER_CLASS_SUPER_PROP_REFERENCE; - } -#endif /* ENABLED (JERRY_ES2015) */ } /* parser_parse_expression */ /** diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index d7edd0202..bf63d450c 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -65,23 +65,26 @@ typedef enum PARSER_DISALLOW_YIELD = (1u << 16), /**< throw SyntaxError for yield expression */ PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM = (1u << 17), /**< function has a non simple parameter */ PARSER_FUNCTION_HAS_REST_PARAM = (1u << 18), /**< function has rest parameter */ - /* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */ - PARSER_CLASS_CONSTRUCTOR = (1u << 19), /**< a class constructor is parsed (this value must be kept in - * in sync with ECMA_PARSE_CLASS_CONSTRUCTOR) */ - PARSER_CLASS_HAS_SUPER = (1u << 20), /**< class has super reference */ - PARSER_CLASS_IMPLICIT_SUPER = (1u << 21), /**< class has implicit parent class */ - PARSER_CLASS_STATIC_FUNCTION = (1u << 22), /**< this function is a static class method */ - PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 23), /**< super property call or assignment */ + /* These three status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */ + PARSER_CLASS_CONSTRUCTOR = (1u << 19), /**< a class constructor is parsed + * Note: PARSER_ALLOW_SUPER must be present */ + PARSER_ALLOW_SUPER = (1u << 20), /**< allow super property access */ + PARSER_ALLOW_SUPER_CALL = (1u << 21), /**< allow super constructor call + * Note: PARSER_CLASS_CONSTRUCTOR must be present */ + #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 24), /**< parsing a function or class default export */ - PARSER_MODULE_STORE_IDENT = (1u << 25), /**< store identifier of the current export statement */ + PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 22), /**< parsing a function or class default export */ + PARSER_MODULE_STORE_IDENT = (1u << 23), /**< store identifier of the current export statement */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ PARSER_HAS_LATE_LIT_INIT = (1u << 30), /**< there are identifier or string literals which construction * is postponed after the local parser data is freed */ #ifndef JERRY_NDEBUG PARSER_SCANNING_SUCCESSFUL = PARSER_HAS_LATE_LIT_INIT, /**< scanning process was successful */ #endif /* !JERRY_NDEBUG */ +#if ENABLED (JERRY_ES2015) + PARSER_ALLOW_NEW_TARGET = PARSER_IS_FUNCTION, /**< allow new.target parsing in the current context */ +#endif /* ENABLED (JERRY_ES2015) */ } parser_general_flags_t; /** @@ -127,43 +130,32 @@ typedef enum /** * Offset between PARSER_CLASS_CONSTRUCTOR and ECMA_PARSE_CLASS_CONSTRUCTOR */ -#define PARSER_CLASS_PARSE_OPTS_OFFSET \ +#define PARSER_SAVED_FLAGS_OFFSET \ (JERRY_LOG2 (PARSER_CLASS_CONSTRUCTOR) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR)) /** * Count of ecma_parse_opts_t class parsing options related bits */ -#define PARSER_CLASS_PARSE_OPTS_COUNT \ - (JERRY_LOG2 (ECMA_PARSE_HAS_STATIC_SUPER) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR)) +#define PARSER_SAVED_FLAGS_COUNT \ + (JERRY_LOG2 (ECMA_PARSE_ALLOW_SUPER_CALL) - JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR) + 1) /** * Mask for get class option bits from ecma_parse_opts_t */ #define PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK \ - (((1 << PARSER_CLASS_PARSE_OPTS_COUNT) - 1) << JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR)) + (((1 << PARSER_SAVED_FLAGS_COUNT) - 1) << JERRY_LOG2 (ECMA_PARSE_CLASS_CONSTRUCTOR)) /** * Get class option bits from ecma_parse_opts_t */ -#define PARSER_GET_CLASS_PARSER_OPTS(opts) \ - (((opts) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK) << PARSER_CLASS_PARSE_OPTS_OFFSET) +#define PARSER_GET_SAVED_FLAGS(opts) \ + (((opts) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK) << PARSER_SAVED_FLAGS_OFFSET) /** * Get class option bits from parser_general_flags_t */ -#define PARSER_GET_CLASS_ECMA_PARSE_OPTS(opts) \ - ((uint16_t) (((opts) >> PARSER_CLASS_PARSE_OPTS_OFFSET) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK)) - -/** - * Class constructor with heritage context representing bits - */ -#define PARSER_CLASS_CONSTRUCTOR_SUPER (PARSER_CLASS_CONSTRUCTOR | PARSER_CLASS_HAS_SUPER) - -/** - * Check the scope is a class constructor with heritage context - */ -#define PARSER_IS_CLASS_CONSTRUCTOR_SUPER(flag) \ - (((flag) & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER) +#define PARSER_SAVE_STATUS_FLAGS(opts) \ + ((uint16_t) (((opts) >> PARSER_SAVED_FLAGS_OFFSET) & PARSER_CLASS_ECMA_PARSE_OPTS_TO_PARSER_OPTS_MASK)) /* All flags that affect exotic arguments object creation. */ #define PARSER_ARGUMENTS_RELATED_FLAGS \ @@ -697,8 +689,6 @@ void parser_parse_expression_statement (parser_context_t *context_p, int options void parser_parse_expression (parser_context_t *context_p, int options); #if ENABLED (JERRY_ES2015) void parser_parse_class (parser_context_t *context_p, bool is_statement); -void parser_parse_super_class_context_start (parser_context_t *context_p); -void parser_parse_super_class_context_end (parser_context_t *context_p); void parser_parse_initializer (parser_context_t *context_p, parser_pattern_flags_t flags); void parser_parse_initializer_by_next_char (parser_context_t *context_p, parser_pattern_flags_t flags); #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index d815184e2..56aaa142f 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -901,64 +901,6 @@ parser_parse_with_statement_end (parser_context_t *context_p) /**< context */ parser_set_branch_to_current_position (context_p, &with_statement.branch); } /* parser_parse_with_statement_end */ -#if ENABLED (JERRY_ES2015) -/** - * Parse super class context like a with statement (starting part). - */ -void -parser_parse_super_class_context_start (parser_context_t *context_p) /**< context */ -{ - JERRY_ASSERT (context_p->token.type == LEXER_KEYW_EXTENDS - || (context_p->status_flags & PARSER_CLASS_HAS_SUPER)); - parser_with_statement_t with_statement; - - if (context_p->token.type == LEXER_KEYW_EXTENDS) - { - lexer_next_token (context_p); - - parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_LEFT_HAND_SIDE); - } - else - { - JERRY_ASSERT (context_p->status_flags & PARSER_CLASS_HAS_SUPER); - parser_emit_cbc (context_p, CBC_PUSH_NULL); - context_p->status_flags |= PARSER_CLASS_IMPLICIT_SUPER; - } - -#ifndef JERRY_NDEBUG - PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION); -#endif /* !JERRY_NDEBUG */ - - context_p->status_flags |= PARSER_CLASS_HAS_SUPER; - parser_emit_cbc_ext_forward_branch (context_p, - CBC_EXT_SUPER_CLASS_CREATE_CONTEXT, - &with_statement.branch); - - parser_stack_push (context_p, &with_statement, sizeof (parser_with_statement_t)); - parser_stack_push_uint8 (context_p, PARSER_STATEMENT_WITH); -} /* parser_parse_super_class_context_start */ - -/** - * Parse super class context like a with statement (ending part). - */ -void -parser_parse_super_class_context_end (parser_context_t *context_p) /**< context */ -{ - parser_with_statement_t with_statement; - parser_stack_pop_uint8 (context_p); - parser_stack_pop (context_p, &with_statement, sizeof (parser_with_statement_t)); - - parser_flush_cbc (context_p); - PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION); -#ifndef JERRY_NDEBUG - PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION); -#endif /* !JERRY_NDEBUG */ - - parser_emit_cbc_ext (context_p, CBC_EXT_CLASS_EXPR_CONTEXT_END); - parser_set_branch_to_current_position (context_p, &with_statement.branch); -} /* parser_parse_super_class_context_end */ -#endif /* ENABLED (JERRY_ES2015) */ - /** * Parse do-while statement (ending part). */ @@ -2958,7 +2900,12 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ case LEXER_KEYW_RETURN: { - if (!(context_p->status_flags & PARSER_IS_FUNCTION)) + uint32_t status_flag = PARSER_IS_FUNCTION; +#if ENABLED (JERRY_ES2015) + status_flag |= PARSER_IS_ARROW_FUNCTION; +#endif /* ENABLED (JERRY_ES2015) */ + + if (!(context_p->status_flags & status_flag)) { parser_raise_error (context_p, PARSER_ERR_INVALID_RETURN); } @@ -2971,20 +2918,6 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ || context_p->token.type == LEXER_RIGHT_BRACE) { #if ENABLED (JERRY_ES2015) - if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))) - { - if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER) - { - parser_emit_cbc (context_p, CBC_PUSH_THIS); - } - else - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS); - } - parser_emit_cbc (context_p, CBC_RETURN); - break; - } - if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) { parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED); @@ -3000,12 +2933,6 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ parser_parse_expression (context_p, PARSE_EXPR); #if ENABLED (JERRY_ES2015) - if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))) - { - parser_emit_cbc_ext (context_p, CBC_EXT_CONSTRUCTOR_RETURN); - break; - } - if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) { parser_emit_cbc_ext (context_p, CBC_EXT_RETURN_PROMISE); @@ -3174,22 +3101,6 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ #endif /* !JERRY_NDEBUG */ /* There is no lexer_next_token here, since the * next token belongs to the parent context. */ - -#if ENABLED (JERRY_ES2015) - if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))) - { - if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER) - { - parser_emit_cbc (context_p, CBC_PUSH_THIS); - } - else - { - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS); - } - parser_emit_cbc (context_p, CBC_RETURN); - parser_flush_cbc (context_p); - } -#endif /* ENABLED (JERRY_ES2015) */ return; } parser_raise_error (context_p, PARSER_ERR_INVALID_RIGHT_SQUARE); diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index bad4d77a9..ff38dd19d 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -153,6 +153,8 @@ parser_flush_cbc (parser_context_t *context_p) /**< context */ return; } + JERRY_ASSERT (last_opcode != PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER)); + context_p->status_flags |= PARSER_NO_END_LABEL; if (PARSER_IS_BASIC_OPCODE (last_opcode)) @@ -1154,7 +1156,7 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Classes may not have a static property called 'prototype'."; } - case PARSER_ERR_UNEXPECTED_SUPER_REFERENCE: + case PARSER_ERR_UNEXPECTED_SUPER_KEYWORD: { return "Super is not allowed to be used here."; } diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 67fbee932..40e574eac 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -27,8 +27,8 @@ JERRY_STATIC_ASSERT ((int) ECMA_PARSE_STRICT_MODE == (int) PARSER_IS_STRICT, ecma_parse_strict_mode_must_be_equal_to_parser_is_strict); #if ENABLED (JERRY_ES2015) -JERRY_STATIC_ASSERT ((ECMA_PARSE_CLASS_CONSTRUCTOR << PARSER_CLASS_PARSE_OPTS_OFFSET) == PARSER_CLASS_CONSTRUCTOR, - ecma_class_parse_options_must_be_able_to_be_shifted_to_ecma_general_flags); +JERRY_STATIC_ASSERT ((ECMA_PARSE_CLASS_CONSTRUCTOR << PARSER_SAVED_FLAGS_OFFSET) == PARSER_CLASS_CONSTRUCTOR, + ecma_saved_parse_options_must_be_transformed_to_ecma_general_flags); #endif /* ENABLED (JERRY_ES2015) */ /** \addtogroup parser Parser @@ -675,7 +675,7 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code JERRY_DEBUG_MSG (",arrow"); } - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR) { JERRY_DEBUG_MSG (",constructor"); } @@ -994,8 +994,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ length++; #if ENABLED (JERRY_ES2015) - if (ext_opcode == CBC_EXT_CONSTRUCTOR_RETURN - || ext_opcode == CBC_EXT_RETURN_PROMISE) + if (ext_opcode == CBC_EXT_RETURN_PROMISE) { last_opcode = CBC_RETURN; } @@ -1294,7 +1293,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ if (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR) { - compiled_code_p->status_flags |= CBC_CODE_FLAGS_CONSTRUCTOR; + compiled_code_p->status_flags |= CBC_CODE_FLAGS_CLASS_CONSTRUCTOR; } if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) @@ -1936,7 +1935,7 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ } #if ENABLED (JERRY_ES2015) - context.status_flags |= PARSER_GET_CLASS_PARSER_OPTS (parse_opts); + context.status_flags |= PARSER_GET_SAVED_FLAGS (parse_opts); context.tagged_template_literal_cp = JMEM_CP_NULL; #endif /* ENABLED (JERRY_ES2015) */ @@ -2374,13 +2373,6 @@ parser_parse_function (parser_context_t *context_p, /**< context */ } lexer_next_token (context_p); - -#if ENABLED (JERRY_ES2015) - if ((context_p->status_flags & PARSER_CLASS_CONSTRUCTOR_SUPER) == PARSER_CLASS_CONSTRUCTOR_SUPER) - { - context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; - } -#endif /* ENABLED (JERRY_ES2015) */ parser_parse_statements (context_p); compiled_code_p = parser_post_processing (context_p); @@ -2416,12 +2408,14 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */ parser_saved_context_t saved_context; ecma_compiled_code_t *compiled_code_p; - JERRY_ASSERT ((status_flags & PARSER_IS_FUNCTION) + JERRY_ASSERT (!(status_flags & PARSER_IS_FUNCTION) && (status_flags & PARSER_IS_ARROW_FUNCTION)); parser_save_context (context_p, &saved_context); context_p->status_flags |= status_flags; #if ENABLED (JERRY_ES2015) - context_p->status_flags |= saved_context.status_flags & PARSER_CLASS_HAS_SUPER; + context_p->status_flags |= saved_context.status_flags & (PARSER_IS_FUNCTION + | PARSER_ALLOW_SUPER + | PARSER_ALLOW_SUPER_CALL); #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h index e1e2588ab..c455fff5e 100644 --- a/jerry-core/parser/js/js-parser.h +++ b/jerry-core/parser/js/js-parser.h @@ -133,7 +133,7 @@ typedef enum PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR, /**< class constructor cannot be an accessor */ PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR, /**< class constructor cannot be a generator */ PARSER_ERR_CLASS_STATIC_PROTOTYPE, /**< static method name 'prototype' is not allowed */ - PARSER_ERR_UNEXPECTED_SUPER_REFERENCE, /**< unexpected super keyword */ + PARSER_ERR_UNEXPECTED_SUPER_KEYWORD, /**< unexpected super keyword */ PARSER_ERR_RIGHT_BRACE_EXPECTED, /**< right brace expected */ PARSER_ERR_OF_EXPECTED, /**< of keyword expected */ diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index 02552522a..c6000ddc6 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -104,6 +104,8 @@ typedef enum SCAN_STACK_FOR_BLOCK_END, /**< end of "for" statement with let/const declaration */ SCAN_STACK_ARROW_ARGUMENTS, /**< might be arguments of an arrow function */ SCAN_STACK_ARROW_EXPRESSION, /**< expression body of an arrow function */ + SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR, /**< explicit class constructor */ + SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR, /**< implicit class constructor */ SCAN_STACK_CLASS_STATEMENT, /**< class statement */ SCAN_STACK_CLASS_EXPRESSION, /**< class expression */ SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */ @@ -346,6 +348,8 @@ void scanner_detect_invalid_let (parser_context_t *context_p, lexer_lit_location void scanner_detect_eval_call (parser_context_t *context_p, scanner_context_t *scanner_context_p); #if ENABLED (JERRY_ES2015) +void scanner_push_class_declaration (parser_context_t *context_p, scanner_context_t *scanner_context_p, + uint8_t stack_mode); void scanner_push_destructuring_pattern (parser_context_t *context_p, scanner_context_t *scanner_context_p, uint8_t binding_type, bool is_nested); void scanner_pop_binding_list (scanner_context_t *scanner_context_p); diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index f10c78b4a..73a8ff814 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -1327,6 +1327,27 @@ scanner_detect_invalid_let (parser_context_t *context_p, /**< context */ } } /* scanner_detect_invalid_let */ +/** + * Push the values required for class declaration parsing. + */ +void +scanner_push_class_declaration (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p, /* scanner context */ + uint8_t stack_mode) /**< stack mode */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_KEYW_CLASS); + + parser_stack_push_uint8 (context_p, stack_mode); + scanner_source_start_t source_start; + source_start.source_p = context_p->source_p; + + parser_stack_push (context_p, &source_start, sizeof (scanner_source_start_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR); + scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION; + + lexer_next_token (context_p); +} /* scanner_push_class_declaration */ + /** * Push the values required for destructuring assignment or binding parsing. */ @@ -1512,6 +1533,7 @@ scanner_cleanup (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_ES2015) JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS || scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION + || scanner_info_p->type == SCANNER_TYPE_CLASS_CONSTRUCTOR || scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); #else /* !ENABLED (JERRY_ES2015) */ JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS); diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index 3fb3097f0..63dd0e1c8 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -196,10 +196,7 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) case LEXER_KEYW_CLASS: { - parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_EXPRESSION); - scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION; - - lexer_next_token (context_p); + scanner_push_class_declaration (context_p, scanner_context_p, SCAN_STACK_CLASS_EXPRESSION); if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) { @@ -1028,8 +1025,10 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * { break; } + scanner_context_p->mode = SCAN_MODE_CLASS_METHOD; parser_stack_pop_uint8 (context_p); + return SCAN_KEEP_TOKEN; } case SCAN_STACK_FUNCTION_PARAMETERS: @@ -1407,7 +1406,7 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) case LEXER_KEYW_CLASS: { - lexer_next_token (context_p); + scanner_push_class_declaration (context_p, scanner_context_p, SCAN_STACK_CLASS_STATEMENT); if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) { @@ -1427,8 +1426,6 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ } #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION; - parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_STATEMENT); return SCAN_NEXT_TOKEN; } #endif /* ENABLED (JERRY_ES2015) */ @@ -1659,10 +1656,7 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_KEYW_CLASS) { - scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION; - parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_STATEMENT); - - lexer_next_token (context_p); + scanner_push_class_declaration (context_p, scanner_context_p, SCAN_STACK_CLASS_STATEMENT); if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { @@ -1976,8 +1970,8 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ parser_stack_pop_uint8 (context_p); #if ENABLED (JERRY_ES2015) - if (context_p->stack_top_uint8 == SCAN_STACK_CLASS_STATEMENT - || context_p->stack_top_uint8 == SCAN_STACK_CLASS_EXPRESSION) + if (context_p->stack_top_uint8 == SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR + || context_p->stack_top_uint8 == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR) { scanner_context_p->mode = SCAN_MODE_CLASS_METHOD; return SCAN_KEEP_TOKEN; @@ -2342,13 +2336,28 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } case SCAN_MODE_CLASS_METHOD: { - JERRY_ASSERT (stack_top == SCAN_STACK_CLASS_STATEMENT || stack_top == SCAN_STACK_CLASS_EXPRESSION); + JERRY_ASSERT (stack_top == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR + || stack_top == SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR); lexer_skip_empty_statements (context_p); + lexer_scan_identifier (context_p); if (context_p->token.type == LEXER_RIGHT_BRACE) { + scanner_source_start_t source_start; + + parser_stack_pop_uint8 (context_p); + + if (stack_top == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR) + { + parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t)); + } + + stack_top = context_p->stack_top_uint8; + + JERRY_ASSERT (stack_top == SCAN_STACK_CLASS_STATEMENT || stack_top == SCAN_STACK_CLASS_EXPRESSION); + if (stack_top == SCAN_STACK_CLASS_STATEMENT) { /* The token is kept to disallow consuming a semicolon after it. */ @@ -2361,6 +2370,22 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ break; } + if (context_p->token.type == LEXER_LITERAL + && LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type) + && lexer_compare_literal_to_string (context_p, "constructor", 11)) + { + if (stack_top == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR) + { + scanner_source_start_t source_start; + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t)); + + scanner_info_t *info_p = scanner_insert_info (context_p, source_start.source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_CLASS_CONSTRUCTOR; + parser_stack_push_uint8 (context_p, SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR); + } + } + if (lexer_token_is_identifier (context_p, "static", 6)) { lexer_scan_identifier (context_p); @@ -3328,6 +3353,13 @@ scan_completed: print_location = true; break; } + case SCANNER_TYPE_CLASS_CONSTRUCTOR: + { + JERRY_DEBUG_MSG (" CLASS-CONSTRUCTOR: source:%d\n", + (int) (info_p->source_p - source_start_p)); + print_location = false; + break; + } case SCANNER_TYPE_LET_EXPRESSION: { JERRY_DEBUG_MSG (" LET_EXPRESSION: source:%d\n", diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index 1737cc8af..5e4832d66 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -46,6 +46,7 @@ typedef enum SCANNER_TYPE_CASE, /**< case statement */ #if ENABLED (JERRY_ES2015) SCANNER_TYPE_INITIALIZER, /**< destructuring binding or assignment pattern with initializer */ + SCANNER_TYPE_CLASS_CONSTRUCTOR, /**< class constructor */ SCANNER_TYPE_LET_EXPRESSION, /**< let expression */ SCANNER_TYPE_ERR_REDECLARED, /**< syntax error: a variable is redeclared */ #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 529b0694c..8dcfc36bc 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -27,6 +27,7 @@ #include "ecma-lex-env.h" #include "ecma-objects.h" #include "ecma-promise-object.h" +#include "ecma-proxy-object.h" #include "ecma-try-catch-macro.h" #include "jcontext.h" #include "opcodes.h" @@ -756,6 +757,466 @@ opfunc_return_promise (ecma_value_t value) /**< value */ return result; } /* opfunc_return_promise */ +/** + * Implicit class constructor handler when the classHeritage is not present. + * + * See also: ECMAScript v6, 14.5.14.10.b.i + * + * @return ECMA_VALUE_ERROR - if the function was invoked without 'new' + * ECMA_VALUE_UNDEFINED - otherwise + */ +static ecma_value_t +ecma_op_implicit_constructor_handler_cb (const ecma_value_t function_obj, /**< the function itself */ + const ecma_value_t this_val, /**< this_arg of the function */ + const ecma_value_t args_p[], /**< argument list */ + const ecma_length_t args_count) /**< argument number */ +{ + JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count); + + if (JERRY_CONTEXT (current_new_target) == NULL) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); + } + + JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != JERRY_CONTEXT_INVALID_NEW_TARGET); + return ECMA_VALUE_UNDEFINED; +} /* ecma_op_implicit_constructor_handler_cb */ + +/** + * Implicit class constructor handler when the classHeritage is present. + * + * See also: ECMAScript v6, 14.5.14.10.a.i + * + * @return ECMA_VALUE_ERROR - if the operation fails + * result of the super call - otherwise + */ +static ecma_value_t +ecma_op_implicit_constructor_handler_heritage_cb (const ecma_value_t function_obj, /**< the function itself */ + const ecma_value_t this_val, /**< this_arg of the function */ + const ecma_value_t args_p[], /**< argument list */ + const ecma_length_t args_count) /**< argument number */ +{ + JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count); + + if (JERRY_CONTEXT (current_new_target) == NULL) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); + } + + JERRY_ASSERT (JERRY_CONTEXT (current_new_target) != JERRY_CONTEXT_INVALID_NEW_TARGET); + + ecma_object_t *func_obj_p = ecma_get_object_from_value (function_obj); + ecma_value_t super_ctor = ecma_op_function_get_super_constructor (func_obj_p); + + if (ECMA_IS_VALUE_ERROR (super_ctor)) + { + return super_ctor; + } + + ecma_object_t *super_ctor_p = ecma_get_object_from_value (super_ctor); + + ecma_value_t result = ecma_op_function_construct (super_ctor_p, + JERRY_CONTEXT (current_new_target), + args_p, + args_count); + + if (ecma_is_value_object (result)) + { + ecma_value_t proto_value = ecma_op_object_get_by_magic_id (JERRY_CONTEXT (current_new_target), + LIT_MAGIC_STRING_PROTOTYPE); + if (ECMA_IS_VALUE_ERROR (proto_value)) + { + ecma_free_value (result); + result = ECMA_VALUE_ERROR; + } + else if (ecma_is_value_object (proto_value)) + { + ECMA_SET_POINTER (ecma_get_object_from_value (result)->u2.prototype_cp, + ecma_get_object_from_value (proto_value)); + } + ecma_free_value (proto_value); + } + + ecma_deref_object (super_ctor_p); + + return result; +} /* ecma_op_implicit_constructor_handler_heritage_cb */ + +/** + * Create implicit class constructor + * + * See also: ECMAScript v6, 14.5.14 + * + * @return - new external function ecma-object + */ +ecma_value_t +opfunc_create_implicit_class_constructor (uint8_t opcode) /**< current cbc opcode */ +{ + /* 8. */ + ecma_object_t *func_obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE), + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + + ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) func_obj_p; + + /* 10.a.i */ + if (opcode == CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR_HERITAGE) + { + ext_func_obj_p->u.external_handler_cb = ecma_op_implicit_constructor_handler_heritage_cb; + } + /* 10.b.i */ + else + { + ext_func_obj_p->u.external_handler_cb = ecma_op_implicit_constructor_handler_cb; + } + + return ecma_make_object_value (func_obj_p); +} /* opfunc_create_implicit_class_constructor */ + +/** + * Set the [[HomeObject]] attribute of the given functon object + */ +static inline void JERRY_ATTR_ALWAYS_INLINE +opfunc_set_home_object (ecma_object_t *func_p, /**< function object */ + ecma_object_t *parent_env_p) /**< parent environment */ +{ + if (ecma_get_object_type (func_p) == ECMA_OBJECT_TYPE_FUNCTION) + { + JERRY_ASSERT (!ecma_get_object_is_builtin (func_p)); + + ECMA_SET_NON_NULL_POINTER_TAG (((ecma_extended_object_t *) func_p)->u.function.scope_cp, parent_env_p, 0); + } +} /* opfunc_set_home_object */ + +/** + * ClassDefinitionEvaluation environment initialization part + * + * See also: ECMAScript v6, 14.5.14 + * + * @return - ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_EMPTY - otherwise + */ +void +opfunc_push_class_environment (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ + ecma_value_t **vm_stack_top, /**< VM stack top */ + ecma_value_t class_name) /**< class name */ +{ + JERRY_ASSERT (ecma_is_value_undefined (class_name) || ecma_is_value_string (class_name)); + ecma_object_t *class_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p); + + /* 4.a */ + if (!ecma_is_value_undefined (class_name)) + { + ecma_op_create_immutable_binding (class_env_p, + ecma_get_string_from_value (class_name), + ECMA_VALUE_UNINITIALIZED); + } + frame_ctx_p->lex_env_p = class_env_p; + + *(*vm_stack_top)++ = ECMA_VALUE_RELEASE_LEX_ENV; +} /* opfunc_push_class_environment */ + +/** + * ClassDefinitionEvaluation object initialization part + * + * See also: ECMAScript v6, 14.5.14 + * + * @return - ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +opfunc_init_class (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ + ecma_value_t *stack_top_p) /**< stack top */ +{ + /* 5.b, 6.e.ii */ + ecma_object_t *ctor_parent_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + ecma_object_t *proto_parent_p = NULL; + bool free_proto_parent = false; + + ecma_value_t super_class = stack_top_p[-2]; + ecma_object_t *ctor_p = ecma_get_object_from_value (stack_top_p[-1]); + + bool heritage_present = !ecma_is_value_array_hole (super_class); + + /* 5. ClassHeritage opt is not present */ + if (!heritage_present) + { + /* 5.a */ + proto_parent_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); + } + else if (!ecma_is_value_null (super_class)) + { + /* 6.f, 6.g.i */ + if (!ecma_is_constructor (super_class) + || ecma_op_function_is_generator (ecma_get_object_from_value (super_class))) + { + return ecma_raise_type_error ("Class extends value is not a constructor or null"); + } + + ecma_object_t *parent_p = ecma_get_object_from_value (super_class); + + /* 6.g.ii */ + ecma_value_t proto_parent = ecma_op_object_get_by_magic_id (parent_p, LIT_MAGIC_STRING_PROTOTYPE); + + /* 6.g.iii */ + if (ECMA_IS_VALUE_ERROR (proto_parent)) + { + return proto_parent; + } + + /* 6.g.iv */ + if (ecma_is_value_object (proto_parent)) + { + proto_parent_p = ecma_get_object_from_value (proto_parent); + free_proto_parent = true; + } + else if (ecma_is_value_null (proto_parent)) + { + proto_parent_p = NULL; + } + else + { + return ecma_raise_type_error ("Property 'prototype' is not an object or null"); + } + + /* 6.g.v */ + ctor_parent_p = parent_p; + } + + /* 7. */ + ecma_object_t *proto_p = ecma_create_object (proto_parent_p, 0, ECMA_OBJECT_TYPE_GENERAL); + ecma_value_t proto = ecma_make_object_value (proto_p); + + ECMA_SET_POINTER (ctor_p->u2.prototype_cp, ctor_parent_p); + + if (free_proto_parent) + { + ecma_deref_object (proto_parent_p); + } + ecma_free_value (super_class); + + /* 16. */ + ecma_property_value_t *property_value_p; + property_value_p = ecma_create_named_data_property (ctor_p, + ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE), + ECMA_PROPERTY_FIXED, + NULL); + property_value_p->value = proto; + + /* 18. */ + property_value_p = ecma_create_named_data_property (proto_p, + ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR), + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + NULL); + property_value_p->value = ecma_make_object_value (ctor_p); + + if (ecma_get_object_type (ctor_p) == ECMA_OBJECT_TYPE_FUNCTION) + { + ecma_object_t *proto_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p, + proto_p, + ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); + + ECMA_SET_NON_NULL_POINTER_TAG (((ecma_extended_object_t *) ctor_p)->u.function.scope_cp, proto_env_p, 0); + + /* 15. set F’s [[ConstructorKind]] internal slot to "derived". */ + if (heritage_present) + { + ECMA_SET_THIRD_BIT_TO_POINTER_TAG (((ecma_extended_object_t *) ctor_p)->u.function.scope_cp); + } + + ecma_deref_object (proto_env_p); + } + + stack_top_p[-2] = stack_top_p[-1]; + stack_top_p[-1] = proto; + + return ECMA_VALUE_EMPTY; +} /* opfunc_init_class */ + +/** + * Set [[Enumerable]] and [[HomeObject]] attributes for all class method + */ +static void +opfunc_set_class_attributes (ecma_object_t *obj_p, /**< object */ + ecma_object_t *parent_env_p) /**< parent environment */ +{ + jmem_cpointer_t prop_iter_cp = obj_p->u1.property_list_cp; + +#if ENABLED (JERRY_PROPRETY_HASHMAP) + if (prop_iter_cp != JMEM_CP_NULL) + { + ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); + if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) + { + prop_iter_cp = prop_iter_p->next_property_cp; + } + } +#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ + + while (prop_iter_cp != JMEM_CP_NULL) + { + ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); + JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); + + ecma_property_pair_t *property_pair_p = (ecma_property_pair_t *) prop_iter_p; + + for (uint32_t index = 0; index < ECMA_PROPERTY_PAIR_ITEM_COUNT; index++) + { + uint8_t property = property_pair_p->header.types[index]; + + if (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA) + { + JERRY_ASSERT (ecma_is_value_object (property_pair_p->values[index].value)); + if (ecma_is_property_enumerable (property)) + { + property_pair_p->header.types[index] = (uint8_t) (property & ~ECMA_PROPERTY_FLAG_ENUMERABLE); + opfunc_set_home_object (ecma_get_object_from_value (property_pair_p->values[index].value), parent_env_p); + } + } + else if (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDACCESSOR) + { + ecma_property_value_t *accessor_objs_p = property_pair_p->values + index; + + ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (accessor_objs_p); + + if (get_set_pair_p->getter_cp != JMEM_CP_NULL) + { + opfunc_set_home_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp), parent_env_p); + } + + if (get_set_pair_p->setter_cp != JMEM_CP_NULL) + { + opfunc_set_home_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->setter_cp), parent_env_p); + } + } + else + { + JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_SPECIAL); + + JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_HASHMAP + || property == ECMA_PROPERTY_TYPE_DELETED); + } + } + + prop_iter_cp = prop_iter_p->next_property_cp; + } +} /* opfunc_set_class_attributes */ + +/** + * Pop the current lexical environment referenced by the frame context + */ +void +opfunc_pop_lexical_environment (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ +{ + ecma_object_t *outer_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, frame_ctx_p->lex_env_p->u2.outer_reference_cp); + ecma_deref_object (frame_ctx_p->lex_env_p); + frame_ctx_p->lex_env_p = outer_env_p; +} /* opfunc_pop_lexical_environment */ + +/** + * ClassDefinitionEvaluation finalization part + * + * See also: ECMAScript v6, 14.5.14 + */ +void +opfunc_finalize_class (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ + ecma_value_t **vm_stack_top_p, /**< current vm stack top */ + ecma_value_t class_name) /**< class name */ +{ + JERRY_ASSERT (ecma_is_value_undefined (class_name) || ecma_is_value_string (class_name)); + ecma_value_t *stack_top_p = *vm_stack_top_p; + + ecma_object_t *ctor_p = ecma_get_object_from_value (stack_top_p[-2]); + ecma_object_t *proto_p = ecma_get_object_from_value (stack_top_p[-1]); + + ecma_object_t *class_env_p = frame_ctx_p->lex_env_p; + + /* 23.a */ + if (!ecma_is_value_undefined (class_name)) + { + ecma_op_initialize_binding (class_env_p, ecma_get_string_from_value (class_name), stack_top_p[-2]); + } + + ecma_object_t *ctor_env_p = ecma_create_object_lex_env (class_env_p, + ctor_p, + ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); + ecma_object_t *proto_env_p = ecma_create_object_lex_env (class_env_p, + proto_p, + ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); + + opfunc_set_class_attributes (ctor_p, ctor_env_p); + opfunc_set_class_attributes (proto_p, proto_env_p); + + ecma_deref_object (proto_env_p); + ecma_deref_object (ctor_env_p); + + opfunc_pop_lexical_environment (frame_ctx_p); + + ecma_deref_object (proto_p); + + /* only the current class remains on the stack */ + JERRY_ASSERT (stack_top_p[-3] == ECMA_VALUE_RELEASE_LEX_ENV); + stack_top_p[-3] = stack_top_p[-2]; + *vm_stack_top_p -= 2; +} /* opfunc_finalize_class */ + +/** + * MakeSuperPropertyReference operation + * + * See also: ECMAScript v6, 12.3.5.3 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +opfunc_form_super_reference (ecma_value_t **vm_stack_top_p, /**< current vm stack top */ + vm_frame_ctx_t *frame_ctx_p, /**< frame context */ + ecma_value_t prop_name, /**< property name to resolve */ + uint8_t opcode) /**< current cbc opcode */ +{ + ecma_value_t parent = ecma_op_resolve_super_base (frame_ctx_p->lex_env_p); + + if (ECMA_IS_VALUE_ERROR (parent)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot invoke nullable super method.")); + } + + if (ECMA_IS_VALUE_ERROR (ecma_op_check_object_coercible (parent))) + { + return ECMA_VALUE_ERROR; + } + + ecma_object_t *parent_p = ecma_get_object_from_value (parent); + ecma_string_t *prop_name_p = ecma_op_to_prop_name (prop_name); + + if (prop_name_p == NULL) + { + ecma_deref_object (parent_p); + return ECMA_VALUE_ERROR; + } + + ecma_value_t result = ecma_op_object_get_with_receiver (parent_p, prop_name_p, frame_ctx_p->this_binding); + ecma_deref_ecma_string (prop_name_p); + ecma_deref_object (parent_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + ecma_value_t *stack_top_p = *vm_stack_top_p; + + if (opcode == CBC_EXT_SUPER_PROP_LITERAL_CALL_REFERENCE || opcode == CBC_EXT_SUPER_PROP_CALL_REFERENCE) + { + *stack_top_p++ = ecma_copy_value (frame_ctx_p->this_binding); + *stack_top_p++ = ECMA_VALUE_UNDEFINED; + } + + *stack_top_p++ = result; + *vm_stack_top_p = stack_top_p; + + return ECMA_VALUE_EMPTY; +} /* opfunc_form_super_reference */ #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 43c8fdd49..8c20fe713 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -118,6 +118,25 @@ opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, ec ecma_value_t opfunc_return_promise (ecma_value_t value); + +ecma_value_t +opfunc_create_implicit_class_constructor (uint8_t opcode); + +void +opfunc_push_class_environment (vm_frame_ctx_t *frame_ctx_p, ecma_value_t **vm_stack_top, ecma_value_t class_name); + +ecma_value_t +opfunc_init_class (vm_frame_ctx_t *frame_context_p, ecma_value_t *stack_top_p); + +void +opfunc_pop_lexical_environment (vm_frame_ctx_t *frame_ctx_p); + +void +opfunc_finalize_class (vm_frame_ctx_t *frame_ctx_p, ecma_value_t **vm_stack_top_p, ecma_value_t class_name); + +ecma_value_t +opfunc_form_super_reference (ecma_value_t **vm_stack_top_p, vm_frame_ctx_t *frame_ctx_p, ecma_value_t prop_name, + uint8_t opcode); #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/vm/vm-stack.c b/jerry-core/vm/vm-stack.c index d4319a166..e22b3509b 100644 --- a/jerry-core/vm/vm-stack.c +++ b/jerry-core/vm/vm-stack.c @@ -29,8 +29,6 @@ JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_BLOCK_CONTEXT_STACK_ALLOCATION, parser_with_context_stack_allocation_must_be_equal_to_parser_block_context_stack_allocation); -JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION, - parser_with_context_stack_allocation_must_be_equal_to_parser_super_class_context_stack_allocation); /** * Abort (finalize) the current stack context, and remove it. @@ -69,7 +67,6 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ } #if ENABLED (JERRY_ES2015) case VM_CONTEXT_BLOCK: - case VM_CONTEXT_SUPER_CLASS: #endif /* ENABLED (JERRY_ES2015) */ case VM_CONTEXT_WITH: { @@ -315,7 +312,6 @@ vm_get_context_value_offsets (ecma_value_t *context_item_p) /**< any item of a c } #if ENABLED (JERRY_ES2015) case VM_CONTEXT_BLOCK: - case VM_CONTEXT_SUPER_CLASS: #endif /* ENABLED (JERRY_ES2015) */ case VM_CONTEXT_WITH: { diff --git a/jerry-core/vm/vm-stack.h b/jerry-core/vm/vm-stack.h index 5875c2b89..a555d7452 100644 --- a/jerry-core/vm/vm-stack.h +++ b/jerry-core/vm/vm-stack.h @@ -74,7 +74,6 @@ typedef enum VM_CONTEXT_FOR_IN, /**< for-in context */ #if ENABLED (JERRY_ES2015) VM_CONTEXT_FOR_OF, /**< for-of context */ - VM_CONTEXT_SUPER_CLASS, /**< super class context */ #endif /* ENABLED (JERRY_ES2015) */ } vm_stack_context_type_t; diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 8cd13f18d..d39bb549d 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -548,24 +548,40 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_value_t func_value = *(--frame_ctx_p->stack_top_p); ecma_value_t completion_value; - ecma_op_set_super_called (frame_ctx_p->lex_env_p); - ecma_value_t this_value = ecma_op_get_class_this_binding (frame_ctx_p->lex_env_p); - if (!ecma_is_constructor (func_value)) + ecma_property_t *prop_p = ecma_op_get_this_property (frame_ctx_p->lex_env_p); + + if (ecma_op_this_binding_is_initialized (prop_p)) + { + completion_value = ecma_raise_reference_error (ECMA_ERR_MSG ("Super constructor may only be called once")); + } + else if (!ecma_is_constructor (func_value)) { completion_value = ecma_raise_type_error (ECMA_ERR_MSG ("Class extends value is not a constructor.")); } else { - completion_value = ecma_op_function_construct (ecma_get_object_from_value (func_value), - this_value, + ecma_object_t *func_obj_p = ecma_get_object_from_value (func_value); + completion_value = ecma_op_function_construct (func_obj_p, + JERRY_CONTEXT (current_new_target), arguments_p, arguments_list_len); - if (this_value != completion_value && ecma_is_value_object (completion_value)) + if (ecma_is_value_object (completion_value)) { - ecma_op_set_class_prototype (completion_value, this_value); - ecma_op_set_class_this_binding (frame_ctx_p->lex_env_p, completion_value); + ecma_value_t proto_value = ecma_op_object_get_by_magic_id (JERRY_CONTEXT (current_new_target), + LIT_MAGIC_STRING_PROTOTYPE); + if (ECMA_IS_VALUE_ERROR (proto_value)) + { + ecma_free_value (completion_value); + completion_value = ECMA_VALUE_ERROR; + } + else if (ecma_is_value_object (proto_value)) + { + ECMA_SET_POINTER (ecma_get_object_from_value (completion_value)->u2.prototype_cp, + ecma_get_object_from_value (proto_value)); + } + ecma_free_value (proto_value); } } @@ -591,6 +607,9 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { + ecma_op_bind_this_value (prop_p, completion_value); + frame_ctx_p->this_binding = completion_value; + frame_ctx_p->byte_code_p = byte_code_p; uint32_t opcode_data = vm_decode_table[(CBC_END + 1) + opcode]; @@ -641,7 +660,7 @@ vm_spread_operation (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_object_t *constructor_obj_p = ecma_get_object_from_value (func_value); completion_value = ecma_op_function_construct (constructor_obj_p, - ECMA_VALUE_UNDEFINED, + constructor_obj_p, collection_p->buffer_p, collection_p->item_count); } @@ -829,7 +848,7 @@ opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_object_t *constructor_obj_p = ecma_get_object_from_value (constructor_value); completion_value = ecma_op_function_construct (constructor_obj_p, - ECMA_VALUE_UNDEFINED, + constructor_obj_p, stack_top_p, arguments_list_len); } @@ -1648,6 +1667,13 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ continue; } #if ENABLED (JERRY_ES2015) + case VM_OC_LOCAL_EVAL: + { + ECMA_CLEAR_LOCAL_PARSE_OPTS (); + uint8_t parse_opts = *byte_code_p++; + ECMA_SET_LOCAL_PARSE_OPTS (parse_opts); + continue; + } case VM_OC_SUPER_CALL: { uint8_t arguments_list_len = *byte_code_p++; @@ -1676,327 +1702,65 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ frame_ctx_p->stack_top_p = stack_top_p; return ECMA_VALUE_UNDEFINED; } - case VM_OC_CLASS_HERITAGE: + case VM_OC_PUSH_CLASS_ENVIRONMENT: { - ecma_value_t super_value = *(--stack_top_p); - ecma_object_t *super_class_p; - branch_offset += (int32_t) (byte_code_start_p - frame_ctx_p->byte_code_start_p); + opfunc_push_class_environment (frame_ctx_p, &stack_top_p, left_value); + goto free_left_value; + } + case VM_OC_PUSH_IMPLICIT_CTOR: + { + *stack_top_p++ = opfunc_create_implicit_class_constructor (opcode); + continue; + } + case VM_OC_INIT_CLASS: + { + result = opfunc_init_class (frame_ctx_p, stack_top_p); - if (ecma_is_value_null (super_value)) + if (ECMA_IS_VALUE_ERROR (result)) { - super_class_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), - 0, - ECMA_OBJECT_TYPE_GENERAL); + goto error; } - else + continue; + } + case VM_OC_FINALIZE_CLASS: + { + opfunc_finalize_class (frame_ctx_p, &stack_top_p, left_value); + goto free_left_value; + } + case VM_OC_PUSH_SUPER_CONSTRUCTOR: + { + result = ecma_op_function_get_super_constructor (JERRY_CONTEXT (current_function_obj_p)); + + if (ECMA_IS_VALUE_ERROR (result)) { - result = ecma_op_to_object (super_value); - ecma_free_value (super_value); - - if (ECMA_IS_VALUE_ERROR (result) || !ecma_is_constructor (result)) - { - if (ECMA_IS_VALUE_ERROR (result)) - { - jcontext_release_exception (); - } - - ecma_free_value (result); - - result = ecma_raise_type_error ("Value provided by class extends is not an object or null."); - goto error; - } - else - { - super_class_p = ecma_get_object_from_value (result); - } - } - - ecma_object_t *super_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p, - super_class_p, - ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND); - - ecma_deref_object (super_class_p); - - VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION); - stack_top_p += PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION; - - stack_top_p[-1] = VM_CREATE_CONTEXT_WITH_ENV (VM_CONTEXT_SUPER_CLASS, branch_offset); - - frame_ctx_p->lex_env_p = super_env_p; - continue; - } - case VM_OC_CLASS_INHERITANCE: - { - ecma_value_t child_value = stack_top_p[-2]; - ecma_value_t child_prototype_value = stack_top_p[-1]; - - ecma_object_t *child_class_p = ecma_get_object_from_value (child_value); - ecma_object_t *child_prototype_class_p = ecma_get_object_from_value (child_prototype_value); - - ecma_object_t *super_class_p = ecma_get_lex_env_binding_object (frame_ctx_p->lex_env_p); - - if (super_class_p->u2.prototype_cp != JMEM_CP_NULL) - { - ecma_value_t super_prototype_value = ecma_op_object_get_by_magic_id (super_class_p, - LIT_MAGIC_STRING_PROTOTYPE); - - if (ECMA_IS_VALUE_ERROR (super_prototype_value)) - { - result = super_prototype_value; - goto error; - } - - if (ecma_get_object_type (super_class_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION - && !ecma_is_value_object (super_prototype_value)) - { - ecma_free_value (super_prototype_value); - result = ecma_raise_type_error (ECMA_ERR_MSG ("Class extends value does not have valid " - "prototype property.")); - goto error; - } - if (!(ECMA_IS_VALUE_ERROR (super_prototype_value) || !ecma_is_value_object (super_prototype_value))) - { - ecma_object_t *super_prototype_class_p = ecma_get_object_from_value (super_prototype_value); - - ECMA_SET_NON_NULL_POINTER (child_prototype_class_p->u2.prototype_cp, super_prototype_class_p); - ECMA_SET_NON_NULL_POINTER (child_class_p->u2.prototype_cp, super_class_p); - - } - ecma_free_value (super_prototype_value); - } - - continue; - } - case VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE: - { - ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); - - ecma_object_t *function_obj_p = ecma_create_object (prototype_obj_p, - sizeof (ecma_extended_object_t), - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); - - ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) function_obj_p; - ext_func_obj_p->u.external_handler_cb = ecma_op_function_implicit_constructor_handler_cb; - - ecma_value_t function_obj_value = ecma_make_object_value (function_obj_p); - *stack_top_p++ = function_obj_value; - - ecma_object_t *prototype_class_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), - 0, - ECMA_OBJECT_TYPE_GENERAL); - *stack_top_p++ = ecma_make_object_value (prototype_class_p); - - /* 14.5.14.18 Set constructor to prototype */ - ecma_property_value_t *prop_value_p; - prop_value_p = ecma_create_named_data_property (prototype_class_p, - ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR), - ECMA_PROPERTY_CONFIGURABLE_WRITABLE, - NULL); - ecma_named_data_property_assign_value (prototype_class_p, prop_value_p, function_obj_value); - - continue; - } - case VM_OC_SET_CLASS_CONSTRUCTOR: - { - ecma_object_t *new_constructor_obj_p = ecma_get_object_from_value (left_value); - ecma_object_t *current_constructor_obj_p = ecma_get_object_from_value (stack_top_p[-2]); - - ecma_extended_object_t *new_ext_func_obj_p = (ecma_extended_object_t *) new_constructor_obj_p; - ecma_extended_object_t *current_ext_func_obj_p = (ecma_extended_object_t *) current_constructor_obj_p; - - uint16_t type_flags_refs = current_constructor_obj_p->type_flags_refs; - const int new_type = ECMA_OBJECT_TYPE_FUNCTION - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION; - current_constructor_obj_p->type_flags_refs = (uint16_t) (type_flags_refs + new_type); - - ecma_compiled_code_t *bytecode_p; - bytecode_p = (ecma_compiled_code_t *) ecma_op_function_get_compiled_code (new_ext_func_obj_p); - bytecode_p->status_flags |= CBC_CODE_FLAGS_CONSTRUCTOR; - ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_p); - ECMA_SET_INTERNAL_VALUE_POINTER (current_ext_func_obj_p->u.function.bytecode_cp, - bytecode_p); - - ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t, - new_ext_func_obj_p->u.function.scope_cp); - ECMA_SET_NON_NULL_POINTER_TAG (current_ext_func_obj_p->u.function.scope_cp, scope_p, 0); - ecma_deref_object (new_constructor_obj_p); - continue; - } - case VM_OC_PUSH_IMPL_CONSTRUCTOR: - { - ecma_object_t *current_constructor_obj_p = ecma_get_object_from_value (stack_top_p[-2]); - - uint16_t type_flags_refs = current_constructor_obj_p->type_flags_refs; - const int new_type = ECMA_OBJECT_TYPE_BOUND_FUNCTION - ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION; - current_constructor_obj_p->type_flags_refs = (uint16_t) (type_flags_refs + new_type); - - ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) current_constructor_obj_p; - ecma_object_t *super_obj_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p); - - ECMA_SET_INTERNAL_VALUE_POINTER (ext_function_p->u.bound_function.target_function, - super_obj_p); - ext_function_p->u.bound_function.args_len_or_this = ECMA_VALUE_IMPLICIT_CONSTRUCTOR; - - continue; - } - case VM_OC_CLASS_EXPR_CONTEXT_END: - { - JERRY_ASSERT (VM_GET_CONTEXT_TYPE (stack_top_p[-2]) == VM_CONTEXT_SUPER_CLASS); - stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p - 1); - - stack_top_p++; - stack_top_p[-1] = *stack_top_p; - continue; - } - case VM_OC_CLASS_EVAL: - { - ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS (); - ECMA_SET_SUPER_EVAL_PARSER_OPTS (*byte_code_p++); - continue; - } - case VM_OC_PUSH_CONSTRUCTOR_SUPER: - { - JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE); - - bool is_super_called = ecma_op_is_super_called (frame_ctx_p->lex_env_p); - - if (byte_code_start_p[1] != CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP) - { - /* Calling super(...) */ - if (is_super_called) - { - result = ecma_raise_reference_error (ECMA_ERR_MSG ("Super constructor may only be called once.")); - - goto error; - } - } - else if (!is_super_called) - { - /* Reference to super.method or super["method"] */ - result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before " - "accessing 'super'.")); goto error; } - /* FALLTHRU */ - } - case VM_OC_PUSH_SUPER: - { - JERRY_ASSERT (byte_code_start_p[0] == CBC_EXT_OPCODE); - - if (byte_code_start_p[1] == CBC_EXT_PUSH_SUPER - || byte_code_start_p[1] == CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP) - { - ecma_object_t *super_class_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p); - - ecma_value_t super_prototype = ecma_op_object_get_by_magic_id (super_class_p, - LIT_MAGIC_STRING_PROTOTYPE); - - if (ECMA_IS_VALUE_ERROR (super_prototype)) - { - result = super_prototype; - goto error; - } - - *stack_top_p++ = super_prototype; - } - else - { - ecma_object_t *super_class_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p); - ecma_ref_object (super_class_p); - *stack_top_p++ = ecma_make_object_value (super_class_p); - } - + *stack_top_p++ = result; continue; } - case VM_OC_PUSH_CONSTRUCTOR_THIS: + case VM_OC_RESOLVE_LEXICAL_THIS: { - if (!ecma_op_is_super_called (frame_ctx_p->lex_env_p)) + result = ecma_op_get_this_binding (frame_ctx_p->lex_env_p); + + if (ECMA_IS_VALUE_ERROR (result)) { - result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before " - "accessing 'this' or returning from it.")); goto error; } - *stack_top_p++ = ecma_copy_value (ecma_op_get_class_this_binding (frame_ctx_p->lex_env_p)); + *stack_top_p++ = result; continue; } - case VM_OC_SUPER_PROP_REFERENCE: + case VM_OC_SUPER_REFERENCE: { - /** - * In case of this VM_OC_SUPER_PROP_REFERENCE the previously pushed 'super' must be replaced - * with the current 'this' value to correctly access the properties. - */ - int index = -1; /* -1 in case of CBC_EXT_SUPER_PROP_ASSIGN */ + result = opfunc_form_super_reference (&stack_top_p, frame_ctx_p, left_value, opcode); - if (JERRY_LIKELY (byte_code_start_p[1] == CBC_EXT_SUPER_PROP_CALL)) + if (ECMA_IS_VALUE_ERROR (result)) { - cbc_opcode_t next_call_opcode = (cbc_opcode_t) byte_code_start_p[2]; - /* The next opcode must be a call opcode */ - JERRY_ASSERT ((next_call_opcode >= CBC_CALL && next_call_opcode <= CBC_CALL2_PROP_BLOCK) - || (next_call_opcode == CBC_EXT_OPCODE - && byte_code_start_p[3] >= CBC_EXT_SPREAD_CALL - && byte_code_start_p[3] <= CBC_EXT_SPREAD_CALL_PROP_BLOCK)); - - int arguments_list_len; - if (next_call_opcode >= CBC_CALL0) - { - /* CBC_CALL{0,1,2}* have their arg count encoded, extract it from there */ - arguments_list_len = (int) ((next_call_opcode - CBC_CALL0) / 6); - } - else - { - /** - * In this case the arguments are coded into the byte code stream as a byte argument - * following the call opcode. - */ - arguments_list_len = (int) byte_code_start_p[next_call_opcode == CBC_EXT_OPCODE ? 4 : 3]; - } - /* The old 'super' value is at least '-3' element away from the current position on the stack. */ - index = -3 - arguments_list_len; - } - else - { - /** - * The bytecode order for super assignment should be one of this: - * - CBC_EXT_PUSH_SUPER, CBC_EXT_SUPER_PROP_ASSIGN. - * - CBC_EXT_PUSH_STATIC_SUPER, CBC_EXT_SUPER_PROP_ASSIGN. - * - CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP, CBC_EXT_SUPER_PROP_ASSIGN. - * That is one ext opcode back (-1). - */ - JERRY_ASSERT (byte_code_start_p[-1] == CBC_EXT_PUSH_SUPER - || byte_code_start_p[-1] == CBC_EXT_PUSH_STATIC_SUPER - || byte_code_start_p[-1] == CBC_EXT_PUSH_CONSTRUCTOR_SUPER_PROP); + goto error; } - /* Replace the old 'super' value with the correct 'this' binding */ - ecma_free_value (stack_top_p[index]); - stack_top_p[index] = ecma_copy_value (frame_ctx_p->this_binding); - continue; - } - case VM_OC_CONSTRUCTOR_RET: - { - result = left_value; - left_value = ECMA_VALUE_UNDEFINED; - - if (!ecma_is_value_object (result)) - { - if (ecma_is_value_undefined (result)) - { - if (!ecma_op_is_super_called (frame_ctx_p->lex_env_p)) - { - result = ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class " - "before returning from derived constructor")); - } - } - else - { - ecma_free_value (result); - result = ecma_raise_type_error (ECMA_ERR_MSG ("Derived constructors may only " - "return object or undefined.")); - } - } - - goto error; + goto free_left_value; } case VM_OC_PUSH_SPREAD_ELEMENT: { @@ -4016,7 +3780,15 @@ error: while (stack_top_p > stack_bottom_p) { - ecma_fast_free_value (*(--stack_top_p)); + ecma_value_t stack_item = *(--stack_top_p); +#if ENABLED (JERRY_ES2015) + if (stack_item == ECMA_VALUE_RELEASE_LEX_ENV) + { + opfunc_pop_lexical_environment (frame_ctx_p); + continue; + } +#endif /* ENABLED (JERRY_ES2015) */ + ecma_fast_free_value (stack_item); } #if ENABLED (JERRY_DEBUGGER) diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index cc5a88ec7..9bdef19a8 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -240,19 +240,16 @@ typedef enum VM_OC_FOR_OF_GET_NEXT, /**< get next */ VM_OC_FOR_OF_HAS_NEXT, /**< has next */ - VM_OC_CLASS_HERITAGE, /**< create a super class context */ - VM_OC_CLASS_INHERITANCE, /**< inherit properties from the 'super' class */ - VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE, /**< push class constructor */ - VM_OC_SET_CLASS_CONSTRUCTOR, /**< set class constructor to the given function literal */ - VM_OC_PUSH_IMPL_CONSTRUCTOR, /**< create implicit class constructor */ - VM_OC_CLASS_EXPR_CONTEXT_END, /**< class expression heritage context end */ - VM_OC_CLASS_EVAL, /**< eval inside a class */ + VM_OC_LOCAL_EVAL, /**< eval in local context */ VM_OC_SUPER_CALL, /**< call the 'super' constructor */ - VM_OC_SUPER_PROP_REFERENCE, /**< resolve super property reference */ - VM_OC_PUSH_SUPER, /**< push resolvable super reference */ - VM_OC_PUSH_CONSTRUCTOR_SUPER, /**< push 'super' inside a class constructor */ - VM_OC_PUSH_CONSTRUCTOR_THIS, /**< push 'this' inside a class constructor */ - VM_OC_CONSTRUCTOR_RET, /**< explicit return from a class constructor */ + VM_OC_PUSH_CLASS_ENVIRONMENT, /**< push class environment */ + VM_OC_PUSH_IMPLICIT_CTOR, /**< create implicit class constructor */ + VM_OC_INIT_CLASS, /**< initialize class */ + VM_OC_FINALIZE_CLASS, /**< finalize class */ + VM_OC_PUSH_SUPER_CONSTRUCTOR, /**< getSuperConstructor operation */ + VM_OC_RESOLVE_LEXICAL_THIS, /**< resolve this_binding from from the lexical environment */ + VM_OC_SUPER_REFERENCE, /**< push super reference */ + VM_OC_PUSH_SPREAD_ELEMENT, /**< push spread element */ VM_OC_GET_ITERATOR, /**< GetIterator abstract operation */ VM_OC_ITERATOR_STEP, /**< IteratorStep abstract operation */ @@ -300,19 +297,16 @@ typedef enum VM_OC_FOR_OF_GET_NEXT = VM_OC_NONE, /**< get next */ VM_OC_FOR_OF_HAS_NEXT = VM_OC_NONE, /**< has next */ - VM_OC_CLASS_HERITAGE = VM_OC_NONE, /**< create a super class context */ - VM_OC_CLASS_INHERITANCE = VM_OC_NONE, /**< inherit properties from the 'super' class */ - VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE = VM_OC_NONE, /**< push class constructor */ - VM_OC_SET_CLASS_CONSTRUCTOR = VM_OC_NONE, /**< set class constructor to the given function literal */ - VM_OC_PUSH_IMPL_CONSTRUCTOR = VM_OC_NONE, /**< create implicit class constructor */ - VM_OC_CLASS_EXPR_CONTEXT_END = VM_OC_NONE, /**< class expression heritage context end */ - VM_OC_CLASS_EVAL = VM_OC_NONE, /**< eval inside a class */ + VM_OC_LOCAL_EVAL = VM_OC_NONE, /**< eval in local context */ VM_OC_SUPER_CALL = VM_OC_NONE, /**< call the 'super' constructor */ - VM_OC_SUPER_PROP_REFERENCE = VM_OC_NONE, /**< resolve super property reference */ - VM_OC_PUSH_SUPER = VM_OC_NONE, /**< push resolvable super reference */ - VM_OC_PUSH_CONSTRUCTOR_SUPER = VM_OC_NONE, /**< push 'super' inside a class constructor */ - VM_OC_PUSH_CONSTRUCTOR_THIS = VM_OC_NONE, /**< push 'this' inside a class constructor */ - VM_OC_CONSTRUCTOR_RET = VM_OC_NONE, /**< explicit return from a class constructor */ + VM_OC_PUSH_CLASS_ENVIRONMENT = VM_OC_NONE, /**< push class environment */ + VM_OC_PUSH_IMPLICIT_CTOR = VM_OC_NONE, /**< create implicit class constructor */ + VM_OC_INIT_CLASS = VM_OC_NONE, /**< initialize class */ + VM_OC_FINALIZE_CLASS = VM_OC_NONE, /**< finalize class */ + VM_OC_PUSH_SUPER_CONSTRUCTOR = VM_OC_NONE, /**< getSuperConstructor operation */ + VM_OC_RESOLVE_LEXICAL_THIS = VM_OC_NONE, /**< resolve this_binding from from the lexical environment */ + VM_OC_SUPER_REFERENCE = VM_OC_NONE, /**< push super reference */ + VM_OC_PUSH_SPREAD_ELEMENT = VM_OC_NONE, /**< push spread element */ VM_OC_GET_ITERATOR = VM_OC_NONE, /**< GetIterator abstract operation */ VM_OC_ITERATOR_STEP = VM_OC_NONE, /**< IteratorStep abstract operation */ diff --git a/tests/jerry/es2015/class-inheritance-has-instance.js b/tests/jerry/es2015/class-inheritance-has-instance.js index 7152db9ab..4d9932de6 100644 --- a/tests/jerry/es2015/class-inheritance-has-instance.js +++ b/tests/jerry/es2015/class-inheritance-has-instance.js @@ -35,7 +35,7 @@ assert (secretArray instanceof Array); assert (!([] instanceof mySecretArray)); /* Add a new element to the bound function chain */ -class myEpicSecretArray extends myArray { }; +class myEpicSecretArray extends mySecretArray { }; var epicSecretArray = new myEpicSecretArray (1, 2, 3); epicSecretArray.push (4); diff --git a/tests/jerry/es2015/class-inheritance-inner-class.js b/tests/jerry/es2015/class-inheritance-inner-class.js index f92b047fa..3de029828 100644 --- a/tests/jerry/es2015/class-inheritance-inner-class.js +++ b/tests/jerry/es2015/class-inheritance-inner-class.js @@ -13,6 +13,8 @@ * limitations under the License. */ +// TODO: enable this test when super keyword is supported for normal functions +/* var console = { assert : assert }; class C1 { @@ -57,3 +59,4 @@ class C2 extends C1 { } (new C2).f (); +*/ diff --git a/tests/jerry/es2015/class.js b/tests/jerry/es2015/class.js index 34ded493b..916f8ace9 100644 --- a/tests/jerry/es2015/class.js +++ b/tests/jerry/es2015/class.js @@ -258,3 +258,77 @@ assert (G.get() == 11); assert (G.set() == 12); G.constructor = 30; assert (G.constructor === 30); + +class H { + method() { assert (typeof H === 'function'); return H; } +} + +let H_original = H; +var H_method = H.prototype.method; +C = undefined; +assert(C === undefined); +C = H_method(); +assert(C === H_original); + +var I = class C { + method() { assert(typeof C === 'function'); return C; } +} + +let I_original = I; +var I_method = I.prototype.method; +I = undefined; +assert(I === undefined); +I = I_method(); +assert(I == I_original); + +var J_method; +class J { + static [(J_method = eval('(function() { return J; })'), "X")]() {} +} +var J_original = J; +J = 6; +assert (J_method() == J_original); + +var K_method; +class K { + constructor () { + K_method = function() { return K; } + } +} +var K_original = K; +new K; +K = 6; +assert (K_method() == K_original); + +var L_method; +class L extends (L_method = function() { return L; }) { +} +var L_original = L; +L = 6; +assert (L_method() == L_original); + +/* Test cleanup class environment */ +try { + class A { + [d]() {} + } + let d; + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} + +try { + class A extends d {} + let d; + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +} +try { + var a = 1 + 2 * 3 >> class A extends d {}; + let d; + assert(false); +} catch (e) { + assert(e instanceof ReferenceError); +}