diff --git a/jerry-core/ecma/base/ecma-alloc.c b/jerry-core/ecma/base/ecma-alloc.c index cdff7c6d3..004c6d880 100644 --- a/jerry-core/ecma/base/ecma-alloc.c +++ b/jerry-core/ecma/base/ecma-alloc.c @@ -131,14 +131,14 @@ ecma_alloc_extended_object (size_t size) /**< size of object */ * Dealloc memory of an extended object */ inline void __attr_always_inline___ -ecma_dealloc_extended_object (ecma_extended_object_t *ext_object_p, /**< property pair to be freed */ +ecma_dealloc_extended_object (ecma_object_t *object_p, /**< extended object */ size_t size) /**< size of object */ { #ifdef JMEM_STATS jmem_stats_free_object_bytes (size); #endif /* JMEM_STATS */ - jmem_heap_free_block (ext_object_p, size); + jmem_heap_free_block (object_p, size); } /* ecma_dealloc_extended_object */ /** diff --git a/jerry-core/ecma/base/ecma-alloc.h b/jerry-core/ecma/base/ecma-alloc.h index 16ebf8316..22d0d066d 100644 --- a/jerry-core/ecma/base/ecma-alloc.h +++ b/jerry-core/ecma/base/ecma-alloc.h @@ -47,7 +47,7 @@ ecma_extended_object_t *ecma_alloc_extended_object (size_t size); /** * Dealloc memory of an extended object */ -void ecma_dealloc_extended_object (ecma_extended_object_t *ext_object_p, size_t size); +void ecma_dealloc_extended_object (ecma_object_t *object_p, size_t size); /** * Allocate memory for ecma-number diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index ad1e3bbcc..1f5bf2a4d 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -348,13 +348,26 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - ext_func_p->u.function.scope_cp); - - ecma_gc_set_object_visited (scope_p); + ecma_gc_set_object_visited (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + ext_func_p->u.function.scope_cp)); } break; } +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + case ECMA_OBJECT_TYPE_ARROW_FUNCTION: + { + ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; + + ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, + arrow_func_p->scope_cp)); + + if (ecma_is_value_object (arrow_func_p->this_binding)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (arrow_func_p->this_binding)); + } + break; + } +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ default: { break; @@ -554,7 +567,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ { ecma_length_t arraybuffer_length = ext_object_p->u.class_prop.u.length; size_t size = sizeof (ecma_extended_object_t) + arraybuffer_length; - ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p, size); + ecma_dealloc_extended_object (object_p, size); return; } @@ -565,7 +578,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ ecma_free_value_if_not_object (ext_object_p->u.class_prop.u.value); ecma_free_values_collection (((ecma_promise_object_t *) object_p)->fulfill_reactions, false); ecma_free_values_collection (((ecma_promise_object_t *) object_p)->reject_reactions, false); - ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p, sizeof (ecma_promise_object_t)); + ecma_dealloc_extended_object (object_p, sizeof (ecma_promise_object_t)); return; } #endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ @@ -576,7 +589,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ } } - ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p, ext_object_size); + ecma_dealloc_extended_object (object_p, ext_object_size); return; } @@ -584,7 +597,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ || object_type == ECMA_OBJECT_TYPE_ARRAY || object_type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) { - ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p, ext_object_size); + ecma_dealloc_extended_object (object_p, ext_object_size); return; } @@ -596,10 +609,25 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ext_func_p->u.function.bytecode_cp)); - ecma_dealloc_extended_object (ext_func_p, sizeof (ecma_extended_object_t)); + ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); return; } +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + if (object_type == ECMA_OBJECT_TYPE_ARROW_FUNCTION) + { + ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; + + ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, + arrow_func_p->bytecode_cp)); + + ecma_free_value_if_not_object (arrow_func_p->this_binding); + + ecma_dealloc_extended_object (object_p, sizeof (ecma_arrow_function_t)); + return; + } +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + if (object_type == ECMA_OBJECT_TYPE_PSEUDO_ARRAY) { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; @@ -621,20 +649,18 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ } size_t formal_params_size = formal_params_number * sizeof (jmem_cpointer_t); - ecma_dealloc_extended_object (ext_object_p, sizeof (ecma_extended_object_t) + formal_params_size); + ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t) + formal_params_size); return; } #ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN case ECMA_PSEUDO_ARRAY_TYPEDARRAY: { - ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p, - sizeof (ecma_extended_object_t)); + ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); return; } case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO: { - ecma_dealloc_extended_object ((ecma_extended_object_t *) object_p, - sizeof (ecma_extended_typedarray_object_t)); + ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_typedarray_object_t)); return; } #endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ @@ -657,7 +683,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ if (!ecma_is_value_integer_number (args_len_or_this)) { ecma_free_value_if_not_object (args_len_or_this); - ecma_dealloc_extended_object (ext_function_p, sizeof (ecma_extended_object_t)); + ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); return; } @@ -670,7 +696,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ } size_t args_size = ((size_t) args_length) * sizeof (ecma_value_t); - ecma_dealloc_extended_object (ext_function_p, sizeof (ecma_extended_object_t) + args_size); + ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t) + args_size); return; } } diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index b5eb5337c..f386b173c 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -574,18 +574,20 @@ typedef enum */ typedef enum { - ECMA_OBJECT_TYPE_GENERAL = 0, /**< all objects that are not String (15.5), - * Function (15.3), Arguments (10.6), Array (15.4) objects */ + ECMA_OBJECT_TYPE_GENERAL = 0, /**< all objects that are not belongs to the sub-types below. */ ECMA_OBJECT_TYPE_CLASS = 1, /**< Objects with class property */ ECMA_OBJECT_TYPE_FUNCTION = 2, /**< Function objects (15.3), created through 13.2 routine */ ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION = 3, /**< External (host) function object */ ECMA_OBJECT_TYPE_ARRAY = 4, /**< Array object (15.4) */ ECMA_OBJECT_TYPE_BOUND_FUNCTION = 5, /**< Function objects (15.3), created through 15.3.4.5 routine */ ECMA_OBJECT_TYPE_PSEUDO_ARRAY = 6, /**< Array-like object, such as Arguments object (10.6) */ +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + ECMA_OBJECT_TYPE_ARROW_FUNCTION = 7, /**< arrow function objects */ +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ /* Types between 13-15 cannot have a built-in flag. See ecma_lexical_environment_type_t. */ - ECMA_OBJECT_TYPE__MAX = ECMA_OBJECT_TYPE_PSEUDO_ARRAY /**< maximum value */ + ECMA_OBJECT_TYPE__MAX /**< maximum value */ } ecma_object_type_t; /** @@ -777,6 +779,21 @@ typedef struct ecma_built_in_props_t built_in; /**< built-in object part */ } ecma_extended_built_in_object_t; +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + +/** + * Description of arrow function objects. + */ +typedef struct +{ + ecma_object_t object; /**< object header */ + ecma_value_t this_binding; /**< value of 'this' binding */ + jmem_cpointer_t scope_cp; /**< function scope */ + jmem_cpointer_t bytecode_cp; /**< function byte code */ +} ecma_arrow_function_t; + +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + /** * Description of ECMA property descriptor * diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 4f4200c1c..22fc27e5e 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -45,7 +45,7 @@ JERRY_STATIC_ASSERT (ECMA_PROPERTY_TYPE_MASK >= ECMA_PROPERTY_TYPE__MAX, /** * The ecma object types must be lower than the container mask. */ -JERRY_STATIC_ASSERT (ECMA_OBJECT_TYPE_MASK >= ECMA_OBJECT_TYPE__MAX, +JERRY_STATIC_ASSERT (ECMA_OBJECT_TYPE_MASK >= ECMA_OBJECT_TYPE__MAX - 1, ecma_object_types_must_be_lower_than_the_container_mask); /** diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 546d540dc..9af402ea0 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -34,6 +34,22 @@ * @{ */ +/** + * Checks whether the type is a normal or arrow function. + * + * @return true - if the type is a normal or arrow function; + * false - otherwise + */ +inline bool __attr_always_inline___ +ecma_is_normal_or_arrow_function (ecma_object_type_t type) +{ +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + return (type == ECMA_OBJECT_TYPE_FUNCTION || type == ECMA_OBJECT_TYPE_ARROW_FUNCTION); +#else /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + return (type == ECMA_OBJECT_TYPE_FUNCTION); +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ +} /* ecma_is_normal_or_arrow_function */ + /** * IsCallable operation. * @@ -55,13 +71,18 @@ ecma_op_is_callable (ecma_value_t value) /**< ecma value */ JERRY_ASSERT (obj_p != NULL); JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); - return (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION - || ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION - || ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); + ecma_object_type_t type = ecma_get_object_type (obj_p); + + return (type == ECMA_OBJECT_TYPE_FUNCTION +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + || type == ECMA_OBJECT_TYPE_ARROW_FUNCTION +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + || type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION + || type == ECMA_OBJECT_TYPE_BOUND_FUNCTION); } /* ecma_op_is_callable */ /** - * Check whether the value is Object that implements [[Construct]]. + * Checks whether the value is Object that implements [[Construct]]. * * @return true - if value is constructor object; * false - otherwise @@ -142,6 +163,42 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ return func_p; } /* ecma_op_create_function_object */ +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + +/** + * Arrow function object creation operation. + * + * See also: ES2015, 9.2.12 + * + * @return pointer to newly created Function object + */ +ecma_object_t * +ecma_op_create_arrow_function_object (ecma_object_t *scope_p, /**< function's scope */ + const ecma_compiled_code_t *bytecode_data_p, /**< byte-code array */ + ecma_value_t this_binding) /**< value of 'this' binding */ +{ + ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + + ecma_object_t *func_p = ecma_create_object (prototype_obj_p, + sizeof (ecma_arrow_function_t), + ECMA_OBJECT_TYPE_ARROW_FUNCTION); + + ecma_deref_object (prototype_obj_p); + + + ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_p; + + ECMA_SET_NON_NULL_POINTER (arrow_func_p->scope_cp, scope_p); + + ECMA_SET_NON_NULL_POINTER (arrow_func_p->bytecode_cp, bytecode_data_p); + ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); + + arrow_func_p->this_binding = ecma_copy_value_if_not_object (this_binding); + return func_p; +} /* ecma_op_create_arrow_function_object */ + +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + /** * External function object creation operation. * @@ -192,57 +249,7 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object * JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p)); - ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); - - if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION - || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION) - { - if (!ecma_is_value_object (value)) - { - return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); - } - - ecma_object_t *v_obj_p = ecma_get_object_from_value (value); - - ecma_string_t *prototype_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); - - ECMA_TRY_CATCH (prototype_obj_value, - ecma_op_object_get (func_obj_p, prototype_magic_string_p), - ret_value); - - if (!ecma_is_value_object (prototype_obj_value)) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Object expected.")); - } - else - { - ecma_object_t *prototype_obj_p = ecma_get_object_from_value (prototype_obj_value); - JERRY_ASSERT (prototype_obj_p != NULL); - - do - { - v_obj_p = ecma_get_object_prototype (v_obj_p); - - if (v_obj_p == NULL) - { - ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); - - break; - } - else if (v_obj_p == prototype_obj_p) - { - ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_TRUE); - - break; - } - } while (true); - } - - ECMA_FINALIZE (prototype_obj_value); - - ecma_deref_ecma_string (prototype_magic_string_p); - } - else + if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION) { JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); @@ -254,10 +261,57 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object * ext_function_p->u.bound_function.target_function); /* 3. */ - ret_value = ecma_op_object_has_instance (target_func_obj_p, value); + return ecma_op_object_has_instance (target_func_obj_p, value); } - return ret_value; + JERRY_ASSERT (ecma_is_normal_or_arrow_function (ecma_get_object_type (func_obj_p)) + || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + + if (!ecma_is_value_object (value)) + { + return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); + } + + ecma_object_t *v_obj_p = ecma_get_object_from_value (value); + + ecma_string_t prototype_magic_string; + ecma_init_ecma_magic_string (&prototype_magic_string, LIT_MAGIC_STRING_PROTOTYPE); + + ecma_value_t prototype_obj_value = ecma_op_object_get (func_obj_p, &prototype_magic_string); + + if (ECMA_IS_VALUE_ERROR (prototype_obj_value)) + { + return prototype_obj_value; + } + + if (!ecma_is_value_object (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); + JERRY_ASSERT (prototype_obj_p != NULL); + + bool result = false; + + while (true) + { + v_obj_p = ecma_get_object_prototype (v_obj_p); + + if (v_obj_p == NULL) + { + break; + } + + if (v_obj_p == prototype_obj_p) + { + result = true; + break; + } + } + + ecma_deref_object (prototype_obj_p); + return ecma_make_boolean_value (result); } /* ecma_op_function_has_instance */ /** @@ -364,6 +418,48 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ ecma_free_value (this_binding); } } +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + else if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_ARROW_FUNCTION) + { + /* Entering Function Code (ES2015, 9.2.1) */ + ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_obj_p; + + ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, + arrow_func_p->scope_cp); + + bool is_no_lex_env; + + const ecma_compiled_code_t *bytecode_data_p; + bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, + arrow_func_p->bytecode_cp); + + is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false; + + ecma_object_t *local_env_p; + if (is_no_lex_env) + { + local_env_p = scope_p; + } + else + { + local_env_p = ecma_create_decl_lex_env (scope_p); + + JERRY_ASSERT (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED)); + } + + ret_value = vm_run (bytecode_data_p, + arrow_func_p->this_binding, + local_env_p, + false, + arguments_list_p, + arguments_list_len); + + if (!is_no_lex_env) + { + ecma_deref_object (local_env_p); + } + } +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ else if (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; diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index 3566ebfd4..3a92c092e 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -26,12 +26,20 @@ * @{ */ +bool ecma_is_normal_or_arrow_function (ecma_object_type_t type); + bool ecma_op_is_callable (ecma_value_t value); bool ecma_is_constructor (ecma_value_t value); ecma_object_t * ecma_op_create_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p); +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION +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); +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + ecma_object_t * ecma_op_create_external_function_object (ecma_external_handler_t handler_cb); diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 335e5d303..818e7e0f5 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -50,13 +50,7 @@ */ #ifndef JERRY_NDEBUG #define JERRY_ASSERT_OBJECT_TYPE_IS_VALID(type) \ - JERRY_ASSERT (type == ECMA_OBJECT_TYPE_GENERAL \ - || type == ECMA_OBJECT_TYPE_CLASS \ - || type == ECMA_OBJECT_TYPE_FUNCTION \ - || type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION \ - || type == ECMA_OBJECT_TYPE_ARRAY \ - || type == ECMA_OBJECT_TYPE_BOUND_FUNCTION \ - || type == ECMA_OBJECT_TYPE_PSEUDO_ARRAY); + JERRY_ASSERT (type < ECMA_OBJECT_TYPE__MAX); #else /* JERRY_NDEBUG */ #define JERRY_ASSERT_OBJECT_TYPE_IS_VALID(type) #endif /* !JERRY_NDEBUG */ @@ -199,18 +193,33 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ { property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p); } - else if (type == ECMA_OBJECT_TYPE_FUNCTION) + else if (ecma_is_normal_or_arrow_function (type)) { if (ecma_string_is_length (property_name_p)) { if (options & ECMA_PROPERTY_GET_VALUE) { /* Get length virtual property. */ - ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - const ecma_compiled_code_t *bytecode_data_p; + +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + if (type != ECMA_OBJECT_TYPE_ARROW_FUNCTION) + { + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, + ext_func_p->u.function.bytecode_cp); + } + else + { + ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; + bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, + arrow_func_p->bytecode_cp); + } +#else /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, ext_func_p->u.function.bytecode_cp); +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ uint32_t len; if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) @@ -510,16 +519,31 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ { property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p); } - else if (type == ECMA_OBJECT_TYPE_FUNCTION) + else if (ecma_is_normal_or_arrow_function (type)) { if (ecma_string_is_length (property_name_p)) { /* Get length virtual property. */ - ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - const ecma_compiled_code_t *bytecode_data_p; + +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + if (type != ECMA_OBJECT_TYPE_ARROW_FUNCTION) + { + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, + ext_func_p->u.function.bytecode_cp); + } + else + { + ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; + bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, + arrow_func_p->bytecode_cp); + } +#else /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, ext_func_p->u.function.bytecode_cp); +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ uint32_t len; if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) @@ -824,7 +848,7 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ { property_p = ecma_builtin_try_to_instantiate_property (object_p, property_name_p); } - else if (type == ECMA_OBJECT_TYPE_FUNCTION) + else if (ecma_is_normal_or_arrow_function (type)) { if (ecma_string_is_length (property_name_p)) { @@ -985,48 +1009,23 @@ ecma_op_object_delete (ecma_object_t *obj_p, /**< the object */ && !ecma_is_lexical_environment (obj_p)); JERRY_ASSERT (property_name_p != NULL); - const ecma_object_type_t type = ecma_get_object_type (obj_p); - - switch (type) + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_PSEUDO_ARRAY) { - case ECMA_OBJECT_TYPE_GENERAL: - case ECMA_OBJECT_TYPE_CLASS: - case ECMA_OBJECT_TYPE_FUNCTION: - case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: - case ECMA_OBJECT_TYPE_ARRAY: - case ECMA_OBJECT_TYPE_BOUND_FUNCTION: - { - return ecma_op_general_object_delete (obj_p, - property_name_p, - is_throw); - } + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; - case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: + if (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS) { - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; - - if (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS) - { - return ecma_op_arguments_object_delete (obj_p, - property_name_p, - is_throw); - } - else - { - return ecma_op_general_object_delete (obj_p, + return ecma_op_arguments_object_delete (obj_p, property_name_p, is_throw); - } - - break; - } - default: - { - JERRY_ASSERT (false); - - return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE); } } + + JERRY_ASSERT_OBJECT_TYPE_IS_VALID (ecma_get_object_type (obj_p)); + + return ecma_op_general_object_delete (obj_p, + property_name_p, + is_throw); } /* ecma_op_object_delete */ /** @@ -1058,6 +1057,7 @@ ecma_op_object_default_value (ecma_object_t *obj_p, /**< the object */ * [ECMA_OBJECT_TYPE_ARRAY] = &ecma_op_general_object_default_value, * [ECMA_OBJECT_TYPE_BOUND_FUNCTION] = &ecma_op_general_object_default_value, * [ECMA_OBJECT_TYPE_PSEUDO_ARRAY] = &ecma_op_general_object_default_value + * [ECMA_OBJECT_TYPE_ARROW_FUNCTION] = &ecma_op_general_object_default_value * }; * * return default_value[type] (obj_p, property_name_p); @@ -1093,6 +1093,9 @@ ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */ case ECMA_OBJECT_TYPE_GENERAL: case ECMA_OBJECT_TYPE_CLASS: case ECMA_OBJECT_TYPE_FUNCTION: +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + case ECMA_OBJECT_TYPE_ARROW_FUNCTION: +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { @@ -1263,29 +1266,16 @@ ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */ const ecma_object_type_t type = ecma_get_object_type (obj_p); - switch (type) + if (ecma_is_normal_or_arrow_function (type) + || type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION + || type == ECMA_OBJECT_TYPE_BOUND_FUNCTION) { - case ECMA_OBJECT_TYPE_GENERAL: - case ECMA_OBJECT_TYPE_CLASS: - case ECMA_OBJECT_TYPE_ARRAY: - case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Expected a function object.")); - } - - case ECMA_OBJECT_TYPE_FUNCTION: - case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: - case ECMA_OBJECT_TYPE_BOUND_FUNCTION: - { - return ecma_op_function_has_instance (obj_p, value); - } - - default: - { - JERRY_UNREACHABLE (); - break; - } + return ecma_op_function_has_instance (obj_p, value); } + + JERRY_ASSERT_OBJECT_TYPE_IS_VALID (type); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Expected a function object.")); } /* ecma_op_object_has_instance */ /** @@ -1387,6 +1377,9 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ break; } case ECMA_OBJECT_TYPE_FUNCTION: +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + case ECMA_OBJECT_TYPE_ARROW_FUNCTION: +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ { ecma_op_function_list_lazy_property_names (obj_p, is_enumerable_only, @@ -1782,6 +1775,9 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ break; } case ECMA_OBJECT_TYPE_FUNCTION: +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + case ECMA_OBJECT_TYPE_ARROW_FUNCTION: +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 0eb3522cf..d9cc702ca 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -654,6 +654,9 @@ typedef enum CBC_CODE_FLAGS_ARGUMENTS_NEEDED = (1u << 4), /**< arguments object must be constructed */ CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 5), /**< no need to create a lexical environment */ CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 6), /**< this function should be ignored by debugger */ +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + CBC_CODE_FLAGS_ARROW_FUNCTION = (1u << 6), /**< this function is an arrow function */ +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ } cbc_code_flags; #define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1, diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 5dc9cacf1..ab9042a21 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1190,6 +1190,13 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code JERRY_DEBUG_MSG (",no_lexical_env"); } +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) + { + JERRY_DEBUG_MSG (",arrow"); + } +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + JERRY_DEBUG_MSG ("]\n"); JERRY_DEBUG_MSG (" Argument range end: %d\n", (int) argument_end); @@ -1666,6 +1673,13 @@ parser_post_processing (parser_context_t *context_p) /**< context */ compiled_code_p->status_flags |= CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED; } +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + if (context_p->status_flags & PARSER_IS_ARROW_FUNCTION) + { + compiled_code_p->status_flags |= CBC_CODE_FLAGS_ARROW_FUNCTION; + } +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + literal_pool_p = (jmem_cpointer_t *) byte_code_p; byte_code_p += context_p->literal_count * sizeof (jmem_cpointer_t); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 0d69ff004..87822c4e3 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -302,8 +302,24 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ if (is_function) { - ecma_object_t *func_obj_p = ecma_op_create_function_object (frame_ctx_p->lex_env_p, - bytecode_p); + ecma_object_t *func_obj_p; + +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION)) + { + func_obj_p = ecma_op_create_function_object (frame_ctx_p->lex_env_p, + bytecode_p); + } + else + { + func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p, + bytecode_p, + frame_ctx_p->this_binding); + } +#else /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + func_obj_p = ecma_op_create_function_object (frame_ctx_p->lex_env_p, + bytecode_p); +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ return ecma_make_object_value (func_obj_p); } diff --git a/tests/jerry/es2015/arrow-this.js b/tests/jerry/es2015/arrow-this.js new file mode 100644 index 000000000..e78f9451f --- /dev/null +++ b/tests/jerry/es2015/arrow-this.js @@ -0,0 +1,40 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var o = { + x: 13, + + f: function() + { + return () => this.x + 1 + }, + + g: function() + { + return function() { + return this.x + 1 + } + } +} + +assert(o.f().call(o) === 14); +assert(o.g().call(o) === 14); + +assert(o.f()() === 14); + +var o2 = { x:4, f:o.f(), g:o.g() } + +assert(o2.f() === 14); +assert(o2.g() === 5);