aboutsummaryrefslogtreecommitdiff
path: root/compiler/elymasAsm.ey
blob: ff57627e51f0bc84be33b1127c772ad87cbe16a8 (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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<
  4096 ==PAGESIZE
  4096 16 mul 8 mul ==STACKSIZE
  65536 ==GLOBALALLOCSSIZE
  16 ==STACKSTART

  6148914691236517205 ==STACKBOTTOMMARKER
  4 ==ERRORMARKER

  # hex decoding
  {
    "(.)(.)" regex { } { "not a valid hex-string" die } ? *
    { { eq }_ [ "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "A" "B" "C" "D" "E" "F" ] -01 index }
    -20*10* 16 mul add
  } "%" defq

  "elymasAsmOps.ey" include

  # map "anonymous" allocations away from interpreter heap

  52776558133248 ==miscAllocBase # 0x300000000000
  { ==size
    size miscAllocBase sys .asm .allocAt
    size miscAllocBase add =miscAllocBase
  } /alloc deff

  # global alloc list layout
  # %0 : next unused byte of global alloc list as an offset from beginning of list
  # %8 : <unused>
  # %10 : base of this very alloc
  # %18 : size of this very alloc
  # %20... : <base> <size> of next allocs
  <
    { # ==addr
      [ -01 7 add 8 { _ sys .asm .peek -01 1 sub } rep -- ] { -01 256 mul add } fold
    } /peekImm64 deff

    { ==addr ==value
      [ value imm64 ] { addr sys .asm .poke addr 1 add =addr } each
    } /pokeImm64 deff

    GLOBALALLOCSSIZE alloc ==allocs
    allocs .base ==i
    [
      %20 imm64
      0 imm64
      allocs .base imm64
      allocs .size imm64
    ] { i sys .asm .poke i 1 add =i } each

    { ==block
      allocs .base peekImm64 ==nextOffset
      nextOffset 16 add _
        GLOBALALLOCSSIZE gt { "Global allocation list full." die } rep
        allocs .base pokeImm64
      allocs .base nextOffset add =nextOffset

      block .base nextOffset       pokeImm64
      block .size nextOffset 8 add pokeImm64
    } /register deff

    { allocs .base } /base deff
  > ==globalAllocations

  # stack layout
  #    %0 : stack size
  #    %8 : current stack pointer
  #   ... : real stack
  # <end> : stack bottom marker
  [ /bootStack /bootCallStack ] {
    <
      PAGESIZE alloc _ globalAllocations .register
                        ==stack
      stack .base ==i
      [
        PAGESIZE imm64
        stack .base PAGESIZE add 8 sub imm64
      ] { i sys .asm .poke i 1 add =i } each

      stack .base PAGESIZE add 8 sub =i
      [
        STACKBOTTOMMARKER imm64
      ] { i sys .asm .poke i 1 add =i } each

      stack
    > -12 ==
  }' each

  PAGESIZE alloc _ globalAllocations .register
                   ==:initialCoroutine

  # TODO create a heap-based initial coroutine
  <
    initialCoroutine .base ==i
    [
      40 0 0 0 0 0 0 %C8
      0 imm64 # no instruction pointer, will be driven via executeOn
      0 imm64 # no scope pointer, will be installed by elymalGlobal into r14
      bootCallStack .base imm64
      bootStack .base imm64
      # 40 bytes so far, coroutine image stops here
      # 40-47: original rsp value
      0 imm64
      # 48-55: currently running co-routine (so elymasGlobal can switch to heap allocated one)
      initialCoroutine .base imm64
    ] { i sys .asm .poke i 1 add =i } each
  > --

  STACKSIZE alloc _ globalAllocations .register
                    .base ==:quoteEncodingBufferCode

  STACKSIZE alloc _ globalAllocations .register
                    .base ==:quoteEncodingBufferObjects

  { ==opcodes
    opcodes len 1 sub PAGESIZE udiv 1 add PAGESIZE mul alloc /codearea defv
    sys .asm .|poke =*poke
    codearea .base opcodes { -101 poke 1 add } each --
    codearea
  } /arrayToCode deff

  # take an array of instruction bytes and execute it in the given coroutine context
  { ==opcodes
    [
      /rbx pushqReg
      /rbp pushqReg
      /r12 pushqReg
      /r13 pushqReg
      /r14 pushqReg
      /r15 pushqReg
      initialCoroutine .base 40 add /rbx movqImmReg
      /rsp /rbx movqRegMem

      initialCoroutine .base 48 add /rbx movqImmReg
      /rbx /r13 movqMemReg
      16 /r13 /r14 movqMemDisp8Reg
      24 /r13 /rbx movqMemDisp8Reg
      8 /rbx /r15 movqMemDisp8Reg
      32 /r13 /rbx movqMemDisp8Reg
      8 /rbx /rsp movqMemDisp8Reg

      opcodes _ len dearray

      /r14 16 /r13 movqRegMemDisp8
      24 /r13 /rbx movqMemDisp8Reg
      /r15 8 /rbx movqRegMemDisp8
      32 /r13 /rbx movqMemDisp8Reg
      /rsp 8 /rbx movqRegMemDisp8
      initialCoroutine .base 48 add /rbx movqImmReg
      /r13 /rbx movqRegMem

      initialCoroutine .base 40 add /rbx movqImmReg
      /rbx /rsp movqMemReg
      /r15 popqReg
      /r14 popqReg
      /r13 popqReg
      /r12 popqReg
      /rbp popqReg
      /rbx popqReg
      retn
    ]
  } /compile deff

  {
    compile arrayToCode _ .base sys .asm .execute
                          .free
  } /execute deff
> /assembler defv

# vim: syn=elymas