summaryrefslogtreecommitdiffstats
path: root/frame_layout.h
blob: 18a0a65281854d782f19b8ae22cdb2cc916134ea (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
#ifndef FRAME_LAYOUT_H
#include "newstack.h"
#include "bytecode.h"

struct closure {
  struct bytecode* bc;
  stack_ptr env;
};

union frame_entry {
  struct closure closure;
  jv localvar;
};

struct frame {
  struct bytecode* bc;
  stack_ptr env;
  stack_ptr retdata;
  uint16_t* retaddr;
  /* bc->nclosures closures followed by bc->nlocals local variables */
  union frame_entry entries[0]; 
};

static int frame_size(struct bytecode* bc) {
  return sizeof(struct frame) + sizeof(union frame_entry) * (bc->nclosures + bc->nlocals);
}

static struct closure* frame_closure_arg(struct frame* fr, int closure) {
  assert(closure >= 0);
  assert(closure < fr->bc->nclosures);
  return &fr->entries[closure].closure;
}

static jv* frame_local_var(struct frame* fr, int var) {
  assert(var >= 0);
  assert(var < fr->bc->nlocals);
  return &fr->entries[fr->bc->nclosures + var].localvar;
}

static struct frame* frame_current(struct stack* stk, stack_ptr idx) {
  struct frame* fp = stack_block(stk, idx);

  stack_ptr next = *stack_block_next(stk, idx);
  if (next) {
    struct frame* fpnext = stack_block(stk, next);
    struct bytecode* bc = fpnext->bc;
    assert(fp->retaddr >= bc->code && fp->retaddr < bc->code + bc->codelen);
  } else {
    assert(fp->retaddr == 0);
  }
  return fp;
}

static stack_ptr frame_get_level(struct stack* stk, stack_ptr fr, int level) {
  for (int i=0; i<level; i++) {
    struct frame* fp = stack_block(stk, fr);
    fr = fp->env;
  }
  return fr;
}

static stack_ptr frame_push(struct stack* stk, stack_ptr curr, struct closure cl, uint16_t* retaddr, stack_ptr datastk) {
  stack_ptr fpidx = stack_push_block(stk, curr, frame_size(cl.bc));
  struct frame* fp = stack_block(stk, fpidx);
  fp->bc = cl.bc;
  fp->env = cl.env;
  fp->retdata = datastk;
  fp->retaddr = retaddr;
  for (int i=0; i<cl.bc->nlocals; i++) {
    *frame_local_var(fp, i) = jv_invalid();
  }
  return fpidx;
}

static stack_ptr frame_pop(struct stack* stk, stack_ptr curr) {
  struct frame* fp = frame_current(stk, curr);
  if (stack_pop_will_free(stk, curr)) {
    int nlocals = fp->bc->nlocals;
    for (int i=0; i<nlocals; i++) {
      jv_free(*frame_local_var(fp, i));
    }
  }
  return stack_pop_block(stk, curr, frame_size(fp->bc));
}

#endif