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-conversion.h"
20 #include "ecma-exceptions.h"
21 #include "ecma-gc.h"
22 #include "ecma-globals.h"
23 #include "ecma-helpers.h"
24 #include "ecma-function-object.h"
25 #include "ecma-objects.h"
26 #include "ecma-proxy-object.h"
27 #include "ecma-try-catch-macro.h"
28 #include "jrt.h"
29 #include "ecma-builtin-function-prototype.h"
30
31 #define ECMA_BUILTINS_INTERNAL
32 #include "ecma-builtins-internal.h"
33
34 /**
35 * This object has a custom dispatch function.
36 */
37 #define BUILTIN_CUSTOM_DISPATCH
38
39 /**
40 * List of built-in routine identifiers.
41 */
42 enum
43 {
44 ECMA_FUNCTION_PROTOTYPE_ROUTINE_START = ECMA_BUILTIN_ID__COUNT - 1,
45 ECMA_FUNCTION_PROTOTYPE_TO_STRING,
46 ECMA_FUNCTION_PROTOTYPE_CALL,
47 ECMA_FUNCTION_PROTOTYPE_APPLY,
48 ECMA_FUNCTION_PROTOTYPE_BIND,
49 #if ENABLED (JERRY_ES2015)
50 ECMA_FUNCTION_PROTOTYPE_SYMBOL_HAS_INSTANCE,
51 #endif /* ENABLED (JERRY_ES2015) */
52 };
53
54 #define BUILTIN_INC_HEADER_NAME "ecma-builtin-function-prototype.inc.h"
55 #define BUILTIN_UNDERSCORED_ID function_prototype
56 #include "ecma-builtin-internal-routines-template.inc.h"
57
58 /** \addtogroup ecma ECMA
59 * @{
60 *
61 * \addtogroup ecmabuiltins
62 * @{
63 *
64 * \addtogroup functionprototype ECMA Function.prototype object built-in
65 * @{
66 */
67
68 /**
69 * Maximum number of arguments for an apply function.
70 */
71 #define ECMA_FUNCTION_APPLY_ARGUMENT_COUNT_LIMIT 65535
72
73 /**
74 * The Function.prototype object's 'toString' routine
75 *
76 * See also:
77 * ECMA-262 v5, 15.3.4.2
78 *
79 * @return ecma value
80 * Returned value must be freed with ecma_free_value.
81 */
82 static ecma_value_t
ecma_builtin_function_prototype_object_to_string(void)83 ecma_builtin_function_prototype_object_to_string (void)
84 {
85 return ecma_make_magic_string_value (LIT_MAGIC_STRING__FUNCTION_TO_STRING);
86 } /* ecma_builtin_function_prototype_object_to_string */
87
88 /**
89 * The Function.prototype object's 'apply' routine
90 *
91 * See also:
92 * ECMA-262 v5, 15.3.4.3
93 *
94 * @return ecma value
95 * Returned value must be freed with ecma_free_value.
96 */
97 ecma_value_t
ecma_builtin_function_prototype_object_apply(ecma_object_t * func_obj_p,ecma_value_t arg1,ecma_value_t arg2)98 ecma_builtin_function_prototype_object_apply (ecma_object_t *func_obj_p, /**< this argument object */
99 ecma_value_t arg1, /**< first argument */
100 ecma_value_t arg2) /**< second argument */
101 {
102 /* 2. */
103 if (ecma_is_value_null (arg2) || ecma_is_value_undefined (arg2))
104 {
105 return ecma_op_function_call (func_obj_p, arg1, NULL, 0);
106 }
107
108 /* 3. */
109 if (!ecma_is_value_object (arg2))
110 {
111 return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object."));
112 }
113
114 ecma_object_t *obj_p = ecma_get_object_from_value (arg2);
115
116 /* 4-5. */
117 uint32_t length;
118 ecma_value_t len_value = ecma_op_object_get_length (obj_p, &length);
119
120 if (ECMA_IS_VALUE_ERROR (len_value))
121 {
122 return len_value;
123 }
124
125 if (length >= ECMA_FUNCTION_APPLY_ARGUMENT_COUNT_LIMIT)
126 {
127 return ecma_raise_range_error (ECMA_ERR_MSG ("Too many arguments declared for Function.apply()."));
128 }
129
130 /* 6. */
131 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
132 JMEM_DEFINE_LOCAL_ARRAY (arguments_list_p, length, ecma_value_t);
133 uint32_t index = 0;
134
135 /* 7. */
136 for (index = 0; index < length; index++)
137 {
138 ecma_value_t get_value = ecma_op_object_get_by_uint32_index (obj_p, index);
139
140 if (ECMA_IS_VALUE_ERROR (get_value))
141 {
142 ret_value = get_value;
143 break;
144 }
145
146 arguments_list_p[index] = get_value;
147 }
148
149 if (ecma_is_value_empty (ret_value))
150 {
151 JERRY_ASSERT (index == length);
152 ret_value = ecma_op_function_call (func_obj_p,
153 arg1,
154 arguments_list_p,
155 length);
156 }
157
158 for (uint32_t remove_index = 0; remove_index < index; remove_index++)
159 {
160 ecma_free_value (arguments_list_p[remove_index]);
161 }
162
163 JMEM_FINALIZE_LOCAL_ARRAY (arguments_list_p);
164
165 return ret_value;
166 } /* ecma_builtin_function_prototype_object_apply */
167
168 /**
169 * The Function.prototype object's 'call' routine
170 *
171 * See also:
172 * ECMA-262 v5, 15.3.4.4
173 *
174 * @return ecma value
175 * Returned value must be freed with ecma_free_value.
176 */
177 static ecma_value_t
ecma_builtin_function_prototype_object_call(ecma_object_t * func_obj_p,const ecma_value_t * arguments_list_p,ecma_length_t arguments_number)178 ecma_builtin_function_prototype_object_call (ecma_object_t *func_obj_p , /**< this argument object */
179 const ecma_value_t *arguments_list_p, /**< list of arguments */
180 ecma_length_t arguments_number) /**< number of arguments */
181 {
182 if (arguments_number == 0)
183 {
184 /* Even a 'this' argument is missing. */
185 return ecma_op_function_call (func_obj_p,
186 ECMA_VALUE_UNDEFINED,
187 NULL,
188 0);
189 }
190
191 return ecma_op_function_call (func_obj_p,
192 arguments_list_p[0],
193 arguments_list_p + 1,
194 (ecma_length_t) (arguments_number - 1u));
195 } /* ecma_builtin_function_prototype_object_call */
196
197 /**
198 * The Function.prototype object's 'bind' routine
199 *
200 * See also:
201 * ECMA-262 v5, 15.3.4.5
202 *
203 * @return ecma value
204 * Returned value must be freed with ecma_free_value.
205 */
206 static ecma_value_t
ecma_builtin_function_prototype_object_bind(ecma_object_t * this_arg_obj_p,const ecma_value_t * arguments_list_p,ecma_length_t arguments_number)207 ecma_builtin_function_prototype_object_bind (ecma_object_t *this_arg_obj_p , /**< this argument object */
208 const ecma_value_t *arguments_list_p, /**< list of arguments */
209 ecma_length_t arguments_number) /**< number of arguments */
210 {
211 /* 4. 11. 18. */
212 ecma_object_t *prototype_obj_p;
213
214 #if !ENABLED (JERRY_ES2015)
215 prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
216 #else /* ENABLED (JERRY_ES2015) */
217 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
218 if (ECMA_OBJECT_IS_PROXY (this_arg_obj_p))
219 {
220 ecma_value_t proto = ecma_proxy_object_get_prototype_of (this_arg_obj_p);
221
222 if (ECMA_IS_VALUE_ERROR (proto))
223 {
224 return proto;
225 }
226 prototype_obj_p = ecma_is_value_null (proto) ? NULL : ecma_get_object_from_value (proto);
227 }
228 else
229 {
230 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
231 jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (this_arg_obj_p);
232 if (proto_cp != JMEM_CP_NULL)
233 {
234 prototype_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp);
235 ecma_ref_object (prototype_obj_p);
236 }
237 else
238 {
239 prototype_obj_p = NULL;
240 }
241 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
242 }
243 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
244 #endif /* !ENABLED (JERRY_ES2015) */
245
246 ecma_object_t *function_p;
247 ecma_bound_function_t *bound_func_p;
248
249 if (arguments_number == 0
250 || (arguments_number == 1 && !ecma_is_value_integer_number (arguments_list_p[0])))
251 {
252 function_p = ecma_create_object (prototype_obj_p,
253 sizeof (ecma_bound_function_t),
254 ECMA_OBJECT_TYPE_BOUND_FUNCTION);
255
256 /* 8. */
257 bound_func_p = (ecma_bound_function_t *) function_p;
258 ECMA_SET_NON_NULL_POINTER_TAG (bound_func_p->header.u.bound_function.target_function,
259 this_arg_obj_p,
260 0);
261
262 bound_func_p->header.u.bound_function.args_len_or_this = ECMA_VALUE_UNDEFINED;
263
264 if (arguments_number != 0)
265 {
266 bound_func_p->header.u.bound_function.args_len_or_this = ecma_copy_value_if_not_object (arguments_list_p[0]);
267 }
268 }
269 else
270 {
271 JERRY_ASSERT (arguments_number > 0);
272
273 size_t obj_size = sizeof (ecma_bound_function_t) + (arguments_number * sizeof (ecma_value_t));
274
275 function_p = ecma_create_object (prototype_obj_p,
276 obj_size,
277 ECMA_OBJECT_TYPE_BOUND_FUNCTION);
278
279 /* 8. */
280 bound_func_p = (ecma_bound_function_t *) function_p;
281 ECMA_SET_NON_NULL_POINTER_TAG (bound_func_p->header.u.bound_function.target_function,
282 this_arg_obj_p,
283 0);
284
285 /* NOTE: This solution provides temporary false data about the object's size
286 but prevents GC from freeing it until it's not fully initialized. */
287 bound_func_p->header.u.bound_function.args_len_or_this = ECMA_VALUE_UNDEFINED;
288 ecma_value_t *args_p = (ecma_value_t *) (bound_func_p + 1);
289
290 for (ecma_length_t i = 0; i < arguments_number; i++)
291 {
292 *args_p++ = ecma_copy_value_if_not_object (arguments_list_p[i]);
293 }
294
295 ecma_value_t args_len_or_this = ecma_make_integer_value ((ecma_integer_value_t) arguments_number);
296 bound_func_p->header.u.bound_function.args_len_or_this = args_len_or_this;
297 }
298
299 #if defined(JERRY_FUNCTION_NAME) && !defined(__APPLE__)
300 ecma_object_type_t obj_type = ecma_get_object_type(this_arg_obj_p);
301 if (obj_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION || obj_type == ECMA_OBJECT_TYPE_FUNCTION) {
302 ecma_string_t* name_prop = ecma_get_magic_string (LIT_MAGIC_STRING_NAME);
303 ecma_value_t func_name_value = ecma_op_object_get (this_arg_obj_p, name_prop);
304 if (ecma_find_named_property (function_p, name_prop) == NULL) {
305 ecma_property_value_t* prop_val = ecma_create_named_data_property(function_p, name_prop,
306 ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL);
307 prop_val->value = ecma_copy_value(func_name_value);
308 } else {
309 ecma_deref_ecma_string (name_prop);
310 }
311 }
312 #endif
313
314 #if ENABLED (JERRY_ES2015)
315 ecma_integer_value_t len = 0;
316 ecma_string_t *len_string = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);
317 ecma_property_descriptor_t prop_desc;
318 ecma_value_t status = ecma_op_object_get_own_property_descriptor (this_arg_obj_p,
319 len_string,
320 &prop_desc);
321
322 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
323 if (ECMA_IS_VALUE_ERROR (status))
324 {
325 return status;
326 }
327 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
328
329 if (ecma_is_value_true (status))
330 {
331 ecma_free_property_descriptor (&prop_desc);
332 ecma_value_t len_value = ecma_op_object_get (this_arg_obj_p,
333 len_string);
334
335 if (ECMA_IS_VALUE_ERROR (len_value))
336 {
337 return len_value;
338 }
339
340 if (ecma_is_value_number (len_value))
341 {
342 ecma_number_t len_num;
343 ecma_op_to_integer (len_value, &len_num);
344 len = (ecma_integer_value_t) len_num;
345 }
346 }
347
348 bound_func_p->target_length = len;
349
350 if (prototype_obj_p != NULL)
351 {
352 ecma_deref_object (prototype_obj_p);
353 }
354 #endif /* ENABLED (JERRY_ES2015) */
355
356 /*
357 * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type.
358 *
359 * See also: ecma_object_get_class_name
360 */
361
362 /* 22. */
363 return ecma_make_object_value (function_p);
364 } /* ecma_builtin_function_prototype_object_bind */
365
366 /**
367 * Handle calling [[Call]] of built-in Function.prototype object
368 *
369 * @return ecma value
370 */
371 ecma_value_t
ecma_builtin_function_prototype_dispatch_call(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len)372 ecma_builtin_function_prototype_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */
373 ecma_length_t arguments_list_len) /**< number of arguments */
374 {
375 JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
376
377 return ECMA_VALUE_UNDEFINED;
378 } /* ecma_builtin_function_prototype_dispatch_call */
379
380 /**
381 * Handle calling [[Construct]] of built-in Function.prototype object
382 *
383 * @return ecma value
384 */
385 ecma_value_t
ecma_builtin_function_prototype_dispatch_construct(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len)386 ecma_builtin_function_prototype_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
387 ecma_length_t arguments_list_len) /**< number of arguments */
388 {
389 JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
390
391 return ecma_raise_type_error (ECMA_ERR_MSG ("'Function.prototype' is not a constructor."));
392 } /* ecma_builtin_function_prototype_dispatch_construct */
393
394 /**
395 * Dispatcher of the built-in's routines
396 *
397 * @return ecma value
398 * Returned value must be freed with ecma_free_value.
399 */
400 ecma_value_t
ecma_builtin_function_prototype_dispatch_routine(uint16_t builtin_routine_id,ecma_value_t this_arg,const ecma_value_t arguments_list_p[],ecma_length_t arguments_number)401 ecma_builtin_function_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< built-in wide routine
402 * identifier */
403 ecma_value_t this_arg, /**< 'this' argument value */
404 const ecma_value_t arguments_list_p[], /**< list of arguments
405 * passed to routine */
406 ecma_length_t arguments_number) /**< length of arguments' list */
407 {
408 if (!ecma_op_is_callable (this_arg))
409 {
410 #if ENABLED (JERRY_ES2015)
411 if (JERRY_UNLIKELY (builtin_routine_id == ECMA_FUNCTION_PROTOTYPE_SYMBOL_HAS_INSTANCE))
412 {
413 return ECMA_VALUE_FALSE;
414 }
415 #endif /* ENABLED (JERRY_ES2015) */
416
417 return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a function."));
418 }
419
420 ecma_object_t *func_obj_p = ecma_get_object_from_value (this_arg);
421
422 switch (builtin_routine_id)
423 {
424 case ECMA_FUNCTION_PROTOTYPE_TO_STRING:
425 {
426 return ecma_builtin_function_prototype_object_to_string ();
427 }
428 case ECMA_FUNCTION_PROTOTYPE_APPLY:
429 {
430 return ecma_builtin_function_prototype_object_apply (func_obj_p,
431 arguments_list_p[0],
432 arguments_list_p[1]);
433 }
434 case ECMA_FUNCTION_PROTOTYPE_CALL:
435 {
436 return ecma_builtin_function_prototype_object_call (func_obj_p, arguments_list_p, arguments_number);
437 }
438 case ECMA_FUNCTION_PROTOTYPE_BIND:
439 {
440 return ecma_builtin_function_prototype_object_bind (func_obj_p, arguments_list_p, arguments_number);
441 }
442 #if ENABLED (JERRY_ES2015)
443 case ECMA_FUNCTION_PROTOTYPE_SYMBOL_HAS_INSTANCE:
444 {
445 return ecma_op_object_has_instance (func_obj_p, arguments_list_p[0]);
446 }
447 #endif /* ENABLED (JERRY_ES2015) */
448 default:
449 {
450 JERRY_UNREACHABLE ();
451 }
452 }
453 } /* ecma_builtin_function_prototype_dispatch_routine */
454
455 /**
456 * @}
457 * @}
458 * @}
459 */
460