mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Add support for aborts. (#2176)
Aborts are similar to exceptions except they are not caught by catch and finally blocks. Callbacks should honor aborts as well and return them without processing them. Aborts are never thrown by JavaScript code. In the future certain events such as out-of-memory condition may also throw aborts. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
parent
b548eae4ad
commit
918eb22a01
@ -1457,13 +1457,54 @@ jerry_value_has_error_flag (const jerry_value_t value);
|
||||
**See also**
|
||||
|
||||
- [jerry_value_t](#jerry_value_t)
|
||||
- [jerry_value_has_abort_flag](#jerry_value_has_abort_flag)
|
||||
|
||||
|
||||
## jerry_value_has_abort_flag
|
||||
|
||||
**Summary**
|
||||
|
||||
Returns whether the given `jerry_value_t` has the error and abort flags set.
|
||||
|
||||
**Prototype**
|
||||
|
||||
```c
|
||||
bool
|
||||
jerry_value_has_abort_flag (const jerry_value_t value);
|
||||
```
|
||||
|
||||
- `value` - api value
|
||||
- return value
|
||||
- true, if the given `jerry_value_t` has the error and abort flags set
|
||||
- false, otherwise
|
||||
|
||||
**Example**
|
||||
|
||||
```c
|
||||
{
|
||||
jerry_value_t value;
|
||||
... // create or acquire value
|
||||
|
||||
if (jerry_value_has_abort_flag (value))
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
jerry_release_value (value);
|
||||
}
|
||||
```
|
||||
|
||||
**See also**
|
||||
|
||||
- [jerry_value_t](#jerry_value_t)
|
||||
- [jerry_value_has_error_flag](#jerry_value_has_error_flag)
|
||||
|
||||
|
||||
## jerry_value_clear_error_flag
|
||||
|
||||
**Summary**
|
||||
|
||||
Clear the error flag.
|
||||
Clear both the error and abort flags.
|
||||
|
||||
**Prototype**
|
||||
|
||||
@ -1490,6 +1531,8 @@ jerry_value_clear_error_flag (jerry_value_t *value_p);
|
||||
**See also**
|
||||
|
||||
- [jerry_value_t](#jerry_value_t)
|
||||
- [jerry_value_set_error_flag](#jerry_value_set_error_flag)
|
||||
- [jerry_value_set_abort_flag](#jerry_value_set_abort_flag)
|
||||
|
||||
|
||||
## jerry_value_set_error_flag
|
||||
@ -1523,6 +1566,43 @@ jerry_value_set_error_flag (jerry_value_t *value_p);
|
||||
**See also**
|
||||
|
||||
- [jerry_value_t](#jerry_value_t)
|
||||
- [jerry_value_clear_error_flag](#jerry_value_clear_error_flag)
|
||||
- [jerry_value_set_abort_flag](#jerry_value_set_abort_flag)
|
||||
|
||||
|
||||
## jerry_value_set_abort_flag
|
||||
|
||||
**Summary**
|
||||
|
||||
Set both the error and abort flags.
|
||||
|
||||
**Prototype**
|
||||
|
||||
```c
|
||||
void
|
||||
jerry_value_set_abort_flag (jerry_value_t *value_p);
|
||||
```
|
||||
|
||||
- `value_p` - pointer to an api value
|
||||
|
||||
**Example**
|
||||
|
||||
```c
|
||||
{
|
||||
jerry_value_t value;
|
||||
... // create or acquire value
|
||||
|
||||
jerry_value_set_abort_flag (&value);
|
||||
|
||||
jerry_release_value (value);
|
||||
}
|
||||
```
|
||||
|
||||
**See also**
|
||||
|
||||
- [jerry_value_t](#jerry_value_t)
|
||||
- [jerry_value_clear_error_flag](#jerry_value_clear_error_flag)
|
||||
- [jerry_value_set_error_flag](#jerry_value_set_error_flag)
|
||||
|
||||
|
||||
## jerry_get_value_without_error_flag
|
||||
|
||||
@ -730,7 +730,7 @@ jerry_snapshot_result_at (const uint32_t *snapshot_p, /**< snapshot */
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (ret_val))
|
||||
{
|
||||
return ecma_create_error_reference (JERRY_CONTEXT (error_value));
|
||||
return ecma_create_error_reference_from_context ();
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
|
||||
@ -82,10 +82,10 @@ static const char * const wrong_args_msg_p = "wrong type of argument";
|
||||
* Assert that it is correct to call API in current state.
|
||||
*
|
||||
* Note:
|
||||
* By convention, there can be some states when API could not be invoked.
|
||||
* By convention, there are some states when API could not be invoked.
|
||||
*
|
||||
* While, API can be invoked jerry_api_available flag is set,
|
||||
* and while it is incorrect to invoke API - it is not set.
|
||||
* The API can be and only be invoked when the ECMA_STATUS_API_AVAILABLE
|
||||
* flag is set.
|
||||
*
|
||||
* This procedure checks whether the API is available, and terminates
|
||||
* the engine if it is unavailable. Otherwise it is a no-op.
|
||||
@ -98,7 +98,7 @@ static const char * const wrong_args_msg_p = "wrong type of argument";
|
||||
static inline void __attr_always_inline___
|
||||
jerry_assert_api_available (void)
|
||||
{
|
||||
if (unlikely (!JERRY_CONTEXT (jerry_api_available)))
|
||||
if (unlikely (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_AVAILABLE)))
|
||||
{
|
||||
/* Terminates the execution. */
|
||||
JERRY_UNREACHABLE ();
|
||||
@ -111,7 +111,7 @@ jerry_assert_api_available (void)
|
||||
static inline void __attr_always_inline___
|
||||
jerry_make_api_available (void)
|
||||
{
|
||||
JERRY_CONTEXT (jerry_api_available) = true;
|
||||
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_API_AVAILABLE;
|
||||
} /* jerry_make_api_available */
|
||||
|
||||
/**
|
||||
@ -120,7 +120,7 @@ jerry_make_api_available (void)
|
||||
static inline void __attr_always_inline___
|
||||
jerry_make_api_unavailable (void)
|
||||
{
|
||||
JERRY_CONTEXT (jerry_api_available) = false;
|
||||
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_API_AVAILABLE;
|
||||
} /* jerry_make_api_unavailable */
|
||||
|
||||
/**
|
||||
@ -152,7 +152,7 @@ jerry_return (jerry_value_t value) /**< return value */
|
||||
{
|
||||
if (ECMA_IS_VALUE_ERROR (value))
|
||||
{
|
||||
value = ecma_create_error_reference (JERRY_CONTEXT (error_value));
|
||||
value = ecma_create_error_reference_from_context ();
|
||||
}
|
||||
|
||||
return value;
|
||||
@ -167,7 +167,7 @@ static inline jerry_value_t __attr_always_inline___
|
||||
jerry_throw (jerry_value_t value) /**< return value */
|
||||
{
|
||||
JERRY_ASSERT (ECMA_IS_VALUE_ERROR (value));
|
||||
return ecma_create_error_reference (JERRY_CONTEXT (error_value));
|
||||
return ecma_create_error_reference_from_context ();
|
||||
} /* jerry_throw */
|
||||
|
||||
/**
|
||||
@ -176,7 +176,7 @@ jerry_throw (jerry_value_t value) /**< return value */
|
||||
void
|
||||
jerry_init (jerry_init_flag_t flags) /**< combination of Jerry flags */
|
||||
{
|
||||
if (unlikely (JERRY_CONTEXT (jerry_api_available)))
|
||||
if (unlikely (JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_AVAILABLE))
|
||||
{
|
||||
/* This function cannot be called twice unless jerry_cleanup is called. */
|
||||
JERRY_UNREACHABLE ();
|
||||
@ -391,7 +391,7 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (parse_status))
|
||||
{
|
||||
return ecma_create_error_reference (JERRY_CONTEXT (error_value));
|
||||
return ecma_create_error_reference_from_context ();
|
||||
}
|
||||
|
||||
ecma_free_value (parse_status);
|
||||
@ -493,7 +493,7 @@ jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (u
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (parse_status))
|
||||
{
|
||||
return ecma_create_error_reference (JERRY_CONTEXT (error_value));
|
||||
return ecma_create_error_reference_from_context ();
|
||||
}
|
||||
|
||||
ecma_free_value (parse_status);
|
||||
@ -809,7 +809,7 @@ bool jerry_is_feature_enabled (const jerry_feature_t feature)
|
||||
} /* jerry_is_feature_enabled */
|
||||
|
||||
/**
|
||||
* Check if the specified value is an error value.
|
||||
* Check if the specified value is an error or abort value.
|
||||
*
|
||||
* @return true - if the error flag of the specified value is true,
|
||||
* false - otherwise
|
||||
@ -822,6 +822,27 @@ jerry_value_has_error_flag (const jerry_value_t value) /**< api value */
|
||||
return ecma_is_value_error_reference (value);
|
||||
} /* jerry_value_has_error_flag */
|
||||
|
||||
/**
|
||||
* Check if the specified value is an abort value.
|
||||
*
|
||||
* @return true - if both the error and abort flags of the specified value are true,
|
||||
* false - otherwise
|
||||
*/
|
||||
bool
|
||||
jerry_value_has_abort_flag (const jerry_value_t value) /**< api value */
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
|
||||
if (!ecma_is_value_error_reference (value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ecma_error_reference_t *error_ref_p = ecma_get_error_reference_from_value (value);
|
||||
|
||||
return (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT) != 0;
|
||||
} /* jerry_value_has_abort_flag */
|
||||
|
||||
/**
|
||||
* Clear the error flag
|
||||
*/
|
||||
@ -832,24 +853,56 @@ jerry_value_clear_error_flag (jerry_value_t *value_p)
|
||||
|
||||
if (ecma_is_value_error_reference (*value_p))
|
||||
{
|
||||
*value_p = ecma_clear_error_reference (*value_p);
|
||||
*value_p = ecma_clear_error_reference (*value_p, false);
|
||||
}
|
||||
} /* jerry_value_clear_error_flag */
|
||||
|
||||
/**
|
||||
* Set the error flag.
|
||||
* Set the error flag if the value is not an error reference.
|
||||
*/
|
||||
void
|
||||
jerry_value_set_error_flag (jerry_value_t *value_p)
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
|
||||
if (!ecma_is_value_error_reference (*value_p))
|
||||
if (unlikely (ecma_is_value_error_reference (*value_p)))
|
||||
{
|
||||
*value_p = ecma_create_error_reference (*value_p);
|
||||
/* This is a rare case so it is optimized for
|
||||
* binary size rather than performance. */
|
||||
if (!jerry_value_has_abort_flag (*value_p))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
jerry_value_clear_error_flag (value_p);
|
||||
}
|
||||
|
||||
*value_p = ecma_create_error_reference (*value_p, true);
|
||||
} /* jerry_value_set_error_flag */
|
||||
|
||||
/**
|
||||
* Set both the abort and error flags if the value is not an error reference.
|
||||
*/
|
||||
void
|
||||
jerry_value_set_abort_flag (jerry_value_t *value_p)
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
|
||||
if (unlikely (ecma_is_value_error_reference (*value_p)))
|
||||
{
|
||||
/* This is a rare case so it is optimized for
|
||||
* binary size rather than performance. */
|
||||
if (jerry_value_has_abort_flag (*value_p))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
jerry_value_clear_error_flag (value_p);
|
||||
}
|
||||
|
||||
*value_p = ecma_create_error_reference (*value_p, false);
|
||||
} /* jerry_value_set_abort_flag */
|
||||
|
||||
/**
|
||||
* If the input value is an error value, then return a new reference to its referenced value.
|
||||
* Otherwise, return a new reference to the value itself.
|
||||
|
||||
@ -902,7 +902,7 @@ ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< sever
|
||||
{
|
||||
--JERRY_CONTEXT (ecma_prop_hashmap_alloc_state);
|
||||
}
|
||||
JERRY_CONTEXT (ecma_prop_hashmap_alloc_last_is_hs_gc) = false;
|
||||
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_SEV_GC;
|
||||
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
|
||||
|
||||
/*
|
||||
@ -921,14 +921,14 @@ ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< sever
|
||||
JERRY_ASSERT (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH);
|
||||
|
||||
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
|
||||
if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_last_is_hs_gc))
|
||||
if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_HIGH_SEV_GC)
|
||||
{
|
||||
JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_MAX;
|
||||
}
|
||||
else if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) < ECMA_PROP_HASHMAP_ALLOC_MAX)
|
||||
{
|
||||
++JERRY_CONTEXT (ecma_prop_hashmap_alloc_state);
|
||||
JERRY_CONTEXT (ecma_prop_hashmap_alloc_last_is_hs_gc) = true;
|
||||
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_HIGH_SEV_GC;
|
||||
}
|
||||
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
|
||||
|
||||
|
||||
@ -64,6 +64,19 @@ typedef enum
|
||||
ECMA_INIT_MEM_STATS = (1u << 2), /**< dump memory statistics */
|
||||
} ecma_init_flag_t;
|
||||
|
||||
/**
|
||||
* JerryScript status flags.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
ECMA_STATUS_API_AVAILABLE = (1u << 0), /**< api available */
|
||||
ECMA_STATUS_DIRECT_EVAL = (1u << 1), /**< eval is called directly */
|
||||
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
|
||||
ECMA_STATUS_HIGH_SEV_GC = (1u << 2), /**< last gc run was a high severity run */
|
||||
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
|
||||
ECMA_STATUS_EXCEPTION = (1u << 3), /**< last exception is a normal exception */
|
||||
} ecma_status_flag_t;
|
||||
|
||||
/**
|
||||
* Type of ecma value
|
||||
*/
|
||||
@ -1161,12 +1174,27 @@ typedef struct
|
||||
lit_utf8_size_t long_utf8_string_length; /**< length of this long utf-8 string in bytes */
|
||||
} ecma_long_string_t;
|
||||
|
||||
/**
|
||||
* Abort flag for error reference.
|
||||
*/
|
||||
#define ECMA_ERROR_REF_ABORT 0x1
|
||||
|
||||
/**
|
||||
* Value for increasing or decreasing the reference counter.
|
||||
*/
|
||||
#define ECMA_ERROR_REF_ONE (1u << 1)
|
||||
|
||||
/**
|
||||
* Maximum value of the reference counter.
|
||||
*/
|
||||
#define ECMA_ERROR_MAX_REF (UINT32_MAX - 1u)
|
||||
|
||||
/**
|
||||
* Representation of a thrown value on API level.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t refs; /**< reference counter */
|
||||
uint32_t refs_and_flags; /**< reference counter */
|
||||
ecma_value_t value; /**< referenced value */
|
||||
} ecma_error_reference_t;
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#include "ecma-helpers.h"
|
||||
#include "ecma-lcache.h"
|
||||
#include "ecma-property-hashmap.h"
|
||||
#include "jcontext.h"
|
||||
#include "jrt-bit-fields.h"
|
||||
#include "byte-code.h"
|
||||
#include "re-compiler.h"
|
||||
@ -26,7 +27,6 @@
|
||||
|
||||
#ifdef JERRY_DEBUGGER
|
||||
#include "debugger.h"
|
||||
#include "jcontext.h"
|
||||
#endif /* JERRY_DEBUGGER */
|
||||
|
||||
/** \addtogroup ecma ECMA
|
||||
@ -1335,15 +1335,28 @@ JERRY_STATIC_ASSERT (sizeof (ecma_error_reference_t) == 8,
|
||||
* @return error reference value
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_create_error_reference (ecma_value_t value) /**< referenced value */
|
||||
ecma_create_error_reference (ecma_value_t value, /**< referenced value */
|
||||
bool is_exception) /**< error reference is an exception */
|
||||
{
|
||||
ecma_error_reference_t *error_ref_p = (ecma_error_reference_t *) jmem_pools_alloc (sizeof (ecma_error_reference_t));
|
||||
|
||||
error_ref_p->refs = 1;
|
||||
error_ref_p->refs_and_flags = ECMA_ERROR_REF_ONE | (is_exception ? 0 : ECMA_ERROR_REF_ABORT);
|
||||
error_ref_p->value = value;
|
||||
return ecma_make_error_reference_value (error_ref_p);
|
||||
} /* ecma_create_error_reference */
|
||||
|
||||
/**
|
||||
* Create an error reference from the currently thrown error value.
|
||||
*
|
||||
* @return error reference value
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_create_error_reference_from_context (void)
|
||||
{
|
||||
return ecma_create_error_reference (JERRY_CONTEXT (error_value),
|
||||
(JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION) != 0);
|
||||
} /* ecma_create_error_reference_from_context */
|
||||
|
||||
/**
|
||||
* Create an error reference from a given object.
|
||||
*
|
||||
@ -1355,7 +1368,7 @@ ecma_create_error_reference (ecma_value_t value) /**< referenced value */
|
||||
inline ecma_value_t __attr_always_inline___
|
||||
ecma_create_error_object_reference (ecma_object_t *object_p) /**< referenced object */
|
||||
{
|
||||
return ecma_create_error_reference (ecma_make_object_value (object_p));
|
||||
return ecma_create_error_reference (ecma_make_object_value (object_p), true);
|
||||
} /* ecma_create_error_object_reference */
|
||||
|
||||
/**
|
||||
@ -1364,9 +1377,9 @@ ecma_create_error_object_reference (ecma_object_t *object_p) /**< referenced obj
|
||||
void
|
||||
ecma_ref_error_reference (ecma_error_reference_t *error_ref_p) /**< error reference */
|
||||
{
|
||||
if (likely (error_ref_p->refs < UINT32_MAX))
|
||||
if (likely (error_ref_p->refs_and_flags < ECMA_ERROR_MAX_REF))
|
||||
{
|
||||
error_ref_p->refs++;
|
||||
error_ref_p->refs_and_flags += ECMA_ERROR_REF_ONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1380,11 +1393,11 @@ ecma_ref_error_reference (ecma_error_reference_t *error_ref_p) /**< error refere
|
||||
void
|
||||
ecma_deref_error_reference (ecma_error_reference_t *error_ref_p) /**< error reference */
|
||||
{
|
||||
JERRY_ASSERT (error_ref_p->refs > 0);
|
||||
JERRY_ASSERT (error_ref_p->refs_and_flags >= ECMA_ERROR_REF_ONE);
|
||||
|
||||
error_ref_p->refs--;
|
||||
error_ref_p->refs_and_flags -= ECMA_ERROR_REF_ONE;
|
||||
|
||||
if (error_ref_p->refs == 0)
|
||||
if (error_ref_p->refs_and_flags < ECMA_ERROR_REF_ONE)
|
||||
{
|
||||
ecma_free_value (error_ref_p->value);
|
||||
jmem_pools_free (error_ref_p, sizeof (ecma_error_reference_t));
|
||||
@ -1397,15 +1410,28 @@ ecma_deref_error_reference (ecma_error_reference_t *error_ref_p) /**< error refe
|
||||
* @return value referenced by the error
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_clear_error_reference (ecma_value_t value)
|
||||
ecma_clear_error_reference (ecma_value_t value, /**< error reference */
|
||||
bool set_abort_flag) /**< set abort flag */
|
||||
{
|
||||
ecma_error_reference_t *error_ref_p = ecma_get_error_reference_from_value (value);
|
||||
|
||||
JERRY_ASSERT (error_ref_p->refs > 0);
|
||||
|
||||
if (error_ref_p->refs > 1)
|
||||
if (set_abort_flag)
|
||||
{
|
||||
error_ref_p->refs--;
|
||||
if (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT)
|
||||
{
|
||||
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
|
||||
}
|
||||
}
|
||||
|
||||
JERRY_ASSERT (error_ref_p->refs_and_flags >= ECMA_ERROR_REF_ONE);
|
||||
|
||||
if (error_ref_p->refs_and_flags >= 2 * ECMA_ERROR_REF_ONE)
|
||||
{
|
||||
error_ref_p->refs_and_flags -= ECMA_ERROR_REF_ONE;
|
||||
return ecma_copy_value (error_ref_p->value);
|
||||
}
|
||||
|
||||
|
||||
@ -352,11 +352,12 @@ void ecma_set_property_lcached (ecma_property_t *property_p, bool is_lcached);
|
||||
ecma_property_descriptor_t ecma_make_empty_property_descriptor (void);
|
||||
void ecma_free_property_descriptor (ecma_property_descriptor_t *prop_desc_p);
|
||||
|
||||
ecma_value_t ecma_create_error_reference (ecma_value_t value);
|
||||
ecma_value_t ecma_create_error_reference (ecma_value_t value, bool is_exception);
|
||||
ecma_value_t ecma_create_error_reference_from_context (void);
|
||||
ecma_value_t ecma_create_error_object_reference (ecma_object_t *object_p);
|
||||
void ecma_ref_error_reference (ecma_error_reference_t *error_ref_p);
|
||||
void ecma_deref_error_reference (ecma_error_reference_t *error_ref_p);
|
||||
ecma_value_t ecma_clear_error_reference (ecma_value_t value);
|
||||
ecma_value_t ecma_clear_error_reference (ecma_value_t value, bool set_abort_flag);
|
||||
|
||||
void ecma_bytecode_ref (ecma_compiled_code_t *bytecode_p);
|
||||
void ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p);
|
||||
|
||||
@ -43,7 +43,7 @@ ecma_init (void)
|
||||
|
||||
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
|
||||
JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_ON;
|
||||
JERRY_CONTEXT (ecma_prop_hashmap_alloc_last_is_hs_gc) = false;
|
||||
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_SEV_GC;
|
||||
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
|
||||
|
||||
#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN
|
||||
|
||||
@ -157,6 +157,7 @@ ecma_raise_standard_error (ecma_standard_error_t error_type, /**< error type */
|
||||
}
|
||||
|
||||
JERRY_CONTEXT (error_value) = ecma_make_object_value (error_obj_p);
|
||||
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
|
||||
return ECMA_VALUE_ERROR;
|
||||
} /* ecma_raise_standard_error */
|
||||
|
||||
@ -243,6 +244,7 @@ ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, /**< er
|
||||
ecma_deref_ecma_string (error_msg_p);
|
||||
|
||||
JERRY_CONTEXT (error_value) = ecma_make_object_value (error_obj_p);
|
||||
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
|
||||
return ECMA_VALUE_ERROR;
|
||||
} /* ecma_raise_standard_error_with_format */
|
||||
|
||||
|
||||
@ -470,14 +470,14 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
|
||||
|
||||
if (unlikely (ecma_is_value_error_reference (ret_value)))
|
||||
{
|
||||
JERRY_CONTEXT (error_value) = ecma_clear_error_reference (ret_value);
|
||||
JERRY_CONTEXT (error_value) = ecma_clear_error_reference (ret_value, true);
|
||||
ret_value = ECMA_VALUE_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION);
|
||||
JERRY_CONTEXT (is_direct_eval_form_call) = false;
|
||||
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL;
|
||||
|
||||
/* 2-3. */
|
||||
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p;
|
||||
|
||||
@ -293,8 +293,10 @@ bool jerry_is_feature_enabled (const jerry_feature_t feature);
|
||||
* Error flag manipulation functions.
|
||||
*/
|
||||
bool jerry_value_has_error_flag (const jerry_value_t value);
|
||||
bool jerry_value_has_abort_flag (const jerry_value_t value);
|
||||
void jerry_value_clear_error_flag (jerry_value_t *value_p);
|
||||
void jerry_value_set_error_flag (jerry_value_t *value_p);
|
||||
void jerry_value_set_abort_flag (jerry_value_t *value_p);
|
||||
jerry_value_t jerry_get_value_without_error_flag (jerry_value_t value);
|
||||
|
||||
/**
|
||||
|
||||
@ -84,13 +84,11 @@ typedef struct
|
||||
ecma_value_t error_value; /**< currently thrown error value */
|
||||
uint32_t lit_magic_string_ex_count; /**< external magic strings count */
|
||||
uint32_t jerry_init_flags; /**< run-time configuration flags */
|
||||
uint8_t is_direct_eval_form_call; /**< direct call from eval */
|
||||
uint8_t jerry_api_available; /**< API availability flag */
|
||||
uint32_t status_flags; /**< run-time flags */
|
||||
|
||||
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
|
||||
uint8_t ecma_prop_hashmap_alloc_state; /**< property hashmap allocation state: 0-4,
|
||||
* if !0 property hashmap allocation is disabled */
|
||||
bool ecma_prop_hashmap_alloc_last_is_hs_gc; /**< true, if and only if the last gc action was a high severity gc */
|
||||
#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */
|
||||
|
||||
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
|
||||
|
||||
@ -2744,6 +2744,7 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */
|
||||
/* It is unlikely that memory can be allocated in an out-of-memory
|
||||
* situation. However, a simple value can still be thrown. */
|
||||
JERRY_CONTEXT (error_value) = ECMA_VALUE_NULL;
|
||||
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
|
||||
return ECMA_VALUE_ERROR;
|
||||
}
|
||||
#ifdef JERRY_ENABLE_ERROR_MESSAGES
|
||||
|
||||
@ -428,7 +428,7 @@ opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
||||
arguments_list_len);
|
||||
}
|
||||
|
||||
JERRY_CONTEXT (is_direct_eval_form_call) = false;
|
||||
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL;
|
||||
|
||||
/* Free registers. */
|
||||
for (uint32_t i = 0; i < arguments_list_len; i++)
|
||||
@ -888,8 +888,10 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_CONTEXT (error_value) = ecma_clear_error_reference (result);
|
||||
JERRY_CONTEXT (error_value) = ecma_clear_error_reference (result, false);
|
||||
}
|
||||
|
||||
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION;
|
||||
result = ECMA_VALUE_ERROR;
|
||||
goto error;
|
||||
}
|
||||
@ -1405,6 +1407,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
||||
case VM_OC_THROW:
|
||||
{
|
||||
JERRY_CONTEXT (error_value) = left_value;
|
||||
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
|
||||
|
||||
result = ECMA_VALUE_ERROR;
|
||||
left_value = ECMA_VALUE_UNDEFINED;
|
||||
goto error;
|
||||
@ -1416,7 +1420,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
||||
}
|
||||
case VM_OC_EVAL:
|
||||
{
|
||||
JERRY_CONTEXT (is_direct_eval_form_call) = true;
|
||||
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_DIRECT_EVAL;
|
||||
JERRY_ASSERT (*byte_code_p >= CBC_CALL && *byte_code_p <= CBC_CALL2_PROP_BLOCK);
|
||||
continue;
|
||||
}
|
||||
@ -2449,6 +2453,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
|
||||
case VM_CONTEXT_FINALLY_THROW:
|
||||
{
|
||||
JERRY_CONTEXT (error_value) = stack_top_p[-2];
|
||||
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
|
||||
|
||||
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth,
|
||||
PARSER_TRY_CONTEXT_STACK_ALLOCATION);
|
||||
@ -2714,10 +2719,6 @@ error:
|
||||
|
||||
if (!ECMA_IS_VALUE_ERROR (result))
|
||||
{
|
||||
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
|
||||
|
||||
stack_top_p = frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth;
|
||||
|
||||
if (vm_stack_find_finally (frame_ctx_p,
|
||||
&stack_top_p,
|
||||
VM_CONTEXT_FINALLY_RETURN,
|
||||
@ -2731,7 +2732,7 @@ error:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION)
|
||||
{
|
||||
if (vm_stack_find_finally (frame_ctx_p,
|
||||
&stack_top_p,
|
||||
@ -2774,40 +2775,19 @@ error:
|
||||
stack_top_p[-2] = JERRY_CONTEXT (error_value);
|
||||
}
|
||||
|
||||
#ifdef JERRY_VM_EXEC_STOP
|
||||
if (JERRY_CONTEXT (vm_exec_stop_cb) != NULL
|
||||
&& --JERRY_CONTEXT (vm_exec_stop_counter) == 0)
|
||||
{
|
||||
result = JERRY_CONTEXT (vm_exec_stop_cb) (JERRY_CONTEXT (vm_exec_stop_user_p));
|
||||
|
||||
if (ecma_is_value_undefined (result))
|
||||
{
|
||||
JERRY_CONTEXT (vm_exec_stop_counter) = JERRY_CONTEXT (vm_exec_stop_frequency);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_CONTEXT (vm_exec_stop_counter) = 1;
|
||||
|
||||
left_value = ECMA_VALUE_UNDEFINED;
|
||||
right_value = ECMA_VALUE_UNDEFINED;
|
||||
|
||||
if (!ecma_is_value_error_reference (result))
|
||||
{
|
||||
JERRY_CONTEXT (error_value) = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_CONTEXT (error_value) = ecma_clear_error_reference (result);
|
||||
}
|
||||
result = ECMA_VALUE_ERROR;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
#endif /* JERRY_VM_EXEC_STOP */
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p);
|
||||
|
||||
stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p);
|
||||
}
|
||||
while (frame_ctx_p->context_depth > 0);
|
||||
}
|
||||
|
||||
ecma_free_value (block_result);
|
||||
return result;
|
||||
@ -2871,7 +2851,7 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
|
||||
}
|
||||
}
|
||||
|
||||
JERRY_CONTEXT (is_direct_eval_form_call) = false;
|
||||
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL;
|
||||
|
||||
JERRY_CONTEXT (vm_top_context_p) = frame_ctx_p;
|
||||
|
||||
@ -3000,7 +2980,7 @@ vm_is_strict_mode (void)
|
||||
inline bool __attr_always_inline___
|
||||
vm_is_direct_eval_form_call (void)
|
||||
{
|
||||
return JERRY_CONTEXT (is_direct_eval_form_call);
|
||||
return (JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL) != 0;
|
||||
} /* vm_is_direct_eval_form_call */
|
||||
|
||||
/**
|
||||
|
||||
129
tests/unit-core/test-abort.c
Normal file
129
tests/unit-core/test-abort.c
Normal file
@ -0,0 +1,129 @@
|
||||
/* 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 jerry_value_t
|
||||
callback_func (const jerry_value_t function_obj,
|
||||
const jerry_value_t this_val,
|
||||
const jerry_value_t args_p[],
|
||||
const jerry_length_t args_count)
|
||||
{
|
||||
JERRY_UNUSED (function_obj);
|
||||
JERRY_UNUSED (this_val);
|
||||
JERRY_UNUSED (args_p);
|
||||
JERRY_UNUSED (args_count);
|
||||
|
||||
jerry_value_t value = jerry_create_string ((jerry_char_t *) "Abort run!");
|
||||
jerry_value_set_abort_flag (&value);
|
||||
return value;
|
||||
} /* callback_func */
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
TEST_INIT ();
|
||||
|
||||
jerry_init (JERRY_INIT_EMPTY);
|
||||
|
||||
jerry_value_t global = jerry_get_global_object ();
|
||||
jerry_value_t callback_name = jerry_create_string ((jerry_char_t *) "callback");
|
||||
jerry_value_t func = jerry_create_external_function (callback_func);
|
||||
jerry_value_t res = jerry_set_property (global, callback_name, func);
|
||||
TEST_ASSERT (!jerry_value_has_error_flag (res));
|
||||
|
||||
jerry_release_value (res);
|
||||
jerry_release_value (func);
|
||||
jerry_release_value (callback_name);
|
||||
jerry_release_value (global);
|
||||
|
||||
const char *inf_loop_code_src_p = ("while(true) {\n"
|
||||
" with ({}) {\n"
|
||||
" try {\n"
|
||||
" callback();\n"
|
||||
" } catch (e) {\n"
|
||||
" } finally {\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}");
|
||||
|
||||
jerry_value_t parsed_code_val = jerry_parse ((jerry_char_t *) inf_loop_code_src_p,
|
||||
strlen (inf_loop_code_src_p),
|
||||
false);
|
||||
|
||||
TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
|
||||
res = jerry_run (parsed_code_val);
|
||||
|
||||
TEST_ASSERT (jerry_value_has_abort_flag (res));
|
||||
|
||||
jerry_release_value (res);
|
||||
jerry_release_value (parsed_code_val);
|
||||
|
||||
inf_loop_code_src_p = ("function f() {"
|
||||
" while(true) {\n"
|
||||
" with ({}) {\n"
|
||||
" try {\n"
|
||||
" callback();\n"
|
||||
" } catch (e) {\n"
|
||||
" } finally {\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" }"
|
||||
"}\n"
|
||||
"function g() {\n"
|
||||
" for (a in { x:5 })\n"
|
||||
" f();\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"with({})\n"
|
||||
" f();\n");
|
||||
|
||||
parsed_code_val = jerry_parse ((jerry_char_t *) inf_loop_code_src_p,
|
||||
strlen (inf_loop_code_src_p),
|
||||
false);
|
||||
|
||||
TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
|
||||
res = jerry_run (parsed_code_val);
|
||||
|
||||
TEST_ASSERT (jerry_value_has_abort_flag (res));
|
||||
|
||||
jerry_release_value (res);
|
||||
jerry_release_value (parsed_code_val);
|
||||
|
||||
/* Test flag overwrites. */
|
||||
jerry_value_t value = jerry_create_string ((jerry_char_t *) "Error description");
|
||||
TEST_ASSERT (!jerry_value_has_abort_flag (value));
|
||||
TEST_ASSERT (!jerry_value_has_error_flag (value));
|
||||
|
||||
jerry_value_set_abort_flag (&value);
|
||||
TEST_ASSERT (jerry_value_has_abort_flag (value));
|
||||
TEST_ASSERT (jerry_value_has_error_flag (value));
|
||||
|
||||
jerry_value_set_error_flag (&value);
|
||||
TEST_ASSERT (!jerry_value_has_abort_flag (value));
|
||||
TEST_ASSERT (jerry_value_has_error_flag (value));
|
||||
|
||||
jerry_value_set_abort_flag (&value);
|
||||
TEST_ASSERT (jerry_value_has_abort_flag (value));
|
||||
TEST_ASSERT (jerry_value_has_error_flag (value));
|
||||
|
||||
jerry_release_value (value);
|
||||
|
||||
jerry_cleanup ();
|
||||
return 0;
|
||||
} /* main */
|
||||
@ -166,21 +166,6 @@ handler_construct (const jerry_value_t func_obj_val, /**< function object */
|
||||
return jerry_create_boolean (true);
|
||||
} /* handler_construct */
|
||||
|
||||
static jerry_value_t
|
||||
vm_exec_stop_callback (void *user_p)
|
||||
{
|
||||
int *int_p = (int *) user_p;
|
||||
|
||||
if (*int_p > 0)
|
||||
{
|
||||
(*int_p)--;
|
||||
|
||||
return jerry_create_undefined ();
|
||||
}
|
||||
|
||||
return jerry_create_string ((const jerry_char_t *) "Abort script");
|
||||
} /* vm_exec_stop_callback */
|
||||
|
||||
/**
|
||||
* Extended Magic Strings
|
||||
*/
|
||||
@ -1100,50 +1085,6 @@ main (void)
|
||||
jerry_cleanup ();
|
||||
}
|
||||
|
||||
/* Test stopping an infinite loop. */
|
||||
if (jerry_is_feature_enabled (JERRY_FEATURE_VM_EXEC_STOP))
|
||||
{
|
||||
jerry_init (JERRY_INIT_EMPTY);
|
||||
|
||||
int countdown = 6;
|
||||
jerry_set_vm_exec_stop_callback (vm_exec_stop_callback, &countdown, 16);
|
||||
|
||||
const char *inf_loop_code_src_p = "while(true) {}";
|
||||
parsed_code_val = jerry_parse ((jerry_char_t *) inf_loop_code_src_p, strlen (inf_loop_code_src_p), false);
|
||||
TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
|
||||
res = jerry_run (parsed_code_val);
|
||||
TEST_ASSERT (countdown == 0);
|
||||
|
||||
TEST_ASSERT (jerry_value_has_error_flag (res));
|
||||
|
||||
jerry_release_value (res);
|
||||
jerry_release_value (parsed_code_val);
|
||||
|
||||
/* A more complex example. Although the callback error is captured
|
||||
* by the catch block, it is automatically thrown again. */
|
||||
|
||||
/* We keep the callback function, only the countdown is reset. */
|
||||
countdown = 6;
|
||||
|
||||
inf_loop_code_src_p = ("function f() { while (true) ; }\n"
|
||||
"try { f(); } catch(e) {}");
|
||||
|
||||
parsed_code_val = jerry_parse ((jerry_char_t *) inf_loop_code_src_p, strlen (inf_loop_code_src_p), false);
|
||||
|
||||
TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
|
||||
res = jerry_run (parsed_code_val);
|
||||
TEST_ASSERT (countdown == 0);
|
||||
|
||||
/* The result must have an error flag which proves that
|
||||
* the error is thrown again inside the catch block. */
|
||||
TEST_ASSERT (jerry_value_has_error_flag (res));
|
||||
|
||||
jerry_release_value (res);
|
||||
jerry_release_value (parsed_code_val);
|
||||
|
||||
jerry_cleanup ();
|
||||
}
|
||||
|
||||
/* External Magic String */
|
||||
jerry_init (JERRY_INIT_SHOW_OPCODES);
|
||||
|
||||
|
||||
92
tests/unit-core/test-exec-stop.c
Normal file
92
tests/unit-core/test-exec-stop.c
Normal file
@ -0,0 +1,92 @@
|
||||
/* 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 jerry_value_t
|
||||
vm_exec_stop_callback (void *user_p)
|
||||
{
|
||||
int *int_p = (int *) user_p;
|
||||
|
||||
if (*int_p > 0)
|
||||
{
|
||||
(*int_p)--;
|
||||
|
||||
return jerry_create_undefined ();
|
||||
}
|
||||
|
||||
return jerry_create_string ((const jerry_char_t *) "Abort script");
|
||||
} /* vm_exec_stop_callback */
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
TEST_INIT ();
|
||||
|
||||
/* Test stopping an infinite loop. */
|
||||
if (!jerry_is_feature_enabled (JERRY_FEATURE_VM_EXEC_STOP))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
jerry_init (JERRY_INIT_EMPTY);
|
||||
|
||||
int countdown = 6;
|
||||
jerry_set_vm_exec_stop_callback (vm_exec_stop_callback, &countdown, 16);
|
||||
|
||||
const char *inf_loop_code_src_p = "while(true) {}";
|
||||
jerry_value_t parsed_code_val = jerry_parse ((jerry_char_t *) inf_loop_code_src_p,
|
||||
strlen (inf_loop_code_src_p),
|
||||
false);
|
||||
|
||||
TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
|
||||
jerry_value_t res = jerry_run (parsed_code_val);
|
||||
TEST_ASSERT (countdown == 0);
|
||||
|
||||
TEST_ASSERT (jerry_value_has_error_flag (res));
|
||||
|
||||
jerry_release_value (res);
|
||||
jerry_release_value (parsed_code_val);
|
||||
|
||||
/* A more complex example. Although the callback error is captured
|
||||
* by the catch block, it is automatically thrown again. */
|
||||
|
||||
/* We keep the callback function, only the countdown is reset. */
|
||||
countdown = 6;
|
||||
|
||||
inf_loop_code_src_p = ("function f() { while (true) ; }\n"
|
||||
"try { f(); } catch(e) {}");
|
||||
|
||||
parsed_code_val = jerry_parse ((jerry_char_t *) inf_loop_code_src_p,
|
||||
strlen (inf_loop_code_src_p),
|
||||
false);
|
||||
|
||||
TEST_ASSERT (!jerry_value_has_error_flag (parsed_code_val));
|
||||
res = jerry_run (parsed_code_val);
|
||||
TEST_ASSERT (countdown == 0);
|
||||
|
||||
/* The result must have an error flag which proves that
|
||||
* the error is thrown again inside the catch block. */
|
||||
TEST_ASSERT (jerry_value_has_error_flag (res));
|
||||
|
||||
jerry_release_value (res);
|
||||
jerry_release_value (parsed_code_val);
|
||||
|
||||
jerry_cleanup ();
|
||||
return 0;
|
||||
} /* main */
|
||||
Loading…
x
Reference in New Issue
Block a user