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 */
42 void
ecma_op_create_arguments_object(ecma_object_t * func_obj_p,ecma_object_t * lex_env_p,const ecma_value_t * arguments_list_p,ecma_length_t arguments_number,const ecma_compiled_code_t * bytecode_data_p)43 ecma_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 */
232 ecma_value_t
ecma_op_arguments_object_define_own_property(ecma_object_t * object_p,ecma_string_t * property_name_p,const ecma_property_descriptor_t * property_desc_p)233 ecma_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 */
313 ecma_value_t
ecma_op_arguments_object_delete(ecma_object_t * object_p,ecma_string_t * property_name_p,bool is_throw)314 ecma_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