• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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