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:
Zoltan Herczeg 2019-11-08 12:18:23 +01:00 committed by Dániel Bátyai
parent 923fd128b5
commit e1fc90db0e
7 changed files with 223 additions and 92 deletions

View File

@ -320,6 +320,14 @@ typedef struct
/**
* 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
@ -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_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_switch_cases (scanner_case_info_t *case_p);
void scanner_seek (parser_context_t *context_p);

View File

@ -1617,13 +1617,16 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */
#endif /* ENABLED (JERRY_ES2015) */
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)
{
scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
return;
}
scanner_create_variables (context_p, SCANNER_CREATE_VARS_IS_FUNCTION_ARGS);
scanner_set_active (context_p);
while (true)
{
#if ENABLED (JERRY_ES2015)
@ -1730,6 +1733,9 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */
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 */
/**

View File

@ -258,6 +258,19 @@ scanner_set_active (parser_context_t *context_p) /**< context */
context_p->active_scanner_info_p = scanner_info_p;
} /* 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.
*/
@ -394,7 +407,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
lexer_lit_location_t *literal_p;
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 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);
#if ENABLED (JERRY_ES2015)
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))
{
compressed_size += is_function ? sizeof (scanner_function_info_t) : sizeof (scanner_info_t);
compressed_size += sizeof (scanner_info_t);
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;
}
uint8_t *data_p = (uint8_t *) info_p;
uint8_t *data_p = (uint8_t *) (info_p + 1);
if (is_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;
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;
function_info_p->info.u16_arg = (uint16_t) no_declarations;
info_p->u8_arg = status_flags;
info_p->u16_arg = (uint16_t) no_declarations;
}
else
{
info_p->type = SCANNER_TYPE_BLOCK;
data_p += sizeof (scanner_info_t);
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;
lexer_lit_location_t *literal_p;
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)
{
@ -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)
{
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;
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;
}
case SCANNER_TYPE_FUNCTION:
{
size = scanner_get_stream_size (scanner_info_p, sizeof (scanner_function_info_t));
break;
}
case SCANNER_TYPE_BLOCK:
{
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_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;
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
};
/**
* 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.
*/
@ -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 */
{
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;
lexer_lit_location_t literal;
parser_scope_stack *scope_stack_p;
parser_scope_stack *scope_stack_end_p;
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);
@ -1492,59 +1526,55 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
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;
}
scope_stack_p = (parser_scope_stack *) parser_malloc (context_p, stack_size);
context_p->scope_stack_p = scope_stack_p;
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
{
JERRY_ASSERT (context_p->scope_stack_p != NULL);
scope_stack_p = context_p->scope_stack_p;
scope_stack_end_p = scope_stack_p + context_p->scope_stack_size;
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;
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 (context_p->scope_stack_size == PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK);
parser_raise_error (context_p, PARSER_ERR_SCOPE_STACK_LIMIT_REACHED);
}
JERRY_ASSERT ((option_flags & (SCANNER_CREATE_VARS_IS_FUNCTION_BODY | SCANNER_CREATE_VARS_IS_FUNCTION_ARGS))
|| (type != SCANNER_STREAM_TYPE_HOLE
&& type != SCANNER_STREAM_TYPE_ARG
&& 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)
{
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 (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 = LEXER_FLAG_FUNCTION_ARGUMENT;
context_p->literal_count++;
scanner_create_unused_literal (context_p, LEXER_FLAG_FUNCTION_ARGUMENT);
}
if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
@ -1554,19 +1584,17 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
continue;
}
size_t length;
if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF))
{
if (data_p[2] != 0)
{
literal.char_p += data_p[2];
length = 2 + 1;
next_data_p += 2 + 1;
}
else
{
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
@ -1579,7 +1607,22 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
}
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];
@ -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;
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;
uint16_t map_to;
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 (info_type == SCANNER_TYPE_FUNCTION)
{
@ -1682,6 +1748,7 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
break;
}
case SCANNER_STREAM_TYPE_ARG:
case SCANNER_STREAM_TYPE_ARG_FUNC:
{
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
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,
(uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top),
map_to);
/* FALLTHRU */
}
case SCANNER_STREAM_TYPE_ARG_FUNC:
{
if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
{
scope_stack_reg_top++;
}
break;
}
}
}
@ -1706,9 +1771,6 @@ scanner_create_variables (parser_context_t *context_p, /**< context */
scope_stack_p++;
literal.char_p += data_p[1];
data_p += length;
if (!SCANNER_STREAM_TYPE_IS_FUNCTION (type))
{
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);
}
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)
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
if (func_init_opcode == CBC_INIT_LOCAL
&& (option_flags & SCANNER_CREATE_VARS_IS_EVAL))
if (type != SCANNER_STREAM_TYPE_ARG_FUNC)
{
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_to = context_p->literal_count;
scope_stack_p++;
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 = 0;
context_p->literal_count++;
scanner_create_unused_literal (context_p, 0);
}
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))
{
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;
}
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);
} /* scanner_create_variables */

View File

@ -2632,12 +2632,11 @@ scan_completed:
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 *) (function_info_p + 1);
data_p = (const uint8_t *) (info_p + 1);
JERRY_DEBUG_MSG (" FUNCTION: flags: 0x%x declarations: %d",
(int) function_info_p->info.u8_arg,
(int) function_info_p->info.u16_arg);
(int) info_p->u8_arg,
(int) info_p->u16_arg);
}
else
{

View File

@ -175,14 +175,6 @@ typedef enum
SCANNER_FUNCTION_ARGUMENTS_NEEDED = (1 << 0), /**< arguments object needs to be created */
} 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.
*/
@ -190,6 +182,8 @@ typedef enum
{
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_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;
/**

View File

@ -949,7 +949,6 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
break;
}
#if ENABLED (JERRY_ES2015)
case CBC_SET_VAR_FUNC:
{
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)
{
JERRY_ASSERT (type == CBC_SET_VAR_FUNC);
ecma_fast_free_value (frame_ctx_p->registers_p[literal_index]);
frame_ctx_p->registers_p[literal_index] = lit_value;
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);
break;
}
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_SNAPSHOT_EXEC)
case CBC_SET_BYTECODE_PTR:

View File

@ -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);