Update API for invocation of functions and constructors.

With the change, if exception is thrown in `jerry_api_function_call` and `jerry_api_construct_object`, the exception object is returned to the caller.

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
This commit is contained in:
Ruben Ayrapetyan 2015-06-15 15:09:50 +03:00
parent 5dc44b1362
commit 53156771dc
2 changed files with 124 additions and 31 deletions

View File

@ -879,8 +879,8 @@ jerry_api_set_object_native_handle (jerry_api_object_t *object_p, /**< object to
* Invoke function specified by a function object
*
* Note:
* if invocation was performed successfully, returned value should be freed
* with jerry_api_release_value just when the value becomes unnecessary.
* returned value should be freed with jerry_api_release_value
* just when the value becomes unnecessary.
*
* Note:
* If function is invoked as constructor, it should support [[Construct]] method,
@ -900,8 +900,9 @@ jerry_api_invoke_function (bool is_invoke_as_constructor, /**< true - invoke fun
* if function is invoked as constructor;
* in case of simple function call set 'this'
* binding to the global object) */
jerry_api_value_t *retval_p, /**< pointer to place for function's return value
* or NULL (to ignore the return value) */
jerry_api_value_t *retval_p, /**< pointer to place for function's
* return value / thrown exception value
* or NULL (to ignore the values) */
const jerry_api_value_t args_p[], /**< function's call arguments
* (NULL if arguments number is zero) */
uint16_t args_count) /**< number of the arguments */
@ -950,28 +951,20 @@ jerry_api_invoke_function (bool is_invoke_as_constructor, /**< true - invoke fun
args_count);
}
if (ecma_is_completion_value_normal (call_completion))
{
if (retval_p != NULL)
{
jerry_api_convert_ecma_value_to_api_value (retval_p,
ecma_get_completion_value_value (call_completion));
}
}
else
if (!ecma_is_completion_value_normal (call_completion))
{
/* unhandled exception during the function call */
JERRY_ASSERT (ecma_is_completion_value_throw (call_completion));
if (retval_p != NULL)
{
jerry_api_convert_ecma_value_to_api_value (retval_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));
}
is_successful = false;
}
if (retval_p != NULL)
{
jerry_api_convert_ecma_value_to_api_value (retval_p,
ecma_get_completion_value_value (call_completion));
}
ecma_free_completion_value (call_completion);
for (uint32_t i = 0; i < args_count; i++)
@ -984,24 +977,42 @@ jerry_api_invoke_function (bool is_invoke_as_constructor, /**< true - invoke fun
return is_successful;
} /* jerry_api_invoke_function */
/**
* Construct new TypeError object
*/
static void
jerry_api_construct_type_error (jerry_api_value_t *retval_p) /**< out: value with constructed
* TypeError object */
{
ecma_object_t *type_error_obj_p = ecma_new_standard_error (ECMA_ERROR_TYPE);
ecma_value_t type_error_value = ecma_make_object_value (type_error_obj_p);
jerry_api_convert_ecma_value_to_api_value (retval_p, type_error_value);
ecma_deref_object (type_error_obj_p);
} /* jerry_api_construct_type_error */
/**
* Call function specified by a function object
*
* Note:
* if call was performed successfully, returned value should be freed
* with jerry_api_release_value just when the value becomes unnecessary.
* returned value should be freed with jerry_api_release_value
* just when the value becomes unnecessary.
*
* @return true, if call was performed successfully, i.e.:
* - specified object is a function object (see also jerry_api_is_function);
* - no unhandled exceptions were thrown in connection with the call;
* false - otherwise.
* false - otherwise, 'retval_p' contains thrown exception:
* if called object is not function object - a TypeError instance;
* else - exception, thrown during the function call.
*/
bool
jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function object to call */
jerry_api_object_t *this_arg_p, /**< object for 'this' binding
* or NULL (set 'this' binding to the global object) */
jerry_api_value_t *retval_p, /**< pointer to place for function's return value
* or NULL (to ignore the return value) */
jerry_api_value_t *retval_p, /**< pointer to place for function's
* return value / thrown exception value
* or NULL (to ignore the values) */
const jerry_api_value_t args_p[], /**< function's call arguments
* (NULL if arguments number is zero) */
uint16_t args_count) /**< number of the arguments */
@ -1012,7 +1023,13 @@ jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function ob
{
return jerry_api_invoke_function (false, function_object_p, this_arg_p, retval_p, args_p, args_count);
}
else
{
if (retval_p != NULL)
{
jerry_api_construct_type_error (retval_p);
}
return false;
}
} /* jerry_api_call_function */
@ -1021,18 +1038,21 @@ jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function ob
* Construct object invoking specified function object as a constructor
*
* Note:
* if construction was performed successfully, returned value should be freed
* with jerry_api_release_value just when the value becomes unnecessary.
* returned value should be freed with jerry_api_release_value
* just when the value becomes unnecessary.
*
* @return true, if construction was performed successfully, i.e.:
* - specified object is a constructor function object (see also jerry_api_is_constructor);
* - no unhandled exceptions were thrown in connection with the invocation;
* false - otherwise.
* false - otherwise, 'retval_p' contains thrown exception:
* if specified object is not a constructor function object - a TypeError instance;
* else - exception, thrown during the invocation.
*/
bool
jerry_api_construct_object (jerry_api_object_t *function_object_p, /**< function object to call */
jerry_api_value_t *retval_p, /**< pointer to place for function's return value
* or NULL (to ignore the return value) */
jerry_api_value_t *retval_p, /**< pointer to place for function's
* return value / thrown exception value
* or NULL (to ignore the values) */
const jerry_api_value_t args_p[], /**< function's call arguments
* (NULL if arguments number is zero) */
uint16_t args_count) /**< number of the arguments */
@ -1045,6 +1065,11 @@ jerry_api_construct_object (jerry_api_object_t *function_object_p, /**< function
}
else
{
if (retval_p != NULL)
{
jerry_api_construct_type_error (retval_p);
}
return false;
}
} /* jerry_api_construct_object */

View File

@ -46,6 +46,9 @@ const char *test_source = (
" } "
" assert(catched); "
"} "
"function throw_reference_error() { "
" throw new ReferenceError ();"
"} "
);
bool test_api_is_free_callback_was_called = false;
@ -222,11 +225,11 @@ main (void)
jerry_init (JERRY_FLAG_EMPTY);
bool is_ok;
bool is_ok, is_exception;
ssize_t sz;
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;
jerry_api_object_t* global_obj_p;
jerry_api_object_t* global_obj_p, *obj_p;
jerry_api_object_t* external_func_p, *external_construct_p;
jerry_api_object_t* throw_test_handler_p;
jerry_api_value_t res, args[2];
@ -437,6 +440,71 @@ main (void)
jerry_api_release_value (&val_t);
jerry_api_release_value (&res);
// Test: Unhandled exception in called function
is_ok = jerry_api_get_object_field_value (global_obj_p, "throw_reference_error", &val_t);
JERRY_ASSERT (is_ok
&& val_t.type == JERRY_API_DATA_TYPE_OBJECT);
is_ok = jerry_api_call_function (val_t.v_object,
global_obj_p,
&res,
NULL, 0);
is_exception = !is_ok;
JERRY_ASSERT (is_exception);
jerry_api_release_value (&val_t);
// 'res' should contain exception object
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
jerry_api_release_value (&res);
// Test: Call of non-function
obj_p = jerry_api_create_object ();
is_ok = jerry_api_call_function (obj_p,
global_obj_p,
&res,
NULL, 0);
is_exception = !is_ok;
JERRY_ASSERT (is_exception);
// 'res' should contain exception object
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
jerry_api_release_value (&res);
jerry_api_release_object (obj_p);
// Test: Unhandled exception in function called, as constructor
is_ok = jerry_api_get_object_field_value (global_obj_p, "throw_reference_error", &val_t);
JERRY_ASSERT (is_ok
&& val_t.type == JERRY_API_DATA_TYPE_OBJECT);
is_ok = jerry_api_construct_object (val_t.v_object,
&res,
NULL, 0);
is_exception = !is_ok;
JERRY_ASSERT (is_exception);
jerry_api_release_value (&val_t);
// 'res' should contain exception object
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
jerry_api_release_value (&res);
// Test: Call of non-function as constructor
obj_p = jerry_api_create_object ();
is_ok = jerry_api_construct_object (obj_p,
&res,
NULL, 0);
is_exception = !is_ok;
JERRY_ASSERT (is_exception);
// 'res' should contain exception object
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
jerry_api_release_value (&res);
jerry_api_release_object (obj_p);
// Test: eval
const char *eval_code_src_p = "(function () { return 123; })";
jerry_completion_code_t status = jerry_api_eval (eval_code_src_p,
strlen (eval_code_src_p),