diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index b95271885..10e49b9ca 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -10606,6 +10606,7 @@ main (void) - [jerry_backtrace_get_frame_type](#jerry_backtrace_get_frame_type) - [jerry_backtrace_get_location](#jerry_backtrace_get_location) - [jerry_backtrace_get_function](#jerry_backtrace_get_function) +- [jerry_backtrace_get_this](#jerry_backtrace_get_this) - [jerry_backtrace_is_strict](#jerry_backtrace_is_strict) @@ -10785,6 +10786,63 @@ backtrace_callback (jerry_backtrace_frame_t *frame_p, - [jerry_backtrace_capture](#jerry_backtrace_capture) +## jerry_backtrace_get_this + +**Summary** + +Initialize and return with the 'this' binding private field of a backtrace frame. +The 'this' binding is a hidden value passed to the called function. As for arrow +functions, the 'this' binding is assigned at function creation. This getter +function can only be called from the callback function of +[jerry_backtrace_capture](#jerry_backtrace_capture), and the value becomes invalid +after the callback returns. + +*Notes*: +- The returned data must not be modified, and does not need to be freed. + Any cleanup is done automatically after the callback is returned. + +**Prototype** + +```c +const jerry_value_t * +jerry_backtrace_get_this (jerry_backtrace_frame_t *frame_p); +``` + +- `frame_p` - a frame passed to the [jerry_backtrace_callback_t](#jerry_backtrace_callback_t) callback +- return value + - pointer to the 'this' binding if the binding is available, + - NULL otherwise + +*New in version [[NEXT_RELEASE]]*. + +**Example** + +See the example of [jerry_backtrace_capture](#jerry_backtrace_capture) +with the following callback function: + +```c +static bool +backtrace_callback (jerry_backtrace_frame_t *frame_p, + void *user_p) +{ + jerry_value_t *this_p = jerry_backtrace_get_this (frame_p); + + if (this_p != NULL) + { + printf ("The 'this' binding is available"); + return true; + } + + printf ("The 'this' binding is NOT available"); + return true; +} +``` + +**See also** + +- [jerry_backtrace_capture](#jerry_backtrace_capture) + + ## jerry_backtrace_is_strict **Summary** diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index a08f798d7..0621d08d3 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -5276,6 +5276,26 @@ jerry_backtrace_get_function (jerry_backtrace_frame_t *frame_p) /**< frame point return NULL; } /* jerry_backtrace_get_function */ +/** + * Initialize and return with the 'this' binding private field of a backtrace frame. + * The 'this' binding is a hidden value passed to the called function. As for arrow + * functions, the 'this' binding is assigned at function creation. + * + * @return pointer to the 'this' binding - if the binding is available, + * NULL - otherwise + */ +const jerry_value_t * +jerry_backtrace_get_this (jerry_backtrace_frame_t *frame_p) /**< frame pointer */ +{ + if (frame_p->frame_type == JERRY_BACKTRACE_FRAME_JS) + { + frame_p->this_binding = frame_p->context_p->this_binding; + return &frame_p->this_binding; + } + + return NULL; +} /* jerry_backtrace_get_this */ + /** * Returns true, if the code bound to the backtrace frame is strict mode code. * diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 32f35aea6..6d8583669 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -350,6 +350,7 @@ void jerry_backtrace_capture (jerry_backtrace_callback_t callback, void *user_p) jerry_backtrace_frame_types_t jerry_backtrace_get_frame_type (jerry_backtrace_frame_t *frame_p); const jerry_backtrace_location_t *jerry_backtrace_get_location (jerry_backtrace_frame_t *frame_p); const jerry_value_t *jerry_backtrace_get_function (jerry_backtrace_frame_t *frame_p); +const jerry_value_t *jerry_backtrace_get_this (jerry_backtrace_frame_t *frame_p); bool jerry_backtrace_is_strict (jerry_backtrace_frame_t *frame_p); /** diff --git a/jerry-core/vm/vm-defines.h b/jerry-core/vm/vm-defines.h index d10f7662d..047f25559 100644 --- a/jerry-core/vm/vm-defines.h +++ b/jerry-core/vm/vm-defines.h @@ -157,6 +157,7 @@ struct jerry_backtrace_frame_internal_t uint8_t frame_type; /**< frame type */ jerry_backtrace_location_t location; /**< location information */ ecma_value_t function; /**< function reference */ + ecma_value_t this_binding; /**< this binding passed to the function */ }; /** diff --git a/tests/unit-core/test-backtrace.c b/tests/unit-core/test-backtrace.c index b1492e586..b32ac580a 100644 --- a/tests/unit-core/test-backtrace.c +++ b/tests/unit-core/test-backtrace.c @@ -61,9 +61,11 @@ backtrace_callback (jerry_backtrace_frame_t *frame_p, /* frame information */ const jerry_backtrace_location_t *location_p = jerry_backtrace_get_location (frame_p); const jerry_value_t *function_p = jerry_backtrace_get_function (frame_p); + const jerry_value_t *this_p = jerry_backtrace_get_this (frame_p); TEST_ASSERT (location_p != NULL); TEST_ASSERT (function_p != NULL); + TEST_ASSERT (this_p != NULL); compare_string (location_p->resource_name, "capture_test.js"); @@ -75,6 +77,7 @@ backtrace_callback (jerry_backtrace_frame_t *frame_p, /* frame information */ TEST_ASSERT (location_p->line == 2); TEST_ASSERT (location_p->column == 1); TEST_ASSERT (handler_args_p[0] == *function_p); + TEST_ASSERT (handler_args_p[1] == *this_p); return true; } @@ -83,15 +86,21 @@ backtrace_callback (jerry_backtrace_frame_t *frame_p, /* frame information */ TEST_ASSERT (jerry_backtrace_is_strict (frame_p)); TEST_ASSERT (location_p->line == 7); TEST_ASSERT (location_p->column == 1); - TEST_ASSERT (handler_args_p[1] == *function_p); + TEST_ASSERT (handler_args_p[2] == *function_p); + TEST_ASSERT (jerry_value_is_undefined (*this_p)); return true; } + jerry_value_t global = jerry_get_global_object (); + TEST_ASSERT (frame_index == 3); TEST_ASSERT (!jerry_backtrace_is_strict (frame_p)); TEST_ASSERT (location_p->line == 11); TEST_ASSERT (location_p->column == 1); - TEST_ASSERT (handler_args_p[2] == *function_p); + TEST_ASSERT (handler_args_p[3] == *function_p); + TEST_ASSERT (global == *this_p); + + jerry_release_value (global); return false; } /* backtrace_callback */ @@ -170,7 +179,7 @@ capture_handler (const jerry_call_info_t *call_info_p, /**< call information */ JERRY_UNUSED (args_p); JERRY_UNUSED (args_count); - TEST_ASSERT (args_count == 0 || args_count == 2 || args_count == 3); + TEST_ASSERT (args_count == 0 || args_count == 2 || args_count == 4); TEST_ASSERT (args_count == 0 || frame_index == 0); jerry_backtrace_callback_t callback = backtrace_callback; @@ -187,7 +196,7 @@ capture_handler (const jerry_call_info_t *call_info_p, /**< call information */ handler_args_p = args_p; jerry_backtrace_capture (callback, (void *) args_p); - TEST_ASSERT (args_count == 0 || frame_index == (int) args_count); + TEST_ASSERT (args_count == 0 || frame_index == (args_count == 4 ? 3 : 2)); return jerry_create_undefined (); } /* capture_handler */ @@ -323,13 +332,13 @@ test_get_backtrace_api_call (void) /* Test frame capturing. */ frame_index = 0; - source_p = ("function f() {\n" - " return capture(f, g, h);\n" - "}\n" + source_p = ("var o = { f:function() {\n" + " return capture(o.f, o, g, h);\n" + "} }\n" "\n" "function g() {\n" " 'use strict';\n" - " return f();\n" + " return o.f();\n" "}\n" "\n" "function h() {\n"