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 | 834M | const struct opcode_description* opcode_describe(opcode op) { |
32 | 834M | if ((int)op >= 0 && (int)op < NUM_OPCODES) { |
33 | 834M | return &opcode_descriptions[op]; |
34 | 834M | } else { |
35 | 0 | return &invalid_opcode_description; |
36 | 0 | } |
37 | 834M | } |
38 | | |
39 | | |
40 | 2.15M | int bytecode_operation_length(uint16_t* codeptr) { |
41 | 2.15M | int length = opcode_describe(*codeptr)->length; |
42 | 2.15M | if (*codeptr == CALL_JQ || *codeptr == TAIL_CALL_JQ) { |
43 | 127k | length += codeptr[1] * 2; |
44 | 127k | } |
45 | 2.15M | return length; |
46 | 2.15M | } |
47 | | |
48 | 84 | static void dump_code(int indent, struct bytecode* bc) { |
49 | 84 | int pc = 0; |
50 | 36.4k | while (pc < bc->codelen) { |
51 | 36.3k | printf("%*s", indent, ""); |
52 | 36.3k | dump_operation(bc, bc->code + pc); |
53 | 36.3k | printf("\n"); |
54 | 36.3k | pc += bytecode_operation_length(bc->code + pc); |
55 | 36.3k | } |
56 | 84 | } |
57 | | |
58 | 12.1k | static void symbol_table_free(struct symbol_table* syms) { |
59 | 12.1k | jv_mem_free(syms->cfunctions); |
60 | 12.1k | jv_free(syms->cfunc_names); |
61 | 12.1k | jv_mem_free(syms); |
62 | 12.1k | } |
63 | | |
64 | 84 | void dump_disassembly(int indent, struct bytecode* bc) { |
65 | 84 | if (bc->nclosures > 0) { |
66 | 10 | printf("%*s[params: ", indent, ""); |
67 | 10 | jv params = jv_object_get(jv_copy(bc->debuginfo), jv_string("params")); |
68 | 24 | for (int i=0; i<bc->nclosures; i++) { |
69 | 14 | if (i) printf(", "); |
70 | 14 | jv name = jv_array_get(jv_copy(params), i); |
71 | 14 | printf("%s", jv_string_value(name)); |
72 | 14 | jv_free(name); |
73 | 14 | } |
74 | 10 | jv_free(params); |
75 | 10 | printf("]\n"); |
76 | 10 | } |
77 | 84 | dump_code(indent, bc); |
78 | 113 | for (int i=0; i<bc->nsubfunctions; i++) { |
79 | 29 | struct bytecode* subfn = bc->subfunctions[i]; |
80 | 29 | jv name = jv_object_get(jv_copy(subfn->debuginfo), jv_string("name")); |
81 | 29 | printf("%*s%s:%d:\n", indent, "", jv_string_value(name), i); |
82 | 29 | jv_free(name); |
83 | 29 | dump_disassembly(indent+2, subfn); |
84 | 29 | } |
85 | 84 | } |
86 | | |
87 | 6.81k | static struct bytecode* getlevel(struct bytecode* bc, int level) { |
88 | 6.84k | while (level > 0) { |
89 | 25 | bc = bc->parent; |
90 | 25 | level--; |
91 | 25 | } |
92 | 6.81k | return bc; |
93 | 6.81k | } |
94 | | |
95 | 36.3k | void dump_operation(struct bytecode* bc, uint16_t* codeptr) { |
96 | 36.3k | int pc = codeptr - bc->code; |
97 | 36.3k | printf("%04d ", pc); |
98 | 36.3k | const struct opcode_description* op = opcode_describe(bc->code[pc++]); |
99 | 36.3k | printf("%s", op->name); |
100 | 36.3k | if (op->length > 1) { |
101 | 22.6k | uint16_t imm = bc->code[pc++]; |
102 | 22.6k | if (op->op == CALL_JQ || op->op == TAIL_CALL_JQ) { |
103 | 75 | for (int i=0; i<imm+1; i++) { |
104 | 45 | uint16_t level = bc->code[pc++]; |
105 | 45 | uint16_t idx = bc->code[pc++]; |
106 | 45 | jv name; |
107 | 45 | if (idx & ARG_NEWCLOSURE) { |
108 | 31 | idx &= ~ARG_NEWCLOSURE; |
109 | 31 | name = jv_object_get(jv_copy(getlevel(bc,level)->subfunctions[idx]->debuginfo), |
110 | 31 | jv_string("name")); |
111 | 31 | } else { |
112 | 14 | name = jv_array_get(jv_object_get(jv_copy(getlevel(bc,level)->debuginfo), |
113 | 14 | jv_string("params")), idx); |
114 | 14 | } |
115 | 45 | printf(" %s:%d", |
116 | 45 | jv_string_value(name), |
117 | 45 | idx); |
118 | 45 | jv_free(name); |
119 | 45 | if (level) { |
120 | 21 | printf("^%d", level); |
121 | 21 | } |
122 | 45 | } |
123 | 22.6k | } else if (op->op == CALL_BUILTIN) { |
124 | 28 | int func = bc->code[pc++]; |
125 | 28 | jv name = jv_array_get(jv_copy(bc->globals->cfunc_names), func); |
126 | 28 | printf(" %s", jv_string_value(name)); |
127 | 28 | jv_free(name); |
128 | 22.6k | } else if (op->flags & OP_HAS_BRANCH) { |
129 | 9.02k | printf(" %04d", pc + imm); |
130 | 13.5k | } else if (op->flags & OP_HAS_CONSTANT) { |
131 | 6.80k | printf(" "); |
132 | 6.80k | jv_dump(jv_array_get(jv_copy(bc->constants), imm), 0); |
133 | 6.80k | } else if (op->flags & OP_HAS_VARIABLE) { |
134 | 6.77k | uint16_t v = bc->code[pc++]; |
135 | 6.77k | jv name = jv_array_get(jv_object_get(jv_copy(getlevel(bc,imm)->debuginfo), jv_string("locals")), v); |
136 | 6.77k | printf(" $%s:%d", |
137 | 6.77k | jv_string_value(name), |
138 | 6.77k | v); |
139 | 6.77k | jv_free(name); |
140 | 6.77k | if (imm) { |
141 | 1 | printf("^%d", imm); |
142 | 1 | } |
143 | 6.77k | } else { |
144 | 0 | printf(" %d", imm); |
145 | 0 | } |
146 | 22.6k | } |
147 | 36.3k | } |
148 | | |
149 | 123k | void bytecode_free(struct bytecode* bc) { |
150 | 123k | if (!bc) |
151 | 937 | return; |
152 | 122k | jv_mem_free(bc->code); |
153 | 122k | jv_free(bc->constants); |
154 | 233k | for (int i=0; i<bc->nsubfunctions; i++) |
155 | 110k | bytecode_free(bc->subfunctions[i]); |
156 | 122k | if (!bc->parent) |
157 | 12.1k | symbol_table_free(bc->globals); |
158 | 122k | jv_mem_free(bc->subfunctions); |
159 | 122k | jv_free(bc->debuginfo); |
160 | 122k | jv_mem_free(bc); |
161 | 122k | } |