Skip to content

Commit 5315677

Browse files
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 [email protected]
1 parent 5dc44b1 commit 5315677

File tree

2 files changed

+124
-31
lines changed

2 files changed

+124
-31
lines changed

jerry-core/jerry.cpp

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -879,8 +879,8 @@ jerry_api_set_object_native_handle (jerry_api_object_t *object_p, /**< object to
879879
* Invoke function specified by a function object
880880
*
881881
* Note:
882-
* if invocation was performed successfully, returned value should be freed
883-
* with jerry_api_release_value just when the value becomes unnecessary.
882+
* returned value should be freed with jerry_api_release_value
883+
* just when the value becomes unnecessary.
884884
*
885885
* Note:
886886
* 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
900900
* if function is invoked as constructor;
901901
* in case of simple function call set 'this'
902902
* binding to the global object) */
903-
jerry_api_value_t *retval_p, /**< pointer to place for function's return value
904-
* or NULL (to ignore the return value) */
903+
jerry_api_value_t *retval_p, /**< pointer to place for function's
904+
* return value / thrown exception value
905+
* or NULL (to ignore the values) */
905906
const jerry_api_value_t args_p[], /**< function's call arguments
906907
* (NULL if arguments number is zero) */
907908
uint16_t args_count) /**< number of the arguments */
@@ -950,28 +951,20 @@ jerry_api_invoke_function (bool is_invoke_as_constructor, /**< true - invoke fun
950951
args_count);
951952
}
952953

953-
if (ecma_is_completion_value_normal (call_completion))
954-
{
955-
if (retval_p != NULL)
956-
{
957-
jerry_api_convert_ecma_value_to_api_value (retval_p,
958-
ecma_get_completion_value_value (call_completion));
959-
}
960-
}
961-
else
954+
if (!ecma_is_completion_value_normal (call_completion))
962955
{
963956
/* unhandled exception during the function call */
964-
965957
JERRY_ASSERT (ecma_is_completion_value_throw (call_completion));
966958

967-
if (retval_p != NULL)
968-
{
969-
jerry_api_convert_ecma_value_to_api_value (retval_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));
970-
}
971-
972959
is_successful = false;
973960
}
974961

962+
if (retval_p != NULL)
963+
{
964+
jerry_api_convert_ecma_value_to_api_value (retval_p,
965+
ecma_get_completion_value_value (call_completion));
966+
}
967+
975968
ecma_free_completion_value (call_completion);
976969

977970
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
984977
return is_successful;
985978
} /* jerry_api_invoke_function */
986979

