Skip to content

Commit 3b77117

Browse files
authored
Add a callback which is called when Error objects are created (#4465)
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg [email protected]
1 parent e009641 commit 3b77117

File tree

14 files changed

+249
-51
lines changed

14 files changed

+249
-51
lines changed

docs/02.API-REFERENCE.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,33 @@ typedef void (*jerry_object_native_free_callback_t) (void *native_p);
586586
- [jerry_object_native_info_t](#jerry_object_native_info_t)
587587
- [jerry_create_arraybuffer_external](#jerry_create_arraybuffer_external)
588588

589+
## jerry_error_object_created_callback_t
590+
591+
**Summary**
592+
593+
Decorator callback for Error objects. This native callback is called every time when an Error
594+
object is created and the decorator can create or update any properties of the newly created
595+
Error object.
596+
597+
*Note*:
598+
- The callback function cannot be called recursively, so the Error objects created
599+
when the callback is running are not updated.
600+
601+
*New in version [[NEXT_RELEASE]]*.
602+
603+
**Prototype**
604+
605+
```c
606+
typedef void (*jerry_error_object_created_callback_t) (const jerry_value_t error_object, void *user_p);
607+
```
608+
609+
- `error_object` - the newly created Error object.
610+
- `user_p` - pointer passed to [jerry_set_error_object_created_callback](#jerry_set_error_object_created_callback).
611+
612+
**See also**
613+
614+
- [jerry_set_error_object_created_callback](#jerry_set_error_object_created_callback)
615+
589616
## jerry_object_native_info_t
590617

591618
**Summary**
@@ -2996,6 +3023,54 @@ jerry_get_value_from_error (jerry_value_t value, bool release)
29963023
- [jerry_create_error_from_value](#jerry_create_error_from_value)
29973024
- [jerry_create_abort_from_value](#jerry_create_abort_from_value)
29983025

3026+
## jerry_set_error_object_created_callback
3027+
3028+
**Summary**
3029+
3030+
Set the decorator callback for newly created Error objects. The operation of the callback
3031+
is described in [jerry_error_object_created_callback_t](#jerry_error_object_created_callback_t).
3032+
3033+
**Prototype**
3034+
3035+
```c
3036+
void jerry_set_error_object_created_callback (jerry_error_object_created_callback_t callback, void *user_p);
3037+
```
3038+
3039+
- `callback` - callback function, the previously set value is overwritten, and setting NULL
3040+
disables the operation
3041+
- `user_p` - pointer passed to the callback function, can be NULL
3042+
3043+
*New in version [[NEXT_RELEASE]]*.
3044+
3045+
**Example**
3046+
3047+
```c
3048+
static void
3049+
error_object_created_callback (const jerry_value_t error_object) /**< new error object */
3050+
void *user_p) /**< user pointer */
3051+
{
3052+
(void) error_object;
3053+
(void) user_p;
3054+
printf ("Notification: a new error is created\n");
3055+
} /* error_object_created_callback */
3056+
3057+
void main(void)
3058+
{
3059+
jerry_init (JERRY_INIT_EMPTY);
3060+
3061+
jerry_set_error_object_created_callback (error_object_created_callback, NULL);
3062+
3063+
jerry_release_value (jerry_create_error (JERRY_ERROR_COMMON,
3064+
(const jerry_char_t *) "Message"));
3065+
3066+
jerry_cleanup ();
3067+
} /* main */
3068+
```
3069+
3070+
**See also**
3071+
3072+
- [jerry_error_object_created_callback_t](#jerry_error_object_created_callback_t)
3073+
29993074
# Getter functions of 'jerry_value_t'
30003075

30013076
Get raw data from API values.

jerry-core/api/jerry-snapshot.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,8 @@ static_snapshot_error_unsupported_literal (snapshot_globals_t *globals_p, /**< s
314314

315315
ecma_deref_ecma_string (literal_string_p);
316316

317-
ecma_object_t *error_object_p = ecma_new_standard_error_with_message (ECMA_ERROR_RANGE,
318-
ecma_stringbuilder_finalize (&builder));
317+
ecma_object_t *error_object_p = ecma_new_standard_error (ECMA_ERROR_RANGE,
318+
ecma_stringbuilder_finalize (&builder));
319319

320320
globals_p->snapshot_error = ecma_create_error_object_reference (error_object_p);
321321
} /* static_snapshot_error_unsupported_literal */

jerry-core/api/jerry.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,6 +1601,20 @@ jerry_get_value_from_error (jerry_value_t value, /**< api value */
16011601
return ret_val;
16021602
} /* jerry_get_value_from_error */
16031603

1604+
/**
1605+
* Set new decorator callback for Error objects. The decorator can
1606+
* create or update any properties of the newly created Error object.
1607+
*/
1608+
void
1609+
jerry_set_error_object_created_callback (jerry_error_object_created_callback_t callback, /**< new callback */
1610+
void *user_p) /**< user pointer passed to the callback */
1611+
{
1612+
jerry_assert_api_available ();
1613+
1614+
JERRY_CONTEXT (error_object_created_callback_p) = callback;
1615+
JERRY_CONTEXT (error_object_created_callback_user_p) = user_p;
1616+
} /* jerry_set_error_object_created_callback */
1617+
16041618
/**
16051619
* Return the type of the Error object if possible.
16061620
*
@@ -1990,15 +2004,15 @@ jerry_create_error_sz (jerry_error_t error_type, /**< type of error */
19902004

19912005
if (message_p == NULL || message_size == 0)
19922006
{
1993-
return ecma_create_error_object_reference (ecma_new_standard_error ((ecma_standard_error_t) error_type));
2007+
return ecma_create_error_object_reference (ecma_new_standard_error ((ecma_standard_error_t) error_type, NULL));
19942008
}
19952009
else
19962010
{
19972011
ecma_string_t *message_string_p = ecma_new_ecma_string_from_utf8 ((lit_utf8_byte_t *) message_p,
19982012
(lit_utf8_size_t) message_size);
19992013

2000-
ecma_object_t *error_object_p = ecma_new_standard_error_with_message ((ecma_standard_error_t) error_type,
2001-
message_string_p);
2014+
ecma_object_t *error_object_p = ecma_new_standard_error ((ecma_standard_error_t) error_type,
2015+
message_string_p);
20022016

20032017
ecma_deref_ecma_string (message_string_p);
20042018

jerry-core/ecma/base/ecma-globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ typedef enum
7272
#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */
7373
ECMA_STATUS_EXCEPTION = (1u << 3), /**< last exception is a normal exception */
7474
ECMA_STATUS_ABORT = (1u << 4), /**< last exception is an abort */
75+
ECMA_STATUS_ERROR_UPDATE = (1u << 5), /**< the error_object_created_callback_p is called */
7576
} ecma_status_flag_t;
7677

7778
/**

jerry-core/ecma/builtin-objects/ecma-builtin-helpers-error.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,13 @@ ecma_builtin_helper_error_dispatch_call (ecma_standard_error_t error_type, /**<
5353
return ECMA_VALUE_ERROR;
5454
}
5555

56-
ecma_object_t *new_error_object_p = ecma_new_standard_error_with_message (error_type,
57-
message_string_p);
56+
ecma_object_t *new_error_object_p = ecma_new_standard_error (error_type, message_string_p);
5857

5958
ecma_deref_ecma_string (message_string_p);
6059
return ecma_make_object_value (new_error_object_p);
6160
}
6261

63-
ecma_object_t *new_error_object_p = ecma_new_standard_error (error_type);
62+
ecma_object_t *new_error_object_p = ecma_new_standard_error (error_type, NULL);
6463

6564
return ecma_make_object_value (new_error_object_p);
6665
} /* ecma_builtin_helper_error_dispatch_call */

jerry-core/ecma/operations/ecma-exceptions.c

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,18 @@ const ecma_error_mapping_t ecma_error_mappings[] =
6969
* Standard ecma-error object constructor.
7070
*
7171
* Note:
72+
* message_string_p can be NULL.
73+
*
74+
* Note:
7275
* calling with ECMA_ERROR_NONE does not make sense thus it will
7376
* cause a fault in the system.
7477
*
7578
* @return pointer to ecma-object representing specified error
7679
* with reference counter set to one.
7780
*/
7881
ecma_object_t *
79-
ecma_new_standard_error (ecma_standard_error_t error_type) /**< native error type */
82+
ecma_new_standard_error (ecma_standard_error_t error_type, /**< native error type */
83+
ecma_string_t *message_string_p) /**< message string */
8084
{
8185
#if ENABLED (JERRY_BUILTIN_ERRORS)
8286
ecma_builtin_id_t prototype_id = ECMA_BUILTIN_ID__COUNT;
@@ -140,23 +144,45 @@ ecma_new_standard_error (ecma_standard_error_t error_type) /**< native error typ
140144

141145
((ecma_extended_object_t *) new_error_obj_p)->u.class_prop.class_id = LIT_MAGIC_STRING_ERROR_UL;
142146

143-
#if ENABLED (JERRY_LINE_INFO)
144-
/* The "stack" identifier is not a magic string. */
145-
const char * const stack_id_p = "stack";
147+
if (message_string_p != NULL)
148+
{
149+
ecma_property_value_t *prop_value_p;
150+
prop_value_p = ecma_create_named_data_property (new_error_obj_p,
151+
ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE),
152+
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
153+
NULL);
154+
155+
ecma_ref_ecma_string (message_string_p);
156+
prop_value_p->value = ecma_make_string_value (message_string_p);
157+
}
146158

147-
ecma_string_t *stack_str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) stack_id_p, 5);
159+
/* Avoid calling the decorator function recursively. */
160+
if (JERRY_CONTEXT (error_object_created_callback_p) != NULL
161+
&& !(JERRY_CONTEXT (status_flags) & ECMA_STATUS_ERROR_UPDATE))
162+
{
163+
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_ERROR_UPDATE;
164+
JERRY_CONTEXT (error_object_created_callback_p) (ecma_make_object_value (new_error_obj_p),
165+
JERRY_CONTEXT (error_object_created_callback_user_p));
166+
JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_ERROR_UPDATE;
167+
}
168+
else
169+
{
170+
#if ENABLED (JERRY_LINE_INFO)
171+
/* Default decorator when line info is enabled. */
172+
ecma_string_t *stack_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_STACK);
148173

149-
ecma_property_value_t *prop_value_p = ecma_create_named_data_property (new_error_obj_p,
150-
stack_str_p,
151-
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
152-
NULL);
153-
ecma_deref_ecma_string (stack_str_p);
174+
ecma_property_value_t *prop_value_p = ecma_create_named_data_property (new_error_obj_p,
175+
stack_str_p,
176+
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
177+
NULL);
178+
ecma_deref_ecma_string (stack_str_p);
154179

155-
ecma_value_t backtrace_value = vm_get_backtrace (0, NULL);
180+
ecma_value_t backtrace_value = vm_get_backtrace (0, NULL);
156181

157-
prop_value_p->value = backtrace_value;
158-
ecma_deref_object (ecma_get_object_from_value (backtrace_value));
182+
prop_value_p->value = backtrace_value;
183+
ecma_deref_object (ecma_get_object_from_value (backtrace_value));
159184
#endif /* ENABLED (JERRY_LINE_INFO) */
185+
}
160186

161187
return new_error_obj_p;
162188
} /* ecma_new_standard_error */
@@ -190,30 +216,6 @@ ecma_get_error_type (ecma_object_t *error_object) /**< possible error object */
190216
return ECMA_ERROR_NONE;
191217
} /* ecma_get_error_type */
192218

193-
/**
194-
* Standard ecma-error object constructor.
195-
*
196-
* @return pointer to ecma-object representing specified error
197-
* with reference counter set to one.
198-
*/
199-
ecma_object_t *
200-
ecma_new_standard_error_with_message (ecma_standard_error_t error_type, /**< native error type */
201-
ecma_string_t *message_string_p) /**< message string */
202-
{
203-
ecma_object_t *new_error_obj_p = ecma_new_standard_error (error_type);
204-
205-
ecma_property_value_t *prop_value_p;
206-
prop_value_p = ecma_create_named_data_property (new_error_obj_p,
207-
ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE),
208-
ECMA_PROPERTY_CONFIGURABLE_WRITABLE,
209-
NULL);
210-
211-
ecma_ref_ecma_string (message_string_p);
212-
prop_value_p->value = ecma_make_string_value (message_string_p);
213-
214-
return new_error_obj_p;
215-
} /* ecma_new_standard_error_with_message */
216-
217219
/**
218220
* Raise a standard ecma-error with the given type and message.
219221
*
@@ -230,12 +232,12 @@ ecma_raise_standard_error (ecma_standard_error_t error_type, /**< error type */
230232
{
231233
ecma_string_t *error_msg_p = ecma_new_ecma_string_from_utf8 (msg_p,
232234
lit_zt_utf8_string_size (msg_p));
233-
error_obj_p = ecma_new_standard_error_with_message (error_type, error_msg_p);
235+
error_obj_p = ecma_new_standard_error (error_type, error_msg_p);
234236
ecma_deref_ecma_string (error_msg_p);
235237
}
236238
else
237239
{
238-
error_obj_p = ecma_new_standard_error (error_type);
240+
error_obj_p = ecma_new_standard_error (error_type, NULL);
239241
}
240242

241243
jcontext_raise_exception (ecma_make_object_value (error_obj_p));
@@ -320,7 +322,7 @@ ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, /**< er
320322

321323
ecma_string_t *builder_str_p = ecma_stringbuilder_finalize (&builder);
322324

323-
ecma_object_t *error_obj_p = ecma_new_standard_error_with_message (error_type, builder_str_p);
325+
ecma_object_t *error_obj_p = ecma_new_standard_error (error_type, builder_str_p);
324326

325327
ecma_deref_ecma_string (builder_str_p);
326328

jerry-core/ecma/operations/ecma-exceptions.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ typedef enum
5151
} ecma_standard_error_t;
5252

5353
ecma_standard_error_t ecma_get_error_type (ecma_object_t *error_object);
54-
ecma_object_t *ecma_new_standard_error (ecma_standard_error_t error_type);
55-
ecma_object_t *ecma_new_standard_error_with_message (ecma_standard_error_t error_type, ecma_string_t *message_string_p);
54+
ecma_object_t *ecma_new_standard_error (ecma_standard_error_t error_type, ecma_string_t *message_string_p);
5655
#if ENABLED (JERRY_ERROR_MESSAGES)
5756
ecma_value_t ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, const char *msg_p, ...);
5857
#endif /* ENABLED (JERRY_ERROR_MESSAGES) */

jerry-core/include/jerryscript-core.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,12 @@ typedef jerry_value_t (*jerry_external_handler_t) (const jerry_value_t function_
231231
*/
232232
typedef void (*jerry_object_native_free_callback_t) (void *native_p);
233233

234+
/**
235+
* Decorator callback for Error objects. The decorator can create
236+
* or update any properties of the newly created Error object.
237+
*/
238+
typedef void (*jerry_error_object_created_callback_t) (const jerry_value_t error_object, void *user_p);
239+
234240
/**
235241
* Callback which tells whether the ECMAScript execution should be stopped.
236242
*
@@ -512,6 +518,7 @@ jerry_value_t jerry_binary_operation (jerry_binary_operation_t op,
512518
jerry_value_t jerry_create_abort_from_value (jerry_value_t value, bool release);
513519
jerry_value_t jerry_create_error_from_value (jerry_value_t value, bool release);
514520
jerry_value_t jerry_get_value_from_error (jerry_value_t value, bool release);
521+
void jerry_set_error_object_created_callback (jerry_error_object_created_callback_t callback, void *user_p);
515522

516523
/**
517524
* Error object function(s).

jerry-core/jcontext/jcontext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ struct jerry_context_t
156156

157157
vm_frame_ctx_t *vm_top_context_p; /**< top (current) interpreter context */
158158
jerry_context_data_header_t *context_data_p; /**< linked list of user-provided context-specific pointers */
159+
void *error_object_created_callback_user_p; /**< user pointer for error_object_update_callback_p */
160+
jerry_error_object_created_callback_t error_object_created_callback_p; /**< decorator callback for Error objects */
159161
size_t ecma_gc_objects_number; /**< number of currently allocated objects */
160162
size_t ecma_gc_new_objects; /**< number of newly allocated objects since last GC session */
161163
size_t jmem_heap_allocated_size; /**< size of allocated regions */

jerry-core/lit/lit-magic-strings.inc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SLICE, "slice")
300300
|| ENABLED (JERRY_ESNEXT)
301301
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SPLIT, "split")
302302
#endif
303+
#if ENABLED (JERRY_LINE_INFO)
304+
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_STACK, "stack")
305+
#endif
303306
#if ENABLED (JERRY_ESNEXT)
304307
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_THROW, "throw")
305308
#endif

0 commit comments

Comments
 (0)