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

View File

@ -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;
}
}

View File

@ -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);

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
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) );
}

View File

@ -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) */

View File

@ -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.
*

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)
/* 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);

View File

@ -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),

View File

@ -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();

View File

@ -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),

View File

@ -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),

View File

@ -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),

View File

@ -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),

View File

@ -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();