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-builtin-helpers.h"
18#include "ecma-builtins.h"
19#include "ecma-function-object.h"
20#include "ecma-gc.h"
21#include "ecma-globals.h"
22#include "ecma-helpers.h"
23#include "ecma-lex-env.h"
24#include "ecma-objects.h"
25#include "ecma-objects-arguments.h"
26#include "ecma-objects-general.h"
27#include "ecma-try-catch-macro.h"
28#include "jrt.h"
29
30/** \addtogroup ecma ECMA
31 * @{
32 *
33 * \addtogroup ecmafunctionobject ECMA Function object related routines
34 * @{
35 */
36
37/**
38 * Arguments object creation operation.
39 *
40 * See also: ECMA-262 v5, 10.6
41 */
42void
43ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function */
44                                 ecma_object_t *lex_env_p, /**< lexical environment the Arguments
45                                                                object is created for */
46                                 const ecma_value_t *arguments_list_p, /**< arguments list */
47                                 ecma_length_t arguments_number, /**< length of arguments list */
48                                 const ecma_compiled_code_t *bytecode_data_p) /**< byte code */
49{
50  bool is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0;
51
52  ecma_length_t formal_params_number;
53
54  if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
55  {
56    cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_data_p;
57
58    formal_params_number = args_p->argument_end;
59  }
60  else
61  {
62    cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_data_p;
63
64    formal_params_number = args_p->argument_end;
65  }
66
67  ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
68
69  ecma_object_t *obj_p;
70
71  if ((bytecode_data_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)
72      && arguments_number > 0
73      && formal_params_number > 0)
74  {
75    size_t formal_params_size = formal_params_number * sizeof (ecma_value_t);
76
77    obj_p = ecma_create_object (prototype_p,
78                                sizeof (ecma_extended_object_t) + formal_params_size,
79                                ECMA_OBJECT_TYPE_PSEUDO_ARRAY);
80
81    ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
82
83    ext_object_p->u.pseudo_array.type = ECMA_PSEUDO_ARRAY_ARGUMENTS;
84
85    ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.pseudo_array.u2.lex_env_cp, lex_env_p);
86
87    ext_object_p->u.pseudo_array.u1.length = (uint16_t) formal_params_number;
88
89    ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
90
91    uint8_t *byte_p = (uint8_t *) bytecode_data_p;
92    byte_p += ((size_t) bytecode_data_p->size) << JMEM_ALIGNMENT_LOG;
93    byte_p -= formal_params_size;
94
95    memcpy (arg_Literal_p, byte_p, formal_params_size);
96
97    for (ecma_length_t i = 0; i < formal_params_number; i++)
98    {
99      if (arg_Literal_p[i] != ECMA_VALUE_EMPTY)
100      {
101        ecma_string_t *name_p = ecma_get_string_from_value (arg_Literal_p[i]);
102        ecma_ref_ecma_string (name_p);
103      }
104    }
105  }
106  else
107  {
108    obj_p = ecma_create_object (prototype_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS);
109
110    ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
111    ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_ARGUMENTS_UL;
112  }
113
114  ecma_property_value_t *prop_value_p;
115
116  /* 11.a, 11.b */
117  for (ecma_length_t index = 0;
118       index < arguments_number;
119       index++)
120  {
121    ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
122
123    prop_value_p = ecma_create_named_data_property (obj_p,
124                                                    index_string_p,
125                                                    ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
126                                                    NULL);
127
128    prop_value_p->value = ecma_copy_value_if_not_object (arguments_list_p[index]);
129
130    ecma_deref_ecma_string (index_string_p);
131  }
132
133  /* 7. */
134  prop_value_p = ecma_create_named_data_property (obj_p,
135                                                  ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH),
136                                                  ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
137                                                  NULL);
138
139  prop_value_p->value = ecma_make_uint32_value (arguments_number);
140
141  ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
142
143#if ENABLED (JERRY_ES2015)
144  /* ECMAScript v6, 9.4.4.6.7, 9.4.4.7.22 */
145  ecma_string_t *symbol_p = ecma_op_get_global_symbol (LIT_GLOBAL_SYMBOL_ITERATOR);
146
147  prop_value_p = ecma_create_named_data_property (obj_p,
148                                                  symbol_p,
149                                                  ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
150                                                  NULL);
151  ecma_deref_ecma_string (symbol_p);
152  prop_value_p->value = ecma_op_object_get_by_magic_id (ecma_builtin_get (ECMA_BUILTIN_ID_INTRINSIC_OBJECT),
153                                                        LIT_INTERNAL_MAGIC_STRING_ARRAY_PROTOTYPE_VALUES);
154
155  JERRY_ASSERT (ecma_is_value_object (prop_value_p->value));
156  ecma_deref_object (ecma_get_object_from_value (prop_value_p->value));
157#endif /* ENABLED (JERRY_ES2015) */
158
159  /* 13. */
160  if (!is_strict)
161  {
162    prop_value_p = ecma_create_named_data_property (obj_p,
163                                                    ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE),
164                                                    ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
165                                                    NULL);
166
167    prop_value_p->value = ecma_make_object_value (func_obj_p);
168  }
169  else
170  {
171    ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);
172
173    /* 14. */
174    prop_desc = ecma_make_empty_property_descriptor ();
175    {
176      prop_desc.flags = (ECMA_PROP_IS_GET_DEFINED
177                         | ECMA_PROP_IS_SET_DEFINED
178                         | ECMA_PROP_IS_ENUMERABLE_DEFINED
179                         | ECMA_PROP_IS_CONFIGURABLE_DEFINED);
180    }
181    prop_desc.set_p = thrower_p;
182    prop_desc.get_p = thrower_p;
183
184    ecma_value_t completion = ecma_op_object_define_own_property (obj_p,
185                                                                  ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE),
186                                                                  &prop_desc);
187
188    JERRY_ASSERT (ecma_is_value_true (completion));
189
190    completion = ecma_op_object_define_own_property (obj_p,
191                                                     ecma_get_magic_string (LIT_MAGIC_STRING_CALLER),
192                                                     &prop_desc);
193    JERRY_ASSERT (ecma_is_value_true (completion));
194  }
195
196  ecma_string_t *arguments_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
197
198  if (is_strict)
199  {
200    ecma_op_create_immutable_binding (lex_env_p,
201                                      arguments_string_p,
202                                      ecma_make_object_value (obj_p));
203  }
204  else
205  {
206    ecma_value_t completion = ecma_op_create_mutable_binding (lex_env_p,
207                                                              arguments_string_p,
208                                                              false);
209    JERRY_ASSERT (ecma_is_value_empty (completion));
210
211    completion = ecma_op_set_mutable_binding (lex_env_p,
212                                              arguments_string_p,
213                                              ecma_make_object_value (obj_p),
214                                              false);
215
216    JERRY_ASSERT (ecma_is_value_empty (completion));
217  }
218
219  ecma_deref_object (obj_p);
220} /* ecma_op_create_arguments_object */
221
222/**
223 * [[DefineOwnProperty]] ecma Arguments object's operation
224 *
225 * See also:
226 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
227 *          ECMA-262 v5, 10.6
228 *
229 * @return ecma value
230 *         Returned value must be freed with ecma_free_value
231 */
232ecma_value_t
233ecma_op_arguments_object_define_own_property (ecma_object_t *object_p, /**< the object */
234                                              ecma_string_t *property_name_p, /**< property name */
235                                              const ecma_property_descriptor_t *property_desc_p) /**< property
236                                                                                                  *   descriptor */
237{
238  /* 3. */
239  ecma_value_t ret_value = ecma_op_general_object_define_own_property (object_p,
240                                                                       property_name_p,
241                                                                       property_desc_p);
242
243  if (ECMA_IS_VALUE_ERROR (ret_value))
244  {
245    return ret_value;
246  }
247
248  uint32_t index = ecma_string_get_array_index (property_name_p);
249
250  if (index == ECMA_STRING_NOT_ARRAY_INDEX)
251  {
252    return ret_value;
253  }
254
255  ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
256
257  if (index >= ext_object_p->u.pseudo_array.u1.length)
258  {
259    return ret_value;
260  }
261
262  ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
263
264  if (arg_Literal_p[index] == ECMA_VALUE_EMPTY)
265  {
266    return ret_value;
267  }
268
269  ecma_string_t *name_p = ecma_get_string_from_value (arg_Literal_p[index]);
270
271  if (property_desc_p->flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED))
272  {
273    ecma_deref_ecma_string (name_p);
274    arg_Literal_p[index] = ECMA_VALUE_EMPTY;
275  }
276  else
277  {
278    if (property_desc_p->flags & ECMA_PROP_IS_VALUE_DEFINED)
279    {
280      /* emulating execution of function described by MakeArgSetter */
281      ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
282                                                                  ext_object_p->u.pseudo_array.u2.lex_env_cp);
283
284      ecma_value_t completion = ecma_op_set_mutable_binding (lex_env_p,
285                                                             name_p,
286                                                             property_desc_p->value,
287                                                             true);
288
289      JERRY_ASSERT (ecma_is_value_empty (completion));
290    }
291
292    if ((property_desc_p->flags & ECMA_PROP_IS_WRITABLE_DEFINED)
293        && !(property_desc_p->flags & ECMA_PROP_IS_WRITABLE))
294    {
295      ecma_deref_ecma_string (name_p);
296      arg_Literal_p[index] = ECMA_VALUE_EMPTY;
297    }
298  }
299
300  return ret_value;
301} /* ecma_op_arguments_object_define_own_property */
302
303/**
304 * [[Delete]] ecma Arguments object's operation
305 *
306 * See also:
307 *          ECMA-262 v5, 8.6.2; ECMA-262 v5, Table 8
308 *          ECMA-262 v5, 10.6
309 *
310 * @return ecma value
311 *         Returned value must be freed with ecma_free_value
312 */
313ecma_value_t
314ecma_op_arguments_object_delete (ecma_object_t *object_p, /**< the object */
315                                 ecma_string_t *property_name_p, /**< property name */
316                                 bool is_throw) /**< flag that controls failure handling */
317{
318  /* 3. */
319  ecma_value_t ret_value = ecma_op_general_object_delete (object_p, property_name_p, is_throw);
320
321  if (ECMA_IS_VALUE_ERROR (ret_value))
322  {
323    return ret_value;
324  }
325
326  JERRY_ASSERT (ecma_is_value_boolean (ret_value));
327
328  if (ecma_is_value_true (ret_value))
329  {
330    uint32_t index = ecma_string_get_array_index (property_name_p);
331
332    if (index != ECMA_STRING_NOT_ARRAY_INDEX)
333    {
334      ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
335
336      if (index < ext_object_p->u.pseudo_array.u1.length)
337      {
338        ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1);
339
340        if (arg_Literal_p[index] != ECMA_VALUE_EMPTY)
341        {
342          ecma_string_t *name_p = ecma_get_string_from_value (arg_Literal_p[index]);
343          ecma_deref_ecma_string (name_p);
344          arg_Literal_p[index] = ECMA_VALUE_EMPTY;
345        }
346      }
347    }
348
349    ret_value = ECMA_VALUE_TRUE;
350  }
351
352  return ret_value;
353} /* ecma_op_arguments_object_delete */
354
355/**
356 * @}
357 * @}
358 */
359