980+
/**
981+
* Construct new TypeError object
982+
*/
983+
static void
984+
jerry_api_construct_type_error (jerry_api_value_t *retval_p) /**< out: value with constructed
985+
* TypeError object */
986+
{
987+
ecma_object_t *type_error_obj_p = ecma_new_standard_error (ECMA_ERROR_TYPE);
988+
ecma_value_t type_error_value = ecma_make_object_value (type_error_obj_p);
989+
990+
jerry_api_convert_ecma_value_to_api_value (retval_p, type_error_value);
991+
992+
ecma_deref_object (type_error_obj_p);
993+
} /* jerry_api_construct_type_error */
994+
987995
/**
988996
* Call function specified by a function object
989997
*
990998
* Note:
991-
* if call was performed successfully, returned value should be freed
992-
* with jerry_api_release_value just when the value becomes unnecessary.
999+
* returned value should be freed with jerry_api_release_value
1000+
* just when the value becomes unnecessary.
9931001
*
9941002
* @return true, if call was performed successfully, i.e.:
9951003
* - specified object is a function object (see also jerry_api_is_function);
9961004
* - no unhandled exceptions were thrown in connection with the call;
997-
* false - otherwise.
1005+
* false - otherwise, 'retval_p' contains thrown exception:
1006+
* if called object is not function object - a TypeError instance;
1007+
* else - exception, thrown during the function call.
9981008
*/
9991009
bool
10001010
jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function object to call */
10011011
jerry_api_object_t *this_arg_p, /**< object for 'this' binding
10021012
* or NULL (set 'this' binding to the global object) */
1003-
jerry_api_value_t *retval_p, /**< pointer to place for function's return value
1004-
* or NULL (to ignore the return value) */
1013+
jerry_api_value_t *retval_p, /**< pointer to place for function's
1014+
* return value / thrown exception value
1015+
* or NULL (to ignore the values) */
10051016
const jerry_api_value_t args_p[], /**< function's call arguments
10061017
* (NULL if arguments number is zero) */
10071018
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
10121023
{
10131024
return jerry_api_invoke_function (false, function_object_p, this_arg_p, retval_p, args_p, args_count);
10141025
}
1026+
else
10151027
{
1028+
if (retval_p != NULL)
1029+
{
1030+
jerry_api_construct_type_error (retval_p);
1031+
}
1032+
10161033
return false;
10171034
}
10181035
} /* jerry_api_call_function */
@@ -1021,18 +1038,21 @@ jerry_api_call_function (jerry_api_object_t *function_object_p, /**< function ob
10211038
* Construct object invoking specified function object as a constructor
10221039
*
10231040
* Note:
1024-
* if construction was performed successfully, returned value should be freed
1025-
* with jerry_api_release_value just when the value becomes unnecessary.
1041+
* returned value should be freed with jerry_api_release_value
1042+
* just when the value becomes unnecessary.
10261043
*
10271044
* @return true, if construction was performed successfully, i.e.:
10281045
* - specified object is a constructor function object (see also jerry_api_is_constructor);
10291046
* - no unhandled exceptions were thrown in connection with the invocation;
1030-
* false - otherwise.
1047+
* false - otherwise, 'retval_p' contains thrown exception:
1048+
* if specified object is not a constructor function object - a TypeError instance;
1049+
* else - exception, thrown during the invocation.
10311050
*/
10321051
bool
10331052
jerry_api_construct_object (jerry_api_object_t *function_object_p, /**< function object to call */
1034-
jerry_api_value_t *retval_p, /**< pointer to place for function's return value
1035-
* or NULL (to ignore the return value) */
1053+
jerry_api_value_t *retval_p, /**< pointer to place for function's
1054+
* return value / thrown exception value
1055+
* or NULL (to ignore the values) */
10361056
const jerry_api_value_t args_p[], /**< function's call arguments
10371057
* (NULL if arguments number is zero) */
10381058
uint16_t args_count) /**< number of the arguments */
@@ -1045,6 +1065,11 @@ jerry_api_construct_object (jerry_api_object_t *function_object_p, /**< function
10451065
}
10461066
else
10471067
{
1068+
if (retval_p != NULL)
1069+
{
1070+
jerry_api_construct_type_error (retval_p);
1071+
}
1072+
10481073
return false;
10491074
}
10501075
} /* jerry_api_construct_object */

tests/unit/test-api.cpp

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ const char *test_source = (
4646
" } "
4747
" assert(catched); "
4848
"} "
49+
"function throw_reference_error() { "
50+
" throw new ReferenceError ();"
51+
"} "
4952
);
5053

5154
bool test_api_is_free_callback_was_called = false;
@@ -222,11 +225,11 @@ main (void)
222225

223226
jerry_init (JERRY_FLAG_EMPTY);
224227

225-
bool is_ok;
228+
bool is_ok, is_exception;
226229
ssize_t sz;
227230
jerry_api_value_t val_t, val_foo, val_bar, val_A, val_A_prototype, val_a, val_a_foo, val_value_field;
228231
jerry_api_value_t val_external, val_external_construct, val_call_external;
229-
jerry_api_object_t* global_obj_p;
232+
jerry_api_object_t* global_obj_p, *obj_p;
230233
jerry_api_object_t* external_func_p, *external_construct_p;
231234
jerry_api_object_t* throw_test_handler_p;
232235
jerry_api_value_t res, args[2];
@@ -437,6 +440,71 @@ main (void)
437440
jerry_api_release_value (&val_t);
438441
jerry_api_release_value (&res);
439442

443+
// Test: Unhandled exception in called function
444+
is_ok = jerry_api_get_object_field_value (global_obj_p, "throw_reference_error", &val_t);
445+
JERRY_ASSERT (is_ok
446+
&& val_t.type == JERRY_API_DATA_TYPE_OBJECT);
447+
448+
is_ok = jerry_api_call_function (val_t.v_object,
449+
global_obj_p,
450+
&res,
451+
NULL, 0);
452+
is_exception = !is_ok;
453+
454+
JERRY_ASSERT (is_exception);
455+
jerry_api_release_value (&val_t);
456+
457+
// 'res' should contain exception object
458+
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
459+
jerry_api_release_value (&res);
460+
461+
// Test: Call of non-function
462+
obj_p = jerry_api_create_object ();
463+
is_ok = jerry_api_call_function (obj_p,
464+
global_obj_p,
465+
&res,
466+
NULL, 0);
467+
is_exception = !is_ok;
468+
JERRY_ASSERT (is_exception);
469+
470+
// 'res' should contain exception object
471+
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
472+
jerry_api_release_value (&res);
473+
474+
jerry_api_release_object (obj_p);
475+
476+
// Test: Unhandled exception in function called, as constructor
477+
is_ok = jerry_api_get_object_field_value (global_obj_p, "throw_reference_error", &val_t);
478+
JERRY_ASSERT (is_ok
479+
&& val_t.type == JERRY_API_DATA_TYPE_OBJECT);
480+
481+
is_ok = jerry_api_construct_object (val_t.v_object,
482+
&res,
483+
NULL, 0);
484+
is_exception = !is_ok;
485+
486+
JERRY_ASSERT (is_exception);
487+
jerry_api_release_value (&val_t);
488+
489+
// 'res' should contain exception object
490+
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
491+
jerry_api_release_value (&res);
492+
493+
// Test: Call of non-function as constructor
494+
obj_p = jerry_api_create_object ();
495+
is_ok = jerry_api_construct_object (obj_p,
496+
&res,
497+
NULL, 0);
498+
is_exception = !is_ok;
499+
JERRY_ASSERT (is_exception);
500+
501+
// 'res' should contain exception object
502+
JERRY_ASSERT (res.type == JERRY_API_DATA_TYPE_OBJECT);
503+
jerry_api_release_value (&res);
504+
505+
jerry_api_release_object (obj_p);
506+
507+
// Test: eval
440508
const char *eval_code_src_p = "(function () { return 123; })";
441509
jerry_completion_code_t status = jerry_api_eval (eval_code_src_p,
442510
strlen (eval_code_src_p),

0 commit comments

Comments
 (0)