Fix lexical scoping between scripts (#3558)

This change fixes the handling of lexical blocks when executing multiple
scripts, and also fixes a few issues with module environments.

After this change, all script files will run in the same context and
will have access to lexically scoped global variables of previous
scripts, and module environments will no longer have a bound global
'this' value.

The REPL implementation in main-unix is also fixed to correctly handle
lexically scoped variables.

Fixes #3561.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
This commit is contained in:
Dániel Bátyai
2020-02-21 13:30:48 +01:00
committed by GitHub
parent b0a575b049
commit 68909fc5de
22 changed files with 416 additions and 129 deletions
+2 -2
View File
@@ -44,7 +44,7 @@ ecma_init (void)
JERRY_CONTEXT (ecma_gc_mark_recursion_limit) = JERRY_GC_MARK_LIMIT;
#endif /* (JERRY_GC_MARK_LIMIT != 0) */
ecma_init_global_lex_env ();
ecma_init_global_environment ();
#if ENABLED (JERRY_PROPRETY_HASHMAP)
JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_ON;
@@ -77,7 +77,7 @@ ecma_finalize (void)
JERRY_ASSERT (JERRY_CONTEXT (current_function_obj_p) == NULL);
#endif /* ENABLED (JERRY_ES2015) */
ecma_finalize_global_lex_env ();
ecma_finalize_global_environment ();
uint8_t runs = 0;
do
{
+57 -7
View File
@@ -660,7 +660,7 @@ ecma_module_evaluate (ecma_module_t *module_p) /**< module */
* @return ECMA_VALUE_ERROR - if an error occured
* ECMA_VALUE_EMPTY - otherwise
*/
ecma_value_t
static ecma_value_t
ecma_module_connect_imports (void)
{
ecma_module_context_t *current_context_p = JERRY_CONTEXT (module_top_context_p);
@@ -669,6 +669,39 @@ ecma_module_connect_imports (void)
JERRY_ASSERT (ecma_is_lexical_environment (local_env_p));
ecma_module_node_t *import_node_p = current_context_p->imports_p;
/* Check that the imported bindings don't exist yet. */
while (import_node_p != NULL)
{
ecma_module_names_t *import_names_p = import_node_p->module_names_p;
while (import_names_p != NULL)
{
ecma_object_t *lex_env_p = local_env_p;
ecma_property_t *binding_p = NULL;
if (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK)
{
binding_p = ecma_find_named_property (lex_env_p, import_names_p->local_name_p);
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
}
if (binding_p != NULL || ecma_op_has_binding (lex_env_p, import_names_p->local_name_p))
{
return ecma_raise_syntax_error (ECMA_ERR_MSG ("Imported binding shadows local variable."));
}
import_names_p = import_names_p->next_p;
}
import_node_p = import_node_p->next_p;
}
import_node_p = current_context_p->imports_p;
/* Resolve imports and create local bindings. */
while (import_node_p != NULL)
{
ecma_value_t result = ecma_module_evaluate (import_node_p->module_request_p);
@@ -761,6 +794,26 @@ ecma_module_connect_imports (void)
return ECMA_VALUE_EMPTY;
} /* ecma_module_connect_imports */
/**
* Initialize the current module by creating the local binding for the imported variables
* and verifying indirect exports.
*
* @return ECMA_VALUE_ERROR - if an error occured
* ECMA_VALUE_EMPTY - otherwise
*/
ecma_value_t
ecma_module_initialize_current (void)
{
ecma_value_t ret_value = ecma_module_connect_imports ();
if (ecma_is_value_empty (ret_value))
{
ret_value = ecma_module_check_indirect_exports ();
}
return ret_value;
} /* ecma_module_initialize_current */
/**
* Parses an EcmaScript module.
*
@@ -975,7 +1028,8 @@ ecma_module_release_module (ecma_module_t *module_p) /**< module */
ecma_module_release_module_context (module_p->context_p);
}
if (module_p->state >= ECMA_MODULE_STATE_EVALUATING)
if (module_p->state >= ECMA_MODULE_STATE_EVALUATING
&& module_p->scope_p != NULL)
{
ecma_deref_object (module_p->scope_p);
}
@@ -996,11 +1050,6 @@ finished:
void
ecma_module_cleanup (void)
{
if (JERRY_CONTEXT (module_top_context_p)->parent_p != NULL)
{
return;
}
ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p);
while (current_p != NULL)
{
@@ -1009,6 +1058,7 @@ ecma_module_cleanup (void)
current_p = next_p;
}
JERRY_CONTEXT (ecma_modules_p) = NULL;
JERRY_CONTEXT (module_top_context_p) = NULL;
} /* ecma_module_cleanup */
+1 -1
View File
@@ -133,7 +133,7 @@ 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_value_t ecma_module_connect_imports (void);
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);
+52 -9
View File
@@ -37,25 +37,35 @@
* Initialize Global environment
*/
void
ecma_init_global_lex_env (void)
ecma_init_global_environment (void)
{
ecma_object_t *glob_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL);
ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL,
glob_obj_p,
ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_lex_env_cp), global_lex_env_p);
} /* ecma_init_global_lex_env */
ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_env_cp), global_lex_env_p);
#if ENABLED (JERRY_ES2015)
ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_scope_cp), global_lex_env_p);
#endif /* ENABLED (JERRY_ES2015) */
} /* ecma_init_global_environment */
/**
* Finalize Global environment
*/
void
ecma_finalize_global_lex_env (void)
ecma_finalize_global_environment (void)
{
ecma_deref_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_lex_env_cp)));
JERRY_CONTEXT (ecma_global_lex_env_cp) = JMEM_CP_NULL;
} /* ecma_finalize_global_lex_env */
#if ENABLED (JERRY_ES2015)
if (JERRY_CONTEXT (ecma_global_scope_cp) != JERRY_CONTEXT (ecma_global_env_cp))
{
ecma_deref_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_scope_cp)));
}
JERRY_CONTEXT (ecma_global_scope_cp) = JMEM_CP_NULL;
#endif /* ENABLED (JERRY_ES2015) */
ecma_deref_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_env_cp)));
JERRY_CONTEXT (ecma_global_env_cp) = JMEM_CP_NULL;
} /* ecma_finalize_global_environment */
/**
* Get reference to Global lexical environment
@@ -66,10 +76,43 @@ ecma_finalize_global_lex_env (void)
ecma_object_t *
ecma_get_global_environment (void)
{
JERRY_ASSERT (JERRY_CONTEXT (ecma_global_lex_env_cp) != JMEM_CP_NULL);
return ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_lex_env_cp));
JERRY_ASSERT (JERRY_CONTEXT (ecma_global_env_cp) != JMEM_CP_NULL);
return ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_env_cp));
} /* ecma_get_global_environment */
#if ENABLED (JERRY_ES2015)
/**
* Create the global lexical block on top of the global environment.
*/
void
ecma_create_global_lexical_block (void)
{
if (JERRY_CONTEXT (ecma_global_scope_cp) == JERRY_CONTEXT (ecma_global_env_cp))
{
ecma_object_t *global_scope_p = ecma_create_decl_lex_env (ecma_get_global_environment ());
global_scope_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_BLOCK;
ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_scope_cp), global_scope_p);
}
} /* ecma_create_global_lexical_block */
#endif /* ENABLED (JERRY_ES2015) */
/**
* Get reference to Global lexical scope
* without increasing its reference count.
*
* @return pointer to the object's instance
*/
ecma_object_t *
ecma_get_global_scope (void)
{
#if ENABLED (JERRY_ES2015)
JERRY_ASSERT (JERRY_CONTEXT (ecma_global_scope_cp) != JMEM_CP_NULL);
return ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_scope_cp));
#else /* !ENABLED (JERRY_ES2015) */
return ecma_get_global_environment ();
#endif /* !ENABLED (JERRY_ES2015) */
} /* ecma_get_global_scope */
/**
* @}
*/
+6 -2
View File
@@ -30,9 +30,13 @@
* @{
*/
void ecma_init_global_lex_env (void);
void ecma_finalize_global_lex_env (void);
void ecma_init_global_environment (void);
void ecma_finalize_global_environment (void);
ecma_object_t *ecma_get_global_environment (void);
ecma_object_t *ecma_get_global_scope (void);
#if ENABLED (JERRY_ES2015)
void ecma_create_global_lexical_block (void);
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
void ecma_module_add_lex_env (ecma_object_t *lex_env_p);
+1 -1
View File
@@ -106,7 +106,7 @@ ecma_value_t
ecma_op_is_prop_unscopable (ecma_object_t *lex_env_p, /**< lexical environment */
ecma_string_t *prop_name_p) /**< property's name */
{
if (lex_env_p == ecma_get_global_environment ())
if (lex_env_p == ecma_get_global_scope ())
{
return ECMA_VALUE_FALSE;
}