aboutsummaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorDrahflow <drahflow@gmx.de>2014-02-18 18:07:19 +0100
committerDrahflow <drahflow@gmx.de>2014-02-18 18:07:19 +0100
commit676307d3cc203f3a5e583cdc96c37c7821f79452 (patch)
tree320fb1fa91ada14f46bd3b06f966bf08a52462a7 /compiler
parentb66ee5f07c7642b3b92cf2b820823a1564b48a8e (diff)
Coroutines.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/elymasAsm.ey92
-rw-r--r--compiler/elymasAsmLib.ey148
-rw-r--r--compiler/elymasAsmOps.ey9
-rw-r--r--compiler/elymasGlobal.ey264
-rw-r--r--compiler/elymasGlobalSysAsm.ey12
5 files changed, 483 insertions, 42 deletions
diff --git a/compiler/elymasAsm.ey b/compiler/elymasAsm.ey
index b5099ac..265ff95 100644
--- a/compiler/elymasAsm.ey
+++ b/compiler/elymasAsm.ey
@@ -2,7 +2,10 @@
4096 ==PAGESIZE
4096 16 mul 8 mul ==STACKSIZE
65536 ==GLOBALALLOCSSIZE
- 128 ==STACKSTART
+ 16 ==STACKSTART
+
+ 6148914691236517205 ==STACKBOTTOMMARKER
+ 4 ==ERRORMARKER
# hex decoding
{
@@ -59,23 +62,50 @@
{ allocs .base } /base deff
> ==globalAllocations
- # global stack layout
- # 0 - STACKSTART : global variables
- # %0 : current stack pointer
- # STACKSTART - ...: real stack
- [ /mainStack /mainCallStack ] {
+ # stack layout
+ # %0 : stack size
+ # %8 : current stack pointer
+ # ... : real stack
+ # <end> : stack bottom marker
+ [ /bootStack /bootCallStack ] {
<
- STACKSIZE alloc _ globalAllocations .register
+ PAGESIZE alloc _ globalAllocations .register
==stack
stack .base ==i
[
- stack .base STACKSIZE add imm64
+ 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
@@ -89,8 +119,8 @@
codearea
} /arrayToCode deff
- # take an array of instruction bytes and execute it on the given stack
- { ==callStack ==valueStack ==opcodes
+ # take an array of instruction bytes and execute it in the given coroutine context
+ { ==opcodes
[
/rbx pushqReg
/rbp pushqReg
@@ -98,19 +128,29 @@
/r13 pushqReg
/r14 pushqReg
/r15 pushqReg
- valueStack /rbx movqImmReg
- /rsp /rbx xchgqRegMem
- callStack /rbx movqImmReg
- /r15 /rbx xchgqRegMem
- /r14 8 /rbx xchgqRegMemDisp8
+ 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
- callStack /rbx movqImmReg
- /r15 /rbx xchgqRegMem
- /r14 8 /rbx xchgqRegMemDisp8
- valueStack /rbx movqImmReg
- /rsp /rbx xchgqRegMem
+ /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
@@ -119,16 +159,12 @@
/rbx popqReg
retn
]
- } /compileOn deff
+ } /compile deff
{
- compileOn arrayToCode _ .base sys .asm .execute
- .free
- } /executeOn deff
-
- { mainStack .base mainCallStack .base executeOn } /execute deff
-
- { mainStack .base mainCallStack .base compileOn } /compile deff
+ compile arrayToCode _ .base sys .asm .execute
+ .free
+ } /execute deff
> /assembler defv
# vim: syn=elymas
diff --git a/compiler/elymasAsmLib.ey b/compiler/elymasAsmLib.ey
index 15cbfbd..b619bfd 100644
--- a/compiler/elymasAsmLib.ey
+++ b/compiler/elymasAsmLib.ey
@@ -349,22 +349,33 @@
/r14 /rdi :movqRegReg
/markObject :callqLbl32
+ # start from current coroutine and mark all reachable blocks
+ /r13 /rdi :movqRegReg
+ /markObject :callqLbl32
+
# start from stack and mark all reachable blocks
- :mainStack .base :STACKSIZE add /rsi :movqImmReg
- @loopThroughMainStack
- 8 /rsi :subqImm8Reg
+ :STACKBOTTOMMARKER /rcx :movqImmReg
+ /rsp /rsi :movqRegReg
+ /rcx /rsi :cmpqRegMem
+ /dataStackEmpty :jzLbl8
+ @loopThroughDataStack
/rsi /rdi :movqMemReg
/markStackObject :callqLbl32
- /rsi /rsp :cmpqRegReg
- /loopThroughMainStack :jbLbl8
+ 8 /rsi :addqImm8Reg
+ /rcx /rsi :cmpqRegMem
+ /loopThroughDataStack :jnzLbl8
+ @dataStackEmpty
- :mainCallStack .base :STACKSIZE add /rsi :movqImmReg
+ /r15 /rsi :movqRegReg
+ /rcx /rsi :cmpqRegMem
+ /callStackEmpty :jzLbl8
@loopThroughCallStack
- 8 /rsi :subqImm8Reg
/rsi /rdi :movqMemReg
/markStackObject :callqLbl32
- /rsi /r15 :cmpqRegReg
- /loopThroughCallStack :jbLbl8
+ 8 /rsi :addqImm8Reg
+ /rcx /rsi :cmpqRegMem
+ /loopThroughCallStack :jnzLbl8
+ @callStackEmpty
# start from encoding buffer and mark all reachable blocks
:quoteEncodingBufferObjects /rsi :movqImmReg
@@ -487,6 +498,10 @@
/markScope :jzLbl32
/rax :decqReg
/markNameTable :jzLbl32
+ /rax :decqReg
+ /markStack :jzLbl32
+ /rax :decqReg
+ /markCoroutine :jzLbl32
@markInvalidType
/rax /rbx :movqRegReg # for easier inspection
@@ -669,6 +684,48 @@
/rcx :popqReg
:retn
+ @markStack
+ # /rdi :pushqReg
+ # "stack marked\n" outputError
+ # /rdi :popqReg
+
+ /rsi :pushqReg
+ /rcx :pushqReg
+
+ :STACKBOTTOMMARKER /rcx :movqImmReg
+ 8 /rdi /rsi :movqMemDisp8Reg
+ /rcx /rsi :cmpqRegMem
+ /stackEmpty :jzLbl8
+
+ @loopThroughStack
+ /rsi /rdi :movqMemReg
+ /markStackObject :callqLbl32
+ 8 /rsi :addqImm8Reg
+ /rcx /rsi :cmpqRegMem
+ /loopThroughStack :jnzLbl8
+
+ @stackEmpty
+
+ /rcx :popqReg
+ /rsi :popqReg
+ :retn
+
+ @markCoroutine
+ # /rdi :pushqReg
+ # "coroutine marked\n" outputError
+ # /rdi :popqReg
+
+ /rsi :pushqReg
+ /rdi /rsi :movqRegReg
+ 8 /rsi /rdi :movqMemDisp8Reg
+ /markStackObject :callqLbl32
+ 16 /rsi /rdi :movqMemDisp8Reg
+ /markObject :callqLbl32
+ 24 /rsi /rdi :movqMemDisp8Reg
+ /markObject :callqLbl32
+ 32 /rsi /rdi :movqMemDisp8Reg
+ /rsi :popqReg
+ /markObject :jmpLbl32
# allocate next chunk of memory from the operating system
@allocateFromSystem
@@ -785,6 +842,9 @@
%90 /al :cmpbImmReg
/isScope :jeLbl8
+ /rdi :pushqReg
+ :ERRORMARKER /rax :movqImmReg
+ /rax :pushqReg
"object resolving in is not a scope" outputError
:ud2
@@ -879,6 +939,33 @@
/rax /rax :xorqRegReg
:retn
]] /internalResolve defv
+
+ # return a pointer to start of object
+ # rdi -> pointer somewhere into an object (or outside of heap)
+ # rax <- pointer to start of object, zero if outside of heap
+ [[
+ /rax :movqImmOOBReg HEAPBASE
+ /rdx :movqImmOOBReg BLOCKBASE
+ /rax /rdi :subqRegReg
+ /nonHeapObject :jbLbl8
+
+ 4 /rdi :shrqImm8Reg # rdi == cell index of pointer target
+ /testForStart :jmpLbl8
+
+ @scanLoop
+ /rdi :decqReg
+ @testForStart
+ /rdi /rdx :btqRegMem
+ /scanLoop :jncLbl8
+
+ 4 /rdi :shlqImm8Reg
+ /rdi /rax :addqRegReg
+ :retn
+
+ @nonHeapObject
+ /rax /rax :xorqRegReg
+ :retn
+ ]] /internalObjectStart defv
> { defv }' allocateOffsetStruct
# TODO: link internal functions statically with relative calls
@@ -1043,6 +1130,49 @@
:retn
] /internalAllocateString defv
+
+ # allocate empty stack
+ # rax <- new empty stack
+ [
+ :STACKSIZE /rdi :movqImmReg
+ internalAllocate /rax :movqImmReg
+ /rax :callqReg
+
+ # set type
+ %B0 7 /rax :orbImmMemDisp8
+
+ :STACKSIZE /rax /rdi :leaqMemDisp32Reg
+ 8 /rdi :subqImm8Reg
+ :STACKBOTTOMMARKER /rdx :movqImmReg
+ /rdx /rdi :movqRegMem
+ /rdi 8 /rax :movqRegMemDisp8
+
+ :retn
+ ] /internalAllocateStack defv
+
+ # allocate coroutine state
+ # rdi -> instruction pointer
+ # rsi -> scope pointer
+ # rax <- new coroutine state
+ # does not do any stack copying
+ [[
+ /rsi :pushqReg
+ /rdi :pushqReg
+
+ 40 /rdi :movqImmReg
+ internalAllocate /rax :movqImmReg
+ /rax :callqReg
+
+ # set type
+ %C0 7 /rax :orbImmMemDisp8
+
+ 8 /rax :popqMemDisp8
+ 16 /rax :popqMemDisp8
+ 0 24 /rax :andqImm8MemDisp8
+ 0 32 /rax :andqImm8MemDisp8
+
+ :retn
+ ]] /internalAllocateCoroutine defv
> { defv }' allocateOffsetStruct
<
diff --git a/compiler/elymasAsmOps.ey b/compiler/elymasAsmOps.ey
index 1a7cc9b..a9f47bc 100644
--- a/compiler/elymasAsmOps.ey
+++ b/compiler/elymasAsmOps.ey
@@ -55,8 +55,8 @@
} /rex deff
{ ==mem ==reg
- mem [ /spl /sp /esp /rsp /bpl /bp /ebp /rbp ] eq any {
- "modrm00 not possible on rsp / rbp and their partial registers" die
+ mem [ /spl /sp /esp /rsp /bpl /bp /ebp /rbp /r12b /r12w /r12d /r12 /r13b /r13w /r13d /r13 ] eq any {
+ "modrm00 not possible on rsp / rbp / r12 / r13 and their partial registers" die
} rep
%00
@@ -504,6 +504,7 @@
/bts %0F %BA /five defAsmBtqImm
/bsf %0F %BC defAsmBsfq
+/bsr %0F %BD defAsmBsfq
{ ==off
%E8
@@ -1332,6 +1333,10 @@ memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*p
} /shrqImm8Reg deff
{
+ %FD
+} /std deff
+
+{
%AA
} /stosb deff
diff --git a/compiler/elymasGlobal.ey b/compiler/elymasGlobal.ey
index e64bc05..0e324f2 100644
--- a/compiler/elymasGlobal.ey
+++ b/compiler/elymasGlobal.ey
@@ -502,6 +502,9 @@
/arrayFunction :jmpLbl32
@unexecutable
+ /rdx :pushqReg
+ :ERRORMARKER /rax :movqImmReg
+ /rax :pushqReg
"not an executable thing" ::outputError
:ud2
@@ -2414,6 +2417,244 @@
/rax :callqReg
/end :jmpLbl8
]] /eydom defv
+
+ # create a coroutine with empty call stack and data stack
+ # 0 -> function to execute (type is ignored)
+ [[
+ 8 /r15 :subqImm8Reg
+ /r15 :popqMem
+
+ /rax :popqReg
+ 8 /rax /rsi :movqMemDisp8Reg
+ 24 /rax /rdi :movqMemDisp8Reg
+ 58 /rdi :btsqImm8Mem # prevent these opcodes from being optimized
+ 16 /rdi :addqImm8Reg
+
+ # test for and skip initial popping of return address, there is nothing to return to
+ # leaving them in results in gobbling up of the first passed data item
+ %49 0 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl8
+ %83 1 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl8
+ %EF 2 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl8
+ %08 3 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl8
+ %49 4 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl8
+ %8F 5 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl8
+ %07 6 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl8
+
+ 7 /rdi :addqImm8Reg
+ ::internalAllocateCoroutine /rax :movqImmReg
+ /rax :callqReg
+ /rax :pushqReg
+
+ /r15 :pushqMem
+ 8 /r15 :addqImm8Reg
+ :retn
+
+ @wrongOpcodeSequence
+ "could not parse function start while preparing coroutine" ::outputError
+ :ud2
+ ]] /ey!! defv
+
+ # create a coroutine with copied data and call stack
+ # push said coroutine to stack
+ # then continue execution at specified function
+ # 0 -> function to execute within new coroutine (type is ignored)
+ # 1 -> function to execute outside of new coroutine
+ [[
+ 8 /r15 :subqImm8Reg
+ /r15 :popqMem
+
+ /rax :popqReg
+ 8 /rax /rsi :movqMemDisp8Reg
+ 24 /rax /rdi :movqMemDisp8Reg
+ 58 /rdi :btsqImm8Mem # prevent these opcodes from being optimized
+ 16 /rdi :addqImm8Reg
+
+ # test for and skip initial popping of return address
+ # leaving them in results in gobbling up of the first passed data item
+ # instead put the return address on the call stack
+ %49 0 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl32
+ %83 1 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl32
+ %EF 2 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl32
+ %08 3 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl32
+ %49 4 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl32
+ %8F 5 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl32
+ %07 6 /rdi :cmpbImmMemDisp8
+ /wrongOpcodeSequence :jnzLbl32
+
+ 7 /rdi :addqImm8Reg
+ ::internalAllocateCoroutine /rax :movqImmReg
+ /rax :callqReg
+ /rax /rbx :movqRegReg
+
+ ::internalAllocateStack /rax :movqImmReg
+ /rax :callqReg
+ /rax 24 /rbx :movqRegMemDisp8
+
+ # copy call stack
+ :STACKBOTTOMMARKER /rdx :movqImmReg
+ /r15 /rsi :movqRegReg
+ /rdx /rsi :cmpqRegMem
+ /callStackEmpty :jzLbl8
+ @scanCallStack
+ 8 /rsi :addqImm8Reg
+ /rdx /rsi :cmpqRegMem
+ /scanCallStack :jnzLbl8
+
+ 8 /rax /rdi :movqMemDisp8Reg
+ /rsi /rcx :movqRegReg
+ /r15 /rcx :subqRegReg
+ 3 /rcx :shrqImm8Reg
+ /rcx :incqReg
+ :std
+ :reprcx :movsq
+ :cld
+ 8 /rdi :addqImm8Reg
+ /rdi 8 /rax :movqRegMemDisp8
+ @callStackEmpty
+
+ ::internalAllocateStack /rax :movqImmReg
+ /rax :callqReg
+ /rax 32 /rbx :movqRegMemDisp8
+
+ # copy data stack
+ :STACKBOTTOMMARKER /rdx :movqImmReg
+ /rsp /rsi :movqRegReg
+ /rdx /rsi :cmpqRegMem
+ /dataStackEmpty :jzLbl8
+ @scanDataStack
+ 8 /rsi :addqImm8Reg
+ /rdx /rsi :cmpqRegMem
+ /scanDataStack :jnzLbl8
+
+ 8 /rax /rdi :movqMemDisp8Reg
+ /rsi /rcx :movqRegReg
+ /rsp /rcx :subqRegReg
+ 3 /rcx :shrqImm8Reg
+ :std
+ :reprcx :movsq
+ :cld
+ 8 /rdi :addqImm8Reg
+ /rdi 8 /rax :movqRegMemDisp8
+ @dataStackEmpty
+
+ /rax :popqReg
+ /rbx :pushqReg
+ /rax :pushqReg
+
+ /r15 :pushqMem
+ 8 /r15 :addqImm8Reg
+
+ |ey* /rax :movqImmReg
+ /rax :jmpqReg
+
+ @wrongOpcodeSequence
+ "could not parse function start while preparing coroutine" ::outputError
+ :ud2
+ ]] /ey!!' defv
+
+ # pass control to a coroutine
+ # 0 -> number of stack elements to copy over
+ # 1 -> coroutine to continue (may also be some other executable, in which case no stack passing is done)
+ # 2... -> passed stack arguments
+ [[
+ /rbx :popqReg
+
+ /rcx :popqReg
+ /rbp :popqReg
+ /rcx :pushqReg
+
+ 7 /rbp /cl :movbMemDisp8Reg
+ %F0 /cl :andbImmReg
+ %C0 /cl :cmpbImmReg
+ /coroutineCase :jzLbl8
+
+ "type of object not handled in !" ::outputError
+ :ud2
+
+ @coroutineCase
+ 0 24 /rbp :cmpqImm8MemDisp8
+ /targetCallStackExists :jnzLbl8
+ /rbp :pushqReg
+ ::internalAllocateStack /rax :movqImmReg
+ /rax :callqReg
+ /rbp :popqReg
+ /rax 24 /rbp :movqRegMemDisp8
+ @targetCallStackExists
+
+ 0 32 /rbp :cmpqImm8MemDisp8
+ /targetDataStackExists :jnzLbl8
+ /rbp :pushqReg
+ ::internalAllocateStack /rax :movqImmReg
+ /rax :callqReg
+ /rbp :popqReg
+ /rax 32 /rbp :movqRegMemDisp8
+ @targetDataStackExists
+
+ /rcx :popqReg
+ /rcx ::unboxInteger
+
+ # move stack data
+ /rsp /rsi :movqRegReg
+
+ 32 /rbp /rdi :movqMemDisp8Reg
+ 8 /rdi /rdi :movqMemDisp8Reg
+ /rcx /rdx :movqRegReg
+ 3 /rdx :shlqImm8Reg
+ /rdx /rdi :subqRegReg
+ /rdi :pushqReg
+ /rdi :pushqReg
+ 32 /rbp /rdi :movqMemDisp8Reg
+ 8 /rdi :popqMemDisp8
+ /rdi :popqReg
+ /rdx /rsp :addqRegReg
+ :reprcx :movsq
+
+ # save old state
+ /rbx 8 /r13 :movqRegMemDisp8
+ /r14 16 /r13 :movqRegMemDisp8
+ 24 /r13 /rax :movqMemDisp8Reg
+ /r15 8 /rax :movqRegMemDisp8
+ 32 /r13 /rax :movqMemDisp8Reg
+ /rsp 8 /rax :movqRegMemDisp8
+
+ # exclude source opcodes from being optimized away
+ /rbp :pushqReg
+ /rbx /rdi :movqRegReg
+ ::internalObjectStart /rax :movqImmReg
+ /rax :callqReg
+ /rax /rax :testqRegReg
+ /nonHeapCoroutine :jzLbl8
+ 58 /rax :btsqImm8Mem
+ @nonHeapCoroutine
+ /rbp :popqReg
+
+ # load new state
+ 8 /rbp /rbx :movqMemDisp8Reg
+ 16 /rbp /r14 :movqMemDisp8Reg
+ 24 /rbp /rax :movqMemDisp8Reg
+ 8 /rax /r15 :movqMemDisp8Reg
+ 32 /rbp /rax :movqMemDisp8Reg
+ 8 /rax /rsp :movqMemDisp8Reg
+
+ /r13 :pushqReg # push caller to target stack
+ /rbp /r13 :movqRegReg
+
+ /rbx :pushqReg
+ :retn
+ ]] /ey! defv
> _ ==globalFunctions3 { defv }' ::allocateOffsetStruct
<
@@ -3014,7 +3255,26 @@
} each
} /createScopeExtensionEntries deff
- [
+ [[
+ /afterRipInitialization :jmpLbl8
+ @ripInitialization
+ /rdi :popqReg
+ /rsi /rsi :xorqRegReg
+ ::internalAllocateCoroutine /rax :movqImmReg
+ /rax :callqReg
+ /rax :pushqReg
+
+ /rdx /rdx :xorqRegReg
+ 63 /rdx :btsqImm8Reg
+ /rdx :pushqReg
+
+ |ey! /rax :movqImmReg
+ /rax :callqReg # switch over to heap-allocated coroutine
+
+ @afterRipInitialization
+ /ripInitialization :callqLbl32
+ /rax :popqReg # drop initial coroutine reference
+
globalFunctions keys len
globalFunctions2 keys len add
globalFunctions3 keys len add
@@ -3034,7 +3294,7 @@
globalMacros keys eydefq { | }' createScopeEntries
globalT11t1Functions keys eydeffd t11t1 { | }' createTypedScopeEntries
globalT1t1Functions keys eydeffd t1t1 { | }' createTypedScopeEntries
- ] :execute
+ ]] :execute
{ ==name
[[
diff --git a/compiler/elymasGlobalSysAsm.ey b/compiler/elymasGlobalSysAsm.ey
index e865f34..97d4bb7 100644
--- a/compiler/elymasGlobalSysAsm.ey
+++ b/compiler/elymasGlobalSysAsm.ey
@@ -492,6 +492,7 @@
:globalAllocations .base /rax :movqImmReg # 99
/rbx :movqImmOOBReg %EE %EE %EE %EE %EE %EE %EE %EE # 109
/rbx /rax :movqRegMem # 112
+ /r13 :movqImmOOBReg %EE %EE %EE %EE %EE %EE %EE %EE # 122
/r8 /rsp :xchgqRegReg # swap to elymas stack to ensure correct GC behavior for what follows
@@ -589,7 +590,15 @@
eyprogramStart /rax :movqImmReg
/rsp 2 /rax :movqRegMemDisp8
# /r15 12 /rax :movqRegMemDisp8 # TODO: something like this (but correctly adjusted) would be right
- :mainCallStack .base :STACKSIZE add /rdx :movqImmReg # TODO whereas this just flushes the stack
+ # TODO whereas this just flushes the stack
+ /r15 /rdx :movqRegReg
+ :STACKBOTTOMMARKER /rcx :movqImmReg
+ /cmpCallStackStart :jmpLbl8
+ @scanCallStackStart
+ 8 /rdx :addqImm8Reg
+ @cmpCallStackStart
+ /rcx /rdx :cmpqRegMem
+ /scanCallStackStart :jnzLbl8
/rdx 12 /rax :movqRegMemDisp8
::heapSize /rdx :movqImmReg
/rdx /rdx :movqMemReg
@@ -604,6 +613,7 @@
/rdx /rdx :movqMemReg
/rdx :pushqReg # store allocation count for later return value
/rdx 101 /rax :movqRegMemDisp8
+ /r13 114 /rax :movqRegMemDisp8
::internalAllocateInteger /rax :movqImmReg
/rax :callqReg