From 0fec9135ecece852c7884b61e1a21da441e769d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20B=C3=A1tyai?= Date: Mon, 18 Jan 2021 15:33:43 +0100 Subject: [PATCH] Rework module parsing and execution (#4462) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch disables automatic detection of module code, and instead requires the user to explicitly specify whether to parse a source as a module or as a script. To achieve this the jerry_parse API function now takes a new option which signals that the source should be parsed as a module. JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai daniel.batyai@h-lab.eu --- docs/02.API-REFERENCE.md | 2 + jerry-core/api/jerry.c | 79 +++- jerry-core/ecma/base/ecma-gc.c | 14 + jerry-core/ecma/base/ecma-globals.h | 8 + jerry-core/ecma/base/ecma-module.c | 418 ++++++++++-------- jerry-core/ecma/base/ecma-module.h | 84 ++-- jerry-core/include/jerryscript-core.h | 3 +- jerry-core/jcontext/jcontext.h | 4 +- jerry-core/lit/lit-char-helpers.c | 8 +- jerry-core/lit/lit-magic-strings.inc.h | 3 + jerry-core/lit/lit-magic-strings.ini | 1 + jerry-core/parser/js/js-lexer.h | 2 + jerry-core/parser/js/js-parser-internal.h | 4 +- jerry-core/parser/js/js-parser-module.c | 106 ++--- jerry-core/parser/js/js-parser-statm.c | 6 +- jerry-core/parser/js/js-parser-util.c | 2 +- jerry-core/parser/js/js-parser.c | 34 +- jerry-core/parser/js/js-scanner.c | 4 - jerry-core/vm/vm.c | 30 +- jerry-core/vm/vm.h | 3 +- jerry-main/main-options.c | 16 + jerry-main/main-options.h | 1 + jerry-main/main-unix.c | 12 +- ...dule-export-01.js => module-export-01.mjs} | 0 ...dule-export-02.js => module-export-02.mjs} | 8 +- ...dule-export-03.js => module-export-03.mjs} | 2 +- ...dule-export-04.js => module-export-04.mjs} | 0 ...dule-export-05.js => module-export-05.mjs} | 4 +- ...dule-export-06.js => module-export-06.mjs} | 4 +- ...dule-export-07.js => module-export-07.mjs} | 0 ...dule-export-08.js => module-export-08.mjs} | 2 +- ...il-test.js => module-export-fail-test.mjs} | 0 ...dule-import-01.js => module-import-01.mjs} | 14 +- ...dule-import-02.js => module-import-02.mjs} | 4 +- ...dule-import-03.js => module-import-03.mjs} | 2 +- ...dule-import-04.js => module-import-04.mjs} | 8 +- ...dule-import-05.js => module-import-05.mjs} | 2 +- ...ource-name.js => module-resource-name.mjs} | 2 +- ...2842.js => regression-test-issue-2842.mjs} | 0 .../es.next/regression-test-issue-2975.js | 2 +- .../fail/{module-001.js => module-001.mjs} | 2 +- .../fail/{module-002.js => module-002.mjs} | 2 +- .../fail/{module-003.js => module-003.mjs} | 2 +- tests/jerry/fail/module-004.js | 16 - tests/jerry/fail/module-004.mjs | 16 + .../fail/{module-005.js => module-005.mjs} | 2 +- .../fail/{module-006.js => module-006.mjs} | 0 .../fail/{module-007.js => module-007.mjs} | 2 +- .../fail/{module-008.js => module-008.mjs} | 0 .../fail/{module-009.js => module-009.mjs} | 0 .../fail/{module-010.js => module-010.mjs} | 2 +- .../fail/{module-011.js => module-011.mjs} | 0 .../fail/{module-012.js => module-012.mjs} | 0 .../fail/{module-013.js => module-013.mjs} | 0 .../fail/{module-014.js => module-014.mjs} | 2 +- .../fail/{module-015.js => module-015.mjs} | 2 +- .../fail/{module-016.js => module-016.mjs} | 2 +- .../fail/{module-017.js => module-017.mjs} | 2 +- .../fail/{module-018.js => module-018.mjs} | 2 +- .../fail/{module-019.js => module-019.mjs} | 0 .../fail/{module-020.js => module-020.mjs} | 2 +- .../fail/{module-021.js => module-021.mjs} | 4 +- .../fail/{module-022.js => module-022.mjs} | 2 +- .../fail/{module-023.js => module-023.mjs} | 2 +- .../fail/{module-024.js => module-024.mjs} | 2 +- .../fail/{module-025.js => module-025.mjs} | 2 +- .../fail/{module-026.js => module-026.mjs} | 2 +- .../fail/{module-027.js => module-027.mjs} | 2 +- .../fail/{module-028.js => module-028.mjs} | 2 +- .../fail/{module-029.js => module-029.mjs} | 2 +- .../fail/{module-030.js => module-030.mjs} | 2 +- .../fail/{module-031.js => module-031.mjs} | 0 .../fail/{module-032.js => module-032.mjs} | 2 +- .../fail/{module-033.js => module-033.mjs} | 2 +- .../fail/{module-034.js => module-034.mjs} | 2 +- .../fail/{module-035.js => module-035.mjs} | 2 +- .../fail/{module-036.js => module-036.mjs} | 2 +- .../fail/{module-037.js => module-037.mjs} | 2 +- ...dule-await-001.js => module-await-001.mjs} | 0 ...le-export-001.js => module-export-001.mjs} | 0 ...le-sideeffect.js => module-sideeffect.mjs} | 0 .../jerry/fail/regression-test-issue-2896.js | 4 +- tests/test262-esnext-excludelist.xml | 19 - tools/runners/run-test-suite.py | 11 +- tools/runners/test262-harness.py | 45 +- 85 files changed, 575 insertions(+), 492 deletions(-) rename tests/jerry/es.next/{module-export-01.js => module-export-01.mjs} (100%) rename tests/jerry/es.next/{module-export-02.js => module-export-02.mjs} (79%) rename tests/jerry/es.next/{module-export-03.js => module-export-03.mjs} (95%) rename tests/jerry/es.next/{module-export-04.js => module-export-04.mjs} (100%) rename tests/jerry/es.next/{module-export-05.js => module-export-05.mjs} (89%) rename tests/jerry/es.next/{module-export-06.js => module-export-06.mjs} (89%) rename tests/jerry/es.next/{module-export-07.js => module-export-07.mjs} (100%) rename tests/jerry/es.next/{module-export-08.js => module-export-08.mjs} (94%) rename tests/jerry/es.next/{module-export-fail-test.js => module-export-fail-test.mjs} (100%) rename tests/jerry/es.next/{module-import-01.js => module-import-01.mjs} (74%) rename tests/jerry/es.next/{module-import-02.js => module-import-02.mjs} (89%) rename tests/jerry/es.next/{module-import-03.js => module-import-03.mjs} (92%) rename tests/jerry/es.next/{module-import-04.js => module-import-04.mjs} (83%) rename tests/jerry/es.next/{module-import-05.js => module-import-05.mjs} (94%) rename tests/jerry/es.next/{module-resource-name.js => module-resource-name.mjs} (94%) rename tests/jerry/es.next/{regression-test-issue-2842.js => regression-test-issue-2842.mjs} (100%) rename tests/jerry/fail/{module-001.js => module-001.mjs} (94%) rename tests/jerry/fail/{module-002.js => module-002.mjs} (91%) rename tests/jerry/fail/{module-003.js => module-003.mjs} (92%) delete mode 100644 tests/jerry/fail/module-004.js create mode 100644 tests/jerry/fail/module-004.mjs rename tests/jerry/fail/{module-005.js => module-005.mjs} (92%) rename tests/jerry/fail/{module-006.js => module-006.mjs} (100%) rename tests/jerry/fail/{module-007.js => module-007.mjs} (95%) rename tests/jerry/fail/{module-008.js => module-008.mjs} (100%) rename tests/jerry/fail/{module-009.js => module-009.mjs} (100%) rename tests/jerry/fail/{module-010.js => module-010.mjs} (91%) rename tests/jerry/fail/{module-011.js => module-011.mjs} (100%) rename tests/jerry/fail/{module-012.js => module-012.mjs} (100%) rename tests/jerry/fail/{module-013.js => module-013.mjs} (100%) rename tests/jerry/fail/{module-014.js => module-014.mjs} (92%) rename tests/jerry/fail/{module-015.js => module-015.mjs} (92%) rename tests/jerry/fail/{module-016.js => module-016.mjs} (91%) rename tests/jerry/fail/{module-017.js => module-017.mjs} (92%) rename tests/jerry/fail/{module-018.js => module-018.mjs} (91%) rename tests/jerry/fail/{module-019.js => module-019.mjs} (100%) rename tests/jerry/fail/{module-020.js => module-020.mjs} (92%) rename tests/jerry/fail/{module-021.js => module-021.mjs} (86%) rename tests/jerry/fail/{module-022.js => module-022.mjs} (93%) rename tests/jerry/fail/{module-023.js => module-023.mjs} (93%) rename tests/jerry/fail/{module-024.js => module-024.mjs} (92%) rename tests/jerry/fail/{module-025.js => module-025.mjs} (93%) rename tests/jerry/fail/{module-026.js => module-026.mjs} (94%) rename tests/jerry/fail/{module-027.js => module-027.mjs} (94%) rename tests/jerry/fail/{module-028.js => module-028.mjs} (92%) rename tests/jerry/fail/{module-029.js => module-029.mjs} (91%) rename tests/jerry/fail/{module-030.js => module-030.mjs} (93%) rename tests/jerry/fail/{module-031.js => module-031.mjs} (100%) rename tests/jerry/fail/{module-032.js => module-032.mjs} (91%) rename tests/jerry/fail/{module-033.js => module-033.mjs} (91%) rename tests/jerry/fail/{module-034.js => module-034.mjs} (91%) rename tests/jerry/fail/{module-035.js => module-035.mjs} (91%) rename tests/jerry/fail/{module-036.js => module-036.mjs} (95%) rename tests/jerry/fail/{module-037.js => module-037.mjs} (95%) rename tests/jerry/fail/{module-await-001.js => module-await-001.mjs} (100%) rename tests/jerry/fail/{module-export-001.js => module-export-001.mjs} (100%) rename tests/jerry/fail/{module-sideeffect.js => module-sideeffect.mjs} (100%) diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 946f98a75..65b20a7b5 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -212,8 +212,10 @@ Option bits for [jerry_parse](#jerry_parse) and - JERRY_PARSE_NO_OPTS - no options passed - JERRY_PARSE_STRICT_MODE - enable strict mode + - JERRY_PARSE_MODULE - parse source as an ECMAScript module *New in version 2.0*. +*Changed in version 2.4: Added `JERRY_PARSE_MODULE`.* ## jerry_gc_mode_t diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 61db554c4..e43f786ae 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -246,10 +246,6 @@ jerry_cleanup (void) } } -#if ENABLED (JERRY_MODULE_SYSTEM) - ecma_module_cleanup (); -#endif /* ENABLED (JERRY_MODULE_SYSTEM) */ - #if ENABLED (JERRY_BUILTIN_PROMISE) ecma_free_all_enqueued_jobs (); #endif /* ENABLED (JERRY_BUILTIN_PROMISE) */ @@ -456,6 +452,15 @@ jerry_parse (const jerry_char_t *resource_name_p, /**< resource name (usually a } #endif /* ENABLED (JERRY_RESOURCE_NAME) */ + if ((parse_opts & JERRY_PARSE_MODULE) != 0) + { +#if ENABLED (JERRY_MODULE_SYSTEM) + ecma_module_initialize_context (ecma_get_string_from_value (resource_name)); +#else /* !ENABLED (JERRY_MODULE_SYSTEM) */ + return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("Module system has been disabled."))); +#endif /* !ENABLED (JERRY_MODULE_SYSTEM) */ + } + ecma_compiled_code_t *bytecode_data_p = parser_parse_script (NULL, 0, source_p, @@ -465,9 +470,44 @@ jerry_parse (const jerry_char_t *resource_name_p, /**< resource name (usually a if (JERRY_UNLIKELY (bytecode_data_p == NULL)) { +#if ENABLED (JERRY_MODULE_SYSTEM) + if ((parse_opts & JERRY_PARSE_MODULE) != 0) + { + ecma_module_cleanup_context (); + } +#endif /* ENABLED (JERRY_MODULE_SYSTEM) */ + return ecma_create_error_reference_from_context (); } +#if ENABLED (JERRY_MODULE_SYSTEM) + if ((parse_opts & JERRY_PARSE_MODULE) != 0) + { + if (ECMA_IS_VALUE_ERROR (ecma_module_parse_referenced_modules ())) + { + ecma_bytecode_deref (bytecode_data_p); + ecma_module_cleanup_context (); + + return ecma_create_error_reference_from_context (); + } + + ecma_object_t *obj_p = ecma_create_object (NULL, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS); + + ecma_extended_object_t *wrapper_p = (ecma_extended_object_t *) obj_p; + wrapper_p->u.class_prop.class_id = LIT_MAGIC_STRING_RUNNABLE_UL; + wrapper_p->u.class_prop.extra_info = ECMA_RUNNABLE_FLAGS_MODULE; + + ecma_module_t *root_module_p = JERRY_CONTEXT (module_current_p); + root_module_p->compiled_code_p = bytecode_data_p; + + ECMA_SET_INTERNAL_VALUE_POINTER (wrapper_p->u.class_prop.u.value, root_module_p); + JERRY_CONTEXT (module_current_p) = NULL; + JERRY_CONTEXT (module_list_p) = NULL; + + return ecma_make_object_value (obj_p); + } +#endif /* ENABLED (JERRY_MODULE_SYSTEM) */ + ecma_object_t *global_object_p = ecma_builtin_get_global (); #if ENABLED (JERRY_BUILTIN_REALMS) @@ -475,6 +515,9 @@ jerry_parse (const jerry_char_t *resource_name_p, /**< resource name (usually a #endif /* ENABLED (JERRY_BUILTIN_REALMS) */ ecma_object_t *lex_env_p = ecma_get_global_environment (global_object_p); + + /* TODO(dbatyai): For now Scripts continue to return Function objects due to backwards compatibility. This should be + * changed to also return a Runnable object eventually. */ ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_data_p); ecma_bytecode_deref (bytecode_data_p); @@ -588,15 +631,35 @@ jerry_run (const jerry_value_t func_val) /**< function to run */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); } - ecma_object_t *func_obj_p = ecma_get_object_from_value (func_val); + ecma_object_t *obj_p = ecma_get_object_from_value (func_val); - if (ecma_get_object_type (func_obj_p) != ECMA_OBJECT_TYPE_FUNCTION - || ecma_get_object_is_builtin (func_obj_p)) +#if ENABLED (JERRY_MODULE_SYSTEM) + if (ecma_object_class_is (obj_p, LIT_MAGIC_STRING_RUNNABLE_UL)) + { + ecma_extended_object_t *wrapper_p = (ecma_extended_object_t *) obj_p; + JERRY_ASSERT (wrapper_p->u.class_prop.extra_info == ECMA_RUNNABLE_FLAGS_MODULE); + ecma_module_t *root_module_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_module_t, wrapper_p->u.class_prop.u.value); + +#if ENABLED (JERRY_BUILTIN_REALMS) + ecma_object_t *global_object_p = (ecma_object_t *) ecma_op_function_get_realm (root_module_p->compiled_code_p); +#else /* !ENABLED (JERRY_BUILTIN_REALMS) */ + ecma_object_t *global_object_p = ecma_builtin_get_global (); +#endif /* ENABLED (JERRY_BUILTIN_REALMS) */ + + ecma_create_global_lexical_block (global_object_p); + root_module_p->scope_p = ecma_get_global_scope (global_object_p); + + return jerry_return (vm_run_module (root_module_p)); + } +#endif /* ENABLED (JERRY_MODULE_SYSTEM) */ + + if (ecma_get_object_type (obj_p) != ECMA_OBJECT_TYPE_FUNCTION + || ecma_get_object_is_builtin (obj_p)) { return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); } - ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) func_obj_p; + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) obj_p; const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 96a6f69f5..44a6500bd 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -1630,6 +1630,20 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ break; } #endif /* ENABLED (JERRY_ESNEXT) */ +#if ENABLED (JERRY_MODULE_SYSTEM) + case LIT_MAGIC_STRING_RUNNABLE_UL: + { + ecma_extended_object_t *wrapper_p = (ecma_extended_object_t *) object_p; + + JERRY_ASSERT (wrapper_p->u.class_prop.extra_info == ECMA_RUNNABLE_FLAGS_MODULE); + ecma_module_t *root_module_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_module_t, + wrapper_p->u.class_prop.u.value); + + ecma_bytecode_deref (root_module_p->compiled_code_p); + ecma_module_cleanup (root_module_p); + break; + } +#endif /* ENABLED (JERRY_MODULE_SYSTEM) */ default: { /* The undefined id represents an uninitialized class. */ diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index d85759f0a..a15bdaa63 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -1059,6 +1059,14 @@ typedef struct #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ #if ENABLED (JERRY_ESNEXT) +/** + * Flags for runnable objects. + */ +typedef enum +{ + ECMA_RUNNABLE_FLAGS_EMPTY = (0), /**< empty flags */ + ECMA_RUNNABLE_FLAGS_MODULE = (1 << 0) /**< runnable is a module */ +} ecma_runnable_flags_t; /** * Description of arrow function objects. diff --git a/jerry-core/ecma/base/ecma-module.c b/jerry-core/ecma/base/ecma-module.c index c1302211b..aecc5e250 100644 --- a/jerry-core/ecma/base/ecma-module.c +++ b/jerry-core/ecma/base/ecma-module.c @@ -37,8 +37,9 @@ * @return pointer to ecma_string_t containing the normalized and zero terminated path */ ecma_string_t * -ecma_module_create_normalized_path (const uint8_t *char_p, /**< module specifier */ - prop_length_t size) /**< size of module specifier */ +ecma_module_create_normalized_path (const lit_utf8_byte_t *char_p, /**< module path specifier */ + lit_utf8_size_t size, /**< size of module specifier */ + ecma_string_t *const base_path_p) /**< base path for the module specifier */ { JERRY_ASSERT (size > 0); ecma_string_t *ret_p = NULL; @@ -57,16 +58,13 @@ ecma_module_create_normalized_path (const uint8_t *char_p, /**< module specifier lit_utf8_byte_t *module_path_p = NULL; lit_utf8_size_t module_path_size = 0; - /* Check if we have a current module, and use its path as the base path. */ - JERRY_ASSERT (JERRY_CONTEXT (module_top_context_p) != NULL); - if (JERRY_CONTEXT (module_top_context_p)->module_p != NULL) + if (base_path_p != NULL) { - JERRY_ASSERT (JERRY_CONTEXT (module_top_context_p)->module_p->path_p != NULL); - module_path_size = ecma_string_get_size (JERRY_CONTEXT (module_top_context_p)->module_p->path_p); + module_path_size = ecma_string_get_size (base_path_p); module_path_p = (lit_utf8_byte_t *) jmem_heap_alloc_block (module_path_size + 1); lit_utf8_size_t module_utf8_size; - module_utf8_size = ecma_string_copy_to_utf8_buffer (JERRY_CONTEXT (module_top_context_p)->module_p->path_p, + module_utf8_size = ecma_string_copy_to_utf8_buffer (base_path_p, module_path_p, module_path_size); @@ -96,26 +94,39 @@ ecma_module_create_normalized_path (const uint8_t *char_p, /**< module specifier } /* ecma_module_create_normalized_path */ /** - * Find a module with a specific identifier + * Push a new module into the module list. New modules are inserted after the head module, this way in the end the + * root module remains the first in the list. + */ +static void +ecma_module_list_push (ecma_module_t *module_p) +{ + ecma_module_t *head_p = JERRY_CONTEXT (module_list_p); + module_p->next_p = head_p->next_p; + head_p->next_p = module_p; +} /* ecma_module_list_push */ + +/** + * Lookup a module with a specific identifier. * * @return pointer to ecma_module_t, if found * NULL, otherwise */ -ecma_module_t * -ecma_module_find_module (ecma_string_t *const path_p) /**< module identifier */ +static ecma_module_t * +ecma_module_list_lookup (ecma_string_t *const path_p) /**< module identifier */ { - ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p); + ecma_module_t *current_p = JERRY_CONTEXT (module_list_p); while (current_p != NULL) { if (ecma_compare_ecma_strings (path_p, current_p->path_p)) { return current_p; } + current_p = current_p->next_p; } - return current_p; -} /* ecma_module_find_module */ + return NULL; +} /* ecma_module_list_lookup */ /** * Create a new module @@ -129,8 +140,7 @@ ecma_module_create_module (ecma_string_t *const path_p) /**< module identifier * memset (module_p, 0, sizeof (ecma_module_t)); module_p->path_p = path_p; - module_p->next_p = JERRY_CONTEXT (ecma_modules_p); - JERRY_CONTEXT (ecma_modules_p) = module_p; + ecma_module_list_push (module_p); return module_p; } /* ecma_module_create_module */ @@ -140,9 +150,10 @@ ecma_module_create_module (ecma_string_t *const path_p) /**< module identifier * * @return pointer to found or newly created module structure */ ecma_module_t * -ecma_module_find_or_create_module (ecma_string_t *const path_p) /**< module path */ +ecma_module_find_module (ecma_string_t *const path_p) /**< module path */ { - ecma_module_t *module_p = ecma_module_find_module (path_p); + ecma_module_t *module_p = ecma_module_list_lookup (path_p); + if (module_p) { ecma_deref_ecma_string (path_p); @@ -150,7 +161,7 @@ ecma_module_find_or_create_module (ecma_string_t *const path_p) /**< module path } return ecma_module_create_module (path_p); -} /* ecma_module_find_or_create_module */ +} /* ecma_module_find_module */ /** * Create a new native module @@ -158,28 +169,83 @@ ecma_module_find_or_create_module (ecma_string_t *const path_p) /**< module path * @return pointer to created module */ ecma_module_t * -ecma_module_create_native_module (ecma_string_t *const path_p, /**< module identifier */ - ecma_object_t *const namespace_p) /**< module namespace */ +ecma_module_find_native_module (ecma_string_t *const path_p) { - ecma_module_t *module_p = ecma_module_create_module (path_p); - module_p->state = ECMA_MODULE_STATE_NATIVE; - module_p->namespace_object_p = namespace_p; - return module_p; -} /* ecma_module_create_native_module */ + ecma_module_t *module_p = ecma_module_list_lookup (path_p); + + if (module_p != NULL) + { + return module_p; + } + + ecma_value_t native = jerry_port_get_native_module (ecma_make_string_value (path_p)); + + if (!ecma_is_value_undefined (native)) + { + JERRY_ASSERT (ecma_is_value_object (native)); + + module_p = ecma_module_create_module (path_p); + module_p->state = ECMA_MODULE_STATE_NATIVE; + module_p->namespace_object_p = ecma_get_object_from_value (native); + + return module_p; + } + + return NULL; +} /* ecma_module_find_native_module */ /** - * Creates a module context. - * - * @return pointer to created module context + * Initialize context variables for the root module. */ -static ecma_module_context_t * -ecma_module_create_module_context (void) +void +ecma_module_initialize_context (ecma_string_t *root_path_p) /**< root module */ { - ecma_module_context_t *context_p = (ecma_module_context_t *) jmem_heap_alloc_block (sizeof (ecma_module_context_t)); - memset (context_p, 0, sizeof (ecma_module_context_t)); + JERRY_ASSERT (JERRY_CONTEXT (module_current_p) == NULL); + JERRY_ASSERT (JERRY_CONTEXT (module_list_p) == NULL); - return context_p; -} /* ecma_module_create_module_context */ + lit_utf8_size_t path_str_size; + uint8_t flags = ECMA_STRING_FLAG_EMPTY; + + const lit_utf8_byte_t *path_str_chars_p = ecma_string_get_chars (root_path_p, + &path_str_size, + NULL, + NULL, + &flags); + + ecma_string_t *path_p = ecma_module_create_normalized_path (path_str_chars_p, + path_str_size, + NULL); + + if (path_p == NULL) + { + ecma_ref_ecma_string (root_path_p); + path_p = root_path_p; + } + + ecma_module_t *module_p = (ecma_module_t *) jmem_heap_alloc_block (sizeof (ecma_module_t)); + memset (module_p, 0, sizeof (ecma_module_t)); + + module_p->path_p = path_p; + /* Root modules are handled differently then the rest of the referenced modules, as the scope and compiled code + * are handled separately. */ + module_p->state = ECMA_MODULE_STATE_ROOT; + + JERRY_CONTEXT (module_current_p) = module_p; + JERRY_CONTEXT (module_list_p) = module_p; +} /* ecma_module_initialize_context */ + +/** + * cleanup context variables for the root module. + */ +void +ecma_module_cleanup_context (void) +{ + ecma_module_cleanup (JERRY_CONTEXT (module_current_p)); +#ifndef JERRY_NDEBUG + JERRY_CONTEXT (module_current_p) = NULL; + JERRY_CONTEXT (module_list_p) = NULL; +#endif /* JERRY_NDEBUG */ +} /* ecma_module_cleanup_context */ /** * Inserts a {module, export_name} record into a resolve set. @@ -190,8 +256,8 @@ ecma_module_create_module_context (void) */ bool ecma_module_resolve_set_insert (ecma_module_resolve_set_t **set_p, /**< [in, out] resolve set */ - ecma_module_t * const module_p, /**< module */ - ecma_string_t * const export_name_p) /**< export name */ + ecma_module_t *const module_p, /**< module */ + ecma_string_t *const export_name_p) /**< export name */ { JERRY_ASSERT (set_p != NULL); ecma_module_resolve_set_t *current_p = *set_p; @@ -283,8 +349,8 @@ ecma_module_resolve_stack_pop (ecma_module_resolve_stack_t **stack_p) /**< [in, * ECMA_VALUE_EMPTY - otherwise */ static ecma_value_t -ecma_module_resolve_export (ecma_module_t * const module_p, /**< base module */ - ecma_string_t * const export_name_p, /**< export name */ +ecma_module_resolve_export (ecma_module_t *const module_p, /**< base module */ + ecma_string_t *const export_name_p, /**< export name */ ecma_module_record_t *out_record_p) /**< [out] found module record */ { ecma_module_resolve_set_t *resolve_set_p = NULL; @@ -302,7 +368,6 @@ ecma_module_resolve_export (ecma_module_t * const module_p, /**< base module */ ecma_module_t *current_module_p = current_frame_p->module_p; JERRY_ASSERT (current_module_p->state >= ECMA_MODULE_STATE_PARSED); - ecma_module_context_t *context_p = current_module_p->context_p; ecma_string_t *current_export_name_p = current_frame_p->export_name_p; if (!current_frame_p->resolving) @@ -341,11 +406,11 @@ ecma_module_resolve_export (ecma_module_t * const module_p, /**< base module */ continue; } - if (context_p->local_exports_p != NULL) + if (current_module_p->local_exports_p != NULL) { /* 15.2.1.16.3 / 4 */ - JERRY_ASSERT (context_p->local_exports_p->next_p == NULL); - ecma_module_names_t *export_names_p = context_p->local_exports_p->module_names_p; + JERRY_ASSERT (current_module_p->local_exports_p->next_p == NULL); + ecma_module_names_t *export_names_p = current_module_p->local_exports_p->module_names_p; while (export_names_p != NULL) { if (ecma_compare_ecma_strings (current_export_name_p, export_names_p->imex_name_p)) @@ -377,7 +442,7 @@ ecma_module_resolve_export (ecma_module_t * const module_p, /**< base module */ } /* 15.2.1.16.3 / 5 */ - ecma_module_node_t *indirect_export_p = context_p->indirect_exports_p; + ecma_module_node_t *indirect_export_p = current_module_p->indirect_exports_p; while (indirect_export_p != NULL) { ecma_module_names_t *export_names_p = indirect_export_p->module_names_p; @@ -389,6 +454,7 @@ ecma_module_resolve_export (ecma_module_t * const module_p, /**< base module */ ecma_module_resolve_stack_push (&stack_p, indirect_export_p->module_request_p, export_names_p->local_name_p); + break; } export_names_p = export_names_p->next_p; @@ -432,7 +498,7 @@ ecma_module_resolve_export (ecma_module_t * const module_p, /**< base module */ ecma_module_resolve_stack_pop (&stack_p); /* 15.2.1.16.3 / 10 */ - ecma_module_node_t *star_export_p = context_p->star_exports_p; + ecma_module_node_t *star_export_p = current_module_p->star_exports_p; while (star_export_p != NULL) { JERRY_ASSERT (star_export_p->module_names_p == NULL); @@ -493,12 +559,9 @@ ecma_module_evaluate (ecma_module_t *module_p) /**< module */ module_p->state = ECMA_MODULE_STATE_EVALUATING; module_p->scope_p = ecma_create_decl_lex_env (ecma_get_global_environment (global_object_p)); - module_p->context_p->parent_p = JERRY_CONTEXT (module_top_context_p); - JERRY_CONTEXT (module_top_context_p) = module_p->context_p; ecma_value_t ret_value; - ret_value = vm_run_module (module_p->compiled_code_p, - module_p->scope_p); + ret_value = vm_run_module (module_p); if (!ECMA_IS_VALUE_ERROR (ret_value)) { @@ -506,10 +569,11 @@ ecma_module_evaluate (ecma_module_t *module_p) /**< module */ ret_value = ECMA_VALUE_EMPTY; } - JERRY_CONTEXT (module_top_context_p) = module_p->context_p->parent_p; - - ecma_bytecode_deref (module_p->compiled_code_p); module_p->state = ECMA_MODULE_STATE_EVALUATED; + ecma_bytecode_deref (module_p->compiled_code_p); +#ifndef JERRY_NDEBUG + module_p->compiled_code_p = NULL; +#endif /* JERRY_NDEBUG */ return ret_value; } /* ecma_module_evaluate */ @@ -597,7 +661,6 @@ ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */ { ecma_module_resolve_stack_t *current_frame_p = stack_p; ecma_module_t *current_module_p = current_frame_p->module_p; - ecma_module_context_t *context_p = current_module_p->context_p; ecma_module_resolve_stack_pop (&stack_p); @@ -617,11 +680,11 @@ ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */ break; } - if (context_p->local_exports_p != NULL) + if (current_module_p->local_exports_p != NULL) { /* 15.2.1.16.2 / 5 */ - JERRY_ASSERT (context_p->local_exports_p->next_p == NULL); - ecma_module_names_t *export_names_p = context_p->local_exports_p->module_names_p; + JERRY_ASSERT (current_module_p->local_exports_p->next_p == NULL); + ecma_module_names_t *export_names_p = current_module_p->local_exports_p->module_names_p; while (export_names_p != NULL && ecma_is_value_empty (result)) { result = ecma_module_namespace_object_add_export_if_needed (module_p, @@ -631,7 +694,7 @@ ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */ } /* 15.2.1.16.2 / 6 */ - ecma_module_node_t *indirect_export_p = context_p->indirect_exports_p; + ecma_module_node_t *indirect_export_p = current_module_p->indirect_exports_p; while (indirect_export_p != NULL && ecma_is_value_empty (result)) { ecma_module_names_t *export_names_p = indirect_export_p->module_names_p; @@ -645,7 +708,7 @@ ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */ } /* 15.2.1.16.2 / 7 */ - ecma_module_node_t *star_export_p = context_p->star_exports_p; + ecma_module_node_t *star_export_p = current_module_p->star_exports_p; while (star_export_p != NULL && ecma_is_value_empty (result)) { JERRY_ASSERT (star_export_p->module_names_p == NULL); @@ -670,20 +733,18 @@ ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */ } /* ecma_module_create_namespace_object */ /** - * Connects imported values to the current context. + * Connects imported values to the current module scope. * * @return ECMA_VALUE_ERROR - if an error occured * ECMA_VALUE_EMPTY - otherwise */ static ecma_value_t -ecma_module_connect_imports (void) +ecma_module_connect_imports (ecma_module_t *module_p) { - ecma_module_context_t *current_context_p = JERRY_CONTEXT (module_top_context_p); - - ecma_object_t *local_env_p = current_context_p->module_p->scope_p; + ecma_object_t *local_env_p = module_p->scope_p; JERRY_ASSERT (ecma_is_lexical_environment (local_env_p)); - ecma_module_node_t *import_node_p = current_context_p->imports_p; + ecma_module_node_t *import_node_p = module_p->imports_p; /* Check that the imported bindings don't exist yet. */ while (import_node_p != NULL) @@ -728,7 +789,7 @@ ecma_module_connect_imports (void) import_node_p = import_node_p->next_p; } - import_node_p = current_context_p->imports_p; + import_node_p = module_p->imports_p; /* Resolve imports and create local bindings. */ while (import_node_p != NULL) @@ -823,6 +884,48 @@ ecma_module_connect_imports (void) return ECMA_VALUE_EMPTY; } /* ecma_module_connect_imports */ +/** + * Checks if indirect exports in the current context are resolvable. + * Note: See 15.2.1.16.4 / 9. + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise + */ +static ecma_value_t +ecma_module_check_indirect_exports (ecma_module_t *module_p) +{ + ecma_module_node_t *indirect_export_p = module_p->indirect_exports_p; + while (indirect_export_p != NULL) + { + ecma_module_names_t *name_p = indirect_export_p->module_names_p; + while (name_p != NULL) + { + ecma_module_record_t record; + ecma_value_t result = ecma_module_resolve_export (indirect_export_p->module_request_p, + name_p->local_name_p, + &record); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + JERRY_ASSERT (ecma_is_value_empty (result)); + + if (record.module_p == NULL) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Ambiguous indirect export request.")); + } + + name_p = name_p->next_p; + } + + indirect_export_p = indirect_export_p->next_p; + } + + return ECMA_VALUE_EMPTY; +} /* ecma_module_check_indirect_exports */ + /** * Initialize the current module by creating the local binding for the imported variables * and verifying indirect exports. @@ -831,17 +934,42 @@ ecma_module_connect_imports (void) * ECMA_VALUE_EMPTY - otherwise */ ecma_value_t -ecma_module_initialize_current (void) +ecma_module_initialize (ecma_module_t *module_p) /**< module */ { - ecma_value_t ret_value = ecma_module_connect_imports (); + ecma_value_t ret_value = ecma_module_connect_imports (module_p); if (ecma_is_value_empty (ret_value)) { - ret_value = ecma_module_check_indirect_exports (); + ret_value = ecma_module_check_indirect_exports (module_p); } return ret_value; -} /* ecma_module_initialize_current */ +} /* ecma_module_initialize */ + +static ecma_value_t ecma_module_parse (ecma_module_t *module_p); + +/** + * Parses all referenced modules. + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +ecma_module_parse_referenced_modules (void) +{ + ecma_module_t *current_p = JERRY_CONTEXT (module_list_p); + while (current_p != NULL) + { + if (ECMA_IS_VALUE_ERROR (ecma_module_parse (current_p))) + { + return ECMA_VALUE_ERROR; + } + + current_p = current_p->next_p; + } + + return ECMA_VALUE_EMPTY; +} /* ecma_module_parse_referenced_modules */ /** * Parses an EcmaScript module. @@ -849,7 +977,7 @@ ecma_module_initialize_current (void) * @return ECMA_VALUE_ERROR - if an error occured * ECMA_VALUE_EMPTY - otherwise */ -static jerry_value_t +static ecma_value_t ecma_module_parse (ecma_module_t *module_p) /**< module */ { if (module_p->state >= ECMA_MODULE_STATE_PARSING) @@ -858,7 +986,6 @@ ecma_module_parse (ecma_module_t *module_p) /**< module */ } module_p->state = ECMA_MODULE_STATE_PARSING; - module_p->context_p = ecma_module_create_module_context (); lit_utf8_size_t module_path_size = ecma_string_get_size (module_p->path_p); lit_utf8_byte_t *module_path_p = (lit_utf8_byte_t *) jmem_heap_alloc_block (module_path_size + 1); @@ -878,9 +1005,8 @@ ecma_module_parse (ecma_module_t *module_p) /**< module */ return ecma_raise_syntax_error (ECMA_ERR_MSG ("File not found.")); } - module_p->context_p->module_p = module_p; - module_p->context_p->parent_p = JERRY_CONTEXT (module_top_context_p); - JERRY_CONTEXT (module_top_context_p) = module_p->context_p; + ecma_module_t *prev_module_p = JERRY_CONTEXT (module_current_p); + JERRY_CONTEXT (module_current_p) = module_p; #if ENABLED (JERRY_DEBUGGER) && ENABLED (JERRY_PARSER) if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) @@ -899,8 +1025,7 @@ ecma_module_parse (ecma_module_t *module_p) /**< module */ ecma_make_string_value (module_p->path_p), ECMA_PARSE_STRICT_MODE | ECMA_PARSE_MODULE); - JERRY_CONTEXT (module_top_context_p) = module_p->context_p->parent_p; - + JERRY_CONTEXT (module_current_p) = prev_module_p; jerry_port_release_source (source_p); if (JERRY_UNLIKELY (bytecode_p == NULL)) @@ -908,78 +1033,18 @@ ecma_module_parse (ecma_module_t *module_p) /**< module */ return ECMA_VALUE_ERROR; } + if (ECMA_IS_VALUE_ERROR (ecma_module_parse_referenced_modules ())) + { + ecma_bytecode_deref (bytecode_p); + return ECMA_VALUE_ERROR; + } + module_p->compiled_code_p = bytecode_p; module_p->state = ECMA_MODULE_STATE_PARSED; return ECMA_VALUE_EMPTY; } /* ecma_module_parse */ -/** - * Parses all referenced modules. - * - * @return ECMA_VALUE_ERROR - if an error occured - * ECMA_VALUE_EMPTY - otherwise - */ -ecma_value_t -ecma_module_parse_modules (void) -{ - ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p); - - while (current_p != NULL) - { - ecma_value_t ret_value = ecma_module_parse (current_p); - if (ECMA_IS_VALUE_ERROR (ret_value)) - { - return ret_value; - } - - JERRY_ASSERT (ecma_is_value_empty (ret_value)); - current_p = current_p->next_p; - } - - return ECMA_VALUE_EMPTY; -} /* ecma_module_parse_modules */ - -/** - * Checks if indirect exports in the current context are resolvable. - * Note: See 15.2.1.16.4 / 9. - * - * @return ECMA_VALUE_ERROR - if an error occured - * ECMA_VALUE_EMPTY - otherwise - */ -ecma_value_t -ecma_module_check_indirect_exports (void) -{ - ecma_module_node_t *indirect_export_p = JERRY_CONTEXT (module_top_context_p)->indirect_exports_p; - while (indirect_export_p != NULL) - { - ecma_module_names_t *name_p = indirect_export_p->module_names_p; - while (name_p != NULL) - { - ecma_module_record_t record; - ecma_value_t result = ecma_module_resolve_export (indirect_export_p->module_request_p, - name_p->local_name_p, - &record); - - if (ECMA_IS_VALUE_ERROR (result)) - { - return result; - } - - if (record.module_p == NULL) - { - return ecma_raise_syntax_error (ECMA_ERR_MSG ("Ambiguous indirect export request.")); - } - - name_p = name_p->next_p; - } - - indirect_export_p = indirect_export_p->next_p; - } - - return ECMA_VALUE_EMPTY; -} /* ecma_module_check_indirect_exports */ - /** * Cleans up a list of module names. */ @@ -1016,52 +1081,60 @@ ecma_module_release_module_nodes (ecma_module_node_t *module_node_p) /**< first } /* ecma_module_release_module_nodes */ /** - * Cleans up a module context. - */ -static void -ecma_module_release_module_context (ecma_module_context_t *module_context_p) /**< modle context */ -{ - ecma_module_release_module_nodes (module_context_p->imports_p); - ecma_module_release_module_nodes (module_context_p->local_exports_p); - ecma_module_release_module_nodes (module_context_p->indirect_exports_p); - ecma_module_release_module_nodes (module_context_p->star_exports_p); - - jmem_heap_free_block (module_context_p, sizeof (ecma_module_context_t)); -} /* ecma_module_release_module_context */ - -/** - * Cleans up a module structure. + * Cleans up and releases a module structure including all referenced modules. */ static void ecma_module_release_module (ecma_module_t *module_p) /**< module */ { + ecma_module_state_t state = module_p->state; + ecma_deref_ecma_string (module_p->path_p); +#ifndef JERRY_NDEBUG + module_p->path_p = NULL; +#endif /* JERRY_NDEBUG */ 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; +#endif /* JERRY_NDEBUG */ } - if (module_p->state == ECMA_MODULE_STATE_NATIVE) + if (state == ECMA_MODULE_STATE_NATIVE) { goto finished; } - if (module_p->state >= ECMA_MODULE_STATE_PARSING) + if (state >= ECMA_MODULE_STATE_PARSING) { - ecma_module_release_module_context (module_p->context_p); + ecma_module_release_module_nodes (module_p->imports_p); + ecma_module_release_module_nodes (module_p->local_exports_p); + ecma_module_release_module_nodes (module_p->indirect_exports_p); + ecma_module_release_module_nodes (module_p->star_exports_p); } - if (module_p->state >= ECMA_MODULE_STATE_EVALUATING - && module_p->scope_p != NULL) + if (state == ECMA_MODULE_STATE_ROOT) { + goto finished; + } + + if (state >= ECMA_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->state >= ECMA_MODULE_STATE_PARSED - && module_p->state < ECMA_MODULE_STATE_EVALUATED) + if (state >= ECMA_MODULE_STATE_PARSED + && state < ECMA_MODULE_STATE_EVALUATED) { ecma_bytecode_deref (module_p->compiled_code_p); +#ifndef JERRY_NDEBUG + module_p->compiled_code_p = NULL; +#endif /* JERRY_NDEBUG */ } finished: @@ -1069,21 +1142,16 @@ finished: } /* ecma_module_release_module */ /** - * Cleans up all modules if the current context is the root context. + * Cleans up and releases a module list. */ void -ecma_module_cleanup (void) +ecma_module_cleanup (ecma_module_t *head_p) /**< module */ { - ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p); - while (current_p != NULL) + while (head_p != NULL) { - ecma_module_t *next_p = current_p->next_p; - ecma_module_release_module (current_p); - current_p = next_p; + ecma_module_t *next_p = head_p->next_p; + ecma_module_release_module (head_p); + head_p = next_p; } - - JERRY_CONTEXT (ecma_modules_p) = NULL; - JERRY_CONTEXT (module_top_context_p) = NULL; } /* ecma_module_cleanup */ - #endif /* ENABLED (JERRY_MODULE_SYSTEM) */ diff --git a/jerry-core/ecma/base/ecma-module.h b/jerry-core/ecma/base/ecma-module.h index 3a564bf22..49df29a95 100644 --- a/jerry-core/ecma/base/ecma-module.h +++ b/jerry-core/ecma/base/ecma-module.h @@ -16,11 +16,11 @@ #ifndef ECMA_MODULE_H #define ECMA_MODULE_H -#if ENABLED (JERRY_MODULE_SYSTEM) - #include "common.h" #include "ecma-globals.h" +#if ENABLED (JERRY_MODULE_SYSTEM) + #define ECMA_MODULE_MAX_PATH 255u /** @@ -35,31 +35,6 @@ typedef struct ecma_module_names ecma_string_t *local_name_p; /**< Local name of the item */ } ecma_module_names_t; -typedef struct ecma_module ecma_module_t; - -/** - * Module node to store imports / exports. - */ -typedef struct ecma_module_node -{ - struct ecma_module_node *next_p; /**< next linked list node */ - ecma_module_names_t *module_names_p; /**< names of the requested import/export node */ - ecma_module_t *module_request_p; /**< module structure of the requested module */ -} ecma_module_node_t; - -/** - * Module context containing all import and export nodes. - */ -typedef struct ecma_module_context -{ - struct ecma_module_context *parent_p; /**< parent context */ - ecma_module_node_t *imports_p; /**< import item of the current context */ - ecma_module_node_t *local_exports_p; /**< export item of the current context */ - ecma_module_node_t *indirect_exports_p; /**< export item of the current context */ - ecma_module_node_t *star_exports_p; /**< export item of the current context */ - ecma_module_t *module_p; /**< module request */ -} ecma_module_context_t; - /** * An enum identifing the current state of the module */ @@ -71,21 +46,36 @@ typedef enum ECMA_MODULE_STATE_EVALUATING = 3, /**< module is currently being evaluated */ ECMA_MODULE_STATE_EVALUATED = 4, /**< module has been evaluated */ ECMA_MODULE_STATE_NATIVE = 5, /**< module is native */ + ECMA_MODULE_STATE_ROOT = 6, /**< module is a root module */ } ecma_module_state_t; /** * Module structure storing an instance of a module */ -struct ecma_module +typedef struct ecma_module { - struct ecma_module *next_p; /**< next linked list node */ - ecma_module_state_t state; /**< state of the mode */ - ecma_string_t *path_p; /**< path of the module */ - ecma_module_context_t *context_p; /**< module context of the module */ - ecma_compiled_code_t *compiled_code_p; /**< compiled code of the module */ - ecma_object_t *scope_p; /**< lexica lenvironment of the module */ - ecma_object_t *namespace_object_p; /**< namespace import object of the module */ -}; + /* TODO(dbatyai): These could be compressed pointers */ + struct ecma_module *next_p; /**< next module in the list */ + struct ecma_module_node *imports_p; /**< import requests of the module */ + struct ecma_module_node *local_exports_p; /**< local exports of the module */ + struct ecma_module_node *indirect_exports_p; /**< indirect exports of the module */ + struct ecma_module_node *star_exports_p; /**< star exports of the module*/ + ecma_string_t *path_p; /**< path of the module */ + ecma_compiled_code_t *compiled_code_p; /**< compiled code for the module */ + ecma_object_t *scope_p; /**< lexical lenvironment of the module */ + ecma_object_t *namespace_object_p; /**< namespace object of the module */ + ecma_module_state_t state; /**< evaluation state of the module */ +} ecma_module_t; + +/** + * Module node to store imports / exports. + */ +typedef struct ecma_module_node +{ + struct ecma_module_node *next_p; /**< next linked list node */ + ecma_module_names_t *module_names_p; /**< names of the requested import/export node */ + ecma_module_t *module_request_p; /**< module structure of the requested module */ +} ecma_module_node_t; /** * A record that can be used to store {module, identifier} pairs @@ -126,19 +116,21 @@ void ecma_module_resolve_stack_push (ecma_module_resolve_stack_t **stack_p, ecma_string_t *const export_name_p); void ecma_module_resolve_stack_pop (ecma_module_resolve_stack_t **stack_p); -ecma_string_t *ecma_module_create_normalized_path (const uint8_t *char_p, - prop_length_t size); -ecma_module_t *ecma_module_find_module (ecma_string_t *const path_p); -ecma_module_t *ecma_module_create_native_module (ecma_string_t *const path_p, - ecma_object_t *const namespace_p); -ecma_module_t *ecma_module_find_or_create_module (ecma_string_t *const path_p); +ecma_string_t *ecma_module_create_normalized_path (const lit_utf8_byte_t *char_p, + lit_utf8_size_t size, + ecma_string_t *const base_path_p); -ecma_value_t ecma_module_initialize_current (void); -ecma_value_t ecma_module_parse_modules (void); -ecma_value_t ecma_module_check_indirect_exports (void); +ecma_module_t *ecma_module_find_module (ecma_string_t *const path_p); +ecma_module_t *ecma_module_find_native_module (ecma_string_t *const path_p); + +ecma_value_t ecma_module_parse_referenced_modules (void); +ecma_value_t ecma_module_initialize (ecma_module_t *module_p); + +void ecma_module_initialize_context (ecma_string_t *root_path_p); +void ecma_module_cleanup_context (void); void ecma_module_release_module_nodes (ecma_module_node_t *module_node_p); -void ecma_module_cleanup (void); +void ecma_module_cleanup (ecma_module_t *head_p); #endif /* ENABLED (JERRY_MODULE_SYSTEM) */ #endif /* !ECMA_MODULE_H */ diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 5a5097def..b575afa57 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -115,7 +115,8 @@ typedef enum typedef enum { JERRY_PARSE_NO_OPTS = 0, /**< no options passed */ - JERRY_PARSE_STRICT_MODE = (1 << 0) /**< enable strict mode */ + JERRY_PARSE_STRICT_MODE = (1 << 0), /**< enable strict mode */ + JERRY_PARSE_MODULE = (1 << 1) /**< parse source as an ECMAScript module */ } jerry_parse_opts_t; /** diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 983ea1e11..940431a11 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -150,8 +150,8 @@ struct jerry_context_t #endif /* ENABLED (JERRY_ESNEXT) */ #if ENABLED (JERRY_MODULE_SYSTEM) - ecma_module_t *ecma_modules_p; /**< list of referenced modules */ - ecma_module_context_t *module_top_context_p; /**< top (current) module parser context */ + ecma_module_t *module_list_p; /**< current module context */ + ecma_module_t *module_current_p; /**< current module context */ #endif /* ENABLED (JERRY_MODULE_SYSTEM) */ vm_frame_ctx_t *vm_top_context_p; /**< top (current) interpreter context */ diff --git a/jerry-core/lit/lit-char-helpers.c b/jerry-core/lit/lit-char-helpers.c index 0c0a0995d..f235de281 100644 --- a/jerry-core/lit/lit-char-helpers.c +++ b/jerry-core/lit/lit-char-helpers.c @@ -16,14 +16,16 @@ #include "config.h" #include "ecma-helpers.h" #include "lit-char-helpers.h" -#include "lit-unicode-ranges.inc.h" -#include "lit-unicode-ranges-sup.inc.h" #include "lit-strings.h" +#include "lit-unicode-ranges.inc.h" +#if ENABLED (JERRY_ESNEXT) +#include "lit-unicode-ranges-sup.inc.h" +#endif /* ENABLED (JERRY_ESNEXT) */ #if ENABLED (JERRY_UNICODE_CASE_CONVERSION) #include "lit-unicode-conversions.inc.h" -#include "lit-unicode-conversions-sup.inc.h" #if ENABLED (JERRY_ESNEXT) +#include "lit-unicode-conversions-sup.inc.h" #include "lit-unicode-folding.inc.h" #endif /* ENABLED (JERRY_ESNEXT) */ #endif /* ENABLED (JERRY_UNICODE_CASE_CONVERSION) */ diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 4c9ac2703..d0f0b23c4 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -549,6 +549,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DATAVIEW_UL, "DataView") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FUNCTION_UL, "Function") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INFINITY_UL, "Infinity") +#if ENABLED (JERRY_MODULE_SYSTEM) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RUNNABLE_UL, "Runnable") +#endif #if ENABLED (JERRY_BUILTIN_ERRORS) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_URI_ERROR_UL, "URIError") #endif diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index 66d80b432..848433b1d 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -214,6 +214,7 @@ LIT_MAGIC_STRING_VALUE_OF_UL = "valueOf" LIT_MAGIC_STRING_WEAKMAP_UL = "WeakMap" LIT_MAGIC_STRING_WEAKSET_UL = "WeakSet" LIT_MAGIC_STRING_EPSILON_U = "EPSILON" +LIT_MAGIC_STRING_RUNNABLE_UL = "Runnable" LIT_MAGIC_STRING_DATAVIEW_UL = "DataView" LIT_MAGIC_STRING_FUNCTION_UL = "Function" LIT_MAGIC_STRING_INFINITY_UL = "Infinity" diff --git a/jerry-core/parser/js/js-lexer.h b/jerry-core/parser/js/js-lexer.h index da7b1420c..927723102 100644 --- a/jerry-core/parser/js/js-lexer.h +++ b/jerry-core/parser/js/js-lexer.h @@ -16,6 +16,8 @@ #ifndef JS_LEXER_H #define JS_LEXER_H +#include "ecma-globals.h" + /** \addtogroup parser Parser * @{ * diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 9e487ab4e..561806c50 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -860,8 +860,8 @@ void parser_free_jumps (parser_stack_iterator_t iterator); */ extern const lexer_lit_location_t lexer_default_literal; -void parser_module_add_export_node_to_context (parser_context_t *context_p); -void parser_module_add_import_node_to_context (parser_context_t *context_p); +void parser_module_finalize_export_node (parser_context_t *context_p); +void parser_module_finalize_import_node (parser_context_t *context_p); void parser_module_check_request_place (parser_context_t *context_p); void parser_module_context_init (parser_context_t *context_p); void parser_module_handle_module_specifier (parser_context_t *context_p); diff --git a/jerry-core/parser/js/js-parser-module.c b/jerry-core/parser/js/js-parser-module.c index 26cba3fa8..d8fb7b9af 100644 --- a/jerry-core/parser/js/js-parser-module.c +++ b/jerry-core/parser/js/js-parser-module.c @@ -55,7 +55,7 @@ parser_module_check_duplicate_import (parser_context_t *context_p, /**< parser c module_names_p = module_names_p->next_p; } - ecma_module_node_t *module_node_p = JERRY_CONTEXT (module_top_context_p)->imports_p; + ecma_module_node_t *module_node_p = JERRY_CONTEXT (module_current_p)->imports_p; while (module_node_p != NULL) { module_names_p = module_node_p->module_names_p; @@ -124,7 +124,7 @@ parser_module_check_duplicate_export (parser_context_t *context_p, /**< parser c current_names_p = current_names_p->next_p; } - ecma_module_node_t *export_node_p = JERRY_CONTEXT (module_top_context_p)->local_exports_p; + ecma_module_node_t *export_node_p = JERRY_CONTEXT (module_current_p)->local_exports_p; if (export_node_p != NULL) { JERRY_ASSERT (export_node_p->next_p == NULL); @@ -141,7 +141,7 @@ parser_module_check_duplicate_export (parser_context_t *context_p, /**< parser c } } - export_node_p = JERRY_CONTEXT (module_top_context_p)->indirect_exports_p; + export_node_p = JERRY_CONTEXT (module_current_p)->indirect_exports_p; while (export_node_p != NULL) { ecma_module_names_t *name_p = export_node_p->module_names_p; @@ -167,7 +167,7 @@ parser_module_check_duplicate_export (parser_context_t *context_p, /**< parser c * Add export node to parser context. */ void -parser_module_add_export_node_to_context (parser_context_t *context_p) /**< parser context */ +parser_module_finalize_export_node (parser_context_t *context_p) /**< parser context */ { ecma_module_node_t *module_node_p = context_p->module_current_node_p; context_p->module_current_node_p = NULL; @@ -180,17 +180,17 @@ parser_module_add_export_node_to_context (parser_context_t *context_p) /**< pars if (!module_node_p->module_names_p) { /* If there are no names in the node, then it's a star export. */ - export_list_p = &(JERRY_CONTEXT (module_top_context_p)->star_exports_p); + export_list_p = &(JERRY_CONTEXT (module_current_p)->star_exports_p); } else { - export_list_p = &(JERRY_CONTEXT (module_top_context_p)->indirect_exports_p); + export_list_p = &(JERRY_CONTEXT (module_current_p)->indirect_exports_p); } } else { /* If there is no module request, then it's a local export. */ - export_list_p = &(JERRY_CONTEXT (module_top_context_p)->local_exports_p); + export_list_p = &(JERRY_CONTEXT (module_current_p)->local_exports_p); } /* Check if we have a node with the same module request, append to it if we do. */ @@ -213,7 +213,7 @@ parser_module_add_export_node_to_context (parser_context_t *context_p) /**< pars module_node_p->module_names_p = NULL; } - ecma_module_release_module_nodes (module_node_p); + jmem_heap_free_block (module_node_p, sizeof (ecma_module_node_t)); return; } @@ -222,22 +222,22 @@ parser_module_add_export_node_to_context (parser_context_t *context_p) /**< pars module_node_p->next_p = *export_list_p; *export_list_p = module_node_p; -} /* parser_module_add_export_node_to_context */ +} /* parser_module_finalize_export_node */ /** * Add import node to parser context. */ void -parser_module_add_import_node_to_context (parser_context_t *context_p) /**< parser context */ +parser_module_finalize_import_node (parser_context_t *context_p) /**< parser context */ { ecma_module_node_t *module_node_p = context_p->module_current_node_p; context_p->module_current_node_p = NULL; - ecma_module_node_t *stored_imports = JERRY_CONTEXT (module_top_context_p)->imports_p; + ecma_module_node_t *stored_imports_p = JERRY_CONTEXT (module_current_p)->imports_p; /* Check if we have a node with the same module request, append to it if we do. */ - while (stored_imports != NULL) + while (stored_imports_p != NULL) { - if (stored_imports->module_request_p == module_node_p->module_request_p) + if (stored_imports_p->module_request_p == module_node_p->module_request_p) { ecma_module_names_t *module_names_p = module_node_p->module_names_p; @@ -248,21 +248,21 @@ parser_module_add_import_node_to_context (parser_context_t *context_p) /**< pars module_names_p = module_names_p->next_p; } - module_names_p->next_p = stored_imports->module_names_p; - stored_imports->module_names_p = module_node_p->module_names_p; + module_names_p->next_p = stored_imports_p->module_names_p; + stored_imports_p->module_names_p = module_node_p->module_names_p; module_node_p->module_names_p = NULL; } - ecma_module_release_module_nodes (module_node_p); + jmem_heap_free_block (module_node_p, sizeof (ecma_module_node_t)); return; } - stored_imports = stored_imports->next_p; + stored_imports_p = stored_imports_p->next_p; } - module_node_p->next_p = JERRY_CONTEXT (module_top_context_p)->imports_p; - JERRY_CONTEXT (module_top_context_p)->imports_p = module_node_p; -} /* parser_module_add_import_node_to_context */ + module_node_p->next_p = JERRY_CONTEXT (module_current_p)->imports_p; + JERRY_CONTEXT (module_current_p)->imports_p = module_node_p; +} /* parser_module_finalize_import_node */ /** * Add module names to current module node. @@ -289,50 +289,6 @@ parser_module_add_names_to_node (parser_context_t *context_p, /**< parser contex new_names_p->local_name_p = local_name_p; } /* parser_module_add_names_to_node */ -/** - * Create module context if needed. - */ -void -parser_module_context_init (parser_context_t *context_p) -{ - if (JERRY_CONTEXT (module_top_context_p) == NULL) - { - ecma_module_context_t *module_context_p; - module_context_p = (ecma_module_context_t *) jmem_heap_alloc_block (sizeof (ecma_module_context_t)); - memset (module_context_p, 0, sizeof (ecma_module_context_t)); - JERRY_CONTEXT (module_top_context_p) = module_context_p; - - ecma_string_t *path_str_p = ecma_get_string_from_value (context_p->resource_name); - - lit_utf8_size_t path_str_size; - uint8_t flags = ECMA_STRING_FLAG_EMPTY; - - const lit_utf8_byte_t *path_str_chars_p = ecma_string_get_chars (path_str_p, - &path_str_size, - NULL, - NULL, - &flags); - - ecma_string_t *path_p = ecma_module_create_normalized_path (path_str_chars_p, - (prop_length_t) path_str_size); - - if (path_p == NULL) - { - ecma_ref_ecma_string (path_str_p); - path_p = path_str_p; - } - - ecma_module_t *module_p = ecma_module_find_or_create_module (path_p); - - module_p->state = ECMA_MODULE_STATE_EVALUATED; - /* The lexical scope of the root module does not exist yet. */ - module_p->scope_p = NULL; - - module_p->context_p = module_context_p; - module_context_p->module_p = module_p; - } -} /* parser_module_context_init */ - /** * Create a permanent import/export node from a template node. * @return - the copy of the template if the second parameter is not NULL. @@ -567,7 +523,8 @@ parser_module_check_request_place (parser_context_t *context_p) /**< parser cont if (context_p->last_context_p != NULL || context_p->stack_top_uint8 != 0 || (context_p->status_flags & PARSER_IS_FUNCTION) - || (context_p->global_status_flags & ECMA_PARSE_EVAL)) + || (context_p->global_status_flags & ECMA_PARSE_EVAL) + || (context_p->global_status_flags & ECMA_PARSE_MODULE) == 0) { parser_raise_error (context_p, PARSER_ERR_MODULE_UNEXPECTED); } @@ -592,34 +549,25 @@ parser_module_handle_module_specifier (parser_context_t *context_p) /**< parser ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->lit_object.literal_p->u.char_p, context_p->lit_object.literal_p->prop.length); - ecma_module_t *module_p = ecma_module_find_module (name_p); + ecma_module_t *module_p = ecma_module_find_native_module (name_p); + if (module_p) { ecma_deref_ecma_string (name_p); goto module_found; } - ecma_value_t native = jerry_port_get_native_module (ecma_make_string_value (name_p)); - - if (!ecma_is_value_undefined (native)) - { - JERRY_ASSERT (ecma_is_value_object (native)); - ecma_object_t *module_object_p = ecma_get_object_from_value (native); - - module_p = ecma_module_create_native_module (name_p, module_object_p); - goto module_found; - } - ecma_deref_ecma_string (name_p); ecma_string_t *path_p = ecma_module_create_normalized_path (context_p->lit_object.literal_p->u.char_p, - context_p->lit_object.literal_p->prop.length); + context_p->lit_object.literal_p->prop.length, + JERRY_CONTEXT (module_current_p)->path_p); if (path_p == NULL) { parser_raise_error (context_p, PARSER_ERR_FILE_NOT_FOUND); } - module_p = ecma_module_find_or_create_module (path_p); + module_p = ecma_module_find_module (path_p); module_found: module_node_p->module_request_p = module_p; diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index c5ba6124f..c29bc234b 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -2427,7 +2427,6 @@ parser_parse_import_statement (parser_context_t *context_p) /**< parser context JERRY_ASSERT (context_p->token.type == LEXER_KEYW_IMPORT); parser_module_check_request_place (context_p); - parser_module_context_init (context_p); context_p->module_current_node_p = parser_module_create_module_node (context_p); @@ -2529,7 +2528,7 @@ parser_parse_import_statement (parser_context_t *context_p) /**< parser context } parser_module_handle_module_specifier (context_p); - parser_module_add_import_node_to_context (context_p); + parser_module_finalize_import_node (context_p); context_p->module_current_node_p = NULL; } /* parser_parse_import_statement */ @@ -2543,7 +2542,6 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */ JERRY_ASSERT (context_p->token.type == LEXER_KEYW_EXPORT); parser_module_check_request_place (context_p); - parser_module_context_init (context_p); context_p->module_current_node_p = parser_module_create_module_node (context_p); @@ -2656,7 +2654,7 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */ } context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_DEFAULT_CLASS_OR_FUNC | PARSER_MODULE_STORE_IDENT); - parser_module_add_export_node_to_context (context_p); + parser_module_finalize_export_node (context_p); context_p->module_current_node_p = NULL; } /* parser_parse_export_statement */ #endif /* ENABLED (JERRY_MODULE_SYSTEM) */ diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index de3639fb9..35d6f6b55 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -1396,7 +1396,7 @@ parser_error_to_string (parser_error_t error) /**< error code */ } case PARSER_ERR_MODULE_UNEXPECTED: { - return "Import and export statements must be in the global context."; + return "Unexpected import or export statement."; } case PARSER_ERR_LEFT_BRACE_MULTIPLY_EXPECTED: { diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index c7e62ad97..0031dfe0c 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1811,6 +1811,15 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.status_flags = parse_opts & PARSER_STRICT_MODE_MASK; context.global_status_flags = parse_opts; +#if ENABLED (JERRY_MODULE_SYSTEM) + if (context.global_status_flags & ECMA_PARSE_MODULE) + { + context.status_flags |= PARSER_IS_STRICT; + } + + context.module_current_node_p = NULL; +#endif /* ENABLED (JERRY_MODULE_SYSTEM) */ + if (arg_list_p != NULL) { context.status_flags |= PARSER_IS_FUNCTION; @@ -1934,15 +1943,6 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.breakpoint_info_count = 0; #endif /* ENABLED (JERRY_DEBUGGER) */ -#if ENABLED (JERRY_MODULE_SYSTEM) - if (context.global_status_flags & ECMA_PARSE_MODULE) - { - context.status_flags |= PARSER_IS_STRICT; - } - - context.module_current_node_p = NULL; -#endif /* ENABLED (JERRY_MODULE_SYSTEM) */ - JERRY_ASSERT (context.next_scanner_info_p->source_p == context.source_p); JERRY_ASSERT (context.next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); @@ -2859,12 +2859,6 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */ resource_name, line_str_val, col_str_val); -#if ENABLED (JERRY_MODULE_SYSTEM) - if (JERRY_CONTEXT (module_top_context_p) != NULL) - { - ecma_module_cleanup (); - } -#endif /* ENABLED (JERRY_MODULE_SYSTEM) */ ecma_free_value (col_str_val); ecma_free_value (line_str_val); @@ -2881,16 +2875,6 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */ return NULL; } -#if ENABLED (JERRY_MODULE_SYSTEM) - if (JERRY_CONTEXT (module_top_context_p) != NULL && ECMA_IS_VALUE_ERROR (ecma_module_parse_modules ())) - { - ecma_bytecode_deref (bytecode_p); - ecma_module_cleanup (); - - return NULL; - } -#endif /* ENABLED (JERRY_MODULE_SYSTEM) */ - #if ENABLED (JERRY_DEBUGGER) if ((JERRY_CONTEXT (debugger_flags) & (JERRY_DEBUGGER_CONNECTED | JERRY_DEBUGGER_PARSER_WAIT)) == (JERRY_DEBUGGER_CONNECTED | JERRY_DEBUGGER_PARSER_WAIT)) diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index 6052fc02d..2d253f506 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -1649,8 +1649,6 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } - context_p->global_status_flags |= ECMA_PARSE_MODULE; - scanner_context_p->mode = SCAN_MODE_STATEMENT_END; lexer_next_token (context_p); @@ -1801,8 +1799,6 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ scanner_raise_error (context_p); } - context_p->global_status_flags |= ECMA_PARSE_MODULE; - lexer_next_token (context_p); if (context_p->token.type == LEXER_KEYW_DEFAULT) diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index c27a9e569..d891f3662 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -272,10 +272,9 @@ static const uint16_t vm_decode_table[] JERRY_ATTR_CONST_DATA = * @return ecma value */ ecma_value_t -vm_run_module (const ecma_compiled_code_t *bytecode_p, /**< pointer to bytecode to run */ - ecma_object_t *lex_env_p) /**< pointer to the specified lexenv to run in */ +vm_run_module (ecma_module_t *module_p) /**< module to be executed */ { - const ecma_value_t module_init_result = ecma_module_initialize_current (); + const ecma_value_t module_init_result = ecma_module_initialize (module_p); if (ECMA_IS_VALUE_ERROR (module_init_result)) { @@ -283,10 +282,10 @@ vm_run_module (const ecma_compiled_code_t *bytecode_p, /**< pointer to bytecode } vm_frame_ctx_shared_t shared; - shared.bytecode_header_p = bytecode_p; + shared.bytecode_header_p = module_p->compiled_code_p; shared.status_flags = 0; - return vm_run (&shared, ECMA_VALUE_UNDEFINED, lex_env_p); + return vm_run (&shared, ECMA_VALUE_UNDEFINED, module_p->scope_p); } /* vm_run_module */ #endif /* ENABLED (JERRY_MODULE_SYSTEM) */ @@ -316,27 +315,6 @@ vm_run_global (const ecma_compiled_code_t *bytecode_p) /**< pointer to bytecode ecma_object_t *const global_scope_p = ecma_get_global_scope (global_obj_p); -#if ENABLED (JERRY_MODULE_SYSTEM) - if (JERRY_CONTEXT (module_top_context_p) != NULL) - { - JERRY_ASSERT (JERRY_CONTEXT (module_top_context_p)->parent_p == NULL); - ecma_module_t *module_p = JERRY_CONTEXT (module_top_context_p)->module_p; - - JERRY_ASSERT (module_p->scope_p == NULL); - ecma_ref_object (global_scope_p); - module_p->scope_p = global_scope_p; - - const ecma_value_t module_init_result = ecma_module_initialize_current (); - JERRY_CONTEXT (module_top_context_p) = NULL; - - if (ECMA_IS_VALUE_ERROR (module_init_result)) - { - ecma_module_cleanup (); - return module_init_result; - } - } -#endif /* ENABLED (JERRY_MODULE_SYSTEM) */ - vm_frame_ctx_shared_t shared; shared.bytecode_header_p = bytecode_p; shared.status_flags = 0; diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index c2287180f..4a519e5bf 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -17,6 +17,7 @@ #define VM_H #include "ecma-globals.h" +#include "ecma-module.h" #include "jrt.h" #include "vm-defines.h" @@ -481,7 +482,7 @@ ecma_value_t vm_run_global (const ecma_compiled_code_t *bytecode_p); ecma_value_t vm_run_eval (ecma_compiled_code_t *bytecode_data_p, uint32_t parse_opts); #if ENABLED (JERRY_MODULE_SYSTEM) -ecma_value_t vm_run_module (const ecma_compiled_code_t *bytecode_p, ecma_object_t *lex_env_p); +ecma_value_t vm_run_module (ecma_module_t *module_p); #endif /* ENABLED (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/jerry-main/main-options.c b/jerry-main/main-options.c index da10a9532..f373a0358 100644 --- a/jerry-main/main-options.c +++ b/jerry-main/main-options.c @@ -44,6 +44,7 @@ typedef enum OPT_DEBUGGER_WAIT_SOURCE, OPT_EXEC_SNAP, OPT_EXEC_SNAP_FUNC, + OPT_MODULE, OPT_LOG_LEVEL, OPT_NO_PROMPT, OPT_CALL_ON_EXIT, @@ -85,6 +86,8 @@ static const cli_opt_t main_opts[] = .help = "execute input snapshot file(s)"), CLI_OPT_DEF (.id = OPT_EXEC_SNAP_FUNC, .longopt = "exec-snapshot-func", .meta = "FILE NUM", .help = "execute specific function from input snapshot file(s)"), + CLI_OPT_DEF (.id = OPT_MODULE, .opt = "m", .longopt = "module", .meta = "FILE", + .help = "execute module file"), CLI_OPT_DEF (.id = OPT_LOG_LEVEL, .longopt = "log-level", .meta = "NUM", .help = "set log level (0-3)"), CLI_OPT_DEF (.id = OPT_NO_PROMPT, .longopt = "no-prompt", @@ -307,6 +310,19 @@ main_parse_args (int argc, /**< argc */ break; } + case OPT_MODULE: + { + const uint32_t path_index = cli_consume_path (&cli_state); + + main_source_t *source_p = arguments_p->sources_p + arguments_p->source_count; + arguments_p->source_count++; + + source_p->type = SOURCE_MODULE; + source_p->path_index = path_index; + source_p->snapshot_index = 0; + + break; + } case OPT_LOG_LEVEL: { long int log_level = cli_consume_int (&cli_state); diff --git a/jerry-main/main-options.h b/jerry-main/main-options.h index 4486e5d12..21afad354 100644 --- a/jerry-main/main-options.h +++ b/jerry-main/main-options.h @@ -38,6 +38,7 @@ typedef enum typedef enum { SOURCE_SNAPSHOT, + SOURCE_MODULE, SOURCE_SCRIPT, } main_source_type_t; diff --git a/jerry-main/main-unix.c b/jerry-main/main-unix.c index 08075ce81..abd9e96d7 100644 --- a/jerry-main/main-unix.c +++ b/jerry-main/main-unix.c @@ -86,6 +86,8 @@ restart: goto exit; } + uint32_t parse_opts = JERRY_PARSE_NO_OPTS; + switch (source_file_p->type) { case SOURCE_SNAPSHOT: @@ -98,9 +100,15 @@ restart: jerry_port_release_source (source_p); break; } + case SOURCE_MODULE: + { + parse_opts = JERRY_PARSE_MODULE; + /* FALLTHRU */ + } default: { - assert (source_file_p->type == SOURCE_SCRIPT); + assert (source_file_p->type == SOURCE_SCRIPT + || source_file_p->type == SOURCE_MODULE); if (!jerry_is_valid_utf8_string ((jerry_char_t *) source_p, (jerry_size_t) source_size)) { @@ -113,7 +121,7 @@ restart: strlen (file_path_p), source_p, source_size, - JERRY_PARSE_NO_OPTS); + parse_opts); jerry_port_release_source (source_p); diff --git a/tests/jerry/es.next/module-export-01.js b/tests/jerry/es.next/module-export-01.mjs similarity index 100% rename from tests/jerry/es.next/module-export-01.js rename to tests/jerry/es.next/module-export-01.mjs diff --git a/tests/jerry/es.next/module-export-02.js b/tests/jerry/es.next/module-export-02.mjs similarity index 79% rename from tests/jerry/es.next/module-export-02.js rename to tests/jerry/es.next/module-export-02.mjs index 6fddc5f09..40aa9533e 100644 --- a/tests/jerry/es.next/module-export-02.js +++ b/tests/jerry/es.next/module-export-02.mjs @@ -13,8 +13,8 @@ * limitations under the License. */ -export {} from "module-export-01.js"; -export {aa,} from "module-export-01.js"; -export {bb as b_, cc as c_} from "module-export-01.js"; -export * from "module-export-01.js"; +export {} from "module-export-01.mjs"; +export {aa,} from "module-export-01.mjs"; +export {bb as b_, cc as c_} from "module-export-01.mjs"; +export * from "module-export-01.mjs"; export default function () {return "default"}; diff --git a/tests/jerry/es.next/module-export-03.js b/tests/jerry/es.next/module-export-03.mjs similarity index 95% rename from tests/jerry/es.next/module-export-03.js rename to tests/jerry/es.next/module-export-03.mjs index eb8850c36..3f1d28622 100644 --- a/tests/jerry/es.next/module-export-03.js +++ b/tests/jerry/es.next/module-export-03.mjs @@ -23,4 +23,4 @@ export default class { } } -export * from "module-export-02.js" +export * from "module-export-02.mjs" diff --git a/tests/jerry/es.next/module-export-04.js b/tests/jerry/es.next/module-export-04.mjs similarity index 100% rename from tests/jerry/es.next/module-export-04.js rename to tests/jerry/es.next/module-export-04.mjs diff --git a/tests/jerry/es.next/module-export-05.js b/tests/jerry/es.next/module-export-05.mjs similarity index 89% rename from tests/jerry/es.next/module-export-05.js rename to tests/jerry/es.next/module-export-05.mjs index 5a6349c02..d53e54a5b 100644 --- a/tests/jerry/es.next/module-export-05.js +++ b/tests/jerry/es.next/module-export-05.mjs @@ -13,6 +13,6 @@ * limitations under the License. */ -export * from "module-export-01.js"; -export * from "module-export-04.js"; +export * from "module-export-01.mjs"; +export * from "module-export-04.mjs"; export default a = "str" diff --git a/tests/jerry/es.next/module-export-06.js b/tests/jerry/es.next/module-export-06.mjs similarity index 89% rename from tests/jerry/es.next/module-export-06.js rename to tests/jerry/es.next/module-export-06.mjs index 8c614a490..30ea99e64 100644 --- a/tests/jerry/es.next/module-export-06.js +++ b/tests/jerry/es.next/module-export-06.mjs @@ -14,6 +14,6 @@ */ export {} -export {} from "module-export-01.js"; +export {} from "module-export-01.mjs"; export {}; -export {} from "module-export-04.js" +export {} from "module-export-04.mjs" diff --git a/tests/jerry/es.next/module-export-07.js b/tests/jerry/es.next/module-export-07.mjs similarity index 100% rename from tests/jerry/es.next/module-export-07.js rename to tests/jerry/es.next/module-export-07.mjs diff --git a/tests/jerry/es.next/module-export-08.js b/tests/jerry/es.next/module-export-08.mjs similarity index 94% rename from tests/jerry/es.next/module-export-08.js rename to tests/jerry/es.next/module-export-08.mjs index 5453c7fb8..a5bc4488f 100644 --- a/tests/jerry/es.next/module-export-08.js +++ b/tests/jerry/es.next/module-export-08.mjs @@ -13,5 +13,5 @@ * limitations under the License. */ -export * from "./module-export-04.js"; +export * from "./module-export-04.mjs"; export let c = 5; diff --git a/tests/jerry/es.next/module-export-fail-test.js b/tests/jerry/es.next/module-export-fail-test.mjs similarity index 100% rename from tests/jerry/es.next/module-export-fail-test.js rename to tests/jerry/es.next/module-export-fail-test.mjs diff --git a/tests/jerry/es.next/module-import-01.js b/tests/jerry/es.next/module-import-01.mjs similarity index 74% rename from tests/jerry/es.next/module-import-01.js rename to tests/jerry/es.next/module-import-01.mjs index 54f6826f5..daf90d1c1 100644 --- a/tests/jerry/es.next/module-import-01.js +++ b/tests/jerry/es.next/module-import-01.mjs @@ -13,13 +13,13 @@ * limitations under the License. */ -import "./module-export-01.js"; -import def from "module-export-01.js"; -import {} from "module-export-01.js"; -import {aa as a,} from "module-export-01.js"; -import {bb as b, cc as c} from "module-export-01.js"; -import {x} from "module-export-01.js"; -import * as mod from "module-export-01.js"; +import "./module-export-01.mjs"; +import def from "module-export-01.mjs"; +import {} from "module-export-01.mjs"; +import {aa as a,} from "module-export-01.mjs"; +import {bb as b, cc as c} from "module-export-01.mjs"; +import {x} from "module-export-01.mjs"; +import * as mod from "module-export-01.mjs"; assert (def === "default"); assert (a === "a"); diff --git a/tests/jerry/es.next/module-import-02.js b/tests/jerry/es.next/module-import-02.mjs similarity index 89% rename from tests/jerry/es.next/module-import-02.js rename to tests/jerry/es.next/module-import-02.mjs index 669c7a49e..3ffb8ef93 100644 --- a/tests/jerry/es.next/module-import-02.js +++ b/tests/jerry/es.next/module-import-02.mjs @@ -13,8 +13,8 @@ * limitations under the License. */ -import def, * as mod from "module-export-02.js"; -import {b_, c_,} from "module-export-02.js"; +import def, * as mod from "module-export-02.mjs"; +import {b_, c_,} from "module-export-02.mjs"; assert (def() === "default") assert (mod.aa === "a") diff --git a/tests/jerry/es.next/module-import-03.js b/tests/jerry/es.next/module-import-03.mjs similarity index 92% rename from tests/jerry/es.next/module-import-03.js rename to tests/jerry/es.next/module-import-03.mjs index 11214a9e6..7d8c4dd50 100644 --- a/tests/jerry/es.next/module-import-03.js +++ b/tests/jerry/es.next/module-import-03.mjs @@ -13,7 +13,7 @@ * limitations under the License. */ -import incrementer, {aa, c_, x,} from "module-export-03.js" +import incrementer, {aa, c_, x,} from "module-export-03.mjs" var i = new incrementer(3); assert(i.incr() === 4); assert(i.incr() === 5); diff --git a/tests/jerry/es.next/module-import-04.js b/tests/jerry/es.next/module-import-04.mjs similarity index 83% rename from tests/jerry/es.next/module-import-04.js rename to tests/jerry/es.next/module-import-04.mjs index f0a5181a1..60fd24a6f 100644 --- a/tests/jerry/es.next/module-import-04.js +++ b/tests/jerry/es.next/module-import-04.mjs @@ -13,7 +13,7 @@ * limitations under the License. */ -import "module-import-01.js"; -import "module-export-05.js"; -import "module-export-06.js"; -import "module-export-07.js"; +import "module-import-01.mjs"; +import "module-export-05.mjs"; +import "module-export-06.mjs"; +import "module-export-07.mjs"; diff --git a/tests/jerry/es.next/module-import-05.js b/tests/jerry/es.next/module-import-05.mjs similarity index 94% rename from tests/jerry/es.next/module-import-05.js rename to tests/jerry/es.next/module-import-05.mjs index b04277cf7..04658cda3 100644 --- a/tests/jerry/es.next/module-import-05.js +++ b/tests/jerry/es.next/module-import-05.mjs @@ -13,7 +13,7 @@ * limitations under the License. */ -import * as f from "./module-export-08.js"; +import * as f from "./module-export-08.mjs"; assert (f.c === 5) assert (f.x === 41) diff --git a/tests/jerry/es.next/module-resource-name.js b/tests/jerry/es.next/module-resource-name.mjs similarity index 94% rename from tests/jerry/es.next/module-resource-name.js rename to tests/jerry/es.next/module-resource-name.mjs index 5a3e0d464..33bf743d2 100644 --- a/tests/jerry/es.next/module-resource-name.js +++ b/tests/jerry/es.next/module-resource-name.mjs @@ -22,6 +22,6 @@ getNamePromise(collector).then(() => { collector["end"] = resourceName(); }); function __checkAsync() { assert(collector["start"].endsWith("module-resource-name-export.mjs")); assert(collector["middle"].endsWith("module-resource-name-export.mjs")); - assert(collector["end"].endsWith("module-resource-name.js")); + assert(collector["end"].endsWith("module-resource-name.mjs")); assert(Object.keys(collector).length === 3); } diff --git a/tests/jerry/es.next/regression-test-issue-2842.js b/tests/jerry/es.next/regression-test-issue-2842.mjs similarity index 100% rename from tests/jerry/es.next/regression-test-issue-2842.js rename to tests/jerry/es.next/regression-test-issue-2842.mjs diff --git a/tests/jerry/es.next/regression-test-issue-2975.js b/tests/jerry/es.next/regression-test-issue-2975.js index d7068951a..92d92f86e 100644 --- a/tests/jerry/es.next/regression-test-issue-2975.js +++ b/tests/jerry/es.next/regression-test-issue-2975.js @@ -16,7 +16,7 @@ /* Import/export statements must be in the global scope. */ var eval = eval.bind(); try { - eval('import { c } from "tests/jerry/es.next/module-export-01.js";'); + eval('import { c } from "tests/jerry/es.next/module-export-01.mjs";'); assert (false); } catch (e) { assert (e instanceof SyntaxError); diff --git a/tests/jerry/fail/module-001.js b/tests/jerry/fail/module-001.mjs similarity index 94% rename from tests/jerry/fail/module-001.js rename to tests/jerry/fail/module-001.mjs index 7dba7a828..b590983c7 100644 --- a/tests/jerry/fail/module-001.js +++ b/tests/jerry/fail/module-001.mjs @@ -14,4 +14,4 @@ */ // File does not exist. -import b from "module-exports.js" +import b from "module-exports.mjs" diff --git a/tests/jerry/fail/module-002.js b/tests/jerry/fail/module-002.mjs similarity index 91% rename from tests/jerry/fail/module-002.js rename to tests/jerry/fail/module-002.mjs index c7e266512..b3b3f85e1 100644 --- a/tests/jerry/fail/module-002.js +++ b/tests/jerry/fail/module-002.mjs @@ -13,4 +13,4 @@ * limitations under the License. */ -import { , as b } from "../es.next/module-export-01.js"; +import { , as b } from "../es.next/module-export-01.mjs"; diff --git a/tests/jerry/fail/module-003.js b/tests/jerry/fail/module-003.mjs similarity index 92% rename from tests/jerry/fail/module-003.js rename to tests/jerry/fail/module-003.mjs index b4c22d266..9ec4d2023 100644 --- a/tests/jerry/fail/module-003.js +++ b/tests/jerry/fail/module-003.mjs @@ -13,4 +13,4 @@ * limitations under the License. */ -import , as b from "../es.next/module-export-01.js"; +import , as b from "../es.next/module-export-01.mjs"; diff --git a/tests/jerry/fail/module-004.js b/tests/jerry/fail/module-004.js deleted file mode 100644 index 732365a12..000000000 --- a/tests/jerry/fail/module-004.js +++ /dev/null @@ -1,16 +0,0 @@ -/* 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 { b as , } from "../es.next/module-export-01.js"; diff --git a/tests/jerry/fail/module-004.mjs b/tests/jerry/fail/module-004.mjs new file mode 100644 index 000000000..3aac57984 --- /dev/null +++ b/tests/jerry/fail/module-004.mjs @@ -0,0 +1,16 @@ +/* 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 { b as , } from "../es.next/module-export-01.mjs"; diff --git a/tests/jerry/fail/module-005.js b/tests/jerry/fail/module-005.mjs similarity index 92% rename from tests/jerry/fail/module-005.js rename to tests/jerry/fail/module-005.mjs index 7b6d7bb5f..1c05584e2 100644 --- a/tests/jerry/fail/module-005.js +++ b/tests/jerry/fail/module-005.mjs @@ -14,4 +14,4 @@ */ /* Named imports must be in a NamedImports block. */ -import b as , from "../es.next/module-export-01.js"; +import b as , from "../es.next/module-export-01.mjs"; diff --git a/tests/jerry/fail/module-006.js b/tests/jerry/fail/module-006.mjs similarity index 100% rename from tests/jerry/fail/module-006.js rename to tests/jerry/fail/module-006.mjs diff --git a/tests/jerry/fail/module-007.js b/tests/jerry/fail/module-007.mjs similarity index 95% rename from tests/jerry/fail/module-007.js rename to tests/jerry/fail/module-007.mjs index 5a0ca65f9..8265b1668 100644 --- a/tests/jerry/fail/module-007.js +++ b/tests/jerry/fail/module-007.mjs @@ -14,4 +14,4 @@ */ /* Module requests must always be evaluated. */ -import "./module-sideeffect.js" +import "./module-sideeffect.mjs" diff --git a/tests/jerry/fail/module-008.js b/tests/jerry/fail/module-008.mjs similarity index 100% rename from tests/jerry/fail/module-008.js rename to tests/jerry/fail/module-008.mjs diff --git a/tests/jerry/fail/module-009.js b/tests/jerry/fail/module-009.mjs similarity index 100% rename from tests/jerry/fail/module-009.js rename to tests/jerry/fail/module-009.mjs diff --git a/tests/jerry/fail/module-010.js b/tests/jerry/fail/module-010.mjs similarity index 91% rename from tests/jerry/fail/module-010.js rename to tests/jerry/fail/module-010.mjs index ca970f7f0..15af24a8c 100644 --- a/tests/jerry/fail/module-010.js +++ b/tests/jerry/fail/module-010.mjs @@ -14,4 +14,4 @@ */ /* Can't have duplicate local bindings */ -import { c as a, d as a } from "../es.next/module-export-01.js"; +import { c as a, d as a } from "../es.next/module-export-01.mjs"; diff --git a/tests/jerry/fail/module-011.js b/tests/jerry/fail/module-011.mjs similarity index 100% rename from tests/jerry/fail/module-011.js rename to tests/jerry/fail/module-011.mjs diff --git a/tests/jerry/fail/module-012.js b/tests/jerry/fail/module-012.mjs similarity index 100% rename from tests/jerry/fail/module-012.js rename to tests/jerry/fail/module-012.mjs diff --git a/tests/jerry/fail/module-013.js b/tests/jerry/fail/module-013.mjs similarity index 100% rename from tests/jerry/fail/module-013.js rename to tests/jerry/fail/module-013.mjs diff --git a/tests/jerry/fail/module-014.js b/tests/jerry/fail/module-014.mjs similarity index 92% rename from tests/jerry/fail/module-014.js rename to tests/jerry/fail/module-014.mjs index 5deeeff88..51c620066 100644 --- a/tests/jerry/fail/module-014.js +++ b/tests/jerry/fail/module-014.mjs @@ -15,5 +15,5 @@ /* Import/export statements must be in the global scope. */ if (true) { - import { c } from "../es.next/module-export-01.js"; + import { c } from "../es.next/module-export-01.mjs"; } diff --git a/tests/jerry/fail/module-015.js b/tests/jerry/fail/module-015.mjs similarity index 92% rename from tests/jerry/fail/module-015.js rename to tests/jerry/fail/module-015.mjs index ecf41e7e4..63efbe35d 100644 --- a/tests/jerry/fail/module-015.js +++ b/tests/jerry/fail/module-015.mjs @@ -15,5 +15,5 @@ /* Import/export statements must be in the global scope. */ function someFunction() { - import { c } from "../es.next/module-export-01.js"; + import { c } from "../es.next/module-export-01.mjs"; } diff --git a/tests/jerry/fail/module-016.js b/tests/jerry/fail/module-016.mjs similarity index 91% rename from tests/jerry/fail/module-016.js rename to tests/jerry/fail/module-016.mjs index 100871b08..2e22cb69b 100644 --- a/tests/jerry/fail/module-016.js +++ b/tests/jerry/fail/module-016.mjs @@ -14,4 +14,4 @@ */ /* Import/export statements must be in the global scope. */ -eval ('import { c } from "../es.next/module-export-01.js";'); +eval ('import { c } from "../es.next/module-export-01.mjs";'); diff --git a/tests/jerry/fail/module-017.js b/tests/jerry/fail/module-017.mjs similarity index 92% rename from tests/jerry/fail/module-017.js rename to tests/jerry/fail/module-017.mjs index 642ef9dea..e038a0173 100644 --- a/tests/jerry/fail/module-017.js +++ b/tests/jerry/fail/module-017.mjs @@ -14,4 +14,4 @@ */ /* NamedImports must always be followed by a FromClause. */ -import { b }, from "../es.next/module-export-01.js" +import { b }, from "../es.next/module-export-01.mjs" diff --git a/tests/jerry/fail/module-018.js b/tests/jerry/fail/module-018.mjs similarity index 91% rename from tests/jerry/fail/module-018.js rename to tests/jerry/fail/module-018.mjs index 5face7e7c..60c9a96db 100644 --- a/tests/jerry/fail/module-018.js +++ b/tests/jerry/fail/module-018.mjs @@ -14,4 +14,4 @@ */ /* An import statement can have either a NameSpaceImport or NamedIpmorts */ -import * as mod, { b } from "../es.next/module-export-01.js" +import * as mod, { b } from "../es.next/module-export-01.mjs" diff --git a/tests/jerry/fail/module-019.js b/tests/jerry/fail/module-019.mjs similarity index 100% rename from tests/jerry/fail/module-019.js rename to tests/jerry/fail/module-019.mjs diff --git a/tests/jerry/fail/module-020.js b/tests/jerry/fail/module-020.mjs similarity index 92% rename from tests/jerry/fail/module-020.js rename to tests/jerry/fail/module-020.mjs index f99ecf9c3..4a160d547 100644 --- a/tests/jerry/fail/module-020.js +++ b/tests/jerry/fail/module-020.mjs @@ -14,4 +14,4 @@ */ /* '*' is not valid inside NamedImports. */ -import { *, d } from "../es.next/module-imported-01.js" +import { *, d } from "../es.next/module-imported-01.mjs" diff --git a/tests/jerry/fail/module-021.js b/tests/jerry/fail/module-021.mjs similarity index 86% rename from tests/jerry/fail/module-021.js rename to tests/jerry/fail/module-021.mjs index 498273360..016bb3778 100644 --- a/tests/jerry/fail/module-021.js +++ b/tests/jerry/fail/module-021.mjs @@ -14,5 +14,5 @@ */ /* Can't have duplicated local bindings. */ -import { b } from "../es.next/module-export-01.js" -import { b } from "../es.next/module-export-02.js" +import { b } from "../es.next/module-export-01.mjs" +import { b } from "../es.next/module-export-02.mjs" diff --git a/tests/jerry/fail/module-022.js b/tests/jerry/fail/module-022.mjs similarity index 93% rename from tests/jerry/fail/module-022.js rename to tests/jerry/fail/module-022.mjs index 3d9f0688f..4ad7d3af0 100644 --- a/tests/jerry/fail/module-022.js +++ b/tests/jerry/fail/module-022.mjs @@ -14,4 +14,4 @@ */ /* FromClause must follow an ImportClause. */ -import from "../es.next/module-export-02.js" +import from "../es.next/module-export-02.mjs" diff --git a/tests/jerry/fail/module-023.js b/tests/jerry/fail/module-023.mjs similarity index 93% rename from tests/jerry/fail/module-023.js rename to tests/jerry/fail/module-023.mjs index 03d072f41..568207778 100644 --- a/tests/jerry/fail/module-023.js +++ b/tests/jerry/fail/module-023.mjs @@ -14,4 +14,4 @@ */ /* Namespace imports must have a local name. */ -import * from "../es.next/module-export-01.js" +import * from "../es.next/module-export-01.mjs" diff --git a/tests/jerry/fail/module-024.js b/tests/jerry/fail/module-024.mjs similarity index 92% rename from tests/jerry/fail/module-024.js rename to tests/jerry/fail/module-024.mjs index be81cf929..1e9f3bad5 100644 --- a/tests/jerry/fail/module-024.js +++ b/tests/jerry/fail/module-024.mjs @@ -14,4 +14,4 @@ */ /* Star exports can't have an export name. */ -export * as star from "../es.next/module-export-01.js" +export * as star from "../es.next/module-export-01.mjs" diff --git a/tests/jerry/fail/module-025.js b/tests/jerry/fail/module-025.mjs similarity index 93% rename from tests/jerry/fail/module-025.js rename to tests/jerry/fail/module-025.mjs index c26d673ad..cb05adc9a 100644 --- a/tests/jerry/fail/module-025.js +++ b/tests/jerry/fail/module-025.mjs @@ -14,4 +14,4 @@ */ /* Indirect exports must be checked if they are resolvable. */ -export { l } from "../es.next/module-export-01.js" +export { l } from "../es.next/module-export-01.mjs" diff --git a/tests/jerry/fail/module-026.js b/tests/jerry/fail/module-026.mjs similarity index 94% rename from tests/jerry/fail/module-026.js rename to tests/jerry/fail/module-026.mjs index b4eef17ba..9d11cfa71 100644 --- a/tests/jerry/fail/module-026.js +++ b/tests/jerry/fail/module-026.mjs @@ -14,4 +14,4 @@ */ /* Can't have circular imports/exports. */ -export { b } from "./module-027.js" +export { b } from "./module-027.mjs" diff --git a/tests/jerry/fail/module-027.js b/tests/jerry/fail/module-027.mjs similarity index 94% rename from tests/jerry/fail/module-027.js rename to tests/jerry/fail/module-027.mjs index 87b62a9da..b50e3475b 100644 --- a/tests/jerry/fail/module-027.js +++ b/tests/jerry/fail/module-027.mjs @@ -14,4 +14,4 @@ */ /* Can't have circular imports/exports. */ -export { b } from "./module-026.js" +export { b } from "./module-026.mjs" diff --git a/tests/jerry/fail/module-028.js b/tests/jerry/fail/module-028.mjs similarity index 92% rename from tests/jerry/fail/module-028.js rename to tests/jerry/fail/module-028.mjs index 8db2d5f04..08ede2d75 100644 --- a/tests/jerry/fail/module-028.js +++ b/tests/jerry/fail/module-028.mjs @@ -14,4 +14,4 @@ */ /* Ambiguous import */ -import { x } from "../es.next/module-export-05.js" +import { x } from "../es.next/module-export-05.mjs" diff --git a/tests/jerry/fail/module-029.js b/tests/jerry/fail/module-029.mjs similarity index 91% rename from tests/jerry/fail/module-029.js rename to tests/jerry/fail/module-029.mjs index 1f4929eab..b04e2a382 100644 --- a/tests/jerry/fail/module-029.js +++ b/tests/jerry/fail/module-029.mjs @@ -14,4 +14,4 @@ */ /* Import/export statements must be in the global scope. */ -Function('','import { c } from "../es.next/module-export-01.js";') +Function('','import { c } from "../es.next/module-export-01.mjs";') diff --git a/tests/jerry/fail/module-030.js b/tests/jerry/fail/module-030.mjs similarity index 93% rename from tests/jerry/fail/module-030.js rename to tests/jerry/fail/module-030.mjs index 3cd2f89b5..d9dc5adc5 100644 --- a/tests/jerry/fail/module-030.js +++ b/tests/jerry/fail/module-030.mjs @@ -14,4 +14,4 @@ */ /* No default export found. */ -import def from "../es.next/module-export-06.js" +import def from "../es.next/module-export-06.mjs" diff --git a/tests/jerry/fail/module-031.js b/tests/jerry/fail/module-031.mjs similarity index 100% rename from tests/jerry/fail/module-031.js rename to tests/jerry/fail/module-031.mjs diff --git a/tests/jerry/fail/module-032.js b/tests/jerry/fail/module-032.mjs similarity index 91% rename from tests/jerry/fail/module-032.js rename to tests/jerry/fail/module-032.mjs index 6dd05c8c9..fb6898c3a 100644 --- a/tests/jerry/fail/module-032.js +++ b/tests/jerry/fail/module-032.mjs @@ -14,4 +14,4 @@ */ let a; -import { a } from "../es.next/module-export-fail-test.js"; +import { a } from "../es.next/module-export-fail-test.mjs"; diff --git a/tests/jerry/fail/module-033.js b/tests/jerry/fail/module-033.mjs similarity index 91% rename from tests/jerry/fail/module-033.js rename to tests/jerry/fail/module-033.mjs index 08dba16ad..235927d9e 100644 --- a/tests/jerry/fail/module-033.js +++ b/tests/jerry/fail/module-033.mjs @@ -14,4 +14,4 @@ */ var a; -import { a } from "../es.next/module-export-fail-test.js"; +import { a } from "../es.next/module-export-fail-test.mjs"; diff --git a/tests/jerry/fail/module-034.js b/tests/jerry/fail/module-034.mjs similarity index 91% rename from tests/jerry/fail/module-034.js rename to tests/jerry/fail/module-034.mjs index c4375a426..7723b8c34 100644 --- a/tests/jerry/fail/module-034.js +++ b/tests/jerry/fail/module-034.mjs @@ -13,5 +13,5 @@ * limitations under the License. */ -import { a } from "../es.next/module-export-fail-test.js"; +import { a } from "../es.next/module-export-fail-test.mjs"; class a {}; diff --git a/tests/jerry/fail/module-035.js b/tests/jerry/fail/module-035.mjs similarity index 91% rename from tests/jerry/fail/module-035.js rename to tests/jerry/fail/module-035.mjs index e332f5a93..d19fce94b 100644 --- a/tests/jerry/fail/module-035.js +++ b/tests/jerry/fail/module-035.mjs @@ -13,5 +13,5 @@ * limitations under the License. */ -import { a } from "../es.next/module-export-fail-test.js"; +import { a } from "../es.next/module-export-fail-test.mjs"; function a() {} diff --git a/tests/jerry/fail/module-036.js b/tests/jerry/fail/module-036.mjs similarity index 95% rename from tests/jerry/fail/module-036.js rename to tests/jerry/fail/module-036.mjs index 8550de8ad..ef0387abc 100644 --- a/tests/jerry/fail/module-036.js +++ b/tests/jerry/fail/module-036.mjs @@ -13,4 +13,4 @@ * limitations under the License. */ -import "./module-export-001.js" +import "./module-await-001.mjs" diff --git a/tests/jerry/fail/module-037.js b/tests/jerry/fail/module-037.mjs similarity index 95% rename from tests/jerry/fail/module-037.js rename to tests/jerry/fail/module-037.mjs index 29f3dba46..ef0387abc 100644 --- a/tests/jerry/fail/module-037.js +++ b/tests/jerry/fail/module-037.mjs @@ -13,4 +13,4 @@ * limitations under the License. */ -import "./module-await-001.js" +import "./module-await-001.mjs" diff --git a/tests/jerry/fail/module-await-001.js b/tests/jerry/fail/module-await-001.mjs similarity index 100% rename from tests/jerry/fail/module-await-001.js rename to tests/jerry/fail/module-await-001.mjs diff --git a/tests/jerry/fail/module-export-001.js b/tests/jerry/fail/module-export-001.mjs similarity index 100% rename from tests/jerry/fail/module-export-001.js rename to tests/jerry/fail/module-export-001.mjs diff --git a/tests/jerry/fail/module-sideeffect.js b/tests/jerry/fail/module-sideeffect.mjs similarity index 100% rename from tests/jerry/fail/module-sideeffect.js rename to tests/jerry/fail/module-sideeffect.mjs diff --git a/tests/jerry/fail/regression-test-issue-2896.js b/tests/jerry/fail/regression-test-issue-2896.js index 94a60abd9..720264eee 100644 --- a/tests/jerry/fail/regression-test-issue-2896.js +++ b/tests/jerry/fail/regression-test-issue-2896.js @@ -12,5 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -export {} from "dummy.js"; -export {} from "../es.next/module-export-04.js"; +export {} from "dummy.mjs"; +export {} from "../es.next/module-export-04.mjs"; diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index 592b78a0c..36f2bb80c 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -328,8 +328,6 @@ - - @@ -414,7 +412,6 @@ - @@ -457,7 +454,6 @@ - @@ -487,7 +483,6 @@ - @@ -498,13 +493,6 @@ - - - - - - - @@ -576,13 +564,9 @@ - - - - @@ -699,8 +683,6 @@ - - @@ -5242,7 +5224,6 @@ - diff --git a/tools/runners/run-test-suite.py b/tools/runners/run-test-suite.py index 3c3967c4c..a5718d154 100755 --- a/tools/runners/run-test-suite.py +++ b/tools/runners/run-test-suite.py @@ -54,7 +54,9 @@ def get_tests(test_dir, test_list, skip_list): if test_dir: tests = [] for root, _, files in os.walk(test_dir): - tests.extend([os.path.join(root, test_file) for test_file in files if test_file.endswith('.js')]) + for test_file in files: + if test_file.endswith('.js') or test_file.endswith('.mjs'): + tests.extend([os.path.join(root, test_file)]) if test_list: dirname = os.path.dirname(test_list) @@ -136,7 +138,12 @@ def run_normal_tests(args, tests): tested += 1 test_path = os.path.relpath(test) is_expected_to_fail = os.path.join(os.path.sep, 'fail', '') in test - (returncode, stdout) = execute_test_command(test_cmd + [test]) + + test_argument = [] + if test.endswith('.mjs'): + test_argument.extend(['-m']) + + (returncode, stdout) = execute_test_command(test_cmd + test_argument + [test]) if (returncode == 0 and not is_expected_to_fail) or (returncode == 1 and is_expected_to_fail): passed += 1 diff --git a/tools/runners/test262-harness.py b/tools/runners/test262-harness.py index f2a36d7ab..a5ce19a67 100755 --- a/tools/runners/test262-harness.py +++ b/tools/runners/test262-harness.py @@ -367,6 +367,8 @@ def build_options(): help="Command to print from console") result.add_option("--list-includes", default=False, action="store_true", help="List includes required by tests") + result.add_option("--module-flag", default="-m", + help="List includes required by tests") return result @@ -481,7 +483,7 @@ class TestResult(object): class TestCase(object): - def __init__(self, suite, name, full_path, strict_mode, command_template): + def __init__(self, suite, name, full_path, strict_mode, command_template, module_flag): self.suite = suite self.name = name self.full_path = full_path @@ -495,6 +497,7 @@ class TestCase(object): test_record.pop("commentary", None) # do not throw if missing self.test_record = test_record self.command_template = command_template + self.module_flag = module_flag self.validate() @@ -543,6 +546,9 @@ class TestCase(object): def is_async_test(self): return 'async' in self.test_record or '$DONE' in self.test + def is_module(self): + return 'module' in self.test_record + def get_include_list(self): if self.test_record.get('includes'): return self.test_record['includes'] @@ -618,9 +624,16 @@ class TestCase(object): def run_test_in(self, tmp): tmp.write(self.get_source()) tmp.close() + + if self.is_module(): + arg = self.module_flag + ' ' + tmp.name + else: + arg = tmp.name + command = TestCase.instantiate_template(self.command_template, { - 'path': tmp.name + 'path': arg }) + (code, out, err) = TestCase.execute(command) return TestResult(code, out, err, self) @@ -695,15 +708,16 @@ def percent_format(partial, total): class TestSuite(object): - def __init__(self, root, strict_only, non_strict_only, unmarked_default, print_handle, exclude_list_path): - self.test_root = path.join(root, 'test') - self.lib_root = path.join(root, 'harness') - self.strict_only = strict_only - self.non_strict_only = non_strict_only - self.unmarked_default = unmarked_default - self.print_handle = print_handle + def __init__(self, options): + self.test_root = path.join(options.tests, 'test') + self.lib_root = path.join(options.tests, 'harness') + self.strict_only = options.strict_only + self.non_strict_only = options.non_strict_only + self.unmarked_default = options.unmarked_default + self.print_handle = options.print_handle self.include_cache = {} - self.exclude_list_path = exclude_list_path + self.exclude_list_path = options.exclude_list + self.module_flag = options.module_flag self.logf = None def _load_excludes(self): @@ -772,12 +786,12 @@ class TestSuite(object): print('Excluded: ' + rel_path) else: if not self.non_strict_only: - strict_case = TestCase(self, name, full_path, True, command_template) + strict_case = TestCase(self, name, full_path, True, command_template, self.module_flag) if not strict_case.is_no_strict(): if strict_case.is_only_strict() or self.unmarked_default in ['both', 'strict']: cases.append(strict_case) if not self.strict_only: - non_strict_case = TestCase(self, name, full_path, False, command_template) + non_strict_case = TestCase(self, name, full_path, False, command_template, self.module_flag) if not non_strict_case.is_only_strict(): if non_strict_case.is_no_strict() or self.unmarked_default in ['both', 'non_strict']: cases.append(non_strict_case) @@ -901,12 +915,7 @@ def main(): (options, args) = parser.parse_args() validate_options(options) - test_suite = TestSuite(options.tests, - options.strict_only, - options.non_strict_only, - options.unmarked_default, - options.print_handle, - options.exclude_list) + test_suite = TestSuite(options) test_suite.validate() if options.loglevel == 'debug':