Implement vm_throw callback (#4726)
Slightly improve the description of vm_exec_stop callback. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
+106
-10
@@ -153,6 +153,7 @@ Possible compile time enabled feature types:
|
|||||||
- JERRY_FEATURE_SNAPSHOT_EXEC - executing snapshot files
|
- JERRY_FEATURE_SNAPSHOT_EXEC - executing snapshot files
|
||||||
- JERRY_FEATURE_DEBUGGER - debugging
|
- JERRY_FEATURE_DEBUGGER - debugging
|
||||||
- JERRY_FEATURE_VM_EXEC_STOP - stopping ECMAScript execution
|
- JERRY_FEATURE_VM_EXEC_STOP - stopping ECMAScript execution
|
||||||
|
- JERRY_FEATURE_VM_THROW - capturing ECMAScript throws
|
||||||
- JERRY_FEATURE_JSON - JSON support
|
- JERRY_FEATURE_JSON - JSON support
|
||||||
- JERRY_FEATURE_PROMISE - promise support
|
- JERRY_FEATURE_PROMISE - promise support
|
||||||
- JERRY_FEATURE_TYPEDARRAY - Typedarray support
|
- JERRY_FEATURE_TYPEDARRAY - Typedarray support
|
||||||
@@ -1122,6 +1123,32 @@ typedef jerry_value_t (*jerry_vm_exec_stop_callback_t) (void *user_p);
|
|||||||
|
|
||||||
- [jerry_set_vm_exec_stop_callback](#jerry_set_vm_exec_stop_callback)
|
- [jerry_set_vm_exec_stop_callback](#jerry_set_vm_exec_stop_callback)
|
||||||
|
|
||||||
|
## jerry_vm_throw_callback_t
|
||||||
|
|
||||||
|
**Summary**
|
||||||
|
|
||||||
|
Callback which is called when a value is thrown in an ECMAScript code. The callback
|
||||||
|
should not change the `error_value`. The callback is not called again until the value
|
||||||
|
is caught.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
- The engine considers errors thrown by external functions as never caught. The
|
||||||
|
application can maintain a status flag to ignore the next call of the callback
|
||||||
|
if necessary.
|
||||||
|
See: [jerry_create_external_function](#jerry_create_external_function)
|
||||||
|
|
||||||
|
**Prototype**
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef void (*jerry_vm_throw_callback_t) (const jerry_value_t error_value, void *user_p);
|
||||||
|
```
|
||||||
|
|
||||||
|
*New in [[NEXT_RELEASE]]*.
|
||||||
|
|
||||||
|
**See also**
|
||||||
|
|
||||||
|
- [jerry_set_vm_throw_callback](#jerry_set_vm_throw_callback)
|
||||||
|
|
||||||
## jerry_promise_state_t
|
## jerry_promise_state_t
|
||||||
|
|
||||||
Enum which describes the state of a Promise.
|
Enum which describes the state of a Promise.
|
||||||
@@ -11329,8 +11356,7 @@ backtrace_callback (jerry_backtrace_frame_t *frame_p,
|
|||||||
|
|
||||||
**Summary**
|
**Summary**
|
||||||
|
|
||||||
When JERRY_FEATURE_VM_EXEC_STOP is enabled a callback function can be
|
The callback passed to this function is periodically called when
|
||||||
specified by this function. This callback is periodically called when
|
|
||||||
JerryScript executes an ECMAScript program.
|
JerryScript executes an ECMAScript program.
|
||||||
|
|
||||||
If the callback returns with undefined value the ECMAScript execution
|
If the callback returns with undefined value the ECMAScript execution
|
||||||
@@ -11345,6 +11371,10 @@ or an exception is caught. Setting the `frequency` to a greater
|
|||||||
than `1` value reduces this overhead further. If its value is N
|
than `1` value reduces this overhead further. If its value is N
|
||||||
only every Nth event (backward jump, etc.) trigger the next check.
|
only every Nth event (backward jump, etc.) trigger the next check.
|
||||||
|
|
||||||
|
*Notes*:
|
||||||
|
- This API depends on a build option (`JERRY_VM_EXEC_STOP`) and can be checked
|
||||||
|
in runtime with the `JERRY_FEATURE_VM_EXEC_STOP` feature enum value,
|
||||||
|
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
|
||||||
|
|
||||||
**Prototype**
|
**Prototype**
|
||||||
|
|
||||||
@@ -11368,14 +11398,14 @@ jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb,
|
|||||||
```c
|
```c
|
||||||
#include "jerryscript.h"
|
#include "jerryscript.h"
|
||||||
|
|
||||||
static int countdown = 10;
|
|
||||||
|
|
||||||
static jerry_value_t
|
static jerry_value_t
|
||||||
vm_exec_stop_callback (void *user_p)
|
vm_exec_stop_callback (void *user_p)
|
||||||
{
|
{
|
||||||
while (countdown > 0)
|
int *countdown_p = (int *) user_p;
|
||||||
|
|
||||||
|
while (*countdown_p > 0)
|
||||||
{
|
{
|
||||||
countdown--;
|
(*countdown_p)--;
|
||||||
return jerry_create_undefined ();
|
return jerry_create_undefined ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11388,6 +11418,7 @@ main (void)
|
|||||||
{
|
{
|
||||||
jerry_init (JERRY_INIT_EMPTY);
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
int countdown = 10;
|
||||||
jerry_set_vm_exec_stop_callback (vm_exec_stop_callback, &countdown, 16);
|
jerry_set_vm_exec_stop_callback (vm_exec_stop_callback, &countdown, 16);
|
||||||
|
|
||||||
// Infinite loop.
|
// Infinite loop.
|
||||||
@@ -11402,12 +11433,77 @@ main (void)
|
|||||||
|
|
||||||
**See also**
|
**See also**
|
||||||
|
|
||||||
- [jerry_init](#jerry_init)
|
|
||||||
- [jerry_cleanup](#jerry_cleanup)
|
|
||||||
- [jerry_parse](#jerry_parse)
|
|
||||||
- [jerry_run](#jerry_run)
|
|
||||||
- [jerry_vm_exec_stop_callback_t](#jerry_vm_exec_stop_callback_t)
|
- [jerry_vm_exec_stop_callback_t](#jerry_vm_exec_stop_callback_t)
|
||||||
|
|
||||||
|
## jerry_set_vm_throw_callback
|
||||||
|
|
||||||
|
**Summary**
|
||||||
|
|
||||||
|
The callback passed to this function is called when an error is thrown
|
||||||
|
in ECMAScript code. The callback is not called again until the value is
|
||||||
|
caught. See: [jerry_vm_throw_callback_t](#jerry_vm_throw_callback_t).
|
||||||
|
|
||||||
|
*Notes*:
|
||||||
|
- This API depends on a build option (`JERRY_VM_THROW`) and can be checked
|
||||||
|
in runtime with the `JERRY_FEATURE_VM_THROW` feature enum value,
|
||||||
|
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
|
||||||
|
|
||||||
|
**Prototype**
|
||||||
|
|
||||||
|
```c
|
||||||
|
void
|
||||||
|
jerry_set_vm_throw_callback (jerry_vm_throw_callback_t throw_cb,
|
||||||
|
void *user_p);
|
||||||
|
```
|
||||||
|
|
||||||
|
- `throw_cb` - callback which is called on throws (passing NULL disables this feature)
|
||||||
|
- `user_p` - user pointer passed to the `throw_cb` function
|
||||||
|
|
||||||
|
*New in version [[NEXT_RELEASE]]*.
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
[doctest]: # (test="compile")
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "jerryscript.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
vm_throw_callback (const jerry_value_t error_value, /**< captured error */
|
||||||
|
void *user_p) /**< user pointer */
|
||||||
|
{
|
||||||
|
(void) error_value;
|
||||||
|
|
||||||
|
/* Counts the number of throws. */
|
||||||
|
int *counter_p = (int *) user_p;
|
||||||
|
(*counter_p)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
jerry_set_vm_throw_callback (vm_throw_callback, &counter);
|
||||||
|
|
||||||
|
const jerry_char_t script[] = "try { throw new Error('1') } catch (e) { throw new Error('2') }";
|
||||||
|
|
||||||
|
jerry_value_t parsed_code = jerry_parse (script, sizeof (script) - 1, NULL);
|
||||||
|
jerry_release_value (jerry_run (parsed_code));
|
||||||
|
jerry_release_value (parsed_code);
|
||||||
|
|
||||||
|
/* The counter contains 2. */
|
||||||
|
|
||||||
|
jerry_cleanup ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**See also**
|
||||||
|
|
||||||
|
- [jerry_vm_throw_callback_t](#jerry_vm_throw_callback_t)
|
||||||
|
|
||||||
## jerry_get_resource_name
|
## jerry_get_resource_name
|
||||||
|
|
||||||
**Summary**
|
**Summary**
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ set(JERRY_SNAPSHOT_EXEC OFF CACHE BOOL "Enable executing
|
|||||||
set(JERRY_SNAPSHOT_SAVE OFF CACHE BOOL "Enable saving snapshot files?")
|
set(JERRY_SNAPSHOT_SAVE OFF CACHE BOOL "Enable saving snapshot files?")
|
||||||
set(JERRY_SYSTEM_ALLOCATOR OFF CACHE BOOL "Enable system allocator?")
|
set(JERRY_SYSTEM_ALLOCATOR OFF CACHE BOOL "Enable system allocator?")
|
||||||
set(JERRY_VALGRIND OFF CACHE BOOL "Enable Valgrind support?")
|
set(JERRY_VALGRIND OFF CACHE BOOL "Enable Valgrind support?")
|
||||||
set(JERRY_VM_EXEC_STOP OFF CACHE BOOL "Enable VM execution stopping?")
|
set(JERRY_VM_EXEC_STOP OFF CACHE BOOL "Enable VM execution stop callback?")
|
||||||
|
set(JERRY_VM_THROW OFF CACHE BOOL "Enable VM throw callback?")
|
||||||
set(JERRY_GLOBAL_HEAP_SIZE "(512)" CACHE STRING "Size of memory heap, in kilobytes")
|
set(JERRY_GLOBAL_HEAP_SIZE "(512)" CACHE STRING "Size of memory heap, in kilobytes")
|
||||||
set(JERRY_GC_LIMIT "(0)" CACHE STRING "Heap usage limit to trigger garbage collection")
|
set(JERRY_GC_LIMIT "(0)" CACHE STRING "Heap usage limit to trigger garbage collection")
|
||||||
set(JERRY_STACK_LIMIT "(0)" CACHE STRING "Maximum stack usage size, in kilobytes")
|
set(JERRY_STACK_LIMIT "(0)" CACHE STRING "Maximum stack usage size, in kilobytes")
|
||||||
@@ -96,6 +97,7 @@ message(STATUS "JERRY_SNAPSHOT_SAVE " ${JERRY_SNAPSHOT_SAVE} ${JERRY_
|
|||||||
message(STATUS "JERRY_SYSTEM_ALLOCATOR " ${JERRY_SYSTEM_ALLOCATOR})
|
message(STATUS "JERRY_SYSTEM_ALLOCATOR " ${JERRY_SYSTEM_ALLOCATOR})
|
||||||
message(STATUS "JERRY_VALGRIND " ${JERRY_VALGRIND})
|
message(STATUS "JERRY_VALGRIND " ${JERRY_VALGRIND})
|
||||||
message(STATUS "JERRY_VM_EXEC_STOP " ${JERRY_VM_EXEC_STOP})
|
message(STATUS "JERRY_VM_EXEC_STOP " ${JERRY_VM_EXEC_STOP})
|
||||||
|
message(STATUS "JERRY_VM_THROW " ${JERRY_VM_THROW})
|
||||||
message(STATUS "JERRY_GLOBAL_HEAP_SIZE " ${JERRY_GLOBAL_HEAP_SIZE})
|
message(STATUS "JERRY_GLOBAL_HEAP_SIZE " ${JERRY_GLOBAL_HEAP_SIZE})
|
||||||
message(STATUS "JERRY_GC_LIMIT " ${JERRY_GC_LIMIT})
|
message(STATUS "JERRY_GC_LIMIT " ${JERRY_GC_LIMIT})
|
||||||
message(STATUS "JERRY_STACK_LIMIT " ${JERRY_STACK_LIMIT})
|
message(STATUS "JERRY_STACK_LIMIT " ${JERRY_STACK_LIMIT})
|
||||||
@@ -627,9 +629,12 @@ if(JERRY_VALGRIND)
|
|||||||
set(INCLUDE_CORE_PRIVATE ${INCLUDE_CORE_PRIVATE} ${INCLUDE_THIRD_PARTY_VALGRIND})
|
set(INCLUDE_CORE_PRIVATE ${INCLUDE_CORE_PRIVATE} ${INCLUDE_THIRD_PARTY_VALGRIND})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Enable VM execution stopping
|
# Enable VM execution stop callback
|
||||||
jerry_add_define01(JERRY_VM_EXEC_STOP)
|
jerry_add_define01(JERRY_VM_EXEC_STOP)
|
||||||
|
|
||||||
|
# Enable VM throw callback
|
||||||
|
jerry_add_define01(JERRY_VM_THROW)
|
||||||
|
|
||||||
# Size of heap
|
# Size of heap
|
||||||
set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_GLOBAL_HEAP_SIZE=${JERRY_GLOBAL_HEAP_SIZE})
|
set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_GLOBAL_HEAP_SIZE=${JERRY_GLOBAL_HEAP_SIZE})
|
||||||
|
|
||||||
|
|||||||
+22
-3
@@ -1800,6 +1800,9 @@ jerry_is_feature_enabled (const jerry_feature_t feature) /**< feature to check *
|
|||||||
#if JERRY_VM_EXEC_STOP
|
#if JERRY_VM_EXEC_STOP
|
||||||
|| feature == JERRY_FEATURE_VM_EXEC_STOP
|
|| feature == JERRY_FEATURE_VM_EXEC_STOP
|
||||||
#endif /* JERRY_VM_EXEC_STOP */
|
#endif /* JERRY_VM_EXEC_STOP */
|
||||||
|
#if JERRY_VM_THROW
|
||||||
|
|| feature == JERRY_FEATURE_VM_THROW
|
||||||
|
#endif /* JERRY_VM_THROW */
|
||||||
#if JERRY_BUILTIN_JSON
|
#if JERRY_BUILTIN_JSON
|
||||||
|| feature == JERRY_FEATURE_JSON
|
|| feature == JERRY_FEATURE_JSON
|
||||||
#endif /* JERRY_BUILTIN_JSON */
|
#endif /* JERRY_BUILTIN_JSON */
|
||||||
@@ -5202,8 +5205,8 @@ jerry_create_context (uint32_t heap_size, /**< the size of heap */
|
|||||||
} /* jerry_create_context */
|
} /* jerry_create_context */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If JERRY_VM_EXEC_STOP is enabled the callback passed to this function is
|
* When JERRY_VM_EXEC_STOP is enabled, the callback passed to this function
|
||||||
* periodically called with the user_p argument. If frequency is greater
|
* is periodically called with the user_p argument. If frequency is greater
|
||||||
* than 1, the callback is only called at every frequency ticks.
|
* than 1, the callback is only called at every frequency ticks.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@@ -5219,8 +5222,8 @@ jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, /**< per
|
|||||||
|
|
||||||
JERRY_CONTEXT (vm_exec_stop_frequency) = frequency;
|
JERRY_CONTEXT (vm_exec_stop_frequency) = frequency;
|
||||||
JERRY_CONTEXT (vm_exec_stop_counter) = frequency;
|
JERRY_CONTEXT (vm_exec_stop_counter) = frequency;
|
||||||
JERRY_CONTEXT (vm_exec_stop_user_p) = user_p;
|
|
||||||
JERRY_CONTEXT (vm_exec_stop_cb) = stop_cb;
|
JERRY_CONTEXT (vm_exec_stop_cb) = stop_cb;
|
||||||
|
JERRY_CONTEXT (vm_exec_stop_user_p) = user_p;
|
||||||
#else /* !JERRY_VM_EXEC_STOP */
|
#else /* !JERRY_VM_EXEC_STOP */
|
||||||
JERRY_UNUSED (stop_cb);
|
JERRY_UNUSED (stop_cb);
|
||||||
JERRY_UNUSED (user_p);
|
JERRY_UNUSED (user_p);
|
||||||
@@ -5228,6 +5231,22 @@ jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, /**< per
|
|||||||
#endif /* JERRY_VM_EXEC_STOP */
|
#endif /* JERRY_VM_EXEC_STOP */
|
||||||
} /* jerry_set_vm_exec_stop_callback */
|
} /* jerry_set_vm_exec_stop_callback */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When JERRY_VM_THROW is enabled, the callback passed to this
|
||||||
|
* function is called when an error is thrown in ECMAScript code.
|
||||||
|
*/
|
||||||
|
void jerry_set_vm_throw_callback (jerry_vm_throw_callback_t throw_cb, /**< callback which is called on throws */
|
||||||
|
void *user_p) /**< pointer passed to the function */
|
||||||
|
{
|
||||||
|
#if JERRY_VM_THROW
|
||||||
|
JERRY_CONTEXT (vm_throw_callback_p) = throw_cb;
|
||||||
|
JERRY_CONTEXT (vm_throw_callback_user_p) = user_p;
|
||||||
|
#else /* !JERRY_VM_THROW */
|
||||||
|
JERRY_UNUSED (throw_cb);
|
||||||
|
JERRY_UNUSED (user_p);
|
||||||
|
#endif /* JERRY_VM_THROW */
|
||||||
|
} /* jerry_set_vm_throw_callback */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get backtrace. The backtrace is an array of strings where
|
* Get backtrace. The backtrace is an array of strings where
|
||||||
* each string contains the position of the corresponding frame.
|
* each string contains the position of the corresponding frame.
|
||||||
|
|||||||
+17
-2
@@ -430,13 +430,24 @@
|
|||||||
* Enable/Disable the vm execution stop callback function.
|
* Enable/Disable the vm execution stop callback function.
|
||||||
*
|
*
|
||||||
* Allowed values:
|
* Allowed values:
|
||||||
* 0: Disable vm exec stop callbacks.
|
* 0: Disable vm exec stop callback support.
|
||||||
* 1: Enable vm exec stop callback functionality.
|
* 1: Enable vm exec stop callback support.
|
||||||
*/
|
*/
|
||||||
#ifndef JERRY_VM_EXEC_STOP
|
#ifndef JERRY_VM_EXEC_STOP
|
||||||
# define JERRY_VM_EXEC_STOP 0
|
# define JERRY_VM_EXEC_STOP 0
|
||||||
#endif /* !defined (JERRY_VM_EXEC_STOP) */
|
#endif /* !defined (JERRY_VM_EXEC_STOP) */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disable the vm throw callback function.
|
||||||
|
*
|
||||||
|
* Allowed values:
|
||||||
|
* 0: Disable vm throw callback support.
|
||||||
|
* 1: Enable vm throw callback support.
|
||||||
|
*/
|
||||||
|
#ifndef JERRY_VM_THROW
|
||||||
|
# define JERRY_VM_THROW 0
|
||||||
|
#endif /* !defined (JERRY_VM_THROW) */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Advanced section configurations.
|
* Advanced section configurations.
|
||||||
*/
|
*/
|
||||||
@@ -680,6 +691,10 @@
|
|||||||
|| ((JERRY_VM_EXEC_STOP != 0) && (JERRY_VM_EXEC_STOP != 1))
|
|| ((JERRY_VM_EXEC_STOP != 0) && (JERRY_VM_EXEC_STOP != 1))
|
||||||
# error "Invalid value for 'JERRY_VM_EXEC_STOP' macro."
|
# error "Invalid value for 'JERRY_VM_EXEC_STOP' macro."
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined (JERRY_VM_THROW) \
|
||||||
|
|| ((JERRY_VM_THROW != 0) && (JERRY_VM_THROW != 1))
|
||||||
|
# error "Invalid value for 'JERRY_VM_THROW' macro."
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cross component requirements check.
|
* Cross component requirements check.
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ typedef enum
|
|||||||
ECMA_STATUS_EXCEPTION = (1u << 3), /**< last exception is a normal exception */
|
ECMA_STATUS_EXCEPTION = (1u << 3), /**< last exception is a normal exception */
|
||||||
ECMA_STATUS_ABORT = (1u << 4), /**< last exception is an abort */
|
ECMA_STATUS_ABORT = (1u << 4), /**< last exception is an abort */
|
||||||
ECMA_STATUS_ERROR_UPDATE = (1u << 5), /**< the error_object_created_callback_p is called */
|
ECMA_STATUS_ERROR_UPDATE = (1u << 5), /**< the error_object_created_callback_p is called */
|
||||||
|
#if JERRY_VM_THROW
|
||||||
|
ECMA_STATUS_ERROR_THROWN = (1u << 6), /**< the vm_throw_callback_p is called */
|
||||||
|
#endif /* JERRY_VM_THROW */
|
||||||
} ecma_status_flag_t;
|
} ecma_status_flag_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -360,6 +360,7 @@ bool jerry_backtrace_is_strict (jerry_backtrace_frame_t *frame_p);
|
|||||||
* Miscellaneous functions.
|
* Miscellaneous functions.
|
||||||
*/
|
*/
|
||||||
void jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, void *user_p, uint32_t frequency);
|
void jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, void *user_p, uint32_t frequency);
|
||||||
|
void jerry_set_vm_throw_callback (jerry_vm_throw_callback_t throw_cb, void *user_p);
|
||||||
jerry_value_t jerry_get_resource_name (const jerry_value_t value);
|
jerry_value_t jerry_get_resource_name (const jerry_value_t value);
|
||||||
jerry_value_t jerry_get_user_value (const jerry_value_t value);
|
jerry_value_t jerry_get_user_value (const jerry_value_t value);
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ typedef enum
|
|||||||
JERRY_FEATURE_SNAPSHOT_EXEC, /**< executing snapshot files */
|
JERRY_FEATURE_SNAPSHOT_EXEC, /**< executing snapshot files */
|
||||||
JERRY_FEATURE_DEBUGGER, /**< debugging */
|
JERRY_FEATURE_DEBUGGER, /**< debugging */
|
||||||
JERRY_FEATURE_VM_EXEC_STOP, /**< stopping ECMAScript execution */
|
JERRY_FEATURE_VM_EXEC_STOP, /**< stopping ECMAScript execution */
|
||||||
|
JERRY_FEATURE_VM_THROW, /**< capturing ECMAScript throws */
|
||||||
JERRY_FEATURE_JSON, /**< JSON support */
|
JERRY_FEATURE_JSON, /**< JSON support */
|
||||||
JERRY_FEATURE_PROMISE, /**< promise support */
|
JERRY_FEATURE_PROMISE, /**< promise support */
|
||||||
JERRY_FEATURE_TYPEDARRAY, /**< Typedarray support */
|
JERRY_FEATURE_TYPEDARRAY, /**< Typedarray support */
|
||||||
@@ -306,6 +307,15 @@ typedef void (*jerry_error_object_created_callback_t) (const jerry_value_t error
|
|||||||
*/
|
*/
|
||||||
typedef jerry_value_t (*jerry_vm_exec_stop_callback_t) (void *user_p);
|
typedef jerry_value_t (*jerry_vm_exec_stop_callback_t) (void *user_p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function which is called when an error is thrown in an ECMAScript code.
|
||||||
|
* The callback should not change the error_value. The callback is not called again
|
||||||
|
* until the value is caught.
|
||||||
|
*
|
||||||
|
* Note: the engine considers errors thrown by external functions as never caught.
|
||||||
|
*/
|
||||||
|
typedef void (*jerry_vm_throw_callback_t) (const jerry_value_t error_value, void *user_p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function type applied for each data property of an object.
|
* Function type applied for each data property of an object.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -113,8 +113,11 @@ jcontext_take_exception (void)
|
|||||||
{
|
{
|
||||||
JERRY_ASSERT (jcontext_has_pending_exception ());
|
JERRY_ASSERT (jcontext_has_pending_exception ());
|
||||||
|
|
||||||
jcontext_set_abort_flag (false);
|
JERRY_CONTEXT (status_flags) &= (uint32_t) ~(ECMA_STATUS_EXCEPTION
|
||||||
jcontext_set_exception_flag (false);
|
#if JERRY_VM_THROW
|
||||||
|
| ECMA_STATUS_ERROR_THROWN
|
||||||
|
#endif /* JERRY_VM_THROW */
|
||||||
|
| ECMA_STATUS_ABORT);
|
||||||
return JERRY_CONTEXT (error_value);
|
return JERRY_CONTEXT (error_value);
|
||||||
} /* jcontext_take_exception */
|
} /* jcontext_take_exception */
|
||||||
|
|
||||||
|
|||||||
@@ -200,6 +200,11 @@ struct jerry_context_t
|
|||||||
* ECMAScript execution should be stopped */
|
* ECMAScript execution should be stopped */
|
||||||
#endif /* JERRY_VM_EXEC_STOP */
|
#endif /* JERRY_VM_EXEC_STOP */
|
||||||
|
|
||||||
|
#if JERRY_VM_THROW
|
||||||
|
void *vm_throw_callback_user_p; /**< user pointer for vm_throw_callback_p */
|
||||||
|
jerry_vm_throw_callback_t vm_throw_callback_p; /**< callback for capturing throws */
|
||||||
|
#endif /* JERRY_VM_THROW */
|
||||||
|
|
||||||
#if (JERRY_STACK_LIMIT != 0)
|
#if (JERRY_STACK_LIMIT != 0)
|
||||||
uintptr_t stack_base; /**< stack base marker */
|
uintptr_t stack_base; /**< stack base marker */
|
||||||
#endif /* (JERRY_STACK_LIMIT != 0) */
|
#endif /* (JERRY_STACK_LIMIT != 0) */
|
||||||
|
|||||||
@@ -4457,6 +4457,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
|||||||
if (context_type == VM_CONTEXT_FINALLY_THROW)
|
if (context_type == VM_CONTEXT_FINALLY_THROW)
|
||||||
{
|
{
|
||||||
jcontext_raise_exception (*stack_top_p);
|
jcontext_raise_exception (*stack_top_p);
|
||||||
|
#if JERRY_VM_THROW
|
||||||
|
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_ERROR_THROWN;
|
||||||
|
#endif /* JERRY_VM_THROW */
|
||||||
result = ECMA_VALUE_ERROR;
|
result = ECMA_VALUE_ERROR;
|
||||||
|
|
||||||
#if JERRY_DEBUGGER
|
#if JERRY_DEBUGGER
|
||||||
@@ -4789,6 +4792,20 @@ error:
|
|||||||
ecma_fast_free_value (stack_item);
|
ecma_fast_free_value (stack_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if JERRY_VM_THROW
|
||||||
|
if (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_ERROR_THROWN))
|
||||||
|
{
|
||||||
|
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_ERROR_THROWN;
|
||||||
|
|
||||||
|
jerry_vm_throw_callback_t vm_throw_callback_p = JERRY_CONTEXT (vm_throw_callback_p);
|
||||||
|
|
||||||
|
if (vm_throw_callback_p != NULL)
|
||||||
|
{
|
||||||
|
vm_throw_callback_p (JERRY_CONTEXT (error_value), JERRY_CONTEXT (vm_throw_callback_user_p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* JERRY_VM_THROW */
|
||||||
|
|
||||||
#if JERRY_DEBUGGER
|
#if JERRY_DEBUGGER
|
||||||
const uint32_t dont_stop = (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION
|
const uint32_t dont_stop = (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION
|
||||||
| JERRY_DEBUGGER_VM_IGNORE
|
| JERRY_DEBUGGER_VM_IGNORE
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ set(SOURCE_UNIT_TEST_MAIN_MODULES
|
|||||||
test-context-data.c
|
test-context-data.c
|
||||||
test-dataview.c
|
test-dataview.c
|
||||||
test-date-helpers.c
|
test-date-helpers.c
|
||||||
test-exec-stop.c
|
|
||||||
test-external-string.c
|
test-external-string.c
|
||||||
test-from-property-descriptor.c
|
test-from-property-descriptor.c
|
||||||
test-get-own-property.c
|
test-get-own-property.c
|
||||||
@@ -91,6 +90,8 @@ set(SOURCE_UNIT_TEST_MAIN_MODULES
|
|||||||
test-to-property-descriptor.c
|
test-to-property-descriptor.c
|
||||||
test-typedarray.c
|
test-typedarray.c
|
||||||
test-unicode.c
|
test-unicode.c
|
||||||
|
test-vm-exec-stop.c
|
||||||
|
test-vm-throw.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# jerry_heap_stats_t.size == 0 if system allocator is used.
|
# jerry_heap_stats_t.size == 0 if system allocator is used.
|
||||||
|
|||||||
@@ -0,0 +1,199 @@
|
|||||||
|
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "jerryscript.h"
|
||||||
|
|
||||||
|
#include "test-common.h"
|
||||||
|
|
||||||
|
static int mode = 0;
|
||||||
|
static int counter = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
vm_throw_callback (const jerry_value_t error_value, /**< captured error */
|
||||||
|
void *user_p) /**< user pointer */
|
||||||
|
{
|
||||||
|
TEST_ASSERT (user_p == (void *) &mode);
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
TEST_ASSERT (counter == 1);
|
||||||
|
TEST_ASSERT (jerry_value_is_number (error_value) && jerry_get_number_value (error_value) == -5.6);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
TEST_ASSERT (counter == 1);
|
||||||
|
TEST_ASSERT (jerry_value_is_null (error_value));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
jerry_char_t string_buf[2];
|
||||||
|
jerry_size_t size = sizeof (string_buf);
|
||||||
|
|
||||||
|
string_buf[0] = '\0';
|
||||||
|
string_buf[1] = '\0';
|
||||||
|
|
||||||
|
TEST_ASSERT (counter >= 1 && counter <= 3);
|
||||||
|
TEST_ASSERT (jerry_value_is_string (error_value));
|
||||||
|
TEST_ASSERT (jerry_get_string_size (error_value) == size);
|
||||||
|
TEST_ASSERT (jerry_string_to_char_buffer (error_value, string_buf, size) == size);
|
||||||
|
TEST_ASSERT (string_buf[0] == 'e' && string_buf[1] == (char) ('0' + counter));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
TEST_ASSERT (counter == 1);
|
||||||
|
TEST_ASSERT (jerry_get_error_type (error_value) == JERRY_ERROR_RANGE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
TEST_ASSERT (mode == 4);
|
||||||
|
TEST_ASSERT (counter >= 1 && counter <= 2);
|
||||||
|
|
||||||
|
jerry_error_t error = (counter == 1) ? JERRY_ERROR_REFERENCE : JERRY_ERROR_TYPE;
|
||||||
|
TEST_ASSERT (jerry_get_error_type (error_value) == error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 5:
|
||||||
|
{
|
||||||
|
TEST_ASSERT (counter >= 1 && counter <= 2);
|
||||||
|
TEST_ASSERT (jerry_value_is_false (error_value));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
TEST_ASSERT (mode == 6 || mode == 7);
|
||||||
|
TEST_ASSERT (counter == 1);
|
||||||
|
TEST_ASSERT (jerry_value_is_true (error_value));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /* vm_throw_callback */
|
||||||
|
|
||||||
|
static jerry_value_t
|
||||||
|
native_handler (const jerry_call_info_t *call_info_p, /**< call info */
|
||||||
|
const jerry_value_t args_p[], /**< arguments */
|
||||||
|
const jerry_length_t args_count) /**< arguments length */
|
||||||
|
{
|
||||||
|
(void) call_info_p;
|
||||||
|
(void) args_p;
|
||||||
|
TEST_ASSERT (args_count == 0);
|
||||||
|
|
||||||
|
jerry_char_t source[] = TEST_STRING_LITERAL ("throw false");
|
||||||
|
return jerry_eval (source, sizeof (source) - 1, JERRY_PARSE_NO_OPTS);
|
||||||
|
} /* native_handler */
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_eval (const char *script_p, /**< script to evaluate */
|
||||||
|
bool should_throw) /**< script throws an error */
|
||||||
|
{
|
||||||
|
jerry_value_t result = jerry_eval ((const jerry_char_t *) script_p, strlen (script_p), JERRY_PARSE_NO_OPTS);
|
||||||
|
TEST_ASSERT (jerry_value_is_error (result) == should_throw);
|
||||||
|
jerry_release_value (result);
|
||||||
|
} /* do_eval */
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
TEST_INIT ();
|
||||||
|
|
||||||
|
/* Test stopping an infinite loop. */
|
||||||
|
if (!jerry_is_feature_enabled (JERRY_FEATURE_VM_THROW))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_init (JERRY_INIT_EMPTY);
|
||||||
|
|
||||||
|
jerry_set_vm_throw_callback (vm_throw_callback, (void *) &mode);
|
||||||
|
|
||||||
|
mode = 0;
|
||||||
|
counter = 0;
|
||||||
|
do_eval (TEST_STRING_LITERAL ("throw -5.6"),
|
||||||
|
true);
|
||||||
|
TEST_ASSERT (counter == 1);
|
||||||
|
|
||||||
|
mode = 1;
|
||||||
|
counter = 0;
|
||||||
|
do_eval (TEST_STRING_LITERAL ("function f() { throw null }\n"
|
||||||
|
"function g() { f() }\n"
|
||||||
|
"g()\n"),
|
||||||
|
true);
|
||||||
|
TEST_ASSERT (counter == 1);
|
||||||
|
|
||||||
|
mode = 2;
|
||||||
|
counter = 0;
|
||||||
|
do_eval (TEST_STRING_LITERAL ("function f() { throw 'e1' }\n"
|
||||||
|
"function g() { try { f() } catch (e) { throw 'e2' } }\n"
|
||||||
|
"try { g() } catch (e) { throw 'e3' }\n"),
|
||||||
|
true);
|
||||||
|
TEST_ASSERT (counter == 3);
|
||||||
|
|
||||||
|
mode = 3;
|
||||||
|
counter = 0;
|
||||||
|
do_eval (TEST_STRING_LITERAL ("function f() { throw new RangeError() }\n"
|
||||||
|
"function g() { try { f() } finally { } }\n"
|
||||||
|
"try { g() } finally { }\n"),
|
||||||
|
true);
|
||||||
|
TEST_ASSERT (counter == 1);
|
||||||
|
|
||||||
|
mode = 4;
|
||||||
|
counter = 0;
|
||||||
|
do_eval (TEST_STRING_LITERAL ("function f() { unresolved }\n"
|
||||||
|
"function g() { try { f() } finally { null.member } }\n"
|
||||||
|
"try { g() } finally { }\n"),
|
||||||
|
true);
|
||||||
|
TEST_ASSERT (counter == 2);
|
||||||
|
|
||||||
|
/* Native functions may trigger the call twice: */
|
||||||
|
jerry_value_t global_object_value = jerry_get_global_object ();
|
||||||
|
jerry_value_t function_value = jerry_create_external_function (native_handler);
|
||||||
|
jerry_value_t function_name_value = jerry_create_string ((const jerry_char_t *) "native");
|
||||||
|
|
||||||
|
jerry_release_value (jerry_set_property (global_object_value, function_name_value, function_value));
|
||||||
|
jerry_release_value (function_name_value);
|
||||||
|
jerry_release_value (function_value);
|
||||||
|
jerry_release_value (global_object_value);
|
||||||
|
|
||||||
|
mode = 5;
|
||||||
|
counter = 0;
|
||||||
|
do_eval (TEST_STRING_LITERAL ("native()\n"),
|
||||||
|
true);
|
||||||
|
TEST_ASSERT (counter == 2);
|
||||||
|
|
||||||
|
/* Built-in functions should not trigger the call twice: */
|
||||||
|
mode = 6;
|
||||||
|
counter = 0;
|
||||||
|
do_eval (TEST_STRING_LITERAL ("function f() { eval('eval(\\'throw true\\')') }\n"
|
||||||
|
"f()\n"),
|
||||||
|
true);
|
||||||
|
TEST_ASSERT (counter == 1);
|
||||||
|
|
||||||
|
mode = 7;
|
||||||
|
counter = 0;
|
||||||
|
do_eval (TEST_STRING_LITERAL ("function f() { [1].map(function() { throw true }) }\n"
|
||||||
|
"f()\n"),
|
||||||
|
true);
|
||||||
|
TEST_ASSERT (counter == 1);
|
||||||
|
|
||||||
|
jerry_cleanup ();
|
||||||
|
return 0;
|
||||||
|
} /* main */
|
||||||
+4
-1
@@ -155,7 +155,9 @@ def get_arguments():
|
|||||||
coregrp.add_argument('--valgrind', metavar='X', choices=['ON', 'OFF'], type=str.upper,
|
coregrp.add_argument('--valgrind', metavar='X', choices=['ON', 'OFF'], type=str.upper,
|
||||||
help=devhelp('enable Valgrind support (%(choices)s)'))
|
help=devhelp('enable Valgrind support (%(choices)s)'))
|
||||||
coregrp.add_argument('--vm-exec-stop', metavar='X', choices=['ON', 'OFF'], type=str.upper,
|
coregrp.add_argument('--vm-exec-stop', metavar='X', choices=['ON', 'OFF'], type=str.upper,
|
||||||
help='enable VM execution stopping (%(choices)s)')
|
help='enable VM execution stop callback (%(choices)s)')
|
||||||
|
coregrp.add_argument('--vm-throw', metavar='X', choices=['ON', 'OFF'], type=str.upper,
|
||||||
|
help='enable VM throw callback (%(choices)s)')
|
||||||
|
|
||||||
maingrp = parser.add_argument_group('jerry-main options')
|
maingrp = parser.add_argument_group('jerry-main options')
|
||||||
maingrp.add_argument('--link-map', metavar='X', choices=['ON', 'OFF'], type=str.upper,
|
maingrp.add_argument('--link-map', metavar='X', choices=['ON', 'OFF'], type=str.upper,
|
||||||
@@ -223,6 +225,7 @@ def generate_build_options(arguments):
|
|||||||
build_options_append('JERRY_SYSTEM_ALLOCATOR', arguments.system_allocator)
|
build_options_append('JERRY_SYSTEM_ALLOCATOR', arguments.system_allocator)
|
||||||
build_options_append('JERRY_VALGRIND', arguments.valgrind)
|
build_options_append('JERRY_VALGRIND', arguments.valgrind)
|
||||||
build_options_append('JERRY_VM_EXEC_STOP', arguments.vm_exec_stop)
|
build_options_append('JERRY_VM_EXEC_STOP', arguments.vm_exec_stop)
|
||||||
|
build_options_append('JERRY_VM_THROW', arguments.vm_throw)
|
||||||
|
|
||||||
if arguments.gc_mark_limit is not None:
|
if arguments.gc_mark_limit is not None:
|
||||||
build_options.append('-D%s=%s' % ('JERRY_GC_MARK_LIMIT', arguments.gc_mark_limit))
|
build_options.append('-D%s=%s' % ('JERRY_GC_MARK_LIMIT', arguments.gc_mark_limit))
|
||||||
|
|||||||
+1
-1
@@ -50,7 +50,7 @@ OPTIONS_DEBUG = ['--debug']
|
|||||||
OPTIONS_SNAPSHOT = ['--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on']
|
OPTIONS_SNAPSHOT = ['--snapshot-save=on', '--snapshot-exec=on', '--jerry-cmdline-snapshot=on']
|
||||||
OPTIONS_UNITTESTS = ['--unittests=on', '--jerry-cmdline=off', '--error-messages=on',
|
OPTIONS_UNITTESTS = ['--unittests=on', '--jerry-cmdline=off', '--error-messages=on',
|
||||||
'--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on',
|
'--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on',
|
||||||
'--line-info=on', '--mem-stats=on']
|
'--vm-throw=on', '--line-info=on', '--mem-stats=on']
|
||||||
OPTIONS_DOCTESTS = ['--doctests=on', '--jerry-cmdline=off', '--error-messages=on',
|
OPTIONS_DOCTESTS = ['--doctests=on', '--jerry-cmdline=off', '--error-messages=on',
|
||||||
'--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on']
|
'--snapshot-save=on', '--snapshot-exec=on', '--vm-exec-stop=on']
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user