From dd5d2da6628f1cd3d1e5d7a2dc4199d58e19aaeb Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Fri, 18 Jun 2021 15:01:48 +0000 Subject: [PATCH] Introduced "debugger" token support. --- src/njs_disassembler.c | 3 +++ src/njs_generator.c | 23 +++++++++++++++++++++++ src/njs_parser.c | 19 +++++++++++++++++-- src/njs_scope.c | 7 +++++++ src/njs_scope.h | 1 + src/njs_vmcode.c | 29 +++++++++++++++++++++++++++++ src/njs_vmcode.h | 7 +++++++ src/test/njs_unit_test.c | 17 +++++++++++++++++ 8 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/njs_disassembler.c b/src/njs_disassembler.c index acfc5e26..010d53ef 100644 --- a/src/njs_disassembler.c +++ b/src/njs_disassembler.c @@ -153,6 +153,9 @@ static njs_code_name_t code_names[] = { { NJS_VMCODE_ASSIGNMENT_ERROR, sizeof(njs_vmcode_variable_t), njs_str("ASSIGNMENT ERROR") }, + + { NJS_VMCODE_DEBUGGER, sizeof(njs_vmcode_debugger_t), + njs_str("DEBUGGER ") }, }; diff --git a/src/njs_generator.c b/src/njs_generator.c index 56cb6fe2..0a021db6 100644 --- a/src/njs_generator.c +++ b/src/njs_generator.c @@ -111,6 +111,8 @@ static njs_int_t njs_generate_continue_statement(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_break_statement(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); +static njs_int_t njs_generate_debugger_statement(njs_vm_t *vm, + njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_statement(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_block_statement(njs_vm_t *vm, @@ -317,6 +319,9 @@ njs_generate(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node) case NJS_TOKEN_BREAK: return njs_generate_break_statement(vm, generator, node); + case NJS_TOKEN_DEBUGGER: + return njs_generate_debugger_statement(vm, generator, node); + case NJS_TOKEN_STATEMENT: return njs_generate_statement(vm, generator, node); @@ -1819,6 +1824,24 @@ syntax_error: } +static njs_int_t +njs_generate_debugger_statement(njs_vm_t *vm, njs_generator_t *generator, + njs_parser_node_t *node) +{ + njs_vmcode_debugger_t *debugger; + + njs_generate_code(generator, njs_vmcode_debugger_t, debugger, + NJS_VMCODE_DEBUGGER, 0, node); + + debugger->retval = njs_generate_dest_index(vm, generator, node); + if (njs_slow_path(debugger->retval == NJS_INDEX_ERROR)) { + return debugger->retval; + } + + return NJS_OK; +} + + static njs_int_t njs_generate_statement(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node) diff --git a/src/njs_parser.c b/src/njs_parser.c index 97b0abbd..fc8adc06 100644 --- a/src/njs_parser.c +++ b/src/njs_parser.c @@ -6545,7 +6545,22 @@ static njs_int_t njs_parser_debugger_statement(njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current) { - return njs_parser_not_supported(parser, token); + parser->node = njs_parser_node_new(parser, NJS_TOKEN_DEBUGGER); + if (parser->node == NULL) { + return NJS_ERROR; + } + + parser->node->token_line = parser->line; + + if (token->type != NJS_TOKEN_SEMICOLON + && token->type != NJS_TOKEN_END) + { + return njs_parser_failed(parser); + } + + njs_lexer_consume_token(parser->lexer, 1); + + return njs_parser_stack_pop(parser); } @@ -8882,6 +8897,7 @@ njs_parser_serialize_node(njs_chb_t *chain, njs_parser_node_t *node) njs_token_serialize(NJS_TOKEN_EVAL); njs_token_serialize(NJS_TOKEN_IMPORT); njs_token_serialize(NJS_TOKEN_EXPORT); + njs_token_serialize(NJS_TOKEN_DEBUGGER); #if 0 @@ -8889,7 +8905,6 @@ njs_parser_serialize_node(njs_chb_t *chain, njs_parser_node_t *node) njs_token_serialize(NJS_TOKEN_META); njs_token_serialize(NJS_TOKEN_ASYNC); njs_token_serialize(NJS_TOKEN_AWAIT); - njs_token_serialize(NJS_TOKEN_DEBUGGER); njs_token_serialize(NJS_TOKEN_ENUM); njs_token_serialize(NJS_TOKEN_CLASS); diff --git a/src/njs_scope.c b/src/njs_scope.c index 29ab18ac..5e3e3754 100644 --- a/src/njs_scope.c +++ b/src/njs_scope.c @@ -111,6 +111,13 @@ njs_scope_global_index(njs_vm_t *vm, const njs_value_t *src, njs_uint_t runtime) } +njs_value_t * +njs_scope_value_get(njs_vm_t *vm, njs_index_t index) +{ + return njs_scope_value(vm, index); +} + + static njs_int_t njs_scope_values_hash_test(njs_lvlhsh_query_t *lhq, void *data) { diff --git a/src/njs_scope.h b/src/njs_scope.h index e7d4c10b..e7bfa7c8 100644 --- a/src/njs_scope.h +++ b/src/njs_scope.h @@ -23,6 +23,7 @@ njs_value_t *njs_scope_create_index_value(njs_vm_t *vm, njs_index_t index); njs_value_t **njs_scope_make(njs_vm_t *vm, uint32_t count); njs_index_t njs_scope_global_index(njs_vm_t *vm, const njs_value_t *src, njs_uint_t runtime); +njs_value_t *njs_scope_value_get(njs_vm_t *vm, njs_index_t index); njs_inline njs_index_t diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c index 2b7253ad..c24a599c 100644 --- a/src/njs_vmcode.c +++ b/src/njs_vmcode.c @@ -37,6 +37,7 @@ static njs_jump_off_t njs_vmcode_instance_of(njs_vm_t *vm, njs_value_t *object, njs_value_t *constructor); static njs_jump_off_t njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld); +static njs_jump_off_t njs_vmcode_debugger(njs_vm_t *vm); static njs_jump_off_t njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval); @@ -603,6 +604,10 @@ next: ret = sizeof(njs_vmcode_2addr_t); break; + case NJS_VMCODE_DEBUGGER: + ret = njs_vmcode_debugger(vm); + break; + default: njs_internal_error(vm, "%d has retval", op); goto error; @@ -1516,6 +1521,30 @@ njs_vmcode_typeof(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld) } +static njs_jump_off_t +njs_vmcode_debugger(njs_vm_t *vm) +{ + /* + * HOW TO DEBUG JS CODE: + * 1) put debugger instruction when certain condition is met + * in the JS code: + * function test() { + * if (<>) debugger; + * } + * 2) set a breakpoint to njs_vmcode_debugger() in gdb. + * + * To see the values of certain indices: + * 1) use njs -d test.js to dump the byte code + * 2) find an appropriate index around DEBUGGER instruction + * 3) in gdb: p *njs_scope_value_get(vm, ) + **/ + + njs_set_undefined(&vm->retval); + + return sizeof(njs_vmcode_debugger_t); +} + + static njs_jump_off_t njs_string_concat(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2) { diff --git a/src/njs_vmcode.h b/src/njs_vmcode.h index 8a28d999..6a2fc26e 100644 --- a/src/njs_vmcode.h +++ b/src/njs_vmcode.h @@ -126,6 +126,7 @@ enum { NJS_VMCODE_TYPEOF, NJS_VMCODE_VOID, NJS_VMCODE_DELETE, + NJS_VMCODE_DEBUGGER, NJS_VMCODE_NOP = 255 }; @@ -421,6 +422,12 @@ typedef struct { } njs_vmcode_variable_t; +typedef struct { + njs_vmcode_t code; + njs_index_t retval; +} njs_vmcode_debugger_t; + + njs_int_t njs_vmcode_interpreter(njs_vm_t *vm, u_char *pc); njs_object_t *njs_function_new_object(njs_vm_t *vm, njs_value_t *constructor); diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 0b458ace..ec920dee 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -16562,6 +16562,23 @@ static njs_unit_test_t njs_test[] = { njs_str("parseFloat('-5.7e+abc')"), njs_str("-5.7") }, + /* debugger. */ + + { njs_str("debugger"), + njs_str("undefined") }, + + { njs_str("debugger;"), + njs_str("undefined") }, + + { njs_str("while (false) debugger;"), + njs_str("undefined") }, + + { njs_str("1 + debugger"), + njs_str("SyntaxError: Unexpected token \"debugger\" in 1") }, + + { njs_str("debugger + 1"), + njs_str("SyntaxError: Unexpected token \"+\" in 1") }, + /* Top-level objects. */ { njs_str("var global = this;" -- 2.47.3