Fixing break / continue, nested into 'try', 'with' blocks.
Related issue: #128 JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
This commit is contained in:
@@ -2142,22 +2142,50 @@ dump_continue_iterations_check (operand op)
|
||||
STACK_DROP (next_iterations, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump template of 'jmp_break_continue' instruction.
|
||||
*
|
||||
* Note:
|
||||
* the instruction's flags field is written later (see also: rewrite_breaks, rewrite_continues).
|
||||
*
|
||||
* @return position of dumped instruction
|
||||
*/
|
||||
void
|
||||
dump_continue_for_rewrite (void)
|
||||
dump_break_continue_for_rewrite (bool is_break, /**< flag indicating whether 'break' should be dumped (true)
|
||||
* or 'continue' (false) */
|
||||
bool is_simple_jump) /**< flag indicating, whether simple jump
|
||||
* or 'jmp_break_continue' template should be dumped */
|
||||
{
|
||||
STACK_PUSH (continues, serializer_get_current_opcode_counter ());
|
||||
const opcode_t opcode = getop_jmp_down (INVALID_VALUE, INVALID_VALUE);
|
||||
serializer_dump_op_meta (create_op_meta_000 (opcode));
|
||||
}
|
||||
if (is_break)
|
||||
{
|
||||
STACK_PUSH (breaks, serializer_get_current_opcode_counter ());
|
||||
}
|
||||
else
|
||||
{
|
||||
STACK_PUSH (continues, serializer_get_current_opcode_counter ());
|
||||
}
|
||||
|
||||
void
|
||||
dump_break_for_rewrite (void)
|
||||
{
|
||||
STACK_PUSH (breaks, serializer_get_current_opcode_counter ());
|
||||
const opcode_t opcode = getop_jmp_down (INVALID_VALUE, INVALID_VALUE);
|
||||
serializer_dump_op_meta (create_op_meta_000 (opcode));
|
||||
}
|
||||
opcode_t opcode;
|
||||
if (is_simple_jump)
|
||||
{
|
||||
opcode = getop_jmp_down (INVALID_VALUE, INVALID_VALUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
opcode = getop_jmp_break_continue (INVALID_VALUE, INVALID_VALUE);
|
||||
}
|
||||
|
||||
serializer_dump_op_meta (create_op_meta_000 (opcode));
|
||||
} /* dump_break_continue_for_rewrite */
|
||||
|
||||
/**
|
||||
* Write jump target positions into previously dumped templates of instructions
|
||||
* for currently processed set of 'break' statements.
|
||||
*
|
||||
* See also:
|
||||
* dump_break_continue_for_rewrite
|
||||
* start_collecting_breaks
|
||||
*/
|
||||
void
|
||||
rewrite_breaks (void)
|
||||
{
|
||||
@@ -2168,9 +2196,22 @@ rewrite_breaks (void)
|
||||
idx_t id1, id2;
|
||||
split_opcode_counter ((opcode_counter_t) (break_target - break_oc), &id1, &id2);
|
||||
op_meta break_op_meta = serializer_get_op_meta (break_oc);
|
||||
JERRY_ASSERT (break_op_meta.op.op_idx == OPCODE (jmp_down));
|
||||
break_op_meta.op.data.jmp_down.opcode_1 = id1;
|
||||
break_op_meta.op.data.jmp_down.opcode_2 = id2;
|
||||
|
||||
bool is_simple_jump = (break_op_meta.op.op_idx == OPCODE (jmp_down));
|
||||
|
||||
if (is_simple_jump)
|
||||
{
|
||||
break_op_meta.op.data.jmp_down.opcode_1 = id1;
|
||||
break_op_meta.op.data.jmp_down.opcode_2 = id2;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (break_op_meta.op.op_idx == OPCODE (jmp_break_continue));
|
||||
|
||||
break_op_meta.op.data.jmp_break_continue.opcode_1 = id1;
|
||||
break_op_meta.op.data.jmp_break_continue.opcode_2 = id2;
|
||||
}
|
||||
|
||||
serializer_rewrite_op_meta (break_oc, break_op_meta);
|
||||
}
|
||||
STACK_ITERATE_END ();
|
||||
@@ -2178,8 +2219,16 @@ rewrite_breaks (void)
|
||||
STACK_DROP (break_targets, 1);
|
||||
STACK_DROP (breaks, STACK_SIZE (breaks) - STACK_TOP (U8));
|
||||
STACK_DROP (U8, 1);
|
||||
}
|
||||
} /* rewrite_breaks */
|
||||
|
||||
/**
|
||||
* Write jump target positions into previously dumped templates of instructions
|
||||
* for currently processed set of 'continue' statements.
|
||||
*
|
||||
* See also:
|
||||
* dump_break_continue_for_rewrite
|
||||
* start_collecting_continues
|
||||
*/
|
||||
void
|
||||
rewrite_continues (void)
|
||||
{
|
||||
@@ -2190,9 +2239,22 @@ rewrite_continues (void)
|
||||
idx_t id1, id2;
|
||||
split_opcode_counter ((opcode_counter_t) (continue_target - continue_oc), &id1, &id2);
|
||||
op_meta continue_op_meta = serializer_get_op_meta (continue_oc);
|
||||
JERRY_ASSERT (continue_op_meta.op.op_idx == OPCODE (jmp_down));
|
||||
continue_op_meta.op.data.jmp_down.opcode_1 = id1;
|
||||
continue_op_meta.op.data.jmp_down.opcode_2 = id2;
|
||||
|
||||
bool is_simple_jump = (continue_op_meta.op.op_idx == OPCODE (jmp_down));
|
||||
|
||||
if (is_simple_jump)
|
||||
{
|
||||
continue_op_meta.op.data.jmp_down.opcode_1 = id1;
|
||||
continue_op_meta.op.data.jmp_down.opcode_2 = id2;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (continue_op_meta.op.op_idx == OPCODE (jmp_break_continue));
|
||||
|
||||
continue_op_meta.op.data.jmp_break_continue.opcode_1 = id1;
|
||||
continue_op_meta.op.data.jmp_break_continue.opcode_2 = id2;
|
||||
}
|
||||
|
||||
serializer_rewrite_op_meta (continue_oc, continue_op_meta);
|
||||
}
|
||||
STACK_ITERATE_END ();
|
||||
@@ -2200,7 +2262,7 @@ rewrite_continues (void)
|
||||
STACK_DROP (continue_targets, 1);
|
||||
STACK_DROP (continues, STACK_SIZE (continues) - STACK_TOP (U8));
|
||||
STACK_DROP (U8, 1);
|
||||
}
|
||||
} /* rewrite_continues */
|
||||
|
||||
void
|
||||
start_dumping_case_clauses (void)
|
||||
|
||||
@@ -183,8 +183,7 @@ void start_collecting_continues (void);
|
||||
void dumper_set_break_target (void);
|
||||
void dumper_set_continue_target (void);
|
||||
void dumper_set_next_interation_target (void);
|
||||
void dump_continue_for_rewrite (void);
|
||||
void dump_break_for_rewrite (void);
|
||||
void dump_break_continue_for_rewrite (bool is_break, bool is_simple_jump);
|
||||
void rewrite_continues (void);
|
||||
void rewrite_breaks (void);
|
||||
void dump_continue_iterations_check (operand);
|
||||
|
||||
@@ -109,15 +109,19 @@ pop_nesting (nesting_t nesting_type) /**< type of current nesting */
|
||||
STACK_DROP (nestings, 1);
|
||||
} /* pop_nesting */
|
||||
|
||||
/**
|
||||
* Check that current nesting chain contains one of the specified 'inside' nesting types,
|
||||
* and there is no 'not_in' nesting between current nesting and the 'inside' nesting type
|
||||
* in the chain.
|
||||
*/
|
||||
static void
|
||||
must_be_inside_but_not_in (uint8_t not_in, uint8_t insides_count, ...)
|
||||
must_be_inside_but_not_in (uint8_t not_in, /**< 'not_in' nesting type */
|
||||
uint8_t insides_count, /**< 'inside' nestings number */
|
||||
...) /**< 'inside' nestings list */
|
||||
{
|
||||
va_list insides_list;
|
||||
if (STACK_SIZE (nestings) == 0)
|
||||
{
|
||||
EMIT_ERROR ("Shall be inside a nesting");
|
||||
}
|
||||
JERRY_ASSERT (STACK_SIZE (nestings) != 0);
|
||||
|
||||
va_list insides_list;
|
||||
va_start (insides_list, insides_count);
|
||||
uint8_t *insides = (uint8_t*) mem_heap_alloc_block (insides_count, MEM_HEAP_ALLOC_SHORT_TERM);
|
||||
for (uint8_t i = 0; i < insides_count; i++)
|
||||
@@ -142,7 +146,7 @@ must_be_inside_but_not_in (uint8_t not_in, uint8_t insides_count, ...)
|
||||
}
|
||||
}
|
||||
EMIT_ERROR ("Shall be inside a nesting");
|
||||
}
|
||||
} /* must_be_inside_but_not_in */
|
||||
|
||||
static bool
|
||||
token_is (token_type tt)
|
||||
@@ -2376,27 +2380,50 @@ parse_statement (void)
|
||||
parse_for_or_for_in_statement ();
|
||||
return;
|
||||
}
|
||||
if (is_keyword (KW_CONTINUE))
|
||||
if (is_keyword (KW_CONTINUE)
|
||||
|| is_keyword (KW_BREAK))
|
||||
{
|
||||
must_be_inside_but_not_in (NESTING_FUNCTION,
|
||||
4,
|
||||
NESTING_ITERATIONAL,
|
||||
NESTING_TRY,
|
||||
NESTING_WITH);
|
||||
bool is_break = is_keyword (KW_BREAK);
|
||||
|
||||
if (STACK_SIZE (nestings) == 0)
|
||||
{
|
||||
EMIT_ERROR ("Shall be inside a nesting");
|
||||
}
|
||||
|
||||
nesting_t topmost_nesting = STACK_ELEMENT (nestings, STACK_SIZE (nestings) - 1);
|
||||
|
||||
if (is_break)
|
||||
{
|
||||
must_be_inside_but_not_in (NESTING_FUNCTION,
|
||||
4,
|
||||
NESTING_ITERATIONAL,
|
||||
NESTING_SWITCH,
|
||||
NESTING_TRY,
|
||||
NESTING_WITH);
|
||||
}
|
||||
else
|
||||
{
|
||||
must_be_inside_but_not_in (NESTING_FUNCTION,
|
||||
3,
|
||||
NESTING_ITERATIONAL,
|
||||
NESTING_TRY,
|
||||
NESTING_WITH);
|
||||
}
|
||||
|
||||
if (topmost_nesting == NESTING_ITERATIONAL
|
||||
|| (topmost_nesting == NESTING_SWITCH && is_break))
|
||||
{
|
||||
dump_break_continue_for_rewrite (is_break, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (topmost_nesting == NESTING_TRY
|
||||
|| topmost_nesting == NESTING_WITH
|
||||
|| (topmost_nesting == NESTING_SWITCH && !is_break));
|
||||
|
||||
dump_break_continue_for_rewrite (is_break, false);
|
||||
}
|
||||
|
||||
must_be_inside_but_not_in (NESTING_FUNCTION, 1, NESTING_ITERATIONAL);
|
||||
dump_continue_for_rewrite ();
|
||||
return;
|
||||
}
|
||||
if (is_keyword (KW_BREAK))
|
||||
{
|
||||
must_be_inside_but_not_in (NESTING_FUNCTION,
|
||||
4,
|
||||
NESTING_ITERATIONAL,
|
||||
NESTING_SWITCH,
|
||||
NESTING_TRY,
|
||||
NESTING_WITH);
|
||||
dump_break_for_rewrite ();
|
||||
return;
|
||||
}
|
||||
if (is_keyword (KW_RETURN))
|
||||
|
||||
Reference in New Issue
Block a user