From ef1220719d8604b5ad61898d9e2b7eb1ceea2726 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Mon, 1 Oct 2018 20:50:41 -0700 Subject: [PATCH] Rework op_construct. The new form should be more suitable for classes. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/api/jerry.c | 1 + .../ecma/operations/ecma-function-object.c | 228 +++++++++--------- .../ecma/operations/ecma-function-object.h | 4 +- jerry-core/vm/vm.c | 1 + 4 files changed, 114 insertions(+), 120 deletions(-) diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index a7374ffc6f..5de273111a 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -2213,6 +2213,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, args_p, args_count)); } diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index fd6f5eabe9..ca22e233bc 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -699,86 +699,6 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ } } /* ecma_op_function_call */ -/** - * [[Construct]] implementation for Function objects (13.2.2), - * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) and - * externally defined (host) functions (ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION). - * - * @return ecma value - * Returned value must be freed with ecma_free_value - */ -static ecma_value_t -ecma_op_function_construct_ecma_or_external (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_FUNCTION - || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_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. */ - ecma_object_t *obj_p; - if (ecma_is_value_object (prototype_prop_value)) - { - /* 6. */ - 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); - - obj_p = ecma_create_object (prototype_p, 0, ECMA_OBJECT_TYPE_GENERAL); - - ecma_deref_object (prototype_p); - } - - ecma_free_value (prototype_prop_value); - - /* 3. */ - /* - * [[Class]] property of ECMA_OBJECT_TYPE_GENERAL type objects - * without ECMA_INTERNAL_PROPERTY_CLASS internal property - * is "Object". - * - * See also: ecma_object_get_class_name. - */ - - /* 8. */ - ecma_value_t this_obj = ecma_make_object_value (obj_p); - ecma_value_t ret_value; - - if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION) - { - arguments_list_p = ecma_op_function_set_construct_flag (arguments_list_p); - } - - ret_value = ecma_op_function_call (func_obj_p, - this_obj, - arguments_list_p, - arguments_list_len); - - /* 9. */ - if (ECMA_IS_VALUE_ERROR (ret_value) || ecma_is_value_object (ret_value)) - { - ecma_deref_object (obj_p); - return ret_value; - } - - ecma_fast_free_value (ret_value); - return this_obj; -} /* ecma_op_function_construct_ecma_or_external */ - /** * [[Construct]] implementation: * 13.2.2 - for Function objects, created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION), @@ -790,51 +710,19 @@ ecma_op_function_construct_ecma_or_external (ecma_object_t *func_obj_p, /**< Fun */ 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 */ 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)); - while (true) - { - switch (ecma_get_object_type (func_obj_p)) - { - case ECMA_OBJECT_TYPE_FUNCTION: - { - if (JERRY_UNLIKELY (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_builtin_dispatch_construct (func_obj_p, - arguments_list_p, - arguments_list_len); - } - /* FALLTHRU */ - } - case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: - { - return ecma_op_function_construct_ecma_or_external (func_obj_p, - arguments_list_p, - arguments_list_len); - } -#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION - case ECMA_OBJECT_TYPE_ARROW_FUNCTION: - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Arrow functions have no constructor.")); - } -#endif /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ - default: - { - break; - } - } - - JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + JERRY_ASSERT (ecma_is_value_object (this_arg_value) + || this_arg_value == ECMA_VALUE_UNDEFINED); + while (JERRY_UNLIKELY (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION)) + { /* 1-3. */ ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p; @@ -874,6 +762,7 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ /* 5. */ ret_value = ecma_op_function_construct (target_func_obj_p, + this_arg_value, merged_args_list_p, merged_args_list_len); @@ -881,6 +770,109 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ return ret_value; } + + ecma_object_type_t type = ecma_get_object_type (func_obj_p); + +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_ARROW_FUNCTION)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Arrow functions have no constructor.")); + } +#endif /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + + if (JERRY_UNLIKELY (type == ECMA_OBJECT_TYPE_FUNCTION && 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_builtin_dispatch_construct (func_obj_p, + arguments_list_p, + arguments_list_len); + } + + ecma_object_t *new_this_obj_p = NULL; + + if (JERRY_LIKELY (this_arg_value == ECMA_VALUE_UNDEFINED)) + { + /* 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_deref_object (prototype_p); + } + + ecma_free_value (prototype_prop_value); + + this_arg_value = ecma_make_object_value (new_this_obj_p); + } + + /* 8. */ + ecma_value_t ret_value; + + switch (type) + { + case ECMA_OBJECT_TYPE_FUNCTION: + { + arguments_list_p = ecma_op_function_set_construct_flag (arguments_list_p); + + ret_value = ecma_op_function_call (func_obj_p, + this_arg_value, + arguments_list_p, + arguments_list_len); + break; + } + default: + { + JERRY_ASSERT (type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + + ret_value = ecma_op_function_call (func_obj_p, + this_arg_value, + arguments_list_p, + arguments_list_len); + break; + } + } + + /* 9. */ + if (ECMA_IS_VALUE_ERROR (ret_value) || ecma_is_value_object (ret_value)) + { + if (new_this_obj_p != NULL) + { + ecma_deref_object (new_this_obj_p); + } + 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; } /* 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 a047b6ad0f..59d89a83a9 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -59,8 +59,8 @@ 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, const ecma_value_t *arguments_list_p, - ecma_length_t arguments_list_len); +ecma_op_function_construct (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_property_t * ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 815c81ef3a..29d7998f5d 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -494,6 +494,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, stack_top_p, arguments_list_len); }