Delay the variable construction in the function body. (#3289)
Local variables inside the function body should be constructed after the parameters are initialized. Furthermore arguments should be available during parameter initialization. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
committed by
Dániel Bátyai
parent
923fd128b5
commit
e1fc90db0e
@@ -320,6 +320,14 @@ typedef struct
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This item represents a function literal in the scope stack.
|
* This item represents a function literal in the scope stack.
|
||||||
|
*
|
||||||
|
* When map_from == PARSER_SCOPE_STACK_FUNC:
|
||||||
|
* map_to represents the literal reserved for a function literal
|
||||||
|
* Note: the name of the function is the previous value in the scope stack
|
||||||
|
*
|
||||||
|
* When map_to == PARSER_SCOPE_STACK_FUNC:
|
||||||
|
* map_from represents the name of the function literal following this literal
|
||||||
|
* Note: only the name, the real mapping is somewhere else in the scope stack
|
||||||
*/
|
*/
|
||||||
#define PARSER_SCOPE_STACK_FUNC 0xffff
|
#define PARSER_SCOPE_STACK_FUNC 0xffff
|
||||||
|
|
||||||
@@ -626,6 +634,7 @@ void parser_parse_super_class_context_end (parser_context_t *context_p);
|
|||||||
|
|
||||||
void scanner_release_next (parser_context_t *context_p, size_t size);
|
void scanner_release_next (parser_context_t *context_p, size_t size);
|
||||||
void scanner_set_active (parser_context_t *context_p);
|
void scanner_set_active (parser_context_t *context_p);
|
||||||
|
void scanner_revert_active (parser_context_t *context_p);
|
||||||
void scanner_release_active (parser_context_t *context_p, size_t size);
|
void scanner_release_active (parser_context_t *context_p, size_t size);
|
||||||
void scanner_release_switch_cases (scanner_case_info_t *case_p);
|
void scanner_release_switch_cases (scanner_case_info_t *case_p);
|
||||||
void scanner_seek (parser_context_t *context_p);
|
void scanner_seek (parser_context_t *context_p);
|
||||||
|
|||||||
@@ -1617,13 +1617,16 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */
|
|||||||
#endif /* ENABLED (JERRY_ES2015) */
|
#endif /* ENABLED (JERRY_ES2015) */
|
||||||
|
|
||||||
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
|
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
|
||||||
scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
|
|
||||||
|
|
||||||
if (context_p->token.type == end_type)
|
if (context_p->token.type == end_type)
|
||||||
{
|
{
|
||||||
|
scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scanner_create_variables (context_p, SCANNER_CREATE_VARS_IS_FUNCTION_ARGS);
|
||||||
|
scanner_set_active (context_p);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
#if ENABLED (JERRY_ES2015)
|
#if ENABLED (JERRY_ES2015)
|
||||||
@@ -1730,6 +1733,9 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */
|
|||||||
|
|
||||||
parser_raise_error (context_p, error);
|
parser_raise_error (context_p, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scanner_revert_active (context_p);
|
||||||
|
scanner_create_variables (context_p, SCANNER_CREATE_VARS_IS_FUNCTION_BODY);
|
||||||
} /* parser_parse_function_arguments */
|
} /* parser_parse_function_arguments */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -258,6 +258,19 @@ scanner_set_active (parser_context_t *context_p) /**< context */
|
|||||||
context_p->active_scanner_info_p = scanner_info_p;
|
context_p->active_scanner_info_p = scanner_info_p;
|
||||||
} /* scanner_set_active */
|
} /* scanner_set_active */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the next scanner info to the active scanner info.
|
||||||
|
*/
|
||||||
|
inline void JERRY_ATTR_ALWAYS_INLINE
|
||||||
|
scanner_revert_active (parser_context_t *context_p) /**< context */
|
||||||
|
{
|
||||||
|
scanner_info_t *scanner_info_p = context_p->active_scanner_info_p;
|
||||||
|
|
||||||
|
context_p->active_scanner_info_p = scanner_info_p->next_p;
|
||||||
|
scanner_info_p->next_p = context_p->next_scanner_info_p;
|
||||||
|
context_p->next_scanner_info_p = scanner_info_p;
|
||||||
|
} /* scanner_revert_active */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release the active scanner info.
|
* Release the active scanner info.
|
||||||
*/
|
*/
|
||||||
@@ -394,7 +407,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
|
|||||||
lexer_lit_location_t *literal_p;
|
lexer_lit_location_t *literal_p;
|
||||||
bool is_function = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION) != 0;
|
bool is_function = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION) != 0;
|
||||||
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 = is_function && (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);
|
||||||
#if ENABLED (JERRY_ES2015)
|
#if ENABLED (JERRY_ES2015)
|
||||||
bool no_var_reg = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_VAR_REG) != 0;
|
bool no_var_reg = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_VAR_REG) != 0;
|
||||||
@@ -545,7 +558,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
|
|||||||
|
|
||||||
if (is_function || (compressed_size > 1))
|
if (is_function || (compressed_size > 1))
|
||||||
{
|
{
|
||||||
compressed_size += is_function ? sizeof (scanner_function_info_t) : sizeof (scanner_info_t);
|
compressed_size += sizeof (scanner_info_t);
|
||||||
|
|
||||||
scanner_info_t *info_p;
|
scanner_info_t *info_p;
|
||||||
|
|
||||||
@@ -564,14 +577,12 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
|
|||||||
no_declarations = PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK;
|
no_declarations = PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *data_p = (uint8_t *) info_p;
|
uint8_t *data_p = (uint8_t *) (info_p + 1);
|
||||||
|
|
||||||
if (is_function)
|
if (is_function)
|
||||||
{
|
{
|
||||||
info_p->type = SCANNER_TYPE_FUNCTION;
|
info_p->type = SCANNER_TYPE_FUNCTION;
|
||||||
data_p += sizeof (scanner_function_info_t);
|
|
||||||
|
|
||||||
scanner_function_info_t *function_info_p = (scanner_function_info_t *) info_p;
|
|
||||||
uint8_t status_flags = 0;
|
uint8_t status_flags = 0;
|
||||||
|
|
||||||
if (arguments_required)
|
if (arguments_required)
|
||||||
@@ -584,13 +595,12 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function_info_p->info.u8_arg = status_flags;
|
info_p->u8_arg = status_flags;
|
||||||
function_info_p->info.u16_arg = (uint16_t) no_declarations;
|
info_p->u16_arg = (uint16_t) no_declarations;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
info_p->type = SCANNER_TYPE_BLOCK;
|
info_p->type = SCANNER_TYPE_BLOCK;
|
||||||
data_p += sizeof (scanner_info_t);
|
|
||||||
|
|
||||||
JERRY_ASSERT (prev_literal_pool_p != NULL);
|
JERRY_ASSERT (prev_literal_pool_p != NULL);
|
||||||
}
|
}
|
||||||
@@ -730,6 +740,7 @@ scanner_filter_arguments (parser_context_t *context_p, /**< context */
|
|||||||
parser_list_iterator_t literal_iterator;
|
parser_list_iterator_t literal_iterator;
|
||||||
lexer_lit_location_t *literal_p;
|
lexer_lit_location_t *literal_p;
|
||||||
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 has_arguments = (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_NO_ARGUMENTS) == 0;
|
||||||
|
|
||||||
if (no_reg && prev_literal_pool_p != NULL)
|
if (no_reg && prev_literal_pool_p != NULL)
|
||||||
{
|
{
|
||||||
@@ -774,7 +785,10 @@ scanner_filter_arguments (parser_context_t *context_p, /**< context */
|
|||||||
|
|
||||||
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
|
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
|
||||||
{
|
{
|
||||||
if (literal_p->type & SCANNER_LITERAL_IS_ARG)
|
if ((literal_p->type & SCANNER_LITERAL_IS_ARG)
|
||||||
|
|| (has_arguments
|
||||||
|
&& literal_p->length == 9
|
||||||
|
&& lexer_compare_identifiers (literal_p->char_p, (const uint8_t *) "arguments", 9)))
|
||||||
{
|
{
|
||||||
lexer_lit_location_t *new_literal_p;
|
lexer_lit_location_t *new_literal_p;
|
||||||
new_literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &new_literal_pool_p->literal_pool);
|
new_literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &new_literal_pool_p->literal_pool);
|
||||||
@@ -1189,10 +1203,6 @@ scanner_cleanup (parser_context_t *context_p) /**< context */
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case SCANNER_TYPE_FUNCTION:
|
case SCANNER_TYPE_FUNCTION:
|
||||||
{
|
|
||||||
size = scanner_get_stream_size (scanner_info_p, sizeof (scanner_function_info_t));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SCANNER_TYPE_BLOCK:
|
case SCANNER_TYPE_BLOCK:
|
||||||
{
|
{
|
||||||
size = scanner_get_stream_size (scanner_info_p, sizeof (scanner_info_t));
|
size = scanner_get_stream_size (scanner_info_p, sizeof (scanner_info_t));
|
||||||
@@ -1396,7 +1406,7 @@ bool
|
|||||||
scanner_is_global_context_needed (parser_context_t *context_p) /**< context */
|
scanner_is_global_context_needed (parser_context_t *context_p) /**< context */
|
||||||
{
|
{
|
||||||
scanner_info_t *info_p = context_p->next_scanner_info_p;
|
scanner_info_t *info_p = context_p->next_scanner_info_p;
|
||||||
const uint8_t *data_p = ((const uint8_t *) info_p) + sizeof (scanner_function_info_t);
|
const uint8_t *data_p = (const uint8_t *) (info_p + 1);
|
||||||
uint32_t scope_stack_reg_top = 0;
|
uint32_t scope_stack_reg_top = 0;
|
||||||
|
|
||||||
JERRY_ASSERT (info_p->type == SCANNER_TYPE_FUNCTION);
|
JERRY_ASSERT (info_p->type == SCANNER_TYPE_FUNCTION);
|
||||||
@@ -1467,6 +1477,26 @@ const lexer_lit_location_t lexer_arguments_literal =
|
|||||||
(const uint8_t *) "arguments", 9, LEXER_IDENT_LITERAL, false
|
(const uint8_t *) "arguments", 9, LEXER_IDENT_LITERAL, false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an unused literal.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
scanner_create_unused_literal (parser_context_t *context_p, /**< context */
|
||||||
|
uint8_t status_flags) /**< initial status flags */
|
||||||
|
{
|
||||||
|
if (JERRY_UNLIKELY (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS))
|
||||||
|
{
|
||||||
|
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
|
||||||
|
|
||||||
|
literal_p->type = LEXER_UNUSED_LITERAL;
|
||||||
|
literal_p->status_flags = status_flags;
|
||||||
|
|
||||||
|
context_p->literal_count++;
|
||||||
|
} /* scanner_create_unused_literal */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and/or initialize var/let/const/function/etc. variables.
|
* Create and/or initialize var/let/const/function/etc. variables.
|
||||||
*/
|
*/
|
||||||
@@ -1475,15 +1505,19 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
|
|||||||
uint32_t option_flags) /**< combination of scanner_create_variables_flags_t bits */
|
uint32_t option_flags) /**< combination of scanner_create_variables_flags_t bits */
|
||||||
{
|
{
|
||||||
scanner_info_t *info_p = context_p->next_scanner_info_p;
|
scanner_info_t *info_p = context_p->next_scanner_info_p;
|
||||||
const uint8_t *data_p;
|
const uint8_t *next_data_p = (const uint8_t *) (info_p + 1);
|
||||||
uint8_t info_type = info_p->type;
|
uint8_t info_type = info_p->type;
|
||||||
lexer_lit_location_t literal;
|
lexer_lit_location_t literal;
|
||||||
parser_scope_stack *scope_stack_p;
|
parser_scope_stack *scope_stack_p;
|
||||||
parser_scope_stack *scope_stack_end_p;
|
parser_scope_stack *scope_stack_end_p;
|
||||||
|
|
||||||
JERRY_ASSERT (info_type == SCANNER_TYPE_FUNCTION || info_type == SCANNER_TYPE_BLOCK);
|
JERRY_ASSERT (info_type == SCANNER_TYPE_FUNCTION || info_type == SCANNER_TYPE_BLOCK);
|
||||||
|
JERRY_ASSERT (!(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_ARGS)
|
||||||
|
|| !(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY));
|
||||||
|
JERRY_ASSERT (info_type == SCANNER_TYPE_FUNCTION
|
||||||
|
|| !(option_flags & (SCANNER_CREATE_VARS_IS_FUNCTION_ARGS | SCANNER_CREATE_VARS_IS_FUNCTION_BODY)));
|
||||||
|
|
||||||
if (info_type == SCANNER_TYPE_FUNCTION)
|
if (info_type == SCANNER_TYPE_FUNCTION && !(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY))
|
||||||
{
|
{
|
||||||
JERRY_ASSERT (context_p->scope_stack_p == NULL);
|
JERRY_ASSERT (context_p->scope_stack_p == NULL);
|
||||||
|
|
||||||
@@ -1492,59 +1526,55 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
|
|||||||
|
|
||||||
if (stack_size == 0)
|
if (stack_size == 0)
|
||||||
{
|
{
|
||||||
scanner_release_next (context_p, sizeof (scanner_function_info_t) + 1);
|
if (!(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_ARGS))
|
||||||
|
{
|
||||||
|
scanner_release_next (context_p, sizeof (scanner_info_t) + 1);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scope_stack_p = (parser_scope_stack *) parser_malloc (context_p, stack_size);
|
scope_stack_p = (parser_scope_stack *) parser_malloc (context_p, stack_size);
|
||||||
context_p->scope_stack_p = scope_stack_p;
|
context_p->scope_stack_p = scope_stack_p;
|
||||||
scope_stack_end_p = scope_stack_p + context_p->scope_stack_size;
|
scope_stack_end_p = scope_stack_p + context_p->scope_stack_size;
|
||||||
|
|
||||||
data_p = ((const uint8_t *) info_p) + sizeof (scanner_function_info_t);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JERRY_ASSERT (context_p->scope_stack_p != NULL);
|
JERRY_ASSERT (context_p->scope_stack_p != NULL);
|
||||||
|
|
||||||
scope_stack_p = context_p->scope_stack_p;
|
scope_stack_p = context_p->scope_stack_p;
|
||||||
scope_stack_end_p = scope_stack_p + context_p->scope_stack_size;
|
scope_stack_end_p = scope_stack_p + context_p->scope_stack_size;
|
||||||
scope_stack_p += context_p->scope_stack_top;
|
scope_stack_p += context_p->scope_stack_top;
|
||||||
|
|
||||||
data_p = ((const uint8_t *) info_p) + sizeof (scanner_info_t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t scope_stack_reg_top = context_p->scope_stack_reg_top;
|
uint32_t scope_stack_reg_top = context_p->scope_stack_reg_top;
|
||||||
|
|
||||||
literal.char_p = info_p->source_p - 1;
|
literal.char_p = info_p->source_p - 1;
|
||||||
|
|
||||||
while (data_p[0] != SCANNER_STREAM_TYPE_END)
|
while (next_data_p[0] != SCANNER_STREAM_TYPE_END)
|
||||||
{
|
{
|
||||||
uint32_t type = data_p[0] & SCANNER_STREAM_TYPE_MASK;
|
uint32_t type = next_data_p[0] & SCANNER_STREAM_TYPE_MASK;
|
||||||
|
const uint8_t *data_p = next_data_p;
|
||||||
|
|
||||||
if (JERRY_UNLIKELY (scope_stack_p >= scope_stack_end_p))
|
JERRY_ASSERT ((option_flags & (SCANNER_CREATE_VARS_IS_FUNCTION_BODY | SCANNER_CREATE_VARS_IS_FUNCTION_ARGS))
|
||||||
{
|
|| (type != SCANNER_STREAM_TYPE_HOLE
|
||||||
JERRY_ASSERT (context_p->scope_stack_size == PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK);
|
&& type != SCANNER_STREAM_TYPE_ARG
|
||||||
parser_raise_error (context_p, PARSER_ERR_SCOPE_STACK_LIMIT_REACHED);
|
&& type != SCANNER_STREAM_TYPE_ARG_FUNC));
|
||||||
}
|
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
|
||||||
|
JERRY_ASSERT (type != SCANNER_STREAM_TYPE_IMPORT || (data_p[0] & SCANNER_STREAM_NO_REG));
|
||||||
|
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
|
||||||
|
|
||||||
if (type == SCANNER_STREAM_TYPE_HOLE)
|
if (type == SCANNER_STREAM_TYPE_HOLE)
|
||||||
{
|
{
|
||||||
data_p++;
|
next_data_p++;
|
||||||
|
|
||||||
JERRY_ASSERT (info_type == SCANNER_TYPE_FUNCTION);
|
if (option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (info_p->u8_arg & SCANNER_FUNCTION_ARGUMENTS_NEEDED)
|
if (info_p->u8_arg & SCANNER_FUNCTION_ARGUMENTS_NEEDED)
|
||||||
{
|
{
|
||||||
if (JERRY_UNLIKELY (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS))
|
scanner_create_unused_literal (context_p, LEXER_FLAG_FUNCTION_ARGUMENT);
|
||||||
{
|
|
||||||
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
|
|
||||||
}
|
|
||||||
|
|
||||||
lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
|
|
||||||
|
|
||||||
literal_p->type = LEXER_UNUSED_LITERAL;
|
|
||||||
literal_p->status_flags = LEXER_FLAG_FUNCTION_ARGUMENT;
|
|
||||||
|
|
||||||
context_p->literal_count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
|
if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
|
||||||
@@ -1554,19 +1584,17 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t length;
|
|
||||||
|
|
||||||
if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF))
|
if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF))
|
||||||
{
|
{
|
||||||
if (data_p[2] != 0)
|
if (data_p[2] != 0)
|
||||||
{
|
{
|
||||||
literal.char_p += data_p[2];
|
literal.char_p += data_p[2];
|
||||||
length = 2 + 1;
|
next_data_p += 2 + 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy (&literal.char_p, data_p + 2 + 1, sizeof (const uint8_t *));
|
memcpy (&literal.char_p, data_p + 2 + 1, sizeof (const uint8_t *));
|
||||||
length = 2 + 1 + sizeof (const uint8_t *);
|
next_data_p += 2 + 1 + sizeof (const uint8_t *);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1579,7 +1607,22 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
|
|||||||
}
|
}
|
||||||
|
|
||||||
literal.char_p += diff;
|
literal.char_p += diff;
|
||||||
length = 2 + 2;
|
next_data_p += 2 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == SCANNER_STREAM_TYPE_ARG)
|
||||||
|
{
|
||||||
|
if (option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY)
|
||||||
|
{
|
||||||
|
literal.char_p += data_p[1];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_ARGS)
|
||||||
|
&& type != SCANNER_STREAM_TYPE_ARG_FUNC)
|
||||||
|
{
|
||||||
|
/* Function arguments must come first. */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
literal.length = data_p[1];
|
literal.length = data_p[1];
|
||||||
@@ -1587,16 +1630,39 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
|
|||||||
literal.has_escape = (data_p[0] & SCANNER_STREAM_HAS_ESCAPE) ? 1 : 0;
|
literal.has_escape = (data_p[0] & SCANNER_STREAM_HAS_ESCAPE) ? 1 : 0;
|
||||||
|
|
||||||
lexer_construct_literal_object (context_p, &literal, LEXER_NEW_IDENT_LITERAL);
|
lexer_construct_literal_object (context_p, &literal, LEXER_NEW_IDENT_LITERAL);
|
||||||
|
literal.char_p += data_p[1];
|
||||||
|
|
||||||
|
if (type == SCANNER_STREAM_TYPE_ARG_FUNC && (option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY))
|
||||||
|
{
|
||||||
|
JERRY_ASSERT (scope_stack_p >= context_p->scope_stack_p + 2);
|
||||||
|
|
||||||
|
parser_scope_stack *function_map_p = scope_stack_p - 2;
|
||||||
|
uint16_t literal_index = context_p->lit_object.index;
|
||||||
|
|
||||||
|
while (literal_index != function_map_p->map_from)
|
||||||
|
{
|
||||||
|
function_map_p--;
|
||||||
|
|
||||||
|
JERRY_ASSERT (function_map_p >= context_p->scope_stack_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
JERRY_ASSERT (function_map_p[1].map_from == PARSER_SCOPE_STACK_FUNC);
|
||||||
|
|
||||||
|
parser_emit_cbc_literal_value (context_p, CBC_SET_VAR_FUNC, function_map_p[1].map_to, function_map_p[0].map_to);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JERRY_UNLIKELY (scope_stack_p >= scope_stack_end_p))
|
||||||
|
{
|
||||||
|
JERRY_ASSERT (context_p->scope_stack_size == PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK);
|
||||||
|
parser_raise_error (context_p, PARSER_ERR_SCOPE_STACK_LIMIT_REACHED);
|
||||||
|
}
|
||||||
|
|
||||||
scope_stack_p->map_from = context_p->lit_object.index;
|
scope_stack_p->map_from = context_p->lit_object.index;
|
||||||
|
|
||||||
uint16_t map_to;
|
uint16_t map_to;
|
||||||
uint16_t func_init_opcode = CBC_INIT_LOCAL;
|
uint16_t func_init_opcode = CBC_INIT_LOCAL;
|
||||||
|
|
||||||
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
|
|
||||||
JERRY_ASSERT (type != SCANNER_STREAM_TYPE_IMPORT || (data_p[0] & SCANNER_STREAM_NO_REG));
|
|
||||||
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
|
|
||||||
|
|
||||||
#if ENABLED (JERRY_ES2015)
|
#if ENABLED (JERRY_ES2015)
|
||||||
if (info_type == SCANNER_TYPE_FUNCTION)
|
if (info_type == SCANNER_TYPE_FUNCTION)
|
||||||
{
|
{
|
||||||
@@ -1682,6 +1748,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCANNER_STREAM_TYPE_ARG:
|
case SCANNER_STREAM_TYPE_ARG:
|
||||||
|
case SCANNER_STREAM_TYPE_ARG_FUNC:
|
||||||
{
|
{
|
||||||
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
|
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
|
||||||
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
|
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
|
||||||
@@ -1691,14 +1758,12 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
|
|||||||
CBC_INIT_LOCAL,
|
CBC_INIT_LOCAL,
|
||||||
(uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top),
|
(uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top),
|
||||||
map_to);
|
map_to);
|
||||||
/* FALLTHRU */
|
|
||||||
}
|
|
||||||
case SCANNER_STREAM_TYPE_ARG_FUNC:
|
|
||||||
{
|
|
||||||
if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
|
if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
|
||||||
{
|
{
|
||||||
scope_stack_reg_top++;
|
scope_stack_reg_top++;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1706,9 +1771,6 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
|
|||||||
|
|
||||||
scope_stack_p++;
|
scope_stack_p++;
|
||||||
|
|
||||||
literal.char_p += data_p[1];
|
|
||||||
data_p += length;
|
|
||||||
|
|
||||||
if (!SCANNER_STREAM_TYPE_IS_FUNCTION (type))
|
if (!SCANNER_STREAM_TYPE_IS_FUNCTION (type))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -1720,37 +1782,34 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
|
|||||||
parser_raise_error (context_p, PARSER_ERR_SCOPE_STACK_LIMIT_REACHED);
|
parser_raise_error (context_p, PARSER_ERR_SCOPE_STACK_LIMIT_REACHED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JERRY_UNLIKELY (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS))
|
|
||||||
{
|
|
||||||
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
|
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
|
||||||
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
|
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
|
||||||
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
|
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
|
||||||
|
|
||||||
if (func_init_opcode == CBC_INIT_LOCAL
|
if (type != SCANNER_STREAM_TYPE_ARG_FUNC)
|
||||||
&& (option_flags & SCANNER_CREATE_VARS_IS_EVAL))
|
|
||||||
{
|
{
|
||||||
func_init_opcode = CBC_CREATE_VAR_FUNC_EVAL;
|
if (func_init_opcode == CBC_INIT_LOCAL
|
||||||
}
|
&& (option_flags & SCANNER_CREATE_VARS_IS_EVAL))
|
||||||
|
{
|
||||||
|
func_init_opcode = CBC_CREATE_VAR_FUNC_EVAL;
|
||||||
|
}
|
||||||
|
|
||||||
parser_emit_cbc_literal_value (context_p, func_init_opcode, context_p->literal_count, map_to);
|
parser_emit_cbc_literal_value (context_p, func_init_opcode, context_p->literal_count, map_to);
|
||||||
|
}
|
||||||
|
|
||||||
scope_stack_p->map_from = PARSER_SCOPE_STACK_FUNC;
|
scope_stack_p->map_from = PARSER_SCOPE_STACK_FUNC;
|
||||||
scope_stack_p->map_to = context_p->literal_count;
|
scope_stack_p->map_to = context_p->literal_count;
|
||||||
scope_stack_p++;
|
scope_stack_p++;
|
||||||
|
|
||||||
lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
|
scanner_create_unused_literal (context_p, 0);
|
||||||
|
|
||||||
literal_p->type = LEXER_UNUSED_LITERAL;
|
|
||||||
literal_p->status_flags = 0;
|
|
||||||
|
|
||||||
context_p->literal_count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info_type == SCANNER_TYPE_FUNCTION && (info_p->u8_arg & SCANNER_FUNCTION_ARGUMENTS_NEEDED))
|
if (info_type == SCANNER_TYPE_FUNCTION
|
||||||
|
&& !(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_BODY)
|
||||||
|
&& (info_p->u8_arg & SCANNER_FUNCTION_ARGUMENTS_NEEDED))
|
||||||
{
|
{
|
||||||
|
JERRY_ASSERT (info_type == SCANNER_TYPE_FUNCTION);
|
||||||
|
|
||||||
if (JERRY_UNLIKELY (scope_stack_p >= scope_stack_end_p))
|
if (JERRY_UNLIKELY (scope_stack_p >= scope_stack_end_p))
|
||||||
{
|
{
|
||||||
JERRY_ASSERT (context_p->scope_stack_size == PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK);
|
JERRY_ASSERT (context_p->scope_stack_size == PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK);
|
||||||
@@ -1781,7 +1840,10 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
|
|||||||
context_p->register_count = (uint16_t) scope_stack_reg_top;
|
context_p->register_count = (uint16_t) scope_stack_reg_top;
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner_release_next (context_p, (size_t) (data_p + 1 - ((const uint8_t *) info_p)));
|
if (!(option_flags & SCANNER_CREATE_VARS_IS_FUNCTION_ARGS))
|
||||||
|
{
|
||||||
|
scanner_release_next (context_p, (size_t) (next_data_p + 1 - ((const uint8_t *) info_p)));
|
||||||
|
}
|
||||||
parser_flush_cbc (context_p);
|
parser_flush_cbc (context_p);
|
||||||
} /* scanner_create_variables */
|
} /* scanner_create_variables */
|
||||||
|
|
||||||
|
|||||||
@@ -2632,12 +2632,11 @@ scan_completed:
|
|||||||
|
|
||||||
if (info_p->type == SCANNER_TYPE_FUNCTION)
|
if (info_p->type == SCANNER_TYPE_FUNCTION)
|
||||||
{
|
{
|
||||||
scanner_function_info_t *function_info_p = (scanner_function_info_t *) info_p;
|
data_p = (const uint8_t *) (info_p + 1);
|
||||||
data_p = (const uint8_t *) (function_info_p + 1);
|
|
||||||
|
|
||||||
JERRY_DEBUG_MSG (" FUNCTION: flags: 0x%x declarations: %d",
|
JERRY_DEBUG_MSG (" FUNCTION: flags: 0x%x declarations: %d",
|
||||||
(int) function_info_p->info.u8_arg,
|
(int) info_p->u8_arg,
|
||||||
(int) function_info_p->info.u16_arg);
|
(int) info_p->u16_arg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -175,14 +175,6 @@ typedef enum
|
|||||||
SCANNER_FUNCTION_ARGUMENTS_NEEDED = (1 << 0), /**< arguments object needs to be created */
|
SCANNER_FUNCTION_ARGUMENTS_NEEDED = (1 << 0), /**< arguments object needs to be created */
|
||||||
} scanner_function_flags_t;
|
} scanner_function_flags_t;
|
||||||
|
|
||||||
/**
|
|
||||||
* Scanner info for function statements.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
scanner_info_t info; /**< header */
|
|
||||||
} scanner_function_info_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Option bits for scanner_create_variables function.
|
* Option bits for scanner_create_variables function.
|
||||||
*/
|
*/
|
||||||
@@ -190,6 +182,8 @@ typedef enum
|
|||||||
{
|
{
|
||||||
SCANNER_CREATE_VARS_NO_OPTS = 0, /**< no options */
|
SCANNER_CREATE_VARS_NO_OPTS = 0, /**< no options */
|
||||||
SCANNER_CREATE_VARS_IS_EVAL = (1 << 0), /**< create variables for script / direct eval */
|
SCANNER_CREATE_VARS_IS_EVAL = (1 << 0), /**< create variables for script / direct eval */
|
||||||
|
SCANNER_CREATE_VARS_IS_FUNCTION_ARGS = (1 << 1), /**< create variables for function arguments */
|
||||||
|
SCANNER_CREATE_VARS_IS_FUNCTION_BODY = (1 << 2), /**< create variables for function body */
|
||||||
} scanner_create_variables_flags_t;
|
} scanner_create_variables_flags_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -949,7 +949,6 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLED (JERRY_ES2015)
|
|
||||||
case CBC_SET_VAR_FUNC:
|
case CBC_SET_VAR_FUNC:
|
||||||
{
|
{
|
||||||
uint32_t literal_index, value_index;
|
uint32_t literal_index, value_index;
|
||||||
@@ -966,8 +965,6 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
|||||||
|
|
||||||
if (literal_index < register_end)
|
if (literal_index < register_end)
|
||||||
{
|
{
|
||||||
JERRY_ASSERT (type == CBC_SET_VAR_FUNC);
|
|
||||||
|
|
||||||
ecma_fast_free_value (frame_ctx_p->registers_p[literal_index]);
|
ecma_fast_free_value (frame_ctx_p->registers_p[literal_index]);
|
||||||
frame_ctx_p->registers_p[literal_index] = lit_value;
|
frame_ctx_p->registers_p[literal_index] = lit_value;
|
||||||
break;
|
break;
|
||||||
@@ -978,7 +975,6 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
|||||||
vm_set_var (frame_ctx_p->lex_env_p, name_p, is_strict, lit_value);
|
vm_set_var (frame_ctx_p->lex_env_p, name_p, is_strict, lit_value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif /* ENABLED (JERRY_ES2015) */
|
|
||||||
|
|
||||||
#if ENABLED (JERRY_SNAPSHOT_EXEC)
|
#if ENABLED (JERRY_SNAPSHOT_EXEC)
|
||||||
case CBC_SET_BYTECODE_PTR:
|
case CBC_SET_BYTECODE_PTR:
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
function f(a, b = a)
|
||||||
|
{
|
||||||
|
function a() { return 2; }
|
||||||
|
|
||||||
|
assert(a() === 2);
|
||||||
|
assert(b === 1)
|
||||||
|
}
|
||||||
|
f(1);
|
||||||
|
|
||||||
|
function g(a, b = a)
|
||||||
|
{
|
||||||
|
function a() { return 2; }
|
||||||
|
|
||||||
|
eval("assert(a() === 2)");
|
||||||
|
eval("assert(b === 1)");
|
||||||
|
}
|
||||||
|
g(1);
|
||||||
|
|
||||||
|
var x = 1;
|
||||||
|
function h(a = x) {
|
||||||
|
assert(x === undefined);
|
||||||
|
var x = 2;
|
||||||
|
assert(a === 1);
|
||||||
|
assert(x === 2);
|
||||||
|
}
|
||||||
|
h();
|
||||||
|
|
||||||
|
x = function() { return 4; }
|
||||||
|
let y = 6;
|
||||||
|
|
||||||
|
function i(a = x() / 2, b = (y) + 2, c = typeof z) {
|
||||||
|
let y = 10;
|
||||||
|
let z = 11;
|
||||||
|
|
||||||
|
function x() { return 5; }
|
||||||
|
|
||||||
|
assert(a === 2);
|
||||||
|
assert(x() === 5);
|
||||||
|
assert(b === 8);
|
||||||
|
assert(c === "undefined");
|
||||||
|
assert(y === 10);
|
||||||
|
assert(z === 11);
|
||||||
|
}
|
||||||
|
i();
|
||||||
|
|
||||||
|
var arguments = 10;
|
||||||
|
function j(a = arguments[1])
|
||||||
|
{
|
||||||
|
assert(a === 2);
|
||||||
|
}
|
||||||
|
j(undefined,2);
|
||||||
Reference in New Issue
Block a user