From 8433df309734eef433624505969ec88380b845c4 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Tue, 2 Jun 2015 17:04:18 +0300 Subject: [PATCH] Introducing interpreter run scopes. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- jerry-core/parser/js/opcodes-dumper.cpp | 53 +++++++++++++++++-- jerry-core/parser/js/opcodes-dumper.h | 3 +- jerry-core/parser/js/parser.cpp | 3 +- .../vm/opcodes-ecma-try-catch-finally.cpp | 11 ++-- jerry-core/vm/opcodes-varg.cpp | 2 +- jerry-core/vm/opcodes.cpp | 28 ++++++---- jerry-core/vm/opcodes.h | 18 ++++++- jerry-core/vm/vm.cpp | 18 ++++--- jerry-core/vm/vm.h | 2 +- 9 files changed, 110 insertions(+), 28 deletions(-) diff --git a/jerry-core/parser/js/opcodes-dumper.cpp b/jerry-core/parser/js/opcodes-dumper.cpp index 6d626583c..e42c8474c 100644 --- a/jerry-core/parser/js/opcodes-dumper.cpp +++ b/jerry-core/parser/js/opcodes-dumper.cpp @@ -2262,18 +2262,61 @@ finish_dumping_case_clauses (void) STACK_DROP (U8, 1); } -void -dump_with (operand op) +/** + * Dump template of 'with' instruction. + * + * Note: + * the instruction's flags field is written later (see also: rewrite_with). + * + * @return position of dumped instruction + */ +opcode_counter_t +dump_with_for_rewrite (operand op) /**< operand - result of evaluating Expression + * in WithStatement */ { - dump_single_address (getop_with, op); -} + opcode_counter_t oc = serializer_get_current_opcode_counter (); + if (op.type == OPERAND_LITERAL) + { + const opcode_t opcode = getop_with (LITERAL_TO_REWRITE, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_100 (opcode, op.data.lit_id)); + } + else + { + JERRY_ASSERT (op.type == OPERAND_TMP); + + const opcode_t opcode = getop_with (op.data.uid, INVALID_VALUE, INVALID_VALUE); + serializer_dump_op_meta (create_op_meta_000 (opcode)); + } + + return oc; +} /* dump_with_for_rewrite */ + +/** + * Write position of 'with' block's end to specified 'with' instruction template, + * dumped earlier (see also: dump_with_for_rewrite). + */ +void +rewrite_with (opcode_counter_t oc) /**< opcode counter of the instruction template */ +{ + op_meta with_op_meta = serializer_get_op_meta (oc); + + idx_t id1, id2; + split_opcode_counter (get_diff_from (oc), &id1, &id2); + with_op_meta.op.data.with.oc_idx_1 = id1; + with_op_meta.op.data.with.oc_idx_2 = id2; + serializer_rewrite_op_meta (oc, with_op_meta); +} /* rewrite_with */ + +/** + * Dump 'meta' instruction of 'end with' type + */ void dump_with_end (void) { const opcode_t opcode = getop_meta (OPCODE_META_TYPE_END_WITH, INVALID_VALUE, INVALID_VALUE); serializer_dump_op_meta (create_op_meta_000 (opcode)); -} +} /* dump_with_end */ void dump_try_for_rewrite (void) diff --git a/jerry-core/parser/js/opcodes-dumper.h b/jerry-core/parser/js/opcodes-dumper.h index 0da07c27e..8a4111dec 100644 --- a/jerry-core/parser/js/opcodes-dumper.h +++ b/jerry-core/parser/js/opcodes-dumper.h @@ -202,7 +202,8 @@ operand dump_delete_res (operand, bool, locus); void dump_typeof (operand, operand); operand dump_typeof_res (operand); -void dump_with (operand); +opcode_counter_t dump_with_for_rewrite (operand); +void rewrite_with (opcode_counter_t); void dump_with_end (void); void dump_try_for_rewrite (void); diff --git a/jerry-core/parser/js/parser.cpp b/jerry-core/parser/js/parser.cpp index 52fbf9c73..91e598c78 100644 --- a/jerry-core/parser/js/parser.cpp +++ b/jerry-core/parser/js/parser.cpp @@ -2022,9 +2022,10 @@ parse_with_statement (void) push_nesting (NESTING_WITH); - dump_with (expr); + opcode_counter_t with_begin_oc = dump_with_for_rewrite (expr); skip_newlines (); parse_statement (); + rewrite_with (with_begin_oc); dump_with_end (); pop_nesting (NESTING_WITH); diff --git a/jerry-core/vm/opcodes-ecma-try-catch-finally.cpp b/jerry-core/vm/opcodes-ecma-try-catch-finally.cpp index 92ac62605..75caf7186 100644 --- a/jerry-core/vm/opcodes-ecma-try-catch-finally.cpp +++ b/jerry-core/vm/opcodes-ecma-try-catch-finally.cpp @@ -37,7 +37,8 @@ opfunc_try_block (opcode_t opdata, /**< operation data */ int_data->pos++; - ecma_completion_value_t try_completion = vm_loop (int_data); + vm_run_scope_t run_scope_try = { int_data->pos, try_end_oc }; + ecma_completion_value_t try_completion = vm_loop (int_data, &run_scope_try); JERRY_ASSERT ((!ecma_is_completion_value_empty (try_completion) && int_data->pos <= try_end_oc) || (ecma_is_completion_value_empty (try_completion) && int_data->pos == try_end_oc)); int_data->pos = try_end_oc; @@ -87,7 +88,9 @@ opfunc_try_block (opcode_t opdata, /**< operation data */ int_data->lex_env_p = catch_env_p; ecma_free_completion_value (try_completion); - try_completion = vm_loop (int_data); + + vm_run_scope_t run_scope_catch = { int_data->pos, catch_end_oc }; + try_completion = vm_loop (int_data, &run_scope_catch); int_data->lex_env_p = old_env_p; @@ -114,7 +117,9 @@ opfunc_try_block (opcode_t opdata, /**< operation data */ read_meta_opcode_counter (OPCODE_META_TYPE_FINALLY, int_data) + int_data->pos); int_data->pos++; - ecma_completion_value_t finally_completion = vm_loop (int_data); + vm_run_scope_t run_scope_finally = { int_data->pos, finally_end_oc }; + ecma_completion_value_t finally_completion = vm_loop (int_data, &run_scope_finally); + JERRY_ASSERT ((!ecma_is_completion_value_empty (finally_completion) && int_data->pos <= finally_end_oc) || (ecma_is_completion_value_empty (finally_completion) && int_data->pos == finally_end_oc)); int_data->pos = finally_end_oc; diff --git a/jerry-core/vm/opcodes-varg.cpp b/jerry-core/vm/opcodes-varg.cpp index a07022477..85c209f64 100644 --- a/jerry-core/vm/opcodes-varg.cpp +++ b/jerry-core/vm/opcodes-varg.cpp @@ -40,7 +40,7 @@ fill_varg_list (int_data_t *int_data, /**< interpreter context */ arg_index < args_number; arg_index++) { - ecma_completion_value_t evaluate_arg_completion = vm_loop (int_data); + ecma_completion_value_t evaluate_arg_completion = vm_loop (int_data, NULL); if (ecma_is_completion_value_normal (evaluate_arg_completion)) { diff --git a/jerry-core/vm/opcodes.cpp b/jerry-core/vm/opcodes.cpp index 3b8446fd5..d123f6ed5 100644 --- a/jerry-core/vm/opcodes.cpp +++ b/jerry-core/vm/opcodes.cpp @@ -912,7 +912,7 @@ opfunc_obj_decl (opcode_t opdata, /**< operation data */ prop_index < args_number; prop_index++) { - ecma_completion_value_t evaluate_prop_completion = vm_loop (int_data); + ecma_completion_value_t evaluate_prop_completion = vm_loop (int_data, NULL); if (ecma_is_completion_value_normal (evaluate_prop_completion)) { @@ -1299,6 +1299,10 @@ opfunc_with (opcode_t opdata, /**< operation data */ int_data_t *int_data) /**< interpreter context */ { const idx_t expr_var_idx = opdata.data.with.expr; + const idx_t block_end_oc_idx_1 = opdata.data.with.oc_idx_1; + const idx_t block_end_oc_idx_2 = opdata.data.with.oc_idx_2; + const opcode_counter_t with_end_oc = (opcode_counter_t) ( + calc_opcode_counter_from_idx_idx (block_end_oc_idx_1, block_end_oc_idx_2) + int_data->pos); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); @@ -1321,15 +1325,19 @@ opfunc_with (opcode_t opdata, /**< operation data */ true); int_data->lex_env_p = new_env_p; - ecma_completion_value_t evaluation_completion = vm_loop (int_data); +#ifndef JERRY_NDEBUG + opcode_t meta_opcode = vm_get_opcode (with_end_oc); + JERRY_ASSERT (meta_opcode.op_idx == __op__idx_meta); + JERRY_ASSERT (meta_opcode.data.meta.type == OPCODE_META_TYPE_END_WITH); +#endif /* !JERRY_NDEBUG */ - if (ecma_is_completion_value_normal (evaluation_completion)) + 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)) { - JERRY_ASSERT (ecma_is_completion_value_empty (evaluation_completion)); - - opcode_t meta_opcode = vm_get_opcode (int_data->pos); - JERRY_ASSERT (meta_opcode.op_idx == __op__idx_meta); - JERRY_ASSERT (meta_opcode.data.meta.type == OPCODE_META_TYPE_END_WITH); + JERRY_ASSERT (ecma_is_completion_value_empty (with_completion)); + JERRY_ASSERT (int_data->pos == with_end_oc); int_data->pos++; @@ -1337,7 +1345,9 @@ opfunc_with (opcode_t opdata, /**< operation data */ } else { - ret_value = evaluation_completion; + JERRY_ASSERT (int_data->pos <= with_end_oc); + + ret_value = with_completion; } int_data->lex_env_p = old_env_p; diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 7996ebd21..2ab1866a6 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -113,6 +113,22 @@ typedef struct #endif /* MEM_STATS */ } int_data_t; +/** + * Description of a run scope + * + * Note: + * Run scope represents boundaries of byte-code block to run. + * + * Jumps within of the current run scope are performed by just changing opcode counter, + * and outside of the run scope - by returning corresponding ECMA_COMPLETION_TYPE_BREAK_CONTINUE + * completion value. + */ +typedef struct +{ + const opcode_counter_t start_oc; /**< opcode counter of the first instruction of the scope */ + const opcode_counter_t end_oc; /**< opcode counter of the last instruction of the scope */ +} vm_run_scope_t; + opcode_counter_t calc_opcode_counter_from_idx_idx (const idx_t oc_idx_1, const idx_t oc_idx_2); opcode_counter_t read_meta_opcode_counter (opcode_meta_type expected_type, int_data_t *int_data); @@ -135,7 +151,7 @@ opcode_counter_t read_meta_opcode_counter (opcode_meta_type expected_type, int_d p##_2 (a, delete_var, lhs, name) \ p##_3 (a, delete_prop, lhs, base, name) \ p##_2 (a, typeof, lhs, obj) \ - p##_1 (a, with, expr) \ + p##_3 (a, with, expr, oc_idx_1, oc_idx_2) \ p##_2 (a, try_block, oc_idx_1, oc_idx_2) \ p##_1 (a, throw_value, var) diff --git a/jerry-core/vm/vm.cpp b/jerry-core/vm/vm.cpp index 834b178b7..11ec30f35 100644 --- a/jerry-core/vm/vm.cpp +++ b/jerry-core/vm/vm.cpp @@ -423,7 +423,9 @@ vm_run_global (void) * Otherwise - the completion value is discarded and normal empty completion value is returned. */ ecma_completion_value_t -vm_loop (int_data_t *int_data) /**< interpreter context */ +vm_loop (int_data_t *int_data_p, /**< interpreter context */ + vm_run_scope_t *run_scope_p) /**< current run scope, + * or NULL - if there is no active run scope */ { ecma_completion_value_t completion; @@ -439,24 +441,28 @@ vm_loop (int_data_t *int_data) /**< interpreter context */ { do { - const opcode_t *curr = &__program[int_data->pos]; + JERRY_ASSERT (run_scope_p == NULL + || (run_scope_p->start_oc <= int_data_p->pos + && int_data_p->pos <= run_scope_p->end_oc)); + + const opcode_t *curr = &__program[int_data_p->pos]; #ifdef MEM_STATS - const opcode_counter_t opcode_pos = int_data->pos; + const opcode_counter_t opcode_pos = int_data_p->pos; interp_mem_stats_opcode_enter (opcode_pos, &heap_stats_before, &pools_stats_before); #endif /* MEM_STATS */ - completion = __opfuncs[curr->op_idx] (*curr, int_data); + completion = __opfuncs[curr->op_idx] (*curr, int_data_p); #ifdef CONFIG_VM_RUN_GC_AFTER_EACH_OPCODE ecma_gc_run (); #endif /* CONFIG_VM_RUN_GC_AFTER_EACH_OPCODE */ #ifdef MEM_STATS - interp_mem_stats_opcode_exit (int_data, + interp_mem_stats_opcode_exit (int_data_p, opcode_pos, &heap_stats_before, &pools_stats_before); @@ -525,7 +531,7 @@ vm_run_from_pos (opcode_counter_t start_pos, /**< identifier of starting opcode interp_mem_stats_context_enter (&int_data, start_pos); #endif /* MEM_STATS */ - completion = vm_loop (&int_data); + completion = vm_loop (&int_data, NULL); JERRY_ASSERT (ecma_is_completion_value_normal (completion) || ecma_is_completion_value_throw (completion) diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index d584c7f2a..37b7e90b7 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -22,7 +22,7 @@ extern void vm_init (const opcode_t* program_p, bool dump_mem_stats); extern jerry_completion_code_t vm_run_global (void); -extern ecma_completion_value_t vm_loop (int_data_t *int_data); +extern ecma_completion_value_t vm_loop (int_data_t *int_data, vm_run_scope_t *run_scope_p); extern ecma_completion_value_t vm_run_from_pos (opcode_counter_t start_pos, ecma_value_t this_binding_value, ecma_object_t *lex_env_p,