diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index aef6293350..d3214b8e52 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -161,21 +161,21 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p; #if ENABLED (JERRY_ESNEXT) - if (compiled_code_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS) + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_HAS_TAGGED_LITERALS) { const char * const error_message_p = "Unsupported feature: tagged template literals."; globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p); return 0; } - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR) + if (CBC_FUNCTION_GET_TYPE (compiled_code_p->status_flags) == CBC_FUNCTION_CONSTRUCTOR) { globals_p->class_found = true; } #endif /* ENABLED (JERRY_ESNEXT) */ #if ENABLED (JERRY_BUILTIN_REGEXP) - if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) + if (!CBC_IS_FUNCTION (compiled_code_p->status_flags)) { /* Regular expression. */ if (globals_p->snapshot_buffer_write_offset + sizeof (ecma_compiled_code_t) > snapshot_buffer_size) @@ -228,7 +228,7 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled } #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ - JERRY_ASSERT (compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION); + JERRY_ASSERT (CBC_IS_FUNCTION (compiled_code_p->status_flags)); if (!snapshot_write_to_buffer_by_offset (snapshot_buffer_p, snapshot_buffer_size, @@ -345,7 +345,7 @@ static_snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< c uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset; ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p; - if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) + if (!CBC_IS_FUNCTION (compiled_code_p->status_flags)) { /* Regular expression literals are not supported. */ const char * const error_message_p = "Regular expression literals are not supported."; @@ -454,7 +454,7 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */ ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p; uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; - if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + if (CBC_IS_FUNCTION (bytecode_p->status_flags)) { ecma_value_t *literal_start_p; uint32_t const_literal_end; @@ -549,9 +549,8 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; #if ENABLED (JERRY_BUILTIN_REGEXP) - if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) + if (!CBC_IS_FUNCTION (bytecode_p->status_flags)) { - const uint8_t *regex_start_p = ((const uint8_t *) bytecode_p) + sizeof (ecma_compiled_code_t); /* Real size is stored in refs. */ @@ -564,10 +563,10 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th return (ecma_compiled_code_t *) re_bytecode_p; } +#else /* !ENABLED (JERRY_BUILTIN_REGEXP) */ + JERRY_ASSERT (CBC_IS_FUNCTION (bytecode_p->status_flags)); #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ - JERRY_ASSERT (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION); - size_t header_size; uint32_t argument_end; uint32_t const_literal_end; @@ -620,13 +619,13 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th #if ENABLED (JERRY_ESNEXT) /* function name */ - if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR)) + if (CBC_FUNCTION_GET_TYPE (bytecode_p->status_flags) != CBC_FUNCTION_CONSTRUCTOR) { extra_bytes += (uint32_t) sizeof (ecma_value_t); } /* tagged template literals */ - if (bytecode_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_HAS_TAGGED_LITERALS) { extra_bytes += (uint32_t) sizeof (ecma_value_t); } @@ -1083,7 +1082,7 @@ scan_snapshot_functions (const uint8_t *buffer_p, /**< snapshot buffer start */ const ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p; uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; - if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + if (CBC_IS_FUNCTION (bytecode_p->status_flags) && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) { const ecma_value_t *literal_start_p; @@ -1149,7 +1148,7 @@ update_literal_offsets (uint8_t *buffer_p, /**< [in,out] snapshot buffer start * const ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p; uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; - if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + if (CBC_IS_FUNCTION (bytecode_p->status_flags) && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) { ecma_value_t *literal_start_p; diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index de61fbb538..68eddd9825 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -683,7 +683,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ #if ENABLED (JERRY_ESNEXT) const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_p); - if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) + if (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_ARROW) { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; @@ -1201,7 +1201,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ ext_func_p->u.function.bytecode_cp)); #if ENABLED (JERRY_ESNEXT) - if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) + if (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_ARROW) { ecma_free_value_if_not_object (((ecma_arrow_function_t *) object_p)->this_binding); ecma_free_value_if_not_object (((ecma_arrow_function_t *) object_p)->new_target); diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 667920341a..03a3ce23e5 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -963,8 +963,8 @@ typedef struct uint16_t size; /**< real size >> JMEM_ALIGNMENT_LOG */ uint16_t refs; /**< reference counter for the byte code */ uint16_t status_flags; /**< various status flags: - * CBC_CODE_FLAGS_FUNCTION flag tells whether - * the byte code is function or regular expression. + * CBC_IS_FUNCTION check tells whether the byte code + * is function or regular expression. * If function, the other flags must be CBC_CODE_FLAGS... * If regexp, the other flags must be RE_FLAG... */ } ecma_compiled_code_t; diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index dba8066d2e..4b88e6099d 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -1367,7 +1367,7 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ return; } - if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + if (CBC_IS_FUNCTION (bytecode_p->status_flags)) { ecma_value_t *literal_start_p = NULL; uint32_t literal_end; @@ -1439,7 +1439,7 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ #endif /* ENABLED (JERRY_DEBUGGER) */ #if ENABLED (JERRY_ESNEXT) - if (bytecode_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_HAS_TAGGED_LITERALS) { ecma_collection_t *collection_p = ecma_compiled_code_get_tagged_template_collection (bytecode_p); @@ -1477,7 +1477,7 @@ ecma_collection_t * ecma_compiled_code_get_tagged_template_collection (const ecma_compiled_code_t *bytecode_header_p) /**< compiled code */ { JERRY_ASSERT (bytecode_header_p != NULL); - JERRY_ASSERT (bytecode_header_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS); + JERRY_ASSERT (bytecode_header_p->status_flags & CBC_CODE_FLAGS_HAS_TAGGED_LITERALS); ecma_value_t *base_p = ecma_compiled_code_resolve_function_name (bytecode_header_p); @@ -1539,7 +1539,7 @@ ecma_compiled_code_resolve_function_name (const ecma_compiled_code_t *bytecode_h ecma_value_t *base_p = ecma_compiled_code_resolve_arguments_start (bytecode_header_p); #if ENABLED (JERRY_ESNEXT) - if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR)) + if (CBC_FUNCTION_GET_TYPE (bytecode_header_p->status_flags) != CBC_FUNCTION_CONSTRUCTOR) { base_p--; } diff --git a/jerry-core/ecma/base/ecma-literal-storage.c b/jerry-core/ecma/base/ecma-literal-storage.c index 0f761d7623..3173e0cf18 100644 --- a/jerry-core/ecma/base/ecma-literal-storage.c +++ b/jerry-core/ecma/base/ecma-literal-storage.c @@ -334,7 +334,7 @@ ecma_save_literals_add_compiled_code (const ecma_compiled_code_t *compiled_code_ uint32_t const_literal_end; uint32_t literal_end; - JERRY_ASSERT (compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION); + JERRY_ASSERT (CBC_IS_FUNCTION (compiled_code_p->status_flags)); if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { @@ -377,7 +377,7 @@ ecma_save_literals_add_compiled_code (const ecma_compiled_code_t *compiled_code_ ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, literal_p[i]); - if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + if (CBC_IS_FUNCTION (bytecode_p->status_flags) && bytecode_p != compiled_code_p) { ecma_save_literals_add_compiled_code (bytecode_p, lit_pool_p); @@ -570,7 +570,7 @@ ecma_snapshot_resolve_serializable_values (ecma_compiled_code_t *compiled_code_p #if ENABLED (JERRY_ESNEXT) /* function name */ - if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR)) + if (CBC_FUNCTION_GET_TYPE (compiled_code_p->status_flags) != CBC_FUNCTION_CONSTRUCTOR) { base_p--; } diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index c4961e6718..f0dc3663b9 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -602,9 +602,9 @@ ecma_op_function_is_generator (ecma_object_t *obj_p) /**< object */ && !ecma_get_object_is_builtin (obj_p)) { 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); + const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_obj_p); - return (bytecode_data_p->status_flags & CBC_CODE_FLAGS_GENERATOR) != 0; + return CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_GENERATOR; } return false; @@ -844,18 +844,12 @@ 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_ESNEXT) - 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_CLASS_CONSTRUCTOR)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); - } + uint16_t function_type = CBC_FUNCTION_GET_TYPE (status_flags); - if ((status_flags & CBC_CODE_FLAGS_GENERATOR) && is_construct_call) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Generator functions cannot be invoked with 'new'.")); - } + if (JERRY_UNLIKELY (function_type == CBC_FUNCTION_CONSTRUCTOR) + && JERRY_CONTEXT (current_new_target) == NULL) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'.")); } #endif /* ENABLED (JERRY_ESNEXT) */ @@ -863,7 +857,7 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ #if ENABLED (JERRY_ESNEXT) ecma_object_t *old_function_object_p = JERRY_CONTEXT (current_function_obj_p); - if (JERRY_UNLIKELY (status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION)) + if (JERRY_UNLIKELY (function_type == CBC_FUNCTION_ARROW)) { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) func_obj_p; @@ -921,7 +915,7 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ } #if ENABLED (JERRY_ESNEXT) // ECMAScript v6, 9.2.2.8 - if (JERRY_UNLIKELY (status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR)) + if (JERRY_UNLIKELY (function_type == CBC_FUNCTION_CONSTRUCTOR)) { ecma_value_t lexical_this; lexical_this = (ECMA_GET_THIRD_BIT_FROM_POINTER_TAG (ext_func_p->u.function.scope_cp) ? ECMA_VALUE_UNINITIALIZED @@ -1279,20 +1273,39 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ ecma_object_t *new_this_obj_p = NULL; ecma_value_t this_arg; + +#if ENABLED (JERRY_ESNEXT) 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 (byte_code_p->status_flags & (CBC_CODE_FLAGS_ARROW_FUNCTION | CBC_CODE_FLAGS_ACCESSOR)) + if (!CBC_FUNCTION_IS_CONSTRUCTABLE (byte_code_p->status_flags)) { - if (byte_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) + const char *message_p; + + switch (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags)) { - return ecma_raise_type_error (ECMA_ERR_MSG ("Arrow functions have no constructor.")); + case CBC_FUNCTION_GENERATOR: + { + message_p = ECMA_ERR_MSG ("Generator functions cannot be invoked with 'new'."); + break; + } + case CBC_FUNCTION_ARROW: + { + message_p = ECMA_ERR_MSG ("Arrow functions cannot be invoked with 'new'."); + break; + } + default: + { + JERRY_ASSERT (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_ACCESSOR); + + message_p = ECMA_ERR_MSG ("Accessor functions cannot be invoked with 'new'."); + break; + } } - return ecma_raise_type_error (ECMA_ERR_MSG ("Expected a constructor.")); + return ecma_raise_type_error (message_p); } -#if ENABLED (JERRY_ESNEXT) /* 6. */ ecma_object_t *old_new_target_p = JERRY_CONTEXT (current_new_target); JERRY_CONTEXT (current_new_target) = new_target_p; @@ -1367,17 +1380,18 @@ ecma_op_lazy_instantiate_prototype_object (ecma_object_t *object_p) /**< the fun { const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p); - if (byte_code_p->status_flags & CBC_CODE_FLAGS_GENERATOR) + if (!CBC_FUNCTION_HAS_PROTOTYPE (byte_code_p->status_flags)) + { + return NULL; + } + + if (CBC_FUNCTION_GET_TYPE (byte_code_p->status_flags) == CBC_FUNCTION_GENERATOR) { proto_object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE), 0, ECMA_OBJECT_TYPE_GENERAL); init_constructor = false; } - else if (byte_code_p->status_flags & (CBC_CODE_FLAGS_ARROW_FUNCTION | CBC_CODE_FLAGS_ACCESSOR)) - { - return NULL; - } } #endif /* ENABLED (JERRY_ESNEXT) */ @@ -1475,7 +1489,7 @@ ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< ECMA_SET_SECOND_BIT_TO_POINTER_TAG (ext_func_p->u.function.scope_cp); const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); - if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR)) + if (CBC_FUNCTION_GET_TYPE (bytecode_data_p->status_flags) != CBC_FUNCTION_CONSTRUCTOR) { ecma_value_t value = *ecma_compiled_code_resolve_function_name (bytecode_data_p); if (value != ECMA_VALUE_EMPTY) @@ -1695,7 +1709,7 @@ ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, /**< functio bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p); #if ENABLED (JERRY_ESNEXT) - if (bytecode_data_p->status_flags & (CBC_CODE_FLAGS_ARROW_FUNCTION | CBC_CODE_FLAGS_ACCESSOR)) + if (!CBC_FUNCTION_HAS_PROTOTYPE (bytecode_data_p->status_flags)) { return; } diff --git a/jerry-core/ecma/operations/ecma-regexp-object.h b/jerry-core/ecma/operations/ecma-regexp-object.h index 4cdd20ebf4..fdb33b202a 100644 --- a/jerry-core/ecma/operations/ecma-regexp-object.h +++ b/jerry-core/ecma/operations/ecma-regexp-object.h @@ -41,6 +41,8 @@ typedef enum RE_FLAG_MULTILINE = (1u << 3), /**< ECMA-262 v5, 15.10.7.4 */ RE_FLAG_STICKY = (1u << 4), /**< ECMA-262 v6, 21.2.5.12 */ RE_FLAG_UNICODE = (1u << 5) /**< ECMA-262 v6, 21.2.5.15 */ + + /* Bits from bit 13 is reserved for function types (see CBC_FUNCTION_TYPE_SHIFT). */ } ecma_regexp_flags_t; /** diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 586ccd5e62..c854bd9528 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -814,23 +814,75 @@ typedef struct */ typedef enum { - CBC_CODE_FLAGS_FUNCTION = (1u << 0), /**< compiled code is JavaScript function */ - CBC_CODE_FLAGS_FULL_LITERAL_ENCODING = (1u << 1), /**< full literal encoding mode is enabled */ - CBC_CODE_FLAGS_UINT16_ARGUMENTS = (1u << 2), /**< compiled code data is cbc_uint16_arguments_t */ - CBC_CODE_FLAGS_STRICT_MODE = (1u << 3), /**< strict mode is enabled */ - CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED = (1u << 4), /**< mapped arguments object must be constructed */ - CBC_CODE_FLAGS_UNMAPPED_ARGUMENTS_NEEDED = (1u << 5), /**< mapped arguments object must be constructed */ - CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 6), /**< no need to create a lexical environment */ - 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_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 */ - CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED = (1u << 14), /**< compiled code needs a lexical block */ - CBC_CODE_FLAGS_ACCESSOR = (1u << 15) /**< accessor propety 'get' and 'set' functions */ -} cbc_code_flags; + CBC_CODE_FLAGS_FULL_LITERAL_ENCODING = (1u << 0), /**< full literal encoding mode is enabled */ + CBC_CODE_FLAGS_UINT16_ARGUMENTS = (1u << 1), /**< compiled code data is cbc_uint16_arguments_t */ + CBC_CODE_FLAGS_STRICT_MODE = (1u << 2), /**< strict mode is enabled */ + CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED = (1u << 3), /**< mapped arguments object must be constructed */ + CBC_CODE_FLAGS_UNMAPPED_ARGUMENTS_NEEDED = (1u << 4), /**< mapped arguments object must be constructed */ + CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 5), /**< no need to create a lexical environment */ + CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 6), /**< this function is a static snapshot function */ + CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 7), /**< this function should be ignored by debugger */ + CBC_CODE_FLAGS_REST_PARAMETER = (1u << 8), /**< this function has rest parameter */ + CBC_CODE_FLAGS_HAS_TAGGED_LITERALS = (1u << 9), /**< this function has tagged template literal list */ + CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED = (1u << 10), /**< compiled code needs a lexical block */ + + /* Bits from bit 13 is reserved for function types (see CBC_FUNCTION_TYPE_SHIFT). + * Note: the last bits are used for type flags because < and >= operators can be used to + check a range of types without decoding the actual type. */ +} cbc_code_flags_t; + +/** + * Compact byte code function types. + */ +typedef enum +{ + /* The first type must be regular expression (see CBC_IS_FUNCTION) */ + CBC_REGULAR_EXPRESSION, /**< regular expression literal */ + CBC_FUNCTION_NORMAL, /**< function without special properties */ + CBC_FUNCTION_CONSTRUCTOR, /**< constructor function */ + + /* The following functions cannot be constructed (see CBC_FUNCTION_IS_CONSTRUCTABLE) */ + CBC_FUNCTION_GENERATOR, /**< generator function */ + + /* The following functions has no prototype (see CBC_FUNCTION_HAS_PROTOTYPE) */ + CBC_FUNCTION_ARROW, /**< arrow function */ + CBC_FUNCTION_ACCESSOR, /**< property accessor function */ +} cbc_code_function_types_t; + +/** + * Shift for getting / setting the function type of a byte code. + */ +#define CBC_FUNCTION_TYPE_SHIFT 13 + +/** + * Compute function type bits in code flags. + */ +#define CBC_FUNCTION_TO_TYPE_BITS(name) \ + ((name) << CBC_FUNCTION_TYPE_SHIFT) + +/** + * Get function type from code flags. + */ +#define CBC_FUNCTION_GET_TYPE(flags) \ + ((uint16_t) ((flags) >> CBC_FUNCTION_TYPE_SHIFT)) + +/** + * Checks whether the byte code is a function or a regular expression. + */ +#define CBC_IS_FUNCTION(flags) \ + ((flags) >= (CBC_FUNCTION_NORMAL << CBC_FUNCTION_TYPE_SHIFT)) + +/** + * Checks whether the function can be constructed with new operator. + */ +#define CBC_FUNCTION_IS_CONSTRUCTABLE(flags) \ + ((flags) < (CBC_FUNCTION_GENERATOR << CBC_FUNCTION_TYPE_SHIFT)) + +/** + * Checks whether the function has prototype property. + */ +#define CBC_FUNCTION_HAS_PROTOTYPE(flags) \ + ((flags) < (CBC_FUNCTION_ARROW << CBC_FUNCTION_TYPE_SHIFT)) /** * Any arguments object is needed diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 254ee355e9..67e07695c3 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -675,19 +675,28 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code } #if ENABLED (JERRY_ESNEXT) - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) + switch (CBC_FUNCTION_GET_TYPE (compiled_code_p->status_flags)) { - JERRY_DEBUG_MSG (",arrow"); - } - - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR) - { - JERRY_DEBUG_MSG (",constructor"); - } - - if (compiled_code_p->status_flags & CBC_CODE_FLAGS_GENERATOR) - { - JERRY_DEBUG_MSG (",generator"); + case CBC_FUNCTION_CONSTRUCTOR: + { + JERRY_DEBUG_MSG (",constructor"); + break; + } + case CBC_FUNCTION_GENERATOR: + { + JERRY_DEBUG_MSG (",generator"); + break; + } + case CBC_FUNCTION_ARROW: + { + JERRY_DEBUG_MSG (",arrow"); + break; + } + case CBC_FUNCTION_ACCESSOR: + { + JERRY_DEBUG_MSG (",accessor"); + break; + } } #endif /* ENABLED (JERRY_ESNEXT) */ @@ -1238,7 +1247,12 @@ parser_post_processing (parser_context_t *context_p) /**< context */ byte_code_p = (uint8_t *) compiled_code_p; compiled_code_p->size = (uint16_t) (total_size >> JMEM_ALIGNMENT_LOG); compiled_code_p->refs = 1; - compiled_code_p->status_flags = CBC_CODE_FLAGS_FUNCTION; + +#if ENABLED (JERRY_ESNEXT) + compiled_code_p->status_flags = 0; +#else /* !ENABLED (JERRY_ESNEXT) */ + compiled_code_p->status_flags = CBC_FUNCTION_TO_TYPE_BITS (CBC_FUNCTION_NORMAL); +#endif /* ENABLED (JERRY_ESNEXT) */ #if ENABLED (JERRY_ESNEXT) if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) @@ -1319,22 +1333,23 @@ parser_post_processing (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_ESNEXT) if (context_p->status_flags & (PARSER_IS_PROPERTY_GETTER | PARSER_IS_PROPERTY_SETTER)) { - compiled_code_p->status_flags |= CBC_CODE_FLAGS_ACCESSOR; + compiled_code_p->status_flags |= CBC_FUNCTION_TO_TYPE_BITS (CBC_FUNCTION_ACCESSOR); } - - if (context_p->status_flags & PARSER_IS_ARROW_FUNCTION) + else if (context_p->status_flags & PARSER_IS_ARROW_FUNCTION) { - compiled_code_p->status_flags |= CBC_CODE_FLAGS_ARROW_FUNCTION; + compiled_code_p->status_flags |= CBC_FUNCTION_TO_TYPE_BITS (CBC_FUNCTION_ARROW); } - - if (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR) + else if (context_p->status_flags & PARSER_CLASS_CONSTRUCTOR) { - compiled_code_p->status_flags |= CBC_CODE_FLAGS_CLASS_CONSTRUCTOR; + compiled_code_p->status_flags |= CBC_FUNCTION_TO_TYPE_BITS (CBC_FUNCTION_CONSTRUCTOR); } - - if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) + else if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) + { + compiled_code_p->status_flags |= CBC_FUNCTION_TO_TYPE_BITS (CBC_FUNCTION_GENERATOR); + } + else { - compiled_code_p->status_flags |= CBC_CODE_FLAGS_GENERATOR; + compiled_code_p->status_flags |= CBC_FUNCTION_TO_TYPE_BITS (CBC_FUNCTION_NORMAL); } if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM) @@ -1344,7 +1359,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ if (context_p->tagged_template_literal_cp != JMEM_CP_NULL) { - compiled_code_p->status_flags |= CBC_CODE_FLAG_HAS_TAGGED_LITERALS; + compiled_code_p->status_flags |= CBC_CODE_FLAGS_HAS_TAGGED_LITERALS; } if (context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED) diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 5f365db827..75e313a4f7 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -456,7 +456,7 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ #if ENABLED (JERRY_BUILTIN_REGEXP) - if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) + if (JERRY_UNLIKELY (!CBC_IS_FUNCTION (bytecode_p->status_flags))) { ecma_object_t *regexp_obj_p = ecma_op_regexp_alloc (NULL); @@ -465,30 +465,36 @@ vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ return ECMA_VALUE_ERROR; } - return ecma_op_create_regexp_from_bytecode (regexp_obj_p, (re_compiled_code_t *) bytecode_p);; + return ecma_op_create_regexp_from_bytecode (regexp_obj_p, (re_compiled_code_t *) bytecode_p); } +#else /* !ENABLED (JERRY_BUILTIN_REGEXP) */ + JERRY_ASSERT (CBC_IS_FUNCTION (bytecode_p->status_flags)); #endif /* ENABLED (JERRY_BUILTIN_REGEXP) */ - JERRY_ASSERT (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION); - ecma_object_t *func_obj_p; #if ENABLED (JERRY_ESNEXT) - if (bytecode_p->status_flags & CBC_CODE_FLAGS_ARROW_FUNCTION) - { - func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p, - bytecode_p, - frame_ctx_p->this_binding); - } - else if (bytecode_p->status_flags & CBC_CODE_FLAGS_GENERATOR) - { - func_obj_p = ecma_op_create_generator_function_object (frame_ctx_p->lex_env_p, bytecode_p); - } - else + switch (CBC_FUNCTION_GET_TYPE (bytecode_p->status_flags)) { + case CBC_FUNCTION_GENERATOR: + { + func_obj_p = ecma_op_create_generator_function_object (frame_ctx_p->lex_env_p, bytecode_p); + break; + } + case CBC_FUNCTION_ARROW: + { + func_obj_p = ecma_op_create_arrow_function_object (frame_ctx_p->lex_env_p, + bytecode_p, + frame_ctx_p->this_binding); + break; + } + default: + { #endif /* ENABLED (JERRY_ESNEXT) */ - func_obj_p = ecma_op_create_simple_function_object (frame_ctx_p->lex_env_p, bytecode_p); + func_obj_p = ecma_op_create_simple_function_object (frame_ctx_p->lex_env_p, bytecode_p); #if ENABLED (JERRY_ESNEXT) + break; + } } #endif /* ENABLED (JERRY_ESNEXT) */