diff --git a/src/libcoreint/opcodes.c b/src/libcoreint/opcodes.c index a74811914..6fde8d637 100644 --- a/src/libcoreint/opcodes.c +++ b/src/libcoreint/opcodes.c @@ -243,6 +243,78 @@ set_variable_value(struct __int_data *int_data, /**< interpreter context */ return ret_value; } /* set_variable_value */ +/** + * Number arithmetic operations. + */ +typedef enum +{ + number_arithmetic_addition, /**< addition */ + number_arithmetic_substraction, /**< substraction */ + number_arithmetic_multiplication, /**< multiplication */ + number_arithmetic_division, /**< division */ + number_arithmetic_remainder, /**< remainder calculation */ +} number_arithmetic_op; + +/** + * Perform ECMA number arithmetic operation. + * + * The algorithm of the operation is following: + * leftNum = ToNumber( leftValue); + * rightNum = ToNumber( rightValue); + * result = leftNum ArithmeticOp rightNum; + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +static ecma_CompletionValue_t +do_number_arithmetic(struct __int_data *int_data, /**< interpreter context */ + T_IDX dst_var_idx, /**< destination variable identifier */ + number_arithmetic_op op, /**< number arithmetic operation */ + ecma_Value_t left_value, /**< left value */ + ecma_Value_t right_value) /** right value */ +{ + ecma_CompletionValue_t ret_value; + + TRY_CATCH(num_left_value, ecma_op_to_number( left_value), ret_value); + TRY_CATCH(num_right_value, ecma_op_to_number( right_value), ret_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(); + + switch ( op ) + { + case number_arithmetic_addition: + *res_p = ecma_op_number_add( *left_p, *right_p); + break; + case number_arithmetic_substraction: + *res_p = ecma_op_number_substract( *left_p, *right_p); + break; + case number_arithmetic_multiplication: + *res_p = ecma_op_number_multiply( *left_p, *right_p); + break; + case number_arithmetic_division: + *res_p = ecma_op_number_divide( *left_p, *right_p); + break; + case number_arithmetic_remainder: + *res_p = ecma_op_number_remainder( *left_p, *right_p); + break; + } + + ret_value = set_variable_value(int_data, + dst_var_idx, + ecma_MakeNumberValue( res_p)); + + ecma_DeallocNumber( res_p); + + FINALIZE( num_right_value); + FINALIZE( num_left_value); + + return ret_value; +} /* do_number_arithmetic */ + #define OP_UNIMPLEMENTED_LIST(op) \ op(is_true_jmp) \ op(is_false_jmp) \ @@ -281,8 +353,6 @@ set_variable_value(struct __int_data *int_data, /**< interpreter context */ op(greater_or_equal_than) \ op(addition) \ op(substraction) \ - op(division) \ - op(remainder) \ op(jmp_up) \ op(jmp_down) \ op(nop) @@ -444,7 +514,7 @@ opfunc_assignment (OPCODE opdata, /**< operation data */ } /* opfunc_assignment */ /** - * Multiplicatoin opcode handler. + * Multiplication opcode handler. * * See also: ECMA-262 v5, 11.5, 11.5.1 * @@ -452,8 +522,8 @@ opfunc_assignment (OPCODE opdata, /**< operation data */ * 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 */ +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; @@ -465,30 +535,89 @@ opfunc_multiplication (OPCODE opdata, /**< operation data */ TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); - TRY_CATCH(num_left_value, ecma_op_to_number( left_value.value), ret_value); - TRY_CATCH(num_right_value, ecma_op_to_number( right_value.value), ret_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); + ret_value = do_number_arithmetic(int_data, + dst_var_idx, + number_arithmetic_multiplication, + left_value.value, + right_value.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); - - FINALIZE( num_right_value); - FINALIZE( num_left_value); - FINALIZE( right_value); - FINALIZE( left_value); + FINALIZE(right_value); + FINALIZE(left_value); return ret_value; } /* opfunc_multiplication */ +/** + * Division opcode handler. + * + * See also: ECMA-262 v5, 11.5, 11.5.2 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +ecma_CompletionValue_t +opfunc_division(OPCODE opdata, /**< operation data */ + struct __int_data *int_data) /**< interpreter context */ +{ + const T_IDX dst_var_idx = opdata.data.division.dst; + const T_IDX left_var_idx = opdata.data.division.var_left; + const T_IDX right_var_idx = opdata.data.division.var_right; + + int_data->pos++; + + ecma_CompletionValue_t ret_value; + + TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); + TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); + + ret_value = do_number_arithmetic(int_data, + dst_var_idx, + number_arithmetic_division, + left_value.value, + right_value.value); + + FINALIZE(right_value); + FINALIZE(left_value); + + return ret_value; +} /* opfunc_division */ + +/** + * Remainder calculation opcode handler. + * + * See also: ECMA-262 v5, 11.5, 11.5.3 + * + * @return completion value + * Returned value must be freed with ecma_free_completion_value + */ +ecma_CompletionValue_t +opfunc_remainder(OPCODE opdata, /**< operation data */ + struct __int_data *int_data) /**< interpreter context */ +{ + const T_IDX dst_var_idx = opdata.data.remainder.dst; + const T_IDX left_var_idx = opdata.data.remainder.var_left; + const T_IDX right_var_idx = opdata.data.remainder.var_right; + + int_data->pos++; + + ecma_CompletionValue_t ret_value; + + TRY_CATCH(left_value, get_variable_value( int_data, left_var_idx, false), ret_value); + TRY_CATCH(right_value, get_variable_value( int_data, right_var_idx, false), ret_value); + + ret_value = do_number_arithmetic(int_data, + dst_var_idx, + number_arithmetic_remainder, + left_value.value, + right_value.value); + + FINALIZE(right_value); + FINALIZE(left_value); + + return ret_value; +} /* opfunc_remainder */ + /** * Variable declaration opcode handler. * diff --git a/src/libecmaoperations/ecma-number-arithmetic.c b/src/libecmaoperations/ecma-number-arithmetic.c index 010be2e78..31d040253 100644 --- a/src/libecmaoperations/ecma-number-arithmetic.c +++ b/src/libecmaoperations/ecma-number-arithmetic.c @@ -103,7 +103,11 @@ ecma_Number_t ecma_op_number_remainder(ecma_Number_t left_num, /**< left operand */ ecma_Number_t right_num) /**< right operand */ { - JERRY_UNIMPLEMENTED_REF_UNUSED_VARS( left_num, right_num); + TODO( Implement according to ECMA ); + + ecma_Number_t n = left_num, d = right_num; + + return ( n - d * (ecma_Number_t)( (int32_t)( n / d ) ) ); } /* ecma_op_number_remainder */ /** diff --git a/tests/unit/test_division_opcode.c b/tests/unit/test_division_opcode.c new file mode 100644 index 000000000..f37444e98 --- /dev/null +++ b/tests/unit/test_division_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_division( 0, 0, 1), + getop_exitval( 0) + }; + + mem_Init(); + + init_int( test_program); + + return run_int() ? 0 + : 1; +} /* main */ diff --git a/tests/unit/test_remainder_opcode.c b/tests/unit/test_remainder_opcode.c new file mode 100644 index 000000000..abdeb95df --- /dev/null +++ b/tests/unit/test_remainder_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_remainder( 0, 0, 1), + getop_exitval( 0) + }; + + mem_Init(); + + init_int( test_program); + + return run_int() ? 0 + : 1; +} /* main */