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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (completion.type == ECMA_COMPLETION_TYPE_META)
|
||||||
|
{
|
||||||
|
completion.type = ECMA_COMPLETION_TYPE_NORMAL;
|
||||||
|
JERRY_ASSERT (ecma_is_completion_value_normal (completion));
|
||||||
|
}
|
||||||
|
|
||||||
return 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 "globals.h"
|
||||||
#include "interpreter.h"
|
#include "interpreter.h"
|
||||||
#include "jerry-libc.h"
|
|
||||||
#include "mem-heap.h"
|
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1456,6 +1454,39 @@ opfunc_with (opcode_t opdata, /**< operation data */
|
|||||||
return ret_value;
|
return ret_value;
|
||||||
} /* opfunc_with */
|
} /* 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.
|
* Evaluate argument of typeof.
|
||||||
*
|
*
|
||||||
@@ -1737,6 +1768,9 @@ opfunc_meta (opcode_t opdata, /**< operation data */
|
|||||||
{
|
{
|
||||||
case OPCODE_META_TYPE_VARG:
|
case OPCODE_META_TYPE_VARG:
|
||||||
case OPCODE_META_TYPE_END_WITH:
|
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,
|
return ecma_make_completion_value (ECMA_COMPLETION_TYPE_META,
|
||||||
ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY),
|
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_GETTER:
|
||||||
case OPCODE_META_TYPE_VARG_PROP_SETTER:
|
case OPCODE_META_TYPE_VARG_PROP_SETTER:
|
||||||
case OPCODE_META_TYPE_FUNCTION_END:
|
case OPCODE_META_TYPE_FUNCTION_END:
|
||||||
|
case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER:
|
||||||
{
|
{
|
||||||
JERRY_UNREACHABLE ();
|
JERRY_UNREACHABLE ();
|
||||||
}
|
}
|
||||||
@@ -1762,14 +1797,14 @@ opfunc_meta (opcode_t opdata, /**< operation data */
|
|||||||
* @return opcode counter
|
* @return opcode counter
|
||||||
*/
|
*/
|
||||||
opcode_counter_t
|
opcode_counter_t
|
||||||
calc_meta_opcode_counter_from_meta_data (const idx_t data_1, /**< first data argument */
|
calc_opcode_counter_from_idx_idx (const idx_t oc_idx_1, /**< first idx */
|
||||||
const idx_t data_2) /**< second data argument */
|
const idx_t oc_idx_2) /**< second idx */
|
||||||
{
|
{
|
||||||
opcode_counter_t counter;
|
opcode_counter_t counter;
|
||||||
|
|
||||||
counter = data_1;
|
counter = oc_idx_1;
|
||||||
counter = (opcode_counter_t) (counter << (sizeof (data_2) * JERRY_BITSINBYTE));
|
counter = (opcode_counter_t) (counter << (sizeof (idx_t) * JERRY_BITSINBYTE));
|
||||||
counter = (opcode_counter_t) (counter | data_2);
|
counter = (opcode_counter_t) (counter | oc_idx_2);
|
||||||
|
|
||||||
return counter;
|
return counter;
|
||||||
} /* calc_meta_opcode_counter_from_meta_data */
|
} /* 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_1 = meta_opcode.data.meta.data_1;
|
||||||
const idx_t data_2 = meta_opcode.data.meta.data_2;
|
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 */
|
} /* read_meta_opcode_counter */
|
||||||
|
|
||||||
#define GETOP_DEF_1(a, name, field1) \
|
#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_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_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_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;
|
} opcode_meta_type;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -74,7 +78,7 @@ typedef struct
|
|||||||
ecma_value_t *regs_p; /**< register variables */
|
ecma_value_t *regs_p; /**< register variables */
|
||||||
} int_data_t;
|
} 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);
|
opcode_counter_t read_meta_opcode_counter (opcode_meta_type expected_type, int_data_t *int_data);
|
||||||
|
|
||||||
#define OP_CALLS_AND_ARGS(p, a) \
|
#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##_2 (a, delete_var, lhs, name) \
|
||||||
p##_3 (a, delete_prop, lhs, base, name) \
|
p##_3 (a, delete_prop, lhs, base, name) \
|
||||||
p##_2 (a, typeof, lhs, obj) \
|
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) \
|
#define OP_ASSIGNMENTS(p, a) \
|
||||||
p##_3 (a, assignment, var_left, type_value_right, value_right)
|
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);
|
JERRY_STATIC_ASSERT (sizeof (idx_t) == 1);
|
||||||
|
|
||||||
const idx_t data_1 = (idx_t) (new_value >> JERRY_BITSINBYTE);
|
const idx_t oc_idx_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_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
|
/* 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