]> git.kaiwu.me - njs.git/commitdiff
Introduced "debugger" token support.
authorDmitry Volyntsev <xeioex@nginx.com>
Fri, 18 Jun 2021 15:01:48 +0000 (15:01 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Fri, 18 Jun 2021 15:01:48 +0000 (15:01 +0000)
src/njs_disassembler.c
src/njs_generator.c
src/njs_parser.c
src/njs_scope.c
src/njs_scope.h
src/njs_vmcode.c
src/njs_vmcode.h
src/test/njs_unit_test.c

index acfc5e26754bf16e77015f24e392ff5011a34def..010d53efc86c925b56ef6ab1a176ec9cecf71307 100644 (file)
@@ -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        ") },
 };
 
 
index 56cb6fe279d5d5b278eda71025cf198cc725c7b0..0a021db60a0beaef1ead7bbb61a95e6f58b402dd 100644 (file)
@@ -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)
index 97b0abbda42feb59330c1b6bacf8b1071ae288e5..fc8adc0649b9eedc81a7cfa38a99328f42b8d5e7 100644 (file)
@@ -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);
index 29ab18acecf846e82a6b4c4d6b918481b8d59d3c..5e3e3754b585a29cdac120a5ec33c3ea526314e8 100644 (file)
@@ -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)
 {
index e7d4c10ba33074d9a93873a9f2ccf66480b66a6e..e7bfa7c84e1a01dff053b5c941810af6c4efc0d3 100644 (file)
@@ -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
index 2b7253ad4dd25063db40d6208a0913013b0608b5..c24a599c9d5ee0345640f80d43dd4e9b8759eeb4 100644 (file)
@@ -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, <index as a hex literal>)
+     **/
+
+    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)
 {
index 8a28d9999fa5608f31d956719f47cdcbd4d7c250..6a2fc26eba3100106e91c28ff6853354da650ad1 100644 (file)
@@ -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);
index 0b458aceccc0287cc1bb4eeeb19adac5bb8bcbff..ec920dee8211ae1c26bd6828035e39a19d9e367f 100644 (file)
@@ -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;"