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:
Ruben Ayrapetyan
2015-06-02 17:06:43 +03:00
parent 8433df3097
commit ac87616f05
13 changed files with 440 additions and 146 deletions
+26 -13
View File
@@ -99,11 +99,26 @@ typedef enum
*/
typedef enum
{
ECMA_COMPLETION_TYPE_NORMAL, /**< default block completion */
ECMA_COMPLETION_TYPE_RETURN, /**< block completed with return */
ECMA_COMPLETION_TYPE_BREAK, /**< block completed with break */
ECMA_COMPLETION_TYPE_CONTINUE, /**< block completed with continue */
ECMA_COMPLETION_TYPE_THROW, /**< block completed with throw */
ECMA_COMPLETION_TYPE_NORMAL, /**< default completion */
ECMA_COMPLETION_TYPE_RETURN, /**< completion with return */
ECMA_COMPLETION_TYPE_JUMP, /**< implementation-defined completion type
* for jump statements (break, continue)
* that require completion of one or several
* statements, before performing related jump.
*
* For example, 'break' in the following code
* requires to return from opfunc_with handler
* before performing jump to the loop end:
*
* for (var i = 0; i < 10; i++)
* {
* with (obj)
* {
* break;
* }
* }
*/
ECMA_COMPLETION_TYPE_THROW, /**< completion with throw */
ECMA_COMPLETION_TYPE_EXIT, /**< implementation-defined completion type
for finishing script execution */
ECMA_COMPLETION_TYPE_META /**< implementation-defined completion type
@@ -142,7 +157,7 @@ typedef uint32_t ecma_value_t;
*
* value (16)
* Bit-field structure: type (8) | padding (8) <
* label_desc_cp (16)
* break / continue target
*/
typedef uint32_t ecma_completion_value_t;
@@ -155,12 +170,10 @@ typedef uint32_t ecma_completion_value_t;
#define ECMA_COMPLETION_VALUE_VALUE_WIDTH (ECMA_VALUE_SIZE)
/**
* Label
*
* Used for break and continue completion types.
* Break / continue jump target
*/
#define ECMA_COMPLETION_VALUE_LABEL_DESC_CP_POS (0)
#define ECMA_COMPLETION_VALUE_LABEL_DESC_CP_WIDTH (ECMA_POINTER_FIELD_WIDTH)
#define ECMA_COMPLETION_VALUE_TARGET_POS (0)
#define ECMA_COMPLETION_VALUE_TARGET_WIDTH ((uint32_t) sizeof (opcode_counter_t) * JERRY_BITSINBYTE)
/**
* Type (ecma_completion_type_t)
@@ -168,8 +181,8 @@ typedef uint32_t ecma_completion_value_t;
#define ECMA_COMPLETION_VALUE_TYPE_POS (JERRY_MAX (JERRY_ALIGNUP (ECMA_COMPLETION_VALUE_VALUE_POS + \
ECMA_COMPLETION_VALUE_VALUE_WIDTH, \
JERRY_BITSINBYTE), \
JERRY_ALIGNUP (ECMA_COMPLETION_VALUE_LABEL_DESC_CP_POS + \
ECMA_COMPLETION_VALUE_LABEL_DESC_CP_WIDTH, \
JERRY_ALIGNUP (ECMA_COMPLETION_VALUE_TARGET_POS + \
ECMA_COMPLETION_VALUE_TARGET_WIDTH, \
JERRY_BITSINBYTE)))
#define ECMA_COMPLETION_VALUE_TYPE_WIDTH (8)
+55 -69
View File
@@ -462,18 +462,17 @@ ecma_get_completion_value_value_field (ecma_completion_value_t completion_value)
} /* ecma_get_completion_value_value_field */
/**
* Get pointer to label descriptor from completion value
* Get target of break / continue completion value
*
* @return pointer to label descriptor
* @return opcode counter
*/
static ecma_label_descriptor_t* __attr_const___
ecma_get_completion_value_label_descriptor (ecma_completion_value_t completion_value) /**< completion value */
static opcode_counter_t
ecma_get_completion_value_target (ecma_completion_value_t completion_value) /**< completion value */
{
return ECMA_GET_NON_NULL_POINTER (ecma_label_descriptor_t,
(uintptr_t) jrt_extract_bit_field (completion_value,
ECMA_COMPLETION_VALUE_LABEL_DESC_CP_POS,
ECMA_COMPLETION_VALUE_LABEL_DESC_CP_WIDTH));
} /* ecma_get_completion_value_label_descriptor */
return (opcode_counter_t) jrt_extract_bit_field (completion_value,
ECMA_COMPLETION_VALUE_TARGET_POS,
ECMA_COMPLETION_VALUE_TARGET_WIDTH);
} /* ecma_get_completion_value_target */
/**
* Set type field of completion value
@@ -508,24 +507,20 @@ ecma_set_completion_value_value_field (ecma_completion_value_t completion_value,
} /* ecma_set_completion_value_value_field */
/**
* Set label descriptor of completion value
* Set target of break / continue completion value
*
* @return completion value with updated field
*/
static ecma_completion_value_t __attr_const___
ecma_set_completion_value_label_descriptor (ecma_completion_value_t completion_value, /**< completion value
* to set field in */
ecma_label_descriptor_t* label_desc_p) /**< pointer to the
* label descriptor */
ecma_set_completion_value_target (ecma_completion_value_t completion_value, /**< completion value
* to set field in */
opcode_counter_t target) /**< break / continue target */
{
uintptr_t label_desc_cp;
ECMA_SET_NON_NULL_POINTER (label_desc_cp, label_desc_p);
return (ecma_completion_value_t) jrt_set_bit_field_value (completion_value,
label_desc_cp,
ECMA_COMPLETION_VALUE_LABEL_DESC_CP_POS,
ECMA_COMPLETION_VALUE_LABEL_DESC_CP_WIDTH);
} /* ecma_set_completion_value_label_descriptor */
target,
ECMA_COMPLETION_VALUE_TARGET_POS,
ECMA_COMPLETION_VALUE_TARGET_WIDTH);
} /* ecma_set_completion_value_target */
/**
* Normal, throw, return, exit and meta completion values constructor
@@ -555,34 +550,6 @@ ecma_make_completion_value (ecma_completion_type_t type, /**< type */
return completion_value;
} /* ecma_make_completion_value */
/**
* Break and continue completion values constructor
*
* @return completion value
*/
ecma_completion_value_t __attr_const___
ecma_make_label_completion_value (ecma_completion_type_t type, /**< type */
uint8_t depth_level, /**< depth level (in try constructions,
with blocks, etc.) */
uint16_t offset) /**< offset to label from end of last block */
{
JERRY_ASSERT (type == ECMA_COMPLETION_TYPE_BREAK
|| type == ECMA_COMPLETION_TYPE_CONTINUE);
ecma_label_descriptor_t *label_desc_p = ecma_alloc_label_descriptor ();
label_desc_p->offset = offset;
label_desc_p->depth = depth_level;
ecma_completion_value_t completion_value = 0;
completion_value = ecma_set_completion_value_type_field (completion_value,
type);
completion_value = ecma_set_completion_value_label_descriptor (completion_value,
label_desc_p);
return completion_value;
} /* ecma_make_label_completion_value */
/**
* Simple normal completion value constructor
*
@@ -688,6 +655,24 @@ ecma_make_meta_completion_value (void)
ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY));
} /* ecma_make_meta_completion_value */
/**
* Break / continue completion values constructor
*
* @return completion value
*/
ecma_completion_value_t __attr_const___
ecma_make_jump_completion_value (opcode_counter_t target) /**< target break / continue */
{
ecma_completion_value_t completion_value = 0;
completion_value = ecma_set_completion_value_type_field (completion_value,
ECMA_COMPLETION_TYPE_JUMP);
completion_value = ecma_set_completion_value_target (completion_value,
target);
return completion_value;
} /* ecma_make_jump_completion_value */
/**
* Get ecma-value from specified completion value
*
@@ -741,6 +726,20 @@ ecma_get_object_from_completion_value (ecma_completion_value_t completion_value)
return ecma_get_object_from_value (ecma_get_completion_value_value (completion_value));
} /* ecma_get_object_from_completion_value */
/**
* Get break / continue target from completion value
*
* @return opcode counter
*/
opcode_counter_t
ecma_get_jump_target_from_completion_value (ecma_completion_value_t completion_value) /**< completion
* value */
{
JERRY_ASSERT (ecma_get_completion_value_type_field (completion_value) == ECMA_COMPLETION_TYPE_JUMP);
return ecma_get_completion_value_target (completion_value);
} /* ecma_get_jump_target_from_completion_value */
/**
* Copy ecma-completion value.
*
@@ -753,6 +752,7 @@ ecma_copy_completion_value (ecma_completion_value_t value) /**< completion value
const bool is_type_ok = (type == ECMA_COMPLETION_TYPE_NORMAL
|| type == ECMA_COMPLETION_TYPE_THROW
|| type == ECMA_COMPLETION_TYPE_RETURN
|| type == ECMA_COMPLETION_TYPE_JUMP
|| type == ECMA_COMPLETION_TYPE_EXIT);
JERRY_ASSERT (is_type_ok);
@@ -784,10 +784,8 @@ ecma_free_completion_value (ecma_completion_value_t completion_value) /**< compl
JERRY_ASSERT (ecma_get_value_type_field (v) == ECMA_TYPE_SIMPLE);
break;
}
case ECMA_COMPLETION_TYPE_CONTINUE:
case ECMA_COMPLETION_TYPE_BREAK:
case ECMA_COMPLETION_TYPE_JUMP:
{
ecma_dealloc_label_descriptor (ecma_get_completion_value_label_descriptor (completion_value));
break;
}
case ECMA_COMPLETION_TYPE_META:
@@ -876,28 +874,16 @@ ecma_is_completion_value_meta (ecma_completion_value_t value) /**< completion va
} /* ecma_is_completion_value_meta */
/**
* Check if the completion value is break value.
* Check if the completion value is break / continue value.
*
* @return true - if the completion type is break,
* @return true - if the completion type is break / continue,
* false - otherwise.
*/
bool __attr_const___ __attr_always_inline___
ecma_is_completion_value_break (ecma_completion_value_t value) /**< completion value */
ecma_is_completion_value_jump (ecma_completion_value_t value) /**< completion value */
{
return (ecma_get_completion_value_type_field (value) == ECMA_COMPLETION_TYPE_BREAK);
} /* ecma_is_completion_value_break */
/**
* Check if the completion value is continue value.
*
* @return true - if the completion type is continue,
* false - otherwise.
*/
bool __attr_const___ __attr_always_inline___
ecma_is_completion_value_continue (ecma_completion_value_t value) /**< completion value */
{
return (ecma_get_completion_value_type_field (value) == ECMA_COMPLETION_TYPE_CONTINUE);
} /* ecma_is_completion_value_continue */
return (ecma_get_completion_value_type_field (value) == ECMA_COMPLETION_TYPE_JUMP);
} /* ecma_is_completion_value_jump */
/**
* Check if the completion value is specified normal simple value.
+5 -5
View File
@@ -25,6 +25,7 @@
#include "ecma-globals.h"
#include "mem-allocator.h"
#include "opcodes.h"
/**
* Get value of pointer from specified non-null compressed pointer.
@@ -74,9 +75,6 @@ extern void ecma_free_value (ecma_value_t value, bool do_deref_if_object);
extern ecma_completion_value_t ecma_make_completion_value (ecma_completion_type_t type,
ecma_value_t value);
extern ecma_completion_value_t ecma_make_label_completion_value (ecma_completion_type_t type,
uint8_t depth_level,
uint16_t offset);
extern ecma_completion_value_t ecma_make_simple_completion_value (ecma_simple_value_t simple_value);
extern ecma_completion_value_t ecma_make_normal_completion_value (ecma_value_t value);
extern ecma_completion_value_t ecma_make_throw_completion_value (ecma_value_t value);
@@ -85,6 +83,7 @@ extern ecma_completion_value_t ecma_make_empty_completion_value (void);
extern ecma_completion_value_t ecma_make_return_completion_value (ecma_value_t value);
extern ecma_completion_value_t ecma_make_exit_completion_value (bool is_successful);
extern ecma_completion_value_t ecma_make_meta_completion_value (void);
extern ecma_completion_value_t ecma_make_jump_completion_value (opcode_counter_t target);
extern ecma_value_t ecma_get_completion_value_value (ecma_completion_value_t completion_value);
extern ecma_number_t* __attr_const___
ecma_get_number_from_completion_value (ecma_completion_value_t completion_value);
@@ -92,6 +91,8 @@ extern ecma_string_t* __attr_const___
ecma_get_string_from_completion_value (ecma_completion_value_t completion_value);
extern ecma_object_t* __attr_const___
ecma_get_object_from_completion_value (ecma_completion_value_t completion_value);
extern opcode_counter_t
ecma_get_jump_target_from_completion_value (ecma_completion_value_t completion_value);
extern ecma_completion_value_t ecma_copy_completion_value (ecma_completion_value_t value);
extern void ecma_free_completion_value (ecma_completion_value_t completion_value);
@@ -100,8 +101,7 @@ extern bool ecma_is_completion_value_throw (ecma_completion_value_t value);
extern bool ecma_is_completion_value_return (ecma_completion_value_t value);
extern bool ecma_is_completion_value_exit (ecma_completion_value_t value);
extern bool ecma_is_completion_value_meta (ecma_completion_value_t value);
extern bool ecma_is_completion_value_break (ecma_completion_value_t value);
extern bool ecma_is_completion_value_continue (ecma_completion_value_t value);
extern bool ecma_is_completion_value_jump (ecma_completion_value_t value);
extern bool ecma_is_completion_value_normal_simple_value (ecma_completion_value_t value,
ecma_simple_value_t simple_value);
extern bool ecma_is_completion_value_normal_true (ecma_completion_value_t value);
+82 -20
View File
@@ -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)
+1 -2
View File
@@ -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);
+53 -26
View File
@@ -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))
+17
View File
@@ -198,3 +198,20 @@ opfunc_jmp_up (opcode_t opdata, /**< operation data */
return ecma_make_empty_completion_value ();
}
/**
* 'Break or continue jump' opcode handler.
*
* Note:
* the opcode returns break-continue completion value with jump target
*/
ecma_completion_value_t
opfunc_jmp_break_continue (opcode_t opdata, /**< operation data */
int_data_t *int_data) /**< interpreter context */
{
opcode_counter_t target = int_data->pos;
target = (opcode_counter_t) (target + calc_opcode_counter_from_idx_idx (opdata.data.jmp_down.opcode_1,
opdata.data.jmp_down.opcode_2));
return ecma_make_jump_completion_value (target);
} /* opfunc_jmp_break_continue */
+4 -6
View File
@@ -1334,22 +1334,20 @@ opfunc_with (opcode_t opdata, /**< operation data */
vm_run_scope_t run_scope_with = { int_data->pos, with_end_oc };
ecma_completion_value_t with_completion = vm_loop (int_data, &run_scope_with);
if (ecma_is_completion_value_normal (with_completion))
if (ecma_is_completion_value_empty (with_completion))
{
JERRY_ASSERT (ecma_is_completion_value_empty (with_completion));
JERRY_ASSERT (int_data->pos == with_end_oc);
int_data->pos++;
ret_value = ecma_make_empty_completion_value ();
}
else
{
JERRY_ASSERT (!ecma_is_completion_value_normal (with_completion));
JERRY_ASSERT (int_data->pos <= with_end_oc);
ret_value = with_completion;
}
ret_value = with_completion;
int_data->lex_env_p = old_env_p;
ecma_deref_object (new_env_p);
+2 -1
View File
@@ -206,7 +206,8 @@ opcode_counter_t read_meta_opcode_counter (opcode_meta_type expected_type, int_d
p##_3 (a, is_true_jmp_up, value, opcode_1, opcode_2) \
p##_3 (a, is_true_jmp_down, value, opcode_1, opcode_2) \
p##_3 (a, is_false_jmp_up, value, opcode_1, opcode_2) \
p##_3 (a, is_false_jmp_down, value, opcode_1, opcode_2)
p##_3 (a, is_false_jmp_down, value, opcode_1, opcode_2) \
p##_2 (a, jmp_break_continue, opcode_1, opcode_2)
#define OP_LIST_FULL(p, a) \
OP_CALLS_AND_ARGS (p, a) \
+1
View File
@@ -288,6 +288,7 @@ pp_op_meta (opcode_counter_t oc, op_meta opm, bool rewrite)
case NAME_TO_ID (is_false_jmp_down): printf ("if (%s == false) goto %d;", VAR (1), oc + OC (2, 3)); break;
case NAME_TO_ID (jmp_up): printf ("goto %d;", oc - OC (1, 2)); break;
case NAME_TO_ID (jmp_down): printf ("goto %d;", oc + OC (1, 2)); break;
case NAME_TO_ID (jmp_break_continue): printf ("goto_nested %d;", oc + OC (1, 2)); break;
case NAME_TO_ID (try_block): printf ("try (end: %d);", oc + OC (1, 2)); break;
case NAME_TO_ID (assignment):
{
+15 -4
View File
@@ -473,12 +473,23 @@ vm_loop (int_data_t *int_data_p, /**< interpreter context */
}
while (ecma_is_completion_value_normal (completion));
if (ecma_is_completion_value_break (completion)
|| ecma_is_completion_value_continue (completion))
if (ecma_is_completion_value_jump (completion))
{
JERRY_UNIMPLEMENTED ("break and continue on labels are not supported.");
opcode_counter_t target = ecma_get_jump_target_from_completion_value (completion);
continue;
/*
* TODO:
* Implement instantiation of run scopes for global scope, functions and eval scope.
* Currently, correctness of jumps without run scope set is guaranteed through byte-code semantics.
*/
if (run_scope_p == NULL /* if no run scope set */
|| (target >= run_scope_p->start_oc /* or target is within the current run scope */
&& target < run_scope_p->end_oc))
{
int_data_p->pos = target;
continue;
}
}
if (ecma_is_completion_value_meta (completion))
@@ -0,0 +1,158 @@
// Copyright 2015 Samsung Electronics Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/* with */
for (var i = 0; i < 10; i++)
{
with ({})
{
break;
assert (false);
}
}
assert (i === 0);
for (var i = 0; i < 10; i++)
{
with ({})
{
continue;
assert (false);
}
}
assert (i === 10);
/* try */
for (var i = 0; i < 10; i++)
{
try
{
break;
assert (false);
}
catch (e)
{
}
}
assert (i === 0);
for (var i = 0; i < 10; i++)
{
try
{
continue;
assert (false);
}
catch (e)
{
}
}
assert (i === 10);
/* catch */
for (var i = 0; i < 10; i++)
{
try
{
throw new TypeError ();
assert (false);
}
catch (e)
{
break;
assert (false);
}
}
assert (i === 0);
for (var i = 0; i < 10; i++)
{
try
{
throw new TypeError ();
assert (false);
}
catch (e)
{
continue;
assert (false);
}
}
assert (i === 10);
/* finally */
for (var i = 0; i < 10; i++)
{
try
{
throw new TypeError ();
assert (false);
}
catch (e)
{
}
finally
{
break;
assert (false);
}
}
assert (i === 0);
for (var i = 0; i < 10; i++)
{
try
{
throw new TypeError ();
assert (false);
}
catch (e)
{
}
finally
{
continue;
assert (false);
}
}
assert (i === 10);
/* with - switch */
str = '';
for (var i = 0; i < 10; i++)
{
with ({})
{
switch (i)
{
case 0:
str += 'A';
break;
default:
str += 'B';
continue;
}
str += 'C';
}
}
assert (str === 'ACBBBBBBBBB');
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2015 Samsung Electronics Co., Ltd.
// Copyright 2015 University of Szeged.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
do {
try {
} finally {
break;
}
} while (false);