Implementing [[Construct]] for external function objects.

This commit is contained in:
Ruben Ayrapetyan
2015-04-06 12:31:29 +03:00
parent 72d8c38d77
commit 4dbc6a9d1a
2 changed files with 158 additions and 71 deletions
@@ -629,29 +629,20 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
} /* ecma_op_function_call */ } /* ecma_op_function_call */
/** /**
* [[Construct]] implementation for Function objects, * [[Construct]] implementation for Function objects (13.2.2),
* created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) and
* or 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION). * externally defined (host) functions (ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION).
* *
* @return completion value * @return completion value
* Returned value must be freed with ecma_free_completion_value * Returned value must be freed with ecma_free_completion_value
*/ */
ecma_completion_value_t static ecma_completion_value_t
ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ ecma_op_function_construct_simple_or_external (ecma_object_t *func_obj_p, /**< Function object */
const ecma_value_t* arguments_list_p, /**< arguments list */ const ecma_value_t* arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< length of arguments list */ ecma_length_t arguments_list_len) /**< length of arguments list */
{ {
JERRY_ASSERT(func_obj_p != NULL JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION
&& !ecma_is_lexical_environment (func_obj_p)); || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
JERRY_ASSERT(ecma_is_constructor (ecma_make_object_value (func_obj_p)));
JERRY_ASSERT(arguments_list_len == 0 || arguments_list_p != NULL);
if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION)
{
if (unlikely (ecma_get_object_is_builtin (func_obj_p)))
{
return ecma_builtin_dispatch_construct (func_obj_p, arguments_list_p, arguments_list_len);
}
ecma_completion_value_t ret_value; ecma_completion_value_t ret_value;
@@ -681,7 +672,7 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
// 3. // 3.
ecma_property_t *class_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CLASS); ecma_property_t *class_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CLASS);
class_prop_p->u.internal_property.value = ECMA_MAGIC_STRING_FUNCTION_UL; class_prop_p->u.internal_property.value = ECMA_MAGIC_STRING_OBJECT_UL;
ecma_deref_object (prototype_p); ecma_deref_object (prototype_p);
@@ -716,6 +707,40 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
ecma_deref_ecma_string (prototype_magic_string_p); ecma_deref_ecma_string (prototype_magic_string_p);
return ret_value; return ret_value;
} /* ecma_op_function_construct_simple_or_external */
/**
* [[Construct]] implementation:
* 13.2.2 - for Function objects, created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION),
* and externally defined host functions (ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
* 15.3.4.5.1 - for Function objects, created through 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION).
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
const ecma_value_t* arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< length of arguments list */
{
JERRY_ASSERT(func_obj_p != NULL
&& !ecma_is_lexical_environment (func_obj_p));
JERRY_ASSERT(ecma_is_constructor (ecma_make_object_value (func_obj_p)));
JERRY_ASSERT(arguments_list_len == 0 || arguments_list_p != NULL);
if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION)
{
if (unlikely (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION
&& ecma_get_object_is_builtin (func_obj_p)))
{
return ecma_builtin_dispatch_construct (func_obj_p, arguments_list_p, arguments_list_len);
}
return ecma_op_function_construct_simple_or_external (func_obj_p, arguments_list_p, arguments_list_len);
}
else if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
{
return ecma_op_function_construct_simple_or_external (func_obj_p, arguments_list_p, arguments_list_len);
} }
else else
{ {
+66 -4
View File
@@ -38,6 +38,9 @@ const char *test_source = (
"function call_external () {" "function call_external () {"
" return this.external ('1', true);" " return this.external ('1', true);"
"}" "}"
"function call_external_construct () {"
" return new external_construct (true);"
"}"
); );
/** /**
@@ -104,6 +107,26 @@ handler (const jerry_api_object_t *function_obj_p,
return true; return true;
} /* handler */ } /* handler */
static bool
handler_construct (const jerry_api_object_t *function_obj_p,
const jerry_api_value_t *this_p,
jerry_api_value_t *ret_val_p,
const jerry_api_value_t args_p [],
const uint16_t args_cnt)
{
printf ("ok construct %p %p %p %d %p\n", function_obj_p, this_p, args_p, args_cnt, ret_val_p);
assert (this_p != NULL);
assert (this_p->type == JERRY_API_DATA_TYPE_OBJECT);
assert (args_cnt == 1);
assert (args_p [0].type == JERRY_API_DATA_TYPE_BOOLEAN);
assert (args_p [0].v_bool == true);
jerry_api_set_object_field_value (this_p->v_object, "value_field", &args_p [0]);
return true;
} /* handler_construct */
int int
main (void) main (void)
@@ -112,10 +135,10 @@ main (void)
bool is_ok; bool is_ok;
ssize_t sz; ssize_t sz;
jerry_api_value_t val_t, val_foo, val_bar, val_A, val_A_prototype, val_a, val_a_foo; jerry_api_value_t val_t, val_foo, val_bar, val_A, val_A_prototype, val_a, val_a_foo, val_value_field;
jerry_api_value_t val_external, val_call_external; jerry_api_value_t val_external, val_external_construct, val_call_external, val_call_external_construct;
jerry_api_object_t* global_obj_p; jerry_api_object_t* global_obj_p;
jerry_api_object_t* external_func_p; jerry_api_object_t* external_func_p, *external_construct_p;
jerry_api_value_t res, args [2]; jerry_api_value_t res, args [2];
char buffer [32]; char buffer [32];
@@ -232,7 +255,9 @@ main (void)
// Create native handler bound function object and set it to 'external' variable // Create native handler bound function object and set it to 'external' variable
external_func_p = jerry_api_create_external_function (handler); external_func_p = jerry_api_create_external_function (handler);
assert (external_func_p != NULL); assert (external_func_p != NULL
&& jerry_api_is_function (external_func_p)
&& jerry_api_is_constructor (external_func_p));
test_api_init_api_value_object (&val_external, external_func_p); test_api_init_api_value_object (&val_external, external_func_p);
is_ok = jerry_api_set_object_field_value (global_obj_p, is_ok = jerry_api_set_object_field_value (global_obj_p,
@@ -262,6 +287,43 @@ main (void)
jerry_api_release_object (global_obj_p); jerry_api_release_object (global_obj_p);
// Create native handler bound function object and set it to 'external_construct' variable
external_construct_p = jerry_api_create_external_function (handler_construct);
assert (external_construct_p != NULL
&& jerry_api_is_function (external_construct_p)
&& jerry_api_is_constructor (external_construct_p));
test_api_init_api_value_object (&val_external_construct, external_construct_p);
is_ok = jerry_api_set_object_field_value (global_obj_p,
"external_construct",
&val_external_construct);
assert (is_ok);
jerry_api_release_value (&val_external_construct);
jerry_api_release_object (external_construct_p);
// Call 'call_external_construct' function that should call external function created above, as constructor
is_ok = jerry_api_get_object_field_value (global_obj_p, "call_external_construct", &val_call_external_construct);
assert (is_ok
&& val_call_external_construct.type == JERRY_API_DATA_TYPE_OBJECT);
is_ok = jerry_api_call_function (val_call_external_construct.v_object,
global_obj_p,
&res,
NULL, 0);
jerry_api_release_value (&val_call_external_construct);
assert (is_ok
&& res.type == JERRY_API_DATA_TYPE_OBJECT);
is_ok = jerry_api_get_object_field_value (res.v_object,
"value_field",
&val_value_field);
// Get 'value_field' of constructed object
assert (is_ok
&& val_value_field.type == JERRY_API_DATA_TYPE_BOOLEAN
&& val_value_field.v_bool == true);
jerry_api_release_value (&val_value_field);
jerry_api_release_value (&res);
jerry_cleanup (); jerry_cleanup ();
return 0; return 0;