Coverage Report

Created: 2026-03-14 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jq/src/bytecode.c
Line
Count
Source
1
#include <stdio.h>
2
#include <stdint.h>
3
#include <stdlib.h>
4
5
#include "bytecode.h"
6
#include "jv_alloc.h"
7
8
// flags, length
9
#define NONE 0, 1
10
#define CONSTANT OP_HAS_CONSTANT, 2
11
#define VARIABLE (OP_HAS_VARIABLE | OP_HAS_BINDING), 3
12
#define GLOBAL (OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING | OP_IS_CALL_PSEUDO), 4
13
#define BRANCH OP_HAS_BRANCH, 2
14
#define CFUNC (OP_HAS_CFUNC | OP_HAS_BINDING), 3
15
#define UFUNC (OP_HAS_UFUNC | OP_HAS_BINDING | OP_IS_CALL_PSEUDO), 4
16
#define DEFINITION (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0
17
#define CLOSURE_REF_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 2
18
19
#define OP(name, imm, in, out) \
20
  {name, #name, imm, in, out},
21
22
static const struct opcode_description opcode_descriptions[] = {
23
#include "opcode_list.h"
24
};
25
26
static const struct opcode_description invalid_opcode_description = {
27
  -1, "#INVALID", 0, 0, 0, 0
28
};
29
30
31
0
const struct opcode_description* opcode_describe(opcode op) {
32
0
  if ((int)op >= 0 && (int)op < NUM_OPCODES) {
33
0
    return &opcode_descriptions[op];
34
0
  } else {
35
0
    return &invalid_opcode_description;
36
0
  }
37
0
}
38
39
40
0
int bytecode_operation_length(uint16_t* codeptr) {
41
0
  int length = opcode_describe(*codeptr)->length;
42
0
  if (*codeptr == CALL_JQ || *codeptr == TAIL_CALL_JQ) {
43
0
    length += codeptr[1] * 2;
44
0
  }
45
0
  return length;
46
0
}
47
48
0
static void dump_code(int indent, struct bytecode* bc) {
49
0
  int pc = 0;
50
0
  while (pc < bc->codelen) {
51
0
    printf("%*s", indent, "");
52
0
    dump_operation(bc, bc->code + pc);
53
0
    printf("\n");
54
0
    pc += bytecode_operation_length(bc->code + pc);
55
0
  }
56
0
}
57
58
0
static void symbol_table_free(struct symbol_table* syms) {
59
0
  jv_mem_free(syms->cfunctions);
60
0
  jv_free(syms->cfunc_names);
61
0
  jv_mem_free(syms);
62
0
}
63
64
0
void dump_disassembly(int indent, struct bytecode* bc) {
65
0
  if (bc->nclosures > 0) {
66
0
    printf("%*s[params: ", indent, "");
67
0
    jv params = jv_object_get(jv_copy(bc->debuginfo), jv_string("params"));
68
0
    for (int i=0; i<bc->nclosures; i++) {
69
0
      if (i) printf(", ");
70
0
      jv name = jv_array_get(jv_copy(params), i);
71
0
      printf("%s", jv_string_value(name));
72
0
      jv_free(name);
73
0
    }
74
0
    jv_free(params);
75
0
    printf("]\n");
76
0
  }
77
0
  dump_code(indent, bc);
78
0
  for (int i=0; i<bc->nsubfunctions; i++) {
79
0
    struct bytecode* subfn = bc->subfunctions[i];
80
0
    jv name = jv_object_get(jv_copy(subfn->debuginfo), jv_string("name"));
81
0
    printf("%*s%s:%d:\n", indent, "", jv_string_value(name), i);
82
0
    jv_free(name);
83
0
    dump_disassembly(indent+2, subfn);
84
0
  }
85
0
}
86
87
0
static struct bytecode* getlevel(struct bytecode* bc, int level) {
88
0
  while (level > 0) {
89
0
    bc = bc->parent;
90
0
    level--;
91
0
  }
92
0
  return bc;
93
0
}
94
95
0
void dump_operation(struct bytecode* bc, uint16_t* codeptr) {
96
0
  int pc = codeptr - bc->code;
97
0
  printf("%04d ", pc);
98
0
  const struct opcode_description* op = opcode_describe(bc->code[pc++]);
99
0
  printf("%s", op->name);
100
0
  if (op->length > 1) {
101
0
    uint16_t imm = bc->code[pc++];
102
0
    if (op->op == CALL_JQ || op->op == TAIL_CALL_JQ) {
103
0
      for (int i=0; i<imm+1; i++) {
104
0
        uint16_t level = bc->code[pc++];
105
0
        uint16_t idx = bc->code[pc++];
106
0
        jv name;
107
0
        if (idx & ARG_NEWCLOSURE) {
108
0
          idx &= ~ARG_NEWCLOSURE;
109
0
          name = jv_object_get(jv_copy(getlevel(bc,level)->subfunctions[idx]->debuginfo),
110
0
                               jv_string("name"));
111
0
        } else {
112
0
          name = jv_array_get(jv_object_get(jv_copy(getlevel(bc,level)->debuginfo),
113
0
                                            jv_string("params")), idx);
114
0
        }
115
0
        printf(" %s:%d",
116
0
               jv_string_value(name),
117
0
               idx);
118
0
        jv_free(name);
119
0
        if (level) {
120
0
          printf("^%d", level);
121
0
        }
122
0
      }
123
0
    } else if (op->op == CALL_BUILTIN) {
124
0
      int func = bc->code[pc++];
125
0
      jv name = jv_array_get(jv_copy(bc->globals->cfunc_names), func);
126
0
      printf(" %s", jv_string_value(name));
127
0
      jv_free(name);
128
0
    } else if (op->flags & OP_HAS_BRANCH) {
129
0
      printf(" %04d", pc + imm);
130
0
    } else if (op->flags & OP_HAS_CONSTANT) {
131
0
      printf(" ");
132
0
      jv_dump(jv_array_get(jv_copy(bc->constants), imm), 0);
133
0
    } else if (op->flags & OP_HAS_VARIABLE) {
134
0
      uint16_t v = bc->code[pc++];
135
0
      jv name = jv_array_get(jv_object_get(jv_copy(getlevel(bc,imm)->debuginfo), jv_string("locals")), v);
136
0
      printf(" $%s:%d",
137
0
             jv_string_value(name),
138
0
             v);
139
0
      jv_free(name);
140
0
      if (imm) {
141
0
        printf("^%d", imm);
142
0
      }
143
0
    } else {
144
0
      printf(" %d", imm);
145
0
    }
146
0
  }
147
0
}
148
149
0
void bytecode_free(struct bytecode* bc) {
150
0
  if (!bc)
151
0
    return;
152
0
  jv_mem_free(bc->code);
153
0
  jv_free(bc->constants);
154
0
  for (int i=0; i<bc->nsubfunctions; i++)
155
0
    bytecode_free(bc->subfunctions[i]);
156
0
  if (!bc->parent)
157
0
    symbol_table_free(bc->globals);
158
0
  jv_mem_free(bc->subfunctions);
159
0
  jv_free(bc->debuginfo);
160
0
  jv_mem_free(bc);
161
0
}