Skip to content

Commit 79ae006

Browse files
author
Zsolt Borbély
committed
Implement Function.prototype.bind function
JerryScript-DCO-1.0-Signed-off-by: Zsolt Borbély [email protected]
1 parent cadc8f4 commit 79ae006

File tree

6 files changed

+422
-13
lines changed

6 files changed

+422
-13
lines changed

jerry-core/ecma/base/ecma-gc.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,31 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
331331
case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31: /* an integer (bit-mask) */
332332
case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63: /* an integer (bit-mask) */
333333
case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE:
334+
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION:
335+
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS:
334336
{
335337
break;
336338
}
337339

340+
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS:
341+
{
342+
ecma_value_t *arg_list_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, property_value);
343+
ecma_number_t *count_p = ecma_get_number_from_value (arg_list_p[0]);
344+
const uint32_t count = ecma_number_to_uint32 (*count_p);
345+
346+
for (uint32_t i = 1; i <= count; i++)
347+
{
348+
if (ecma_is_value_object (arg_list_p[i]))
349+
{
350+
ecma_object_t *obj_p = ecma_get_object_from_value (arg_list_p[i]);
351+
352+
ecma_gc_set_object_visited (obj_p, true);
353+
}
354+
}
355+
356+
break;
357+
}
358+
338359
case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */
339360
case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */
340361
{

jerry-core/ecma/base/ecma-globals.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,11 @@ typedef enum
245245
/** Identifier of implementation-defined extension object */
246246
ECMA_INTERNAL_PROPERTY_EXTENSION_ID,
247247

248+
/** Bound function internal properties **/
249+
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION,
250+
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS,
251+
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS,
252+
248253
/**
249254
* Bit-mask of non-instantiated built-in's properties (bits 0-31)
250255
*/

jerry-core/ecma/base/ecma-helpers.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,10 +800,28 @@ ecma_free_internal_property (ecma_property_t *property_p) /**< the property */
800800
case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */
801801
case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31: /* an integer (bit-mask) */
802802
case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63: /* an integer (bit-mask) */
803+
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION:
804+
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS:
803805
{
804806
break;
805807
}
806808

809+
case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS:
810+
{
811+
ecma_value_t *arg_list_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, property_value);
812+
ecma_number_t *count_p = ecma_get_number_from_value (arg_list_p[0]);
813+
const uint32_t count = ecma_number_to_uint32 (*count_p);
814+
815+
for (uint32_t i = 0; i <= count; i++)
816+
{
817+
ecma_free_value (arg_list_p[i], false);
818+
}
819+
820+
mem_heap_free_block (arg_list_p);
821+
822+
break;
823+
}
824+
807825
case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type,
808826
* but number of the real internal property types */
809827
{

jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.cpp

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,151 @@ ecma_builtin_function_prototype_object_bind (ecma_value_t this_arg, /**< this ar
226226
const ecma_value_t* arguments_list_p, /**< list of arguments */
227227
ecma_length_t arguments_number) /**< number of arguments */
228228
{
229-
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arguments_list_p, arguments_number);
229+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
230+
231+
/* 2. */
232+
if (!ecma_op_is_callable (this_arg))
233+
{
234+
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
235+
}
236+
else
237+
{
238+
/* 4. 11. 18. */
239+
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
240+
ecma_object_t *function_p = ecma_create_object (prototype_obj_p, true, ECMA_OBJECT_TYPE_BOUND_FUNCTION);
241+
242+
ecma_deref_object (prototype_obj_p);
243+
244+
/* 7. */
245+
ecma_property_t *target_function_prop_p;
246+
target_function_prop_p = ecma_create_internal_property (function_p,
247+
ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION);
248+
249+
target_function_prop_p->u.internal_property.value = ecma_copy_value (this_arg, false);
250+
251+
/* 8. */
252+
ecma_property_t *bound_this_prop_p;
253+
bound_this_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS);
254+
255+
size_t arg_list_size;
256+
257+
if (arguments_number > 0)
258+
{
259+
bound_this_prop_p->u.internal_property.value = ecma_copy_value (arguments_list_p[0], false);
260+
261+
arg_list_size = (size_t) (arguments_number) * sizeof (ecma_value_t);
262+
}
263+
else
264+
{
265+
ecma_object_t *glob_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL);
266+
bound_this_prop_p->u.internal_property.value = ecma_copy_value (ecma_make_object_value (glob_obj_p), false);
267+
ecma_deref_object (glob_obj_p);
268+
269+
arg_list_size = (size_t) sizeof (ecma_value_t);
270+
}
271+
272+
/* 9. */
273+
ecma_value_t *arg_list = static_cast <ecma_value_t *> (mem_heap_alloc_block (arg_list_size,
274+
MEM_HEAP_ALLOC_SHORT_TERM));
275+
276+
ecma_number_t *count = ecma_alloc_number ();
277+
*count = ecma_uint32_to_number (arguments_number);
278+
279+
if (arguments_number > 0)
280+
{
281+
(*count)--;
282+
}
283+
284+
/*
285+
* Set the first element of the arguments array to the count of optional arguments.
286+
* We need the number of bounded arguments, when the target function is called.
287+
*/
288+
arg_list[0] = ecma_make_number_value (count);
289+
290+
for (uint32_t i = 1; i < arguments_number; i++)
291+
{
292+
arg_list[i] = ecma_copy_value (arguments_list_p[i], false);
293+
}
294+
295+
ecma_property_t *bound_args_prop_p;
296+
bound_args_prop_p = ecma_create_internal_property (function_p, ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS);
297+
ECMA_SET_POINTER (bound_args_prop_p->u.internal_property.value, arg_list);
298+
299+
/*
300+
* [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type.
301+
*
302+
* See also: ecma_object_get_class_name
303+
*/
304+
305+
/* 17. */
306+
ecma_number_t *length_p = ecma_alloc_number ();
307+
*length_p = 0;
308+
309+
ecma_property_descriptor_t length_prop_desc = ecma_make_empty_property_descriptor ();
310+
length_prop_desc.is_value_defined = true;
311+
length_prop_desc.value = ecma_make_number_value (length_p);
312+
313+
length_prop_desc.is_writable_defined = true;
314+
length_prop_desc.is_writable = false;
315+
316+
length_prop_desc.is_enumerable_defined = true;
317+
length_prop_desc.is_enumerable = false;
318+
319+
length_prop_desc.is_configurable_defined = true;
320+
length_prop_desc.is_configurable = false;
321+
322+
ecma_string_t *magic_string_length_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH);
323+
ecma_completion_value_t completion = ecma_op_object_define_own_property (function_p,
324+
magic_string_length_p,
325+
&length_prop_desc,
326+
false);
327+
328+
ecma_free_completion_value (completion);
329+
ecma_deref_ecma_string (magic_string_length_p);
330+
ecma_dealloc_number (length_p);
331+
332+
/* 19-21. */
333+
ecma_object_t *thrower_p = ecma_builtin_get (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER);
334+
335+
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
336+
{
337+
prop_desc.is_enumerable_defined = true;
338+
prop_desc.is_enumerable = false;
339+
340+
prop_desc.is_configurable_defined = true;
341+
prop_desc.is_configurable = false;
342+
343+
prop_desc.is_get_defined = true;
344+
prop_desc.get_p = thrower_p;
345+
346+
prop_desc.is_set_defined = true;
347+
prop_desc.set_p = thrower_p;
348+
}
349+
350+
ecma_string_t *magic_string_caller_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER);
351+
completion = ecma_op_object_define_own_property (function_p,
352+
magic_string_caller_p,
353+
&prop_desc,
354+
false);
355+
356+
ecma_free_completion_value (completion);
357+
ecma_deref_ecma_string (magic_string_caller_p);
358+
359+
ecma_string_t *magic_string_arguments_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
360+
completion = ecma_op_object_define_own_property (function_p,
361+
magic_string_arguments_p,
362+
&prop_desc,
363+
false);
364+
365+
ecma_free_completion_value (completion);
366+
ecma_deref_ecma_string (magic_string_arguments_p);
367+
ecma_deref_object (thrower_p);
368+
369+
/* 22. */
370+
ret_value = ecma_make_normal_completion_value (ecma_make_object_value (function_p));
371+
}
372+
373+
return ret_value;
230374
} /* ecma_builtin_function_prototype_object_bind */
231375

232376
/**

0 commit comments

Comments
 (0)