1/* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecma-alloc.h"
17#include "ecma-conversion.h"
18#include "ecma-helpers.h"
19#include "ecma-number-arithmetic.h"
20#include "ecma-objects.h"
21#include "ecma-try-catch-macro.h"
22#include "opcodes.h"
23#include "jrt-libc-includes.h"
24
25/** \addtogroup vm Virtual machine
26 * @{
27 *
28 * \addtogroup vm_opcodes Opcodes
29 * @{
30 */
31
32/**
33 * Perform ECMA number arithmetic operation.
34 *
35 * The algorithm of the operation is following:
36 *   leftNum = ToNumber (leftValue);
37 *   rightNum = ToNumber (rightValue);
38 *   result = leftNum ArithmeticOp rightNum;
39 *
40 * @return ecma value
41 *         Returned value must be freed with ecma_free_value
42 */
43ecma_value_t
44do_number_arithmetic (number_arithmetic_op op, /**< number arithmetic operation */
45                      ecma_value_t left_value, /**< left value */
46                      ecma_value_t right_value) /**< right value */
47{
48  ecma_value_t ret_value = ECMA_VALUE_EMPTY;
49
50  ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
51  ECMA_OP_TO_NUMBER_TRY_CATCH (num_right, right_value, ret_value);
52
53  ecma_number_t result = ECMA_NUMBER_ZERO;
54
55  switch (op)
56  {
57    case NUMBER_ARITHMETIC_SUBTRACTION:
58    {
59      result = num_left - num_right;
60      break;
61    }
62    case NUMBER_ARITHMETIC_MULTIPLICATION:
63    {
64      result = num_left * num_right;
65      break;
66    }
67    case NUMBER_ARITHMETIC_DIVISION:
68    {
69      result = num_left / num_right;
70      break;
71    }
72    case NUMBER_ARITHMETIC_REMAINDER:
73    {
74      result = ecma_op_number_remainder (num_left, num_right);
75      break;
76    }
77#if ENABLED (JERRY_ES2015)
78    case NUMBER_ARITHMETIC_EXPONENTIATION:
79    {
80      result = ecma_number_pow (num_left, num_right);
81      break;
82    }
83#endif /* ENABLED (JERRY_ES2015) */
84  }
85
86  ret_value = ecma_make_number_value (result);
87
88  ECMA_OP_TO_NUMBER_FINALIZE (num_right);
89  ECMA_OP_TO_NUMBER_FINALIZE (num_left);
90
91  return ret_value;
92} /* do_number_arithmetic */
93
94/**
95 * 'Addition' opcode handler.
96 *
97 * See also: ECMA-262 v5, 11.6.1
98 *
99 * @return ecma value
100 *         Returned value must be freed with ecma_free_value
101 */
102ecma_value_t
103opfunc_addition (ecma_value_t left_value, /**< left value */
104                 ecma_value_t right_value) /**< right value */
105{
106  bool free_left_value = false;
107  bool free_right_value = false;
108
109  if (ecma_is_value_object (left_value))
110  {
111    ecma_object_t *obj_p = ecma_get_object_from_value (left_value);
112    left_value = ecma_op_object_default_value (obj_p, ECMA_PREFERRED_TYPE_NO);
113    free_left_value = true;
114
115    if (ECMA_IS_VALUE_ERROR (left_value))
116    {
117      return left_value;
118    }
119  }
120
121  if (ecma_is_value_object (right_value))
122  {
123    ecma_object_t *obj_p = ecma_get_object_from_value (right_value);
124    right_value = ecma_op_object_default_value (obj_p, ECMA_PREFERRED_TYPE_NO);
125    free_right_value = true;
126
127    if (ECMA_IS_VALUE_ERROR (right_value))
128    {
129      if (free_left_value)
130      {
131        ecma_free_value (left_value);
132      }
133      return right_value;
134    }
135  }
136
137  ecma_value_t ret_value = ECMA_VALUE_EMPTY;
138
139  if (ecma_is_value_string (left_value)
140      || ecma_is_value_string (right_value))
141  {
142    ecma_string_t *string1_p = ecma_op_to_string (left_value);
143
144    if (JERRY_UNLIKELY (string1_p == NULL))
145    {
146      if (free_left_value)
147      {
148        ecma_free_value (left_value);
149      }
150      if (free_right_value)
151      {
152        ecma_free_value (right_value);
153      }
154      return ECMA_VALUE_ERROR;
155    }
156
157    ecma_string_t *string2_p = ecma_op_to_string (right_value);
158
159    if (JERRY_UNLIKELY (string2_p == NULL))
160    {
161      if (free_right_value)
162      {
163        ecma_free_value (right_value);
164      }
165      if (free_left_value)
166      {
167        ecma_free_value (left_value);
168      }
169      ecma_deref_ecma_string (string1_p);
170      return ECMA_VALUE_ERROR;
171    }
172
173    string1_p = ecma_concat_ecma_strings (string1_p, string2_p);
174    ret_value = ecma_make_string_value (string1_p);
175
176    ecma_deref_ecma_string (string2_p);
177  }
178  else
179  {
180    ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
181    ECMA_OP_TO_NUMBER_TRY_CATCH (num_right, right_value, ret_value);
182
183    ret_value = ecma_make_number_value (num_left + num_right);
184
185    ECMA_OP_TO_NUMBER_FINALIZE (num_right);
186    ECMA_OP_TO_NUMBER_FINALIZE (num_left);
187  }
188
189  if (free_left_value)
190  {
191    ecma_free_value (left_value);
192  }
193
194  if (free_right_value)
195  {
196    ecma_free_value (right_value);
197  }
198
199  return ret_value;
200} /* opfunc_addition */
201
202/**
203 * Unary operation opcode handler.
204 *
205 * See also: ECMA-262 v5, 11.4, 11.4.6, 11.4.7
206 *
207 * @return ecma value
208 *         Returned value must be freed with ecma_free_value
209 */
210ecma_value_t
211opfunc_unary_operation (ecma_value_t left_value, /**< left value */
212                        bool is_plus) /**< unary plus flag */
213{
214  ecma_value_t ret_value = ECMA_VALUE_EMPTY;
215
216  ECMA_OP_TO_NUMBER_TRY_CATCH (num_var_value,
217                               left_value,
218                               ret_value);
219
220  ret_value = ecma_make_number_value (is_plus ? num_var_value : -num_var_value);
221
222  ECMA_OP_TO_NUMBER_FINALIZE (num_var_value);
223
224  return ret_value;
225} /* opfunc_unary_operation */
226
227/**
228 * @}
229 * @}
230 */
231