Implementing register variables.

This commit is contained in:
Ruben Ayrapetyan
2014-07-24 18:13:32 +04:00
parent c837c7d435
commit b7a3a13bc9
13 changed files with 169 additions and 59 deletions
+49 -10
View File
@@ -13,8 +13,11 @@
* limitations under the License. * limitations under the License.
*/ */
#include "ecma-globals.h"
#include "ecma-helpers.h" #include "ecma-helpers.h"
#include "globals.h"
#include "interpreter.h" #include "interpreter.h"
#include "jerry-libc.h"
#define INIT_OP_FUNC(name) [ __op__idx_##name ] = opfunc_##name, #define INIT_OP_FUNC(name) [ __op__idx_##name ] = opfunc_##name,
static const opfunc __opfuncs[LAST_OP] = { static const opfunc __opfuncs[LAST_OP] = {
@@ -42,15 +45,17 @@ run_int (void)
{ {
JERRY_ASSERT( __program != NULL ); JERRY_ASSERT( __program != NULL );
struct __int_data int_data; const int start_pos = 0;
int_data.pos = 0; ecma_object_t *this_binding_p = NULL;
int_data.this_binding_p = NULL; ecma_object_t *lex_env_p = ecma_create_lexical_environment (NULL,
int_data.lex_env_p = ecma_create_lexical_environment( NULL, ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
FIXME( Strict mode ); 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 ) switch ( (ecma_completion_type_t)completion.type )
{ {
@@ -82,16 +87,43 @@ run_int (void)
} }
ecma_completion_value_t 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; 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 ) while ( true )
{ {
do do
{ {
const OPCODE *curr = &__program[int_data->pos]; const OPCODE *curr = &__program[int_data.pos];
completion = __opfuncs[curr->op_idx](*curr, int_data); completion = __opfuncs[curr->op_idx](*curr, &int_data);
JERRY_ASSERT( !ecma_is_completion_value_normal( completion) JERRY_ASSERT( !ecma_is_completion_value_normal( completion)
|| ecma_is_completion_value_normal_simple_value(completion, || ecma_is_completion_value_normal_simple_value(completion,
@@ -111,6 +143,13 @@ run_int_from_pos (struct __int_data *int_data)
continue; continue;
} }
for ( uint32_t reg_index = 0;
reg_index < regs_num;
reg_index++ )
{
ecma_free_value( regs[ reg_index ] );
}
return completion; return completion;
} }
} }
+7 -1
View File
@@ -26,11 +26,17 @@ struct __int_data
ecma_object_t *this_binding_p; /**< this binding for current context */ ecma_object_t *this_binding_p; /**< this binding for current context */
ecma_object_t *lex_env_p; /**< current lexical environment */ ecma_object_t *lex_env_p; /**< current lexical environment */
bool is_strict; /**< is current code execution mode strict? */ 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); void init_int (const OPCODE* program_p);
bool run_int (void); 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); 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); ecma_number_t get_number_by_idx(T_IDX idx);
+77 -32
View File
@@ -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 bool do_eval_or_arguments_check) /** run 'strict eval or arguments reference' check
See also: do_strict_eval_arguments_check */ See also: do_strict_eval_arguments_check */
{ {
string_literal_copy var_name;
ecma_reference_t ref;
ecma_completion_value_t ret_value; ecma_completion_value_t ret_value;
init_string_literal_copy( var_idx, &var_name); if ( var_idx >= int_data->min_reg_num
ref = ecma_op_get_identifier_reference( int_data->lex_env_p, && var_idx <= int_data->max_reg_num )
var_name.str_p, {
int_data->is_strict); ecma_value_t reg_value = int_data->regs_p[ var_idx - int_data->min_reg_num ];
if ( unlikely( do_eval_or_arguments_check JERRY_ASSERT( !ecma_is_value_empty( reg_value) );
&& do_strict_eval_arguments_check( ref) ) )
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)); ret_value = ecma_make_throw_value( ecma_new_standard_error( ECMA_ERROR_SYNTAX));
} }
else else
{ {
ret_value = ecma_op_get_value( ref); ret_value = ecma_op_get_value( ref);
} }
ecma_free_reference( ref); ecma_free_reference( ref);
free_string_literal_copy( &var_name); free_string_literal_copy( &var_name);
}
return ret_value; return ret_value;
} /* get_variable_value */ } /* get_variable_value */
@@ -219,26 +234,44 @@ set_variable_value(struct __int_data *int_data, /**< interpreter context */
T_IDX var_idx, /**< variable identifier */ T_IDX var_idx, /**< variable identifier */
ecma_value_t value) /**< value to set */ ecma_value_t value) /**< value to set */
{ {
string_literal_copy var_name;
ecma_reference_t ref;
ecma_completion_value_t ret_value; ecma_completion_value_t ret_value;
init_string_literal_copy( var_idx, &var_name); if ( var_idx >= int_data->min_reg_num
ref = ecma_op_get_identifier_reference( int_data->lex_env_p, && var_idx <= int_data->max_reg_num )
var_name.str_p, {
int_data->is_strict); 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)); ret_value = ecma_make_throw_value( ecma_new_standard_error( ECMA_ERROR_SYNTAX));
} }
else else
{ {
ret_value = ecma_op_put_value( ref, value); ret_value = ecma_op_put_value( ref, value);
} }
ecma_free_reference( ref); ecma_free_reference( ref);
free_string_literal_copy( &var_name); free_string_literal_copy( &var_name);
}
return ret_value; return ret_value;
} /* set_variable_value */ } /* set_variable_value */
@@ -372,13 +405,13 @@ do_number_arithmetic(struct __int_data *int_data, /**< interpreter context */
op(b_not) \ op(b_not) \
op(instanceof) \ op(instanceof) \
op(in) \ op(in) \
op(reg_var_decl) static char __unused unimplemented_list_end
#define DEFINE_UNIMPLEMENTED_OP(op) \ #define DEFINE_UNIMPLEMENTED_OP(op) \
ecma_completion_value_t opfunc_ ## op(OPCODE opdata, struct __int_data *int_data) { \ ecma_completion_value_t opfunc_ ## op(OPCODE opdata, struct __int_data *int_data) { \
JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( opdata, 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 #undef DEFINE_UNIMPLEMENTED_OP
ecma_completion_value_t ecma_completion_value_t
@@ -804,6 +837,18 @@ opfunc_remainder(OPCODE opdata, /**< operation data */
return ret_value; return ret_value;
} /* opfunc_remainder */ } /* 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. * 'Variable declaration' opcode handler.
* *
@@ -815,25 +860,25 @@ opfunc_remainder(OPCODE opdata, /**< operation data */
*/ */
ecma_completion_value_t ecma_completion_value_t
opfunc_var_decl(OPCODE opdata, /**< operation data */ 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; string_literal_copy variable_name;
init_string_literal_copy( opdata.data.var_decl.variable_name, &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, if ( ecma_is_completion_value_normal_false( ecma_op_has_binding (int_data->lex_env_p,
variable_name.str_p)) ) variable_name.str_p)) )
{ {
FIXME( Pass configurableBindings that is true if and only if current code is eval code ); 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, ecma_op_create_mutable_binding (int_data->lex_env_p,
variable_name.str_p, variable_name.str_p,
false); false);
/* Skipping SetMutableBinding as we have already checked that there were not /* Skipping SetMutableBinding as we have already checked that there were not
* any binding with specified name in current lexical environment * any binding with specified name in current lexical environment
* and CreateMutableBinding sets the created binding's value to undefined */ * 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, JERRY_ASSERT( ecma_is_completion_value_normal_simple_value( ecma_op_get_binding_value (int_data->lex_env_p,
variable_name.str_p, variable_name.str_p,
true), true),
ECMA_SIMPLE_VALUE_UNDEFINED) ); ECMA_SIMPLE_VALUE_UNDEFINED) );
} }
+1 -1
View File
@@ -63,11 +63,11 @@ typedef enum {
* Simple ecma-values * Simple ecma-values
*/ */
typedef enum { 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_UNDEFINED, /**< undefined value */
ECMA_SIMPLE_VALUE_NULL, /**< null value */ ECMA_SIMPLE_VALUE_NULL, /**< null value */
ECMA_SIMPLE_VALUE_FALSE, /**< boolean false */ ECMA_SIMPLE_VALUE_FALSE, /**< boolean false */
ECMA_SIMPLE_VALUE_TRUE, /**< boolean true */ 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, ECMA_SIMPLE_VALUE_ARRAY_REDIRECT, /**< special value for an array's elements that exists,
but is stored directly in the array's property list but is stored directly in the array's property list
(used for array elements with non-default attribute values) */ (used for array elements with non-default attribute values) */
+12
View File
@@ -26,6 +26,18 @@
#include "ecma-helpers.h" #include "ecma-helpers.h"
#include "globals.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. * Check if the value is undefined.
* *
+1
View File
@@ -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) (field) = ecma_compress_pointer( non_compressed_pointer) & ( ( 1u << ECMA_POINTER_FIELD_WIDTH ) - 1)
/* ecma-helpers-value.c */ /* 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_undefined( ecma_value_t value);
extern bool ecma_is_value_null( ecma_value_t value); extern bool ecma_is_value_null( ecma_value_t value);
extern bool ecma_is_value_boolean( ecma_value_t value); extern bool ecma_is_value_boolean( ecma_value_t value);
@@ -26,6 +26,7 @@ main( int __unused argc,
char __unused **argv) char __unused **argv)
{ {
const OPCODE test_program[] = { const OPCODE test_program[] = {
getop_reg_var_decl( 255, 255),
getop_var_decl( 0), getop_var_decl( 0),
getop_var_decl( 1), getop_var_decl( 1),
getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253),
+12 -11
View File
@@ -26,17 +26,18 @@ main( int __unused argc,
char __unused **argv) char __unused **argv)
{ {
const OPCODE test_program[] = { const OPCODE test_program[] = {
/* 0: */ getop_var_decl( 0), /* 0: */ getop_reg_var_decl( 255, 255),
/* 1: */ getop_var_decl( 1), /* 1: */ getop_var_decl( 0),
/* 2: */ getop_assignment( 0, OPCODE_ARG_TYPE_STRING, 1), /* 2: */ getop_var_decl( 1),
/* 3: */ getop_assignment( 1, OPCODE_ARG_TYPE_VARIABLE, 0), /* 3: */ getop_assignment( 0, OPCODE_ARG_TYPE_STRING, 1),
/* 4: */ getop_is_true_jmp( 1, 6), /* 4: */ getop_assignment( 1, OPCODE_ARG_TYPE_VARIABLE, 0),
/* 5: */ getop_jmp_down( 5), /* 5: */ getop_is_true_jmp( 1, 7),
/* 6: */ getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), /* 6: */ getop_jmp_down( 5),
/* 7: */ getop_assignment( 1, OPCODE_ARG_TYPE_NUMBER, 2), /* 7: */ getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253),
/* 8: */ getop_is_false_jmp( 1, 10), /* 8: */ getop_assignment( 1, OPCODE_ARG_TYPE_NUMBER, 2),
/* 9: */ getop_exitval( 0), /* 9: */ getop_is_false_jmp( 1, 11),
/* 10: */ getop_exitval( 1) /* 10: */ getop_exitval( 0),
/* 11: */ getop_exitval( 1)
}; };
mem_init(); mem_init();
+1
View File
@@ -26,6 +26,7 @@ main( int __unused argc,
char __unused **argv) char __unused **argv)
{ {
const OPCODE test_program[] = { const OPCODE test_program[] = {
getop_reg_var_decl( 255, 255),
getop_var_decl( 0), getop_var_decl( 0),
getop_var_decl( 1), getop_var_decl( 1),
getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253),
+1
View File
@@ -26,6 +26,7 @@ main( int __unused argc,
char __unused **argv) char __unused **argv)
{ {
const OPCODE test_program[] = { const OPCODE test_program[] = {
getop_reg_var_decl( 255, 255),
getop_var_decl( 0), getop_var_decl( 0),
getop_var_decl( 1), getop_var_decl( 1),
getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253),
+1
View File
@@ -26,6 +26,7 @@ main( int __unused argc,
char __unused **argv) char __unused **argv)
{ {
const OPCODE test_program[] = { const OPCODE test_program[] = {
getop_reg_var_decl( 255, 255),
getop_var_decl( 0), getop_var_decl( 0),
getop_var_decl( 1), getop_var_decl( 1),
getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253),
+1
View File
@@ -26,6 +26,7 @@ main( int __unused argc,
char __unused **argv) char __unused **argv)
{ {
const OPCODE test_program[] = { const OPCODE test_program[] = {
getop_reg_var_decl( 255, 255),
getop_var_decl( 0), getop_var_decl( 0),
getop_var_decl( 1), getop_var_decl( 1),
getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253), getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253),
@@ -26,10 +26,11 @@ main( int __unused argc,
char __unused **argv) char __unused **argv)
{ {
const OPCODE test_program[] = { const OPCODE test_program[] = {
getop_var_decl( 0), /* 0: */ getop_reg_var_decl( 255, 255),
getop_is_true_jmp( 0, 3), /* 1: */ getop_var_decl( 0),
getop_exitval( 0), /* 2: */ getop_is_true_jmp( 0, 4),
getop_exitval( 1) /* 3: */ getop_exitval( 0),
/* 4: */ getop_exitval( 1)
}; };
mem_init(); mem_init();