Implementing 'multiplication' opcode handler and unit test for the opcode.

This commit is contained in:
Ruben Ayrapetyan 2014-07-21 21:59:15 +04:00
parent 9b2b248728
commit 739d19be5b
8 changed files with 372 additions and 41 deletions

View File

@ -14,8 +14,10 @@
*/
#include "ecma-alloc.h"
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
#include "ecma-helpers.h"
#include "ecma-number-arithmetic.h"
#include "ecma-operations.h"
#include "interpreter.h"
#include "jerry-libc.h"
@ -89,6 +91,61 @@ free_string_literal_copy(string_literal_copy *str_lit_descr_p) /**< string liter
return;
} /* free_string_literal */
/**
* Get variable's value.
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
static ecma_CompletionValue_t
get_variable_value(struct __int_data *int_data, /* interpreter context */
T_IDX var_idx) /* variable identifier */
{
string_literal_copy var_name;
ecma_Reference_t ref;
ecma_CompletionValue_t ret_value;
init_string_literal_copy( var_idx, &var_name);
ref = ecma_OpGetIdentifierReference( int_data->lex_env_p,
var_name.str_p,
int_data->is_strict);
ret_value = ecma_op_get_value( ref);
ecma_FreeReference( ref);
free_string_literal_copy( &var_name);
return ret_value;
} /* get_variable_value */
/**
* Set variable's value.
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
static ecma_CompletionValue_t
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_CompletionValue_t ret_value;
init_string_literal_copy( var_idx, &var_name);
ref = ecma_OpGetIdentifierReference( int_data->lex_env_p,
var_name.str_p,
int_data->is_strict);
ret_value = ecma_op_put_value( ref, value);
ecma_FreeReference( ref);
free_string_literal_copy( &var_name);
return ret_value;
} /* set_variable_value */
#define OP_UNIMPLEMENTED_LIST(op) \
op(is_true_jmp) \
op(is_false_jmp) \
@ -128,7 +185,6 @@ free_string_literal_copy(string_literal_copy *str_lit_descr_p) /**< string liter
op(addition) \
op(substraction) \
op(division) \
op(multiplication) \
op(remainder) \
op(jmp_up) \
op(jmp_down) \
@ -240,29 +296,15 @@ opfunc_assignment (OPCODE opdata, /**< operation data */
}
case OPCODE_ARG_TYPE_VARIABLE:
{
string_literal_copy src_variable_name;
ecma_Reference_t src_reference;
init_string_literal_copy( src_val_descr, &src_variable_name);
src_reference = ecma_OpGetIdentifierReference( int_data->lex_env_p,
src_variable_name.str_p,
int_data->is_strict);
ecma_CompletionValue_t get_value_completion = ecma_op_get_value( &src_reference);
JERRY_ASSERT( get_value_completion.type == ECMA_COMPLETION_TYPE_NORMAL
|| get_value_completion.type == ECMA_COMPLETION_TYPE_THROW );
ecma_FreeReference( src_reference);
free_string_literal_copy( &src_variable_name);
if ( get_value_completion.type == ECMA_COMPLETION_TYPE_NORMAL )
ecma_CompletionValue_t get_value_completion = get_variable_value( int_data,
src_val_descr);
if ( ecma_is_completion_value_normal( get_value_completion) )
{
right_value = get_value_completion.value;
} else
{
JERRY_ASSERT( ecma_is_completion_value_throw( get_value_completion) );
return get_value_completion;
}
@ -314,7 +356,7 @@ opfunc_assignment (OPCODE opdata, /**< operation data */
completion_value = ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_SYNTAX));
} else
{
completion_value = ecma_op_put_value( &dst_reference, right_value);
completion_value = ecma_op_put_value( dst_reference, right_value);
}
ecma_FreeValue( right_value);
@ -326,6 +368,95 @@ opfunc_assignment (OPCODE opdata, /**< operation data */
return completion_value;
} /* opfunc_assignment */
/**
* Multiplicatoin opcode handler.
*
* See also: ECMA-262 v5, 11.5, 11.5.1
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_CompletionValue_t
opfunc_multiplication (OPCODE opdata, /**< operation data */
struct __int_data *int_data) /**< interpreter context */
{
const T_IDX dst_var_idx = opdata.data.multiplication.dst;
const T_IDX left_var_idx = opdata.data.multiplication.var_left;
const T_IDX right_var_idx = opdata.data.multiplication.var_right;
int_data->pos++;
ecma_CompletionValue_t left_value = ecma_make_empty_completion_value(),
right_value = ecma_make_empty_completion_value(),
num_left_value = ecma_make_empty_completion_value(),
num_right_value = ecma_make_empty_completion_value(),
ret_value = ecma_make_empty_completion_value();
left_value = get_variable_value( int_data, left_var_idx);
if ( ecma_is_completion_value_throw( left_value) )
{
ret_value = ecma_copy_completion_value( left_value);
}
else
{
JERRY_ASSERT( ecma_is_completion_value_normal( left_value) );
right_value = get_variable_value( int_data, right_var_idx);
if ( ecma_is_completion_value_throw( right_value) )
{
ret_value = ecma_copy_completion_value( right_value);
}
else
{
JERRY_ASSERT( ecma_is_completion_value_normal( right_value) );
num_left_value = ecma_op_to_number( left_value.value);
if ( ecma_is_completion_value_throw( num_left_value) )
{
ret_value = ecma_copy_completion_value( num_left_value);
}
else
{
JERRY_ASSERT( ecma_is_completion_value_normal( num_left_value) );
num_right_value = ecma_op_to_number( right_value.value);
if ( ecma_is_completion_value_throw( num_right_value) )
{
ret_value = ecma_copy_completion_value( num_right_value);
}
else
{
JERRY_ASSERT( ecma_is_completion_value_normal( num_right_value) );
ecma_Number_t *left_p, *right_p, *res_p;
left_p = (ecma_Number_t*)ecma_GetPointer( num_left_value.value.m_Value);
right_p = (ecma_Number_t*)ecma_GetPointer( num_right_value.value.m_Value);
res_p = ecma_AllocNumber();
*res_p = ecma_op_number_multiply( *left_p, *right_p);
ret_value = set_variable_value( int_data,
dst_var_idx,
ecma_MakeNumberValue( res_p));
ecma_DeallocNumber( res_p);
}
}
}
}
ecma_free_completion_value( left_value);
ecma_free_completion_value( right_value);
ecma_free_completion_value( num_left_value);
ecma_free_completion_value( num_right_value);
return ret_value;
} /* opfunc_multiplication */
/**
* Variable declaration opcode handler.
*

View File

@ -89,6 +89,22 @@ ecma_MakeSimpleValue( ecma_SimpleValue_t value) /**< simple value */
return (ecma_Value_t) { .m_ValueType = ECMA_TYPE_SIMPLE, .m_Value = value };
} /* ecma_MakeSimpleValue */
/**
* Number value constructor
*/
ecma_Value_t
ecma_MakeNumberValue( ecma_Number_t* num_p) /**< number to reference in value */
{
JERRY_ASSERT( num_p != NULL );
ecma_Value_t number_value;
number_value.m_ValueType = ECMA_TYPE_NUMBER;
ecma_SetPointer( number_value.m_Value, num_p);
return number_value;
} /* ecma_MakeNumberValue */
/**
* Object value constructor
*/
@ -255,6 +271,32 @@ ecma_MakeThrowValue( ecma_Object_t *exception_p) /**< an object */
ECMA_TARGET_ID_RESERVED);
} /* ecma_MakeThrowValue */
/**
* Empty completion value constructor.
*
* @return (normal, empty, reserved) completion value.
*/
ecma_CompletionValue_t
ecma_make_empty_completion_value( void)
{
return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL,
ecma_MakeSimpleValue( ECMA_SIMPLE_VALUE_EMPTY),
ECMA_TARGET_ID_RESERVED);
} /* ecma_make_empty_completion_value */
/**
* Copy ecma-completion value.
*
* @return (source.type, ecma_CopyValue( source.value), source.target).
*/
ecma_CompletionValue_t
ecma_copy_completion_value( ecma_CompletionValue_t value) /**< completion value */
{
return ecma_MakeCompletionValue( value.type,
ecma_CopyValue( value.value),
value.target);
} /* ecma_copy_completion_value */
/**
* Free the completion value.
*/
@ -283,11 +325,36 @@ ecma_free_completion_value( ecma_CompletionValue_t completion_value) /**< comple
* false - otherwise.
*/
bool
ecma_is_completion_value_normal( ecma_CompletionValue_t value)
ecma_is_completion_value_normal( ecma_CompletionValue_t value) /**< completion value */
{
return ( value.type == ECMA_COMPLETION_TYPE_NORMAL );
} /* ecma_is_completion_value_normal */
/**
* Check if the completion value is throw value.
*
* @return true - if the completion type is throw,
* false - otherwise.
*/
bool
ecma_is_completion_value_throw( ecma_CompletionValue_t value) /**< completion value */
{
return ( value.type == ECMA_COMPLETION_TYPE_THROW );
} /* ecma_is_completion_value_throw */
/**
* Check if the completion value is normal or throw value.
*
* @return true - if the completion type is normal or throw,
* false - otherwise.
*/
bool
ecma_is_completion_value_normal_or_throw( ecma_CompletionValue_t value) /**< completion value */
{
return ecma_is_completion_value_normal( value)
|| ecma_is_completion_value_throw( value);
} /* ecma_is_completion_value_normal_or_throw */
/**
* Check if the completion value is specified normal simple value.
*

View File

@ -48,15 +48,20 @@ extern bool ecma_IsValueBoolean( ecma_Value_t value);
extern bool ecma_IsValueTrue( ecma_Value_t value);
extern ecma_Value_t ecma_MakeSimpleValue( ecma_SimpleValue_t value);
extern ecma_Value_t ecma_MakeNumberValue( ecma_Number_t* num_p);
extern ecma_Value_t ecma_MakeObjectValue( ecma_Object_t* object_p);
extern ecma_Value_t ecma_CopyValue( const ecma_Value_t value);
extern void ecma_FreeValue( const ecma_Value_t value);
extern ecma_CompletionValue_t ecma_MakeCompletionValue( ecma_CompletionType_t type, ecma_Value_t value, uint8_t target);
extern ecma_CompletionValue_t ecma_MakeThrowValue( ecma_Object_t *exception_p);
extern ecma_CompletionValue_t ecma_make_empty_completion_value( void);
extern ecma_CompletionValue_t ecma_copy_completion_value( ecma_CompletionValue_t value);
extern void ecma_free_completion_value( ecma_CompletionValue_t completion_value);
extern bool ecma_is_completion_value_normal( ecma_CompletionValue_t value);
extern bool ecma_is_completion_value_throw( ecma_CompletionValue_t value);
extern bool ecma_is_completion_value_normal_or_throw( ecma_CompletionValue_t value);
extern bool ecma_is_completion_value_normal_simple_value( ecma_CompletionValue_t value, ecma_SimpleValue_t simple_value);
extern bool ecma_IsCompletionValueNormalFalse( ecma_CompletionValue_t value);
extern bool ecma_IsCompletionValueNormalTrue( ecma_CompletionValue_t value);

View File

@ -38,9 +38,9 @@
* Returned value must be freed with ecma_free_completion_value.
*/
ecma_CompletionValue_t
ecma_op_get_value( ecma_Reference_t *ref_p) /**< ECMA-reference */
ecma_op_get_value( ecma_Reference_t ref) /**< ECMA-reference */
{
const ecma_Value_t base = ref_p->base;
const ecma_Value_t base = ref.base;
const bool is_unresolvable_reference = ecma_IsValueUndefined( base);
const bool has_primitive_base = ( ecma_IsValueBoolean( base)
|| base.m_ValueType == ECMA_TYPE_NUMBER
@ -64,14 +64,14 @@ ecma_op_get_value( ecma_Reference_t *ref_p) /**< ECMA-reference */
JERRY_ASSERT( obj_p != NULL && !obj_p->m_IsLexicalEnvironment );
// GetValue_4.b case 1
/* return [[Get]]( base as this, ref_p->referenced_name_p) */
/* return [[Get]]( base as this, ref.referenced_name_p) */
JERRY_UNIMPLEMENTED();
} else
{ // GetValue_4.b case 2
/*
ecma_Object_t *obj_p = ecma_ToObject( base);
JERRY_ASSERT( obj_p != NULL && !obj_p->m_IsLexicalEnvironment );
ecma_Property_t *property = obj_p->[[GetProperty]]( ref_p->referenced_name_p);
ecma_Property_t *property = obj_p->[[GetProperty]]( ref.referenced_name_p);
if ( property->m_Type == ECMA_PROPERTY_NAMEDDATA )
{
return ecma_MakeCompletionValue( ECMA_COMPLETION_TYPE_NORMAL,
@ -103,7 +103,7 @@ ecma_op_get_value( ecma_Reference_t *ref_p) /**< ECMA-reference */
JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment );
return ecma_OpGetBindingValue( lex_env_p, ref_p->referenced_name_p, ref_p->is_strict);
return ecma_OpGetBindingValue( lex_env_p, ref.referenced_name_p, ref.is_strict);
}
} /* ecma_op_get_value */
@ -116,10 +116,10 @@ ecma_op_get_value( ecma_Reference_t *ref_p) /**< ECMA-reference */
* Returned value must be freed with ecma_free_completion_value.
*/
ecma_CompletionValue_t
ecma_op_put_value(ecma_Reference_t *ref_p, /**< ECMA-reference */
ecma_op_put_value(ecma_Reference_t ref, /**< ECMA-reference */
ecma_Value_t value) /**< ECMA-value */
{
const ecma_Value_t base = ref_p->base;
const ecma_Value_t base = ref.base;
const bool is_unresolvable_reference = ecma_IsValueUndefined( base);
const bool has_primitive_base = ( ecma_IsValueBoolean( base)
|| base.m_ValueType == ECMA_TYPE_NUMBER
@ -130,7 +130,7 @@ ecma_op_put_value(ecma_Reference_t *ref_p, /**< ECMA-reference */
if ( is_unresolvable_reference ) // PutValue_3
{
if ( ref_p->is_strict ) // PutValue_3.a
if ( ref.is_strict ) // PutValue_3.a
{
return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_REFERENCE));
} else // PutValue_3.b
@ -138,7 +138,7 @@ ecma_op_put_value(ecma_Reference_t *ref_p, /**< ECMA-reference */
/*
ecma_Object_t *global_object_p = ecma_GetGlobalObject();
return global_object_p->[[Put]]( ref_p->referenced_name_p, value, false);
return global_object_p->[[Put]]( ref.referenced_name_p, value, false);
*/
JERRY_UNIMPLEMENTED();
@ -149,7 +149,7 @@ ecma_op_put_value(ecma_Reference_t *ref_p, /**< ECMA-reference */
{
// PutValue_4.b case 1
/* return [[Put]]( base as this, ref_p->referenced_name_p, value, ref_p->is_strict); */
/* return [[Put]]( base as this, ref.referenced_name_p, value, ref.is_strict); */
JERRY_UNIMPLEMENTED();
} else
{
@ -161,10 +161,10 @@ ecma_op_put_value(ecma_Reference_t *ref_p, /**< ECMA-reference */
JERRY_ASSERT( obj_p != NULL && !obj_p->m_IsLexicalEnvironment );
// PutValue_sub_2
if ( !obj_p->[[CanPut]]( ref_p->referenced_name_p) )
if ( !obj_p->[[CanPut]]( ref.referenced_name_p) )
{
// PutValue_sub_2.a
if ( ref_p->is_strict )
if ( ref.is_strict )
{
return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_TYPE));
} else
@ -176,13 +176,13 @@ ecma_op_put_value(ecma_Reference_t *ref_p, /**< ECMA-reference */
}
// PutValue_sub_3
ecma_Property_t *own_prop = obj_p->[[GetOwnProperty]]( ref_p->referenced_name_p);
ecma_Property_t *own_prop = obj_p->[[GetOwnProperty]]( ref.referenced_name_p);
// PutValue_sub_4
if ( ecma_OpIsDataDescriptor( own_prop) )
{
// PutValue_sub_4.a
if ( ref_p->is_strict )
if ( ref.is_strict )
{
return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_TYPE));
} else
@ -194,7 +194,7 @@ ecma_op_put_value(ecma_Reference_t *ref_p, /**< ECMA-reference */
}
// PutValue_sub_5
ecma_Property_t *prop = obj_p->[[GetProperty]]( ref_p->referenced_name_p);
ecma_Property_t *prop = obj_p->[[GetProperty]]( ref.referenced_name_p);
// PutValue_sub_6
if ( ecma_OpIsAccessorDescriptor( prop) )
@ -208,7 +208,7 @@ ecma_op_put_value(ecma_Reference_t *ref_p, /**< ECMA-reference */
} else // PutValue_sub_7
{
// PutValue_sub_7.a
if ( ref_p->is_strict )
if ( ref.is_strict )
{
return ecma_MakeThrowValue( ecma_NewStandardError( ECMA_ERROR_TYPE));
}
@ -229,7 +229,7 @@ ecma_op_put_value(ecma_Reference_t *ref_p, /**< ECMA-reference */
JERRY_ASSERT( lex_env_p != NULL && lex_env_p->m_IsLexicalEnvironment );
return ecma_OpSetMutableBinding( lex_env_p, ref_p->referenced_name_p, value, ref_p->is_strict);
return ecma_OpSetMutableBinding( lex_env_p, ref.referenced_name_p, value, ref.is_strict);
}
} /* ecma_op_put_value */

View File

@ -0,0 +1,48 @@
/* 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 "ecma-globals.h"
#include "ecma-number-arithmetic.h"
/** \addtogroup ecma ---TODO---
* @{
*/
/**
* \addtogroup numberarithmetic ECMA number arithmetic operations
* @{
*/
/**
* ECMA-defined number multiplication.
*
* See also:
* ECMA-262 v5, 11.5.1
*
* @return number - result of multiplication.
*/
ecma_Number_t
ecma_op_number_multiply(ecma_Number_t left_num, /**< left operand */
ecma_Number_t right_num) /**< right operand */
{
TODO( Implement according to ECMA );
return left_num * right_num;
} /* ecma_op_number_multiply */
/**
* @}
* @}
*/

View File

@ -0,0 +1,37 @@
/* 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.
*/
#ifndef ECMA_NUMBER_H
#define ECMA_NUMBER_H
#include "ecma-globals.h"
/** \addtogroup ecma ---TODO---
* @{
*/
/**
* \addtogroup numberarithmetic ECMA number arithmetic operations
* @{
*/
extern ecma_Number_t ecma_op_number_multiply( ecma_Number_t left_num, ecma_Number_t right_num);
/**
* @}
* @}
*/
#endif /* ECMA_NUMBER_H */

View File

@ -29,8 +29,8 @@
extern ecma_Reference_t ecma_OpGetIdentifierReference( ecma_Object_t *lex_env_p, ecma_Char_t *name_p, bool is_strict);
extern ecma_CompletionValue_t ecma_op_get_value( ecma_Reference_t *ref_p);
extern ecma_CompletionValue_t ecma_op_put_value( ecma_Reference_t *ref_p, ecma_Value_t value);
extern ecma_CompletionValue_t ecma_op_get_value( ecma_Reference_t ref);
extern ecma_CompletionValue_t ecma_op_put_value( ecma_Reference_t ref, ecma_Value_t value);
/**
* @}

View File

@ -0,0 +1,43 @@
/* 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"
/**
* Unit test's main function.
*/
int
main( int __unused argc,
char __unused **argv)
{
const OPCODE test_program[] = {
getop_var_decl( 0),
getop_var_decl( 1),
getop_assignment( 0, OPCODE_ARG_TYPE_SMALLINT, 253),
getop_assignment( 1, OPCODE_ARG_TYPE_NUMBER, 2),
getop_multiplication( 0, 0, 1),
getop_exitval( 0)
};
mem_Init();
init_int( test_program);
return run_int() ? 0
: 1;
} /* main */