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
+8 -1
View File
@@ -989,7 +989,14 @@ jerry_snapshot_result (const uint32_t *snapshot_p, /**< snapshot */
if (as_function) if (as_function)
{ {
ecma_object_t *lex_env_p = ecma_get_global_environment (); #if ENABLED (JERRY_ES2015)
if (bytecode_p->status_flags & CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED)
{
ecma_create_global_lexical_block ();
}
#endif /* ENABLED (JERRY_ES2015) */
ecma_object_t *lex_env_p = ecma_get_global_scope ();
ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_p); ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_p);
if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
+2 -2
View File
@@ -44,7 +44,7 @@ ecma_init (void)
JERRY_CONTEXT (ecma_gc_mark_recursion_limit) = JERRY_GC_MARK_LIMIT; JERRY_CONTEXT (ecma_gc_mark_recursion_limit) = JERRY_GC_MARK_LIMIT;
#endif /* (JERRY_GC_MARK_LIMIT != 0) */ #endif /* (JERRY_GC_MARK_LIMIT != 0) */
ecma_init_global_lex_env (); ecma_init_global_environment ();
#if ENABLED (JERRY_PROPRETY_HASHMAP) #if ENABLED (JERRY_PROPRETY_HASHMAP)
JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_ON; 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); JERRY_ASSERT (JERRY_CONTEXT (current_function_obj_p) == NULL);
#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_ES2015) */
ecma_finalize_global_lex_env (); ecma_finalize_global_environment ();
uint8_t runs = 0; uint8_t runs = 0;
do 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 * @return ECMA_VALUE_ERROR - if an error occured
* ECMA_VALUE_EMPTY - otherwise * ECMA_VALUE_EMPTY - otherwise
*/ */
ecma_value_t static ecma_value_t
ecma_module_connect_imports (void) ecma_module_connect_imports (void)
{ {
ecma_module_context_t *current_context_p = JERRY_CONTEXT (module_top_context_p); 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)); 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 = 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) while (import_node_p != NULL)
{ {
ecma_value_t result = ecma_module_evaluate (import_node_p->module_request_p); 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; return ECMA_VALUE_EMPTY;
} /* ecma_module_connect_imports */ } /* 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. * 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); 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); ecma_deref_object (module_p->scope_p);
} }
@@ -996,11 +1050,6 @@ finished:
void void
ecma_module_cleanup (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); ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p);
while (current_p != NULL) while (current_p != NULL)
{ {
@@ -1009,6 +1058,7 @@ ecma_module_cleanup (void)
current_p = next_p; current_p = next_p;
} }
JERRY_CONTEXT (ecma_modules_p) = NULL;
JERRY_CONTEXT (module_top_context_p) = NULL; JERRY_CONTEXT (module_top_context_p) = NULL;
} /* ecma_module_cleanup */ } /* 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_object_t *const namespace_p);
ecma_module_t *ecma_module_find_or_create_module (ecma_string_t *const path_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_parse_modules (void);
ecma_value_t ecma_module_check_indirect_exports (void); ecma_value_t ecma_module_check_indirect_exports (void);
+52 -9
View File
@@ -37,25 +37,35 @@
* Initialize Global environment * Initialize Global environment
*/ */
void 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 *glob_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL);
ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL, ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL,
glob_obj_p, glob_obj_p,
ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_lex_env_cp), global_lex_env_p); ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_env_cp), global_lex_env_p);
} /* ecma_init_global_lex_env */ #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 * Finalize Global environment
*/ */
void 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))); #if ENABLED (JERRY_ES2015)
JERRY_CONTEXT (ecma_global_lex_env_cp) = JMEM_CP_NULL; if (JERRY_CONTEXT (ecma_global_scope_cp) != JERRY_CONTEXT (ecma_global_env_cp))
} /* ecma_finalize_global_lex_env */ {
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 * Get reference to Global lexical environment
@@ -66,10 +76,43 @@ ecma_finalize_global_lex_env (void)
ecma_object_t * ecma_object_t *
ecma_get_global_environment (void) ecma_get_global_environment (void)
{ {
JERRY_ASSERT (JERRY_CONTEXT (ecma_global_lex_env_cp) != JMEM_CP_NULL); JERRY_ASSERT (JERRY_CONTEXT (ecma_global_env_cp) != JMEM_CP_NULL);
return ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_lex_env_cp)); return ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_env_cp));
} /* ecma_get_global_environment */ } /* 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_init_global_environment (void);
void ecma_finalize_global_lex_env (void); void ecma_finalize_global_environment (void);
ecma_object_t *ecma_get_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) #if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
void ecma_module_add_lex_env (ecma_object_t *lex_env_p); 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_op_is_prop_unscopable (ecma_object_t *lex_env_p, /**< lexical environment */
ecma_string_t *prop_name_p) /**< property's name */ 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; return ECMA_VALUE_FALSE;
} }
+1 -1
View File
@@ -30,7 +30,7 @@ extern "C"
/** /**
* Jerry snapshot format version. * Jerry snapshot format version.
*/ */
#define JERRY_SNAPSHOT_VERSION (38u) #define JERRY_SNAPSHOT_VERSION (39u)
/** /**
* Flags for jerry_generate_snapshot and jerry_generate_function_snapshot. * Flags for jerry_generate_snapshot and jerry_generate_function_snapshot.
+4 -1
View File
@@ -142,7 +142,10 @@ struct jerry_context_t
jmem_cpointer_t symbol_list_first_cp; /**< first item of the global symbol list */ jmem_cpointer_t symbol_list_first_cp; /**< first item of the global symbol list */
#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_ES2015) */
jmem_cpointer_t number_list_first_cp; /**< first item of the literal number list */ jmem_cpointer_t number_list_first_cp; /**< first item of the literal number list */
jmem_cpointer_t ecma_global_lex_env_cp; /**< global lexical environment */ jmem_cpointer_t ecma_global_env_cp; /**< global lexical environment */
#if ENABLED (JERRY_ES2015)
jmem_cpointer_t ecma_global_scope_cp; /**< global lexical scope */
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) #if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
ecma_module_t *ecma_modules_p; /**< list of referenced modules */ ecma_module_t *ecma_modules_p; /**< list of referenced modules */
+5
View File
@@ -302,6 +302,10 @@
VM_OC_NEW | VM_OC_PUT_STACK) \ VM_OC_NEW | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EVAL, CBC_NO_FLAG, 0, \ CBC_OPCODE (CBC_EVAL, CBC_NO_FLAG, 0, \
VM_OC_EVAL) \ VM_OC_EVAL) \
CBC_OPCODE (CBC_CHECK_VAR, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_CHECK_VAR) \
CBC_OPCODE (CBC_CHECK_LET, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_CHECK_LET) \
CBC_OPCODE (CBC_CREATE_VAR, CBC_HAS_LITERAL_ARG, 0, \ CBC_OPCODE (CBC_CREATE_VAR, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_CREATE_BINDING) \ VM_OC_CREATE_BINDING) \
CBC_OPCODE (CBC_CREATE_LET, CBC_HAS_LITERAL_ARG, 0, \ CBC_OPCODE (CBC_CREATE_LET, CBC_HAS_LITERAL_ARG, 0, \
@@ -780,6 +784,7 @@ typedef enum
CBC_CODE_FLAGS_GENERATOR = (1u << 11), /**< this function is a generator */ CBC_CODE_FLAGS_GENERATOR = (1u << 11), /**< this function is a generator */
CBC_CODE_FLAGS_REST_PARAMETER = (1u << 12), /**< this function has rest parameter */ CBC_CODE_FLAGS_REST_PARAMETER = (1u << 12), /**< this function has rest parameter */
CBC_CODE_FLAG_HAS_TAGGED_LITERALS = (1u << 13), /**< this function has tagged template literal list */ CBC_CODE_FLAG_HAS_TAGGED_LITERALS = (1u << 13), /**< this function has tagged template literal list */
CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED = (1u << 14), /**< compiled code needs a lexical block */
} cbc_code_flags; } cbc_code_flags;
/** /**
+2 -1
View File
@@ -58,7 +58,7 @@ typedef enum
PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 11), /**< pending (unsent) breakpoint PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 11), /**< pending (unsent) breakpoint
* info is available */ * info is available */
#if ENABLED (JERRY_ES2015) #if ENABLED (JERRY_ES2015)
PARSER_INSIDE_BLOCK = (1u << 12), /**< script has a lexical environment for let and const */ PARSER_LEXICAL_BLOCK_NEEDED = (1u << 12), /**< script needs a lexical environment for let and const */
PARSER_IS_ARROW_FUNCTION = (1u << 13), /**< an arrow function is parsed */ PARSER_IS_ARROW_FUNCTION = (1u << 13), /**< an arrow function is parsed */
PARSER_IS_GENERATOR_FUNCTION = (1u << 14), /**< a generator function is parsed */ PARSER_IS_GENERATOR_FUNCTION = (1u << 14), /**< a generator function is parsed */
PARSER_IS_ASYNC_FUNCTION = (1u << 15), /**< an async function is parsed */ PARSER_IS_ASYNC_FUNCTION = (1u << 15), /**< an async function is parsed */
@@ -726,6 +726,7 @@ bool scanner_is_context_needed (parser_context_t *context_p);
bool scanner_is_global_context_needed (parser_context_t *context_p); bool scanner_is_global_context_needed (parser_context_t *context_p);
bool scanner_scope_find_let_declaration (parser_context_t *context_p, lexer_lit_location_t *literal_p); bool scanner_scope_find_let_declaration (parser_context_t *context_p, lexer_lit_location_t *literal_p);
bool scanner_try_scan_new_target (parser_context_t *context_p); bool scanner_try_scan_new_target (parser_context_t *context_p);
void scanner_check_variables (parser_context_t *context_p);
#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_ES2015) */
void scanner_create_variables (parser_context_t *context_p, uint32_t option_flags); void scanner_create_variables (parser_context_t *context_p, uint32_t option_flags);
+2 -2
View File
@@ -325,8 +325,8 @@ parser_module_context_init (void)
ecma_module_t *module_p = ecma_module_find_or_create_module (path_p); ecma_module_t *module_p = ecma_module_find_or_create_module (path_p);
module_p->state = ECMA_MODULE_STATE_EVALUATED; module_p->state = ECMA_MODULE_STATE_EVALUATED;
module_p->scope_p = ecma_get_global_environment (); /* The lexical scope of the root module does not exist yet. */
ecma_ref_object (module_p->scope_p); module_p->scope_p = NULL;
module_p->context_p = module_context_p; module_p->context_p = module_context_p;
module_context_p->module_p = module_p; module_context_p->module_p = module_p;
+3 -17
View File
@@ -125,21 +125,7 @@ static const uint8_t parser_statement_flags[] =
PARSER_STATM_CONTEXT_BREAK PARSER_STATM_CONTEXT_BREAK
}; };
#if !ENABLED (JERRY_ES2015) #if ENABLED (JERRY_ES2015)
/**
* Get the expected depth of a function call.
*/
#define JERRY_GET_EXPECTED_DEPTH(context_p) 0
#else /* ENABLED (JERRY_ES2015) */
/**
* Get the expected depth of a function call.
*/
#define JERRY_GET_EXPECTED_DEPTH(context_p) \
(((context_p)->status_flags & PARSER_INSIDE_BLOCK) ? PARSER_BLOCK_CONTEXT_STACK_ALLOCATION : 0)
/** /**
* Block statement. * Block statement.
*/ */
@@ -2637,7 +2623,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
lexer_lit_location_t lit_location; lexer_lit_location_t lit_location;
bool is_use_strict = false; bool is_use_strict = false;
JERRY_ASSERT (context_p->stack_depth == JERRY_GET_EXPECTED_DEPTH (context_p)); JERRY_ASSERT (context_p->stack_depth == 0);
#ifndef JERRY_NDEBUG #ifndef JERRY_NDEBUG
JERRY_ASSERT (context_p->context_stack_depth == context_p->stack_depth); JERRY_ASSERT (context_p->context_stack_depth == context_p->stack_depth);
#endif /* !JERRY_NDEBUG */ #endif /* !JERRY_NDEBUG */
@@ -3348,7 +3334,7 @@ consume_last_statement:
} }
} }
JERRY_ASSERT (context_p->stack_depth == JERRY_GET_EXPECTED_DEPTH (context_p)); JERRY_ASSERT (context_p->stack_depth == 0);
#ifndef JERRY_NDEBUG #ifndef JERRY_NDEBUG
JERRY_ASSERT (context_p->context_stack_depth == context_p->stack_depth); JERRY_ASSERT (context_p->context_stack_depth == context_p->stack_depth);
#endif /* !JERRY_NDEBUG */ #endif /* !JERRY_NDEBUG */
+10 -23
View File
@@ -1311,6 +1311,11 @@ parser_post_processing (parser_context_t *context_p) /**< context */
{ {
compiled_code_p->status_flags |= CBC_CODE_FLAG_HAS_TAGGED_LITERALS; compiled_code_p->status_flags |= CBC_CODE_FLAG_HAS_TAGGED_LITERALS;
} }
if (context_p->status_flags & PARSER_LEXICAL_BLOCK_NEEDED)
{
compiled_code_p->status_flags |= CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED;
}
#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_ES2015) */
literal_pool_p = ((ecma_value_t *) byte_code_p) - context_p->register_count; literal_pool_p = ((ecma_value_t *) byte_code_p) - context_p->register_count;
@@ -2093,18 +2098,12 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
#if ENABLED (JERRY_ES2015) #if ENABLED (JERRY_ES2015)
if (scanner_is_global_context_needed (&context)) if (scanner_is_global_context_needed (&context))
{ {
parser_branch_t branch; context.status_flags |= PARSER_LEXICAL_BLOCK_NEEDED;
}
#ifndef JERRY_NDEBUG if ((parse_opts & ECMA_PARSE_EVAL) == 0)
PARSER_PLUS_EQUAL_U16 (context.context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION); {
#endif /* !JERRY_NDEBUG */ scanner_check_variables (&context);
parser_emit_cbc_forward_branch (&context,
CBC_BLOCK_CREATE_CONTEXT,
&branch);
parser_stack_push (&context, &branch, sizeof (parser_branch_t));
context.status_flags |= PARSER_INSIDE_BLOCK;
} }
#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_ES2015) */
@@ -2113,18 +2112,6 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */
parser_parse_statements (&context); parser_parse_statements (&context);
#if ENABLED (JERRY_ES2015)
if (context.status_flags & PARSER_INSIDE_BLOCK)
{
parser_branch_t branch;
parser_stack_pop (&context, &branch, sizeof (parser_branch_t));
parser_emit_cbc (&context, CBC_CONTEXT_END);
parser_set_branch_to_current_position (&context, &branch);
parser_flush_cbc (&context);
}
#endif /* ENABLED (JERRY_ES2015) */
/* When the parsing is successful, only the /* When the parsing is successful, only the
* dummy value can be remained on the stack. */ * dummy value can be remained on the stack. */
JERRY_ASSERT (context.stack_top_uint8 == CBC_MAXIMUM_BYTE_VALUE JERRY_ASSERT (context.stack_top_uint8 == CBC_MAXIMUM_BYTE_VALUE
@@ -257,9 +257,6 @@ typedef enum
SCANNER_LITERAL_POOL_BLOCK = (1 << 1), /**< literal pool represents a code block */ SCANNER_LITERAL_POOL_BLOCK = (1 << 1), /**< literal pool represents a code block */
SCANNER_LITERAL_POOL_IS_STRICT = (1 << 2), /**< literal pool represents a strict mode code block */ SCANNER_LITERAL_POOL_IS_STRICT = (1 << 2), /**< literal pool represents a strict mode code block */
SCANNER_LITERAL_POOL_NO_REG = (1 << 3), /**< variable declarations cannot be kept in registers */ SCANNER_LITERAL_POOL_NO_REG = (1 << 3), /**< variable declarations cannot be kept in registers */
#if ENABLED (JERRY_ES2015)
SCANNER_LITERAL_POOL_NO_VAR_REG = (1 << 4), /**< non let/const declarations cannot be kept in registers */
#endif /* ENABLED (JERRY_ES2015) */
SCANNER_LITERAL_POOL_NO_ARGUMENTS = (1 << 5), /**< arguments object must not be constructed */ SCANNER_LITERAL_POOL_NO_ARGUMENTS = (1 << 5), /**< arguments object must not be constructed */
#if ENABLED (JERRY_ES2015) #if ENABLED (JERRY_ES2015)
SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED = (1 << 6), /**< arguments object should be unmapped */ SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED = (1 << 6), /**< arguments object should be unmapped */
+90 -13
View File
@@ -470,21 +470,14 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
bool no_reg = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_REG) != 0; bool no_reg = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_REG) != 0;
bool search_arguments = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_ARGUMENTS) == 0; bool search_arguments = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_ARGUMENTS) == 0;
bool arguments_required = (no_reg && search_arguments); bool arguments_required = (no_reg && search_arguments);
uint8_t no_reg_types = 0;
#if ENABLED (JERRY_ES2015) #if ENABLED (JERRY_ES2015)
uint8_t no_var_flags = 0; if (!(context_p->status_flags & PARSER_IS_DIRECT_EVAL))
if (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_VAR_REG)
{ {
no_var_flags = SCANNER_LITERAL_IS_VAR; no_reg_types |= SCANNER_LITERAL_IS_FUNC;
if (!(context_p->status_flags & PARSER_IS_DIRECT_EVAL))
{
no_var_flags |= SCANNER_LITERAL_IS_FUNC;
}
} }
#else /* !ENABLED (JERRY_ES2015) */ #endif /* !ENABLED (JERRY_ES2015) */
uint8_t no_var_flags = 0;
#endif /* ENABLED (JERRY_ES2015) */
if (no_reg && prev_literal_pool_p != NULL) if (no_reg && prev_literal_pool_p != NULL)
{ {
@@ -565,7 +558,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
no_declarations++; no_declarations++;
} }
if (no_reg || (type & no_var_flags)) if (no_reg || (type & no_reg_types))
{ {
type |= SCANNER_LITERAL_NO_REG; type |= SCANNER_LITERAL_NO_REG;
literal_p->type = type; literal_p->type = type;
@@ -1738,6 +1731,90 @@ scanner_create_unused_literal (parser_context_t *context_p, /**< context */
context_p->literal_count++; context_p->literal_count++;
} /* scanner_create_unused_literal */ } /* scanner_create_unused_literal */
#if ENABLED (JERRY_ES2015)
/**
* Emit checks for redeclared bindings in the global lexical scope.
*/
void
scanner_check_variables (parser_context_t *context_p) /**< context */
{
scanner_info_t *info_p = context_p->next_scanner_info_p;
const uint8_t *next_data_p = (const uint8_t *) (info_p + 1);
lexer_lit_location_t literal;
JERRY_ASSERT (info_p->type == SCANNER_TYPE_FUNCTION);
literal.char_p = info_p->source_p - 1;
while (next_data_p[0] != SCANNER_STREAM_TYPE_END)
{
uint32_t type = next_data_p[0] & SCANNER_STREAM_TYPE_MASK;
const uint8_t *data_p = next_data_p;
JERRY_ASSERT (type != SCANNER_STREAM_TYPE_HOLE
&& !SCANNER_STREAM_TYPE_IS_ARG (type)
&& !SCANNER_STREAM_TYPE_IS_ARG_FUNC (type));
JERRY_ASSERT (data_p[0] & SCANNER_STREAM_NO_REG);
if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF))
{
if (data_p[2] != 0)
{
literal.char_p += data_p[2];
next_data_p += 2 + 1;
}
else
{
memcpy (&literal.char_p, data_p + 2 + 1, sizeof (const uint8_t *));
next_data_p += 2 + 1 + sizeof (const uint8_t *);
}
}
else
{
int32_t diff = ((int32_t) data_p[2]) | ((int32_t) data_p[3]) << 8;
if (diff <= UINT8_MAX)
{
diff = -diff;
}
literal.char_p += diff;
next_data_p += 2 + 2;
}
literal.length = data_p[1];
literal.type = LEXER_IDENT_LITERAL;
literal.has_escape = (data_p[0] & SCANNER_STREAM_HAS_ESCAPE) ? 1 : 0;
lexer_construct_literal_object (context_p, &literal, LEXER_NEW_IDENT_LITERAL);
literal.char_p += data_p[1];
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
if (type == SCANNER_STREAM_TYPE_IMPORT)
{
continue;
}
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_USED;
uint16_t opcode;
if (type == SCANNER_STREAM_TYPE_VAR || type == SCANNER_STREAM_TYPE_FUNC)
{
opcode = CBC_CHECK_VAR;
}
else
{
opcode = CBC_CHECK_LET;
}
parser_emit_cbc_literal (context_p, opcode, context_p->lit_object.index);
}
parser_flush_cbc (context_p);
} /* scanner_check_variables */
#endif /* ENABLED (JERRY_ES2015) */
/** /**
* Create and/or initialize var/let/const/function/etc. variables. * Create and/or initialize var/let/const/function/etc. variables.
*/ */
-4
View File
@@ -2263,11 +2263,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
context_p->source_p = source_p; context_p->source_p = source_p;
context_p->source_end_p = source_end_p; context_p->source_end_p = source_end_p;
#if ENABLED (JERRY_ES2015)
uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS | SCANNER_LITERAL_POOL_NO_VAR_REG;
#else /* !ENABLED (JERRY_DEBUGGER) */
uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS | SCANNER_LITERAL_POOL_NO_REG; uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS | SCANNER_LITERAL_POOL_NO_REG;
#endif /* ENABLED (JERRY_DEBUGGER) */
if (context_p->status_flags & PARSER_IS_STRICT) if (context_p->status_flags & PARSER_IS_STRICT)
{ {
+98 -26
View File
@@ -260,10 +260,14 @@ ecma_value_t
vm_run_module (const ecma_compiled_code_t *bytecode_p, /**< pointer to bytecode to run */ 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 */ ecma_object_t *lex_env_p) /**< pointer to the specified lexenv to run in */
{ {
ecma_object_t *glob_obj_p = ecma_builtin_get_global (); const ecma_value_t module_init_result = ecma_module_initialize_current ();
if (ECMA_IS_VALUE_ERROR (module_init_result))
{
return module_init_result;
}
return vm_run (bytecode_p, return vm_run (bytecode_p,
ecma_make_object_value (glob_obj_p), ECMA_VALUE_UNDEFINED,
lex_env_p, lex_env_p,
NULL, NULL,
0); 0);
@@ -283,9 +287,39 @@ vm_run_global (const ecma_compiled_code_t *bytecode_p) /**< pointer to bytecode
{ {
ecma_object_t *glob_obj_p = ecma_builtin_get_global (); ecma_object_t *glob_obj_p = ecma_builtin_get_global ();
#if ENABLED (JERRY_ES2015)
if (bytecode_p->status_flags & CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED)
{
ecma_create_global_lexical_block ();
}
#endif /* ENABLED (JERRY_ES2015) */
ecma_object_t *const global_scope_p = ecma_get_global_scope ();
#if ENABLED (JERRY_ES2015_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 ();
ecma_module_cleanup ();
JERRY_CONTEXT (module_top_context_p) = NULL;
if (ECMA_IS_VALUE_ERROR (module_init_result))
{
return module_init_result;
}
}
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
return vm_run (bytecode_p, return vm_run (bytecode_p,
ecma_make_object_value (glob_obj_p), ecma_make_object_value (glob_obj_p),
ecma_get_global_environment (), global_scope_p,
NULL, NULL,
0); 0);
} /* vm_run_global */ } /* vm_run_global */
@@ -333,7 +367,7 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */
ecma_object_t *global_obj_p = ecma_builtin_get_global (); ecma_object_t *global_obj_p = ecma_builtin_get_global ();
ecma_ref_object (global_obj_p); ecma_ref_object (global_obj_p);
this_binding = ecma_make_object_value (global_obj_p); this_binding = ecma_make_object_value (global_obj_p);
lex_env_p = ecma_get_global_environment (); lex_env_p = ecma_get_global_scope ();
} }
ecma_ref_object (lex_env_p); ecma_ref_object (lex_env_p);
@@ -341,11 +375,20 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */
if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0) if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0)
{ {
ecma_object_t *strict_lex_env_p = ecma_create_decl_lex_env (lex_env_p); ecma_object_t *strict_lex_env_p = ecma_create_decl_lex_env (lex_env_p);
ecma_deref_object (lex_env_p);
ecma_deref_object (lex_env_p);
lex_env_p = strict_lex_env_p; lex_env_p = strict_lex_env_p;
} }
if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED) != 0)
{
ecma_object_t *lex_block_p = ecma_create_decl_lex_env (lex_env_p);
lex_block_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_BLOCK;
ecma_deref_object (lex_env_p);
lex_env_p = lex_block_p;
}
ecma_value_t completion_value = vm_run (bytecode_data_p, ecma_value_t completion_value = vm_run (bytecode_data_p,
this_binding, this_binding,
lex_env_p, lex_env_p,
@@ -1337,6 +1380,56 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
continue; continue;
} }
#if ENABLED (JERRY_ES2015) #if ENABLED (JERRY_ES2015)
case VM_OC_CHECK_VAR:
{
JERRY_ASSERT (ecma_get_global_scope () == frame_ctx_p->lex_env_p);
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
if ((frame_ctx_p->lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) == 0)
{
continue;
}
ecma_string_t *const literal_name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_property_t *const binding_p = ecma_find_named_property (frame_ctx_p->lex_env_p, literal_name_p);
if (binding_p != NULL)
{
result = ecma_raise_syntax_error (ECMA_ERR_MSG ("Local variable is redeclared."));
goto error;
}
continue;
}
case VM_OC_CHECK_LET:
{
JERRY_ASSERT (ecma_get_global_scope () == frame_ctx_p->lex_env_p);
uint32_t literal_index;
READ_LITERAL_INDEX (literal_index);
ecma_string_t *literal_name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
ecma_object_t *lex_env_p = frame_ctx_p->lex_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, literal_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, literal_name_p))
{
result = ecma_raise_syntax_error (ECMA_ERR_MSG ("Local variable is redeclared."));
goto error;
}
continue;
}
case VM_OC_ASSIGN_LET_CONST: case VM_OC_ASSIGN_LET_CONST:
{ {
uint32_t literal_index; uint32_t literal_index;
@@ -4181,27 +4274,6 @@ vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data heade
vm_frame_ctx_t *frame_ctx_p; vm_frame_ctx_t *frame_ctx_p;
size_t frame_size; size_t frame_size;
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
if (JERRY_CONTEXT (module_top_context_p) != NULL)
{
ecma_value_t ret_value = ecma_module_connect_imports ();
if (ecma_is_value_empty (ret_value))
{
ret_value = ecma_module_check_indirect_exports ();
}
ecma_module_cleanup ();
if (!ecma_is_value_empty (ret_value))
{
return ret_value;
}
JERRY_CONTEXT (module_top_context_p) = NULL;
}
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{ {
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p;
+4
View File
@@ -229,6 +229,8 @@ typedef enum
VM_OC_LINE, /**< line number of the next statement */ VM_OC_LINE, /**< line number of the next statement */
#endif /* ENABLED (JERRY_LINE_INFO) */ #endif /* ENABLED (JERRY_LINE_INFO) */
#if ENABLED (JERRY_ES2015) #if ENABLED (JERRY_ES2015)
VM_OC_CHECK_VAR, /**< check redeclared vars in the global scope */
VM_OC_CHECK_LET, /**< check redeclared lets in the global scope */
VM_OC_ASSIGN_LET_CONST, /**< assign values to let/const declarations */ VM_OC_ASSIGN_LET_CONST, /**< assign values to let/const declarations */
VM_OC_COPY_TO_GLOBAL, /**< copy value to global lex env */ VM_OC_COPY_TO_GLOBAL, /**< copy value to global lex env */
VM_OC_CLONE_CONTEXT, /**< clone lexical environment with let/const declarations */ VM_OC_CLONE_CONTEXT, /**< clone lexical environment with let/const declarations */
@@ -286,6 +288,8 @@ typedef enum
VM_OC_LINE = VM_OC_NONE, /**< line number of the next statement is unused */ VM_OC_LINE = VM_OC_NONE, /**< line number of the next statement is unused */
#endif /* !ENABLED (JERRY_LINE_INFO) */ #endif /* !ENABLED (JERRY_LINE_INFO) */
#if !ENABLED (JERRY_ES2015) #if !ENABLED (JERRY_ES2015)
VM_OC_CHECK_VAR = VM_OC_NONE, /**< check redeclared vars in the global scope */
VM_OC_CHECK_LET = VM_OC_NONE, /**< check redeclared lets in the global scope */
VM_OC_ASSIGN_LET_CONST = VM_OC_NONE, /**< assign values to let/const declarations */ VM_OC_ASSIGN_LET_CONST = VM_OC_NONE, /**< assign values to let/const declarations */
VM_OC_COPY_TO_GLOBAL = VM_OC_NONE, /**< copy value to global lex env */ VM_OC_COPY_TO_GLOBAL = VM_OC_NONE, /**< copy value to global lex env */
VM_OC_CLONE_CONTEXT = VM_OC_NONE, /**< clone lexical environment with let/const declarations */ VM_OC_CLONE_CONTEXT = VM_OC_NONE, /**< clone lexical environment with let/const declarations */
+22 -11
View File
@@ -889,33 +889,44 @@ main (int argc,
} }
/* Evaluate the line */ /* Evaluate the line */
jerry_value_t ret_val_eval = jerry_eval (buffer, len, JERRY_PARSE_NO_OPTS); jerry_value_t ret_val = jerry_parse (NULL,
0,
buffer,
len,
JERRY_PARSE_NO_OPTS);
if (!jerry_value_is_error (ret_val_eval)) if (!jerry_value_is_error (ret_val))
{
jerry_value_t func_val = ret_val;
ret_val = jerry_run (func_val);
jerry_release_value (func_val);
}
if (!jerry_value_is_error (ret_val))
{ {
/* Print return value */ /* Print return value */
const jerry_value_t args[] = { ret_val_eval }; const jerry_value_t args[] = { ret_val };
jerry_value_t ret_val_print = jerryx_handler_print (jerry_create_undefined (), jerry_value_t ret_val_print = jerryx_handler_print (jerry_create_undefined (),
jerry_create_undefined (), jerry_create_undefined (),
args, args,
1); 1);
jerry_release_value (ret_val_print); jerry_release_value (ret_val_print);
jerry_release_value (ret_val_eval); jerry_release_value (ret_val);
ret_val_eval = jerry_run_all_enqueued_jobs (); ret_val = jerry_run_all_enqueued_jobs ();
if (jerry_value_is_error (ret_val_eval)) if (jerry_value_is_error (ret_val))
{ {
ret_val_eval = jerry_get_value_from_error (ret_val_eval, true); ret_val = jerry_get_value_from_error (ret_val, true);
print_unhandled_exception (ret_val_eval); print_unhandled_exception (ret_val);
} }
} }
else else
{ {
ret_val_eval = jerry_get_value_from_error (ret_val_eval, true); ret_val = jerry_get_value_from_error (ret_val, true);
print_unhandled_exception (ret_val_eval); print_unhandled_exception (ret_val);
} }
jerry_release_value (ret_val_eval); jerry_release_value (ret_val);
} }
} }
} }
+41
View File
@@ -811,6 +811,47 @@ main (void)
jerry_cleanup (); jerry_cleanup ();
} }
/* Test parsing/executing scripts with lexically scoped global variables multiple times. */
if (jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL))
{
jerry_init (JERRY_INIT_EMPTY);
const jerry_char_t scoped_src_p[] = "let a;";
jerry_value_t parse_result = jerry_parse (NULL,
0,
scoped_src_p,
sizeof (scoped_src_p) - 1,
JERRY_PARSE_NO_OPTS);
TEST_ASSERT (!jerry_value_is_error (parse_result));
jerry_release_value (parse_result);
parse_result = jerry_parse (NULL,
0,
scoped_src_p,
sizeof (scoped_src_p) - 1,
JERRY_PARSE_NO_OPTS);
TEST_ASSERT (!jerry_value_is_error (parse_result));
jerry_value_t run_result = jerry_run (parse_result);
TEST_ASSERT (!jerry_value_is_error (run_result));
jerry_release_value (run_result);
/* Should be a syntax error due to redeclaration. */
run_result = jerry_run (parse_result);
TEST_ASSERT (jerry_value_is_error (run_result));
jerry_release_value (run_result);
jerry_release_value (parse_result);
/* The variable should have no effect on parsing. */
parse_result = jerry_parse (NULL,
0,
scoped_src_p,
sizeof (scoped_src_p) - 1,
JERRY_PARSE_NO_OPTS);
TEST_ASSERT (!jerry_value_is_error (parse_result));
jerry_release_value (parse_result);
jerry_cleanup ();
}
/* Test: parser error location */ /* Test: parser error location */
if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES)) if (jerry_is_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES))
{ {
+7 -4
View File
@@ -223,15 +223,15 @@ main (void)
/* Check the snapshot data. Unused bytes should be filled with zeroes */ /* Check the snapshot data. Unused bytes should be filled with zeroes */
const uint8_t expected_data[] = const uint8_t expected_data[] =
{ {
0x4A, 0x52, 0x52, 0x59, 0x26, 0x00, 0x00, 0x00, 0x4A, 0x52, 0x52, 0x59, 0x27, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00,
0x2C, 0x00, 0xC1, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0xC3, 0x50, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00,
0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x14, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x73, 0x6E, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x73, 0x6E,
0x61, 0x70, 0x73, 0x68, 0x6F, 0x74, 0x61, 0x70, 0x73, 0x68, 0x6F, 0x74,
@@ -416,7 +416,10 @@ main (void)
size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); size_t snapshot_size = (size_t) jerry_get_number_value (generate_result);
jerry_release_value (generate_result); jerry_release_value (generate_result);
TEST_ASSERT (snapshot_size == 124);
/* In ES2015 we emit extra bytecode instructions to check global variable redeclaration. */
const size_t expected_size = (jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) ? 132 : 124;
TEST_ASSERT (snapshot_size == expected_size);
const size_t lit_c_buf_sz = jerry_get_literals_from_snapshot (literal_snapshot_buffer, const size_t lit_c_buf_sz = jerry_get_literals_from_snapshot (literal_snapshot_buffer,
snapshot_size, snapshot_size,