diff --git a/jerry-core/jerry.cpp b/jerry-core/jerry.cpp index 53adb41374..81f6a008ea 100644 --- a/jerry-core/jerry.cpp +++ b/jerry-core/jerry.cpp @@ -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 */ diff --git a/tests/unit/test-api.cpp b/tests/unit/test-api.cpp index 0e2bea50c6..888d040e64 100644 --- a/tests/unit/test-api.cpp +++ b/tests/unit/test-api.cpp @@ -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),