diff --git a/src/libcoreint/opcodes.c b/src/libcoreint/opcodes.c index 5961db133..57d1391bd 100644 --- a/src/libcoreint/opcodes.c +++ b/src/libcoreint/opcodes.c @@ -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. * diff --git a/src/libecmaobjects/ecma-helpers-value.c b/src/libecmaobjects/ecma-helpers-value.c index 455340df1..d3df38180 100644 --- a/src/libecmaobjects/ecma-helpers-value.c +++ b/src/libecmaobjects/ecma-helpers-value.c @@ -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. * diff --git a/src/libecmaobjects/ecma-helpers.h b/src/libecmaobjects/ecma-helpers.h index dbe890bd1..0168dc04b 100644 --- a/src/libecmaobjects/ecma-helpers.h +++ b/src/libecmaobjects/ecma-helpers.h @@ -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); diff --git a/src/libecmaoperations/ecma-get-put-value.c b/src/libecmaoperations/ecma-get-put-value.c index a6879269c..12cd2fbae 100644 --- a/src/libecmaoperations/ecma-get-put-value.c +++ b/src/libecmaoperations/ecma-get-put-value.c @@ -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 */ diff --git a/src/libecmaoperations/ecma-number-arithmetic.c b/src/libecmaoperations/ecma-number-arithmetic.c new file mode 100644 index 000000000..31244c241 --- /dev/null +++ b/src/libecmaoperations/ecma-number-arithmetic.c @@ -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 */ + +/** + * @} + * @} + */ diff --git a/src/libecmaoperations/ecma-number-arithmetic.h b/src/libecmaoperations/ecma-number-arithmetic.h new file mode 100644 index 000000000..9477b1d5f --- /dev/null +++ b/src/libecmaoperations/ecma-number-arithmetic.h @@ -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 */ diff --git a/src/libecmaoperations/ecma-operations.h b/src/libecmaoperations/ecma-operations.h index a2629664e..cec8a8edf 100644 --- a/src/libecmaoperations/ecma-operations.h +++ b/src/libecmaoperations/ecma-operations.h @@ -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); /** * @} diff --git a/tests/unit/test_multiplication_opcode.c b/tests/unit/test_multiplication_opcode.c new file mode 100644 index 000000000..b02b164cf --- /dev/null +++ b/tests/unit/test_multiplication_opcode.c @@ -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 */