diff --git a/src/libcoreint/interpreter.c b/src/libcoreint/interpreter.c index ea3574d04..84e52cdf0 100644 --- a/src/libcoreint/interpreter.c +++ b/src/libcoreint/interpreter.c @@ -130,6 +130,12 @@ run_int_loop (int_data_t *int_data) continue; } + if (completion.type == ECMA_COMPLETION_TYPE_META) + { + completion.type = ECMA_COMPLETION_TYPE_NORMAL; + JERRY_ASSERT (ecma_is_completion_value_normal (completion)); + } + return completion; } } diff --git a/src/libcoreint/opcodes-ecma-try-catch-finally.c b/src/libcoreint/opcodes-ecma-try-catch-finally.c new file mode 100644 index 000000000..9ded87bf6 --- /dev/null +++ b/src/libcoreint/opcodes-ecma-try-catch-finally.c @@ -0,0 +1,128 @@ +/* Copyright 2014 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. + */ + +#include "globals.h" +#include "interpreter.h" +#include "opcodes.h" +#include "opcodes-ecma-support.h" + +/** + * 'Try' opcode handler. + * + * See also: ECMA-262 v5, 12.14 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +ecma_completion_value_t +opfunc_try (opcode_t opdata, /**< operation data */ + int_data_t *int_data) /**< interpreter context */ +{ + const idx_t block_end_oc_idx_1 = opdata.data.try.oc_idx_1; + const idx_t block_end_oc_idx_2 = opdata.data.try.oc_idx_2; + const opcode_counter_t try_end_oc = calc_opcode_counter_from_idx_idx (block_end_oc_idx_1, + block_end_oc_idx_2); + + int_data->pos++; + + ecma_completion_value_t try_completion = run_int_loop (int_data); + JERRY_ASSERT ((!ecma_is_empty_completion_value (try_completion) && int_data->pos < try_end_oc) + || (ecma_is_empty_completion_value (try_completion) && int_data->pos == try_end_oc)); + int_data->pos = try_end_oc; + + opcode_t next_opcode = read_opcode (int_data->pos); + JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); + + if (try_completion.type == ECMA_COMPLETION_TYPE_EXIT) + { + return try_completion; + } + + if (next_opcode.data.meta.type == OPCODE_META_TYPE_CATCH) + { + const opcode_counter_t catch_end_oc = read_meta_opcode_counter (OPCODE_META_TYPE_CATCH, + int_data); + int_data->pos++; + + if (ecma_is_completion_value_throw (try_completion)) + { + next_opcode = read_opcode (int_data->pos++); + JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); + JERRY_ASSERT (next_opcode.data.meta.type == OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER); + + const idx_t catch_exc_val_var_name_lit_idx = next_opcode.data.meta.data_1; + ecma_string_t *catch_exc_var_name_str_p = ecma_new_ecma_string_from_lit_index (catch_exc_val_var_name_lit_idx); + + ecma_object_t *old_env_p = int_data->lex_env_p; + ecma_object_t *catch_env_p = ecma_create_decl_lex_env (old_env_p); + ecma_completion_value_t completion = ecma_op_create_mutable_binding (catch_env_p, + catch_exc_var_name_str_p, + false); + JERRY_ASSERT (ecma_is_empty_completion_value (completion)); + completion = ecma_op_set_mutable_binding (catch_env_p, + catch_exc_var_name_str_p, + try_completion.value, + false); + JERRY_ASSERT (ecma_is_empty_completion_value (completion)); + + ecma_deref_ecma_string (catch_exc_var_name_str_p); + + int_data->lex_env_p = catch_env_p; + + ecma_free_completion_value (try_completion); + try_completion = run_int_loop (int_data); + + int_data->lex_env_p = old_env_p; + + ecma_deref_object (catch_env_p); + } + + JERRY_ASSERT ((!ecma_is_empty_completion_value (try_completion) && int_data->pos < catch_end_oc) + || (ecma_is_empty_completion_value (try_completion) && int_data->pos == catch_end_oc)); + int_data->pos = catch_end_oc; + } + + next_opcode = read_opcode (int_data->pos); + JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); + + if (try_completion.type == ECMA_COMPLETION_TYPE_EXIT) + { + return try_completion; + } + + if (next_opcode.data.meta.type == OPCODE_META_TYPE_FINALLY) + { + const opcode_counter_t finally_end_oc = read_meta_opcode_counter (OPCODE_META_TYPE_FINALLY, + int_data); + int_data->pos++; + + ecma_completion_value_t finally_completion = run_int_loop (int_data); + JERRY_ASSERT ((!ecma_is_empty_completion_value (finally_completion) && int_data->pos < finally_end_oc) + || (ecma_is_empty_completion_value (finally_completion) && int_data->pos == finally_end_oc)); + int_data->pos = finally_end_oc; + + if (!ecma_is_empty_completion_value (finally_completion)) + { + ecma_free_completion_value (try_completion); + try_completion = finally_completion; + } + } + + next_opcode = read_opcode (int_data->pos++); + JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); + JERRY_ASSERT (next_opcode.data.meta.type == OPCODE_META_TYPE_END_TRY_CATCH_FINALLY); + + return try_completion; +} /* opfunc_try */ diff --git a/src/libcoreint/opcodes.c b/src/libcoreint/opcodes.c index 256d3d387..372eef2f9 100644 --- a/src/libcoreint/opcodes.c +++ b/src/libcoreint/opcodes.c @@ -17,8 +17,6 @@ #include "globals.h" #include "interpreter.h" -#include "jerry-libc.h" -#include "mem-heap.h" #include "opcodes.h" /** @@ -1456,6 +1454,39 @@ opfunc_with (opcode_t opdata, /**< operation data */ return ret_value; } /* opfunc_with */ +/** + * 'Throw' opcode handler. + * + * See also: ECMA-262 v5, 12.13 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +ecma_completion_value_t +opfunc_throw (opcode_t opdata, /**< operation data */ + int_data_t *int_data) /**< interpreter context */ +{ + const idx_t var_idx = opdata.data.throw.var; + + int_data->pos++; + + ecma_completion_value_t ret_value; + + ECMA_TRY_CATCH (var_value, + get_variable_value (int_data, + var_idx, + false), + ret_value); + + return ecma_make_completion_value (ECMA_COMPLETION_TYPE_THROW, + ecma_copy_value (var_value.value, true), + ECMA_TARGET_ID_RESERVED); + + ECMA_FINALIZE (var_value); + + return ret_value; +} /* opfunc_throw */ + /** * Evaluate argument of typeof. * @@ -1737,6 +1768,9 @@ opfunc_meta (opcode_t opdata, /**< operation data */ { case OPCODE_META_TYPE_VARG: case OPCODE_META_TYPE_END_WITH: + case OPCODE_META_TYPE_CATCH: + case OPCODE_META_TYPE_FINALLY: + case OPCODE_META_TYPE_END_TRY_CATCH_FINALLY: { return ecma_make_completion_value (ECMA_COMPLETION_TYPE_META, ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY), @@ -1748,6 +1782,7 @@ opfunc_meta (opcode_t opdata, /**< operation data */ case OPCODE_META_TYPE_VARG_PROP_GETTER: case OPCODE_META_TYPE_VARG_PROP_SETTER: case OPCODE_META_TYPE_FUNCTION_END: + case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER: { JERRY_UNREACHABLE (); } @@ -1762,14 +1797,14 @@ opfunc_meta (opcode_t opdata, /**< operation data */ * @return opcode counter */ opcode_counter_t -calc_meta_opcode_counter_from_meta_data (const idx_t data_1, /**< first data argument */ - const idx_t data_2) /**< second data argument */ +calc_opcode_counter_from_idx_idx (const idx_t oc_idx_1, /**< first idx */ + const idx_t oc_idx_2) /**< second idx */ { opcode_counter_t counter; - counter = data_1; - counter = (opcode_counter_t) (counter << (sizeof (data_2) * JERRY_BITSINBYTE)); - counter = (opcode_counter_t) (counter | data_2); + counter = oc_idx_1; + counter = (opcode_counter_t) (counter << (sizeof (idx_t) * JERRY_BITSINBYTE)); + counter = (opcode_counter_t) (counter | oc_idx_2); return counter; } /* calc_meta_opcode_counter_from_meta_data */ @@ -1788,7 +1823,7 @@ read_meta_opcode_counter (opcode_meta_type expected_type, /**< expected type of const idx_t data_1 = meta_opcode.data.meta.data_1; const idx_t data_2 = meta_opcode.data.meta.data_2; - return calc_meta_opcode_counter_from_meta_data (data_1, data_2); + return calc_opcode_counter_from_idx_idx (data_1, data_2); } /* read_meta_opcode_counter */ #define GETOP_DEF_1(a, name, field1) \ diff --git a/src/libcoreint/opcodes.h b/src/libcoreint/opcodes.h index d74175fd9..51343a7f8 100644 --- a/src/libcoreint/opcodes.h +++ b/src/libcoreint/opcodes.h @@ -59,7 +59,11 @@ typedef enum OPCODE_META_TYPE_VARG_PROP_GETTER, /**< name (lit_idx) and getter (var_idx) for an accessor property descriptor */ OPCODE_META_TYPE_VARG_PROP_SETTER, /**< name (lit_idx) and setter (var_idx) for an accessor property descriptor */ OPCODE_META_TYPE_END_WITH, /**< end of with statement */ - OPCODE_META_TYPE_FUNCTION_END /**< opcode counter */ + OPCODE_META_TYPE_FUNCTION_END, /**< opcode counter */ + OPCODE_META_TYPE_CATCH, /**< mark of beginning of catch block containing pointer to end of catch block */ + OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER, /**< literal index containing name of variable with exception object */ + OPCODE_META_TYPE_FINALLY, /**< mark of beginning of finally block containing pointer to end of finally block */ + OPCODE_META_TYPE_END_TRY_CATCH_FINALLY /**< mark of end of try-catch, try-finally, try-catch-finally blocks */ } opcode_meta_type; typedef struct @@ -74,7 +78,7 @@ typedef struct ecma_value_t *regs_p; /**< register variables */ } int_data_t; -opcode_counter_t calc_meta_opcode_counter_from_meta_data (const idx_t data_1, const idx_t data_2); +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); #define OP_CALLS_AND_ARGS(p, a) \ @@ -101,7 +105,9 @@ 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##_1 (a, with, expr) \ + p##_2 (a, try, oc_idx_1, oc_idx_2) \ + p##_1 (a, throw, var) #define OP_ASSIGNMENTS(p, a) \ p##_3 (a, assignment, var_left, type_value_right, value_right) diff --git a/src/libjsparser/parser.c b/src/libjsparser/parser.c index 11bd15bc6..1cfc23efa 100644 --- a/src/libjsparser/parser.c +++ b/src/libjsparser/parser.c @@ -901,12 +901,12 @@ rewrite_meta_opcode_counter (opcode_meta_type type, { JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); - const idx_t data_1 = (idx_t) (new_value >> JERRY_BITSINBYTE); - const idx_t data_2 = (idx_t) (new_value & ((1 << JERRY_BITSINBYTE) - 1)); + const idx_t oc_idx_1 = (idx_t) (new_value >> JERRY_BITSINBYTE); + const idx_t oc_idx_2 = (idx_t) (new_value & ((1 << JERRY_BITSINBYTE) - 1)); - JERRY_ASSERT (new_value == calc_meta_opcode_counter_from_meta_data (data_1, data_2)); + JERRY_ASSERT (new_value == calc_opcode_counter_from_idx_idx (oc_idx_1, oc_idx_2)); - REWRITE_OPCODE_3 (meta_oc, meta, type, data_1, data_2); + REWRITE_OPCODE_3 (meta_oc, meta, type, oc_idx_1, oc_idx_2); } /* function_declaration diff --git a/tests/unit/test_try_catch.c b/tests/unit/test_try_catch.c new file mode 100644 index 000000000..904a3dac3 --- /dev/null +++ b/tests/unit/test_try_catch.c @@ -0,0 +1,65 @@ +/* Copyright 2014 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. + */ + +#include "globals.h" +#include "interpreter.h" +#include "mem-allocator.h" +#include "opcodes.h" +#include "serializer.h" + +/** + * Unit test's main function. + */ +int +main( int __unused argc, + char __unused **argv) +{ + const opcode_t test_program[] = { + [ 0] = getop_reg_var_decl (255, 255), + [ 1] = getop_var_decl (0), + [ 2] = getop_var_decl (1), + [ 3] = getop_try (0, 8), + [ 4] = getop_assignment (0, OPCODE_ARG_TYPE_STRING, 1), + [ 5] = getop_assignment (1, OPCODE_ARG_TYPE_VARIABLE, 0), + [ 6] = getop_throw (1), + [ 7] = getop_assignment (1, OPCODE_ARG_TYPE_SMALLINT, 12), + [ 8] = getop_meta (OPCODE_META_TYPE_CATCH, 0, 14), + [ 9] = getop_meta (OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER, 2, 255), + [10] = getop_equal_value_type (0, 1, 2), + [11] = getop_is_true_jmp (0, 14), + [12] = getop_exitval (1), + [13] = getop_assignment (0, OPCODE_ARG_TYPE_SIMPLE, ECMA_SIMPLE_VALUE_FALSE), + [14] = getop_meta (OPCODE_META_TYPE_FINALLY, 0, 18), + [15] = getop_is_false_jmp (0, 17), + [16] = getop_exitval (0), + [17] = getop_exitval (1), + [18] = getop_meta (OPCODE_META_TYPE_END_TRY_CATCH_FINALLY, 255, 255), + [19] = getop_exitval (1) + }; + + mem_init(); + + const char *strings[] = { "a", + "b", + "c" }; + ecma_number_t nums [] = { 2.0 }; + uint16_t offset = serializer_dump_strings( strings, 3); + serializer_dump_nums( nums, 1, offset, 3); + + init_int( test_program); + + return run_int() ? 0 + : 1; +} /* main */