diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 6d04896cd..f07735d27 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -861,9 +861,10 @@ jerry_module_get_namespace (const jerry_value_t module_val) /**< module */ if (module_p->namespace_object_p == NULL) { - if (module_p->header.u.cls.u1.module_state != JERRY_MODULE_STATE_EVALUATED) + if (module_p->header.u.cls.u1.module_state < JERRY_MODULE_STATE_LINKED + || module_p->header.u.cls.u1.module_state > JERRY_MODULE_STATE_EVALUATED) { - return jerry_throw (ecma_raise_range_error (ECMA_ERR_MSG ("Namespace object has not been created yet"))); + return jerry_throw (ecma_raise_range_error (ECMA_ERR_MSG ("Namespace object cannot be created"))); } ecma_module_create_namespace_object (module_p); @@ -1264,6 +1265,9 @@ static const uint8_t jerry_class_object_type[] = #if JERRY_BUILTIN_TYPEDARRAY JERRY_OBJECT_TYPE_TYPEDARRAY, /**< type of ECMA_OBJECT_CLASS_TYPEDARRAY */ #endif /* JERRY_BUILTIN_TYPEDARRAY */ +#if JERRY_MODULE_SYSTEM + JERRY_OBJECT_TYPE_GENERIC, /**< type of ECMA_OBJECT_CLASS_MODULE_NAMESPACE */ +#endif /* These objects are marked by Garbage Collector. */ #if JERRY_ESNEXT @@ -5130,9 +5134,7 @@ jerry_realm_set_this (jerry_value_t realm_value, /**< realm value */ ecma_global_object_t *global_object_p = (ecma_global_object_t *) object_p; global_object_p->this_binding = this_value; - ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL, - ecma_get_object_from_value (this_value), - ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); + ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL, ecma_get_object_from_value (this_value)); ECMA_SET_NON_NULL_POINTER (global_object_p->global_env_cp, global_lex_env_p); #if JERRY_ESNEXT diff --git a/jerry-core/ecma/base/ecma-errors.c b/jerry-core/ecma/base/ecma-errors.c index 1471a81da..1426b9b4a 100644 --- a/jerry-core/ecma/base/ecma-errors.c +++ b/jerry-core/ecma/base/ecma-errors.c @@ -138,12 +138,22 @@ const char * const ecma_error_local_variable_is_redeclared = "Local variable is */ const char * const ecma_error_expected_a_function = "Expected a function"; +#if JERRY_ESNEXT + /** * Error message, class constructor invoked without new keyword */ const char * const ecma_error_class_constructor_new = "Class constructor cannot be invoked without 'new'"; -#endif /* JERRY_ERROR_MESSAGES */ +/** + * Error message, variables declared by let/const must be initialized before reading their value + */ +const char * const ecma_error_let_const_not_initialized = ("Variables declared by let/const must be" + " initialized before reading their value"); + +#endif /* JERRY_ESNEXT */ + +#endif /* JERRY_ERROR_MESSAGES */ #if JERRY_SNAPSHOT_SAVE || JERRY_SNAPSHOT_EXEC diff --git a/jerry-core/ecma/base/ecma-errors.h b/jerry-core/ecma/base/ecma-errors.h index 9a9077238..ddcfc0047 100644 --- a/jerry-core/ecma/base/ecma-errors.h +++ b/jerry-core/ecma/base/ecma-errors.h @@ -18,6 +18,8 @@ #ifndef ECMA_ERRORS_H #define ECMA_ERRORS_H +#if JERRY_ERROR_MESSAGES + extern const char * const ecma_error_value_msg_p; extern const char * const ecma_error_wrong_args_msg_p; @@ -65,7 +67,13 @@ extern const char * const ecma_error_argument_is_not_an_regexp; extern const char * const ecma_error_invalid_array_length; extern const char * const ecma_error_local_variable_is_redeclared; extern const char * const ecma_error_expected_a_function; + +#if JERRY_ESNEXT extern const char * const ecma_error_class_constructor_new; +extern const char * const ecma_error_let_const_not_initialized; +#endif /* JERRY_ESNEXT */ + +#endif /* JERRY_ERROR_MESSAGES */ /* snapshot errors */ extern const char * const ecma_error_maximum_snapshot_size; diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index f6fced9ce..fb1422e79 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -293,6 +293,55 @@ ecma_gc_mark_properties (ecma_property_pair_t *property_pair_p) /**< property pa } } /* ecma_gc_mark_properties */ +#if JERRY_MODULE_SYSTEM + +/** + * Mark objects with references (e.g. namespace objects) + */ +static void +ecma_gc_mark_properties_with_references (ecma_object_t *object_p) /**< object */ +{ + jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp; + +#if 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 = object_p->u1.property_list_cp; + } + } +#endif /* 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)); + + for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) + { + ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); + + if (ECMA_PROPERTY_IS_RAW (*property_p) + && (*property_p & ECMA_PROPERTY_FLAG_DATA)) + { + ecma_value_t value = ((ecma_property_pair_t *) prop_iter_p)->values[i].value; + + if (ecma_is_value_object (value)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (value)); + } + } + } + + prop_iter_cp = prop_iter_p->next_property_cp; + } +} /* ecma_gc_mark_properties_with_references */ + +#endif /* JERRY_MODULE_SYSTEM */ + /** * Mark objects referenced by bound function object. */ @@ -659,11 +708,32 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, outer_lex_env_cp)); } - if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + switch (ecma_get_lex_env_type (object_p)) { - ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); - ecma_gc_set_object_visited (binding_object_p); - return; +#if JERRY_ESNEXT + case ECMA_LEXICAL_ENVIRONMENT_CLASS: + { +#if JERRY_MODULE_SYSTEM + if (object_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA) + { + ecma_gc_mark_properties_with_references (object_p); + ecma_gc_set_object_visited (((ecma_lexical_environment_class_t *) object_p)->module_p); + return; + } +#endif /* JERRY_MODULE_SYSTEM */ + /* FALLTHRU */ + } +#endif /* JERRY_ESNEXT */ + case ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND: + { + ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); + ecma_gc_set_object_visited (binding_object_p); + return; + } + default: + { + break; + } } } else @@ -733,10 +803,32 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ break; } #endif /* JERRY_BUILTIN_TYPEDARRAY */ +#if JERRY_MODULE_SYSTEM + case ECMA_OBJECT_CLASS_MODULE_NAMESPACE: + { + JERRY_ASSERT (proto_cp == JMEM_CP_NULL); + ecma_gc_set_object_visited (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, + ext_object_p->u.cls.u3.value)); + ecma_gc_mark_properties_with_references (object_p); + return; + } +#endif /* JERRY_MODULE_SYSTEM */ #if JERRY_MODULE_SYSTEM case ECMA_OBJECT_CLASS_MODULE: { - ecma_module_node_t *node_p = ((ecma_module_t *) ext_object_p)->imports_p; + ecma_module_t *module_p = ((ecma_module_t *) ext_object_p); + + if (module_p->scope_p != NULL) + { + ecma_gc_set_object_visited (((ecma_module_t *) ext_object_p)->scope_p); + } + + if (module_p->namespace_object_p != NULL) + { + ecma_gc_set_object_visited (((ecma_module_t *) ext_object_p)->namespace_object_p); + } + + ecma_module_node_t *node_p = module_p->imports_p; while (node_p != NULL) { @@ -1083,21 +1175,16 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ * Free the native handle/pointer by calling its free callback. */ static void -ecma_gc_free_native_pointer (ecma_property_t *property_p) /**< property */ +ecma_gc_free_native_pointer (ecma_value_t value) /**< property value */ { - JERRY_ASSERT (property_p != NULL); - - ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p); - - if (value_p->value == JMEM_CP_NULL) + if (value == JMEM_CP_NULL) { return; } ecma_native_pointer_t *native_pointer_p; - native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, - value_p->value); + native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, value); JERRY_ASSERT (native_pointer_p != NULL); do @@ -1317,11 +1404,132 @@ ecma_gc_free_executable_object (ecma_object_t *object_p) /**< object */ #endif /* JERRY_ESNEXT */ +JERRY_STATIC_ASSERT (!ECMA_PROPERTY_IS_RAW (ECMA_PROPERTY_TYPE_DELETED), + ecma_property_type_deleted_must_not_be_raw_property); +JERRY_STATIC_ASSERT ((ECMA_PROPERTY_TYPE_DELETED & ECMA_PROPERTY_FLAG_LCACHED) == 0, + ecma_property_type_deleted_must_not_have_lcached_flag); +JERRY_STATIC_ASSERT (ECMA_GC_FREE_SECOND_PROPERTY == 1, + ecma_gc_free_second_must_be_one); + +/** + * Free property of an object + */ +void +ecma_gc_free_property (ecma_object_t *object_p, /**< object */ + ecma_property_pair_t *prop_pair_p, /**< property pair */ + uint32_t options) /**< option bits including property index */ +{ + /* Both cannot be deleted. */ + JERRY_ASSERT (prop_pair_p->header.types[0] != ECMA_PROPERTY_TYPE_DELETED + || prop_pair_p->header.types[1] != ECMA_PROPERTY_TYPE_DELETED); + JERRY_ASSERT (prop_pair_p->header.types[0] != ECMA_PROPERTY_TYPE_HASHMAP); + + uint32_t index = (options & ECMA_GC_FREE_SECOND_PROPERTY); + jmem_cpointer_t name_cp = prop_pair_p->names_cp[index]; + ecma_property_t *property_p = prop_pair_p->header.types + index; + ecma_property_t property = *property_p; + +#if JERRY_LCACHE + if ((property & ECMA_PROPERTY_FLAG_LCACHED) != 0) + { + ecma_lcache_invalidate (object_p, name_cp, property_p); + } +#endif /* JERRY_LCACHE */ + + if (ECMA_PROPERTY_IS_RAW (property)) + { + if (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_PTR) + { + ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp); + ecma_deref_ecma_string (prop_name_p); + } + + if (property & ECMA_PROPERTY_FLAG_DATA) + { + ecma_free_value_if_not_object (prop_pair_p->values[index].value); + return; + } + + if (JERRY_UNLIKELY (options & ECMA_GC_FREE_REFERENCES)) + { + return; + } + +#if JERRY_CPOINTER_32_BIT + ecma_getter_setter_pointers_t *getter_setter_pair_p; + getter_setter_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_getter_setter_pointers_t, + prop_pair_p->values[index].getter_setter_pair_cp); + jmem_pools_free (getter_setter_pair_p, sizeof (ecma_getter_setter_pointers_t)); +#endif /* JERRY_CPOINTER_32_BIT */ + return; + } + + if (property == ECMA_PROPERTY_TYPE_DELETED) + { + return; + } + + ecma_value_t value = prop_pair_p->values[index].value; + + switch (name_cp) + { +#if JERRY_ESNEXT + case LIT_INTERNAL_MAGIC_STRING_ENVIRONMENT_RECORD: + { + ecma_environment_record_t *environment_record_p; + environment_record_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_environment_record_t, value); + jmem_heap_free_block (environment_record_p, sizeof (ecma_environment_record_t)); + break; + } + case LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED: + { + ecma_value_t *compact_collection_p; + compact_collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t, value); + ecma_compact_collection_free (compact_collection_p); + break; + } +#endif /* JERRY_ESNEXT */ +#if JERRY_BUILTIN_WEAKMAP || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKREF + case LIT_INTERNAL_MAGIC_STRING_WEAK_REFS: + { + ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, value); + for (uint32_t j = 0; j < refs_p->item_count; j++) + { + const ecma_value_t reference_value = refs_p->buffer_p[j]; + + if (!ecma_is_value_empty (reference_value)) + { + ecma_object_t *obj_p = ecma_get_object_from_value (reference_value); + + if (ecma_object_class_is (obj_p, ECMA_OBJECT_CLASS_WEAKREF)) + { + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; + ext_obj_p->u.cls.u3.target = ECMA_VALUE_UNDEFINED; + continue; + } + ecma_op_container_remove_weak_entry (obj_p, ecma_make_object_value (object_p)); + } + } + + ecma_collection_destroy (refs_p); + break; + } +#endif /* JERRY_BUILTIN_WEAKMAP || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKREF */ + default: + { + JERRY_ASSERT (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); + ecma_gc_free_native_pointer (value); + break; + } + } +} /* ecma_gc_free_property */ + /** * Free properties of an object */ void -ecma_gc_free_properties (ecma_object_t *object_p) /**< object */ +ecma_gc_free_properties (ecma_object_t *object_p, /**< object */ + uint32_t options) /**< option bits */ { jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp; @@ -1343,89 +1551,11 @@ ecma_gc_free_properties (ecma_object_t *object_p) /**< object */ 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)); - /* Both cannot be deleted. */ - JERRY_ASSERT (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED - || prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED); - ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; - for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) + for (uint32_t i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { - ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); - jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; - - if (*property_p == ECMA_PROPERTY_TYPE_DELETED) - { - continue; - } - - if (!ECMA_PROPERTY_IS_INTERNAL (*property_p)) - { - ecma_free_property (object_p, name_cp, property_p); - continue; - } - - /* Call the native's free callback. */ - switch (name_cp) - { -#if JERRY_ESNEXT - case LIT_INTERNAL_MAGIC_STRING_ENVIRONMENT_RECORD: - { - ecma_environment_record_t *environment_record_p; - environment_record_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_environment_record_t, - prop_pair_p->values[i].value); - jmem_heap_free_block (environment_record_p, sizeof (ecma_environment_record_t)); - break; - } - case LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED: - { - ecma_value_t *compact_collection_p; - compact_collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t, - prop_pair_p->values[i].value); - ecma_compact_collection_free (compact_collection_p); - break; - } -#endif /* JERRY_ESNEXT */ -#if JERRY_BUILTIN_WEAKMAP || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKREF - case LIT_INTERNAL_MAGIC_STRING_WEAK_REFS: - { - ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, - prop_pair_p->values[i].value); - for (uint32_t j = 0; j < refs_p->item_count; j++) - { - const ecma_value_t value = refs_p->buffer_p[j]; - if (!ecma_is_value_empty (value)) - { - ecma_object_t *obj_p = ecma_get_object_from_value (value); - - if (ecma_object_class_is (obj_p, ECMA_OBJECT_CLASS_WEAKREF)) - { - ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; - ext_obj_p->u.cls.u3.target = ECMA_VALUE_UNDEFINED; - continue; - } - ecma_op_container_remove_weak_entry (obj_p, ecma_make_object_value (object_p)); - } - } - - ecma_collection_destroy (refs_p); - break; - } -#endif /* JERRY_BUILTIN_WEAKMAP || JERRY_BUILTIN_WEAKSET || JERRY_BUILTIN_WEAKREF */ - default: - { - JERRY_ASSERT (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); - ecma_gc_free_native_pointer (property_p); - break; - } - } - -#if JERRY_LCACHE - if (ecma_is_property_lcached (property_p)) - { - ecma_lcache_invalidate (object_p, name_cp, property_p); - } -#endif /* JERRY_LCACHE */ + ecma_gc_free_property (object_p, prop_pair_p, i | options); } prop_iter_cp = prop_iter_p->next_property_cp; @@ -1447,9 +1577,19 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ if (ecma_is_lexical_environment (object_p)) { +#if JERRY_MODULE_SYSTEM + if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_CLASS + && (object_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA)) + { + ecma_gc_free_properties (object_p, ECMA_GC_FREE_REFERENCES); + ecma_dealloc_extended_object (object_p, sizeof (ecma_lexical_environment_class_t)); + return; + } +#endif /* JERRY_MODULE_SYSTEM */ + if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { - ecma_gc_free_properties (object_p); + ecma_gc_free_properties (object_p, ECMA_GC_FREE_NO_OPTIONS); } ecma_dealloc_object (object_p); @@ -1538,9 +1678,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ ext_object_size += sizeof (uint64_t) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT); } - ecma_gc_free_properties (object_p); - ecma_dealloc_extended_object (object_p, ext_object_size); - return; + goto free_properties; } } @@ -1548,7 +1686,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ { case ECMA_OBJECT_TYPE_GENERAL: { - ecma_gc_free_properties (object_p); + ecma_gc_free_properties (object_p, ECMA_GC_FREE_NO_OPTIONS); ecma_dealloc_object (object_p); return; } @@ -1599,6 +1737,14 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ break; } #endif /* JERRY_BUILTIN_TYPEDARRAY */ +#if JERRY_MODULE_SYSTEM + case ECMA_OBJECT_CLASS_MODULE_NAMESPACE: + { + ecma_gc_free_properties (object_p, ECMA_GC_FREE_REFERENCES); + ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); + return; + } +#endif /* JERRY_MODULE_SYSTEM */ #if JERRY_PARSER case ECMA_OBJECT_CLASS_SCRIPT: { @@ -1832,7 +1978,8 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ } } - ecma_gc_free_properties (object_p); +free_properties: + ecma_gc_free_properties (object_p, ECMA_GC_FREE_NO_OPTIONS); ecma_dealloc_extended_object (object_p, ext_object_size); } /* ecma_gc_free_object */ diff --git a/jerry-core/ecma/base/ecma-gc.h b/jerry-core/ecma/base/ecma-gc.h index c5a5f548d..8ae76b8a6 100644 --- a/jerry-core/ecma/base/ecma-gc.h +++ b/jerry-core/ecma/base/ecma-gc.h @@ -26,11 +26,22 @@ * @{ */ +/** + * Free option flags + */ +typedef enum +{ + ECMA_GC_FREE_NO_OPTIONS = 0, /**< no options */ + ECMA_GC_FREE_SECOND_PROPERTY = (1 << 0), /**< free second property of a property pair */ + ECMA_GC_FREE_REFERENCES = (1 << 1), /**< free references */ +} ecma_gc_free_options_t; + void ecma_init_gc_info (ecma_object_t *object_p); void ecma_ref_object (ecma_object_t *object_p); void ecma_ref_object_inline (ecma_object_t *object_p); void ecma_deref_object (ecma_object_t *object_p); -void ecma_gc_free_properties (ecma_object_t *object_p); +void ecma_gc_free_property (ecma_object_t *object_p, ecma_property_pair_t *prop_pair_p, uint32_t options); +void ecma_gc_free_properties (ecma_object_t *object_p, uint32_t options); void ecma_gc_run (void); void ecma_free_unused_memory (jmem_pressure_t pressure); diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index c00a474d6..72073d3c0 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -711,6 +711,9 @@ typedef enum #if JERRY_BUILTIN_TYPEDARRAY ECMA_OBJECT_CLASS_TYPEDARRAY, /**< TypedArray which does NOT need extra space to store length and offset */ #endif /* JERRY_BUILTIN_TYPEDARRAY */ +#if JERRY_MODULE_SYSTEM + ECMA_OBJECT_CLASS_MODULE_NAMESPACE, /**< Module Namespace (ECMAScript v11, 9.4.6) */ +#endif /* JERRY_MODULE_SYSTEM */ /* These objects are marked by Garbage Collector. */ #if JERRY_ESNEXT @@ -776,14 +779,14 @@ typedef enum /* Types between 0 - 12 are ecma_object_type_t which can have a built-in flag. */ 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_HOME_OBJECT_BOUND = 15, /**< object-bound lexical environment - * with provided home object reference */ +#if JERRY_ESNEXT + ECMA_LEXICAL_ENVIRONMENT_CLASS = 14, /**< lexical environment with class */ +#endif /* JERRY_ESNEXT */ + ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND = 15, /**< object-bound lexical environment */ ECMA_LEXICAL_ENVIRONMENT_TYPE_START = ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE, /**< first lexical * environment type */ - ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX = ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND /**< maximum value */ + ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX = ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND /**< maximum value */ } ecma_lexical_environment_type_t; #if JERRY_ESNEXT @@ -848,10 +851,15 @@ typedef enum #define ECMA_OBJECT_FLAG_EXTENSIBLE 0x20 /** - * Lexical environments created for non-closure code blocks + * Declarative lexical environments created for non-closure code blocks */ #define ECMA_OBJECT_FLAG_BLOCK ECMA_OBJECT_FLAG_EXTENSIBLE +/** + * Lexical environments with class has extra data + */ +#define ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA ECMA_OBJECT_FLAG_EXTENSIBLE + /** * Bitshift index for an ecma-object reference count field */ @@ -1142,6 +1150,16 @@ typedef struct #define ECMA_BUILTIN_IS_EXTENDED_BUILT_IN(object_type) \ ((object_type) == ECMA_OBJECT_TYPE_CLASS || (object_type) == ECMA_OBJECT_TYPE_ARRAY) +/** + * Description of lexical environment with class + */ +typedef struct +{ + ecma_object_t lexical_env; /**< lexical environment header */ + + ecma_object_t *module_p; /**< module reference */ +} ecma_lexical_environment_class_t; + /** * Description of native functions */ diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 3e4a954b0..30799873d 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -123,7 +123,7 @@ ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environment_p) /**< outer /** * Create a object lexical environment with specified outer lexical environment - * (or NULL if the environment is not nested), binding object and provided type flag. + * (or NULL if the environment is not nested), and binding object. * * See also: ECMA-262 v5, 10.2.1.2 * @@ -133,23 +133,15 @@ ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environment_p) /**< outer */ ecma_object_t * ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, /**< outer lexical environment */ - ecma_object_t *binding_obj_p, /**< binding object */ - ecma_lexical_environment_type_t type) /**< type of the new lexical environment */ + ecma_object_t *binding_obj_p) /**< binding object */ { -#if JERRY_ESNEXT - JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND - || type == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); -#else /* !JERRY_ESNEXT */ - JERRY_ASSERT (type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); -#endif /* JERRY_ESNEXT */ - JERRY_ASSERT (binding_obj_p != NULL && !ecma_is_lexical_environment (binding_obj_p)); ecma_object_t *new_lexical_environment_p = ecma_alloc_object (); - const ecma_object_descriptor_t lexical_env_flag = ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV; - new_lexical_environment_p->type_flags_refs = (ecma_object_descriptor_t) (type | lexical_env_flag); + new_lexical_environment_p->type_flags_refs = (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV + | ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ecma_init_gc_info (new_lexical_environment_p); @@ -161,6 +153,45 @@ ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, /**< out return new_lexical_environment_p; } /* ecma_create_object_lex_env */ +#if JERRY_ESNEXT + +/** + * Create a lexical environment with a specified size. + * + * @return pointer to the descriptor of the lexical environment + */ +ecma_object_t * +ecma_create_lex_env_class (ecma_object_t *outer_lexical_environment_p, /**< outer lexical environment */ + size_t lexical_env_size) /**< size of the lexical environment */ +{ + ecma_object_t *new_lexical_environment_p; + + ecma_object_descriptor_t type_flags_refs = (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV + | ECMA_LEXICAL_ENVIRONMENT_CLASS); + + if (lexical_env_size > 0) + { + new_lexical_environment_p = (ecma_object_t *) ecma_alloc_extended_object (lexical_env_size); + type_flags_refs |= ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA; + } + else + { + new_lexical_environment_p = ecma_alloc_object (); + } + + new_lexical_environment_p->type_flags_refs = type_flags_refs; + + ecma_init_gc_info (new_lexical_environment_p); + + new_lexical_environment_p->u1.property_list_cp = JMEM_CP_NULL; + + ECMA_SET_POINTER (new_lexical_environment_p->u2.outer_reference_cp, outer_lexical_environment_p); + + return new_lexical_environment_p; +} /* ecma_create_lex_env_class */ + +#endif /* JERRY_ESNEXT */ + /** * Check if the object is lexical environment. * @@ -203,6 +234,29 @@ ecma_get_object_type (const ecma_object_t *object_p) /**< object */ return (ecma_object_type_t) (object_p->type_flags_refs & ECMA_OBJECT_TYPE_MASK); } /* ecma_get_object_type */ +/** + * Get value of an object if the class matches + * + * @return value of the object if the class matches + * ECMA_VALUE_NOT_FOUND otherwise + */ +extern inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_object_class_is (ecma_object_t *object_p, /**< object */ + ecma_object_class_type_t class_id) /**< class id */ +{ + if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_CLASS) + { + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + + if (ext_object_p->u.cls.type == (uint8_t) class_id) + { + return true; + } + } + + return false; +} /* ecma_object_class_is */ + /** * Check if the object is a built-in object * @@ -286,7 +340,8 @@ ecma_get_lex_env_binding_object (const ecma_object_t *object_p) /**< object-boun JERRY_ASSERT (ecma_is_lexical_environment (object_p)); #if JERRY_ESNEXT 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_HOME_OBJECT_BOUND); + || (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_CLASS + && (object_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA) == 0)); #else /* !JERRY_ESNEXT */ JERRY_ASSERT (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); #endif /* JERRY_ESNEXT */ @@ -568,6 +623,51 @@ ecma_create_named_accessor_property (ecma_object_t *object_p, /**< object */ return ecma_create_property (object_p, name_p, type_and_flags, value, out_prop_p); } /* ecma_create_named_accessor_property */ +#if JERRY_MODULE_SYSTEM +/** + * Create property reference + */ +void +ecma_create_named_reference_property (ecma_object_t *object_p, /**< object */ + ecma_string_t *name_p, /**< property name */ + ecma_property_t *property_p) /**< referenced property */ +{ + JERRY_ASSERT (object_p != NULL && name_p != NULL && property_p != NULL); + JERRY_ASSERT (*property_p & ECMA_PROPERTY_FLAG_DATA); + JERRY_ASSERT (ecma_find_named_property (object_p, name_p) == NULL); + JERRY_ASSERT ((ecma_is_lexical_environment (object_p) + && ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_CLASS + && (object_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA)) + || ecma_object_class_is (object_p, ECMA_OBJECT_CLASS_MODULE_NAMESPACE)); + + uint8_t type_and_flags = ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE; + + ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + jmem_cpointer_tag_t offset = (jmem_cpointer_tag_t) (((uintptr_t) property_p) & 0x1); + +#if JERRY_CPOINTER_32_BIT + if (offset != 0) + { + --value_p; + } +#else /* !JERRY_CPOINTER_32_BIT */ + if (offset == 0) + { + ++value_p; + } +#endif /* JERRY_CPOINTER_32_BIT */ + + JERRY_ASSERT ((((uintptr_t) value_p) & (((uintptr_t) 1 << JMEM_ALIGNMENT_LOG) - 1)) == 0); + + ecma_property_value_t value; + ECMA_SET_NON_NULL_POINTER_TAG (value.value, value_p, offset); + + ecma_create_property (object_p, name_p, type_and_flags, value, NULL); +} /* ecma_create_named_reference_property */ + +#endif /* JERRY_MODULE_SYSTEM */ + /** * Find named data property or named accessor property in a specified object. * @@ -748,48 +848,6 @@ ecma_get_named_data_property (ecma_object_t *obj_p, /**< object to find property return ECMA_PROPERTY_VALUE_PTR (property_p); } /* ecma_get_named_data_property */ -/** - * Free property values and change their type to deleted. - * - * Note: - * internal properties are not supported - */ -void -ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to */ - jmem_cpointer_t name_cp, /**< name of the property or ECMA_NULL_POINTER */ - ecma_property_t *property_p) /**< property */ -{ - JERRY_ASSERT (object_p != NULL && property_p != NULL); - JERRY_ASSERT (ECMA_PROPERTY_IS_RAW (*property_p)); - - if (*property_p & ECMA_PROPERTY_FLAG_DATA) - { - ecma_free_value_if_not_object (ECMA_PROPERTY_VALUE_PTR (property_p)->value); - } - else - { -#if JERRY_CPOINTER_32_BIT - ecma_getter_setter_pointers_t *getter_setter_pair_p; - getter_setter_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_getter_setter_pointers_t, - ECMA_PROPERTY_VALUE_PTR (property_p)->getter_setter_pair_cp); - jmem_pools_free (getter_setter_pair_p, sizeof (ecma_getter_setter_pointers_t)); -#endif /* JERRY_CPOINTER_32_BIT */ - } - -#if JERRY_LCACHE - if (ecma_is_property_lcached (property_p)) - { - ecma_lcache_invalidate (object_p, name_cp, property_p); - } -#endif /* JERRY_LCACHE */ - - if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR) - { - ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp); - ecma_deref_ecma_string (prop_name_p); - } -} /* ecma_free_property */ - /** * Delete the object's property referenced by its value pointer. * @@ -829,7 +887,7 @@ ecma_delete_property (ecma_object_t *object_p, /**< object */ ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) cur_prop_p; - for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) + for (uint32_t i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { if ((prop_pair_p->values + i) == prop_value_p) { @@ -844,7 +902,7 @@ ecma_delete_property (ecma_object_t *object_p, /**< object */ } #endif /* JERRY_PROPRETY_HASHMAP */ - ecma_free_property (object_p, prop_pair_p->names_cp[i], cur_prop_p->types + i); + ecma_gc_free_property (object_p, prop_pair_p, i); cur_prop_p->types[i] = ECMA_PROPERTY_TYPE_DELETED; prop_pair_p->names_cp[i] = LIT_INTERNAL_MAGIC_STRING_DELETED; @@ -1008,6 +1066,36 @@ ecma_set_named_accessor_property_setter (ecma_object_t *object_p, /**< the prope #endif /* JERRY_CPOINTER_32_BIT */ } /* ecma_set_named_accessor_property_setter */ +#if JERRY_MODULE_SYSTEM + +/** + * Gets the referenced property value + * + * @return pointer to the value + */ +extern inline ecma_property_value_t * JERRY_ATTR_ALWAYS_INLINE +ecma_get_property_value_from_named_reference (ecma_property_value_t *reference_p) /**< data property reference */ +{ + ecma_value_t value = reference_p->value; + reference_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_property_value_t, value); + +#if JERRY_CPOINTER_32_BIT + if (ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (value)) + { + ++reference_p; + } +#else /* !JERRY_CPOINTER_32_BIT */ + if (!ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (value)) + { + --reference_p; + } +#endif /* JERRY_CPOINTER_32_BIT */ + + return reference_p; +} /* ecma_get_property_value_from_named_reference */ + +#endif /* JERRY_MODULE_SYSTEM */ + /** * Get property's 'Writable' attribute value * diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 214fecbd9..211ca1d21 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -358,6 +358,9 @@ const lit_utf8_byte_t *ecma_string_get_chars (const ecma_string_t *string_p, bool ecma_compare_ecma_string_to_magic_id (const ecma_string_t *string_p, lit_magic_string_id_t id); bool ecma_string_is_empty (const ecma_string_t *string_p); bool ecma_string_is_length (const ecma_string_t *string_p); +#if JERRY_ESNEXT +bool ecma_compare_ecma_string_to_global_symbol (ecma_string_t *string_p, lit_magic_string_id_t property_id); +#endif /* JERRY_ESNEXT */ jmem_cpointer_t ecma_string_to_property_name (ecma_string_t *prop_name_p, ecma_property_t *name_type_p); ecma_string_t *ecma_string_from_property_name (ecma_property_t property, jmem_cpointer_t prop_name_cp); @@ -457,11 +460,14 @@ void ecma_compact_collection_free (ecma_value_t *compact_collection_p); /* ecma-helpers.c */ ecma_object_t *ecma_create_object (ecma_object_t *prototype_object_p, size_t ext_object_size, ecma_object_type_t type); ecma_object_t *ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environment_p); -ecma_object_t *ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, ecma_object_t *binding_obj_p, - ecma_lexical_environment_type_t type); +ecma_object_t *ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, ecma_object_t *binding_obj_p); +#if JERRY_ESNEXT +ecma_object_t *ecma_create_lex_env_class (ecma_object_t *outer_lexical_environment_p, size_t lexical_env_size); +#endif /* JERRY_ESNEXT */ bool JERRY_ATTR_PURE ecma_is_lexical_environment (const ecma_object_t *object_p); void ecma_op_ordinary_object_set_extensible (ecma_object_t *object_p); ecma_object_type_t JERRY_ATTR_PURE ecma_get_object_type (const ecma_object_t *object_p); +bool JERRY_ATTR_PURE ecma_object_class_is (ecma_object_t *object_p, ecma_object_class_type_t class_id); 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); @@ -475,13 +481,15 @@ ecma_create_named_data_property (ecma_object_t *object_p, ecma_string_t *name_p, ecma_property_value_t * ecma_create_named_accessor_property (ecma_object_t *object_p, ecma_string_t *name_p, ecma_object_t *get_p, ecma_object_t *set_p, uint8_t prop_attributes, ecma_property_t **out_prop_p); +#if JERRY_MODULE_SYSTEM +void ecma_create_named_reference_property (ecma_object_t *object_p, ecma_string_t *name_p, + ecma_property_t *property_p); +#endif /* JERRY_MODULE_SYSTEM */ ecma_property_t * ecma_find_named_property (ecma_object_t *obj_p, ecma_string_t *name_p); ecma_property_value_t * ecma_get_named_data_property (ecma_object_t *obj_p, ecma_string_t *name_p); -void ecma_free_property (ecma_object_t *object_p, jmem_cpointer_t name_cp, ecma_property_t *property_p); - void ecma_delete_property (ecma_object_t *object_p, ecma_property_value_t *prop_value_p); void ecma_named_data_property_assign_value (ecma_object_t *obj_p, ecma_property_value_t *prop_value_p, @@ -493,6 +501,10 @@ void ecma_set_named_accessor_property_getter (ecma_object_t *object_p, ecma_prop ecma_object_t *getter_p); void ecma_set_named_accessor_property_setter (ecma_object_t *object_p, ecma_property_value_t *prop_value_p, ecma_object_t *setter_p); +#if JERRY_MODULE_SYSTEM +ecma_property_value_t * +ecma_get_property_value_from_named_reference (ecma_property_value_t *reference_p); +#endif /* JERRY_MODULE_SYSTEM */ bool ecma_is_property_writable (ecma_property_t property); void ecma_set_property_writable_attr (ecma_property_t *property_p, bool is_writable); bool ecma_is_property_enumerable (ecma_property_t property); diff --git a/jerry-core/ecma/base/ecma-module.c b/jerry-core/ecma/base/ecma-module.c index 63f3a3127..cd4b8dba7 100644 --- a/jerry-core/ecma/base/ecma-module.c +++ b/jerry-core/ecma/base/ecma-module.c @@ -393,15 +393,9 @@ ecma_module_evaluate (ecma_module_t *module_p) /**< module */ } JERRY_ASSERT (module_p->header.u.cls.u1.module_state == JERRY_MODULE_STATE_LINKED); - -#if JERRY_BUILTIN_REALMS - ecma_object_t *global_object_p = (ecma_object_t *) ecma_op_function_get_realm (module_p->compiled_code_p); -#else /* !JERRY_BUILTIN_REALMS */ - ecma_object_t *global_object_p = ecma_builtin_get_global (); -#endif /* JERRY_BUILTIN_REALMS */ + JERRY_ASSERT (module_p->scope_p != NULL); module_p->header.u.cls.u1.module_state = JERRY_MODULE_STATE_EVALUATING; - module_p->scope_p = ecma_create_decl_lex_env (ecma_get_global_environment (global_object_p)); ecma_value_t ret_value; ret_value = vm_run_module (module_p); @@ -457,21 +451,11 @@ ecma_module_namespace_object_add_export_if_needed (ecma_module_t *module_p, /**< return result; } - ecma_object_t *ref_base_lex_env_p; - ecma_value_t prop_value = ecma_op_get_value_lex_env_base (record.module_p->scope_p, - &ref_base_lex_env_p, - record.name_p); - ecma_property_t *new_property_p; - ecma_create_named_data_property (module_p->namespace_object_p, - export_name_p, - ECMA_PROPERTY_FIXED, - &new_property_p); + ecma_property_t *property_p = ecma_find_named_property (record.module_p->scope_p, record.name_p); - ecma_named_data_property_assign_value (module_p->namespace_object_p, - ECMA_PROPERTY_VALUE_PTR (new_property_p), - prop_value); - - ecma_free_value (prop_value); + ecma_create_named_reference_property (module_p->namespace_object_p, + export_name_p, + property_p); return result; } /* ecma_module_namespace_object_add_export_if_needed */ @@ -491,13 +475,23 @@ ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */ return result; } - JERRY_ASSERT (module_p->header.u.cls.u1.module_state == JERRY_MODULE_STATE_EVALUATED); + JERRY_ASSERT (module_p->header.u.cls.u1.module_state >= JERRY_MODULE_STATE_LINKED + && module_p->header.u.cls.u1.module_state <= JERRY_MODULE_STATE_EVALUATED); ecma_module_resolve_set_t *resolve_set_p = NULL; ecma_module_resolve_stack_t *stack_p = NULL; - module_p->namespace_object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), - 0, - ECMA_OBJECT_TYPE_GENERAL); + ecma_object_t *namespace_object_p = ecma_create_object (NULL, + sizeof (ecma_extended_object_t), + ECMA_OBJECT_TYPE_CLASS); + + namespace_object_p->type_flags_refs &= (ecma_object_descriptor_t) ~ECMA_OBJECT_FLAG_EXTENSIBLE; + + ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) namespace_object_p; + ext_object_p->u.cls.type = ECMA_OBJECT_CLASS_MODULE_NAMESPACE; + ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.cls.u3.value, module_p); + + module_p->namespace_object_p = namespace_object_p; + ecma_deref_object (namespace_object_p); ecma_module_resolve_stack_push (&stack_p, module_p, ecma_get_magic_string (LIT_MAGIC_STRING_ASTERIX_CHAR)); while (stack_p != NULL) @@ -516,13 +510,6 @@ ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */ continue; } - result = ecma_module_evaluate (current_module_p); - - if (ECMA_IS_VALUE_ERROR (result)) - { - break; - } - ecma_module_names_t *export_names_p = current_module_p->local_exports_p; if (export_names_p != NULL) @@ -569,6 +556,11 @@ ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */ star_export_p = star_export_p->next_p; } + + if (ECMA_IS_VALUE_ERROR (result)) + { + break; + } } /* Clean up. */ @@ -659,8 +651,6 @@ ecma_module_connect_imports (ecma_module_t *module_p) const bool is_namespace_import = ecma_compare_ecma_string_to_magic_id (import_names_p->imex_name_p, LIT_MAGIC_STRING_ASTERIX_CHAR); - ecma_value_t prop_value; - if (is_namespace_import) { result = ecma_module_create_namespace_object (imported_module_p); @@ -670,8 +660,12 @@ ecma_module_connect_imports (ecma_module_t *module_p) return result; } - ecma_ref_object (imported_module_p->namespace_object_p); - prop_value = ecma_make_object_value (imported_module_p->namespace_object_p); + ecma_property_value_t *value_p; + value_p = ecma_create_named_data_property (module_p->scope_p, + import_names_p->local_name_p, + ECMA_PROPERTY_FLAG_WRITABLE, + NULL); + value_p->value = ecma_make_object_value (imported_module_p->namespace_object_p); } else /* !is_namespace_import */ { @@ -691,46 +685,28 @@ ecma_module_connect_imports (ecma_module_t *module_p) if (record.module_p->header.u.cls.u1.module_state == JERRY_MODULE_STATE_NATIVE) { ecma_object_t *object_p = record.module_p->namespace_object_p; + ecma_value_t prop_value; + prop_value = ecma_op_object_find_own (ecma_make_object_value (object_p), object_p, record.name_p); JERRY_ASSERT (ecma_is_value_found (prop_value)); + + ecma_property_value_t *value_p; + value_p = ecma_create_named_data_property (module_p->scope_p, + import_names_p->local_name_p, + ECMA_PROPERTY_FLAG_WRITABLE, + NULL); + value_p->value = ecma_copy_value_if_not_object (prop_value); } else { - result = ecma_module_evaluate (record.module_p); - - if (ECMA_IS_VALUE_ERROR (result)) - { - return result; - } - - ecma_object_t *ref_base_lex_env_p; - prop_value = ecma_op_get_value_lex_env_base (record.module_p->scope_p, - &ref_base_lex_env_p, - record.name_p); + ecma_property_t *property_p = ecma_find_named_property (record.module_p->scope_p, record.name_p); + ecma_create_named_reference_property (module_p->scope_p, + import_names_p->local_name_p, + property_p); } } - ecma_property_t *prop_p = ecma_op_create_mutable_binding (local_env_p, - import_names_p->local_name_p, - true /* is_deletable */); - JERRY_ASSERT (prop_p != ECMA_PROPERTY_POINTER_ERROR); - - if (prop_p != NULL) - { - JERRY_ASSERT (ecma_is_value_undefined (ECMA_PROPERTY_VALUE_PTR (prop_p)->value)); - ECMA_PROPERTY_VALUE_PTR (prop_p)->value = prop_value; - ecma_deref_if_object (prop_value); - } - else - { - ecma_op_set_mutable_binding (local_env_p, - import_names_p->local_name_p, - prop_value, - false /* is_strict */); - ecma_free_value (prop_value); - } - import_names_p = import_names_p->next_p; } @@ -975,6 +951,20 @@ restart: node_p = node_p->next_p; } + if (current_module_p->scope_p == NULL) + { + /* Initialize scope for handling circular references. */ + ecma_value_t result = vm_init_module_scope (current_module_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + module_p->header.u.cls.u1.module_state = JERRY_MODULE_STATE_ERROR; + goto error; + } + + JERRY_ASSERT (result == ECMA_VALUE_EMPTY); + } + if (current_module_p->header.u.cls.u3.dfs_ancestor_index != current_p->dfs_index) { current_p = current_p->parent_p; @@ -1079,15 +1069,10 @@ ecma_module_release_module (ecma_module_t *module_p) /**< module */ JERRY_ASSERT (state != JERRY_MODULE_STATE_INVALID); - if (module_p->namespace_object_p != NULL) - { - /* The module structure keeps a strong reference to the namespace object, which will require an extra GC call. */ - JERRY_CONTEXT (ecma_gc_new_objects)++; - ecma_deref_object (module_p->namespace_object_p); #ifndef JERRY_NDEBUG - module_p->namespace_object_p = NULL; + module_p->scope_p = NULL; + module_p->namespace_object_p = NULL; #endif /* JERRY_NDEBUG */ - } if (state == JERRY_MODULE_STATE_NATIVE) { @@ -1099,13 +1084,6 @@ ecma_module_release_module (ecma_module_t *module_p) /**< module */ ecma_module_release_module_nodes (module_p->indirect_exports_p, false); ecma_module_release_module_nodes (module_p->star_exports_p, false); - if (state >= JERRY_MODULE_STATE_EVALUATING) - { - /* The module structure keeps a strong reference to the module scope, which will require an extra GC call. */ - JERRY_CONTEXT (ecma_gc_new_objects)++; - ecma_deref_object (module_p->scope_p); - } - if (module_p->compiled_code_p != NULL) { ecma_bytecode_deref (module_p->compiled_code_p); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.c b/jerry-core/ecma/builtin-objects/ecma-builtins.c index 9185c451f..9724405a3 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.c @@ -593,9 +593,7 @@ ecma_builtin_create_global_object (void) global_object_p->global_scope_cp = global_object_p->global_env_cp; #endif /* JERRY_ESNEXT */ - ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL, - object_p, - ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); + ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL, object_p); ECMA_SET_NON_NULL_POINTER (global_object_p->global_env_cp, global_lex_env_p); #if JERRY_ESNEXT global_object_p->global_scope_cp = global_object_p->global_env_cp; diff --git a/jerry-core/ecma/operations/ecma-array-object.c b/jerry-core/ecma/operations/ecma-array-object.c index e35b0abbf..7311630bf 100644 --- a/jerry-core/ecma/operations/ecma-array-object.c +++ b/jerry-core/ecma/operations/ecma-array-object.c @@ -899,7 +899,7 @@ ecma_delete_array_properties (ecma_object_t *object_p, /**< object */ JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (current_prop_p)); ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) current_prop_p; - for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) + for (uint32_t i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) { if (current_prop_p->types[i] != ECMA_PROPERTY_TYPE_DELETED && ecma_is_property_configurable (current_prop_p->types[i])) @@ -920,7 +920,7 @@ ecma_delete_array_properties (ecma_object_t *object_p, /**< object */ } #endif /* JERRY_PROPRETY_HASHMAP */ - ecma_free_property (object_p, prop_pair_p->names_cp[i], current_prop_p->types + i); + ecma_gc_free_property (object_p, prop_pair_p, i); current_prop_p->types[i] = ECMA_PROPERTY_TYPE_DELETED; prop_pair_p->names_cp[i] = LIT_INTERNAL_MAGIC_STRING_DELETED; } diff --git a/jerry-core/ecma/operations/ecma-get-put-value.c b/jerry-core/ecma/operations/ecma-get-put-value.c index 1a9e1837a..110858e19 100644 --- a/jerry-core/ecma/operations/ecma-get-put-value.c +++ b/jerry-core/ecma/operations/ecma-get-put-value.c @@ -67,8 +67,7 @@ ecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme #if JERRY_ESNEXT if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED)) { - return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be" - " initialized before reading their value")); + return ecma_raise_reference_error (ECMA_ERR_MSG (ecma_error_let_const_not_initialized)); } #endif /* JERRY_ESNEXT */ @@ -77,8 +76,32 @@ ecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme break; } #if JERRY_ESNEXT - case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND: + case ECMA_LEXICAL_ENVIRONMENT_CLASS: { +#if JERRY_MODULE_SYSTEM + if (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA) + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + if (property_p != NULL) + { + *ref_base_lex_env_p = lex_env_p; + ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + if (!(*property_p & ECMA_PROPERTY_FLAG_DATA)) + { + property_value_p = ecma_get_property_value_from_named_reference (property_value_p); + } + + if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED)) + { + return ecma_raise_reference_error (ECMA_ERR_MSG (ecma_error_let_const_not_initialized)); + } + + return ecma_fast_copy_value (property_value_p->value); + } + } +#endif /* JERRY_MODULE_SYSTEM */ break; } #endif /* JERRY_ESNEXT */ @@ -215,52 +238,47 @@ ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme { switch (ecma_get_lex_env_type (lex_env_p)) { +#if JERRY_ESNEXT + case ECMA_LEXICAL_ENVIRONMENT_CLASS: + { + if ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA) == 0) + { + break; + } + /* FALLTHRU */ + } +#endif /* JERRY_ESNEXT */ case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: { ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); if (property_p != NULL) { +#if JERRY_ESNEXT + ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + JERRY_ASSERT (!(*property_p & ECMA_PROPERTY_FLAG_WRITABLE) + || (*property_p & ECMA_PROPERTY_FLAG_DATA)); + + if ((*property_p & ECMA_PROPERTY_FLAG_WRITABLE) + && property_value_p->value != ECMA_VALUE_UNINITIALIZED) + { + ecma_named_data_property_assign_value (lex_env_p, property_value_p, value); + return ECMA_VALUE_EMPTY; + } +#else /* JERRY_ESNEXT */ if (ecma_is_property_writable (*property_p)) { ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); - -#if JERRY_ESNEXT - if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED)) - { - return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be" - " initialized before writing their value")); - } -#endif /* JERRY_ESNEXT */ - ecma_named_data_property_assign_value (lex_env_p, property_value_p, value); - } -#if JERRY_ESNEXT - else if (ecma_is_property_enumerable (*property_p)) - { - if (JERRY_UNLIKELY (ECMA_PROPERTY_VALUE_PTR (property_p)->value == ECMA_VALUE_UNINITIALIZED)) - { - return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be" - " initialized before writing their value")); - } - - return ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned")); + return ECMA_VALUE_EMPTY; } #endif /* JERRY_ESNEXT */ - else if (is_strict) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set")); - } - return ECMA_VALUE_EMPTY; + + return ecma_op_raise_set_binding_error (property_p, is_strict); } break; } -#if JERRY_ESNEXT - case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND: - { - break; - } -#endif /* JERRY_ESNEXT */ default: { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); diff --git a/jerry-core/ecma/operations/ecma-lex-env.c b/jerry-core/ecma/operations/ecma-lex-env.c index b4bb886fd..ea74aab92 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.c +++ b/jerry-core/ecma/operations/ecma-lex-env.c @@ -88,6 +88,42 @@ ecma_create_global_lexical_block (ecma_object_t *global_object_p) /**< global ob } /* ecma_create_global_lexical_block */ #endif /* JERRY_ESNEXT */ +/** + * Raise the appropriate error when setting a binding is failed + * + * @return ECMA_VALUE_EMPTY or ECMA_VALUE_ERROR + */ +ecma_value_t +ecma_op_raise_set_binding_error (ecma_property_t *property_p, /**< property */ + bool is_strict) /**< flag indicating strict mode */ +{ + JERRY_UNUSED (property_p); + +#if JERRY_ESNEXT + const ecma_property_t expected_bits = (ECMA_PROPERTY_FLAG_DATA | ECMA_PROPERTY_FLAG_ENUMERABLE); + + if ((*property_p & expected_bits) == expected_bits) + { + ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED)) + { + return ecma_raise_reference_error (ECMA_ERR_MSG (ecma_error_let_const_not_initialized)); + } + + JERRY_ASSERT (!ecma_is_property_writable (*property_p)); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned")); + } +#endif /* JERRY_ESNEXT */ + + if (is_strict) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set")); + } + return ECMA_VALUE_EMPTY; +} /* ecma_op_raise_set_binding_error */ + /** * Get reference to Global lexical scope * without increasing its reference count. @@ -125,18 +161,33 @@ ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_lexical_environment_type_t lex_env_type = ecma_get_lex_env_type (lex_env_p); - if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + switch (lex_env_type) { - ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); +#if JERRY_ESNEXT + case ECMA_LEXICAL_ENVIRONMENT_CLASS: + { + if ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA) == 0) + { + return ECMA_VALUE_FALSE; + } + /* FALLTHRU */ + } +#endif /* JERRY_ESNEXT */ + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); - return ecma_make_boolean_value (property_p != NULL); + return ecma_make_boolean_value (property_p != NULL); + } + default: + { + JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); + + ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + + return ecma_op_object_has_property (binding_obj_p, name_p); + } } - - JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); - - ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - - return ecma_op_object_has_property (binding_obj_p, name_p); } /* ecma_op_has_binding */ /** @@ -245,53 +296,64 @@ ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment && ecma_is_lexical_environment (lex_env_p)); JERRY_ASSERT (name_p != NULL); - if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + switch (ecma_get_lex_env_type (lex_env_p)) { - ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); - - if (JERRY_UNLIKELY (property_p == NULL)) - { - property_p = ecma_op_create_mutable_binding (lex_env_p, name_p, is_strict); - JERRY_ASSERT (property_p != ECMA_PROPERTY_POINTER_ERROR); - } - - JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_IS_RAW_DATA (*property_p)); - - if (ecma_is_property_writable (*property_p)) - { - ecma_named_data_property_assign_value (lex_env_p, ECMA_PROPERTY_VALUE_PTR (property_p), value); - } #if JERRY_ESNEXT - else if (ecma_is_property_enumerable (*property_p)) + case ECMA_LEXICAL_ENVIRONMENT_CLASS: { - return ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned")); + if ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA) == 0) + { + return ECMA_VALUE_EMPTY; + } + /* FALLTHRU */ } #endif /* JERRY_ESNEXT */ - else if (is_strict) + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: { - return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set")); + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + if (JERRY_UNLIKELY (property_p == NULL)) + { + property_p = ecma_op_create_mutable_binding (lex_env_p, name_p, is_strict); + JERRY_ASSERT (property_p != ECMA_PROPERTY_POINTER_ERROR); + } + + JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_IS_RAW_DATA (*property_p)); + JERRY_ASSERT (!(*property_p & ECMA_PROPERTY_FLAG_WRITABLE) + || (*property_p & ECMA_PROPERTY_FLAG_DATA)); + + if ((*property_p & ECMA_PROPERTY_FLAG_WRITABLE)) + { + ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + JERRY_ASSERT (property_value_p->value != ECMA_VALUE_UNINITIALIZED); + + ecma_named_data_property_assign_value (lex_env_p, property_value_p, value); + return ECMA_VALUE_EMPTY; + } + + return ecma_op_raise_set_binding_error (property_p, is_strict); + } + default: + { + JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); + + ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + + ecma_value_t completion = ecma_op_object_put (binding_obj_p, + name_p, + value, + is_strict); + + if (ECMA_IS_VALUE_ERROR (completion)) + { + return completion; + } + + JERRY_ASSERT (ecma_is_value_boolean (completion)); + return ECMA_VALUE_EMPTY; } } - else - { - JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); - - ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - - ecma_value_t completion = ecma_op_object_put (binding_obj_p, - name_p, - value, - is_strict); - - if (ECMA_IS_VALUE_ERROR (completion)) - { - return completion; - } - - JERRY_ASSERT (ecma_is_value_boolean (completion)); - } - - return ECMA_VALUE_EMPTY; } /* ecma_op_set_mutable_binding */ /** diff --git a/jerry-core/ecma/operations/ecma-lex-env.h b/jerry-core/ecma/operations/ecma-lex-env.h index 8c6c1915b..e77f4f1e8 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.h +++ b/jerry-core/ecma/operations/ecma-lex-env.h @@ -37,6 +37,7 @@ ecma_object_t *ecma_get_global_scope (ecma_object_t *global_object_p); #if JERRY_ESNEXT void ecma_create_global_lexical_block (ecma_object_t *global_object_p); #endif /* JERRY_ESNEXT */ +ecma_value_t ecma_op_raise_set_binding_error (ecma_property_t *property_p, bool is_strict); #if JERRY_MODULE_SYSTEM void ecma_module_add_lex_env (ecma_object_t *lex_env_p); diff --git a/jerry-core/ecma/operations/ecma-objects-general.c b/jerry-core/ecma/operations/ecma-objects-general.c index 056f3c369..ae17779ef 100644 --- a/jerry-core/ecma/operations/ecma-objects-general.c +++ b/jerry-core/ecma/operations/ecma-objects-general.c @@ -425,12 +425,33 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob if (ECMA_PROPERTY_IS_VIRTUAL (current_prop)) { + bool writable_check_failed = (property_desc_p->flags & ECMA_PROP_IS_WRITABLE); + +#if JERRY_MODULE_SYSTEM + if (ecma_object_class_is (object_p, ECMA_OBJECT_CLASS_MODULE_NAMESPACE)) + { + if (JERRY_UNLIKELY (ext_property_ref.property_ref.virtual_value == ECMA_VALUE_UNINITIALIZED)) + { + return ecma_raise_reference_error (ECMA_ERR_MSG (ecma_error_let_const_not_initialized)); + } + + if (property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED) + { + writable_check_failed = ((property_desc_p->flags ^ current_prop) & ECMA_PROP_IS_WRITABLE) != 0; + } + } + else + { + JERRY_ASSERT (!is_current_configurable && !ecma_is_property_writable (current_prop)); + } +#else /* !JERRY_MODULE_SYSTEM */ JERRY_ASSERT (!is_current_configurable && !ecma_is_property_writable (current_prop)); +#endif /* JERRY_MODULE_SYSTEM */ ecma_value_t result = ECMA_VALUE_TRUE; if (property_desc_type == ECMA_OP_OBJECT_DEFINE_ACCESSOR - || (property_desc_p->flags & ECMA_PROP_IS_WRITABLE) + || writable_check_failed || ((property_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED) && !ecma_op_same_value (property_desc_p->value, ext_property_ref.property_ref.virtual_value))) diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 0f8a1838e..b04aeb645 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -183,6 +183,59 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ break; } #endif /* JERRY_BUILTIN_TYPEDARRAY */ +#if JERRY_MODULE_SYSTEM + case ECMA_OBJECT_CLASS_MODULE_NAMESPACE: + { + if (JERRY_UNLIKELY (ecma_prop_name_is_symbol (property_name_p))) + { + if (!ecma_op_compare_string_to_global_symbol (property_name_p, LIT_GLOBAL_SYMBOL_TO_STRING_TAG)) + { + return ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP; + } + + /* ECMA-262 v11, 26.3.1 */ + if (options & ECMA_PROPERTY_GET_VALUE) + { + property_ref_p->virtual_value = ecma_make_magic_string_value (LIT_MAGIC_STRING_MODULE_UL); + } + + return ECMA_PROPERTY_VIRTUAL; + } + + ecma_property_t *property_p = ecma_find_named_property (object_p, property_name_p); + + if (property_p == NULL) + { + return ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP; + } + + JERRY_ASSERT (ECMA_PROPERTY_IS_RAW (*property_p)); + + if (*property_p & ECMA_PROPERTY_FLAG_DATA) + { + if (options & ECMA_PROPERTY_GET_EXT_REFERENCE) + { + ((ecma_extended_property_ref_t *) property_ref_p)->property_p = property_p; + } + + if (property_ref_p != NULL) + { + property_ref_p->value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + } + + return *property_p; + } + + if (options & ECMA_PROPERTY_GET_VALUE) + { + ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + prop_value_p = ecma_get_property_value_from_named_reference (prop_value_p); + property_ref_p->virtual_value = ecma_fast_copy_value (prop_value_p->value); + } + + return ECMA_PROPERTY_ENUMERABLE_WRITABLE | ECMA_PROPERTY_VIRTUAL; + } +#endif /* JERRY_MODULE_SYSTEM */ } break; } @@ -538,6 +591,44 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ break; } #endif /* JERRY_BUILTIN_TYPEDARRAY */ +#if JERRY_MODULE_SYSTEM + case ECMA_OBJECT_CLASS_MODULE_NAMESPACE: + { + if (JERRY_UNLIKELY (ecma_prop_name_is_symbol (property_name_p))) + { + /* ECMA-262 v11, 26.3.1 */ + if (ecma_op_compare_string_to_global_symbol (property_name_p, LIT_GLOBAL_SYMBOL_TO_STRING_TAG)) + { + return ecma_make_magic_string_value (LIT_MAGIC_STRING_MODULE_UL); + } + + return ECMA_VALUE_NOT_FOUND; + } + + ecma_property_t *property_p = ecma_find_named_property (object_p, property_name_p); + + if (property_p == NULL) + { + return ECMA_VALUE_NOT_FOUND; + } + + JERRY_ASSERT (ECMA_PROPERTY_IS_RAW (*property_p)); + + ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + if (!(*property_p & ECMA_PROPERTY_FLAG_DATA)) + { + prop_value_p = ecma_get_property_value_from_named_reference (prop_value_p); + + if (JERRY_UNLIKELY (prop_value_p->value == ECMA_VALUE_UNINITIALIZED)) + { + return ecma_raise_reference_error (ECMA_ERR_MSG (ecma_error_let_const_not_initialized)); + } + } + + return ecma_fast_copy_value (prop_value_p->value); + } +#endif /* JERRY_MODULE_SYSTEM */ } break; } @@ -940,6 +1031,25 @@ ecma_op_get_global_symbol (lit_magic_string_id_t property_id) /**< property symb return symbol_p; } /* ecma_op_get_global_symbol */ +/** + * Checks whether the string equals to the global symbol. + * + * @return true - if the string equals to the global symbol + * false - otherwise + */ +bool +ecma_op_compare_string_to_global_symbol (ecma_string_t *string_p, /**< string to compare */ + lit_magic_string_id_t property_id) /**< property symbol id */ +{ + JERRY_ASSERT (LIT_IS_GLOBAL_SYMBOL (property_id)); + + uint32_t symbol_index = (uint32_t) property_id - (uint32_t) LIT_GLOBAL_SYMBOL__FIRST; + jmem_cpointer_t symbol_cp = JERRY_CONTEXT (global_symbols_cp)[symbol_index]; + + return (symbol_cp != JMEM_CP_NULL + && string_p == ECMA_GET_NON_NULL_POINTER (ecma_string_t, symbol_cp)); +} /* ecma_op_compare_string_to_global_symbol */ + /** * [[Get]] operation of ecma object where the property is a well-known symbol * @@ -1327,6 +1437,12 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */ break; } #endif /* JERRY_BUILTIN_TYPEDARRAY */ +#if JERRY_MODULE_SYSTEM + case ECMA_OBJECT_CLASS_MODULE_NAMESPACE: + { + return ecma_raise_readonly_assignment (property_name_p, is_throw); + } +#endif /* JERRY_MODULE_SYSTEM */ } break; } @@ -1837,6 +1953,12 @@ ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the ob } else { +#if JERRY_MODULE_SYSTEM + if (JERRY_UNLIKELY (property_ref.virtual_value == ECMA_VALUE_UNINITIALIZED)) + { + return ecma_raise_reference_error (ECMA_ERR_MSG (ecma_error_let_const_not_initialized)); + } +#endif /* JERRY_MODULE_SYSTEM */ prop_desc_p->value = property_ref.virtual_value; } @@ -2685,6 +2807,9 @@ static const uint16_t ecma_class_object_magic_string_id[] = #if JERRY_BUILTIN_TYPEDARRAY LIT_MAGIC_STRING__EMPTY, /**< ECMA_OBJECT_CLASS_TYPEDARRAY needs special resolver */ #endif /* JERRY_BUILTIN_TYPEDARRAY */ +#if JERRY_MODULE_SYSTEM + LIT_MAGIC_STRING_MODULE_UL, /**< magic string id of ECMA_OBJECT_CLASS_MODULE_NAMESPACE */ +#endif /* These objects are marked by Garbage Collector. */ #if JERRY_ESNEXT @@ -2887,29 +3012,6 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ } } /* ecma_object_get_class_name */ -/** - * Get value of an object if the class matches - * - * @return value of the object if the class matches - * ECMA_VALUE_NOT_FOUND otherwise - */ -extern inline bool JERRY_ATTR_ALWAYS_INLINE -ecma_object_class_is (ecma_object_t *object_p, /**< object */ - ecma_object_class_type_t class_id) /**< class id */ -{ - if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_CLASS) - { - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - - if (ext_object_p->u.cls.type == (uint8_t) class_id) - { - return true; - } - } - - return false; -} /* ecma_object_class_is */ - #if JERRY_BUILTIN_REGEXP /** * Checks if the given argument has [[RegExpMatcher]] internal slot diff --git a/jerry-core/ecma/operations/ecma-objects.h b/jerry-core/ecma/operations/ecma-objects.h index 36f65059d..55ee97b6b 100644 --- a/jerry-core/ecma/operations/ecma-objects.h +++ b/jerry-core/ecma/operations/ecma-objects.h @@ -71,6 +71,7 @@ ecma_value_t ecma_op_object_get_by_index (ecma_object_t *object_p, ecma_length_t ecma_value_t ecma_op_object_get_by_magic_id (ecma_object_t *object_p, lit_magic_string_id_t property_id); #if JERRY_ESNEXT ecma_string_t *ecma_op_get_global_symbol (lit_magic_string_id_t property_id); +bool ecma_op_compare_string_to_global_symbol (ecma_string_t *string_p, lit_magic_string_id_t property_id); ecma_value_t ecma_op_object_get_by_symbol_id (ecma_object_t *object_p, lit_magic_string_id_t property_id); ecma_value_t ecma_op_get_method_by_symbol_id (ecma_value_t value, lit_magic_string_id_t symbol_id); ecma_value_t ecma_op_get_method_by_magic_id (ecma_value_t value, lit_magic_string_id_t magic_id); @@ -100,7 +101,6 @@ ecma_collection_t *ecma_op_object_own_property_keys (ecma_object_t *obj_p); ecma_collection_t *ecma_op_object_enumerate (ecma_object_t *obj_p); lit_magic_string_id_t ecma_object_get_class_name (ecma_object_t *obj_p); -bool ecma_object_class_is (ecma_object_t *object_p, ecma_object_class_type_t class_id); #if JERRY_BUILTIN_REGEXP bool ecma_object_is_regexp_object (ecma_value_t arg); #endif /* JERRY_BUILTIN_REGEXP */ diff --git a/jerry-core/ecma/operations/ecma-reference.c b/jerry-core/ecma/operations/ecma-reference.c index 5d170971e..ab8f8afb8 100644 --- a/jerry-core/ecma/operations/ecma-reference.c +++ b/jerry-core/ecma/operations/ecma-reference.c @@ -47,14 +47,6 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical while (true) { -#if JERRY_ESNEXT - 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); - } -#endif /* JERRY_ESNEXT */ - ecma_value_t has_binding = ecma_op_has_binding (lex_env_p, name_p); #if JERRY_BUILTIN_PROXY @@ -114,11 +106,12 @@ ecma_op_is_global_environment (ecma_object_t *lex_env_p) /**< lexical environmen 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) { - if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND) + JERRY_ASSERT (lex_env_p != NULL); + + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_CLASS + && (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA) == 0) { ecma_object_t *home_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u1.home_object_cp); @@ -297,82 +290,109 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical while (true) { - ecma_lexical_environment_type_t lex_env_type = ecma_get_lex_env_type (lex_env_p); - - if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + switch (ecma_get_lex_env_type (lex_env_p)) { - ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); - - if (property_p != NULL) + case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE: { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + if (property_p == NULL) + { + break; + } + ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); #if JERRY_ESNEXT if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED)) { - return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be" - " initialized before reading their value")); + return ecma_raise_reference_error (ECMA_ERR_MSG (ecma_error_let_const_not_initialized)); } #endif /* JERRY_ESNEXT */ return ecma_fast_copy_value (property_value_p->value); } - } - else if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND) - { #if JERRY_ESNEXT - bool lcache_lookup_allowed = ecma_op_is_global_environment (lex_env_p); -#else /* !JERRY_ESNEXT*/ - bool lcache_lookup_allowed = true; -#endif /* JERRY_ESNEXT */ - - if (lcache_lookup_allowed) + case ECMA_LEXICAL_ENVIRONMENT_CLASS: { -#if JERRY_LCACHE - ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - ecma_property_t *property_p = ecma_lcache_lookup (binding_obj_p, name_p); - - if (property_p != NULL) +#if JERRY_MODULE_SYSTEM + if (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA) { - JERRY_ASSERT (ECMA_PROPERTY_IS_RAW (*property_p)); + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); - ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); - - if (*property_p & ECMA_PROPERTY_FLAG_DATA) + if (property_p == NULL) { - return ecma_fast_copy_value (prop_value_p->value); + break; } - ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (prop_value_p); + ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); - if (get_set_pair_p->getter_cp == JMEM_CP_NULL) + if (!(*property_p & ECMA_PROPERTY_FLAG_DATA)) { - return ECMA_VALUE_UNDEFINED; + property_value_p = ecma_get_property_value_from_named_reference (property_value_p); } - ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp); + if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED)) + { + return ecma_raise_reference_error (ECMA_ERR_MSG (ecma_error_let_const_not_initialized)); + } - ecma_value_t base_value = ecma_make_object_value (binding_obj_p); - return ecma_op_function_call (getter_p, base_value, NULL, 0); + return ecma_fast_copy_value (property_value_p->value); } -#endif /* JERRY_LCACHE */ +#endif /* JERRY_MODULE_SYSTEM */ + break; } - - ecma_value_t result = ecma_op_object_bound_environment_resolve_reference_value (lex_env_p, name_p); - - if (ecma_is_value_found (result)) - { - /* Note: the result may contains ECMA_VALUE_ERROR */ - return result; - } - } - else - { -#if JERRY_ESNEXT - JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); -#else /* !JERRY_ESNEXT */ - JERRY_UNREACHABLE (); #endif /* JERRY_ESNEXT */ + default: + { + JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); +#if JERRY_ESNEXT + bool lcache_lookup_allowed = ecma_op_is_global_environment (lex_env_p); +#else /* !JERRY_ESNEXT*/ + bool lcache_lookup_allowed = true; +#endif /* JERRY_ESNEXT */ + + if (lcache_lookup_allowed) + { +#if JERRY_LCACHE + ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + ecma_property_t *property_p = ecma_lcache_lookup (binding_obj_p, name_p); + + if (property_p != NULL) + { + JERRY_ASSERT (ECMA_PROPERTY_IS_RAW (*property_p)); + + ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + if (*property_p & ECMA_PROPERTY_FLAG_DATA) + { + return ecma_fast_copy_value (prop_value_p->value); + } + + ecma_getter_setter_pointers_t *get_set_pair_p = ecma_get_named_accessor_property (prop_value_p); + + if (get_set_pair_p->getter_cp == JMEM_CP_NULL) + { + return ECMA_VALUE_UNDEFINED; + } + + ecma_object_t *getter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, get_set_pair_p->getter_cp); + + ecma_value_t base_value = ecma_make_object_value (binding_obj_p); + return ecma_op_function_call (getter_p, base_value, NULL, 0); + } +#endif /* JERRY_LCACHE */ + } + + ecma_value_t result = ecma_op_object_bound_environment_resolve_reference_value (lex_env_p, name_p); + + if (ecma_is_value_found (result)) + { + /* Note: the result may contains ECMA_VALUE_ERROR */ + return result; + } + break; + } } if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL) diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 539c54fe9..74abe4cb9 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1979,7 +1979,13 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ #if JERRY_MODULE_SYSTEM else if (parse_opts & ECMA_PARSE_MODULE) { + parser_branch_t branch; + parser_emit_cbc_forward_branch (&context, CBC_JUMP_FORWARD, &branch); + scanner_create_variables (&context, SCANNER_CREATE_VARS_NO_OPTS); + parser_emit_cbc (&context, CBC_RETURN_WITH_BLOCK); + + parser_set_branch_to_current_position (&context, &branch); } #endif /* JERRY_MODULE_SYSTEM */ else diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 1b104bfcf..b35f45d8b 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -1307,9 +1307,8 @@ opfunc_init_class (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ 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_object_t *proto_env_p = ecma_create_lex_env_class (frame_ctx_p->lex_env_p, 0); + ECMA_SET_NON_NULL_POINTER (proto_env_p->u1.bound_object_cp, proto_p); ECMA_SET_NON_NULL_POINTER_TAG (((ecma_extended_object_t *) ctor_p)->u.function.scope_cp, proto_env_p, 0); @@ -1433,12 +1432,10 @@ opfunc_finalize_class (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ 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); + ecma_object_t *ctor_env_p = ecma_create_lex_env_class (class_env_p, 0); + ECMA_SET_NON_NULL_POINTER (ctor_env_p->u1.bound_object_cp, ctor_p); + ecma_object_t *proto_env_p = ecma_create_lex_env_class (class_env_p, 0); + ECMA_SET_NON_NULL_POINTER (proto_env_p->u1.bound_object_cp, proto_p); opfunc_set_class_attributes (ctor_p, ctor_env_p); opfunc_set_class_attributes (proto_p, proto_env_p); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index f2690fca5..a305c1212 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -262,33 +262,6 @@ static const uint16_t vm_decode_table[] JERRY_ATTR_CONST_DATA = #undef CBC_OPCODE -#if JERRY_MODULE_SYSTEM -/** - * Run module code - * - * Note: - * returned value must be freed with ecma_free_value, when it is no longer needed. - * - * @return ecma value - */ -ecma_value_t -vm_run_module (ecma_module_t *module_p) /**< module to be executed */ -{ - const ecma_value_t module_init_result = ecma_module_initialize (module_p); - - if (ECMA_IS_VALUE_ERROR (module_init_result)) - { - return module_init_result; - } - - vm_frame_ctx_shared_t shared; - shared.bytecode_header_p = module_p->compiled_code_p; - shared.status_flags = 0; - - return vm_run (&shared, ECMA_VALUE_UNDEFINED, module_p->scope_p); -} /* vm_run_module */ -#endif /* JERRY_MODULE_SYSTEM */ - /** * Run global code * @@ -432,6 +405,35 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */ return completion_value; } /* vm_run_eval */ +#if JERRY_MODULE_SYSTEM + +/** + * Run module code + * + * Note: + * returned value must be freed with ecma_free_value, when it is no longer needed. + * + * @return ecma value + */ +ecma_value_t +vm_run_module (ecma_module_t *module_p) /**< module to be executed */ +{ + const ecma_value_t module_init_result = ecma_module_initialize (module_p); + + if (ECMA_IS_VALUE_ERROR (module_init_result)) + { + return module_init_result; + } + + vm_frame_ctx_shared_t shared; + shared.bytecode_header_p = module_p->compiled_code_p; + shared.status_flags = 0; + + return vm_run (&shared, ECMA_VALUE_UNDEFINED, module_p->scope_p); +} /* vm_run_module */ + +#endif /* JERRY_MODULE_SYSTEM */ + /** * Construct object * @@ -1578,12 +1580,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { uint32_t literal_index, value_index; ecma_value_t lit_value; + bool release = false; READ_LITERAL_INDEX (value_index); - READ_LITERAL_INDEX (literal_index); - - JERRY_ASSERT (value_index != literal_index); - JERRY_ASSERT (value_index >= register_end || literal_index >= register_end); if (value_index < register_end) { @@ -1594,11 +1593,18 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { lit_value = vm_construct_literal_object (frame_ctx_p, literal_start_p[value_index]); + release = true; } + READ_LITERAL_INDEX (literal_index); + + JERRY_ASSERT (value_index != literal_index); + JERRY_ASSERT (value_index >= register_end || literal_index >= register_end); + if (literal_index < register_end) { ecma_fast_free_value (VM_GET_REGISTER (frame_ctx_p, literal_index)); + JERRY_ASSERT (release); VM_GET_REGISTER (frame_ctx_p, literal_index) = lit_value; continue; } @@ -1617,11 +1623,10 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (property_value_p->value == ECMA_VALUE_UNDEFINED); property_value_p->value = lit_value; - if (value_index >= register_end) + if (release) { - ecma_free_value (lit_value); + ecma_deref_object (ecma_get_object_from_value (lit_value)); } - continue; } #if JERRY_ESNEXT @@ -1701,12 +1706,16 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ READ_LITERAL_INDEX (literal_index); JERRY_ASSERT (literal_index >= register_end); - JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + JERRY_ASSERT (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE + || (ecma_get_lex_env_type (frame_ctx_p->lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_CLASS + && (frame_ctx_p->lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_LEXICAL_ENV_HAS_DATA))); ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); ecma_property_t *property_p = ecma_find_named_property (frame_ctx_p->lex_env_p, name_p); - JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_IS_RAW_DATA (*property_p)); + JERRY_ASSERT (property_p != NULL + && ECMA_PROPERTY_IS_RAW_DATA (*property_p) + && (*property_p & ECMA_PROPERTY_FLAG_DATA)); JERRY_ASSERT (ECMA_PROPERTY_VALUE_PTR (property_p)->value == ECMA_VALUE_UNINITIALIZED); ECMA_PROPERTY_VALUE_PTR (property_p)->value = left_value; @@ -2176,10 +2185,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ if (opcode == CBC_EXT_PUSH_OBJECT_SUPER_ENVIRONMENT) { ecma_value_t obj_value = stack_top_p[-1]; - ecma_object_t *obj_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p, - ecma_get_object_from_value (obj_value), - ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); + ecma_object_t *obj_env_p = ecma_create_lex_env_class (frame_ctx_p->lex_env_p, 0); + ECMA_SET_NON_NULL_POINTER (obj_env_p->u1.bound_object_cp, ecma_get_object_from_value (obj_value)); stack_top_p[-1] = ecma_make_object_value (obj_env_p); *stack_top_p++ = obj_value; } @@ -4029,9 +4037,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ object_p = ecma_get_object_from_value (result); - with_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p, - object_p, - ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); + with_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p, object_p); ecma_deref_object (object_p); VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION); @@ -4914,6 +4920,172 @@ finish: } } /* vm_loop */ +#if JERRY_MODULE_SYSTEM + +/** + * Create and initialize module scope with all data properties + * + * @return ECMA_VALUE_EMPTY on success, + * ECMA_VALUE_ERROR on failure + */ +ecma_value_t +vm_init_module_scope (ecma_module_t *module_p) /**< module without scope */ +{ + ecma_object_t *global_object_p; +#if JERRY_BUILTIN_REALMS + global_object_p = (ecma_object_t *) ecma_op_function_get_realm (module_p->compiled_code_p); +#else /* !JERRY_BUILTIN_REALMS */ + global_object_p = ecma_builtin_get_global (); +#endif /* JERRY_BUILTIN_REALMS */ + + ecma_object_t *scope_p = ecma_create_lex_env_class (ecma_get_global_environment (global_object_p), + sizeof (ecma_lexical_environment_class_t)); + const ecma_compiled_code_t *compiled_code_p = module_p->compiled_code_p; + ecma_value_t *literal_start_p; + uint8_t *byte_code_p; + uint16_t encoding_limit; + uint16_t encoding_delta; + + ((ecma_lexical_environment_class_t *) scope_p)->module_p = (ecma_object_t *) module_p; + + module_p->scope_p = scope_p; + ecma_deref_object (scope_p); + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) compiled_code_p; + + literal_start_p = (ecma_value_t *) (args_p + 1); + literal_start_p -= args_p->register_end; + byte_code_p = (uint8_t *) (literal_start_p + args_p->literal_end); + } + else + { + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) compiled_code_p; + + literal_start_p = (ecma_value_t *) (args_p + 1); + literal_start_p -= args_p->register_end; + byte_code_p = (uint8_t *) (literal_start_p + args_p->literal_end); + } + + /* Prepare for byte code execution. */ + if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FULL_LITERAL_ENCODING)) + { + encoding_limit = CBC_SMALL_LITERAL_ENCODING_LIMIT; + encoding_delta = CBC_SMALL_LITERAL_ENCODING_DELTA; + } + else + { + encoding_limit = CBC_FULL_LITERAL_ENCODING_LIMIT; + encoding_delta = CBC_FULL_LITERAL_ENCODING_DELTA; + } + + JERRY_ASSERT (*byte_code_p >= CBC_JUMP_FORWARD && *byte_code_p <= CBC_JUMP_FORWARD_3); + + byte_code_p += 1 + CBC_BRANCH_OFFSET_LENGTH (*byte_code_p); + + while (true) + { + uint8_t opcode = *byte_code_p++; + + switch (opcode) + { + case CBC_CREATE_VAR: + case CBC_CREATE_LET: + case CBC_CREATE_CONST: + { + uint32_t literal_index; + + READ_LITERAL_INDEX (literal_index); + + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + + JERRY_ASSERT (ecma_find_named_property (scope_p, name_p) == NULL); + + uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE; + + if (opcode == CBC_CREATE_LET) + { + prop_attributes = ECMA_PROPERTY_ENUMERABLE_WRITABLE; + } + else if (opcode == CBC_CREATE_CONST) + { + prop_attributes = ECMA_PROPERTY_FLAG_ENUMERABLE; + } + + ecma_property_value_t *property_value_p; + property_value_p = ecma_create_named_data_property (scope_p, name_p, prop_attributes, NULL); + + if (opcode != CBC_CREATE_VAR) + { + property_value_p->value = ECMA_VALUE_UNINITIALIZED; + } + break; + } + case CBC_INIT_ARG_OR_FUNC: + { + uint32_t literal_index; + + READ_LITERAL_INDEX (literal_index); + + ecma_compiled_code_t *function_bytecode_p; +#if JERRY_SNAPSHOT_EXEC + if (JERRY_LIKELY (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))) + { +#endif /* JERRY_SNAPSHOT_EXEC */ + function_bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + literal_start_p[literal_index]); +#if JERRY_SNAPSHOT_EXEC + } + else + { + uint8_t *byte_p = ((uint8_t *) compiled_code_p) + literal_start_p[literal_index]; + function_bytecode_p = (ecma_compiled_code_t *) byte_p; + } +#endif /* JERRY_SNAPSHOT_EXEC */ + + JERRY_ASSERT (CBC_IS_FUNCTION (function_bytecode_p->status_flags)); + + ecma_object_t *function_obj_p; + + if (JERRY_UNLIKELY (CBC_FUNCTION_IS_ARROW (function_bytecode_p->status_flags))) + { + function_obj_p = ecma_op_create_arrow_function_object (scope_p, + function_bytecode_p, + ECMA_VALUE_UNDEFINED); + } + else + { + function_obj_p = ecma_op_create_any_function_object (scope_p, function_bytecode_p); + } + + READ_LITERAL_INDEX (literal_index); + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + + JERRY_ASSERT (ecma_find_named_property (scope_p, name_p) == NULL); + + ecma_property_value_t *property_value_p; + property_value_p = ecma_create_named_data_property (scope_p, + name_p, + ECMA_PROPERTY_FLAG_WRITABLE, + NULL); + + JERRY_ASSERT (property_value_p->value == ECMA_VALUE_UNDEFINED); + property_value_p->value = ecma_make_object_value (function_obj_p); + ecma_deref_object (function_obj_p); + break; + } + default: + { + JERRY_ASSERT (opcode == CBC_RETURN_WITH_BLOCK); + return ECMA_VALUE_EMPTY; + } + } + } +} /* vm_init_module_scope */ + +#endif /* JERRY_MODULE_SYSTEM */ + #undef READ_LITERAL #undef READ_LITERAL_INDEX diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index 0210089bc..d03543c54 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -481,6 +481,7 @@ ecma_value_t vm_run_eval (ecma_compiled_code_t *bytecode_data_p, uint32_t parse_ #if JERRY_MODULE_SYSTEM ecma_value_t vm_run_module (ecma_module_t *module_p); +ecma_value_t vm_init_module_scope (ecma_module_t *module_p); #endif /* JERRY_MODULE_SYSTEM */ ecma_value_t vm_run (vm_frame_ctx_shared_t *shared_p, ecma_value_t this_binding_value, ecma_object_t *lex_env_p); diff --git a/tests/jerry/es.next/module-circular-01.mjs b/tests/jerry/es.next/module-circular-01.mjs new file mode 100644 index 000000000..5bf02a307 --- /dev/null +++ b/tests/jerry/es.next/module-circular-01.mjs @@ -0,0 +1,38 @@ +// 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. + +export var a = 0 +export let b = 1 + +function other() { + return 33.5 +} + +export function early() { + // This function is called before the module is executed + assert(other() === 33.5) + assert(a === undefined) + a = "X" + + try { + b + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } +} + +early = "Loaded" + +import * as o from "module-circular-02.mjs" diff --git a/tests/jerry/es.next/module-circular-02.mjs b/tests/jerry/es.next/module-circular-02.mjs new file mode 100644 index 000000000..fd8c6ac5d --- /dev/null +++ b/tests/jerry/es.next/module-circular-02.mjs @@ -0,0 +1,85 @@ +// 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. + +import * as o from "module-circular-01.mjs" + +if (o.early != "Loaded") +{ + // The scope of module-circular-01.mjs is initialized and functions are usable + // However, the module script has not been executed + + assert(o.a === undefined) + o.early() + assert(o.a === "X") + + try { + o.b + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } + + try { + o.a = "X" + assert(false) + } catch (e) { + assert(e instanceof TypeError) + } + + assert(o[Symbol.toStringTag] === "Module") + + var result = Object.getOwnPropertyDescriptor(o, "a") + assert(result.value === "X") + assert(result.configurable === false) + assert(result.enumerable === true) + assert(result.writable === true) + + try { + Object.getOwnPropertyDescriptor(o, "b") + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } + + result = Object.getOwnPropertyDescriptor(o, Symbol.toStringTag) + assert(result.value === "Module") + assert(result.configurable === false) + assert(result.enumerable === false) + assert(result.writable === false) + + Object.defineProperty(o, "a", { value: "X" }) + + try { + Object.defineProperty(o, "a", { value: "Y" }) + assert(false) + } catch (e) { + assert(e instanceof TypeError) + } + + try { + Object.defineProperty(o, "b", { value:5 }) + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } + + Object.defineProperty(o, Symbol.toStringTag, { value: "Module", writable:false }) + + try { + Object.defineProperty(o, Symbol.toStringTag, { writable:true }) + assert(false) + } catch (e) { + assert(e instanceof TypeError) + } +} diff --git a/tests/jerry/es.next/module-circular-03.mjs b/tests/jerry/es.next/module-circular-03.mjs new file mode 100644 index 000000000..b7741fe82 --- /dev/null +++ b/tests/jerry/es.next/module-circular-03.mjs @@ -0,0 +1,38 @@ +// 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. + +export var a = 0 +export let b = 1 + +function other() { + return 33.5 +} + +export function early() { + // This function is called before the module is executed + assert(other() === 33.5) + assert(a === undefined) + a = "X" + + try { + b + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } +} + +early = "Loaded" + +import * as o from "module-circular-04.mjs" diff --git a/tests/jerry/es.next/module-circular-04.mjs b/tests/jerry/es.next/module-circular-04.mjs new file mode 100644 index 000000000..93d6586b0 --- /dev/null +++ b/tests/jerry/es.next/module-circular-04.mjs @@ -0,0 +1,50 @@ +// 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. + +import {a as aa, b as bb, early} from "module-circular-03.mjs" + +export var a = 5 + +if (early != "Loaded") +{ + // The scope of module-circular-03.mjs is initialized and functions are usable + // However, the module script has not been executed + + assert(aa === undefined) + early() + assert(aa === "X") + + try { + bb + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } + + a = 7 + + try { + aa = "X" + assert(false) + } catch (e) { + assert(e instanceof TypeError) + } + + try { + c = 4 + assert(false) + } catch (e) { + assert(e instanceof ReferenceError) + } +} diff --git a/tests/jerry/es.next/module-import-05.mjs b/tests/jerry/es.next/module-import-05.mjs index 04658cda3..62b4a098a 100644 --- a/tests/jerry/es.next/module-import-05.mjs +++ b/tests/jerry/es.next/module-import-05.mjs @@ -17,4 +17,20 @@ import * as f from "./module-export-08.mjs"; assert (f.c === 5) assert (f.x === 41) -assert (!Object.hasOwnProperty(f, "default")); +assert (Object.getPrototypeOf(f) === null) + +try { + Object.hasOwnProperty(f, "default") + assert (false); +} catch (e) { + assert (e instanceof TypeError) +} + +Object.setPrototypeOf(f, null) + +try { + Object.setPrototypeOf(f, {}) + assert (false); +} catch (e) { + assert (e instanceof TypeError) +}