Introducing and implementing 'throw' and 'try' opcode handlers.

This commit is contained in:
Ruben Ayrapetyan
2014-08-28 18:57:34 +04:00
parent 647f6b3c67
commit ddb2e6e9d5
6 changed files with 255 additions and 15 deletions
+6
View File
@@ -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;
}
}
@@ -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 */
+43 -8
View File
@@ -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) \
+9 -3
View File
@@ -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)
+4 -4
View File
@@ -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
+65
View File
@@ -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 */