From b7a3a13bc9d18319fc54ac2310d3cdea9a12aec8 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Thu, 24 Jul 2014 18:13:32 +0400 Subject: [PATCH] Implementing register variables. --- src/libcoreint/interpreter.c | 59 ++++++++-- src/libcoreint/interpreter.h | 8 +- src/libcoreint/opcodes.c | 109 +++++++++++++----- src/libecmaobjects/ecma-globals.h | 2 +- src/libecmaobjects/ecma-helpers-value.c | 12 ++ src/libecmaobjects/ecma-helpers.h | 1 + .../test_addition_opcode_number_operands.c | 1 + tests/unit/test_assignment_opcode.c | 23 ++-- tests/unit/test_division_opcode.c | 1 + tests/unit/test_multiplication_opcode.c | 1 + tests/unit/test_remainder_opcode.c | 1 + tests/unit/test_substraction_opcode.c | 1 + .../test_var_decl_opcode_in_decl_lex_env.c | 9 +- 13 files changed, 169 insertions(+), 59 deletions(-) diff --git a/src/libcoreint/interpreter.c b/src/libcoreint/interpreter.c index 821cb9328..2264cc4de 100644 --- a/src/libcoreint/interpreter.c +++ b/src/libcoreint/interpreter.c @@ -13,8 +13,11 @@ * limitations under the License. */ +#include "ecma-globals.h" #include "ecma-helpers.h" +#include "globals.h" #include "interpreter.h" +#include "jerry-libc.h" #define INIT_OP_FUNC(name) [ __op__idx_##name ] = opfunc_##name, static const opfunc __opfuncs[LAST_OP] = { @@ -42,15 +45,17 @@ run_int (void) { JERRY_ASSERT( __program != NULL ); - struct __int_data int_data; - int_data.pos = 0; - int_data.this_binding_p = NULL; - int_data.lex_env_p = ecma_create_lexical_environment( NULL, - ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + const int start_pos = 0; + ecma_object_t *this_binding_p = NULL; + ecma_object_t *lex_env_p = ecma_create_lexical_environment (NULL, + ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); FIXME( Strict mode ); - int_data.is_strict = false; + const bool is_strict = false; - ecma_completion_value_t completion = run_int_from_pos( &int_data); + ecma_completion_value_t completion = run_int_from_pos (start_pos, + this_binding_p, + lex_env_p, + is_strict); switch ( (ecma_completion_type_t)completion.type ) { @@ -82,16 +87,43 @@ run_int (void) } ecma_completion_value_t -run_int_from_pos (struct __int_data *int_data) +run_int_from_pos (int start_pos, + ecma_object_t *this_binding_p, + ecma_object_t *lex_env_p, + bool is_strict) { ecma_completion_value_t completion; + const OPCODE *curr = &__program[start_pos]; + JERRY_ASSERT( curr->op_idx == __op__idx_reg_var_decl ); + + const T_IDX min_reg_num = curr->data.reg_var_decl.min; + const T_IDX max_reg_num = curr->data.reg_var_decl.max; + JERRY_ASSERT( max_reg_num >= min_reg_num ); + + const uint32_t regs_num = (uint32_t) (max_reg_num - min_reg_num + 1); + + ecma_value_t regs[ regs_num ]; + + /* memseting with zero initializes each 'register' to empty value */ + __memset (regs, 0, sizeof(regs)); + JERRY_ASSERT( ecma_is_value_empty( regs[0]) ); + + struct __int_data int_data; + int_data.pos = start_pos + 1; + int_data.this_binding_p = this_binding_p; + int_data.lex_env_p = lex_env_p; + int_data.is_strict = is_strict; + int_data.min_reg_num = min_reg_num; + int_data.max_reg_num = max_reg_num; + int_data.regs_p = regs; + while ( true ) { do { - const OPCODE *curr = &__program[int_data->pos]; - completion = __opfuncs[curr->op_idx](*curr, int_data); + const OPCODE *curr = &__program[int_data.pos]; + completion = __opfuncs[curr->op_idx](*curr, &int_data); JERRY_ASSERT( !ecma_is_completion_value_normal( completion) || ecma_is_completion_value_normal_simple_value(completion, @@ -111,6 +143,13 @@ run_int_from_pos (struct __int_data *int_data) continue; } + for ( uint32_t reg_index = 0; + reg_index < regs_num; + reg_index++ ) + { + ecma_free_value( regs[ reg_index ] ); + } + return completion; } } diff --git a/src/libcoreint/interpreter.h b/src/libcoreint/interpreter.h index 5825b25eb..253b77565 100644 --- a/src/libcoreint/interpreter.h +++ b/src/libcoreint/interpreter.h @@ -26,11 +26,17 @@ struct __int_data ecma_object_t *this_binding_p; /**< this binding for current context */ ecma_object_t *lex_env_p; /**< current lexical environment */ bool is_strict; /**< is current code execution mode strict? */ + T_IDX min_reg_num; /**< minimum idx used for register identification */ + T_IDX max_reg_num; /**< maximum idx used for register identification */ + ecma_value_t *regs_p; /**< register variables */ }; void init_int (const OPCODE* program_p); bool run_int (void); -ecma_completion_value_t run_int_from_pos (struct __int_data *); +ecma_completion_value_t run_int_from_pos (int start_pos, + ecma_object_t *this_binding_p, + ecma_object_t *lex_env_p, + bool is_strict); ssize_t try_get_string_by_idx( T_IDX idx, ecma_char_t *buffer_p, ssize_t buffer_size); ecma_number_t get_number_by_idx(T_IDX idx); diff --git a/src/libcoreint/opcodes.c b/src/libcoreint/opcodes.c index cc8c8782e..07a31d1f0 100644 --- a/src/libcoreint/opcodes.c +++ b/src/libcoreint/opcodes.c @@ -183,27 +183,42 @@ get_variable_value(struct __int_data *int_data, /**< interpreter context */ bool do_eval_or_arguments_check) /** run 'strict eval or arguments reference' check See also: do_strict_eval_arguments_check */ { - string_literal_copy var_name; - ecma_reference_t ref; ecma_completion_value_t ret_value; - init_string_literal_copy( var_idx, &var_name); - ref = ecma_op_get_identifier_reference( int_data->lex_env_p, - var_name.str_p, - int_data->is_strict); + if ( var_idx >= int_data->min_reg_num + && var_idx <= int_data->max_reg_num ) + { + ecma_value_t reg_value = int_data->regs_p[ var_idx - int_data->min_reg_num ]; - if ( unlikely( do_eval_or_arguments_check - && do_strict_eval_arguments_check( ref) ) ) + JERRY_ASSERT( !ecma_is_value_empty( reg_value) ); + + ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, + ecma_copy_value( reg_value), + ECMA_TARGET_ID_RESERVED); + } + else + { + string_literal_copy var_name; + ecma_reference_t ref; + + init_string_literal_copy( var_idx, &var_name); + ref = ecma_op_get_identifier_reference( int_data->lex_env_p, + var_name.str_p, + int_data->is_strict); + + if ( unlikely( do_eval_or_arguments_check + && do_strict_eval_arguments_check( ref) ) ) { ret_value = ecma_make_throw_value( ecma_new_standard_error( ECMA_ERROR_SYNTAX)); } - else + else { ret_value = ecma_op_get_value( ref); } - ecma_free_reference( ref); - free_string_literal_copy( &var_name); + ecma_free_reference( ref); + free_string_literal_copy( &var_name); + } return ret_value; } /* get_variable_value */ @@ -219,26 +234,44 @@ set_variable_value(struct __int_data *int_data, /**< interpreter context */ T_IDX var_idx, /**< variable identifier */ ecma_value_t value) /**< value to set */ { - string_literal_copy var_name; - ecma_reference_t ref; ecma_completion_value_t ret_value; - init_string_literal_copy( var_idx, &var_name); - ref = ecma_op_get_identifier_reference( int_data->lex_env_p, - var_name.str_p, - int_data->is_strict); + if ( var_idx >= int_data->min_reg_num + && var_idx <= int_data->max_reg_num ) + { + ecma_value_t reg_value = int_data->regs_p[ var_idx - int_data->min_reg_num ]; - if ( unlikely( do_strict_eval_arguments_check( ref) ) ) + if ( !ecma_is_value_empty( reg_value) ) + { + ecma_free_value( reg_value); + } + + int_data->regs_p[ var_idx - int_data->min_reg_num ] = ecma_copy_value( value); + + ret_value = ecma_make_empty_completion_value(); + } + else + { + string_literal_copy var_name; + ecma_reference_t ref; + + init_string_literal_copy( var_idx, &var_name); + ref = ecma_op_get_identifier_reference( int_data->lex_env_p, + var_name.str_p, + int_data->is_strict); + + if ( unlikely( do_strict_eval_arguments_check( ref) ) ) { ret_value = ecma_make_throw_value( ecma_new_standard_error( ECMA_ERROR_SYNTAX)); } - else + else { ret_value = ecma_op_put_value( ref, value); } - ecma_free_reference( ref); - free_string_literal_copy( &var_name); + ecma_free_reference( ref); + free_string_literal_copy( &var_name); + } return ret_value; } /* set_variable_value */ @@ -372,13 +405,13 @@ do_number_arithmetic(struct __int_data *int_data, /**< interpreter context */ op(b_not) \ op(instanceof) \ op(in) \ - op(reg_var_decl) + static char __unused unimplemented_list_end #define DEFINE_UNIMPLEMENTED_OP(op) \ ecma_completion_value_t opfunc_ ## op(OPCODE opdata, struct __int_data *int_data) { \ JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( opdata, int_data); \ } -OP_UNIMPLEMENTED_LIST(DEFINE_UNIMPLEMENTED_OP) +OP_UNIMPLEMENTED_LIST(DEFINE_UNIMPLEMENTED_OP); #undef DEFINE_UNIMPLEMENTED_OP ecma_completion_value_t @@ -804,6 +837,18 @@ opfunc_remainder(OPCODE opdata, /**< operation data */ return ret_value; } /* opfunc_remainder */ +/** + * 'Register variable declaration' opcode handler. + * + * The opcode is meta-opcode that is not supposed to be executed. + */ +ecma_completion_value_t +opfunc_reg_var_decl(OPCODE opdata __unused, /**< operation data */ + struct __int_data *int_data __unused) /**< interpreter context */ +{ + JERRY_UNREACHABLE(); +} /* opfunc_reg_var_decl */ + /** * 'Variable declaration' opcode handler. * @@ -815,25 +860,25 @@ opfunc_remainder(OPCODE opdata, /**< operation data */ */ ecma_completion_value_t opfunc_var_decl(OPCODE opdata, /**< operation data */ - struct __int_data *int_data __unused) /**< interpreter context */ + struct __int_data *int_data) /**< interpreter context */ { string_literal_copy variable_name; init_string_literal_copy( opdata.data.var_decl.variable_name, &variable_name); - if ( ecma_is_completion_value_normal_false( ecma_op_has_binding( int_data->lex_env_p, - variable_name.str_p)) ) + if ( ecma_is_completion_value_normal_false( ecma_op_has_binding (int_data->lex_env_p, + variable_name.str_p)) ) { FIXME( Pass configurableBindings that is true if and only if current code is eval code ); - ecma_op_create_mutable_binding( int_data->lex_env_p, - variable_name.str_p, - false); + ecma_op_create_mutable_binding (int_data->lex_env_p, + variable_name.str_p, + false); /* Skipping SetMutableBinding as we have already checked that there were not * any binding with specified name in current lexical environment * and CreateMutableBinding sets the created binding's value to undefined */ - JERRY_ASSERT( ecma_is_completion_value_normal_simple_value( ecma_op_get_binding_value( int_data->lex_env_p, - variable_name.str_p, - true), + JERRY_ASSERT( ecma_is_completion_value_normal_simple_value( ecma_op_get_binding_value (int_data->lex_env_p, + variable_name.str_p, + true), ECMA_SIMPLE_VALUE_UNDEFINED) ); } diff --git a/src/libecmaobjects/ecma-globals.h b/src/libecmaobjects/ecma-globals.h index 61a58f586..39611a2e3 100644 --- a/src/libecmaobjects/ecma-globals.h +++ b/src/libecmaobjects/ecma-globals.h @@ -63,11 +63,11 @@ typedef enum { * Simple ecma-values */ typedef enum { + ECMA_SIMPLE_VALUE_EMPTY, /**< empty value (see also: ECMA-262 v5, 8.9 Completion specification type) */ ECMA_SIMPLE_VALUE_UNDEFINED, /**< undefined value */ ECMA_SIMPLE_VALUE_NULL, /**< null value */ ECMA_SIMPLE_VALUE_FALSE, /**< boolean false */ ECMA_SIMPLE_VALUE_TRUE, /**< boolean true */ - ECMA_SIMPLE_VALUE_EMPTY, /**< empty value (see also: ECMA-262 v5, 8.9 Completion specification type) */ ECMA_SIMPLE_VALUE_ARRAY_REDIRECT, /**< special value for an array's elements that exists, but is stored directly in the array's property list (used for array elements with non-default attribute values) */ diff --git a/src/libecmaobjects/ecma-helpers-value.c b/src/libecmaobjects/ecma-helpers-value.c index bb66c33a9..efa0a1155 100644 --- a/src/libecmaobjects/ecma-helpers-value.c +++ b/src/libecmaobjects/ecma-helpers-value.c @@ -26,6 +26,18 @@ #include "ecma-helpers.h" #include "globals.h" +/** + * Check if the value is empty. + * + * @return true - if the value contains implementation-defined empty simple value, + * false - otherwise. + */ +bool +ecma_is_value_empty( ecma_value_t value) /**< ecma-value */ +{ + return ( value.value_type == ECMA_TYPE_SIMPLE && value.value == ECMA_SIMPLE_VALUE_EMPTY ); +} /* ecma_is_value_empty */ + /** * Check if the value is undefined. * diff --git a/src/libecmaobjects/ecma-helpers.h b/src/libecmaobjects/ecma-helpers.h index db8e3e0ab..a72e84bec 100644 --- a/src/libecmaobjects/ecma-helpers.h +++ b/src/libecmaobjects/ecma-helpers.h @@ -42,6 +42,7 @@ extern void* ecma_decompress_pointer(uintptr_t compressed_pointer); (field) = ecma_compress_pointer( non_compressed_pointer) & ( ( 1u << ECMA_POINTER_FIELD_WIDTH ) - 1) /* ecma-helpers-value.c */ +extern bool ecma_is_value_empty( ecma_value_t value); extern bool ecma_is_value_undefined( ecma_value_t value); extern bool ecma_is_value_null( ecma_value_t value); extern bool ecma_is_value_boolean( ecma_value_t value); diff --git a/tests/unit/test_addition_opcode_number_operands.c b/tests/unit/test_addition_opcode_number_operands.c index 1c840fde1..683432222 100644 --- a/tests/unit/test_addition_opcode_number_operands.c +++ b/tests/unit/test_addition_opcode_number_operands.c @@ -26,6 +26,7 @@ main( int __unused argc, char __unused **argv) { const OPCODE test_program[] = { + getop_reg_var_decl( 255, 255), getop_var_decl( 0), getop_var_decl( 1), getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), diff --git a/tests/unit/test_assignment_opcode.c b/tests/unit/test_assignment_opcode.c index 8b4ef8292..d138cf377 100644 --- a/tests/unit/test_assignment_opcode.c +++ b/tests/unit/test_assignment_opcode.c @@ -26,17 +26,18 @@ main( int __unused argc, char __unused **argv) { const OPCODE test_program[] = { - /* 0: */ getop_var_decl( 0), - /* 1: */ getop_var_decl( 1), - /* 2: */ getop_assignment( 0, OPCODE_ARG_TYPE_STRING, 1), - /* 3: */ getop_assignment( 1, OPCODE_ARG_TYPE_VARIABLE, 0), - /* 4: */ getop_is_true_jmp( 1, 6), - /* 5: */ getop_jmp_down( 5), - /* 6: */ getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), - /* 7: */ getop_assignment( 1, OPCODE_ARG_TYPE_NUMBER, 2), - /* 8: */ getop_is_false_jmp( 1, 10), - /* 9: */ getop_exitval( 0), - /* 10: */ getop_exitval( 1) + /* 0: */ getop_reg_var_decl( 255, 255), + /* 1: */ getop_var_decl( 0), + /* 2: */ getop_var_decl( 1), + /* 3: */ getop_assignment( 0, OPCODE_ARG_TYPE_STRING, 1), + /* 4: */ getop_assignment( 1, OPCODE_ARG_TYPE_VARIABLE, 0), + /* 5: */ getop_is_true_jmp( 1, 7), + /* 6: */ getop_jmp_down( 5), + /* 7: */ getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), + /* 8: */ getop_assignment( 1, OPCODE_ARG_TYPE_NUMBER, 2), + /* 9: */ getop_is_false_jmp( 1, 11), + /* 10: */ getop_exitval( 0), + /* 11: */ getop_exitval( 1) }; mem_init(); diff --git a/tests/unit/test_division_opcode.c b/tests/unit/test_division_opcode.c index e14084bbc..5c1c121ac 100644 --- a/tests/unit/test_division_opcode.c +++ b/tests/unit/test_division_opcode.c @@ -26,6 +26,7 @@ main( int __unused argc, char __unused **argv) { const OPCODE test_program[] = { + getop_reg_var_decl( 255, 255), getop_var_decl( 0), getop_var_decl( 1), getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), diff --git a/tests/unit/test_multiplication_opcode.c b/tests/unit/test_multiplication_opcode.c index 1bbd2bb29..aba7f5660 100644 --- a/tests/unit/test_multiplication_opcode.c +++ b/tests/unit/test_multiplication_opcode.c @@ -26,6 +26,7 @@ main( int __unused argc, char __unused **argv) { const OPCODE test_program[] = { + getop_reg_var_decl( 255, 255), getop_var_decl( 0), getop_var_decl( 1), getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), diff --git a/tests/unit/test_remainder_opcode.c b/tests/unit/test_remainder_opcode.c index a4b7328ce..7e4882a5d 100644 --- a/tests/unit/test_remainder_opcode.c +++ b/tests/unit/test_remainder_opcode.c @@ -26,6 +26,7 @@ main( int __unused argc, char __unused **argv) { const OPCODE test_program[] = { + getop_reg_var_decl( 255, 255), getop_var_decl( 0), getop_var_decl( 1), getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), diff --git a/tests/unit/test_substraction_opcode.c b/tests/unit/test_substraction_opcode.c index f8c8d64ab..392f1bfb5 100644 --- a/tests/unit/test_substraction_opcode.c +++ b/tests/unit/test_substraction_opcode.c @@ -26,6 +26,7 @@ main( int __unused argc, char __unused **argv) { const OPCODE test_program[] = { + getop_reg_var_decl( 255, 255), getop_var_decl( 0), getop_var_decl( 1), getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), diff --git a/tests/unit/test_var_decl_opcode_in_decl_lex_env.c b/tests/unit/test_var_decl_opcode_in_decl_lex_env.c index d6164c131..a10ab2939 100644 --- a/tests/unit/test_var_decl_opcode_in_decl_lex_env.c +++ b/tests/unit/test_var_decl_opcode_in_decl_lex_env.c @@ -26,10 +26,11 @@ main( int __unused argc, char __unused **argv) { const OPCODE test_program[] = { - getop_var_decl( 0), - getop_is_true_jmp( 0, 3), - getop_exitval( 0), - getop_exitval( 1) + /* 0: */ getop_reg_var_decl( 255, 255), + /* 1: */ getop_var_decl( 0), + /* 2: */ getop_is_true_jmp( 0, 4), + /* 3: */ getop_exitval( 0), + /* 4: */ getop_exitval( 1) }; mem_init();