"elymasAsmLib.ey" include < { assembler -01 . } ":" deff { assemblerLibrary -01 . } "::" deff assembler .|label "@" deff "%" _ : -01 deff { [ } "[[" deff { ] :labelResolve ::stringResolve } "]]" deff 256 ==INITIALEXTENSIONSIZE 256 ==INITIALSCOPESIZE # elymas functions, stack based ABI 1 ==ARRAYMARKER 2 ==QUOTEMARKER # 0 -> integer # 1 -> integer # 0 <- result of the arithmetic operation { ==opcodes [ /rbx :popqReg # allocate result ::internalAllocateInteger /rax :movqImmReg /rax :callqReg # actual calculation /rcx :popqReg 8 /rcx /rcx :movqMemDisp8Reg /rdx :popqReg 8 /rdx /rdx :movqMemDisp8Reg opcodes _ len dearray /rdx 8 /rax :movqRegMemDisp8 # push int address on program stack /rax :pushqReg /rbx :pushqReg :retn ] } /makeArith deff < # do nothing [ :retn ] /ey/ defv # resolve in scope but never execute # 0 -> name to resolve # 0 <- whatever the name resolved to [[ /rcx :popqReg /rbx :popqReg /rcx :pushqReg # scope resolution ::currentScope /rdi :movqImmReg /rdi /rdi :movqMemReg /rbx /rsi :movqRegReg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /found :jnzLbl8 "unresolved name in |: " ::outputError /rbx /rdi :movqRegReg ::internalDumpErrorString /rax :movqImmReg /rax :callqReg :ud2 @found /rcx :popqReg /rax :pushqReg /rcx :pushqReg :retn ]] /ey| defv # decide between two alternatives # 0 -> alternative 0 # 1 -> alternative not 0 # 2 -> decision value # 0 <- the selected alternative [ /rbx :popqReg /rcx :popqReg /rdx :popqReg /rax :popqReg 8 /rax /rax :movqMemDisp8Reg /rax /rax :testqRegReg /rcx /rdx :cmovzqRegReg /rdx :pushqReg /rbx :pushqReg :retn ] /ey? defv # create a new entry in the current scope for the given name # mark that entry's default action according to activation # 0 -> activation # 1 -> name, string # 2 -> object [[ 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem # /r15 now points to activation /rdi :popqReg /rax :popqReg # CHECK this is just sanity checking /rax :pushqReg /rax /rax :testqRegReg /realObject :jnzLbl8 "trying to store zero object address" ::outputError :ud2 @realObject # CHECK end of checking # search for name in nametable ::currentScope /rax :movqImmReg /rax /rbx :movqMemReg # rbx == start of scope in heap 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap 8 /rbx /rsi :movqMemDisp8Reg # rsi == start of nametable in heap 8 /rsi /rsi :addqMemDisp8Reg # rsi == end of nametable in heap (according to fill) @nameSearch 16 /rdx :addqImm8Reg # rsi: end of nametable # rdx: current element of nametable /rdx /rsi :cmpqRegReg /nameUndefined :jbeLbl8 /rdx :pushqReg /rsi :pushqReg /rdi :pushqReg /rcx :pushqReg /rdx /rsi :movqMemReg ::internalStringEqualsCode _ len dearray /rcx :popqReg /rdi :popqReg /rsi :popqReg /rdx :popqReg /rax /rax :testqRegReg /nameOffsetKnown :jnzLbl8 # if not exists, insert @nameUndefined 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap /rdx /eax :movlMemReg # add memory length to obtain memory end /rax /rdx :addqRegReg /rsi /rdx :cmpqRegReg /enlargeNameTable :jbeLbl8 # insert into name table @insertIntoNameTable /rdi /rsi :movqRegMem /r15 /rax :movqMemReg 8 /rax /rax :movqMemDisp8Reg # load int value /rax 8 /rsi :movqRegMemDisp8 # set default activation mode 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap 16 8 /rdx :addqImm8MemDisp8 # increment fill /rsi /rdx :movqRegReg /nameOffsetKnown :jmpLbl8 @enlargeNameTable # if name table is already full, double size 8 /rbx /rdx :movqMemDisp8Reg # rdx == start of nametable in heap /rdi :pushqReg /rdx :pushqReg /rdx /edi :movlMemReg # load current length /rdi /rdi :addqRegReg ::internalAllocate /rax :movqImmReg /rax :callqReg %30 7 /rax :orbImmMemDisp8 # set type /rdx :popqReg 8 /rdx /rcx :movqMemDisp8Reg /rcx 8 /rax :movqRegMemDisp8 # copy fill 16 /rdx /rsi :leaqMemDisp8Reg 16 /rax /rdi :leaqMemDisp8Reg 16 /rcx :subqImm8Reg 3 /rcx :shrqImm8Reg :reprcx :movsq # copy content # rax == enlarged name table on heap /rax 8 /rbx :movqRegMemDisp8 # switch scope to new name table # insert into name table /rsi :popqReg /rsi /rdi :xchgqRegReg /insertIntoNameTable :jmpLbl8 @nameOffsetKnown 8 /rbx /rdx :subqMemDisp8Reg # substract name table address 16 /rdx :subqImm8Reg # substract name table header size /rdx :shrq1Reg # divide by 2 to get offset within scope # rdx == offset in scope # top of stack: the object to store # update # if fits within main area, fine 32 /rdx :addqImm8Reg # add scope header size /edx /rbx :cmplRegMem /inDataArea :jaLbl8 # update within extension area /rbx /edx :sublMemReg # substract scope length 24 /rbx /rdi :movqMemDisp8Reg # load extension area pointer 8 /rdx :addqImm8Reg # add extension area header length # if extension area is non-existent, create /rdi /rdi :testqRegReg /extensionAreaExists :jnzLbl8 /rdx :pushqReg INITIALEXTENSIONSIZE /rdi :movqImmReg ::internalAllocate /rax :movqImmReg /rax :callqReg /rdx :popqReg %40 7 /rax :orbImmMemDisp8 # set type /rax /rdi :movqRegReg /rdi 24 /rbx :movqRegMemDisp8 # store new extension area /inExtensionArea :jmpLbl8 @extensionAreaExists # if extension area is full, double size /edx /rdi :cmplRegMem /inExtensionArea :jaLbl8 # indeed full /rdi :pushqReg /rdx :pushqReg /rdi /edi :movlMemReg /rdi /rdi :addqRegReg ::internalAllocate /rax :movqImmReg /rax :callqReg /rdx :popqReg /rdi :popqReg %40 7 /rax :orbImmMemDisp8 # set type /rdi /rsi :movqRegReg /rax /rdi :movqRegReg /rdi 24 /rbx :movqRegMemDisp8 # store new extension area /rdi :pushqReg /rsi /ecx :movlMemReg # load length as copy count 8 /rsi :addqImm8Reg 8 /rdi :addqImm8Reg 8 /rcx :subqImm8Reg # substract header length 3 /rcx :shrqImm8Reg :reprcx :movsq # copy content /rdi :popqReg @inExtensionArea /rdi /rbx :movqRegReg @inDataArea /rax :popqReg /rax /rbx /rdx :movqRegMemIndex # save entry pointer 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /eydef defv # assign to a scope variable # 0 -> name to assign to # 1 -> value to assign # does not change the default activation mode [[ 8 /r15 :subqImm8Reg /r15 :popqMem ::currentScope /rdi :movqImmReg /rdi /rdi :movqMemReg /rbx :popqReg /rbx /rsi :movqRegReg ::internalResolve /rax :movqImmReg /rax :callqReg # rax == resolved value # rcx == address of the value just resolved /rax /rax :testqRegReg /found :jnzLbl8 "unresolved name in =: " ::outputError /rbx /rdi :movqRegReg ::internalDumpErrorString /rax :movqImmReg /rax :callqReg :ud2 @found /rcx :popqMem /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /ey= defv # execute top stack element # 0 -> function to execute [[ 8 /r15 :subqImm8Reg /r15 :popqMem /rdx :popqReg 7 /rdx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %50 /cl :cmpbImmReg /normalFunction :jeLbl8 %10 /cl :cmpbImmReg /stringFunctionSJ :jeLbl8 %70 /cl :cmpbImmReg /unexecutable :jneLbl8 /arrayFunction :jmpLbl32 @unexecutable "not an executable thing" ::outputError :ud2 @stringFunctionSJ /stringFunction :jmpLbl32 @normalFunction # load scope 8 /rdx /rcx :movqMemDisp8Reg /rcx /rcx :testqRegReg /unscoped :jzLbl8 # save current scope ::currentScope /rax :movqImmReg /rax /rsi :movqMemReg 8 /r15 :subqImm8Reg /rsi /r15 :movqRegMem # enter scope /rcx /rax :movqRegMem # handle typed function 16 /rdx /rcx :movqMemDisp8Reg /rcx /rcx :testqRegReg /untyped :jzLbl8 /typed :jmpLbl32 @untyped 24 /rdx /rax :movqMemDisp8Reg 8 /rax :addqImm8Reg /rax :callqReg /r15 /rcx :movqMemReg ::currentScope /rax :movqImmReg /rcx /rax :movqRegMem 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @unscoped # handle typed unscoped function 16 /rdx /rcx :movqMemDisp8Reg /rcx /rcx :testqRegReg /typedUnscoped :jnzLbl8 24 /rdx /rax :movqMemDisp8Reg 8 /rax :addqImm8Reg /rax :callqReg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @typedUnscoped # save current scope ::currentScope /rax :movqImmReg /rax /rsi :movqMemReg 8 /r15 :subqImm8Reg /rsi /r15 :movqRegMem /typed :jmpLbl32 @arrayFunction # rdx == array on heap /rbx :popqReg 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %00 /cl :cmpbImmReg /arrayIntArgument :jeLbl8 "FIXME: typed array application" ::outputError :ud2 @arrayIntArgument 8 /rbx /rax :movqMemDisp8Reg # rax == requested index /rdx /ecx :movlMemReg # load array length 3 /rcx :shrqImm8Reg # divide by object pointer size /rcx :decqReg # rcx == number of elements in array /rsi /rsi :xorqRegReg /rdx /rsi :xchgqRegReg /rcx /rcx :testqRegReg /nonEmpty :jnzLbl8 "access into empty array" ::outputError :ud2 @nonEmpty /rcx :divqReg # rsi == array object on heap # rdx == correct array index 8 8 /rdx /rsi :pushqMemIndexScaleDisp8 # use some of the CISC goodness /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @typed # quick check for the common case (and to avoid infinite recursion) 16 /rdx /rbx :movqMemDisp8Reg 8 /rbx /rcx :movqMemDisp8Reg # rcx == number of input stack elements 16 /rbx /rbx :leaqMemDisp8Reg # rbx == first input stack element /rsp /rdi :movqRegReg @typedCommonCheck /rbx /rsi :movqMemReg # rsi == address of abstract argument 7 /rsi /al :movbMemDisp8Reg # al == type of abstract argument %F0 /al :andbImmReg /rdi /rsi :movqMemReg # rsi == address of concrete argument 7 /rsi /sil :movbMemDisp8Reg # sil = type of concrete argument %F0 /sil :andbImmReg /al /sil :cmpbRegReg /typedNonCommon :jnzLbl8 # non-equal types %E0 /al :testbImmReg /typedNonCommon :jnzLbl8 # non-trivial types 8 /rdi :addqImm8Reg 8 /rbx :addqImm8Reg /typedCommonCheck :loopLbl8 24 /rdx /rax :movqMemDisp8Reg 8 /rax :addqImm8Reg /rax :callqReg /r15 /rcx :movqMemReg ::currentScope /rax :movqImmReg /rcx /rax :movqRegMem 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @typedNonCommon # escape this to compiled high-level code /rdx :pushqReg /rax :movqImmOOBReg "sys" ::string /rax :pushqReg /rax :movqImmOOBReg "ey*" "ey|" ::linkAbs64 /rax :callqReg /rax :movqImmOOBReg "typed" ::string /rax :pushqReg /rax :movqImmOOBReg "ey*" "ey." ::linkAbs64 /rax :callqReg /rax :movqImmOOBReg "execute" ::string /rax :pushqReg /rax :movqImmOOBReg "ey*" "ey." ::linkAbs64 /rax :callqReg /r15 /rcx :movqMemReg ::currentScope /rax :movqImmReg /rcx /rax :movqRegMem 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @stringFunction # rdx == string on heap /rbx :popqReg 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %00 /cl :cmpbImmReg /stringIntArgument :jeLbl8 "FIXME: typed string application" ::outputError :ud2 @stringIntArgument 8 /rbx /rax :movqMemDisp8Reg # rax == requested index 16 /rdx /rcx :movqMemDisp8Reg # load (exact) string length /rsi /rsi :xorqRegReg /rdx /rsi :xchgqRegReg /rcx /rcx :testqRegReg /nonEmptyString :jnzLbl8 "access into empty string" ::outputError :ud2 @nonEmptyString /rcx :divqReg # rsi == array object on heap # rdx == correct string index 24 1 /rdx /rsi /rbx :movzxMem8IndexScaleDisp8Reg64 # use some of the CISC goodness ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rax :pushqReg # push integer on the stack /rbx 8 /rax :movqRegMemDisp8 # store integer value /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /ey* defv # array construction, push begin marker on stack [ /rax :popqReg ARRAYMARKER :pushqImm32 /rax :pushqReg :retn ] /ey[ defv # array construction, create array from begin marker onwards [[ 8 /r15 :subqImm8Reg /r15 :popqMem ARRAYMARKER /rax :movqImmReg /rsp /rdi :movqRegReg 8 /rdi :subqImm8Reg @search 8 /rdi :addqImm8Reg /rdi /rax :cmpqMemReg /search :jneLbl8 /rdi /rcx :movqRegReg /rsp /rdi :subqRegReg /rcx :pushqReg # rdi == size of array ::internalAllocateArray /rax :movqImmReg /rax :callqReg /rdi :popqReg /rax /rdi :movqRegMem # store array pointer instead of begin marker /rax /ecx :movlMemReg 3 /rcx :shrqImm8Reg /rcx :decqReg # rcx == number of array elements /rcx /rcx :testqRegReg /empty :jzLbl8 8 /rcx /rax /rax :leaqMemIndexScaleReg # rax == address of last cell @copy /rax :popqMem 8 /rax :subqImm8Reg /copy :loopLbl8 @empty /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /ey] defv # assign array cell # 0 -> array # 1 -> index in array # 2 -> value to assign [[ 8 /r15 :subqImm8Reg /r15 :popqMem /rbx :popqReg 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %70 /cl :cmpbImmReg /arrayAssign :jeLbl8 %10 /cl :cmpbImmReg /stringAssign :jeLbl8 "non-array, non-string passed to =[]" ::outputError :ud2 @arrayAssign /rax :popqReg 8 /rax /rax :movqMemDisp8Reg /rbx /ecx :movlMemReg # load array length 3 /rcx :shrqImm8Reg # divide by object pointer size /rcx :decqReg # rcx == number of elements in array /rdx /rdx :xorqRegReg # TODO: think about skipping this if index fits /rcx :divqReg # rbx == array object on heap # rdx == correct array index 8 8 /rdx /rbx :popqMemIndexScaleDisp8 # directly pop into array cell /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @stringAssign /rax :popqReg 8 /rax /rax :movqMemDisp8Reg 16 /rbx /rcx :movqMemDisp8Reg # load string length /rdx /rdx :xorqRegReg /rcx :divqReg # rbx == string object on heap # rdx == correct string offset /rax :popqReg 8 /rax /rax :movqMemDisp8Reg # load int value /al 24 1 /rdx /rbx :movbRegMemIndexScaleDisp8 /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /ey=[] defv # length of array or string # 0 -> array / string # 0 <- number of elements / characters [[ 8 /r15 :subqImm8Reg /r15 :popqMem /rax :popqReg 7 /rax /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %10 /cl :cmpbImmReg /stringLen :jeLbl8 %70 /cl :cmpbImmReg /arrayLen :jeLbl8 "neither string nor array in len" ::outputError :ud2 @arrayLen /rax /rbx :movqMemReg 8 /rbx :shlqImm8Reg # clear type bits 11 /rbx :shrqImm8Reg # divide by 8 /rbx :decqReg # substract header size /done :jmpLbl8 @stringLen 16 /rax /rbx :movqMemDisp8Reg @done ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rax :pushqReg # push integer on the stack /rbx 8 /rax :movqRegMemDisp8 # store integer value /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /eylen defv # concatenate two arrays or strings # 0 -> second part of new array / string # 1 -> first part of new array / string # 0 <- concatenated array / string [[ 8 /r15 :subqImm8Reg /r15 :popqMem /rax :popqReg 7 /rax /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %70 /cl :cmpbImmReg /arrayCat :jeLbl8 %10 /cl :cmpbImmReg /unknownType :jneLbl8 /stringCat :jmpLbl32 @unknownType "neither string nor array in cat" ::outputError :ud2 @arrayCat /rbx :popqReg 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %70 /cl :cmpbImmReg /mismatch :jneLbl8 16 /r15 :subqImm8Reg /rax /r15 :movqRegMem /rbx 8 /r15 :movqRegMemDisp8 # store /rax /edi :movlMemReg /rbx /edi :addlMemReg 16 /rdi :subqImm8Reg # sum of lengths ::internalAllocateArray /rax :movqImmReg /rax :callqReg /rax :pushqReg # result on stack 8 /rax /rdi :leaqMemDisp8Reg 8 /r15 /rbx :movqMemDisp8Reg /rbx /ecx :movlMemReg 8 /rbx /rsi :leaqMemDisp8Reg 3 /rcx :shrqImm8Reg /rcx :decqReg :reprcx :movsq /r15 /rbx :movqMemReg /rbx /ecx :movlMemReg 8 /rbx /rsi :leaqMemDisp8Reg 3 /rcx :shrqImm8Reg /rcx :decqReg :reprcx :movsq 16 /r15 :addqImm8Reg /done :jmpLbl8 @mismatch "type mismatch in cat" ::outputError :ud2 @stringCat /rbx :popqReg 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %10 /cl :cmpbImmReg /mismatch :jneLbl8 16 /r15 :subqImm8Reg /rax /r15 :movqRegMem /rbx 8 /r15 :movqRegMemDisp8 # store 16 /rax /rdi :movqMemDisp8Reg 16 /rbx /rdi :addqMemDisp8Reg ::internalAllocateString /rax :movqImmReg /rax :callqReg /rax :pushqReg 24 /rax /rdi :leaqMemDisp8Reg 8 /r15 /rbx :movqMemDisp8Reg 16 /rbx /rcx :movqMemDisp8Reg 24 /rbx /rsi :leaqMemDisp8Reg :reprcx :movsb /r15 /rbx :movqMemReg 16 /rbx /rcx :movqMemDisp8Reg 24 /rbx /rsi :leaqMemDisp8Reg :reprcx :movsb 16 /r15 :addqImm8Reg @done /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /eycat defv # push array contents on stack # 0 -> number of elements to push # 1 -> array # 0 ... <- array contents [[ 8 /r15 :subqImm8Reg /r15 :popqMem /rcx :popqReg 8 /rcx /rcx :movqMemDisp8Reg /rax :popqReg /rcx /rcx :testqRegReg /empty :jzLbl8 8 /rdi :movqImmReg @loop 1 /rdi /rax :pushqMemIndexScale 8 /rdi :addqImm8Reg /edi /rax :cmplRegMem /noreset :jaLbl8 8 /rdi :movqImmReg @noreset /loop :loopLbl8 @empty /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /eydearray defv # create an array containing a continuous range of ints # 0 -> first element after range # 1 -> first element included in range [[ 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem # 8 /r15 == after last element # /r15 == first element 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi /rdi :movqMemDisp8Reg /r15 /rbx :movqMemReg 8 /rbx /rbx :movqMemDisp8Reg /rbx /rdi :subqRegReg /positiveRange :jnsLbl8 /rdi /rdi :xorqRegReg ::internalAllocateArray /rax :movqImmReg /rax :callqReg /rax :pushqReg # store (empty) array on stack /done :jmpLbl8 @positiveRange 3 /rdi :shlqImm8Reg ::internalAllocateArray /rax :movqImmReg /rax :callqReg /rax :pushqReg # store array on stack 8 /rax /rdi :leaqMemDisp8Reg # fill target 8 /r15 /rax :movqMemDisp8Reg 8 /rax /rax :movqMemDisp8Reg # largest element + 1 @fill /rax /rbx :cmpqRegReg /done :jaeLbl8 /rax :pushqReg /rdi :pushqReg # create int ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rbx 8 /rax :movqRegMemDisp8 # store value /rdi :popqReg /rax /rdi :movqRegMem # store into array /rax :popqReg /rbx :incqReg 8 /rdi :addqImm8Reg /fill :jmpLbl8 @done 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /eyrange defv # create a new scope capturing the current one [ ::currentScope /rbx :movqImmReg INITIALSCOPESIZE /rdi :movqImmReg /rbx /rsi :movqMemReg ::internalAllocateScope /rax :movqImmReg /rax :callqReg /rax /rbx :movqRegMem # switch to new scope :retn ] /ey< defv # push current scope onto stack # switch current scope to its parent # 0 <- scope just exited [ /rbx :popqReg ::currentScope /rax :movqImmReg /rax :pushqMem /rax /rcx :movqMemReg 16 /rcx /rcx :movqMemDisp8Reg /rcx /rax :movqRegMem /rbx :pushqReg :retn ] /ey> defv # push current scope onto stack # 0 <- current scope [ /rbx :popqReg ::currentScope /rax :movqImmReg /rax :pushqMem /rbx :pushqReg :retn ] /eyscope defv # die # 0 -> object explaining what went wrong [ /rbx :popqReg /rdi :popqReg ::internalDumpErrorString /rax :movqImmReg /rax :callqReg :ud2 /rbx :pushqReg :retn ] /eydie defv # determine current quoting mode # 0 <- an integer giving the current quoting level [[ /rbx :popqReg # allocate result int ::internalAllocateInteger /rax :movqImmReg /rax :callqReg # and push to stack /rax :pushqReg ::currentQuoted /rcx :movqImmReg /rcx /rcx :movqMemReg /rcx 8 /rax :movqRegMemDisp8 /rbx :pushqReg :retn ]] /eyquoted defv > _ ==globalFunctions { defv }' ::allocateOffsetStruct < # untyped scoped function jumppad # rdi -> code block object to call # rsi -> scope to install [[ 8 /r15 :subqImm8Reg /r15 :popqMem ::currentScope /rax :movqImmReg /rax /rcx :movqMemReg 8 /r15 :subqImm8Reg /rcx /r15 :movqRegMem /rsi /rax :movqRegMem 8 /rdi :addqImm8Reg /rdi :callqReg /r15 /rcx :movqMemReg ::currentScope /rax :movqImmReg /rcx /rax :movqRegMem 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /internalConstantNormalFunctionScopedUntypedJumpPad defv > { defv }' ::allocateOffsetStruct < # resolve identifier without quoting considerations and act accordingly # 0 -> identifier to resolve [[ 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem # store identifier # scope resolution ::currentScope /rdi :movqImmReg /rdi /rdi :movqMemReg /r15 /rsi :movqMemReg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /unresolved :jzLbl8 /rax :pushqReg /rdx /rcx :movqRegReg %0F /cl :andbImmReg 0 /cl :cmpbImmReg /inactive :jzLbl8 1 /cl :cmpbImmReg /active :jzLbl8 2 /cl :cmpbImmReg /active :jzLbl8 "invalid activation mode in internalExecuteIdentifierUnquoted" ::outputError :ud2 @unresolved "unresolved name in internalExecuteIdentifierUnquoted: " ::outputError /r15 /rdi :movqMemReg ::internalDumpErrorString /rax :movqImmReg /rax :callqReg :ud2 @active |ey* /rax :movqImmReg /rax :callqReg @inactive @done 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /internalExecuteIdentifierUnquoted defv # resolve identifier without quoting considerations and act accordingly # after resolving it, patch the given code block to more efficiently call the name next time # 0 -> address of code block # 1 -> identifier to resolve [[ 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem # store code block 8 /r15 :subqImm8Reg /r15 :popqMem # store identifier # scope resolution ::currentScope /rdi :movqImmReg /rdi /rdi :movqMemReg /r15 /rsi :movqMemReg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /unresolved :jzLbl8 /rax :pushqReg %40 /dl :testbImmReg /patchConstant :jnzLbl8 %10 /dl :testbImmReg /patchStatic :jnzLbl32 /rdx /rcx :movqRegReg %0F /cl :andbImmReg 0 /cl :cmpbImmReg /inactive :jzLbl8 1 /cl :cmpbImmReg /active :jzLbl8 2 /cl :cmpbImmReg /active :jzLbl8 "invalid activation mode in internalExecuteIdentifierUnquotedAndPatchLateResolve" ::outputError :ud2 @unresolved "unresolved name in internalExecuteIdentifierUnquotedAndPatchLateResolve: " ::outputError /r15 /rdi :movqMemReg ::internalDumpErrorString /rax :movqImmReg /rax :callqReg :ud2 @active |ey* /rax :movqImmReg /rax :callqReg @inactive @done 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @patchConstant %0F /dl :testbImmReg /patchConstantPassive :jzLbl32 %01 /dl :testbImmReg /patchConstantActive :jnzLbl32 %02 /dl :testbImmReg /patchConstantQuoted :jnzLbl8 "invalid activation mode in internalExecuteIdentifierUnquotedAndPatchLateResolve@patchConstant" ::outputError :ud2 @patchConstantQuoted "quote activation mode in internalExecuteIdentifierUnquotedAndPatchLateResolve@patchConstant" ::outputError :ud2 @patchConstantActive /rdx :popqReg # fetch resolved object 7 /rdx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %50 /cl :cmpbImmReg /patchConstantNormalFunction :jeLbl8 @patchConstantActiveGeneral 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg [ /rbx :popqReg /rax :movqImmOOBReg ] ::loadToRdi /rdx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rax :pushqReg /rbx :pushqReg |ey* /rax :movqImmReg /rax :jmpqReg ] ::loadToRdi 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rdi :jmpqReg # continue with freshly patched code @patchConstantNormalFunction 8 /rdx /rcx :movqMemDisp8Reg /rcx /rcx :testqRegReg /patchConstantNormalFunctionUnscoped :jzLbl32 # @patchConstantNormalFunctionScoped 16 /rdx /rcx :movqMemDisp8Reg /rcx /rcx :testqRegReg /patchConstantNormalFunctionScopedUntyped :jzLbl32 /patchConstantActiveGeneral :jmpLbl32 @patchConstantNormalFunctionScopedUntyped 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg 8 /rdx /rcx :movqMemDisp8Reg # load function scope 24 /rdx /rdx :movqMemDisp8Reg # load actual function code [ /rsi :movqImmOOBReg ] ::loadToRdi /rcx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rdi :movqImmOOBReg ] ::loadToRdi /rdx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ internalConstantNormalFunctionScopedUntypedJumpPad /rax :movqImmReg /rax :jmpqReg ] ::loadToRdi 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rdi :jmpqReg # continue with freshly patched code @patchConstantNormalFunctionUnscoped 16 /rdx /rcx :movqMemDisp8Reg /rcx /rcx :testqRegReg /patchConstantNormalFunctionUnscopedUntyped :jzLbl32 /patchConstantActiveGeneral :jmpLbl32 @patchConstantNormalFunctionUnscopedUntyped 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg 24 /rdx /rdx :movqMemDisp8Reg # load actual function code 8 /rdx :addqImm8Reg [ /rax :movqImmOOBReg ] ::loadToRdi /rdx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rax :jmpqReg /rax :movqImmOOBReg ] ::loadToRdi 8 /rdx :subqImm8Reg /rdx /rdi :movqRegMem # save the address for the GC 8 /rdi :addqImm8Reg 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rdi :jmpqReg # continue with freshly patched code @patchConstantPassive 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg [ /rbx :popqReg /rax :movqImmOOBReg ] ::loadToRdi /rdi :popqMem 8 /rdi :addqImm8Reg [ /rax :pushqReg /rbx :jmpqReg ] ::loadToRdi 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rdi :jmpqReg # continue with freshly patched code @patchStatic /rax :popqReg # fetch resolved object (just to remove it from stack) %0F /dl :testbImmReg /patchStaticPassive :jzLbl32 %01 /dl :testbImmReg /patchStaticActive :jnzLbl32 %02 /dl :testbImmReg /patchStaticQuoted :jnzLbl8 "invalid activation mode in internalExecuteIdentifierUnquotedAndPatchLateResolve@patchStatic" ::outputError :ud2 @patchStaticQuoted "quote activation mode in internalExecuteIdentifierUnquotedAndPatchLateResolve@patchStatic" ::outputError :ud2 @patchStaticPassive /rdi /rcx :movqRegReg # save parent pointer count # FIXME: keep enough place for repeated parent dereference when creating the to-be-patched-code 15 /rcx :cmpqImm8Reg /patchStaticPassiveParentCountWithinLimits :jbeLbl8 "parent count out of save limits in internalExecuteIdentifierUnquotedAndPatchLateResolve" ::outputError :ud2 @patchStaticPassiveParentCountWithinLimits 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg [ ::currentScope /rax :movqImmReg /rax /rax :movqMemReg ] ::loadToRdi /rcx /rcx :testqRegReg /patchStaticPassiveNoFollowParents :jzLbl8 @patchStaticPassiveFollowParents [ 16 /rax /rax :movqMemDisp8Reg ] ::loadToRdi /patchStaticPassiveFollowParents :loopLbl8 @patchStaticPassiveNoFollowParents %01 /bpl :testbImmReg /patchStaticPassiveLoadFromExtensionArea :jnzLbl8 # @patchStaticPassiveLoadFromScope 32 /rsi :addqImm8Reg # now: rsi == offset of entry in scope [ /rbx :popqReg %EE /rax :pushqMemDisp32 /rbx :jmpqReg ] ::loadToRdi 6 /rdi :subqImm8Reg /esi /rdi :movlRegMem # patch offset 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rdi :jmpqReg # continue with freshly patched code @patchStaticPassiveLoadFromExtensionArea 40 /rsi :addqImm8Reg # now: rsi == offset of entry in extension area + scope length [ 24 /rax /rcx :movqMemDisp8Reg # load extension area pointer /rax /edx :movlMemReg # load scope length /rdx :negqReg # prepare for substraction /rbx :popqReg %EE 1 /rdx /rcx :pushqMemIndexScaleDisp32 # push loaded entry to stack /rbx :jmpqReg ] ::loadToRdi 6 /rdi :subqImm8Reg /esi /rdi :movlRegMem # patch offset 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rdi :jmpqReg # continue with freshly patched code @patchStaticActive /rdi /rcx :movqRegReg # save parent pointer count # FIXME: keep enough place for repeated parent dereference when creating the to-be-patched-code 15 /rcx :cmpqImm8Reg /patchStaticActiveParentCountWithinLimits :jbeLbl8 "parent count out of save limits in internalExecuteIdentifierUnquotedAndPatchLateResolve" ::outputError :ud2 @patchStaticActiveParentCountWithinLimits 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg [ ::currentScope /rax :movqImmReg /rax /rax :movqMemReg ] ::loadToRdi /rcx /rcx :testqRegReg /patchStaticActiveNoFollowParents :jzLbl8 @patchStaticActiveFollowParents [ 16 /rax /rax :movqMemDisp8Reg ] ::loadToRdi /patchStaticActiveFollowParents :loopLbl8 @patchStaticActiveNoFollowParents %01 /bpl :testbImmReg /patchStaticActiveLoadFromExtensionArea :jnzLbl8 # @patchStaticActiveLoadFromScope 32 /rsi :addqImm8Reg # now: rsi == offset of entry in scope [ /rbx :popqReg %EE /rax :pushqMemDisp32 /rbx :pushqReg |ey* /rax :movqImmReg /rax :jmpqReg ] ::loadToRdi 17 /rdi :subqImm8Reg /esi /rdi :movlRegMem # patch offset 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rdi :jmpqReg # continue with freshly patched code @patchStaticActiveLoadFromExtensionArea 40 /rsi :addqImm8Reg # now: rsi == offset of entry in extension area + scope length [ 24 /rax /rcx :movqMemDisp8Reg # load extension area pointer /rax /edx :movlMemReg # load scope length /rdx :negqReg # prepare for substraction /rbx :popqReg %EE 1 /rdx /rcx :pushqMemIndexScaleDisp32 # push loaded entry to stack /rbx :pushqReg |ey* /rax :movqImmReg /rax :jmpqReg ] ::loadToRdi 17 /rdi :subqImm8Reg /esi /rdi :movlRegMem # patch offset 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi :addqImm8Reg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rdi :jmpqReg # continue with freshly patched code ]] /internalExecuteIdentifierUnquotedAndPatchLateResolve defv # optimize function code by # * patching double redirects, # FIXME correctly detect out-of-heap even if below heap # 0 -> address of code block [[ /rbx :popqReg /rsi :popqReg 8 /rsi :addqImm8Reg # move to start of code /rsi :pushqReg :quoteEncodingBuffer /rdi :movqImmReg %34 /rcx :movqImmReg # skip to generated code :reprcx :movsb @parseLoop 0 [ 0 :callqRel32 ] * 0 /rsi :cmpbImmMemDisp8 /parseFooter :jzLbl32 1 [ 8 /rax :addqImm8Reg ] * 11 /rsi :cmpbImmMemDisp8 /parseFunctionCall :jzLbl32 0 [ /rax :pushqReg ] * 10 /rsi :cmpbImmMemDisp8 /parseConstantPush :jzLbl32 0 [ /rax :callqReg ] * 10 /rsi :cmpbImmMemDisp8 /parseConstantCall :jzLbl32 "unknown assembly instruction during internalOptimizeGeneratedScopedFunction" ::outputError :ud2 @parseFunctionCall 2 /rsi /rdx :movqMemDisp8Reg # load function address 1 [ 0 /rax :movqImmReg ] * 9 /rdx :cmpbImmMemDisp8 /parseFunctionCallSkip :jnzLbl32 0 [ /rax :jmpqReg ] * 18 /rdx :cmpbImmMemDisp8 /parseFunctionCallSkip :jnzLbl32 1 [ /rax :jmpqReg ] * 19 /rdx :cmpbImmMemDisp8 /parseFunctionCallSkip :jnzLbl32 10 /rdx /rcx :movqMemDisp8Reg # load final function address /rax :movqImmOOBReg ::HEAPEND /rax /rcx :cmpqRegReg /parseFunctionUnGCable :jaeLbl8 # @parseFunctionGCable [ /rax :movqImmOOBReg ] ::loadToRdi 8 /rcx :subqImm8Reg # make address point to code block object /rcx /rdi :movqRegMem # load final function address 8 /rdi :addqImm8Reg [ 8 /rax :addqImm8Reg # skip code block object header /rax :callqReg ] ::loadToRdi /parseFunctionCallDone :jmpLbl8 @parseFunctionUnGCable [ /rax :movqImmOOBReg ] ::loadToRdi /rcx /rdi :movqRegMem # load final function address 8 /rdi :addqImm8Reg [ /rax :callqReg ] ::loadToRdi @parseFunctionCallDone 16 /rsi :addqImm8Reg /parseLoop :jmpLbl32 @parseFunctionCallSkip :movsq # verbatim copy :movsq /parseLoop :jmpLbl32 @parseConstantPush :movsq # verbatim copy :movsw :movsb /parseLoop :jmpLbl32 @parseConstantCall :movsq # verbatim copy :movsl /parseLoop :jmpLbl32 @parseFooter ::scopingFunctionFooter ::loadToRdi ::allocateCodeFromEncodingBuffer # rax == optimized code object on heap # patch indirection to new code into old /rsi :popqReg # rsi == old code start /rsi /rdi :movqRegReg [ /rax :movqImmOOBReg ] ::loadToRdi 8 /rax :addqImm8Reg /rax /rdi :movqRegMem 8 /rax :subqImm8Reg 8 /rdi :addqImm8Reg [ /rax :jmpqReg /rax :movqImmOOBReg ] ::loadToRdi /rax /rdi :movqRegMem # TODO kill remaining opcodes to remove GC-followable memory addresses # but think of the return stack /rbx :jmpqReg ]] /internalOptimizeGeneratedScopedFunction defv # optimize function code by # * TODO patching double redirects # 0 -> address of code block [[ # :ud2 # FIXME enable here to debug function optimization /rbx :popqReg /rax :popqReg # FIXME do something useful here /rbx :pushqReg :retn ]] /internalOptimizeGeneratedUnscopedFunction defv # optimize function code by # * TODO patching double redirects # 0 -> address of code block [[ # :ud2 # FIXME enable here to debug function optimization /rbx :popqReg /rax :popqReg # FIXME do something useful here /rbx :pushqReg :retn ]] /internalOptimizeGeneratedUncapturingFunction defv > { defv }' ::allocateOffsetStruct < # resolve identifier according to current scope and quote mode and act accordingly # 0 -> identifier to resolve [[ 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem # store identifier # scope resolution ::currentScope /rdi :movqImmReg /rdi /rdi :movqMemReg /r15 /rsi :movqMemReg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /unresolved :jzLbl8 /rdx /rcx :movqRegReg %0F /cl :andbImmReg 0 /cl :cmpbImmReg /inactive :jzLbl32 1 /cl :cmpbImmReg /active :jzLbl8 2 /cl :cmpbImmReg /quoteActive :jzLbl8 "invalid activation mode in internalExecuteIdentifier" ::outputError :ud2 @unresolved ::currentQuoted /rax :movqImmReg /rax /rax :movqMemReg /rax /rax :testqRegReg /constructQuotedResolve :jnzLbl8 "unresolved name in internalExecuteIdentifier: " ::outputError /r15 /rdi :movqMemReg ::internalDumpErrorString /rax :movqImmReg /rax :callqReg :ud2 @quoteActive /rax :pushqReg |ey* /rax :movqImmReg /rax :callqReg /done :jmpLbl8 @active ::currentQuoted /rbx :movqImmReg /rbx /rbx :movqMemReg /rbx /rbx :testqRegReg /constructQuotedResolve :jnzLbl8 /rax :pushqReg |ey* /rax :movqImmReg /rax :callqReg /done :jmpLbl8 @inactive ::currentQuoted /rbx :movqImmReg /rbx /rbx :movqMemReg /rbx /rbx :testqRegReg /constructQuotedResolve :jnzLbl8 /rax :pushqReg @done 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @constructQuotedResolve # construct non-capturing function :quoteEncodingBuffer /rdi :movqImmReg ::unscopingFunctionHeader ::loadToRdi # push identifier [ /rax :movqImmOOBReg ] _ len 2 eq assert 2 dearray 256 mul add /rdi :movwImmMem /r15 /rsi :movqMemReg /rsi 2 /rdi :movqRegMemDisp8 10 /rdi :addqImm8Reg [ /rax :pushqReg 0 :callqRel32 /rax :popqReg # 16 bytes code here, header length, and code block header 16 ::unscopingFunctionHeader len add 8 add /rax :subqImm8Reg /rax :pushqReg 64 { :nop } rep # FIXME the maximum patch length still needs to be determined internalExecuteIdentifierUnquotedAndPatchLateResolve /rax :movqImmReg /rax :callqReg ] ::unscopingFunctionFooter cat ::loadToRdi ::allocateCodeFromEncodingBuffer # rax == code block on heap # create non-capturing function object /rax /rdi :movqRegReg /rsi /rsi :xorqRegReg /rdx /rdx :xorqRegReg ::internalAllocateFunction /rax :movqImmReg /rax :callqReg # rax == function object on heap /rax :pushqReg /done :jmpLbl32 ]] /internalExecuteIdentifier defv > { defv }' ::allocateOffsetStruct < # predefining defv, deff, defq # TODO think about moving this to standard(Client) one day # 0 -> name, string # 1 -> object { ==activation [[ 8 /r15 :subqImm8Reg /r15 :popqMem ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rax :pushqReg activation /rdx :movqImmReg /rdx 8 /rax :movqRegMemDisp8 eydef /rax :movqImmReg /rax :callqReg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] } %00 -101* /eydefv defv %01 -101* /eydeff defv %02 -101* /eydefq defv %10 -101* /eydefvs defv %11 -101* /eydeffs defv %20 -101* /eydefvt defv %21 -101* /eydefft defv %30 -101* /eydefvst defv %31 -101* /eydeffst defv %40 -101* /eydefvc defv %41 -101* /eydeffc defv %C0 -101* /eydefvd defv %C1 -101* /eydeffd defv -- # concatenate two functions # 0 -> function g # 1 -> function f # 0 <- (f g) [[ 8 /r15 :subqImm8Reg /r15 :popqMem # construct non-capturing function :quoteEncodingBuffer /rdi :movqImmReg ::unscopingFunctionHeader ::loadToRdi /rcx :popqReg /rdx :popqReg # push function f [ /rax :movqImmOOBReg ] _ len 2 eq assert 2 dearray 256 mul add /rdi :movwImmMem /rdx 2 /rdi :movqRegMemDisp8 10 /rdi :addqImm8Reg [ /rax :pushqReg |ey* /rax :movqImmReg /rax :callqReg /rax :movqImmOOBReg ] ::loadToRdi # push function g /rcx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rax :pushqReg |ey* /rax :movqImmReg /rax :callqReg ] ::unscopingFunctionFooter cat ::loadToRdi ::allocateCodeFromEncodingBuffer # rax == code block on heap # create non-capturing function object /rax /rdi :movqRegReg /rsi /rsi :xorqRegReg /rdx /rdx :xorqRegReg ::internalAllocateFunction /rax :movqImmReg /rax :callqReg # rax == function object on heap /rax :pushqReg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /ey; defv # drop top stack element [ /rax :popqReg /rcx :popqReg /rax :pushqReg :retn ] /ey-- defv # duplicate top stack element [ /rax :popqReg /rcx :popqReg /rcx :pushqReg /rcx :pushqReg /rax :pushqReg :retn ] /ey_ defv # top stack element is a string defining a stack shuffle # 0-9: push the thusly numbered element # *: execute top element # pops as many elements as the highest number specifies [[ 8 /r15 :subqImm8Reg /r15 :popqMem 80 /r15 :subqImm8Reg /rdi :popqReg 16 /rdi /rcx :movqMemDisp8Reg # load string length 24 /rdi /rax :leaqMemDisp8Reg # rax to begin of string 42 /rsi :movqImmReg # initialize with '*' # find maximal element, note that '*' < '0' @maximalElementSearch /rax /rdx :movzxMem8Reg64 /rsi /rdx :cmpqRegReg /rdx /rsi :cmovaqRegReg /rax :incqReg /maximalElementSearch :loopLbl8 # move elements to temporary storage 42 /rsi :cmpqImm8Reg /elementsSaved :jeLbl8 47 /rsi :subqImm8Reg # substract '0'-1 /rsi /rcx :movqRegReg /rsi /rsi :xorqRegReg @saveElements 8 /rsi /r15 :popqMemIndexScale /rsi :incqReg /saveElements :loopLbl8 # execute shuffle specification @elementsSaved 16 /rdi /rcx :movqMemDisp8Reg # load string length 24 /rdi /rax :leaqMemDisp8Reg # rax to begin of string @executeSpec /rax /rdx :movzxMem8Reg64 /rax :incqReg 42 /rdx :cmpqImm8Reg /executeTop :jeLbl8 48 /rdx :subqImm8Reg # substract '0' 8 /rdx /r15 :pushqMemIndexScale /executeSpec :loopLbl8 /done :jmpLbl8 @executeTop 24 /r15 :subqImm8Reg /rax 16 /r15 :movqRegMemDisp8 /rcx 8 /r15 :movqRegMemDisp8 /rdx /r15 :movqRegMem |ey* /rax :movqImmReg /rax :callqReg /r15 /rdx :movqMemReg 8 /r15 /rcx :movqMemDisp8Reg 16 /r15 /rax :movqMemDisp8Reg 24 /r15 :addqImm8Reg /executeSpec :loopLbl8 @done 80 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /ey- defv # execute top stack element multiple times # 0 -> function to execute # 1 -> how often to execute it [[ 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem # store function to call 8 /r15 :subqImm8Reg /rcx :popqReg 8 /rcx /rcx :movqMemDisp8Reg /rcx /rcx :testqRegReg /end :jzLbl8 @loop /rcx /r15 :movqRegMem 8 /r15 :pushqMemDisp8 |ey* /rax :movqImmReg /rax :callqReg /r15 /rcx :movqMemReg /loop :loopLbl8 @end 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /eyrep defv # a normal loop # 0 -> second part of loop # 1 -> first part of loop # execute first part, if top of stack is nonzero, execute second part, repeat [[ 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem # /r15 -> first part # 8 /r15 -> second part @loop /r15 :pushqMem |ey* /rax :movqImmReg /rax :callqReg /rax :popqReg 0 8 /rax :cmpqImm8MemDisp8 /end :jzLbl8 8 /r15 :pushqMemDisp8 |ey* /rax :movqImmReg /rax :callqReg /loop :jmpLbl8 @end 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /eyloop defv # a foreach loop # 0 -> code to execute # 1 -> array to loop over # for each element in array, push it onto stack then execute the code [[ 8 /r15 :subqImm8Reg /r15 :popqMem 32 /r15 :subqImm8Reg 16 /r15 :popqMemDisp8 /rax :popqReg /rax 24 /r15 :movqRegMemDisp8 7 /rax /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %70 /cl :cmpbImmReg /eachArray :jzLbl8 %10 /cl :cmpbImmReg /eachString :jzLbl8 "neither string nor array in each" ::outputError :ud2 @eachArray 8 /rax /rcx :leaqMemDisp8Reg /rcx /r15 :movqRegMem /rax /edx :movlMemReg 1 /rdx /rax /rcx :leaqMemIndexScaleReg /rcx 8 /r15 :movqRegMemDisp8 # /r15 -> current array element # 8 /r15 -> address after last array element # 16 /r15 -> code to execute # 24 /r15 -> array object (to keep the GC away) @loop /r15 /rax :movqMemReg 8 /r15 /rax :cmpqMemDisp8Reg /end :jnbLbl8 /rax :pushqMem # push array element 16 /r15 :pushqMemDisp8 # push code |ey* /rax :movqImmReg /rax :callqReg 8 /r15 :addqImm8Mem /loop :jmpLbl8 @eachString 16 /rax /rcx :movqMemDisp8Reg /rcx 8 /r15 :movqRegMemDisp8 24 /rax /rcx :leaqMemDisp8Reg /rcx /r15 :movqRegMem # /r15 -> current string element # 8 /r15 -> count remaining # 16 /r15 -> code to execute # 24 /r15 -> string object (to keep the GC away) @stringLoop ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rax :pushqReg /r15 /rdx :movqMemReg /rdx /rdx :movzxMem8Reg64 /rdx 8 /rax :movqRegMemDisp8 16 /r15 :pushqMemDisp8 # push code |ey* /rax :movqImmReg /rax :callqReg 1 /r15 :addqImm8Mem 1 8 /r15 :subqImm8MemDisp8 /stringLoop :jnzLbl8 @end 32 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /eyeach defv # explicitely resolve a scope member # 0 -> member name # 1 -> scope [[ 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem # store identifier /rdi :popqReg # fetch scope /r15 /rsi :movqMemReg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /unresolved :jzLbl8 /rax :pushqReg %0F /dl :testbImmReg /inactive :jzLbl8 %01 /dl :testbImmReg /active :jnzLbl8 "invalid activation mode in ." ::outputError :ud2 @unresolved "unresolved name in .: " ::outputError /r15 /rdi :movqMemReg ::internalDumpErrorString /rax :movqImmReg /rax :callqReg :ud2 @active |ey* /rax :movqImmReg /rax :callqReg @inactive @done 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /ey. defv # explicitely resolve a scope member, but never execute # 0 -> member name # 1 -> scope [[ 8 /r15 :subqImm8Reg /r15 :popqMem 8 /r15 :subqImm8Reg /r15 :popqMem # store identifier /rdi :popqReg # fetch scope /r15 /rsi :movqMemReg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /unresolved :jzLbl8 /rax :pushqReg 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @unresolved "unresolved name in .|: " ::outputError /r15 /rdi :movqMemReg ::internalDumpErrorString /rax :movqImmReg /rax :callqReg :ud2 ]] /ey.| defv # enumerate scope keys # 0 -> scope # 0 <- array of keys [[ 8 /r15 :subqImm8Reg /r15 :popqMem /rax :popqReg 8 /rax /rax :movqMemDisp8Reg 16 /rax /rsi :leaqMemDisp8Reg /rsi :pushqReg 8 /rax /rdi :movqMemDisp8Reg 16 /rdi :subqImm8Reg /rdi :pushqReg /rdi :shrq1Reg ::internalAllocateArray /rax :movqImmReg /rax :callqReg 8 /rax /rdi :leaqMemDisp8Reg /rcx :popqReg /rsi :popqReg 4 /rcx :shrqImm8Reg /empty :jzLbl8 @loop :movsq 8 /rsi :addqImm8Reg /loop :loopLbl8 @empty /rax :pushqReg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /eykeys defv > _ ==globalFunctions2 { defv }' ::allocateOffsetStruct < # domain of an array # 0 -> array # 0 <- an array containing the integers from 0 to len 1 sub [[ 8 /r15 :subqImm8Reg /r15 :popqMem /rax :popqReg 7 /rax /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %70 /cl :cmpbImmReg /arrayDom :jeLbl8 %20 /cl :cmpbImmReg /scopeDom :jeLbl8 "non-array passed to dom" ::outputError :ud2 @arrayDom /rax /edi :movlMemReg 8 /rdi :subqImm8Reg # substract header length ::internalAllocateArray /rax :movqImmReg /rax :callqReg /rax :pushqReg # result on stack 8 /rax /rdi :leaqMemDisp8Reg /rbx /rbx :xorqRegReg /rax /ecx :movlMemReg 3 /rcx :shrqImm8Reg /rcx :decqReg @loop /rcx /rbx :cmpqRegReg /end :jnbLbl8 /rdi :pushqReg /rcx :pushqReg ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rcx :popqReg /rdi :popqReg /rax 8 /rbx /rdi :movqRegMemIndexScale # store in array /rbx 8 /rax :movqRegMemDisp8 # store value in int /rbx :incqReg /loop :jmpLbl8 @end /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @scopeDom /rax :pushqReg /rax :movqImmOOBReg "dom" ::string /rax :pushqReg |ey. /rax :movqImmReg /rax :callqReg /end :jmpLbl8 ]] /eydom defv > _ ==globalFunctions3 { defv }' ::allocateOffsetStruct < # quote construction, push begin marker on stack [ /rax :popqReg QUOTEMARKER :pushqImm32 ::currentQuoted /rcx :movqImmReg /rcx :incqMem /rax :pushqReg :retn ] /ey{ defv # quote construction, create function from begin marker onwards { ==optimizer ==footer ==header ==capturing [[ 8 /r15 :subqImm8Reg /r15 :popqMem ::currentQuoted /rcx :movqImmReg /rcx :decqMem QUOTEMARKER /rcx :movqImmReg /rcx :pushqReg /rsp /rdx :movqRegReg @backwardsSearch 8 /rdx :addqImm8Reg /rdx /rcx :cmpqMemReg /backwardsSearch :jneLbl8 /rdx :pushqReg # store address of begin marker :quoteEncodingBuffer /rdi :movqImmReg header ::loadToRdi @search 8 /rdx :subqImm8Reg /rdx /rcx :cmpqMemReg /markerFound :jeLbl32 /rdx /rsi :movqMemReg 7 /rsi /al :movbMemDisp8Reg %F0 /al :andbImmReg /immediateFound :jzLbl8 %10 /al :cmpbImmReg /immediateFound :jzLbl8 %50 /al :cmpbImmReg /functionFound :jzLbl8 %70 /al :cmpbImmReg /arrayFound :jzLbl32 "invalid object during quote construction" ::outputError :ud2 @immediateFound [ /rax :movqImmOOBReg ] _ len 2 eq assert 2 dearray 256 mul add /rdi :movwImmMem /rsi 2 /rdi :movqRegMemDisp8 [ /rax :pushqReg ] _ len 1 eq assert 1 dearray 10 /rdi :movbImmMemDisp8 11 /rdi :addqImm8Reg /search :jmpLbl32 @functionFound 8 /rsi /rax :movqMemDisp8Reg /rax /rax :testqRegReg /generalFunctionFound :jnzLbl8 16 /rsi /rax :movqMemDisp8Reg /rax /rax :testqRegReg /generalFunctionFound :jnzLbl8 # @nonScopingNonTypedFound 24 /rsi /rax :movqMemDisp8Reg [ /rax :movqImmOOBReg ] _ len 2 eq assert 2 dearray 256 mul add /rdi :movwImmMem /rax 2 /rdi :movqRegMemDisp8 10 /rdi :addqImm8Reg [ 8 /rax :addqImm8Reg # add code offset only here, to keep the address available for GC /rax :callqReg ] ::loadToRdi /search :jmpLbl32 @generalFunctionFound [ /rax :movqImmOOBReg ] _ len 2 eq assert 2 dearray 256 mul add /rdi :movwImmMem /rsi 2 /rdi :movqRegMemDisp8 [ /rax :pushqReg ] _ len 1 eq assert 1 dearray 10 /rdi :movbImmMemDisp8 11 /rdi :addqImm8Reg [ |ey* /rax :movqImmReg /rax :callqReg ] ::loadToRdi /search :jmpLbl32 @arrayFound # FIXME allow macros to put byte arrays into quoted contexts and thereby generate assembly :ud2 /search :jmpLbl32 @markerFound [ 0 :callqRel32 /rax :popqReg /rbx :movqImmOOBReg ] ::loadToRdi :quoteEncodingBuffer /rbx :movqImmReg /rdi /rax :movqRegReg 5 /rax :addqImm8Reg /rbx /rax :subqRegReg /rax /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rbx /rax :subqRegReg /rax :pushqReg optimizer /rax :movqImmReg /rax :callqReg ] ::loadToRdi footer ::loadToRdi ::allocateCodeFromEncodingBuffer # rax == code block on heap ::currentQuoted /rcx :movqImmReg /rcx /rcx :movqMemReg /rcx /rcx :testqRegReg /quoted :jnzLbl8 # create function object /rax /rdi :movqRegReg capturing { ::currentScope /rax :movqImmReg /rax /rsi :movqMemReg } { /rsi /rsi :xorqRegReg } ? * /rdx /rdx :xorqRegReg ::internalAllocateFunction /rax :movqImmReg /rax :callqReg @done # rax == function object on heap # store function instead of begin marker /rdx :popqReg /rax /rdx :movqRegMem /rdx /rsp :movqRegReg # and drop quoted stuff from stack /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @quoted # rax == (inner) code object on heap # create function which # returns a function with the current scope captured :quoteEncodingBuffer /rdi :movqImmReg ::unscopingFunctionHeader ::loadToRdi # 1. load inner code block [ /rdi :movqImmOOBReg ] _ len 2 eq assert 2 dearray 256 mul add /rdi :movwImmMem /rax 2 /rdi :movqRegMemDisp8 10 /rdi :addqImm8Reg [ ::currentScope /rax :movqImmReg /rax /rsi :movqMemReg /rdx /rdx :xorqRegReg ::internalAllocateFunction /rax :movqImmReg /rax :callqReg /rax :pushqReg ] ::unscopingFunctionFooter cat ::loadToRdi ::allocateCodeFromEncodingBuffer # rax == code object on heap # create function object /rax /rdi :movqRegReg /rsi /rsi :xorqRegReg # non-capturing /rdx /rdx :xorqRegReg ::internalAllocateFunction /rax :movqImmReg /rax :callqReg # rax == function object on heap /done :jmpLbl32 ]] } _ 1 ::scopingFunctionHeader ::scopingFunctionFooter internalOptimizeGeneratedScopedFunction -32104* /ey} defv _ 1 ::unscopingFunctionHeader ::unscopingFunctionFooter internalOptimizeGeneratedUnscopedFunction -32104* /ey}' defv _ 0 ::unscopingFunctionHeader ::unscopingFunctionFooter internalOptimizeGeneratedUncapturingFunction -32104* /ey}" defv -- > _ ==globalMacros { defv }' ::allocateOffsetStruct < [ %10 %00 %00 %00 %00 %00 %00 %00 %01 %00 %00 %00 %00 %00 %00 %00 ] /t1 defv [ %28 %00 %00 %00 %00 %00 %00 %80 %01 %00 %00 %00 %00 %00 %00 %00 /t1t1 /t1 ::linkAbs64 %01 %00 %00 %00 %00 %00 %00 %00 /t1t1 /t1 ::linkAbs64 ] /t1t1 defv [ %30 %00 %00 %00 %00 %00 %00 %80 %02 %00 %00 %00 %00 %00 %00 %00 /t11t1 /t1 ::linkAbs64 /t11t1 /t1 ::linkAbs64 %01 %00 %00 %00 %00 %00 %00 %00 /t11t1 /t1 ::linkAbs64 ] /t11t1 defv [ %20 %00 %00 %00 %00 %00 %00 %10 %00 %00 %00 %00 %00 %00 %00 %00 %01 %00 %00 %00 %00 %00 %00 %00 %61 %00 %00 %00 %00 %00 %00 %00 ] /ta defv [ %30 %00 %00 %00 %00 %00 %00 %80 %02 %00 %00 %00 %00 %00 %00 %00 /taat1 /ta ::linkAbs64 /taat1 /ta ::linkAbs64 %01 %00 %00 %00 %00 %00 %00 %00 /taat1 /t1 ::linkAbs64 ] /taat1 defv > _ =globalTypes { defv }' ::allocateOffsetStruct < # arithmetic functions on ints [ /rcx /rdx :addqRegReg ] makeArith /eyadd defv [ /rcx /rdx :subqRegReg ] makeArith /eysub defv [ /rcx /rdx :andqRegReg ] makeArith /eyband defv [ /rcx /rdx :orqRegReg ] makeArith /eybor defv [ /rcx /rdx :xorqRegReg ] makeArith /eybxor defv [ /rdi /rdi :xorqRegReg 1 /rsi :movqImmReg /rdx /rcx :cmpqRegReg /rsi /rdx :movqRegReg /rdi /rdx :cmovnzqRegReg ] makeArith /eyeq defv [ /rdi /rdi :xorqRegReg 1 /rsi :movqImmReg /rdx /rcx :cmpqRegReg /rsi /rdx :movqRegReg /rdi /rdx :cmovzqRegReg ] makeArith /eyneq defv [ /rdi /rdi :xorqRegReg 1 /rsi :movqImmReg /rdx /rcx :cmpqRegReg /rsi /rdx :movqRegReg /rdi /rdx :cmovgeqRegReg ] makeArith /eygt defv [ /rdi /rdi :xorqRegReg 1 /rsi :movqImmReg /rdx /rcx :cmpqRegReg /rsi /rdx :movqRegReg /rdi /rdx :cmovgqRegReg ] makeArith /eyge defv [ /rdi /rdi :xorqRegReg 1 /rsi :movqImmReg /rdx /rcx :cmpqRegReg /rsi /rdx :movqRegReg /rdi /rdx :cmovngqRegReg ] makeArith /eylt defv [ /rdi /rdi :xorqRegReg 1 /rsi :movqImmReg /rdx /rcx :cmpqRegReg /rsi /rdx :movqRegReg /rdi /rdx :cmovngeqRegReg ] makeArith /eyle defv [ /rax :pushqReg /rcx /rax :movqRegReg /rdx :mulqReg /rax /rdx :movqRegReg /rax :popqReg ] makeArith /eymul defv [ /rax :pushqReg /rdx /rax :movqRegReg /rdx /rdx :xorqRegReg /rcx :divqReg /rax :popqReg ] makeArith /eymod defv [ /rax :pushqReg /rdx /rax :movqRegReg /rdx /rdx :xorqRegReg /rcx :divqReg /rax /rdx :movqRegReg /rax :popqReg ] makeArith /eydiv defv [[ /rcx /rcx :testqRegReg /no :jzLbl8 /rdx /rdx :testqRegReg /no :jzLbl8 1 /rdx :movqImmReg /done :jmpLbl8 @no /rdx /rdx :xorqRegReg @done ]] makeArith /eyand defv [[ /rcx /rcx :testqRegReg /yes :jnzLbl8 /rdx /rdx :testqRegReg /yes :jnzLbl8 /rdx /rdx :xorqRegReg /done :jmpLbl8 @yes 1 /rdx :movqImmReg @done ]] makeArith /eyor defv > _ =globalT11t1Functions { defv }' ::allocateOffsetStruct < [[ /rbx :popqReg # allocate result int ::internalAllocateInteger /rax :movqImmReg /rax :callqReg /rdx :popqReg /rdi :popqReg /rax :pushqReg 16 /rdx /rsi :movqMemDisp8Reg 16 /rdi /rcx :movqMemDisp8Reg /rsi /rcx :cmpqRegReg /nonEqual :jneLbl8 24 /rdx /rsi :leaqMemDisp8Reg 24 /rdi /rdi :leaqMemDisp8Reg :repz :cmpsb /nonEqual :jneLbl8 /rdx /rdx :xorqRegReg /rdx :incqReg /done :jmpLbl8 @nonEqual /rdx /rdx :xorqRegReg @done /rdx 8 /rax :movqRegMemDisp8 /rbx :pushqReg :retn ]] /eystreq defv > _ =globalTaat1Functions { defv }' ::allocateOffsetStruct < # 0 -> integer # 0 <- the bitwise negated integer [[ /rbx :popqReg # allocate result int ::internalAllocateInteger /rax :movqImmReg /rax :callqReg # type zero does not need to be changed # actual negation /rcx :popqReg 8 /rcx /rcx :movqMemDisp8Reg /rcx :notqReg /rcx 8 /rax :movqRegMemDisp8 # push int address on program stack /rax :pushqReg /rbx :pushqReg :retn ]] _ /eybnot defv # 0 -> integer # 0 <- the numerically negated integer, i.e. 0 - x [[ /rbx :popqReg # allocate result int ::internalAllocateInteger /rax :movqImmReg /rax :callqReg # type zero does not need to be changed # actual negation /rcx :popqReg 8 /rcx /rcx :movqMemDisp8Reg /rcx :negqReg /rcx 8 /rax :movqRegMemDisp8 # push int address on program stack /rax :pushqReg /rbx :pushqReg :retn ]] _ /eyneg defv # 0 -> integer # 0 <- the logically negated integer [[ /rbx :popqReg # allocate result int ::internalAllocateInteger /rax :movqImmReg /rax :callqReg # type zero does not need to be changed # actual negation /rcx :popqReg 8 /rcx /rcx :movqMemDisp8Reg /rdx /rdx :xorqRegReg /rcx /rcx :testqRegReg /zero :jnzLbl8 /rdx :incqReg @zero /rdx 8 /rax :movqRegMemDisp8 # push int address on program stack /rax :pushqReg /rbx :pushqReg :retn ]] /eynot defv > _ =globalT1t1Functions { defv }' ::allocateOffsetStruct { | }' ::linkResolve { =*resolve ==createScopeEntry { ==name # create function name resolve 8 sub /rdi :movqImmReg # adjust for expected (but non-existent) code block header size /rsi /rsi :xorqRegReg # library functions don't have a captured scope # TODO: put a type here where applicable /rdx /rdx :xorqRegReg ::internalAllocateFunction /rax :movqImmReg /rax :callqReg /rax :pushqReg # create string name "ey(.*)" regex assert ::constStringCode _ len dearray # enter into current (i.e. global) scope createScopeEntry /rax :movqImmReg /rax :callqReg } each } /createScopeEntries deff { =*resolve ==typeToUse ==createScopeEntry { ==name # create function name resolve 8 sub /rdi :movqImmReg # adjust for expected (but non-existent) code block header size /rsi /rsi :xorqRegReg # library functions don't have a captured scope typeToUse /rdx :movqImmReg ::internalAllocateFunction /rax :movqImmReg /rax :callqReg /rax :pushqReg # create string name "ey(.*)" regex assert ::constStringCode _ len dearray # enter into current (i.e. global) scope createScopeEntry /rax :movqImmReg /rax :callqReg } each } /createTypedScopeEntries deff { [ /eydefv /eydeff /eydefq ] { ==name # create function name | 8 sub /rdi :movqImmReg # adjust for expected (but non-existent) code block header size ::currentScope /rsi :movqImmReg /rsi /rsi :movqMemReg /rdx /rdx :xorqRegReg # untyped ::internalAllocateFunction /rax :movqImmReg /rax :callqReg /rax :pushqReg # create string name "ey(.*)" regex assert ::constStringCode _ len dearray # enter into current scope |eydeff /rax :movqImmReg /rax :callqReg } each } /createScopeExtensionEntries deff [ globalFunctions keys len globalFunctions2 keys len add globalFunctions3 keys len add globalMacros keys len add globalT11t1Functions keys len add globalT1t1Functions keys len add globalTaat1Functions keys len add /rdi :movqImmReg /rsi /rsi :xorqRegReg ::internalAllocateScope /rax :movqImmReg /rax :callqReg ::currentScope /rdi :movqImmReg /rax /rdi :movqRegMem globalFunctions keys eydeffd { | }' createScopeEntries globalFunctions2 keys eydeffd { | }' createScopeEntries globalFunctions3 keys eydeffd { | }' createScopeEntries globalMacros keys eydefq { | }' createScopeEntries globalT11t1Functions keys eydeffd t11t1 { | }' createTypedScopeEntries globalT1t1Functions keys eydeffd t1t1 { | }' createTypedScopeEntries globalTaat1Functions keys eydeffd taat1 { | }' createTypedScopeEntries ] :execute { ==name [[ INITIALSCOPESIZE /rdi :movqImmReg ::currentScope /rsi :movqImmReg 8 /r15 :subqImm8Reg /rsi /rsi :movqMemReg /rsi /r15 :movqRegMem # save scope ::internalAllocateScope /rax :movqImmReg /rax :callqReg /rax :pushqReg /rax :pushqReg /rax :movqImmOOBReg name ::string /rax :pushqReg |eydefv /rax :movqImmReg /rax :callqReg ::currentScope /rsi :movqImmReg /rsi :popqMem ]] :execute } /enterSubScope deff { [[ ::currentScope /rsi :movqImmReg /r15 /rax :movqMemReg 8 /r15 :addqImm8Reg /rax /rsi :movqRegMem ]] :execute } /leaveSubScope deff "elymasGlobalSys.ey" include "elymasGlobalStr.ey" include > /global defv # vim: syn=elymas