Create function variables using the data produced by the pre-scanner. (#3199)
The pre-scanner now is able to track all variable declarations and produces a compressed stream which store this data for each function and catch block. When a function or catch block is parsed, this information is decoded and the appropriate variables are created. Furthermore a stack scope is created which contains the currently available local variables and their register or literal index. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
@@ -30,7 +30,7 @@ extern "C"
|
||||
/**
|
||||
* Jerry snapshot format version.
|
||||
*/
|
||||
#define JERRY_SNAPSHOT_VERSION (24u)
|
||||
#define JERRY_SNAPSHOT_VERSION (25u)
|
||||
|
||||
/**
|
||||
* Flags for jerry_generate_snapshot and jerry_generate_function_snapshot.
|
||||
|
||||
@@ -298,11 +298,9 @@
|
||||
VM_OC_NEW | VM_OC_PUT_STACK) \
|
||||
CBC_OPCODE (CBC_EVAL, CBC_NO_FLAG, 0, \
|
||||
VM_OC_EVAL) \
|
||||
CBC_OPCODE (CBC_DEFINE_VARS, CBC_HAS_LITERAL_ARG, 0, \
|
||||
CBC_OPCODE (CBC_CREATE_VAR, CBC_HAS_LITERAL_ARG, 0, \
|
||||
VM_OC_NONE) \
|
||||
CBC_OPCODE (CBC_INITIALIZE_VAR, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
|
||||
VM_OC_NONE) \
|
||||
CBC_OPCODE (CBC_INITIALIZE_VARS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
|
||||
CBC_OPCODE (CBC_INIT_LOCAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
|
||||
VM_OC_NONE) \
|
||||
CBC_OPCODE (CBC_SET_BYTECODE_PTR, CBC_NO_FLAG, 0, \
|
||||
VM_OC_NONE) \
|
||||
|
||||
@@ -85,14 +85,7 @@ util_print_literal (lexer_literal_t *literal_p) /**< literal */
|
||||
{
|
||||
if (literal_p->type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
if (literal_p->status_flags & LEXER_FLAG_VAR)
|
||||
{
|
||||
JERRY_DEBUG_MSG ("var_ident(");
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_DEBUG_MSG ("ident(");
|
||||
}
|
||||
JERRY_DEBUG_MSG ("ident(");
|
||||
util_print_chars (literal_p->u.char_p, literal_p->prop.length);
|
||||
}
|
||||
else if (literal_p->type == LEXER_FUNCTION_LITERAL)
|
||||
|
||||
@@ -55,6 +55,8 @@ typedef enum
|
||||
LEXER_REGEXP_LITERAL = 4, /**< regexp literal */
|
||||
LEXER_UNUSED_LITERAL = 5, /**< unused literal, can only be
|
||||
used by the byte code generator. */
|
||||
LEXER_NEW_IDENT_LITERAL = 6, /**< new local variable, can only be
|
||||
used by the byte code generator. */
|
||||
} lexer_literal_type_t;
|
||||
|
||||
/**
|
||||
@@ -67,15 +69,11 @@ typedef enum
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
LEXER_FLAG_VAR = (1 << 0), /**< local identifier (var, function arg) */
|
||||
LEXER_FLAG_NO_REG_STORE = (1 << 1), /**< this local identifier cannot be stored in register */
|
||||
LEXER_FLAG_INITIALIZED = (1 << 2), /**< this local identifier is initialized with a value */
|
||||
LEXER_FLAG_FUNCTION_ARGUMENT = (1 << 3), /**< this local identifier is a function argument */
|
||||
LEXER_FLAG_UNUSED_IDENT = (1 << 4), /**< this identifier is referenced by sub-functions,
|
||||
* but not referenced by the currently parsed function */
|
||||
LEXER_FLAG_SOURCE_PTR = (1 << 5), /**< the literal is directly referenced in the source code
|
||||
LEXER_FLAG_USED = (1 << 0), /**< this local identifier needs to be stored in the constant pool */
|
||||
LEXER_FLAG_FUNCTION_ARGUMENT = (1 << 1), /**< this local identifier is a function argument */
|
||||
LEXER_FLAG_SOURCE_PTR = (1 << 2), /**< the literal is directly referenced in the source code
|
||||
* (no need to allocate memory) */
|
||||
LEXER_FLAG_LATE_INIT = (1 << 6), /**< initialize this variable after the byte code is freed */
|
||||
LEXER_FLAG_LATE_INIT = (1 << 3), /**< initialize this variable after the byte code is freed */
|
||||
} lexer_literal_status_flags_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1387,7 +1387,7 @@ lexer_next_token (parser_context_t *context_p) /**< context */
|
||||
#undef LEXER_TYPE_D_TOKEN
|
||||
|
||||
/**
|
||||
* Checks whether the next token is the specified character.
|
||||
* Checks whether the next token starts with the specified character.
|
||||
*
|
||||
* @return true - if the next is the specified character
|
||||
* false - otherwise
|
||||
@@ -1443,6 +1443,12 @@ lexer_process_char_literal (parser_context_t *context_p, /**< context */
|
||||
parser_list_iterator_t literal_iterator;
|
||||
lexer_literal_t *literal_p;
|
||||
uint32_t literal_index = 0;
|
||||
bool search_scope_stack = (literal_type == LEXER_IDENT_LITERAL);
|
||||
|
||||
if (JERRY_UNLIKELY (literal_type == LEXER_NEW_IDENT_LITERAL))
|
||||
{
|
||||
literal_type = LEXER_IDENT_LITERAL;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (literal_type == LEXER_IDENT_LITERAL
|
||||
|| literal_type == LEXER_STRING_LITERAL);
|
||||
@@ -1460,7 +1466,27 @@ lexer_process_char_literal (parser_context_t *context_p, /**< context */
|
||||
{
|
||||
context_p->lit_object.literal_p = literal_p;
|
||||
context_p->lit_object.index = (uint16_t) literal_index;
|
||||
literal_p->status_flags = (uint8_t) (literal_p->status_flags & ~LEXER_FLAG_UNUSED_IDENT);
|
||||
|
||||
if (search_scope_stack)
|
||||
{
|
||||
parser_scope_stack *scope_stack_start_p = context_p->scope_stack_p;
|
||||
parser_scope_stack *scope_stack_p = scope_stack_start_p + context_p->scope_stack_top;
|
||||
|
||||
while (scope_stack_p > scope_stack_start_p)
|
||||
{
|
||||
scope_stack_p--;
|
||||
|
||||
if (scope_stack_p->map_from == literal_index)
|
||||
{
|
||||
JERRY_ASSERT (scope_stack_p->map_to >= PARSER_REGISTER_START
|
||||
|| (literal_p->status_flags & LEXER_FLAG_USED));
|
||||
context_p->lit_object.index = scope_stack_p->map_to;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
literal_p->status_flags |= LEXER_FLAG_USED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1482,10 +1508,12 @@ lexer_process_char_literal (parser_context_t *context_p, /**< context */
|
||||
literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
|
||||
literal_p->prop.length = (prop_length_t) length;
|
||||
literal_p->type = literal_type;
|
||||
literal_p->status_flags = has_escape ? 0 : LEXER_FLAG_SOURCE_PTR;
|
||||
|
||||
uint8_t status_flags = LEXER_FLAG_SOURCE_PTR;
|
||||
|
||||
if (has_escape)
|
||||
{
|
||||
status_flags = 0;
|
||||
literal_p->u.char_p = (uint8_t *) jmem_heap_alloc_block (length);
|
||||
memcpy ((uint8_t *) literal_p->u.char_p, char_p, length);
|
||||
}
|
||||
@@ -1494,6 +1522,13 @@ lexer_process_char_literal (parser_context_t *context_p, /**< context */
|
||||
literal_p->u.char_p = char_p;
|
||||
}
|
||||
|
||||
if (search_scope_stack)
|
||||
{
|
||||
status_flags |= LEXER_FLAG_USED;
|
||||
}
|
||||
|
||||
literal_p->status_flags = status_flags;
|
||||
|
||||
context_p->lit_object.literal_p = literal_p;
|
||||
context_p->lit_object.index = (uint16_t) literal_index;
|
||||
context_p->literal_count++;
|
||||
@@ -1509,7 +1544,7 @@ lexer_process_char_literal (parser_context_t *context_p, /**< context */
|
||||
*/
|
||||
void
|
||||
lexer_construct_literal_object (parser_context_t *context_p, /**< context */
|
||||
lexer_lit_location_t *literal_p, /**< literal location */
|
||||
const lexer_lit_location_t *literal_p, /**< literal location */
|
||||
uint8_t literal_type) /**< final literal type */
|
||||
{
|
||||
uint8_t *destination_start_p;
|
||||
@@ -1518,7 +1553,7 @@ lexer_construct_literal_object (parser_context_t *context_p, /**< context */
|
||||
|
||||
JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL
|
||||
|| literal_p->type == LEXER_STRING_LITERAL);
|
||||
JERRY_ASSERT (context_p->allocated_buffer_p == NULL);
|
||||
JERRY_ASSERT (context_p->u.allocated_buffer_p == NULL);
|
||||
|
||||
destination_start_p = local_byte_array;
|
||||
source_p = literal_p->char_p;
|
||||
@@ -1530,7 +1565,7 @@ lexer_construct_literal_object (parser_context_t *context_p, /**< context */
|
||||
if (literal_p->length > LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE)
|
||||
{
|
||||
destination_start_p = (uint8_t *) parser_malloc_local (context_p, literal_p->length);
|
||||
context_p->allocated_buffer_p = destination_start_p;
|
||||
context_p->u.allocated_buffer_p = destination_start_p;
|
||||
context_p->allocated_buffer_size = literal_p->length;
|
||||
}
|
||||
|
||||
@@ -1764,16 +1799,8 @@ lexer_construct_literal_object (parser_context_t *context_p, /**< context */
|
||||
literal_type,
|
||||
literal_p->has_escape);
|
||||
|
||||
JERRY_ASSERT (literal_type == context_p->lit_object.literal_p->type);
|
||||
|
||||
context_p->lit_object.type = LEXER_LITERAL_OBJECT_ANY;
|
||||
|
||||
if (literal_type == LEXER_IDENT_LITERAL
|
||||
&& (context_p->status_flags & PARSER_INSIDE_WITH))
|
||||
{
|
||||
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
|
||||
}
|
||||
|
||||
if (literal_p->length == 4
|
||||
&& source_p[0] == LIT_CHAR_LOWERCASE_E
|
||||
&& source_p[3] == LIT_CHAR_LOWERCASE_L
|
||||
@@ -1789,24 +1816,18 @@ lexer_construct_literal_object (parser_context_t *context_p, /**< context */
|
||||
&& memcmp (source_p + 1, "rgument", 7) == 0)
|
||||
{
|
||||
context_p->lit_object.type = LEXER_LITERAL_OBJECT_ARGUMENTS;
|
||||
if (!(context_p->status_flags & PARSER_ARGUMENTS_NOT_NEEDED)
|
||||
&& literal_type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED;
|
||||
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
|
||||
}
|
||||
}
|
||||
|
||||
if (destination_start_p != local_byte_array)
|
||||
{
|
||||
JERRY_ASSERT (context_p->allocated_buffer_p == destination_start_p);
|
||||
JERRY_ASSERT (context_p->u.allocated_buffer_p == destination_start_p);
|
||||
|
||||
context_p->allocated_buffer_p = NULL;
|
||||
context_p->u.allocated_buffer_p = NULL;
|
||||
parser_free_local (destination_start_p,
|
||||
context_p->allocated_buffer_size);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (context_p->allocated_buffer_p == NULL);
|
||||
JERRY_ASSERT (context_p->u.allocated_buffer_p == NULL);
|
||||
} /* lexer_construct_literal_object */
|
||||
|
||||
#undef LEXER_MAX_LITERAL_LOCAL_BUFFER_SIZE
|
||||
@@ -2251,7 +2272,8 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */
|
||||
uint8_t literal_type) /**< literal type */
|
||||
{
|
||||
JERRY_ASSERT (literal_type == LEXER_STRING_LITERAL
|
||||
|| literal_type == LEXER_IDENT_LITERAL);
|
||||
|| literal_type == LEXER_IDENT_LITERAL
|
||||
|| literal_type == LEXER_NEW_IDENT_LITERAL);
|
||||
|
||||
lexer_skip_spaces (context_p);
|
||||
context_p->token.line = context_p->line;
|
||||
@@ -2264,11 +2286,13 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */
|
||||
|
||||
if (context_p->token.type == LEXER_LITERAL)
|
||||
{
|
||||
JERRY_ASSERT (context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
|
||||
|
||||
lexer_construct_literal_object (context_p,
|
||||
&context_p->token.lit_location,
|
||||
literal_type);
|
||||
|
||||
if (literal_type == LEXER_IDENT_LITERAL
|
||||
if (literal_type != LEXER_STRING_LITERAL
|
||||
&& (context_p->status_flags & PARSER_IS_STRICT)
|
||||
&& context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY)
|
||||
{
|
||||
@@ -2286,8 +2310,6 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */
|
||||
|
||||
parser_raise_error (context_p, error);
|
||||
}
|
||||
|
||||
context_p->token.lit_location.type = literal_type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2300,9 +2322,7 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */
|
||||
context_p->token.literal_is_reserved = false;
|
||||
context_p->token.lit_location.type = LEXER_IDENT_LITERAL;
|
||||
context_p->token.lit_location.has_escape = false;
|
||||
lexer_construct_literal_object (context_p,
|
||||
(lexer_lit_location_t *) &lexer_default_literal,
|
||||
lexer_default_literal.type);
|
||||
lexer_construct_literal_object (context_p, &lexer_default_literal, lexer_default_literal.type);
|
||||
context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_DEFAULT_CLASS_OR_FUNC);
|
||||
return;
|
||||
}
|
||||
@@ -2519,43 +2539,23 @@ lexer_scan_identifier (parser_context_t *context_p, /**< context */
|
||||
} /* lexer_scan_identifier */
|
||||
|
||||
/**
|
||||
* Compares the current identifier in the context to the parameter identifier
|
||||
* Compares two identifiers.
|
||||
*
|
||||
* Note:
|
||||
* Escape sequences are allowed.
|
||||
* Escape sequences are allowed, size must be the same.
|
||||
*
|
||||
* @return true if the input identifiers are the same
|
||||
* @return true if the two identifiers are the same
|
||||
*/
|
||||
bool
|
||||
lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context */
|
||||
const lexer_lit_location_t *right_ident_p) /**< identifier */
|
||||
lexer_compare_identifiers (const uint8_t *left_p, /**< left identifier */
|
||||
const uint8_t *right_p, /**< right identifier */
|
||||
size_t size) /**< byte size of the two identifiers */
|
||||
{
|
||||
lexer_lit_location_t *left_ident_p = &context_p->token.lit_location;
|
||||
const uint8_t *left_p;
|
||||
const uint8_t *right_p;
|
||||
size_t count;
|
||||
|
||||
JERRY_ASSERT (left_ident_p->length > 0 && right_ident_p->length > 0);
|
||||
|
||||
if (left_ident_p->length != right_ident_p->length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!left_ident_p->has_escape && !right_ident_p->has_escape)
|
||||
{
|
||||
return memcmp (left_ident_p->char_p, right_ident_p->char_p, left_ident_p->length) == 0;
|
||||
}
|
||||
|
||||
left_p = left_ident_p->char_p;
|
||||
right_p = right_ident_p->char_p;
|
||||
count = left_ident_p->length;
|
||||
uint8_t utf8_buf[3];
|
||||
size_t utf8_len, offset;
|
||||
|
||||
do
|
||||
{
|
||||
uint8_t utf8_buf[3];
|
||||
size_t utf8_len, offset;
|
||||
|
||||
/* Backslash cannot be part of a multibyte UTF-8 character. */
|
||||
if (*left_p != LIT_CHAR_BACKSLASH && *right_p != LIT_CHAR_BACKSLASH)
|
||||
{
|
||||
@@ -2563,7 +2563,7 @@ lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context *
|
||||
{
|
||||
return false;
|
||||
}
|
||||
count--;
|
||||
size--;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2578,7 +2578,7 @@ lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context *
|
||||
|
||||
left_p += 6;
|
||||
right_p += 6;
|
||||
count += lit_char_get_utf8_length (left_chr);
|
||||
size -= lit_char_get_utf8_length (left_chr);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2593,7 +2593,7 @@ lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context *
|
||||
|
||||
utf8_len = lit_char_to_utf8_bytes (utf8_buf, lexer_unchecked_hex_to_character (left_p + 2, 4));
|
||||
JERRY_ASSERT (utf8_len > 0);
|
||||
count -= utf8_len;
|
||||
size -= utf8_len;
|
||||
offset = 0;
|
||||
|
||||
do
|
||||
@@ -2608,9 +2608,38 @@ lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context *
|
||||
|
||||
left_p += 6;
|
||||
}
|
||||
while (count > 0);
|
||||
while (size > 0);
|
||||
|
||||
return true;
|
||||
} /* lexer_compare_identifiers */
|
||||
|
||||
/**
|
||||
* Compares the current identifier in the context to the parameter identifier
|
||||
*
|
||||
* Note:
|
||||
* Escape sequences are allowed.
|
||||
*
|
||||
* @return true if the input identifiers are the same
|
||||
*/
|
||||
bool
|
||||
lexer_compare_identifier_to_current (parser_context_t *context_p, /**< context */
|
||||
const lexer_lit_location_t *right_ident_p) /**< identifier */
|
||||
{
|
||||
lexer_lit_location_t *left_ident_p = &context_p->token.lit_location;
|
||||
|
||||
JERRY_ASSERT (left_ident_p->length > 0 && right_ident_p->length > 0);
|
||||
|
||||
if (left_ident_p->length != right_ident_p->length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!left_ident_p->has_escape && !right_ident_p->has_escape)
|
||||
{
|
||||
return memcmp (left_ident_p->char_p, right_ident_p->char_p, left_ident_p->length) == 0;
|
||||
}
|
||||
|
||||
return lexer_compare_identifiers (left_ident_p->char_p, right_ident_p->char_p, left_ident_p->length);
|
||||
} /* lexer_compare_identifier_to_current */
|
||||
|
||||
/**
|
||||
|
||||
@@ -601,7 +601,6 @@ parser_parse_class (parser_context_t *context_p, /**< context */
|
||||
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
|
||||
|
||||
class_ident_index = context_p->lit_object.index;
|
||||
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR;
|
||||
|
||||
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
|
||||
if (context_p->status_flags & PARSER_MODULE_STORE_IDENT)
|
||||
@@ -1167,7 +1166,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
|
||||
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
|
||||
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
|
||||
{
|
||||
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ARROW);
|
||||
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
|
||||
break;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
@@ -1209,8 +1208,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
|
||||
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
|
||||
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
|
||||
{
|
||||
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ARROW);
|
||||
scanner_release_next (context_p, sizeof (scanner_info_t));
|
||||
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
|
||||
|
||||
parser_parse_function_expression (context_p,
|
||||
PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION);
|
||||
@@ -1218,23 +1216,24 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
|
||||
if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
|
||||
|| context_p->token.lit_location.type == LEXER_STRING_LITERAL)
|
||||
uint8_t type = context_p->token.lit_location.type;
|
||||
|
||||
if (type == LEXER_IDENT_LITERAL || type == LEXER_STRING_LITERAL)
|
||||
{
|
||||
lexer_construct_literal_object (context_p,
|
||||
&context_p->token.lit_location,
|
||||
context_p->token.lit_location.type);
|
||||
|
||||
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
|
||||
if (context_p->status_flags & PARSER_MODULE_STORE_IDENT
|
||||
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
|
||||
if ((context_p->status_flags & PARSER_MODULE_STORE_IDENT)
|
||||
&& type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR;
|
||||
context_p->module_identifier_lit_p = context_p->lit_object.literal_p;
|
||||
context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT);
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
|
||||
}
|
||||
else if (context_p->token.lit_location.type == LEXER_NUMBER_LITERAL)
|
||||
else if (type == LEXER_NUMBER_LITERAL)
|
||||
{
|
||||
bool is_negative_number = false;
|
||||
|
||||
@@ -1418,8 +1417,7 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
|
||||
case LEXER_LEFT_PAREN:
|
||||
{
|
||||
JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p
|
||||
&& context_p->next_scanner_info_p->type == SCANNER_TYPE_ARROW);
|
||||
scanner_release_next (context_p, sizeof (scanner_info_t));
|
||||
&& context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
|
||||
|
||||
lexer_next_token (context_p);
|
||||
parser_parse_function_expression (context_p,
|
||||
@@ -1479,7 +1477,8 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */
|
||||
|
||||
lexer_expect_identifier (context_p, LEXER_STRING_LITERAL);
|
||||
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
|
||||
&& context_p->token.lit_location.type == LEXER_STRING_LITERAL);
|
||||
&& context_p->lit_object.literal_p->type == LEXER_STRING_LITERAL);
|
||||
context_p->token.lit_location.type = LEXER_STRING_LITERAL;
|
||||
|
||||
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
|
||||
{
|
||||
@@ -1543,7 +1542,6 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */
|
||||
&& context_p->last_cbc.literal_object_type == LEXER_LITERAL_OBJECT_EVAL
|
||||
&& context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE;
|
||||
is_eval = true;
|
||||
}
|
||||
|
||||
@@ -1796,7 +1794,6 @@ parser_append_binary_token (parser_context_t *context_p) /**< context */
|
||||
parser_stack_push_uint8 (context_p, CBC_ASSIGN);
|
||||
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
|
||||
}
|
||||
|
||||
else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL)
|
||||
{
|
||||
if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL)
|
||||
|
||||
@@ -56,8 +56,6 @@ typedef enum
|
||||
PARSER_ARGUMENTS_NEEDED = (1u << 8), /**< arguments object must be created */
|
||||
PARSER_ARGUMENTS_NOT_NEEDED = (1u << 9), /**< arguments object must NOT be created */
|
||||
PARSER_LEXICAL_ENV_NEEDED = (1u << 10), /**< lexical environment object must be created */
|
||||
PARSER_NO_REG_STORE = (1u << 11), /**< all local variables must be stored
|
||||
* in the lexical environment object */
|
||||
PARSER_INSIDE_WITH = (1u << 12), /**< code block is inside a with statement */
|
||||
PARSER_RESOLVE_BASE_FOR_CALLS = (1u << 13), /**< the this object must be resolved when
|
||||
* a function without a base object is called */
|
||||
@@ -313,6 +311,29 @@ typedef struct parser_branch_node_t
|
||||
parser_branch_t branch; /**< branch */
|
||||
} parser_branch_node_t;
|
||||
|
||||
/**
|
||||
* Items of scope stack.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t map_from; /**< original literal index */
|
||||
uint16_t map_to; /**< register or literal index */
|
||||
} parser_scope_stack;
|
||||
|
||||
/**
|
||||
* This item represents a function literal in the scope stack.
|
||||
*/
|
||||
#define PARSER_SCOPE_STACK_FUNC 0xffff
|
||||
|
||||
/**
|
||||
* Starting literal index for registers.
|
||||
*/
|
||||
#define PARSER_REGISTER_START 0x8000
|
||||
|
||||
/* Forward definitions for js-scanner-internal.h. */
|
||||
struct scanner_context_t;
|
||||
typedef struct scanner_context_t scanner_context_t;
|
||||
|
||||
#if ENABLED (JERRY_DEBUGGER)
|
||||
/**
|
||||
* Extra information for each breakpoint.
|
||||
@@ -352,6 +373,10 @@ typedef struct parser_saved_context_t
|
||||
parser_mem_data_t byte_code; /**< byte code buffer */
|
||||
uint32_t byte_code_size; /**< byte code size for branches */
|
||||
parser_mem_data_t literal_pool_data; /**< literal list */
|
||||
parser_scope_stack *scope_stack_p; /**< scope stack */
|
||||
uint16_t scope_stack_size; /**< size of scope stack */
|
||||
uint16_t scope_stack_top; /**< current top of scope stack */
|
||||
uint16_t scope_stack_reg_top; /**< current top register of scope stack */
|
||||
|
||||
#ifndef JERRY_NDEBUG
|
||||
uint16_t context_stack_depth; /**< current context stack depth */
|
||||
@@ -365,8 +390,13 @@ typedef struct
|
||||
{
|
||||
PARSER_TRY_CONTEXT (try_buffer); /**< try_buffer */
|
||||
parser_error_t error; /**< error code */
|
||||
void *allocated_buffer_p; /**< dinamically allocated buffer
|
||||
/** Union for rarely used members. */
|
||||
union
|
||||
{
|
||||
void *allocated_buffer_p; /**< dinamically allocated buffer
|
||||
* which needs to be freed on error */
|
||||
scanner_context_t *scanner_context_p; /**< scanner context for the pre-scanner */
|
||||
} u;
|
||||
uint32_t allocated_buffer_size; /**< size of the dinamically allocated buffer */
|
||||
|
||||
/* Parser members. */
|
||||
@@ -409,7 +439,11 @@ typedef struct
|
||||
uint32_t byte_code_size; /**< current byte code size for branches */
|
||||
parser_list_t literal_pool; /**< literal list */
|
||||
parser_mem_data_t stack; /**< storage space */
|
||||
parser_scope_stack *scope_stack_p; /**< scope stack */
|
||||
parser_mem_page_t *free_page_p; /**< space for fast allocation */
|
||||
uint16_t scope_stack_size; /**< size of scope stack */
|
||||
uint16_t scope_stack_top; /**< current top of scope stack */
|
||||
uint16_t scope_stack_reg_top; /**< current top register of scope stack */
|
||||
uint8_t stack_top_uint8; /**< top byte stored on the stack */
|
||||
|
||||
#ifndef JERRY_NDEBUG
|
||||
@@ -502,6 +536,8 @@ void parser_stack_iterator_write (parser_stack_iterator_t *iterator, const void
|
||||
void parser_flush_cbc (parser_context_t *context_p);
|
||||
void parser_emit_cbc (parser_context_t *context_p, uint16_t opcode);
|
||||
void parser_emit_cbc_literal (parser_context_t *context_p, uint16_t opcode, uint16_t literal_index);
|
||||
void parser_emit_cbc_literal_value (parser_context_t *context_p, uint16_t opcode, uint16_t literal_index,
|
||||
uint16_t value);
|
||||
void parser_emit_cbc_literal_from_token (parser_context_t *context_p, uint16_t opcode);
|
||||
void parser_emit_cbc_call (parser_context_t *context_p, uint16_t opcode, size_t call_arguments);
|
||||
void parser_emit_cbc_push_number (parser_context_t *context_p, bool is_negative_number);
|
||||
@@ -547,12 +583,13 @@ void lexer_expect_identifier (parser_context_t *context_p, uint8_t literal_type)
|
||||
void lexer_scan_identifier (parser_context_t *context_p, uint32_t ident_opts);
|
||||
ecma_char_t lexer_hex_to_character (parser_context_t *context_p, const uint8_t *source_p, int length);
|
||||
void lexer_expect_object_literal_id (parser_context_t *context_p, uint32_t ident_opts);
|
||||
void lexer_construct_literal_object (parser_context_t *context_p, lexer_lit_location_t *literal_p,
|
||||
void lexer_construct_literal_object (parser_context_t *context_p, const lexer_lit_location_t *literal_p,
|
||||
uint8_t literal_type);
|
||||
bool lexer_construct_number_object (parser_context_t *context_p, bool is_expr, bool is_negative_number);
|
||||
void lexer_convert_push_number_to_push_literal (parser_context_t *context_p);
|
||||
uint16_t lexer_construct_function_object (parser_context_t *context_p, uint32_t extra_status_flags);
|
||||
void lexer_construct_regexp_object (parser_context_t *context_p, bool parse_only);
|
||||
bool lexer_compare_identifiers (const uint8_t *left_p, const uint8_t *right_p, size_t size);
|
||||
bool lexer_compare_identifier_to_current (parser_context_t *context_p, const lexer_lit_location_t *right_ident_p);
|
||||
bool lexer_compare_literal_to_identifier (parser_context_t *context_p, const char *identifier_p,
|
||||
size_t identifier_length);
|
||||
@@ -588,7 +625,6 @@ void scanner_raise_error (parser_context_t *context_p);
|
||||
void *scanner_malloc (parser_context_t *context_p, size_t size);
|
||||
void scanner_free (void *ptr, size_t size);
|
||||
|
||||
scanner_info_t *scanner_insert_info (parser_context_t *context_p, const uint8_t *source_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_release_active (parser_context_t *context_p, size_t size);
|
||||
@@ -597,6 +633,8 @@ void scanner_seek (parser_context_t *context_p);
|
||||
void scanner_reverse_info_list (parser_context_t *context_p);
|
||||
void scanner_cleanup (parser_context_t *context_p);
|
||||
|
||||
void scanner_create_variables (parser_context_t *context_p, size_t size);
|
||||
|
||||
void scanner_get_location (scanner_location_t *location_p, parser_context_t *context_p);
|
||||
void scanner_set_location (parser_context_t *context_p, scanner_location_t *location_p);
|
||||
|
||||
|
||||
@@ -52,22 +52,30 @@
|
||||
#define PARSER_MAXIMUM_STRING_LENGTH PARSER_MAXIMUM_STRING_LIMIT
|
||||
#endif /* !PARSER_MAXIMUM_STRING_LENGTH */
|
||||
|
||||
/**
|
||||
* Maximum number of literals.
|
||||
* Limit: 32767. Recommended: 510, 32767
|
||||
*/
|
||||
#ifndef PARSER_MAXIMUM_NUMBER_OF_LITERALS
|
||||
#define PARSER_MAXIMUM_NUMBER_OF_LITERALS 32767
|
||||
#endif /* !PARSER_MAXIMUM_NUMBER_OF_LITERALS */
|
||||
|
||||
/**
|
||||
* Maximum number of registers.
|
||||
* Limit: PARSER_MAXIMUM_NUMBER_OF_LITERALS
|
||||
* Limit: min: 256, max: PARSER_MAXIMUM_NUMBER_OF_LITERALS / 2
|
||||
*/
|
||||
#ifndef PARSER_MAXIMUM_NUMBER_OF_REGISTERS
|
||||
#define PARSER_MAXIMUM_NUMBER_OF_REGISTERS 256
|
||||
#endif /* !PARSER_MAXIMUM_NUMBER_OF_REGISTERS */
|
||||
|
||||
/**
|
||||
* Maximum number of literals.
|
||||
* Limit: 32767 - PARSER_MAXIMUM_NUMBER_OF_REGISTERS. Recommended: 32767 - PARSER_MAXIMUM_NUMBER_OF_REGISTERS.
|
||||
*/
|
||||
#ifndef PARSER_MAXIMUM_NUMBER_OF_LITERALS
|
||||
#define PARSER_MAXIMUM_NUMBER_OF_LITERALS (32767 - PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
|
||||
#endif /* !PARSER_MAXIMUM_NUMBER_OF_LITERALS */
|
||||
|
||||
/**
|
||||
* Maximum depth of scope stack.
|
||||
* Limit: 32767. Recommended: 32767
|
||||
*/
|
||||
#ifndef PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK
|
||||
#define PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK 32767
|
||||
#endif /* !PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK */
|
||||
|
||||
/**
|
||||
* Maximum code size.
|
||||
* Limit: 16777215. Recommended: 65535, 16777215.
|
||||
@@ -95,13 +103,19 @@
|
||||
#error "Maximum identifier length is not within range."
|
||||
#endif /* (PARSER_MAXIMUM_IDENT_LENGTH < 1) || (PARSER_MAXIMUM_IDENT_LENGTH > PARSER_MAXIMUM_STRING_LENGTH) */
|
||||
|
||||
#if (PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) || (PARSER_MAXIMUM_NUMBER_OF_LITERALS > 32767)
|
||||
#if ((PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) \
|
||||
|| (PARSER_MAXIMUM_NUMBER_OF_LITERALS + PARSER_MAXIMUM_NUMBER_OF_REGISTERS > 32767))
|
||||
#error "Maximum number of literals is not within range."
|
||||
#endif /* (PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) || (PARSER_MAXIMUM_NUMBER_OF_LITERALS > 32767) */
|
||||
#endif /* ((PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) \
|
||||
|| (PARSER_MAXIMUM_NUMBER_OF_LITERALS > 32767)) */
|
||||
|
||||
#if (PARSER_MAXIMUM_NUMBER_OF_REGISTERS > PARSER_MAXIMUM_NUMBER_OF_LITERALS)
|
||||
#if (PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK < 1) || (PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK > 32767)
|
||||
#error "Maximum depth of scope stack is not within range."
|
||||
#endif /* (PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK < 1) || (PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK > 32767) */
|
||||
|
||||
#if ((PARSER_MAXIMUM_NUMBER_OF_REGISTERS * 2) > PARSER_MAXIMUM_NUMBER_OF_LITERALS)
|
||||
#error "Maximum number of registers is not within range."
|
||||
#endif /* (PARSER_MAXIMUM_NUMBER_OF_REGISTERS > PARSER_MAXIMUM_NUMBER_OF_LITERALS) */
|
||||
#endif /* ((PARSER_MAXIMUM_NUMBER_OF_REGISTERS * 2) > PARSER_MAXIMUM_NUMBER_OF_LITERALS) */
|
||||
|
||||
#if (PARSER_MAXIMUM_CODE_SIZE < 4096) || (PARSER_MAXIMUM_CODE_SIZE > 16777215)
|
||||
#error "Maximum code size is not within range."
|
||||
|
||||
@@ -181,6 +181,8 @@ typedef enum
|
||||
typedef struct
|
||||
{
|
||||
parser_try_block_type_t type; /**< current block type */
|
||||
uint16_t scope_stack_top; /**< current top of scope stack */
|
||||
uint16_t scope_stack_reg_top; /**< current top register of scope stack */
|
||||
parser_branch_t branch; /**< branch to the end of the current block */
|
||||
} parser_try_statement_t;
|
||||
|
||||
@@ -310,8 +312,6 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
|
||||
parser_line_counter_t ident_line_counter = context_p->token.line;
|
||||
#endif /* ENABLED (JERRY_DEBUGGER) || ENABLED (JERRY_LINE_INFO) */
|
||||
|
||||
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR;
|
||||
|
||||
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
|
||||
if (context_p->status_flags & PARSER_MODULE_STORE_IDENT)
|
||||
{
|
||||
@@ -362,9 +362,7 @@ static void
|
||||
parser_parse_function_statement (parser_context_t *context_p) /**< context */
|
||||
{
|
||||
uint32_t status_flags;
|
||||
lexer_literal_t *name_p;
|
||||
lexer_literal_t *literal_p;
|
||||
uint8_t no_reg_store;
|
||||
|
||||
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FUNCTION);
|
||||
|
||||
@@ -373,7 +371,7 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
|
||||
parser_line_counter_t debugger_column = context_p->token.column;
|
||||
#endif /* ENABLED (JERRY_DEBUGGER) */
|
||||
|
||||
lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);
|
||||
lexer_expect_identifier (context_p, LEXER_NEW_IDENT_LITERAL);
|
||||
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
|
||||
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
|
||||
|
||||
@@ -382,8 +380,6 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
|
||||
context_p->status_flags |= PARSER_ARGUMENTS_NOT_NEEDED;
|
||||
}
|
||||
|
||||
name_p = context_p->lit_object.literal_p;
|
||||
|
||||
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
|
||||
if (context_p->status_flags & PARSER_MODULE_STORE_IDENT)
|
||||
{
|
||||
@@ -403,6 +399,7 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
|
||||
#if ENABLED (JERRY_DEBUGGER)
|
||||
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
|
||||
{
|
||||
lexer_literal_t *name_p = context_p->lit_object.literal_p;
|
||||
jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME,
|
||||
JERRY_DEBUGGER_NO_SUBTYPE,
|
||||
name_p->u.char_p,
|
||||
@@ -414,55 +411,35 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
|
||||
}
|
||||
#endif /* ENABLED (JERRY_DEBUGGER) */
|
||||
|
||||
if (name_p->status_flags & LEXER_FLAG_INITIALIZED)
|
||||
JERRY_ASSERT (context_p->scope_stack_top >= 2);
|
||||
parser_scope_stack *scope_stack_p = context_p->scope_stack_p + context_p->scope_stack_top - 2;
|
||||
|
||||
uint16_t literal_index = context_p->lit_object.index;
|
||||
|
||||
while (literal_index != scope_stack_p->map_from)
|
||||
{
|
||||
if (!(name_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT))
|
||||
{
|
||||
/* Overwrite the previous initialization. */
|
||||
ecma_compiled_code_t *compiled_code_p;
|
||||
scope_stack_p--;
|
||||
|
||||
literal_p = PARSER_GET_LITERAL ((size_t) (context_p->lit_object.index + 1));
|
||||
|
||||
JERRY_ASSERT (literal_p->type == LEXER_FUNCTION_LITERAL
|
||||
&& literal_p->status_flags == 0);
|
||||
|
||||
compiled_code_p = parser_parse_function (context_p, status_flags);
|
||||
util_free_literal (literal_p);
|
||||
|
||||
literal_p->u.bytecode_p = compiled_code_p;
|
||||
lexer_next_token (context_p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (context_p->lit_object.index + 1 == context_p->literal_count)
|
||||
{
|
||||
/* The most common case: the literal is the last literal. */
|
||||
name_p->status_flags |= LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED;
|
||||
lexer_construct_function_object (context_p, status_flags);
|
||||
lexer_next_token (context_p);
|
||||
return;
|
||||
JERRY_ASSERT (scope_stack_p >= context_p->scope_stack_p);
|
||||
}
|
||||
|
||||
/* Clone the literal at the end. */
|
||||
if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
|
||||
JERRY_ASSERT (scope_stack_p[1].map_from == PARSER_SCOPE_STACK_FUNC);
|
||||
|
||||
literal_p = PARSER_GET_LITERAL ((size_t) scope_stack_p[1].map_to);
|
||||
|
||||
JERRY_ASSERT ((literal_p->type == LEXER_UNUSED_LITERAL || literal_p->type == LEXER_FUNCTION_LITERAL)
|
||||
&& literal_p->status_flags == 0);
|
||||
|
||||
ecma_compiled_code_t *compiled_code_p = parser_parse_function (context_p, status_flags);
|
||||
|
||||
if (literal_p->type == LEXER_FUNCTION_LITERAL)
|
||||
{
|
||||
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
|
||||
ecma_bytecode_deref (literal_p->u.bytecode_p);
|
||||
}
|
||||
|
||||
literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
|
||||
*literal_p = *name_p;
|
||||
no_reg_store = name_p->status_flags & (LEXER_FLAG_NO_REG_STORE | LEXER_FLAG_SOURCE_PTR);
|
||||
literal_p->status_flags = LEXER_FLAG_VAR | LEXER_FLAG_INITIALIZED | no_reg_store;
|
||||
literal_p->u.bytecode_p = compiled_code_p;
|
||||
literal_p->type = LEXER_FUNCTION_LITERAL;
|
||||
|
||||
name_p->type = LEXER_UNUSED_LITERAL;
|
||||
name_p->status_flags &= LEXER_FLAG_FUNCTION_ARGUMENT | LEXER_FLAG_SOURCE_PTR;
|
||||
/* Byte code references to this literal are
|
||||
* redirected to the newly allocated literal. */
|
||||
name_p->prop.index = context_p->literal_count;
|
||||
|
||||
context_p->literal_count++;
|
||||
|
||||
lexer_construct_function_object (context_p, status_flags);
|
||||
lexer_next_token (context_p);
|
||||
} /* parser_parse_function_statement */
|
||||
|
||||
@@ -967,8 +944,6 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
|
||||
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
|
||||
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
|
||||
|
||||
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR;
|
||||
|
||||
literal_index = context_p->lit_object.index;
|
||||
|
||||
lexer_next_token (context_p);
|
||||
@@ -1400,6 +1375,9 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
|
||||
|
||||
if (try_statement.type == parser_catch_block)
|
||||
{
|
||||
context_p->scope_stack_top = try_statement.scope_stack_top;
|
||||
context_p->scope_stack_reg_top = try_statement.scope_stack_reg_top;
|
||||
|
||||
if (context_p->token.type != LEXER_KEYW_FINALLY)
|
||||
{
|
||||
parser_flush_cbc (context_p);
|
||||
@@ -1410,6 +1388,7 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
|
||||
|
||||
parser_emit_cbc (context_p, CBC_CONTEXT_END);
|
||||
parser_flush_cbc (context_p);
|
||||
|
||||
try_statement.type = parser_finally_block;
|
||||
}
|
||||
}
|
||||
@@ -1439,12 +1418,34 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
|
||||
parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
|
||||
}
|
||||
|
||||
try_statement.type = parser_catch_block;
|
||||
parser_emit_cbc_ext_forward_branch (context_p,
|
||||
CBC_EXT_CATCH,
|
||||
&try_statement.branch);
|
||||
|
||||
try_statement.scope_stack_top = context_p->scope_stack_top;
|
||||
try_statement.scope_stack_reg_top = context_p->scope_stack_reg_top;
|
||||
|
||||
#ifndef JERRY_NDEBUG
|
||||
bool block_found = false;
|
||||
#endif /* !JERRY_NDEBUG */
|
||||
|
||||
if (context_p->next_scanner_info_p->source_p == context_p->source_p
|
||||
&& context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK)
|
||||
{
|
||||
#ifndef JERRY_NDEBUG
|
||||
block_found = true;
|
||||
#endif /* !JERRY_NDEBUG */
|
||||
scanner_create_variables (context_p, sizeof (scanner_info_t));
|
||||
}
|
||||
|
||||
lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);
|
||||
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
|
||||
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
|
||||
|
||||
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE;
|
||||
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED;
|
||||
#ifndef JERRY_NDEBUG
|
||||
JERRY_ASSERT (block_found);
|
||||
#endif /* !JERRY_NDEBUG */
|
||||
|
||||
literal_index = context_p->lit_object.index;
|
||||
|
||||
@@ -1462,11 +1463,6 @@ parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
|
||||
parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
|
||||
}
|
||||
|
||||
try_statement.type = parser_catch_block;
|
||||
parser_emit_cbc_ext_forward_branch (context_p,
|
||||
CBC_EXT_CATCH,
|
||||
&try_statement.branch);
|
||||
|
||||
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index);
|
||||
parser_flush_cbc (context_p);
|
||||
}
|
||||
@@ -1960,10 +1956,7 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */
|
||||
scanner_set_location (context_p, &location);
|
||||
|
||||
/* 15.2.3.5 Use the synthetic name '*default*' as the identifier. */
|
||||
lexer_construct_literal_object (context_p,
|
||||
(lexer_lit_location_t *) &lexer_default_literal,
|
||||
lexer_default_literal.type);
|
||||
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR;
|
||||
lexer_construct_literal_object (context_p, &lexer_default_literal, lexer_default_literal.type);
|
||||
|
||||
context_p->token.lit_location.type = LEXER_IDENT_LITERAL;
|
||||
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
|
||||
|
||||
@@ -85,6 +85,51 @@ parser_emit_two_bytes (parser_context_t *context_p, /**< context */
|
||||
} \
|
||||
(context_p)->byte_code.last_p->bytes[(context_p)->byte_code.last_position++] = (uint8_t) (byte)
|
||||
|
||||
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
|
||||
|
||||
/**
|
||||
* Print literal corresponding to the current index
|
||||
*/
|
||||
static void
|
||||
parser_print_literal (parser_context_t *context_p, /**< context */
|
||||
uint16_t literal_index) /**< index of literal */
|
||||
{
|
||||
parser_scope_stack *scope_stack_p = context_p->scope_stack_p;
|
||||
parser_scope_stack *scope_stack_end_p = scope_stack_p + context_p->scope_stack_top;
|
||||
int32_t scope_literal_index = -1;
|
||||
|
||||
while (scope_stack_p < scope_stack_end_p)
|
||||
{
|
||||
scope_stack_end_p--;
|
||||
|
||||
if (literal_index == scope_stack_end_p->map_to)
|
||||
{
|
||||
scope_literal_index = scope_stack_end_p->map_from;
|
||||
}
|
||||
}
|
||||
|
||||
if (literal_index < PARSER_REGISTER_START)
|
||||
{
|
||||
JERRY_DEBUG_MSG (scope_literal_index != -1 ? " IDX:%d->" : " idx:%d->", literal_index);
|
||||
lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index);
|
||||
util_print_literal (literal_p);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scope_literal_index == -1)
|
||||
{
|
||||
JERRY_DEBUG_MSG (" reg:%d", (int) (literal_index - PARSER_REGISTER_START));
|
||||
return;
|
||||
}
|
||||
|
||||
JERRY_DEBUG_MSG (" REG:%d->", (int) (literal_index - PARSER_REGISTER_START));
|
||||
|
||||
lexer_literal_t *literal_p = PARSER_GET_LITERAL (scope_stack_end_p->map_from);
|
||||
util_print_literal (literal_p);
|
||||
} /* parser_print_literal */
|
||||
|
||||
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
|
||||
|
||||
/**
|
||||
* Append the current byte code to the stream
|
||||
*/
|
||||
@@ -181,26 +226,16 @@ parser_flush_cbc (parser_context_t *context_p) /**< context */
|
||||
|
||||
if (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2))
|
||||
{
|
||||
uint16_t literal_index = context_p->last_cbc.literal_index;
|
||||
lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index);
|
||||
JERRY_DEBUG_MSG (" idx:%d->", literal_index);
|
||||
util_print_literal (literal_p);
|
||||
parser_print_literal (context_p, context_p->last_cbc.literal_index);
|
||||
}
|
||||
|
||||
if (flags & CBC_HAS_LITERAL_ARG2)
|
||||
{
|
||||
uint16_t literal_index = context_p->last_cbc.value;
|
||||
lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index);
|
||||
JERRY_DEBUG_MSG (" idx:%d->", literal_index);
|
||||
util_print_literal (literal_p);
|
||||
parser_print_literal (context_p, context_p->last_cbc.value);
|
||||
|
||||
if (!(flags & CBC_HAS_LITERAL_ARG))
|
||||
{
|
||||
literal_index = context_p->last_cbc.third_literal_index;
|
||||
|
||||
literal_p = PARSER_GET_LITERAL (literal_index);
|
||||
JERRY_DEBUG_MSG (" idx:%d->", literal_index);
|
||||
util_print_literal (literal_p);
|
||||
parser_print_literal (context_p, context_p->last_cbc.third_literal_index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,6 +311,29 @@ parser_emit_cbc_literal (parser_context_t *context_p, /**< context */
|
||||
context_p->last_cbc.literal_object_type = LEXER_LITERAL_OBJECT_ANY;
|
||||
} /* parser_emit_cbc_literal */
|
||||
|
||||
/**
|
||||
* Append a byte code with a literal and value argument
|
||||
*/
|
||||
void
|
||||
parser_emit_cbc_literal_value (parser_context_t *context_p, /**< context */
|
||||
uint16_t opcode, /**< opcode */
|
||||
uint16_t literal_index, /**< literal index */
|
||||
uint16_t value) /**< value */
|
||||
{
|
||||
JERRY_ASSERT (PARSER_ARGS_EQ (opcode, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2));
|
||||
|
||||
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
|
||||
{
|
||||
parser_flush_cbc (context_p);
|
||||
}
|
||||
|
||||
context_p->last_cbc_opcode = opcode;
|
||||
context_p->last_cbc.literal_index = literal_index;
|
||||
context_p->last_cbc.literal_type = LEXER_UNUSED_LITERAL;
|
||||
context_p->last_cbc.literal_object_type = LEXER_LITERAL_OBJECT_ANY;
|
||||
context_p->last_cbc.value = value;
|
||||
} /* parser_emit_cbc_literal_value */
|
||||
|
||||
/**
|
||||
* Append a byte code with the current literal argument
|
||||
*/
|
||||
@@ -754,6 +812,10 @@ parser_error_to_string (parser_error_t error) /**< error code */
|
||||
{
|
||||
return "Maximum number of literals reached.";
|
||||
}
|
||||
case PARSER_ERR_SCOPE_STACK_LIMIT_REACHED:
|
||||
{
|
||||
return "Maximum depth of scope stack reached.";
|
||||
}
|
||||
case PARSER_ERR_ARGUMENT_LIMIT_REACHED:
|
||||
{
|
||||
return "Maximum number of function arguments reached.";
|
||||
@@ -762,10 +824,6 @@ parser_error_to_string (parser_error_t error) /**< error code */
|
||||
{
|
||||
return "Maximum function stack size reached.";
|
||||
}
|
||||
case PARSER_ERR_REGISTER_LIMIT_REACHED:
|
||||
{
|
||||
return "Maximum number of registers is reached.";
|
||||
}
|
||||
case PARSER_ERR_INVALID_CHARACTER:
|
||||
{
|
||||
return "Invalid (unexpected) character.";
|
||||
|
||||
+245
-865
File diff suppressed because it is too large
Load Diff
@@ -37,9 +37,9 @@ typedef enum
|
||||
|
||||
PARSER_ERR_OUT_OF_MEMORY, /**< out of memory */
|
||||
PARSER_ERR_LITERAL_LIMIT_REACHED, /**< maximum number of literals reached */
|
||||
PARSER_ERR_SCOPE_STACK_LIMIT_REACHED, /**< maximum depth of scope stack reached */
|
||||
PARSER_ERR_ARGUMENT_LIMIT_REACHED, /**< maximum number of function arguments reached */
|
||||
PARSER_ERR_STACK_LIMIT_REACHED, /**< maximum function stack size reached */
|
||||
PARSER_ERR_REGISTER_LIMIT_REACHED, /**< maximum register size reached */
|
||||
|
||||
PARSER_ERR_INVALID_CHARACTER, /**< unexpected character */
|
||||
PARSER_ERR_INVALID_HEX_DIGIT, /**< invalid hexadecimal digit */
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#ifndef JS_SCANNER_INTERNAL_H
|
||||
#define JS_SCANNER_INTERNAL_H
|
||||
|
||||
/** \addtogroup parser Parser
|
||||
/* \addtogroup parser Parser
|
||||
* @{
|
||||
*
|
||||
* \addtogroup jsparser JavaScript
|
||||
@@ -34,6 +34,19 @@ typedef struct
|
||||
const uint8_t *source_p; /**< start source byte */
|
||||
} scanner_source_start_t;
|
||||
|
||||
/**
|
||||
* Flags for type member of lexer_lit_location_t structure in the literal pool.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
SCANNER_LITERAL_IS_ARG = (1 << 0), /**< literal is argument */
|
||||
SCANNER_LITERAL_IS_LOCAL = (1 << 1), /**< literal is local (similar to let,
|
||||
* but var is allowed with the same identifier) */
|
||||
SCANNER_LITERAL_IS_VAR = (1 << 2), /**< literal is var */
|
||||
SCANNER_LITERAL_IS_FUNC = (1 << 3), /**< literal is function */
|
||||
SCANNER_LITERAL_NO_REG = (1 << 4), /**< literal cannot be stored in register */
|
||||
} scanner_literal_type_flags_t;
|
||||
|
||||
/**
|
||||
* For statement descriptor.
|
||||
*/
|
||||
@@ -55,14 +68,64 @@ typedef struct
|
||||
scanner_case_info_t **last_case_p; /**< last case info */
|
||||
} scanner_switch_statement_t;
|
||||
|
||||
/**
|
||||
* Flags for scanner_literal_pool_t structure.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
SCANNER_LITERAL_POOL_FUNCTION = (1 << 0), /**< literal pool represents a function */
|
||||
SCANNER_LITERAL_POOL_BLOCK = (1 << 1), /**< literal pool represents a code block */
|
||||
SCANNER_LITERAL_POOL_NO_REG = (1 << 2), /**< variable declarations cannot be kept in registers */
|
||||
SCANNER_LITERAL_POOL_NO_ARGUMENTS = (1 << 3), /**< arguments object should not be constructed */
|
||||
SCANNER_LITERAL_POOL_IN_WITH = (1 << 4), /**< literal pool is in a with statement */
|
||||
} scanner_literal_pool_flags_t;
|
||||
|
||||
/**
|
||||
* Define a function where no arguments are allowed.
|
||||
*/
|
||||
#define SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS \
|
||||
(SCANNER_LITERAL_POOL_FUNCTION | SCANNER_LITERAL_POOL_NO_ARGUMENTS)
|
||||
|
||||
/**
|
||||
* Local literal pool.
|
||||
*/
|
||||
typedef struct scanner_literal_pool_t
|
||||
{
|
||||
struct scanner_literal_pool_t *prev_p; /**< previous literal pool */
|
||||
const uint8_t *source_p; /**< source position where the final data needs to be inserted */
|
||||
parser_list_t literal_pool; /**< list of literal */
|
||||
uint16_t status_flags; /**< combination of scanner_literal_pool_flags_t flags */
|
||||
uint16_t no_declarations; /**< size of scope stack required during parsing */
|
||||
} scanner_literal_pool_t;
|
||||
|
||||
/**
|
||||
* Scanner context.
|
||||
*/
|
||||
typedef struct
|
||||
struct scanner_context_t
|
||||
{
|
||||
uint8_t mode; /**< scanner mode */
|
||||
#if ENABLED (JERRY_DEBUGGER)
|
||||
uint8_t debugger_enabled; /**< debugger is enabled */
|
||||
#endif /* ENABLED (JERRY_DEBUGGER) */
|
||||
scanner_literal_pool_t *active_literal_pool_p; /**< currently active literal pool */
|
||||
scanner_switch_statement_t active_switch_statement; /**< currently active switch statement */
|
||||
} scanner_context_t;
|
||||
scanner_info_t *end_arguments_p; /**< position of end arguments */
|
||||
};
|
||||
|
||||
size_t scanner_get_stream_size (scanner_info_t *info_p, size_t size);
|
||||
scanner_info_t *scanner_insert_info (parser_context_t *context_p, const uint8_t *source_p, size_t size);
|
||||
scanner_info_t *scanner_insert_info_before (parser_context_t *context_p, const uint8_t *source_p,
|
||||
scanner_info_t *start_info_p, size_t size);
|
||||
scanner_literal_pool_t *scanner_push_literal_pool (parser_context_t *context_p, scanner_context_t *scanner_context_p,
|
||||
uint16_t status_flags);
|
||||
void scanner_pop_literal_pool (parser_context_t *context_p, scanner_context_t *scanner_context_p);
|
||||
void scanner_filter_arguments (parser_context_t *context_p, scanner_context_t *scanner_context_p);
|
||||
lexer_lit_location_t *scanner_add_custom_literal (parser_context_t *context_p, scanner_literal_pool_t *literal_pool_p,
|
||||
const lexer_lit_location_t *literal_location_p);
|
||||
lexer_lit_location_t *scanner_add_literal (parser_context_t *context_p, scanner_context_t *scanner_context_p);
|
||||
void scanner_add_reference (parser_context_t *context_p, scanner_context_t *scanner_context_p);
|
||||
void scanner_append_argument (parser_context_t *context_p, scanner_context_t *scanner_context_p);
|
||||
void scanner_detect_eval_call (parser_context_t *context_p, scanner_context_t *scanner_context_p);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "js-parser-internal.h"
|
||||
#include "js-scanner-internal.h"
|
||||
#include "lit-char-helpers.h"
|
||||
|
||||
#if ENABLED (JERRY_PARSER)
|
||||
|
||||
@@ -28,6 +29,9 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
JERRY_STATIC_ASSERT (PARSER_MAXIMUM_NUMBER_OF_LITERALS + PARSER_MAXIMUM_NUMBER_OF_REGISTERS < PARSER_REGISTER_START,
|
||||
maximum_number_of_literals_plus_registers_must_be_less_than_register_start);
|
||||
|
||||
/**
|
||||
* Raise a scanner error.
|
||||
*/
|
||||
@@ -74,6 +78,52 @@ scanner_free (void *ptr, /**< pointer to free */
|
||||
jmem_heap_free_block (ptr, size);
|
||||
} /* scanner_free */
|
||||
|
||||
/**
|
||||
* Count the size of a stream after an info block.
|
||||
*
|
||||
* @return the size in bytes
|
||||
*/
|
||||
size_t
|
||||
scanner_get_stream_size (scanner_info_t *info_p, /**< scanner info block */
|
||||
size_t size) /**< size excluding the stream */
|
||||
{
|
||||
const uint8_t *data_p = ((const uint8_t *) info_p) + size;
|
||||
const uint8_t *data_p_start = data_p;
|
||||
|
||||
while (data_p[0] != SCANNER_STREAM_TYPE_END)
|
||||
{
|
||||
switch (data_p[0] & SCANNER_STREAM_TYPE_MASK)
|
||||
{
|
||||
case SCANNER_STREAM_TYPE_ARG:
|
||||
case SCANNER_STREAM_TYPE_ARG_FUNC:
|
||||
case SCANNER_STREAM_TYPE_VAR:
|
||||
case SCANNER_STREAM_TYPE_FUNC:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_ASSERT ((data_p[0] & SCANNER_STREAM_TYPE_MASK) == SCANNER_STREAM_TYPE_HOLE);
|
||||
data_p++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
data_p += 3;
|
||||
|
||||
if (data_p[-3] & SCANNER_STREAM_UINT16_DIFF)
|
||||
{
|
||||
data_p++;
|
||||
}
|
||||
else if (data_p[-1] == 0)
|
||||
{
|
||||
data_p += sizeof (const uint8_t *);
|
||||
}
|
||||
}
|
||||
|
||||
return size + 1 + (size_t) (data_p - data_p_start);
|
||||
} /* scanner_get_stream_size */
|
||||
|
||||
/**
|
||||
* Insert a scanner info block into the scanner info chain.
|
||||
*
|
||||
@@ -89,6 +139,7 @@ scanner_insert_info (parser_context_t *context_p, /**< context */
|
||||
scanner_info_t *prev_scanner_info_p = NULL;
|
||||
|
||||
JERRY_ASSERT (scanner_info_p != NULL);
|
||||
JERRY_ASSERT (source_p != NULL);
|
||||
|
||||
new_scanner_info_p->source_p = source_p;
|
||||
|
||||
@@ -117,6 +168,42 @@ scanner_insert_info (parser_context_t *context_p, /**< context */
|
||||
return new_scanner_info_p;
|
||||
} /* scanner_insert_info */
|
||||
|
||||
/**
|
||||
* Insert a scanner info block into the scanner info chain before a given info block.
|
||||
*
|
||||
* @return newly allocated scanner info
|
||||
*/
|
||||
scanner_info_t *
|
||||
scanner_insert_info_before (parser_context_t *context_p, /**< context */
|
||||
const uint8_t *source_p, /**< triggering position */
|
||||
scanner_info_t *start_info_p, /**< first info position */
|
||||
size_t size) /**< size of the memory block */
|
||||
{
|
||||
JERRY_ASSERT (start_info_p != NULL);
|
||||
|
||||
scanner_info_t *new_scanner_info_p = (scanner_info_t *) scanner_malloc (context_p, size);
|
||||
scanner_info_t *scanner_info_p = start_info_p->next_p;
|
||||
scanner_info_t *prev_scanner_info_p = start_info_p;
|
||||
|
||||
new_scanner_info_p->source_p = source_p;
|
||||
|
||||
while (source_p < scanner_info_p->source_p)
|
||||
{
|
||||
prev_scanner_info_p = scanner_info_p;
|
||||
scanner_info_p = scanner_info_p->next_p;
|
||||
|
||||
JERRY_ASSERT (scanner_info_p != NULL);
|
||||
}
|
||||
|
||||
/* Multiple scanner info blocks cannot be assigned to the same position. */
|
||||
JERRY_ASSERT (source_p != scanner_info_p->source_p);
|
||||
|
||||
new_scanner_info_p->next_p = scanner_info_p;
|
||||
|
||||
prev_scanner_info_p->next_p = new_scanner_info_p;
|
||||
return new_scanner_info_p;
|
||||
} /* scanner_insert_info_before */
|
||||
|
||||
/**
|
||||
* Release the next scanner info.
|
||||
*/
|
||||
@@ -225,6 +312,577 @@ scanner_seek (parser_context_t *context_p) /**< context */
|
||||
context_p->next_scanner_info_p = prev_p->next_p;
|
||||
} /* scanner_seek */
|
||||
|
||||
/**
|
||||
* Push a new literal pool.
|
||||
*
|
||||
* @return the newly created literal pool
|
||||
*/
|
||||
scanner_literal_pool_t *
|
||||
scanner_push_literal_pool (parser_context_t *context_p, /**< context */
|
||||
scanner_context_t *scanner_context_p, /**< scanner context */
|
||||
uint16_t status_flags) /**< combination of scanner_literal_pool_flags_t flags */
|
||||
{
|
||||
scanner_literal_pool_t *prev_literal_pool_p = scanner_context_p->active_literal_pool_p;
|
||||
scanner_literal_pool_t *literal_pool_p;
|
||||
|
||||
literal_pool_p = (scanner_literal_pool_t *) scanner_malloc (context_p, sizeof (scanner_literal_pool_t));
|
||||
|
||||
if (!(status_flags & SCANNER_LITERAL_POOL_FUNCTION))
|
||||
{
|
||||
JERRY_ASSERT (prev_literal_pool_p != NULL);
|
||||
|
||||
if (prev_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
|
||||
{
|
||||
status_flags |= SCANNER_LITERAL_POOL_IN_WITH;
|
||||
}
|
||||
}
|
||||
|
||||
parser_list_init (&literal_pool_p->literal_pool,
|
||||
sizeof (lexer_lit_location_t),
|
||||
(uint32_t) ((128 - sizeof (void *)) / sizeof (lexer_lit_location_t)));
|
||||
literal_pool_p->source_p = NULL;
|
||||
literal_pool_p->status_flags = status_flags;
|
||||
literal_pool_p->no_declarations = 0;
|
||||
|
||||
literal_pool_p->prev_p = prev_literal_pool_p;
|
||||
scanner_context_p->active_literal_pool_p = literal_pool_p;
|
||||
|
||||
return literal_pool_p;
|
||||
} /* scanner_push_literal_pool */
|
||||
|
||||
JERRY_STATIC_ASSERT (PARSER_MAXIMUM_IDENT_LENGTH <= UINT8_MAX,
|
||||
maximum_ident_length_must_fit_in_a_byte);
|
||||
|
||||
/**
|
||||
* Pop the last literal pool from the end.
|
||||
*/
|
||||
void
|
||||
scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
|
||||
scanner_context_t *scanner_context_p) /**< scanner context */
|
||||
{
|
||||
scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;
|
||||
scanner_literal_pool_t *prev_literal_pool_p = literal_pool_p->prev_p;
|
||||
parser_list_iterator_t literal_iterator;
|
||||
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 arguments_required = (no_reg && search_arguments);
|
||||
|
||||
if (no_reg && prev_literal_pool_p != NULL)
|
||||
{
|
||||
prev_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG;
|
||||
}
|
||||
|
||||
#if ENABLED (JERRY_DEBUGGER)
|
||||
if (scanner_context_p->debugger_enabled)
|
||||
{
|
||||
/* When debugger is enabled, identifiers are not stored in registers. However,
|
||||
* this does not affect 'eval' detection, so 'arguments' object is not created. */
|
||||
no_reg = true;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_DEBUGGER) */
|
||||
|
||||
parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
|
||||
|
||||
const uint8_t *prev_source_p = literal_pool_p->source_p - 1;
|
||||
size_t compressed_size = 1;
|
||||
uint32_t no_declarations = literal_pool_p->no_declarations;
|
||||
|
||||
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
|
||||
{
|
||||
uint8_t type = literal_p->type;
|
||||
|
||||
if (JERRY_UNLIKELY (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (search_arguments
|
||||
&& literal_p->length == 9
|
||||
&& lexer_compare_identifiers (literal_p->char_p, (const uint8_t *) "arguments", 9))
|
||||
{
|
||||
search_arguments = false;
|
||||
|
||||
if (type & (SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_FUNC))
|
||||
{
|
||||
arguments_required = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
literal_p->type = 0;
|
||||
arguments_required = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (((type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG)) && is_function)
|
||||
|| (type & SCANNER_LITERAL_IS_LOCAL))
|
||||
{
|
||||
JERRY_ASSERT (is_function || !(literal_p->type & SCANNER_LITERAL_IS_ARG));
|
||||
|
||||
if (literal_p->length == 0)
|
||||
{
|
||||
compressed_size += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
no_declarations++;
|
||||
|
||||
if (type & SCANNER_LITERAL_IS_FUNC)
|
||||
{
|
||||
no_declarations++;
|
||||
}
|
||||
|
||||
if (no_reg)
|
||||
{
|
||||
type |= SCANNER_LITERAL_NO_REG;
|
||||
literal_p->type = type;
|
||||
}
|
||||
|
||||
intptr_t diff = (intptr_t) (literal_p->char_p - prev_source_p);
|
||||
|
||||
if (diff >= 1 && diff <= UINT8_MAX)
|
||||
{
|
||||
compressed_size += 2 + 1;
|
||||
}
|
||||
else if (diff >= -UINT8_MAX && diff <= UINT16_MAX)
|
||||
{
|
||||
compressed_size += 2 + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
compressed_size += 2 + 1 + sizeof (const uint8_t *);
|
||||
}
|
||||
|
||||
prev_source_p = literal_p->char_p + literal_p->length;
|
||||
|
||||
if (is_function || !(type & SCANNER_LITERAL_IS_VAR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (prev_literal_pool_p != NULL && literal_p->length > 0)
|
||||
{
|
||||
/* Propagate literal to upper level. */
|
||||
lexer_lit_location_t *literal_location_p = scanner_add_custom_literal (context_p,
|
||||
prev_literal_pool_p,
|
||||
literal_p);
|
||||
|
||||
if (is_function || (type & SCANNER_LITERAL_NO_REG))
|
||||
{
|
||||
literal_location_p->type |= SCANNER_LITERAL_NO_REG;
|
||||
}
|
||||
|
||||
type = (type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC));
|
||||
JERRY_ASSERT (type == 0 || !is_function);
|
||||
|
||||
literal_location_p->type = (uint8_t) (literal_location_p->type | type);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_function || (compressed_size > 1))
|
||||
{
|
||||
compressed_size += is_function ? sizeof (scanner_function_info_t) : sizeof (scanner_info_t);
|
||||
|
||||
scanner_info_t *info_p;
|
||||
|
||||
if (prev_literal_pool_p != NULL || scanner_context_p->end_arguments_p == NULL)
|
||||
{
|
||||
info_p = scanner_insert_info (context_p, literal_pool_p->source_p, compressed_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
scanner_info_t *start_info_p = scanner_context_p->end_arguments_p;
|
||||
info_p = scanner_insert_info_before (context_p, literal_pool_p->source_p, start_info_p, compressed_size);
|
||||
}
|
||||
|
||||
if (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK)
|
||||
{
|
||||
no_declarations = PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK;
|
||||
}
|
||||
|
||||
uint8_t *data_p = (uint8_t *) info_p;
|
||||
|
||||
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)
|
||||
{
|
||||
status_flags |= SCANNER_FUNCTION_ARGUMENTS_NEEDED;
|
||||
|
||||
if (no_declarations < PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK)
|
||||
{
|
||||
no_declarations++;
|
||||
}
|
||||
}
|
||||
|
||||
function_info_p->info.u8_arg = status_flags;
|
||||
function_info_p->info.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);
|
||||
if (prev_literal_pool_p->no_declarations < no_declarations)
|
||||
{
|
||||
prev_literal_pool_p->no_declarations = (uint16_t) no_declarations;
|
||||
}
|
||||
}
|
||||
|
||||
parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
|
||||
prev_source_p = literal_pool_p->source_p - 1;
|
||||
no_declarations = 0;
|
||||
|
||||
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
|
||||
{
|
||||
if (JERRY_UNLIKELY (no_declarations > PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK)
|
||||
|| (!((literal_p->type & (SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_ARG)) && is_function)
|
||||
&& !(literal_p->type & SCANNER_LITERAL_IS_LOCAL)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (literal_p->length == 0)
|
||||
{
|
||||
*data_p++ = SCANNER_STREAM_TYPE_HOLE;
|
||||
continue;
|
||||
}
|
||||
|
||||
no_declarations++;
|
||||
|
||||
uint8_t type = SCANNER_STREAM_TYPE_VAR;
|
||||
|
||||
if (literal_p->type & SCANNER_LITERAL_IS_FUNC)
|
||||
{
|
||||
no_declarations++;
|
||||
type = SCANNER_STREAM_TYPE_FUNC;
|
||||
|
||||
if (literal_p->type & SCANNER_LITERAL_IS_ARG)
|
||||
{
|
||||
type = SCANNER_STREAM_TYPE_ARG_FUNC;
|
||||
}
|
||||
}
|
||||
else if (literal_p->type & SCANNER_LITERAL_IS_ARG)
|
||||
{
|
||||
type = SCANNER_STREAM_TYPE_ARG;
|
||||
}
|
||||
|
||||
if (literal_p->has_escape)
|
||||
{
|
||||
type |= SCANNER_STREAM_HAS_ESCAPE;
|
||||
}
|
||||
|
||||
if ((literal_p->type & SCANNER_LITERAL_NO_REG)
|
||||
|| (arguments_required && (literal_p->type & SCANNER_LITERAL_IS_ARG)))
|
||||
{
|
||||
type |= SCANNER_STREAM_NO_REG;
|
||||
}
|
||||
|
||||
data_p[0] = type;
|
||||
data_p[1] = (uint8_t) literal_p->length;
|
||||
data_p += 3;
|
||||
|
||||
intptr_t diff = (intptr_t) (literal_p->char_p - prev_source_p);
|
||||
|
||||
if (diff >= 1 && diff <= UINT8_MAX)
|
||||
{
|
||||
data_p[-1] = (uint8_t) diff;
|
||||
}
|
||||
else if (diff >= -UINT8_MAX && diff <= UINT16_MAX)
|
||||
{
|
||||
if (diff < 0)
|
||||
{
|
||||
diff = -diff;
|
||||
}
|
||||
|
||||
data_p[-3] |= SCANNER_STREAM_UINT16_DIFF;
|
||||
data_p[-1] = (uint8_t) diff;
|
||||
data_p[0] = (uint8_t) (diff >> 8);
|
||||
data_p += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
data_p[-1] = 0;
|
||||
memcpy (data_p, &literal_p->char_p, sizeof (const uint8_t *));
|
||||
data_p += sizeof (const uint8_t *);
|
||||
}
|
||||
|
||||
prev_source_p = literal_p->char_p + literal_p->length;
|
||||
}
|
||||
|
||||
data_p[0] = SCANNER_STREAM_TYPE_END;
|
||||
|
||||
JERRY_ASSERT (((uint8_t *) info_p) + compressed_size == data_p + 1);
|
||||
}
|
||||
|
||||
scanner_context_p->active_literal_pool_p = literal_pool_p->prev_p;
|
||||
|
||||
parser_list_free (&literal_pool_p->literal_pool);
|
||||
scanner_free (literal_pool_p, sizeof (scanner_literal_pool_t));
|
||||
} /* scanner_pop_literal_pool */
|
||||
|
||||
/**
|
||||
* Filter out the arguments from a literal pool.
|
||||
*/
|
||||
void
|
||||
scanner_filter_arguments (parser_context_t *context_p, /**< context */
|
||||
scanner_context_t *scanner_context_p) /**< scanner context */
|
||||
{
|
||||
/* Fast case: check whether all literals are arguments. */
|
||||
scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;
|
||||
scanner_literal_pool_t *prev_literal_pool_p = literal_pool_p->prev_p;
|
||||
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;
|
||||
|
||||
if (no_reg && prev_literal_pool_p != NULL)
|
||||
{
|
||||
prev_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG;
|
||||
}
|
||||
|
||||
literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_NO_REG;
|
||||
|
||||
parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
|
||||
|
||||
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
|
||||
{
|
||||
if (no_reg)
|
||||
{
|
||||
literal_p->type |= SCANNER_LITERAL_NO_REG;
|
||||
}
|
||||
|
||||
if (!(literal_p->type & SCANNER_LITERAL_IS_ARG))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (literal_p == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
scanner_literal_pool_t *new_literal_pool_p;
|
||||
|
||||
new_literal_pool_p = (scanner_literal_pool_t *) scanner_malloc (context_p, sizeof (scanner_literal_pool_t));
|
||||
|
||||
new_literal_pool_p->prev_p = literal_pool_p;
|
||||
scanner_context_p->active_literal_pool_p = new_literal_pool_p;
|
||||
|
||||
*new_literal_pool_p = *literal_pool_p;
|
||||
parser_list_init (&new_literal_pool_p->literal_pool,
|
||||
sizeof (lexer_lit_location_t),
|
||||
(uint32_t) ((128 - sizeof (void *)) / sizeof (lexer_lit_location_t)));
|
||||
|
||||
parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
|
||||
|
||||
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
|
||||
{
|
||||
if (literal_p->type & SCANNER_LITERAL_IS_ARG)
|
||||
{
|
||||
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 = *literal_p;
|
||||
|
||||
if (no_reg)
|
||||
{
|
||||
new_literal_p->type |= SCANNER_LITERAL_NO_REG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Propagate literal to upper level. */
|
||||
lexer_lit_location_t *literal_location_p = scanner_add_custom_literal (context_p,
|
||||
prev_literal_pool_p,
|
||||
literal_p);
|
||||
if (literal_p->type & SCANNER_LITERAL_NO_REG)
|
||||
{
|
||||
literal_location_p->type |= SCANNER_LITERAL_NO_REG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_literal_pool_p->prev_p = prev_literal_pool_p;
|
||||
|
||||
parser_list_free (&literal_pool_p->literal_pool);
|
||||
scanner_free (literal_pool_p, sizeof (scanner_literal_pool_t));
|
||||
} /* scanner_filter_arguments */
|
||||
|
||||
/**
|
||||
* Add any literal to the specified literal pool.
|
||||
*
|
||||
* @return pointer to the literal
|
||||
*/
|
||||
lexer_lit_location_t *
|
||||
scanner_add_custom_literal (parser_context_t *context_p, /**< context */
|
||||
scanner_literal_pool_t *literal_pool_p, /**< literal pool */
|
||||
const lexer_lit_location_t *literal_location_p) /**< literal */
|
||||
{
|
||||
parser_list_iterator_t literal_iterator;
|
||||
parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
|
||||
lexer_lit_location_t *literal_p;
|
||||
|
||||
const uint8_t *char_p = literal_location_p->char_p;
|
||||
prop_length_t length = literal_location_p->length;
|
||||
|
||||
if (JERRY_LIKELY (!literal_location_p->has_escape))
|
||||
{
|
||||
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
|
||||
{
|
||||
if (literal_p->length == length)
|
||||
{
|
||||
if (JERRY_LIKELY (!literal_p->has_escape))
|
||||
{
|
||||
if (memcmp (literal_p->char_p, char_p, length) == 0)
|
||||
{
|
||||
return literal_p;
|
||||
}
|
||||
}
|
||||
else if (lexer_compare_identifiers (literal_p->char_p, char_p, length))
|
||||
{
|
||||
/* The non-escaped version is preferred. */
|
||||
literal_p->char_p = char_p;
|
||||
literal_p->has_escape = 0;
|
||||
return literal_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
|
||||
{
|
||||
if (literal_p->length == length
|
||||
&& lexer_compare_identifiers (literal_p->char_p, char_p, length))
|
||||
{
|
||||
return literal_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &literal_pool_p->literal_pool);
|
||||
*literal_p = *literal_location_p;
|
||||
|
||||
literal_p->type = 0;
|
||||
|
||||
return literal_p;
|
||||
} /* scanner_add_custom_literal */
|
||||
|
||||
/**
|
||||
* Add the current literal token to the current literal pool.
|
||||
*
|
||||
* @return pointer to the literal
|
||||
*/
|
||||
inline lexer_lit_location_t * JERRY_ATTR_ALWAYS_INLINE
|
||||
scanner_add_literal (parser_context_t *context_p, /**< context */
|
||||
scanner_context_t *scanner_context_p) /**< scanner context */
|
||||
{
|
||||
return scanner_add_custom_literal (context_p,
|
||||
scanner_context_p->active_literal_pool_p,
|
||||
&context_p->token.lit_location);
|
||||
} /* scanner_add_literal */
|
||||
|
||||
/**
|
||||
* Add the current literal token to the current literal pool and
|
||||
* set SCANNER_LITERAL_NO_REG if it is inside a with statement.
|
||||
*
|
||||
* @return pointer to the literal
|
||||
*/
|
||||
inline void JERRY_ATTR_ALWAYS_INLINE
|
||||
scanner_add_reference (parser_context_t *context_p, /**< context */
|
||||
scanner_context_t *scanner_context_p) /**< scanner context */
|
||||
{
|
||||
lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p,
|
||||
scanner_context_p->active_literal_pool_p,
|
||||
&context_p->token.lit_location);
|
||||
if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
|
||||
{
|
||||
lit_location_p->type |= SCANNER_LITERAL_NO_REG;
|
||||
}
|
||||
|
||||
scanner_detect_eval_call (context_p, scanner_context_p);
|
||||
} /* scanner_add_reference */
|
||||
|
||||
/**
|
||||
* Append an argument to the literal pool. If the argument is already present, make it a "hole".
|
||||
*/
|
||||
void
|
||||
scanner_append_argument (parser_context_t *context_p, /**< context */
|
||||
scanner_context_t *scanner_context_p) /**< scanner context */
|
||||
{
|
||||
scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;
|
||||
parser_list_iterator_t literal_iterator;
|
||||
parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
|
||||
lexer_lit_location_t *literal_p;
|
||||
|
||||
const uint8_t *char_p = context_p->token.lit_location.char_p;
|
||||
prop_length_t length = context_p->token.lit_location.length;
|
||||
|
||||
if (JERRY_LIKELY (!context_p->token.lit_location.has_escape))
|
||||
{
|
||||
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
|
||||
{
|
||||
if (literal_p->length == length)
|
||||
{
|
||||
if (JERRY_LIKELY (!literal_p->has_escape))
|
||||
{
|
||||
if (memcmp (literal_p->char_p, char_p, length) == 0)
|
||||
{
|
||||
literal_p->length = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (lexer_compare_identifiers (literal_p->char_p, char_p, length))
|
||||
{
|
||||
literal_p->length = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
|
||||
{
|
||||
if (literal_p->length == length
|
||||
&& lexer_compare_identifiers (literal_p->char_p, char_p, length))
|
||||
{
|
||||
literal_p->length = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &literal_pool_p->literal_pool);
|
||||
*literal_p = context_p->token.lit_location;
|
||||
|
||||
literal_p->type = SCANNER_LITERAL_IS_ARG;
|
||||
} /* scanner_append_argument */
|
||||
|
||||
/**
|
||||
* Check whether an eval call is performed and update the status flags accordingly.
|
||||
*/
|
||||
void
|
||||
scanner_detect_eval_call (parser_context_t *context_p, /**< context */
|
||||
scanner_context_t *scanner_context_p) /**< scanner context */
|
||||
{
|
||||
if (context_p->token.lit_location.length == 4
|
||||
&& lexer_compare_identifiers (context_p->token.lit_location.char_p, (const uint8_t *) "eval", 4)
|
||||
&& lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
|
||||
{
|
||||
scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG;
|
||||
}
|
||||
} /* scanner_detect_eval_call */
|
||||
|
||||
/**
|
||||
* Reverse the scanner info chain after the scanning is completed.
|
||||
*/
|
||||
@@ -282,6 +940,16 @@ scanner_cleanup (parser_context_t *context_p) /**< context */
|
||||
scanner_info_p = context_p->active_scanner_info_p;
|
||||
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));
|
||||
break;
|
||||
}
|
||||
case SCANNER_TYPE_WHILE:
|
||||
case SCANNER_TYPE_FOR_IN:
|
||||
#if ENABLED (JERRY_ES2015_FOR_OF)
|
||||
@@ -305,12 +973,7 @@ scanner_cleanup (parser_context_t *context_p) /**< context */
|
||||
}
|
||||
default:
|
||||
{
|
||||
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
|
||||
JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS
|
||||
|| scanner_info_p->type == SCANNER_TYPE_ARROW);
|
||||
#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS);
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -323,6 +986,251 @@ scanner_cleanup (parser_context_t *context_p) /**< context */
|
||||
context_p->active_scanner_info_p = NULL;
|
||||
} /* scanner_cleanup */
|
||||
|
||||
/**
|
||||
* Description of "arguments" literal string.
|
||||
*/
|
||||
const lexer_lit_location_t lexer_arguments_literal =
|
||||
{
|
||||
(const uint8_t *) "arguments", 9, LEXER_IDENT_LITERAL, false
|
||||
};
|
||||
|
||||
/**
|
||||
* Create and/or initialize var/let/const/function/etc. variables.
|
||||
*/
|
||||
void
|
||||
scanner_create_variables (parser_context_t *context_p, /**< context */
|
||||
size_t size) /**< size excluding the stream */
|
||||
{
|
||||
scanner_info_t *info_p = context_p->next_scanner_info_p;
|
||||
const uint8_t *data_p = ((const uint8_t *) info_p) + size;
|
||||
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);
|
||||
|
||||
if (info_type == SCANNER_TYPE_FUNCTION)
|
||||
{
|
||||
JERRY_ASSERT (context_p->scope_stack_p == NULL);
|
||||
|
||||
size_t stack_size = info_p->u16_arg * sizeof (parser_scope_stack);
|
||||
context_p->scope_stack_size = info_p->u16_arg;
|
||||
|
||||
if (stack_size == 0)
|
||||
{
|
||||
scanner_release_next (context_p, size + 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
uint32_t type = data_p[0] & SCANNER_STREAM_TYPE_MASK;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (type == SCANNER_STREAM_TYPE_HOLE)
|
||||
{
|
||||
data_p++;
|
||||
|
||||
JERRY_ASSERT (info_type == SCANNER_TYPE_FUNCTION);
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
|
||||
{
|
||||
scope_stack_reg_top++;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (&literal.char_p, data_p + 2 + 1, sizeof (const uint8_t *));
|
||||
length = 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;
|
||||
length = 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);
|
||||
|
||||
uint16_t map_to;
|
||||
|
||||
if (!(data_p[0] & SCANNER_STREAM_NO_REG)
|
||||
&& scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
|
||||
{
|
||||
map_to = (uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top);
|
||||
|
||||
scope_stack_p->map_from = context_p->lit_object.index;
|
||||
scope_stack_p->map_to = map_to;
|
||||
scope_stack_reg_top++;
|
||||
}
|
||||
else
|
||||
{
|
||||
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_USED;
|
||||
map_to = context_p->lit_object.index;
|
||||
|
||||
scope_stack_p->map_from = map_to;
|
||||
scope_stack_p->map_to = map_to;
|
||||
|
||||
if (info_type == SCANNER_TYPE_FUNCTION)
|
||||
{
|
||||
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED;
|
||||
}
|
||||
|
||||
if (type == SCANNER_STREAM_TYPE_VAR)
|
||||
{
|
||||
#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) */
|
||||
|
||||
parser_emit_cbc_literal (context_p, CBC_CREATE_VAR, map_to);
|
||||
}
|
||||
else if (type == SCANNER_STREAM_TYPE_ARG || type == SCANNER_STREAM_TYPE_ARG_FUNC)
|
||||
{
|
||||
if (type == SCANNER_STREAM_TYPE_ARG)
|
||||
{
|
||||
#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) */
|
||||
|
||||
parser_emit_cbc_literal_value (context_p,
|
||||
CBC_INIT_LOCAL,
|
||||
(uint16_t) (PARSER_REGISTER_START + scope_stack_reg_top),
|
||||
map_to);
|
||||
}
|
||||
|
||||
if (scope_stack_reg_top < PARSER_MAXIMUM_NUMBER_OF_REGISTERS)
|
||||
{
|
||||
scope_stack_reg_top++;
|
||||
}
|
||||
}
|
||||
}
|
||||
scope_stack_p++;
|
||||
|
||||
literal.char_p += data_p[1];
|
||||
data_p += length;
|
||||
|
||||
if (type != SCANNER_STREAM_TYPE_ARG_FUNC && type != SCANNER_STREAM_TYPE_FUNC)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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) */
|
||||
|
||||
parser_emit_cbc_literal_value (context_p, CBC_INIT_LOCAL, 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++;
|
||||
}
|
||||
|
||||
if (info_type == SCANNER_TYPE_FUNCTION && (info_p->u8_arg & SCANNER_FUNCTION_ARGUMENTS_NEEDED))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED;
|
||||
|
||||
lexer_construct_literal_object (context_p, &lexer_arguments_literal, lexer_arguments_literal.type);
|
||||
|
||||
scope_stack_p->map_from = context_p->lit_object.index;
|
||||
scope_stack_p->map_to = context_p->lit_object.index;
|
||||
scope_stack_p++;
|
||||
}
|
||||
|
||||
context_p->scope_stack_top = (uint16_t) (scope_stack_p - context_p->scope_stack_p);
|
||||
context_p->scope_stack_reg_top = (uint16_t) scope_stack_reg_top;
|
||||
|
||||
if (context_p->register_count < 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)));
|
||||
parser_flush_cbc (context_p);
|
||||
} /* scanner_create_variables */
|
||||
|
||||
/**
|
||||
* Get location from context.
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "jcontext.h"
|
||||
#include "js-parser-internal.h"
|
||||
#include "js-scanner-internal.h"
|
||||
#include "lit-char-helpers.h"
|
||||
@@ -59,13 +60,15 @@ typedef enum
|
||||
typedef enum
|
||||
{
|
||||
SCAN_STACK_SCRIPT, /**< script */
|
||||
SCAN_STACK_EVAL_FUNCTION, /**< evaluated function */
|
||||
SCAN_STACK_SCRIPT_FUNCTION, /**< script is a function body */
|
||||
SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */
|
||||
SCAN_STACK_FUNCTION_STATEMENT, /**< function statement */
|
||||
SCAN_STACK_FUNCTION_EXPRESSION, /**< function expression */
|
||||
SCAN_STACK_FUNCTION_PROPERTY, /**< function expression in an object literal or class */
|
||||
SCAN_STACK_SWITCH_BLOCK, /**< block part of "switch" statement */
|
||||
SCAN_STACK_IF_STATEMENT, /**< statement part of "if" statements */
|
||||
SCAN_STACK_WITH_STATEMENT, /**< statement part of "with" statements */
|
||||
SCAN_STACK_WITH_EXPRESSION, /**< expression part of "with" statements */
|
||||
SCAN_STACK_DO_STATEMENT, /**< statement part of "do" statements */
|
||||
SCAN_STACK_DO_EXPRESSION, /**< expression part of "do" statements */
|
||||
SCAN_STACK_WHILE_EXPRESSION, /**< expression part of "while" iterator */
|
||||
@@ -158,10 +161,7 @@ static void
|
||||
scanner_process_arrow (parser_context_t *context_p, /**< context */
|
||||
scanner_context_t *scanner_context_p) /**< scanner context */
|
||||
{
|
||||
scanner_source_start_t source_start;
|
||||
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t));
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
@@ -169,11 +169,16 @@ scanner_process_arrow (parser_context_t *context_p, /**< context */
|
||||
|| (context_p->token.flags & LEXER_WAS_NEWLINE))
|
||||
{
|
||||
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
|
||||
scanner_pop_literal_pool (context_p, scanner_context_p);
|
||||
return;
|
||||
}
|
||||
|
||||
scanner_info_t *info_p = scanner_insert_info (context_p, source_start.source_p, sizeof (scanner_info_t));
|
||||
info_p->type = SCANNER_TYPE_ARROW;
|
||||
scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;
|
||||
|
||||
literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS;
|
||||
literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_WITH;
|
||||
|
||||
scanner_filter_arguments (context_p, scanner_context_p);
|
||||
|
||||
scanner_check_arrow_body (context_p, scanner_context_p);
|
||||
} /* scanner_process_arrow */
|
||||
@@ -186,8 +191,14 @@ scanner_process_simple_arrow (parser_context_t *context_p, /**< context */
|
||||
scanner_context_t *scanner_context_p, /**< scanner context */
|
||||
const uint8_t *source_p) /**< identifier end position */
|
||||
{
|
||||
scanner_info_t *info_p = scanner_insert_info (context_p, source_p, sizeof (scanner_info_t));
|
||||
info_p->type = SCANNER_TYPE_ARROW;
|
||||
scanner_literal_pool_t *literal_pool_p;
|
||||
literal_pool_p = scanner_push_literal_pool (context_p,
|
||||
scanner_context_p,
|
||||
SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS);
|
||||
literal_pool_p->source_p = source_p;
|
||||
|
||||
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
|
||||
location_p->type |= SCANNER_LITERAL_IS_ARG;
|
||||
|
||||
/* Skip the => token, which size is two. */
|
||||
context_p->source_p += 2;
|
||||
@@ -197,6 +208,64 @@ scanner_process_simple_arrow (parser_context_t *context_p, /**< context */
|
||||
scanner_check_arrow_body (context_p, scanner_context_p);
|
||||
} /* scanner_process_simple_arrow */
|
||||
|
||||
/**
|
||||
* Process the next argument of a might-be arrow function.
|
||||
*/
|
||||
static void
|
||||
scanner_process_arrow_arg (parser_context_t *context_p, /**< context */
|
||||
scanner_context_t *scanner_context_p) /**< scanner context */
|
||||
{
|
||||
JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARROW_ARGUMENTS);
|
||||
|
||||
const uint8_t *source_p = context_p->source_p;
|
||||
bool process_arrow = false;
|
||||
|
||||
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
|
||||
|
||||
#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER)
|
||||
if (context_p->token.type == LEXER_THREE_DOTS)
|
||||
{
|
||||
lexer_next_token (context_p);
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */
|
||||
|
||||
if (context_p->token.type == LEXER_LITERAL
|
||||
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
|
||||
|
||||
if (lexer_check_arrow (context_p))
|
||||
{
|
||||
process_arrow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
scanner_append_argument (context_p, scanner_context_p);
|
||||
|
||||
scanner_detect_eval_call (context_p, scanner_context_p);
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type == LEXER_ASSIGN
|
||||
|| context_p->token.type == LEXER_COMMA
|
||||
|| context_p->token.type == LEXER_RIGHT_PAREN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scanner_pop_literal_pool (context_p, scanner_context_p);
|
||||
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION);
|
||||
|
||||
if (process_arrow)
|
||||
{
|
||||
scanner_process_simple_arrow (context_p, scanner_context_p, source_p);
|
||||
}
|
||||
} /* scanner_process_arrow_arg */
|
||||
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
|
||||
/**
|
||||
@@ -226,6 +295,8 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */
|
||||
}
|
||||
case LEXER_KEYW_FUNCTION:
|
||||
{
|
||||
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
|
||||
|
||||
lexer_next_token (context_p);
|
||||
if (context_p->token.type == LEXER_LITERAL
|
||||
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
|
||||
@@ -240,15 +311,26 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */
|
||||
case LEXER_LEFT_PAREN:
|
||||
{
|
||||
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
|
||||
scanner_source_start_t source_start;
|
||||
source_start.source_p = context_p->source_p;
|
||||
|
||||
parser_stack_push (context_p, &source_start, sizeof (scanner_source_start_t));
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_ARROW_ARGUMENTS);
|
||||
|
||||
scanner_literal_pool_t *literal_pool_p;
|
||||
literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, 0);
|
||||
literal_pool_p->source_p = context_p->source_p;
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type == LEXER_RIGHT_PAREN)
|
||||
{
|
||||
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
|
||||
return SCAN_KEEP_TOKEN;
|
||||
}
|
||||
|
||||
scanner_process_arrow_arg (context_p, scanner_context_p);
|
||||
return SCAN_KEEP_TOKEN;
|
||||
#else
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION);
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
break;
|
||||
}
|
||||
case LEXER_LEFT_SQUARE:
|
||||
@@ -278,8 +360,8 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */
|
||||
case LEXER_LITERAL:
|
||||
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
|
||||
{
|
||||
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
|
||||
const uint8_t *source_p = context_p->source_p;
|
||||
|
||||
if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
|
||||
@@ -288,9 +370,14 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */
|
||||
scanner_process_simple_arrow (context_p, scanner_context_p, source_p);
|
||||
return SCAN_KEEP_TOKEN;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
|
||||
if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
scanner_add_reference (context_p, scanner_context_p);
|
||||
}
|
||||
/* FALLTHRU */
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
case LEXER_KEYW_THIS:
|
||||
case LEXER_KEYW_SUPER:
|
||||
case LEXER_LIT_TRUE:
|
||||
@@ -305,6 +392,13 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */
|
||||
{
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_EXPRESSION);
|
||||
scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION;
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
|
||||
{
|
||||
return SCAN_KEEP_TOKEN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_CLASS) */
|
||||
@@ -335,13 +429,6 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
break;
|
||||
}
|
||||
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
|
||||
if (stack_top == SCAN_STACK_ARROW_ARGUMENTS)
|
||||
{
|
||||
scanner_process_arrow (context_p, scanner_context_p);
|
||||
return SCAN_KEEP_TOKEN;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
/* FALLTHRU */
|
||||
}
|
||||
default:
|
||||
@@ -440,6 +527,12 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
|
||||
break;
|
||||
}
|
||||
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
|
||||
case SCAN_STACK_ARROW_ARGUMENTS:
|
||||
{
|
||||
lexer_next_token (context_p);
|
||||
scanner_process_arrow_arg (context_p, scanner_context_p);
|
||||
return SCAN_KEEP_TOKEN;
|
||||
}
|
||||
case SCAN_STACK_ARROW_EXPRESSION:
|
||||
{
|
||||
break;
|
||||
@@ -476,30 +569,22 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
|
||||
|
||||
switch (stack_top)
|
||||
{
|
||||
case SCAN_STACK_VAR:
|
||||
{
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
return SCAN_KEEP_TOKEN;
|
||||
}
|
||||
case SCAN_STACK_PAREN_EXPRESSION:
|
||||
{
|
||||
if (type != LEXER_RIGHT_PAREN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
return SCAN_NEXT_TOKEN;
|
||||
}
|
||||
case SCAN_STACK_STATEMENT_WITH_EXPR:
|
||||
case SCAN_STACK_WITH_EXPRESSION:
|
||||
{
|
||||
if (type != LEXER_RIGHT_PAREN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
scanner_context_p->mode = SCAN_MODE_STATEMENT;
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
|
||||
uint16_t status_flags = scanner_context_p->active_literal_pool_p->status_flags;
|
||||
parser_stack_push_uint8 (context_p, (status_flags & SCANNER_LITERAL_POOL_IN_WITH) ? 1 : 0);
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_WITH_STATEMENT);
|
||||
status_flags |= SCANNER_LITERAL_POOL_IN_WITH;
|
||||
scanner_context_p->active_literal_pool_p->status_flags = status_flags;
|
||||
|
||||
scanner_context_p->mode = SCAN_MODE_STATEMENT;
|
||||
return SCAN_NEXT_TOKEN;
|
||||
}
|
||||
case SCAN_STACK_DO_EXPRESSION:
|
||||
@@ -535,6 +620,32 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
|
||||
scanner_context_p->mode = SCAN_MODE_STATEMENT;
|
||||
return SCAN_NEXT_TOKEN;
|
||||
}
|
||||
case SCAN_STACK_PAREN_EXPRESSION:
|
||||
{
|
||||
if (type != LEXER_RIGHT_PAREN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
return SCAN_NEXT_TOKEN;
|
||||
}
|
||||
case SCAN_STACK_STATEMENT_WITH_EXPR:
|
||||
{
|
||||
if (type != LEXER_RIGHT_PAREN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
scanner_context_p->mode = SCAN_MODE_STATEMENT;
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
return SCAN_NEXT_TOKEN;
|
||||
}
|
||||
case SCAN_STACK_VAR:
|
||||
{
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
return SCAN_KEEP_TOKEN;
|
||||
}
|
||||
case SCAN_STACK_FOR_VAR_START:
|
||||
case SCAN_STACK_FOR_START:
|
||||
{
|
||||
@@ -750,6 +861,8 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
|
||||
|
||||
if (stack_top == SCAN_STACK_FUNCTION_PROPERTY)
|
||||
{
|
||||
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
|
||||
|
||||
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
|
||||
return SCAN_KEEP_TOKEN;
|
||||
}
|
||||
@@ -758,6 +871,8 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
|
||||
|
||||
if (context_p->token.type == LEXER_LEFT_PAREN)
|
||||
{
|
||||
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
|
||||
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
|
||||
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
|
||||
return SCAN_KEEP_TOKEN;
|
||||
@@ -809,6 +924,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
|
||||
}
|
||||
case SCAN_STACK_ARROW_EXPRESSION:
|
||||
{
|
||||
scanner_pop_literal_pool (context_p, scanner_context_p);
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
|
||||
return SCAN_KEEP_TOKEN;
|
||||
@@ -832,7 +948,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
|
||||
if (type != LEXER_RIGHT_PAREN
|
||||
&& (type != LEXER_EOS || context_p->stack_top_uint8 != SCAN_STACK_EVAL_FUNCTION))
|
||||
&& (type != LEXER_EOS || context_p->stack_top_uint8 != SCAN_STACK_SCRIPT_FUNCTION))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -916,6 +1032,10 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
|
||||
{
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_IF_STATEMENT);
|
||||
}
|
||||
else if (type == LEXER_KEYW_WITH)
|
||||
{
|
||||
mode = SCAN_STACK_WITH_EXPRESSION;
|
||||
}
|
||||
else if (type == LEXER_KEYW_SWITCH)
|
||||
{
|
||||
mode = SCAN_STACK_SWITCH_EXPRESSION;
|
||||
@@ -1065,6 +1185,11 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC;
|
||||
|
||||
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
|
||||
|
||||
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_STATEMENT);
|
||||
return SCAN_NEXT_TOKEN;
|
||||
@@ -1072,6 +1197,16 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
|
||||
#if ENABLED (JERRY_ES2015_CLASS)
|
||||
case LEXER_KEYW_CLASS:
|
||||
{
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
|
||||
{
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR;
|
||||
|
||||
scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION;
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_STATEMENT);
|
||||
return SCAN_NEXT_TOKEN;
|
||||
@@ -1099,6 +1234,9 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
|
||||
if (context_p->token.type == LEXER_LITERAL
|
||||
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR;
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type == LEXER_COMMA)
|
||||
@@ -1129,6 +1267,9 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR;
|
||||
|
||||
lexer_next_token (context_p);
|
||||
}
|
||||
else if (context_p->token.type == LEXER_LEFT_BRACE)
|
||||
@@ -1143,21 +1284,29 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (lexer_compare_literal_to_identifier (context_p, "as", 2))
|
||||
if (lexer_check_next_character (context_p, LIT_CHAR_LOWERCASE_A))
|
||||
{
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (!lexer_compare_literal_to_identifier (context_p, "as", 2))
|
||||
{
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type != LEXER_LITERAL
|
||||
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
lexer_next_token (context_p);
|
||||
}
|
||||
|
||||
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR;
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type != LEXER_RIGHT_BRACE)
|
||||
{
|
||||
if (context_p->token.type != LEXER_COMMA)
|
||||
@@ -1211,8 +1360,21 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
|
||||
if (context_p->token.type == LEXER_LITERAL
|
||||
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC;
|
||||
|
||||
lexer_next_token (context_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
lexer_lit_location_t *location_p;
|
||||
location_p = scanner_add_custom_literal (context_p,
|
||||
scanner_context_p->active_literal_pool_p,
|
||||
&lexer_default_literal);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC;
|
||||
}
|
||||
|
||||
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
|
||||
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_STATEMENT);
|
||||
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
|
||||
@@ -1221,13 +1383,44 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
|
||||
#if ENABLED (JERRY_ES2015_CLASS)
|
||||
if (context_p->token.type == LEXER_KEYW_CLASS)
|
||||
{
|
||||
scanner_context_p->mode = SCAN_MODE_STATEMENT;
|
||||
scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION;
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_STATEMENT);
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR;
|
||||
return SCAN_NEXT_TOKEN;
|
||||
}
|
||||
|
||||
lexer_lit_location_t *location_p;
|
||||
location_p = scanner_add_custom_literal (context_p,
|
||||
scanner_context_p->active_literal_pool_p,
|
||||
&lexer_default_literal);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR;
|
||||
return SCAN_KEEP_TOKEN;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_CLASS) */
|
||||
|
||||
/* Assignment expression. */
|
||||
lexer_lit_location_t *location_p;
|
||||
location_p = scanner_add_custom_literal (context_p,
|
||||
scanner_context_p->active_literal_pool_p,
|
||||
&lexer_default_literal);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR;
|
||||
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
|
||||
return SCAN_KEEP_TOKEN;
|
||||
|
||||
if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
|
||||
{
|
||||
return SCAN_KEEP_TOKEN;
|
||||
}
|
||||
|
||||
location_p = scanner_add_literal (context_p, scanner_context_p);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR;
|
||||
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
|
||||
return SCAN_NEXT_TOKEN;
|
||||
}
|
||||
|
||||
scanner_context_p->mode = SCAN_MODE_STATEMENT_END;
|
||||
@@ -1342,6 +1535,8 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
|
||||
scanner_add_reference (context_p, scanner_context_p);
|
||||
|
||||
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
|
||||
return SCAN_NEXT_TOKEN;
|
||||
}
|
||||
@@ -1374,7 +1569,7 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
|
||||
switch (context_p->stack_top_uint8)
|
||||
{
|
||||
case SCAN_STACK_SCRIPT:
|
||||
case SCAN_STACK_EVAL_FUNCTION:
|
||||
case SCAN_STACK_SCRIPT_FUNCTION:
|
||||
{
|
||||
if (type == LEXER_EOS)
|
||||
{
|
||||
@@ -1393,6 +1588,11 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
|
||||
break;
|
||||
}
|
||||
|
||||
if (context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_STATEMENT)
|
||||
{
|
||||
scanner_pop_literal_pool (context_p, scanner_context_p);
|
||||
}
|
||||
|
||||
terminator_found = true;
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
lexer_next_token (context_p);
|
||||
@@ -1405,6 +1605,8 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
|
||||
break;
|
||||
}
|
||||
|
||||
scanner_pop_literal_pool (context_p, scanner_context_p);
|
||||
|
||||
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
return SCAN_NEXT_TOKEN;
|
||||
@@ -1416,6 +1618,7 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
|
||||
break;
|
||||
}
|
||||
|
||||
scanner_pop_literal_pool (context_p, scanner_context_p);
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
|
||||
#if ENABLED (JERRY_ES2015_CLASS)
|
||||
@@ -1475,6 +1678,22 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case SCAN_STACK_WITH_STATEMENT:
|
||||
{
|
||||
scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;
|
||||
|
||||
JERRY_ASSERT (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH);
|
||||
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
|
||||
if (context_p->stack_top_uint8 == 0)
|
||||
{
|
||||
literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_WITH;
|
||||
}
|
||||
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
continue;
|
||||
}
|
||||
case SCAN_STACK_DO_STATEMENT:
|
||||
{
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
@@ -1515,6 +1734,11 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
|
||||
parser_stack_pop_uint8 (context_p);
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (stack_top == SCAN_STACK_CATCH_STATEMENT)
|
||||
{
|
||||
scanner_pop_literal_pool (context_p, scanner_context_p);
|
||||
}
|
||||
|
||||
/* A finally statement is optional after a try or catch statement. */
|
||||
if (context_p->token.type == LEXER_KEYW_FINALLY)
|
||||
{
|
||||
@@ -1549,6 +1773,8 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
const uint8_t *source_p = context_p->source_p;
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type != LEXER_LITERAL
|
||||
@@ -1557,6 +1783,13 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
scanner_literal_pool_t *literal_pool_p;
|
||||
literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_BLOCK);
|
||||
literal_pool_p->source_p = source_p;
|
||||
|
||||
lexer_lit_location_t *lit_location_p = scanner_add_literal (context_p, scanner_context_p);
|
||||
lit_location_p->type |= SCANNER_LITERAL_IS_LOCAL;
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type != LEXER_RIGHT_PAREN)
|
||||
@@ -1606,7 +1839,15 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
}
|
||||
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
|
||||
|
||||
#if ENABLED (JERRY_DEBUGGER)
|
||||
scanner_context.debugger_enabled = (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) ? 1 : 0;
|
||||
#endif /* ENABLED (JERRY_DEBUGGER) */
|
||||
scanner_context.active_literal_pool_p = NULL;
|
||||
scanner_context.active_switch_statement.last_case_p = NULL;
|
||||
scanner_context.end_arguments_p = NULL;
|
||||
|
||||
/* This assignment must be here because of Apple compilers. */
|
||||
context_p->u.scanner_context_p = &scanner_context;
|
||||
|
||||
parser_stack_init (context_p);
|
||||
|
||||
@@ -1620,6 +1861,10 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
context_p->source_p = source_p;
|
||||
context_p->source_end_p = source_end_p;
|
||||
|
||||
uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS | SCANNER_LITERAL_POOL_NO_REG;
|
||||
scanner_literal_pool_t *literal_pool_p = scanner_push_literal_pool (context_p, &scanner_context, status_flags);
|
||||
literal_pool_p->source_p = source_p;
|
||||
|
||||
scanner_context.mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_SCRIPT);
|
||||
|
||||
@@ -1629,8 +1874,10 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
{
|
||||
context_p->source_p = arg_list_p;
|
||||
context_p->source_end_p = arg_list_end_p;
|
||||
|
||||
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
|
||||
scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS;
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_EVAL_FUNCTION);
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_SCRIPT_FUNCTION);
|
||||
|
||||
/* Faking the first token. */
|
||||
context_p->token.type = LEXER_LEFT_PAREN;
|
||||
@@ -1664,11 +1911,6 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
#if ENABLED (JERRY_ES2015_CLASS)
|
||||
case SCAN_MODE_CLASS_DECLARATION:
|
||||
{
|
||||
if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
|
||||
{
|
||||
lexer_next_token (context_p);
|
||||
}
|
||||
|
||||
if (context_p->token.type == LEXER_KEYW_EXTENDS)
|
||||
{
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_EXTENDS);
|
||||
@@ -1719,6 +1961,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
|
||||
if (context_p->token.type == LEXER_LEFT_PAREN)
|
||||
{
|
||||
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1732,6 +1975,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */
|
||||
|
||||
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
|
||||
lexer_next_token (context_p);
|
||||
continue;
|
||||
}
|
||||
@@ -1791,6 +2035,14 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
lexer_lit_location_t *location_p = scanner_add_literal (context_p, &scanner_context);
|
||||
location_p->type |= SCANNER_LITERAL_IS_VAR;
|
||||
|
||||
if (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
|
||||
{
|
||||
location_p->type |= SCANNER_LITERAL_NO_REG;
|
||||
}
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
switch (context_p->token.type)
|
||||
@@ -1828,11 +2080,16 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
}
|
||||
case SCAN_MODE_FUNCTION_ARGUMENTS:
|
||||
{
|
||||
JERRY_ASSERT (stack_top == SCAN_STACK_EVAL_FUNCTION
|
||||
JERRY_ASSERT (stack_top == SCAN_STACK_SCRIPT_FUNCTION
|
||||
|| stack_top == SCAN_STACK_FUNCTION_STATEMENT
|
||||
|| stack_top == SCAN_STACK_FUNCTION_EXPRESSION
|
||||
|| stack_top == SCAN_STACK_FUNCTION_PROPERTY);
|
||||
|
||||
JERRY_ASSERT (scanner_context.active_literal_pool_p != NULL
|
||||
&& (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION));
|
||||
|
||||
scanner_context.active_literal_pool_p->source_p = context_p->source_p;
|
||||
|
||||
if (type != LEXER_LEFT_PAREN)
|
||||
{
|
||||
scanner_raise_error (context_p);
|
||||
@@ -1862,6 +2119,9 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
{
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
scanner_append_argument (context_p, &scanner_context);
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type != LEXER_COMMA)
|
||||
@@ -1881,13 +2141,14 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */
|
||||
|
||||
if (context_p->token.type == LEXER_EOS && stack_top == SCAN_STACK_EVAL_FUNCTION)
|
||||
if (context_p->token.type == LEXER_EOS && stack_top == SCAN_STACK_SCRIPT_FUNCTION)
|
||||
{
|
||||
/* End of argument parsing. */
|
||||
scanner_info_t *scanner_info_p = (scanner_info_t *) scanner_malloc (context_p, sizeof (scanner_info_t));
|
||||
scanner_info_p->next_p = context_p->next_scanner_info_p;
|
||||
scanner_info_p->source_p = NULL;
|
||||
scanner_info_p->type = SCANNER_TYPE_END_ARGUMENTS;
|
||||
scanner_context.end_arguments_p = scanner_info_p;
|
||||
|
||||
context_p->next_scanner_info_p = scanner_info_p;
|
||||
context_p->source_p = source_p;
|
||||
@@ -1911,6 +2172,8 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
{
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
scanner_filter_arguments (context_p, &scanner_context);
|
||||
scanner_context.mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
|
||||
break;
|
||||
}
|
||||
@@ -1957,6 +2220,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
|
||||
scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS;
|
||||
break;
|
||||
}
|
||||
@@ -1974,6 +2238,8 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER)
|
||||
if (context_p->token.type == LEXER_LEFT_PAREN)
|
||||
{
|
||||
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
|
||||
|
||||
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
|
||||
scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS;
|
||||
continue;
|
||||
@@ -1996,6 +2262,8 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
scanner_add_literal (context_p, &scanner_context);
|
||||
|
||||
lexer_next_token (context_p);
|
||||
|
||||
if (context_p->token.type == LEXER_COMMA)
|
||||
@@ -2026,11 +2294,13 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|
||||
|
||||
scan_completed:
|
||||
if (context_p->stack_top_uint8 != SCAN_STACK_SCRIPT
|
||||
&& context_p->stack_top_uint8 != SCAN_STACK_EVAL_FUNCTION)
|
||||
&& context_p->stack_top_uint8 != SCAN_STACK_SCRIPT_FUNCTION)
|
||||
{
|
||||
scanner_raise_error (context_p);
|
||||
}
|
||||
|
||||
scanner_pop_literal_pool (context_p, &scanner_context);
|
||||
|
||||
#ifndef JERRY_NDEBUG
|
||||
context_p->status_flags |= PARSER_SCANNING_SUCCESSFUL;
|
||||
#endif /* !JERRY_NDEBUG */
|
||||
@@ -2042,6 +2312,30 @@ scan_completed:
|
||||
{
|
||||
context_p->error = PARSER_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
/* The following loop may allocate memory, so it is enclosed in a try/catch. */
|
||||
PARSER_TRY (context_p->try_buffer)
|
||||
{
|
||||
while (scanner_context.active_literal_pool_p != NULL)
|
||||
{
|
||||
scanner_pop_literal_pool (context_p, &scanner_context);
|
||||
}
|
||||
}
|
||||
PARSER_CATCH
|
||||
{
|
||||
JERRY_ASSERT (context_p->error == PARSER_ERR_NO_ERROR);
|
||||
|
||||
while (scanner_context.active_literal_pool_p != NULL)
|
||||
{
|
||||
scanner_literal_pool_t *literal_pool_p = scanner_context.active_literal_pool_p;
|
||||
|
||||
scanner_context.active_literal_pool_p = literal_pool_p->prev_p;
|
||||
|
||||
parser_list_free (&literal_pool_p->literal_pool);
|
||||
scanner_free (literal_pool_p, sizeof (scanner_literal_pool_t));
|
||||
}
|
||||
}
|
||||
PARSER_TRY_END
|
||||
}
|
||||
PARSER_TRY_END
|
||||
|
||||
@@ -2066,6 +2360,102 @@ scan_completed:
|
||||
source_start_p = source_p;
|
||||
break;
|
||||
}
|
||||
case SCANNER_TYPE_FUNCTION:
|
||||
case SCANNER_TYPE_BLOCK:
|
||||
{
|
||||
const uint8_t *prev_source_p = info_p->source_p - 1;
|
||||
const uint8_t *data_p;
|
||||
|
||||
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);
|
||||
|
||||
JERRY_DEBUG_MSG (" FUNCTION: flags: 0x%x declarations: %d",
|
||||
(int) function_info_p->info.u8_arg,
|
||||
(int) function_info_p->info.u16_arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
data_p = (const uint8_t *) (info_p + 1);
|
||||
|
||||
JERRY_DEBUG_MSG (" BLOCK:");
|
||||
}
|
||||
|
||||
JERRY_DEBUG_MSG (" source:%d\n", (int) (info_p->source_p - source_start_p));
|
||||
|
||||
while (data_p[0] != SCANNER_STREAM_TYPE_END)
|
||||
{
|
||||
switch (data_p[0] & SCANNER_STREAM_TYPE_MASK)
|
||||
{
|
||||
case SCANNER_STREAM_TYPE_ARG:
|
||||
{
|
||||
JERRY_DEBUG_MSG (" ARG ");
|
||||
break;
|
||||
}
|
||||
case SCANNER_STREAM_TYPE_ARG_FUNC:
|
||||
{
|
||||
JERRY_DEBUG_MSG (" ARG_FUNC ");
|
||||
break;
|
||||
}
|
||||
case SCANNER_STREAM_TYPE_VAR:
|
||||
{
|
||||
JERRY_DEBUG_MSG (" VAR ");
|
||||
break;
|
||||
}
|
||||
case SCANNER_STREAM_TYPE_FUNC:
|
||||
{
|
||||
JERRY_DEBUG_MSG (" FUNC ");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_ASSERT ((data_p[0] & SCANNER_STREAM_TYPE_MASK) == SCANNER_STREAM_TYPE_HOLE);
|
||||
JERRY_DEBUG_MSG (" HOLE\n");
|
||||
data_p++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
size_t length;
|
||||
|
||||
if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF))
|
||||
{
|
||||
if (data_p[2] != 0)
|
||||
{
|
||||
prev_source_p += data_p[2];
|
||||
length = 2 + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (&prev_source_p, data_p + 2 + 1, sizeof (const uint8_t *));
|
||||
length = 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;
|
||||
}
|
||||
|
||||
prev_source_p += diff;
|
||||
length = 2 + 2;
|
||||
}
|
||||
|
||||
if (data_p[0] & SCANNER_STREAM_NO_REG)
|
||||
{
|
||||
JERRY_DEBUG_MSG ("* ");
|
||||
}
|
||||
|
||||
JERRY_DEBUG_MSG ("'%.*s'\n", data_p[1], (char *) prev_source_p);
|
||||
prev_source_p += data_p[1];
|
||||
data_p += length;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCANNER_TYPE_WHILE:
|
||||
{
|
||||
name_p = "WHILE";
|
||||
@@ -2123,13 +2513,6 @@ scan_completed:
|
||||
print_location = true;
|
||||
break;
|
||||
}
|
||||
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
|
||||
case SCANNER_TYPE_ARROW:
|
||||
{
|
||||
JERRY_DEBUG_MSG (" ARROW: source:%d\n", (int) (info_p->source_p - source_start_p));
|
||||
break;
|
||||
}
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
}
|
||||
|
||||
if (print_location)
|
||||
|
||||
@@ -34,6 +34,8 @@ typedef enum
|
||||
SCANNER_TYPE_END, /**< mark the last info block */
|
||||
SCANNER_TYPE_END_ARGUMENTS, /**< mark the end of function arguments
|
||||
* (only present if a function script is parsed) */
|
||||
SCANNER_TYPE_FUNCTION, /**< declarations in a function */
|
||||
SCANNER_TYPE_BLOCK, /**< declarations in a code block (usually enclosed in {}) */
|
||||
SCANNER_TYPE_WHILE, /**< while statement */
|
||||
SCANNER_TYPE_FOR, /**< for statement */
|
||||
SCANNER_TYPE_FOR_IN, /**< for-in statement */
|
||||
@@ -42,9 +44,6 @@ typedef enum
|
||||
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
|
||||
SCANNER_TYPE_SWITCH, /**< switch statement */
|
||||
SCANNER_TYPE_CASE, /**< case statement */
|
||||
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
|
||||
SCANNER_TYPE_ARROW, /**< arrow function */
|
||||
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
|
||||
} scanner_info_type_t;
|
||||
|
||||
/**
|
||||
@@ -65,6 +64,8 @@ typedef struct scanner_info_t
|
||||
struct scanner_info_t *next_p; /**< next info structure */
|
||||
const uint8_t *source_p; /**< triggering position of this scanner info */
|
||||
uint8_t type; /**< type of the scanner info */
|
||||
uint8_t u8_arg; /**< custom 8-bit value */
|
||||
uint16_t u16_arg; /**< custom 16-bit value */
|
||||
} scanner_info_t;
|
||||
|
||||
/**
|
||||
@@ -104,6 +105,64 @@ typedef struct
|
||||
scanner_case_info_t *case_p; /**< list of switch cases */
|
||||
} scanner_switch_info_t;
|
||||
|
||||
/*
|
||||
* Description of compressed streams.
|
||||
*
|
||||
* The stream is a sequence of commands which encoded as bytes. The first byte
|
||||
* contains the type of the command (see scanner_function_compressed_stream_types_t).
|
||||
*
|
||||
* The variable declaration commands has two arguments:
|
||||
* - The first represents the length of the declared identifier
|
||||
* - The second contains the relative distance from the end of the previous declaration
|
||||
* Usually the distance is between 1 and 255, and represented as a single byte
|
||||
* Distances between -256 and 65535 are encoded as two bytes
|
||||
* Larger distances are encoded as pointers
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constants for compressed streams.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
SCANNER_STREAM_UINT16_DIFF = (1 << 7), /**< relative distance is between -256 and 65535 */
|
||||
SCANNER_STREAM_HAS_ESCAPE = (1 << 6), /**< literal has escape */
|
||||
SCANNER_STREAM_NO_REG = (1 << 5), /**< identifier cannot be stored in register */
|
||||
} scanner_compressed_stream_flags_t;
|
||||
|
||||
/**
|
||||
* Types for compressed streams.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
SCANNER_STREAM_TYPE_END, /**< end of scanner data */
|
||||
SCANNER_STREAM_TYPE_HOLE, /**< no name is assigned to this argument */
|
||||
SCANNER_STREAM_TYPE_ARG, /**< argument declaration */
|
||||
SCANNER_STREAM_TYPE_ARG_FUNC, /**< argument declaration which is later initialized with a function */
|
||||
SCANNER_STREAM_TYPE_VAR, /**< var declaration */
|
||||
SCANNER_STREAM_TYPE_FUNC, /**< function declaration */
|
||||
} scanner_compressed_stream_types_t;
|
||||
|
||||
/**
|
||||
* Mask for decoding the type from the compressed stream.
|
||||
*/
|
||||
#define SCANNER_STREAM_TYPE_MASK 0xf
|
||||
|
||||
/**
|
||||
* Constants for u8_arg flags in scanner_function_info_t.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
||||
+46
-78
@@ -797,90 +797,69 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
||||
{
|
||||
switch (*byte_code_p)
|
||||
{
|
||||
case CBC_DEFINE_VARS:
|
||||
case CBC_CREATE_VAR:
|
||||
{
|
||||
uint32_t literal_index_end;
|
||||
uint32_t literal_index = register_end;
|
||||
|
||||
byte_code_p++;
|
||||
READ_LITERAL_INDEX (literal_index_end);
|
||||
|
||||
while (literal_index <= literal_index_end)
|
||||
{
|
||||
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
|
||||
vm_var_decl (frame_ctx_p, name_p);
|
||||
literal_index++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CBC_INITIALIZE_VAR:
|
||||
case CBC_INITIALIZE_VARS:
|
||||
{
|
||||
uint8_t type = *byte_code_p;
|
||||
uint32_t literal_index;
|
||||
uint32_t literal_index_end;
|
||||
|
||||
byte_code_p++;
|
||||
READ_LITERAL_INDEX (literal_index);
|
||||
|
||||
if (type == CBC_INITIALIZE_VAR)
|
||||
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
|
||||
vm_var_decl (frame_ctx_p, name_p);
|
||||
break;
|
||||
}
|
||||
|
||||
case CBC_INIT_LOCAL:
|
||||
{
|
||||
uint32_t literal_index, value_index;
|
||||
ecma_value_t lit_value;
|
||||
|
||||
byte_code_p++;
|
||||
READ_LITERAL_INDEX (value_index);
|
||||
READ_LITERAL_INDEX (literal_index);
|
||||
|
||||
JERRY_ASSERT (value_index != literal_index);
|
||||
JERRY_ASSERT (value_index >= register_end || literal_index >= register_end);
|
||||
|
||||
if (value_index < register_end)
|
||||
{
|
||||
literal_index_end = literal_index;
|
||||
lit_value = frame_ctx_p->registers_p[value_index];
|
||||
}
|
||||
else
|
||||
{
|
||||
READ_LITERAL_INDEX (literal_index_end);
|
||||
lit_value = vm_construct_literal_object (frame_ctx_p,
|
||||
literal_start_p[value_index]);
|
||||
}
|
||||
|
||||
while (literal_index <= literal_index_end)
|
||||
if (literal_index < register_end)
|
||||
{
|
||||
uint32_t value_index;
|
||||
ecma_value_t lit_value;
|
||||
ecma_fast_free_value (frame_ctx_p->registers_p[literal_index]);
|
||||
frame_ctx_p->registers_p[literal_index] = lit_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
|
||||
|
||||
READ_LITERAL_INDEX (value_index);
|
||||
vm_var_decl (frame_ctx_p, name_p);
|
||||
|
||||
if (value_index < register_end)
|
||||
ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (frame_ctx_p->lex_env_p,
|
||||
name_p,
|
||||
is_strict,
|
||||
lit_value);
|
||||
|
||||
JERRY_ASSERT (ecma_is_value_boolean (put_value_result)
|
||||
|| ecma_is_value_empty (put_value_result)
|
||||
|| ECMA_IS_VALUE_ERROR (put_value_result));
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (put_value_result))
|
||||
{
|
||||
lit_value = frame_ctx_p->registers_p[value_index];
|
||||
}
|
||||
else
|
||||
{
|
||||
lit_value = vm_construct_literal_object (frame_ctx_p,
|
||||
literal_start_p[value_index]);
|
||||
ecma_free_value (JERRY_CONTEXT (error_value));
|
||||
}
|
||||
|
||||
if (literal_index < register_end)
|
||||
if (value_index >= register_end)
|
||||
{
|
||||
frame_ctx_p->registers_p[literal_index] = lit_value;
|
||||
ecma_free_value (lit_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
|
||||
|
||||
vm_var_decl (frame_ctx_p, name_p);
|
||||
|
||||
ecma_value_t put_value_result = ecma_op_put_value_lex_env_base (frame_ctx_p->lex_env_p,
|
||||
name_p,
|
||||
is_strict,
|
||||
lit_value);
|
||||
|
||||
JERRY_ASSERT (ecma_is_value_boolean (put_value_result)
|
||||
|| ecma_is_value_empty (put_value_result)
|
||||
|| ECMA_IS_VALUE_ERROR (put_value_result));
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (put_value_result))
|
||||
{
|
||||
ecma_free_value (JERRY_CONTEXT (error_value));
|
||||
}
|
||||
|
||||
if (value_index >= register_end)
|
||||
{
|
||||
ecma_free_value (lit_value);
|
||||
}
|
||||
}
|
||||
|
||||
literal_index++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3492,30 +3471,18 @@ error:
|
||||
JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
|
||||
#endif /* ENABLED (JERRY_DEBUGGER) */
|
||||
|
||||
byte_code_p = frame_ctx_p->byte_code_p;
|
||||
|
||||
if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH)
|
||||
{
|
||||
*stack_top_p++ = JERRY_CONTEXT (error_value);
|
||||
|
||||
JERRY_ASSERT (byte_code_p[0] == CBC_ASSIGN_SET_IDENT);
|
||||
|
||||
uint32_t literal_index = byte_code_p[1];
|
||||
|
||||
if (literal_index >= encoding_limit)
|
||||
{
|
||||
literal_index = ((literal_index << 8) | byte_code_p[2]) - encoding_delta;
|
||||
}
|
||||
|
||||
ecma_object_t *catch_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p);
|
||||
#if ENABLED (JERRY_DEBUGGER)
|
||||
catch_env_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_NON_CLOSURE;
|
||||
#endif /* ENABLED (JERRY_DEBUGGER) */
|
||||
|
||||
ecma_string_t *catch_name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
|
||||
ecma_op_create_mutable_binding (catch_env_p, catch_name_p, false);
|
||||
|
||||
frame_ctx_p->lex_env_p = catch_env_p;
|
||||
|
||||
vm_init_loop (frame_ctx_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3523,6 +3490,7 @@ error:
|
||||
stack_top_p[-2] = JERRY_CONTEXT (error_value);
|
||||
}
|
||||
|
||||
byte_code_p = frame_ctx_p->byte_code_p;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ level | type
|
||||
2 | global
|
||||
(jerry-debugger) variables 0
|
||||
name | type | value
|
||||
n | Number | 9
|
||||
b | undefined | undefined
|
||||
n | Number | 9
|
||||
(jerry-debugger) variables 1
|
||||
name | type | value
|
||||
x | Number | 3
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
var src = "var a = 0; while(a) { switch(a) {";
|
||||
/* The += operation has a longer opcode. */
|
||||
for (var i = 0; i < 3500; i++)
|
||||
for (var i = 0; i < 3300; i++)
|
||||
src += "case " + i + ": a += a += a; break; ";
|
||||
src += "} }";
|
||||
|
||||
|
||||
@@ -223,15 +223,15 @@ main (void)
|
||||
/* Check the snapshot data. Unused bytes should be filled with zeroes */
|
||||
const uint8_t expected_data[] =
|
||||
{
|
||||
0x4A, 0x52, 0x52, 0x59, 0x18, 0x00, 0x00, 0x00,
|
||||
0x4A, 0x52, 0x52, 0x59, 0x19, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
|
||||
0x03, 0x00, 0x01, 0x00, 0x21, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00,
|
||||
0x28, 0x00, 0xB8, 0x46, 0x00, 0x00, 0x00, 0x00,
|
||||
0x28, 0x00, 0xB7, 0x45, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x01, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
|
||||
0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x73, 0x6E,
|
||||
0x61, 0x70, 0x73, 0x68, 0x6F, 0x74
|
||||
|
||||
Reference in New Issue
Block a user