Introducing and implementing 'throw' and 'try' opcode handlers.
This commit is contained in:
@@ -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 */
|
||||
@@ -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) \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user