summaryrefslogtreecommitdiffstats
path: root/bytecode.c
blob: bafd047495e071b01d7f2f4c2ba1c1f0b5fecbbc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#include "bytecode.h"
#include "opcode.h"

static int bytecode_operation_length(uint16_t* codeptr) {
  if (opcode_describe(*codeptr)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
    return 2 + codeptr[1] * 2;
  } else {
    return opcode_length(*codeptr);
  }
}

void dump_disassembly(int indent, struct bytecode* bc) {
  if (bc->nclosures > 0) {
    printf("%*s[params: %d]\n", indent, "", bc->nclosures);
  }
  dump_code(indent, bc);
  for (int i=0; i<bc->nsubfunctions; i++) {
    printf("%*ssubfn[%d]:\n", indent, "", i);
    dump_disassembly(indent+2, bc->subfunctions[i]);
  }
}

void dump_code(int indent, struct bytecode* bc) {
  int pc = 0;
  while (pc < bc->codelen) {
    printf("%*s", indent, "");
    dump_operation(bc, bc->code + pc);
    printf("\n");
    pc += bytecode_operation_length(bc->code + pc);
  }
}

void dump_operation(struct bytecode* bc, uint16_t* codeptr) {
  int pc = codeptr - bc->code;
  printf("%04d ", pc);
  const struct opcode_description* op = opcode_describe(bc->code[pc++]);
  printf("%s", op->name);
  if (op->length > 1) {
    uint16_t imm = bc->code[pc++];
    if (op->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
      for (int i=0; i<imm; i++) {
        uint16_t level = bc->code[pc++];
        uint16_t idx = bc->code[pc++];
        if (idx & ARG_NEWCLOSURE) {
          printf(" subfn[%d]", idx & ~ARG_NEWCLOSURE);
        } else {
          printf(" param[%d]", idx);
        }
        if (level) {
          printf("^%d", level);
        }
      }
    } else if (op->flags & OP_HAS_BRANCH) {
      printf(" %04d", pc + imm);
    } else if (op->flags & OP_HAS_CONSTANT) {
      printf(" ");
      jv_dump(jv_array_get(jv_copy(bc->constants), imm), 0);
    } else if (op->flags & OP_HAS_VARIABLE) {
      uint16_t v = bc->code[pc++];
      printf(" v%d", v);
      if (imm) {
        printf("^%d", imm);
      }
    } else {
      printf(" %d", imm);
    }
  }  
}

void symbol_table_free(struct symbol_table* syms) {
  free(syms->cfunctions);
  free(syms);
}

void bytecode_free(struct bytecode* bc) {
  free(bc->code);
  jv_free(bc->constants);
  for (int i=0; i<bc->nsubfunctions; i++)
    bytecode_free(bc->subfunctions[i]);
  if (!bc->parent)
    symbol_table_free(bc->globals);
  free(bc->subfunctions);
  free(bc);
}