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:
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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
@@ -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');
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user