Implementing [[Construct]] for external function objects.
This commit is contained in:
@@ -629,9 +629,91 @@ 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
|
||||||
|
* 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
|
* @return completion value
|
||||||
* Returned value must be freed with ecma_free_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 (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);
|
return ecma_builtin_dispatch_construct (func_obj_p, arguments_list_p, arguments_list_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
ecma_completion_value_t ret_value;
|
return ecma_op_function_construct_simple_or_external (func_obj_p, arguments_list_p, arguments_list_len);
|
||||||
|
}
|
||||||
ecma_string_t *prototype_magic_string_p = ecma_get_magic_string (ECMA_MAGIC_STRING_PROTOTYPE);
|
else if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
|
||||||
|
{
|
||||||
// 5.
|
return ecma_op_function_construct_simple_or_external (func_obj_p, arguments_list_p, arguments_list_len);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+66
-4
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user