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,9 +629,91 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
} /* ecma_op_function_call */
/**
* [[Construct]] implementation for Function objects,
* created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION)
* or 15.3.4.5 (ECMA_OBJECT_TYPE_BOUND_FUNCTION).
* [[Construct]] implementation for Function objects (13.2.2),
* created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) and
* externally defined (host) functions (ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION).
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
static ecma_completion_value_t
ecma_op_function_construct_simple_or_external (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 (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION
|| ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
ecma_completion_value_t ret_value;
ecma_string_t *prototype_magic_string_p = ecma_get_magic_string (ECMA_MAGIC_STRING_PROTOTYPE);
// 5.
ECMA_TRY_CATCH (func_obj_prototype_prop_value,
ecma_op_object_get (func_obj_p,
prototype_magic_string_p),
ret_value);
// 6.
ecma_object_t *prototype_p;
if (ecma_is_value_object (func_obj_prototype_prop_value))
{
prototype_p = ecma_get_object_from_value (func_obj_prototype_prop_value);
ecma_ref_object (prototype_p);
}
else
{
// 7.
prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
}
// 1., 2., 4.
ecma_object_t *obj_p = ecma_create_object (prototype_p, true, ECMA_OBJECT_TYPE_GENERAL);
// 3.
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_OBJECT_UL;
ecma_deref_object (prototype_p);
// 8.
ECMA_TRY_CATCH (call_completion,
ecma_op_function_call (func_obj_p,
ecma_make_object_value (obj_p),
arguments_list_p,
arguments_list_len),
ret_value);
ecma_value_t obj_value;
// 9.
if (ecma_is_value_object (call_completion))
{
ecma_deref_object (obj_p);
obj_value = ecma_copy_value (call_completion, true);
}
else
{
// 10.
obj_value = ecma_make_object_value (obj_p);
}
ret_value = ecma_make_normal_completion_value (obj_value);
ECMA_FINALIZE (call_completion);
ECMA_FINALIZE (func_obj_prototype_prop_value);
ecma_deref_ecma_string (prototype_magic_string_p);
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
@@ -648,74 +730,17 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION)
{
if (unlikely (ecma_get_object_is_builtin (func_obj_p)))
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);
}
ecma_completion_value_t ret_value;
ecma_string_t *prototype_magic_string_p = ecma_get_magic_string (ECMA_MAGIC_STRING_PROTOTYPE);
// 5.
ECMA_TRY_CATCH (func_obj_prototype_prop_value,
ecma_op_object_get (func_obj_p,
prototype_magic_string_p),
ret_value);
// 6.
ecma_object_t *prototype_p;
if (ecma_is_value_object (func_obj_prototype_prop_value))
{
prototype_p = ecma_get_object_from_value (func_obj_prototype_prop_value);
ecma_ref_object (prototype_p);
}
else
{
// 7.
prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
}
// 1., 2., 4.
ecma_object_t *obj_p = ecma_create_object (prototype_p, true, ECMA_OBJECT_TYPE_GENERAL);
// 3.
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;
ecma_deref_object (prototype_p);
// 8.
ECMA_TRY_CATCH (call_completion,
ecma_op_function_call (func_obj_p,
ecma_make_object_value (obj_p),
arguments_list_p,
arguments_list_len),
ret_value);
ecma_value_t obj_value;
// 9.
if (ecma_is_value_object (call_completion))
{
ecma_deref_object (obj_p);
obj_value = ecma_copy_value (call_completion, true);
}
else
{
// 10.
obj_value = ecma_make_object_value (obj_p);
}
ret_value = ecma_make_normal_completion_value (obj_value);
ECMA_FINALIZE (call_completion);
ECMA_FINALIZE (func_obj_prototype_prop_value);
ecma_deref_ecma_string (prototype_magic_string_p);
return ret_value;
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
{
+66 -4
View File
@@ -38,6 +38,9 @@ const char *test_source = (
"function call_external () {"
" 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;
} /* 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
main (void)
@@ -112,10 +135,10 @@ main (void)
bool is_ok;
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_external, val_call_external;
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_external_construct, val_call_external, val_call_external_construct;
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];
char buffer [32];
@@ -232,7 +255,9 @@ main (void)
// Create native handler bound function object and set it to 'external' variable
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);
is_ok = jerry_api_set_object_field_value (global_obj_p,
@@ -262,6 +287,43 @@ main (void)
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 ();
return 0;