"elymasAsmLib.ey" include < { assembler -01 . } ":" deff { assemblerLibrary -01 . } "::" deff assembler .|label "@" deff "%" _ : -01 deff { :labelRecord [ } "[[" deff { ] :labelResolve ::stringResolve } "]]" deff # elymas functions, stack based ABI 1 ==ARRAYMARKER 2 ==QUOTEMARKER 3 ==POSITIONMARKER < [ %08 %00 %00 %00 %00 %00 %00 %70 ] /emptyArray defv > { defv }' ::allocateOffsetStruct < # 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 /r14 /rdi :movqRegReg /rbx /rsi :movqRegReg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /found :jnzLbl8 /rcx :popqReg /rbx :pushqReg /r14 :pushqReg /rax :movqImmOOBReg "#.|" ::string /rax :pushqReg /rax :movqImmOOBReg "ey|" "ey." ::linkAbs64 /rcx :pushqReg /rax :jmpqReg @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 63 /rax :btrqImm8Reg /unboxedIntegerCase :jcLbl8 7 /rax /sil :movbMemDisp8Reg %F0 /sil :andbImmReg /integerCase :jzLbl8 %90 /sil :cmpbImmReg /scopeCase :jzLbl8 "invalid type while evaluating ?" ::outputError :ud2 @integerCase 8 /rax /rax :movqMemDisp8Reg @unboxedIntegerCase /rax /rax :testqRegReg /rcx /rdx :cmovzqRegReg /rdx :pushqReg /rbx :pushqReg :retn @scopeCase /rdx :pushqReg /rcx :pushqReg /rax :pushqReg /rax :movqImmOOBReg "#?" ::string /rax :pushqReg /rax :movqImmOOBReg "ey?" "ey." ::linkAbs64 /rbx :pushqReg /rax :jmpqReg ]] /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 8 /r15 :subqImm8Reg /r15 :popqMem # 8 /r15 now points to activation # /r15 now points to key to define ASSERTIONS { /rax :popqReg /rax :pushqReg /rax /rax :testqRegReg /realObject :jnzLbl8 "trying to store zero object address" ::outputError :ud2 @realObject /r15 /rax :movqMemReg 7 /rax /al :movbMemDisp8Reg %f0 /al :andbImmReg %10 /al :cmpbImmReg /keyIsString :jzLbl8 "tried to def to non-string key" ::outputError :ud2 @keyIsString } rep # search for name in nametable /r14 /rbx :movqRegReg # rbx == start of scope in heap 8 /rbx /rsi :movqMemDisp8Reg # rsi == start of nametable in heap /rsi /rsi :testqRegReg /nameTableExists :jnzLbl32 ::INITIALNAMETABLESIZE /rdi :movqImmReg ::internalAllocateNametable /rax :movqImmReg /rax :callqReg # rax == nametable /rax 8 /rbx :movqRegMemDisp8 # save new nametable /rax /rsi :movqRegReg @nameTableExists /r15 /rdi :movqMemReg # rdi == string to insert # rsi == nametable on heap ::internalInsertToNametable /rax :movqImmReg /rax :callqReg # rax == start of 16 byte slot (or zero if no slot was found) /rax /rax :testqRegReg /slotFound :jnzLbl8 8 /rbx /rdi :movqMemDisp8Reg # rdi == start of nametable in heap /rdi /esi :movlMemReg 3 /rsi :shrqImm8Reg ::internalGrowNametable /rax :movqImmReg /rax :callqReg # rax == new, larger nametable /rax 8 /rbx :movqRegMemDisp8 # store new nametable in scope /rax /rsi :movqRegReg /nameTableExists :jmpLbl8 @slotFound # rax == address of 16 byte slot in nametable /rdx /rdx :testqRegReg /nameExists :jnzLbl8 8 /r15 /esi :movlMemDisp8Reg /esi 8 /rax :movlRegMemDisp8 # store execution mode 8 /rbx /rdi :movqMemDisp8Reg # rdi == start of nametable in heap 8 /rdi /esi :movlMemDisp8Reg /esi 12 /rax :movlRegMemDisp8 # store scope index # FIXME measure performance and consider orq-ing the two fields by hand 1 8 /rdi :addqImm8MemDisp8 # increment number of assigned slots /rsi /rdx :movqRegReg /nameInserted :jmpLbl8 @nameExists 12 /rax /edx :movlMemDisp8Reg # load slot index from hash @nameInserted # rdx == slot index 3 /rdx :shlqImm8Reg # multiply by 8 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 8 mul 8 add /rdi :movqImmReg ::internalAllocateAndZero /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 ::internalAllocateAndZero /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 16 /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 /r14 /rdi :movqRegReg /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 /rbx :pushqReg /r14 :pushqReg /rax :movqImmOOBReg "#.=" ::string /rax :pushqReg /rax :movqImmOOBReg "ey=" "ey." ::linkAbs64 /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :jmpqReg @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 63 /rdx :btrqImm8Reg /unexecutable :jcLbl8 7 /rdx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %50 /cl :cmpbImmReg /normalFunction :jeLbl8 %10 /cl :cmpbImmReg /stringFunction :jeLbl32 %70 /cl :cmpbImmReg /arrayFunction :jeLbl32 %C0 /cl :cmpbImmReg /coroutineFunction :jeLbl32 %90 /cl :cmpbImmReg /scopeFunction :jeLbl32 @unexecutable /rdx :pushqReg :ERRORMARKER /rax :movqImmReg /rax :pushqReg "not an executable thing" ::outputError :ud2 @normalFunction # load scope 8 /rdx /rcx :movqMemDisp8Reg /rcx /rcx :testqRegReg /unscoped :jzLbl8 # save current scope 8 /r15 :subqImm8Reg /r14 /r15 :movqRegMem # enter scope /rcx /r14 :movqRegReg # handle typed function 16 /rdx /rcx :movqMemDisp8Reg /rcx /rcx :testqRegReg /untyped :jzLbl8 /typed :jmpLbl32 @untyped 24 /rdx /rax :movqMemDisp8Reg 16 /rax :addqImm8Reg /rax :callqReg /r15 /r14 :movqMemReg 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 16 /rax :addqImm8Reg /rax :callqReg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @typedUnscoped # save current scope 8 /r15 :subqImm8Reg /r14 /r15 :movqRegMem /typed :jmpLbl32 @arrayFunction # rdx == array on heap /rbx :popqReg 63 /rbx :btrqImm8Reg /arrayIntArgumentUnboxed :jcLbl32 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %00 /cl :cmpbImmReg /arrayIntArgumentBoxed :jeLbl8 %01 /cl :cmpbImmReg /arrayWrongScalarArgumentBoxed :jeLbl8 %02 /cl :cmpbImmReg /arrayWrongScalarArgumentBoxed :jeLbl8 # escape this to compiled high-level code /rbx :pushqReg /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 :pushqMem 8 /r15 :addqImm8Reg :retn @arrayWrongScalarArgumentBoxed "trying to execute array on string or float" ::outputError :ud2 @arrayIntArgumentBoxed 8 /rbx /rax :movqMemDisp8Reg # rax == requested index /arrayIntArgumentLoaded :jmpLbl8 @arrayIntArgumentUnboxed /rbx /rax :movqRegReg # rax == requested value @arrayIntArgumentLoaded /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 :cqo /rcx :idivqReg 0 /rdx :cmpqImm8Reg /positiveArrayIndex :jgeLbl8 /rcx /rdx :addqRegReg @positiveArrayIndex # 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 /rbp /rbp :xorqRegReg /rbx /rsi :movqMemReg # rsi == address of abstract argument 63 /rsi :btrqImm8Reg /unboxedAbstract :jcLbl8 /rsi /rax :movqMemReg @unboxedAbstract /rbp /rax :cmovcqRegReg 60 /rax :shrqImm8Reg # al == type of abstract argument /rdi /rsi :movqMemReg # rsi == address of concrete argument 63 /rsi :btrqImm8Reg /unboxedConcrete :jcLbl8 /rsi /rsi :movqMemReg @unboxedConcrete /rbp /rsi :cmovcqRegReg 60 /rsi :shrqImm8Reg # sil = type of concrete argument %0C /sil :testbImmReg /typedNonCommon :jnzLbl8 # non-scalar concrete type %0C /al :testbImmReg /typedNonCommon :jnzLbl8 # non-scalar abstract type 8 /rdi :addqImm8Reg 8 /rbx :addqImm8Reg /typedCommonCheck :loopLbl8 24 /rdx /rax :movqMemDisp8Reg 16 /rax :addqImm8Reg /rax :callqReg /r15 /r14 :movqMemReg 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 /r14 :movqMemReg 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @stringFunction # rdx == string on heap /rbx :popqReg 63 /rbx :btrqImm8Reg /stringIntArgumentUnboxed :jcLbl8 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %00 /cl :cmpbImmReg /stringIntArgumentBoxed :jeLbl8 "FIXME: typed string application" ::outputError :ud2 @stringIntArgumentBoxed 8 /rbx /rax :movqMemDisp8Reg # rax == requested index /stringIntArgumentLoaded :jmpLbl8 @stringIntArgumentUnboxed /rbx /rax :movqRegReg @stringIntArgumentLoaded 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 :cqo /rcx :idivqReg 0 /rdx :cmpqImm8Reg /positiveStringIndex :jgeLbl8 /rcx /rdx :addqRegReg @positiveStringIndex # rsi == array object on heap # rdx == correct string index 24 1 /rdx /rsi /rbx :movzxMem8IndexScaleDisp8Reg64 # use some of the CISC goodness 63 /rbx :btsqImm8Reg /rbx :pushqReg # push unboxed integer /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @coroutineFunction /r15 /rbx :movqMemReg 8 /r15 :addqImm8Reg 0 24 /rdx :cmpqImm8MemDisp8 /targetCallStackExists :jnzLbl8 /rdx :pushqReg ::internalAllocateStack /rax :movqImmReg /rax :callqReg /rdx :popqReg /rax 24 /rdx :movqRegMemDisp8 @targetCallStackExists # save old state /rbx 8 /r13 :movqRegMemDisp8 /r14 16 /r13 :movqRegMemDisp8 24 /r13 /rax :movqMemDisp8Reg /r15 8 /rax :movqRegMemDisp8 32 /r13 /rax :movqMemDisp8Reg /rax /rax :testqRegReg /sourceDataStackMissing :jzLbl8 /rsp 8 /rax :movqRegMemDisp8 @sourceDataStackMissing # exclude source opcodes from being optimized away /rdx :pushqReg /rbx /rdi :movqRegReg ::internalObjectStart /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /nonHeapCoroutine :jzLbl8 58 /rax :btsqImm8Mem @nonHeapCoroutine /rdx :popqReg # load new state 8 /rdx /rbx :movqMemDisp8Reg 16 /rdx /r14 :movqMemDisp8Reg 24 /rdx /rax :movqMemDisp8Reg 8 /rax /r15 :movqMemDisp8Reg /r13 :pushqReg # push caller to target stack /rdx /r13 :movqRegReg /rbx :pushqReg :retn @scopeFunction /rdx :pushqReg /rax :movqImmOOBReg "#*" ::string /rax :pushqReg /rax :movqImmOOBReg "ey*" "ey." ::linkAbs64 /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :jmpqReg ]] /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 /empty :jzLbl8 /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 8 /rcx /rax /rax :leaqMemIndexScaleReg # rax == address of last cell @copy /rax :popqMem 8 /rax :subqImm8Reg /copy :loopLbl8 /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @empty emptyArray /rax :movqImmReg /rax /rcx :movqRegMem # store array pointer instead of begin marker /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 %90 /cl :cmpbImmReg /scopeAssign :jeLbl32 "non-array, non-string passed to =[]" ::outputError :ud2 @arrayAssign /rax :popqReg /rax ::unboxInteger /rbx /ecx :movlMemReg # load array length 3 /rcx :shrqImm8Reg # divide by object pointer size /rcx :decqReg # rcx == number of elements in array # TODO: think about skipping this if index fits :cqo /rcx :idivqReg 0 /rdx :cmpqImm8Reg /positiveArrayIndex :jgeLbl8 /rcx /rdx :addqRegReg @positiveArrayIndex # 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 /rax ::unboxInteger 16 /rbx /rcx :movqMemDisp8Reg # load string length :cqo /rcx :idivqReg 0 /rdx :cmpqImm8Reg /positiveStringIndex :jgeLbl8 /rcx /rdx :addqRegReg @positiveStringIndex # rbx == string object on heap # rdx == correct string offset /rax :popqReg /rax ::unboxInteger /al 24 1 /rdx /rbx :movbRegMemIndexScaleDisp8 /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @scopeAssign /rbx :pushqReg /rax :movqImmOOBReg "#=[]" ::string /rax :pushqReg /rax :movqImmOOBReg "ey=[]" "ey." ::linkAbs64 /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :jmpqReg ]] /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 %90 /cl :cmpbImmReg /scopeLen :jeLbl32 "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 63 /rbx :btsqImm8Reg /rbx :pushqReg # store unboxed integer # TODO can larger arrays/strings ever exist? /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @scopeLen /rax :pushqReg /rax :movqImmOOBReg "#len" ::string /rax :pushqReg /rax :movqImmOOBReg "eylen" "ey." ::linkAbs64 /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :jmpqReg ]] /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 /stringCat :jeLbl32 %90 /cl :cmpbImmReg /scopeCat :jeLbl32 "neither string nor array in cat" ::outputError :ud2 @arrayCat /rbx :popqReg 7 /rbx /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %90 /cl :cmpbImmReg /scopeReverseCat :jeLbl32 %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 %90 /cl :cmpbImmReg /scopeReverseCat :jeLbl32 %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 @scopeCat /rax :pushqReg /rax :movqImmOOBReg "#cat" ::string /rax :pushqReg /rax :movqImmOOBReg "eycat" "ey." ::linkAbs64 /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :jmpqReg @scopeReverseCat /rax :pushqReg /rbx :pushqReg /rax :movqImmOOBReg "#-01 cat" ::string /rax :pushqReg /rax :movqImmOOBReg "eycat" "ey." ::linkAbs64 /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :jmpqReg ]] /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 /rcx ::unboxInteger /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 /rdi ::unboxInteger /r15 /rbx :movqMemReg /rbx ::unboxInteger /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 /rax ::unboxInteger # largest element + 1 @fill /rax /rbx :cmpqRegReg /done :jaeLbl8 /rbx /rcx :movqRegReg 32 /rcx :shrqImm8Reg /largeElement :jnzLbl8 /rbx /rcx :movqRegReg 63 /rcx :btsqImm8Reg /rcx /rdi :movqRegMem # store into array /rbx :incqReg 8 /rdi :addqImm8Reg /fill :jmpLbl8 @largeElement /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 # put a position marker onto the stack [[ /rax :popqReg POSITIONMARKER :pushqImm32 /rax :pushqReg :retn ]] /ey, defv # delete topmost position marker and shift stack [[ /rbx :popqReg /rsp /rsi :movqRegReg POSITIONMARKER /rax :movqImmReg /rdx :popqReg /rax /rdx :cmpqRegReg /done :jzLbl8 @loop 8 /rsi :addqImm8Reg /rdx /rsi :xchgqRegMem /rax /rdx :cmpqRegReg /loop :jnzLbl8 @done /rbx :pushqReg :retn ]] /ey,-- defv # move topmost position marker left/downwards and shift stack [[ /rbx :popqReg /rsp /rsi :movqRegReg POSITIONMARKER /rax :movqImmReg /rdx :popqReg /rax /rdx :cmpqRegReg /done :jzLbl8 @loop 8 /rsi :addqImm8Reg /rdx /rsi :xchgqRegMem /rax /rdx :cmpqRegReg /loop :jnzLbl8 @done /rdx 8 /rsi :movqRegMemDisp8 /rbx :pushqReg :retn ]] /ey--, defv # access element left (below in stack) of topmost position marker [[ /rbx :popqReg /rsp /rdi :movqRegReg POSITIONMARKER /rax :movqImmReg /rcx /rcx :xorqRegReg /rcx :decqReg :repnz :scasq /rdi :pushqMem /rbx :pushqReg :retn ]] /ey_, defv # access element right (above in stack) of topmost position marker [[ /rbx :popqReg /rsp /rdi :movqRegReg POSITIONMARKER /rax :movqImmReg /rcx /rcx :xorqRegReg /rcx :decqReg :repnz :scasq 16 neg /rdi :pushqMemDisp8 /rbx :pushqReg :retn ]] /ey,_ defv # delete stack up to and including topmost position marker [[ /rbx :popqReg POSITIONMARKER /rax :movqImmReg @loop /rdx :popqReg /rax /rdx :cmpqRegReg /loop :jnzLbl8 /rbx :pushqReg :retn ]] /ey,--- defv # create a new scope capturing the current one [ ::INITIALSCOPESIZE /rdi :movqImmReg /r14 /rsi :movqRegReg ::internalAllocateScope /rax :movqImmReg /rax :callqReg /rax /r14 :movqRegReg # switch to new scope :retn ] /ey< defv # push current scope onto stack # switch current scope to its parent # 0 <- scope just exited [ /rbx :popqReg /r14 :pushqReg 16 /r14 /r14 :movqMemDisp8Reg /rbx :pushqReg :retn ] /ey> defv # switch parent of current scope to stack top object # push current scope onto stack # switch current scope to original parent # 0 -> new parent # 0 <- scope just exited [ /rbx :popqReg /rdx :popqReg 16 /r14 /rax :movqMemDisp8Reg /rdx 16 /r14 :movqRegMemDisp8 /r14 :pushqReg /rax /r14 :movqRegReg /rbx :pushqReg :retn ] /ey>' defv # push current scope onto stack # 0 <- current scope [ /rbx :popqReg /r14 :pushqReg /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 ::currentQuoted /rcx :movqImmReg /rcx /rcx :movqMemReg 63 /rcx :btsqImm8Reg /rcx :pushqReg /rbx :pushqReg :retn ]] /eyquoted defv > _ ==globalFunctions { 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 /r14 /rdi :movqRegReg /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 3 /cl :cmpbImmReg /member :jzLbl8 "invalid activation mode in internalExecuteIdentifierUnquoted" ::outputError :ud2 @unresolved /r15 :pushqMem # push member /r14 :pushqReg # push scope /rax :movqImmOOBReg "#." ::string /rax :pushqReg /rax :movqImmOOBReg "internalExecuteIdentifierUnquoted" "ey." ::linkAbs64 8 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :jmpqReg @member /rax :popqReg /r14 :pushqReg /rax :pushqReg @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 /r14 /rdi :movqRegReg /r15 /rsi :movqMemReg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /unresolved :jzLbl8 /rax :pushqReg %40 /dl :testbImmReg /patchConstant :jnzLbl8 %30 /dl :testbImmReg # FIXME separate cases for static and typed /patchStatic :jnzLbl32 /rdx /rcx :movqRegReg %0F /cl :andbImmReg 0 /cl :cmpbImmReg /inactive :jzLbl8 1 /cl :cmpbImmReg /active :jzLbl8 2 /cl :cmpbImmReg /active :jzLbl8 3 /cl :cmpbImmReg /member :jzLbl8 "invalid activation mode in internalExecuteIdentifierUnquotedAndPatchLateResolve" ::outputError :ud2 @unresolved /r15 :pushqMem # push member /r14 :pushqReg # push scope /rax :movqImmOOBReg "#." ::string /rax :pushqReg /rax :movqImmOOBReg "internalExecuteIdentifierUnquotedAndPatchLateResolve" "ey." ::linkAbs64 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :jmpqReg @member # TODO patch late resolve call away /rax :popqReg /r14 :pushqReg /rax :pushqReg @active # TODO patch late resolve call away |ey* /rax :movqImmReg /rax :callqReg @inactive # TODO patch late resolve call away @done 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @patchConstant %0F /dl :andbImmReg /patchConstantPassive :jzLbl32 %01 /dl :cmpbImmReg /patchConstantActive :jzLbl32 %02 /dl :cmpbImmReg /patchConstantQuoted :jzLbl8 %03 /dl :cmpbImmReg /member :jzLbl8 # TODO: patch this as well "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 /rbp :movqMemDisp8Reg 16 1 /rbp /rdi /rbp :leaqMemIndexScaleDisp8Reg 16 /rdi :addqImm8Reg [ /rbx :popqReg /rax :movqImmOOBReg ] ::loadToRdi /rdx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rax :pushqReg /rbx :pushqReg |ey* /rax :movqImmReg /rax :jmpqReg ] ::loadToRdi /rdx 0 /rbp :movqRegMemDisp8 # save reference for the GC 8 /r15 /rdi :movqMemDisp8Reg 16 /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 /rbp :movqMemDisp8Reg 16 1 /rbp /rdi /rbp :leaqMemIndexScaleDisp8Reg 16 /rdi :addqImm8Reg 8 /rdx /rcx :movqMemDisp8Reg # load function scope 24 /rdx /rbx :movqMemDisp8Reg # load actual function code 16 /rbx :addqImm8Reg [ 16 /r15 :subqImm8Reg 8 /r15 :popqMemDisp8 /r14 /r15 :movqRegMem /r14 :movqImmOOBReg ] ::loadToRdi /rcx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rax :movqImmOOBReg ] ::loadToRdi /rbx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rax :callqReg /r15 /r14 :movqMemReg 8 /r15 :pushqMemDisp8 16 /r15 :addqImm8Reg :retn ] ::loadToRdi /rcx 0 /rbp :movqRegMemDisp8 # save scope reference 16 /rbx :subqImm8Reg /rbx 8 /rbp :movqRegMemDisp8 # ... and code reference (in case the function object is ever updated) 8 /r15 /rdi :movqMemDisp8Reg 16 /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 /rbp :movqMemDisp8Reg 16 1 /rbp /rdi /rbp :leaqMemIndexScaleDisp8Reg 16 /rdi :addqImm8Reg 24 /rdx /rdx :movqMemDisp8Reg # load actual function code 16 /rdx /rcx :leaqMemDisp8Reg # correct for header [ /rax :movqImmOOBReg ] ::loadToRdi /rcx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rax :jmpqReg ] ::loadToRdi 16 /rcx :subqImm8Reg /rcx 0 /rbp :movqRegMemDisp8 # save code address for the GC 8 /r15 /rdi :movqMemDisp8Reg 16 /rdi :addqImm8Reg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rdi :jmpqReg # continue with freshly patched code @patchConstantPassive 8 /r15 /rdi :movqMemDisp8Reg 8 /rdi /rbp :movqMemDisp8Reg 16 1 /rbp /rdi /rbp :leaqMemIndexScaleDisp8Reg 16 /rdi :addqImm8Reg [ /rbx :popqReg /rax :movqImmOOBReg ] ::loadToRdi /rdx :popqReg /rdx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rax :pushqReg /rbx :jmpqReg ] ::loadToRdi /rdx 0 /rbp :movqRegMemDisp8 # save constant address for the GC 8 /r15 /rdi :movqMemDisp8Reg 16 /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 :andbImmReg /patchStaticPassive :jzLbl32 %01 /dl :cmpbImmReg /patchStaticActive :jzLbl32 %02 /dl :cmpbImmReg /patchStaticQuoted :jzLbl8 %03 /dl :cmpbImmReg /member :jzLbl32 # TODO: patch this as well "invalid activation mode in internalExecuteIdentifierUnquotedAndPatchLateResolve@patchStatic" ::outputError :ud2 @patchStaticQuoted "quote activation mode in internalExecuteIdentifierUnquotedAndPatchLateResolve@patchStatic" ::outputError :ud2 @patchStaticPassive 0 /rax :movqImmReg /rax :pushqReg /patchStaticImplementation :jmpLbl8 @patchStaticActive 1 /rax :movqImmReg /rax :pushqReg @patchStaticImplementation /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 /patchStaticParentCountWithinLimits :jbeLbl8 "parent count out of save limits in internalExecuteIdentifierUnquotedAndPatchLateResolve" ::outputError :ud2 @patchStaticParentCountWithinLimits 8 /r15 /rdi :movqMemDisp8Reg # replace string reference with example object (for later optimizer inspection) 8 /rdi /rdx :movqMemDisp8Reg 16 1 /rdx /rdi /rdx :leaqMemIndexScaleDisp8Reg /rdi /eax :movlMemReg /rdi /rax :addqRegReg /rdx /rax :cmpqRegReg /patchStaticParentCountWithinLimitsSpaceExists :jaLbl8 "no space available for example object" ::outputError :ud2 @patchStaticParentCountWithinLimitsSpaceExists 0 /rdx :andqImm8Mem # reset example object pointer 16 /rdi :addqImm8Reg [ /r14 /rax :movqRegReg ] ::loadToRdi /rcx /rcx :testqRegReg /patchStaticNoFollowParents :jzLbl8 @patchStaticFollowParents [ 16 /rax /rax :movqMemDisp8Reg ] ::loadToRdi /patchStaticFollowParents :loopLbl8 @patchStaticNoFollowParents /rbp /rbp :testqRegReg /patchStaticLoadFromExtensionArea :jnzLbl8 # @patchStaticLoadFromScope 32 /rsi :addqImm8Reg # now: rsi == offset of entry in scope [ /rbx :popqReg %EE /rax /rax :movqMemDisp32Reg ] ::loadToRdi /esi 4 neg /rdi :movlRegMemDisp8 # patch offset /patchStaticLoadTail :jmpLbl8 @patchStaticLoadFromExtensionArea 40 /rsi :addqImm8Reg # now: rsi == offset of entry in extension area + scope length [ 24 /rax /rcx :movqMemDisp8Reg # load extension area pointer /rbx :popqReg %EE /rcx /rax :movqMemDisp32Reg # load entry ] ::loadToRdi /rbp /rsi :subqRegReg # substract scope object length /esi 4 neg /rdi :movlRegMemDisp8 # patch offset @patchStaticLoadTail [ /rax :pushqReg /rcx :movqImmOOBReg ] ::loadToRdi /rdx /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rax /rcx :movqRegMem ] ::loadToRdi /rax :popqReg /rax /rax :testqRegReg /patchStaticLoadActive :jnzLbl8 # @patchStaticLoadPassive [ /rbx :jmpqReg ] ::loadToRdi /patchStaticLoadTail2 :jmpLbl8 @patchStaticLoadActive [ /rbx :pushqReg |ey* /rax :movqImmReg /rax :jmpqReg ] ::loadToRdi @patchStaticLoadTail2 8 /r15 /rdi :movqMemDisp8Reg 16 /rdi :addqImm8Reg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rdi :jmpqReg # continue with freshly patched code ]] /internalExecuteIdentifierUnquotedAndPatchLateResolve defv # call function optimize hook on code block # 0 -> address of code block [[ 8 /r15 :subqImm8Reg /r15 :popqMem /rax :popqReg 58 /rax :btsqImm8Mem /alreadyOptimized :jcLbl8 /rax :pushqReg /r14 :pushqReg /rax :pushqReg /rax :movqImmOOBReg "sys" ::string /rax :pushqReg /rax :movqImmOOBReg "internalCallOptimizeHook" "ey|" ::linkAbs64 /rax :callqReg /rax :movqImmOOBReg "opt" ::string /rax :pushqReg /rax :movqImmOOBReg "internalCallOptimizeHook" "ey." ::linkAbs64 /rax :callqReg /rax :movqImmOOBReg "hook" ::string /rax :pushqReg /rax :movqImmOOBReg "internalCallOptimizeHook" "ey." ::linkAbs64 /rax :callqReg /rcx :popqReg # result object (not necessarily new code object though) /rax :popqReg # pop returned scope object /rax :popqReg # old object /rax /rcx :cmpqRegReg /optimizationHappened :jnzLbl8 58 /rax :btrqImm8Mem # reset optimized bit @optimizationHappened @alreadyOptimized /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /internalCallOptimizeHook 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 /r14 /rdi :movqRegReg /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 :jzLbl32 2 /cl :cmpbImmReg /quoteActive :jzLbl8 3 /cl :cmpbImmReg /member :jzLbl8 "invalid activation mode in internalExecuteIdentifier" ::outputError :ud2 @unresolved ::currentQuoted /rax :movqImmReg /rax /rax :movqMemReg /rax /rax :testqRegReg /constructQuotedResolve :jnzLbl32 "unresolved name in internalExecuteIdentifier: " ::outputError /r15 /rdi :movqMemReg ::internalDumpErrorString /rax :movqImmReg /rax :callqReg :ud2 @quoteActive /rax :pushqReg |ey* /rax :movqImmReg /rax :callqReg /done :jmpLbl8 @member ::currentQuoted /rbx :movqImmReg /rbx /rbx :movqMemReg /rbx /rbx :testqRegReg /constructQuotedResolve :jnzLbl32 /r14 :pushqReg /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 :quoteEncodingBufferCode /rdi :movqImmReg :quoteEncodingBufferObjects /rbp :movqImmReg ::unscopingFunctionHeader ::loadToRdi # push identifier [ /rax :movqImmOOBReg ] ::loadToRdi /r15 /rsi :movqMemReg /rsi /rdi :movqRegMem /rsi 0 /rbp :movqRegMemDisp8 8 /rdi :addqImm8Reg 16 /rbp :addqImm8Reg # we only save 1 reference here, but some cases need 2 after patching 0 8 neg /rbp :andqImm8MemDisp8 [ /rax :pushqReg 0 :callqRel32 /rax :popqReg # 16 bytes code here, header length, and code block header 16 ::unscopingFunctionHeader len add 16 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 ::internalAllocateCodeFromEncodingBuffer /rax :movqImmReg /rax :callqReg # 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 [ ] ==eydefqImpl < # 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 activation /rdx :movqImmReg 63 /rdx :btsqImm8Reg /rdx :pushqReg eydef /rax :movqImmReg /rax :callqReg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] } %00 -101* /eydefv defv %01 -101* /eydeff defv %02 -101* =eydefqImpl %03 -101* /eydefm defv %10 -101* /eydefvs defv %11 -101* /eydeffs defv %13 -101* /eydefms defv %20 -101* /eydefvt defv %21 -101* /eydefft defv %23 -101* /eydefmt defv %30 -101* /eydefvst defv %31 -101* /eydeffst defv %33 -101* /eydefmst defv %40 -101* /eydefvc defv %41 -101* /eydeffc defv %43 -101* /eydefmc defv %C0 -101* /eydefvd defv %C1 -101* /eydeffd defv %C3 -101* /eydefmd defv -- # retype a function # 0 -> function output arguments as array # 1 -> function input arguments as array # 2 -> function object # 0 <- function object with new types [[ 24 /r15 :subqImm8Reg 16 /r15 :popqMemDisp8 # return address 8 /r15 :popqMemDisp8 # output arguments /r15 :popqMem # input arguments ASSERTIONS { /r15 /rax :movqMemReg 7 /rax /al :movbMemDisp8Reg %f0 /al :andbImmReg %70 /al :cmpbImmReg /inputIsArray :jzLbl8 "tried to '' for non-array input arguments" ::outputError :ud2 @inputIsArray 8 /r15 /rax :movqMemDisp8Reg 7 /rax /al :movbMemDisp8Reg %f0 /al :andbImmReg %70 /al :cmpbImmReg /outputIsArray :jzLbl8 "tried to '' for non-array output arguments" ::outputError :ud2 @outputIsArray } rep /r15 /rdx :movqMemReg /rdx /edi :movlMemReg 8 /r15 /rdx :movqMemDisp8Reg /rdx /edi :addlMemReg # rdi now input + output array lengths + 16 8 /rdi :addqImm8Reg # rdi now length of function type object ::internalAllocate /rax :movqImmReg /rax :callqReg %80 7 /rax :orbImmMemDisp8 # set type 8 /rax /rdi :leaqMemDisp8Reg /rax /rbp :movqRegReg # store type object away for later use /r15 /rdx :movqMemReg /rdx /eax :movlMemReg 3 /rax :shrqImm8Reg /rax :decqReg /rax /rcx :movqRegReg :stosq # store input argument count 8 /rdx /rsi :leaqMemDisp8Reg :reprcx :movsq # store input argument types 8 /r15 /rdx :movqMemDisp8Reg /rdx /eax :movlMemReg 3 /rax :shrqImm8Reg /rax :decqReg /rax /rcx :movqRegReg :stosq # store output argument count 8 /rdx /rsi :leaqMemDisp8Reg :reprcx :movsq # store output argument types /rax :popqReg # original function object 8 /rax /rsi :movqMemDisp8Reg # scope pointer as before 24 /rax /rdi :movqMemDisp8Reg # code pointer as before /rbp /rdx :movqRegReg # type pointer to new type object ::internalAllocateFunction /rax :movqImmReg /rax :callqReg /rax :pushqReg 16 /r15 :pushqMemDisp8 24 /r15 :addqImm8Reg :retn ]] /ey'' defv # concatenate two functions # 0 -> function g # 1 -> function f # 0 <- (f g) [[ 8 /r15 :subqImm8Reg /r15 :popqMem # construct non-capturing function :quoteEncodingBufferCode /rdi :movqImmReg :quoteEncodingBufferObjects /rbp :movqImmReg ::unscopingFunctionHeader ::loadToRdi /rcx :popqReg /rdx :popqReg # push function f [ /rax :movqImmOOBReg ] _ len 2 neq { "unexpected opcode length" die } rep 2 dearray 256 mul add /rdi :movwImmMem /rdx 2 /rdi :movqRegMemDisp8 /rdx 0 /rbp :movqRegMemDisp8 10 /rdi :addqImm8Reg 8 /rbp :addqImm8Reg [ /rax :pushqReg |ey* /rax :movqImmReg /rax :callqReg /rax :movqImmOOBReg ] ::loadToRdi # push function g /rcx /rdi :movqRegMem /rcx 0 /rbp :movqRegMemDisp8 8 /rdi :addqImm8Reg 8 /rbp :addqImm8Reg [ /rax :pushqReg |ey* /rax :movqImmReg /rax :callqReg ] ::unscopingFunctionFooter cat ::loadToRdi ::internalAllocateCodeFromEncodingBuffer /rax :movqImmReg /rax :callqReg # 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 an integer index into the stack, # starting with 0 at the one below this index # duplicates the indicated stack element to the top [[ /rbx :popqReg /rdx :popqReg 63 /rdx :btrqImm8Reg /unboxed :jcLbl8 8 /rdx /rdx :movqMemDisp8Reg @unboxed 8 /rdx /rsp /rdx :movqMemIndexScaleReg /rdx :pushqReg /rbx :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 /rcx ::unboxInteger /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 # check loop parts for being functions /r15 /rsi :movqMemReg 7 /rsi /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %50 /cl :cmpbImmReg /loop :jnzLbl8 8 /r15 /rdi :movqMemDisp8Reg 7 /rdi /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %50 /cl :cmpbImmReg /loop :jnzLbl8 /functionLoop :jmpLbl8 @loop /r15 :pushqMem |ey* /rax :movqImmReg /rax :callqReg /rax :popqReg /rax ::unboxInteger /rax /rax :testqRegReg /end :jzLbl8 8 /r15 :pushqMemDisp8 |ey* /rax :movqImmReg /rax :callqReg /loop :jmpLbl8 @end 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @functionLoop # check loop parts for being non-typed 16 /rsi /rax :movqMemDisp8Reg 16 /rdi /rax :orqMemDisp8Reg /nonTypedLoop :jzLbl8 /loop :jmpLbl8 # TODO: maybe put a faster version here one day @nonTypedLoop # check loop parts for being non-capturing 8 /rsi /rax :movqMemDisp8Reg 8 /rdi /rax :orqMemDisp8Reg /nonCapturingLoopEntry :jzLbl8 /loop :jmpLbl8 # TODO: here should follow a significantly faster version already @nonCapturingLoopEntry 24 /rsi /rsi :movqMemDisp8Reg 24 /rdi /rdi :movqMemDisp8Reg 16 /rsi :addqImm8Reg 16 /rdi :addqImm8Reg /rsi /r15 :movqRegMem /rdi 8 /r15 :movqRegMemDisp8 @nonCapturingLoop /r15 /rax :movqMemReg /rax :callqReg /rax :popqReg /rax ::unboxInteger /rax /rax :testqRegReg /end :jzLbl8 8 /r15 /rax :movqMemDisp8Reg /rax :callqReg /nonCapturingLoop :jmpLbl8 ]] /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 %90 /cl :cmpbImmReg /eachScope :jzLbl32 "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 /rcx :testqRegReg /end :jzLbl8 /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 /r15 /rdx :movqMemReg /rdx /rdx :movzxMem8Reg64 63 /rdx :btsqImm8Reg /rdx :pushqReg 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 @eachScope 16 /r15 :pushqMemDisp8 /rax :pushqReg /rax :movqImmOOBReg "#each" ::string /rax :pushqReg /rax :movqImmOOBReg "eyeach" "ey." ::linkAbs64 32 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :jmpqReg ]] /eyeach defv # explicitely resolve a scope member # 0 -> member name # 1 -> scope [[ 8 /r15 :subqImm8Reg /r15 :popqMem @restart 16 /r15 :subqImm8Reg 8 /r15 :popqMemDisp8 # store identifier /r15 :popqMem # store scope /r15 /rdi :movqMemReg 8 /r15 /rsi :movqMemDisp8Reg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /unresolved :jzLbl8 /rax :pushqReg %0F /dl :andbImmReg /inactive :jzLbl8 %01 /dl :cmpbImmReg /active :jzLbl8 %03 /dl :cmpbImmReg /member :jzLbl8 "invalid activation mode in ." ::outputError :ud2 @member /rax :popqReg /r15 :pushqMem /rax :pushqReg @active |ey* /rax :movqImmReg /rax :callqReg @inactive @done 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @unresolved 8 /r15 :pushqMemDisp8 /r15 :pushqMem 16 /r15 :addqImm8Reg /rax :movqImmOOBReg "#." ::string /rax :pushqReg /restart :jmpLbl8 ]] /ey. defv # explicitely resolve a scope member, but never execute # 0 -> member name # 1 -> scope [[ 8 /r15 :subqImm8Reg /r15 :popqMem 16 /r15 :subqImm8Reg 8 /r15 :popqMemDisp8 # store identifier /r15 :popqMem # store scope /r15 /rdi :movqMemReg 8 /r15 /rsi :movqMemDisp8Reg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /unresolved :jzLbl8 /rax :pushqReg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @unresolved 8 /r15 :pushqMemDisp8 /r15 :pushqMem 16 /r15 :addqImm8Reg /rax :movqImmOOBReg "#.|" ::string /rax :pushqReg /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :movqImmOOBReg "ey.|" "ey." ::linkAbs64 /rax :jmpqReg ]] /ey.| defv # test whether a scope member exists # 0 -> member name # 1 -> scope # 0 <- 1 if scope member exists, 0 otherwise [[ 8 /r15 :subqImm8Reg /r15 :popqMem 16 /r15 :subqImm8Reg 8 /r15 :popqMemDisp8 # store identifier /r15 :popqMem # store scope /r15 /rdi :movqMemReg 8 /r15 /rsi :movqMemDisp8Reg ::internalResolve /rax :movqImmReg /rax :callqReg /rax /rax :testqRegReg /unresolved :jzLbl8 1 /rax :movqImmReg 63 /rax :btsqImm8Reg /rax :pushqReg 16 /r15 :addqImm8Reg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @unresolved 8 /r15 :pushqMemDisp8 /r15 :pushqMem 16 /r15 :addqImm8Reg /rax :movqImmOOBReg "#.?" ::string /rax :pushqReg /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :movqImmOOBReg "ey.?" "ey." ::linkAbs64 /rax :jmpqReg ]] /ey.? defv # test whether a scope member exists without following parent pointers or dynamic lookup # 0 -> member name # 1 -> scope # 0 <- 1 if scope member exists directly in scope, 0 otherwise [[ 8 /r15 :subqImm8Reg /r15 :popqMem /rsi :popqReg # fetch identifier /rdi :popqReg # fetch scope ::internalHasKeyShallow /rax :movqImmReg /rax :callqReg 63 /rax :btsqImm8Reg /rax :pushqReg /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ]] /ey.?' defv # enumerate scope keys # 0 -> scope # 0 <- array of keys [[ 8 /r15 :subqImm8Reg /r15 :popqMem /rax :popqReg 8 /rax /rax :movqMemDisp8Reg # rax == nametable /rax /rax :testqRegReg /emptyScope :jzLbl8 16 /rax /rsi :leaqMemDisp8Reg /rsi :pushqReg # save start of bucket array /rax /ecx :movlMemReg 16 /rcx :subqImm8Reg # substract header size 4 /rcx :shrqImm8Reg /rcx :pushqReg # save bucket count 8 /rax /rdi :movqMemDisp8Reg 3 /rdi :shlqImm8Reg ::internalAllocateArray /rax :movqImmReg /rax :callqReg 8 /rax /rdi :leaqMemDisp8Reg /rcx :popqReg /rsi :popqReg /rax :pushqReg # save array on stack as result /rcx /rcx :testqRegReg /empty :jzLbl8 @loop /rsi /rax :movqMemReg /rax /rax :testqRegReg /emptyBucket :jzLbl8 12 /rsi /edx :movlMemDisp8Reg # load entry index /rax 8 /rdx /rdi :movqRegMemIndexScale # put into array @emptyBucket 16 /rsi :addqImm8Reg /loop :loopLbl8 @empty /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @emptyScope /rdi /rdi :xorqRegReg ::internalAllocateArray /rax :movqImmReg /rax :callqReg /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 63 /rax :btqImm8Reg /unboxedIntegerPassed :jcLbl8 7 /rax /cl :movbMemDisp8Reg %F0 /cl :andbImmReg %10 /cl :cmpbImmReg /stringDom :jeLbl8 %70 /cl :cmpbImmReg /arrayDom :jeLbl8 %90 /cl :cmpbImmReg /scopeDom :jeLbl8 @unboxedIntegerPassed "non-array passed to dom" ::outputError :ud2 @stringDom 16 /rax /rdi :movqMemDisp8Reg # load length 3 /rdi :shlqImm8Reg # multiply to array cell size /populateDom :jmpLbl8 @arrayDom /rax /edi :movlMemReg 8 /rdi :subqImm8Reg # substract header length @populateDom ::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 /rbx /rax :movqRegReg # TODO can larger arrays ever exist? 63 /rax :btsqImm8Reg /rax 8 /rbx /rdi :movqRegMemIndexScale # store in array /rbx :incqReg /loop :jmpLbl8 @end /r15 :pushqMem 8 /r15 :addqImm8Reg :retn @scopeDom /rax :pushqReg /rax :movqImmOOBReg "#dom" ::string /rax :pushqReg |ey. /rax :movqImmReg /r15 :pushqMem 8 /r15 :addqImm8Reg /rax :jmpqReg ]] /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 %50 /cl :cmpbImmReg /functionCase :jzLbl32 %90 /cl :cmpbImmReg /scopeCase :jzLbl32 "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 /rax /rax :testqRegReg /sourceDataStackMissing :jzLbl8 /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 @functionCase /rcx :popqReg /rbp :pushqReg /rbx :pushqReg /rax :movqImmOOBReg "ey!" "ey*" ::linkAbs64 /rax :jmpqReg @scopeCase /rbp :pushqReg /rax :movqImmOOBReg "#!" ::string /rax :pushqReg /rbx :pushqReg /rax :movqImmOOBReg "ey!" "ey." ::linkAbs64 /rax :jmpqReg @sourceDataStackMissing "cannot leave coroutine with ! which was entered by * (missing own stack)" ::outputError :ud2 ]] /ey! defv > _ ==globalFunctions3 { defv }' ::allocateOffsetStruct [[ # the length of the following opcodes needs to fit with the :jmpRel8 below %48 16 /rdi :cmpbImmMemDisp8 /nonReplaced :jnzLbl8 %B8 17 /rdi :cmpbImmMemDisp8 /nonReplaced :jnzLbl8 %FF 26 /rdi :cmpbImmMemDisp8 /nonReplaced :jnzLbl8 %E0 27 /rdi :cmpbImmMemDisp8 /nonReplaced :jnzLbl8 18 /rdi /rdi :movqMemDisp8Reg # use jump target instead of jump pad in new function object 16 /rdi :subqImm8Reg /grabRip :callqLbl32 # TODO: use rip-relative addressing @grabRip /rax :popqReg /rdi 45 neg /rax :movqRegMemDisp8 # update the function code object we use [ 46 :jmpRel8 ] _ len 2 neq { "unexpected opcode length" die } rep 2 dearray 256 mul add 37 neg /rax :movwImmMemDisp8 # don't do rewrite tests next time @nonReplaced /r14 /rsi :movqRegReg /rdx /rdx :xorqRegReg ::internalAllocateFunction /rax :movqImmReg /rax :callqReg /rax :pushqReg ]] ==functionObjectWrapperCode # moved here so [[, ]] work correctly < # 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 :quoteEncodingBufferCode /rdi :movqImmReg :quoteEncodingBufferObjects /rbp :movqImmReg header ::loadToRdi @search 8 /rdx :subqImm8Reg /rdx /rcx :cmpqMemReg /markerFound :jeLbl32 /rdx /rsi :movqMemReg 63 /rsi :btqImm8Reg /immediateFound :jcLbl8 7 /rsi /al :movbMemDisp8Reg %F0 /al :andbImmReg /immediateFound :jzLbl8 %10 /al :cmpbImmReg /immediateFound :jzLbl8 %20 /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 neq { "unexpected opcode length" die } rep 2 dearray 256 mul add /rdi :movwImmMem /rsi 2 /rdi :movqRegMemDisp8 /rsi 0 /rbp :movqRegMemDisp8 [ /rax :pushqReg ] _ len 1 neq { "unexpected opcode length" die } rep 1 dearray 10 /rdi :movbImmMemDisp8 11 /rdi :addqImm8Reg 8 /rbp :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 neq { "unexpected opcode length" die } rep 2 dearray 256 mul add /rdi :movwImmMem /rax 0 /rbp :movqRegMemDisp8 # save code object pointer 16 /rax :addqImm8Reg # but add code offset, before encoding call /rax 2 /rdi :movqRegMemDisp8 10 /rdi :addqImm8Reg 8 /rbp :addqImm8Reg [ /rax :callqReg ] ::loadToRdi /search :jmpLbl32 @generalFunctionFound [ /rax :movqImmOOBReg ] _ len 2 neq { "unexpected opcode length" die } rep 2 dearray 256 mul add /rdi :movwImmMem /rsi 2 /rdi :movqRegMemDisp8 /rsi 0 /rbp :movqRegMemDisp8 [ /rax :pushqReg ] _ len 1 neq { "unexpected opcode length" die } rep 1 dearray 10 /rdi :movbImmMemDisp8 11 /rdi :addqImm8Reg 8 /rbp :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 :quoteEncodingBufferCode /rbx :movqImmReg /rdi /rax :movqRegReg 13 /rax :addqImm8Reg /rbx /rax :subqRegReg /rax /rdi :movqRegMem 8 /rdi :addqImm8Reg [ /rbx /rax :subqRegReg /rax :pushqReg optimizer /rax :movqImmReg /rax :callqReg ] ::loadToRdi footer ::loadToRdi ::internalAllocateCodeFromEncodingBuffer /rax :movqImmReg /rax :callqReg # rax == code block on heap ::currentQuoted /rcx :movqImmReg /rcx /rcx :movqMemReg /rcx /rcx :testqRegReg /quoted :jnzLbl8 # create function object /rax /rdi :movqRegReg capturing { /r14 /rsi :movqRegReg } { /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 capturing { # returns a function with the current scope captured :quoteEncodingBufferCode /rdi :movqImmReg :quoteEncodingBufferObjects /rbp :movqImmReg ::unscopingFunctionHeader ::loadToRdi # load inner code block [ /rdi :movqImmOOBReg ] _ len 2 neq { "unexpected opcode length" die } rep 2 dearray 256 mul add /rdi :movwImmMem /rax 2 /rdi :movqRegMemDisp8 /rax 0 /rbp :movqRegMemDisp8 10 /rdi :addqImm8Reg 8 /rbp :addqImm8Reg functionObjectWrapperCode ::unscopingFunctionFooter cat ::loadToRdi } { # create constant function from inner code block /rax /rdi :movqRegReg /rsi /rsi :xorqRegReg # non-capturing /rdx /rdx :xorqRegReg ::internalAllocateFunction /rax :movqImmReg /rax :callqReg :quoteEncodingBufferCode /rdi :movqImmReg :quoteEncodingBufferObjects /rbp :movqImmReg ::unscopingFunctionHeader ::loadToRdi # rax == function object [ /rax :movqImmOOBReg ] _ len 2 neq { "unexpected opcode length" die } rep 2 dearray 256 mul add /rdi :movwImmMem /rax 2 /rdi :movqRegMemDisp8 /rax 0 /rbp :movqRegMemDisp8 10 /rdi :addqImm8Reg 8 /rbp :addqImm8Reg [ /rax :pushqReg ] ::unscopingFunctionFooter cat ::loadToRdi } ? * ::internalAllocateCodeFromEncodingBuffer /rax :movqImmReg /rax :callqReg # 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 internalCallOptimizeHook -32104* /ey} defv _ 1 ::unscopingFunctionHeader ::unscopingFunctionFooter internalCallOptimizeHook -32104* /ey}' defv _ 0 ::unscopingFunctionHeader ::unscopingFunctionFooter internalCallOptimizeHook -32104* /ey}" defv -- eydefqImpl /eydefq defv > _ ==globalMacros { defv }' ::allocateOffsetStruct < [ %28 %00 %00 %00 %00 %00 %00 %80 %01 %00 %00 %00 %00 %00 %00 %00 %01 %00 %00 %00 %00 %00 %00 %80 # unboxed 1 %01 %00 %00 %00 %00 %00 %00 %00 %01 %00 %00 %00 %00 %00 %00 %80 # unboxed 1 ] /t1t1 defv [ %30 %00 %00 %00 %00 %00 %00 %80 %02 %00 %00 %00 %00 %00 %00 %00 %01 %00 %00 %00 %00 %00 %00 %80 # unboxed 1 %01 %00 %00 %00 %00 %00 %00 %80 # unboxed 1 %01 %00 %00 %00 %00 %00 %00 %00 %01 %00 %00 %00 %00 %00 %00 %80 # unboxed 1 ] /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 # %01 %00 %00 %00 %00 %00 %00 %80 # unboxed 1 # ] /taat1 defv > _ =globalTypes { defv }' ::allocateOffsetStruct # creates a function with the following effects # 0 -> integer or float or string # 1 -> integer or float or string # 0 <- result of the arithmetic operation or comparison { ==comparisonResult ==stringOpcodes ==floatOpcodes ==intOpcodes [[ /rbx :popqReg /rcx :popqReg /rdx :popqReg 63 /rcx :btqImm8Reg /rcxInteger :jcLbl8 7 /rcx /al :movbMemDisp8Reg %F0 /al :andbImmReg /rcxInteger :jzLbl8 %20 /al :cmpbImmReg /floatCase :jzLbl32 %10 /al :cmpbImmReg /stringCase :jzLbl32 # TODO: this should handle # on scopes "invalid operand types for arithmetic (1)" ::outputError :ud2 @rcxInteger 63 /rdx :btqImm8Reg /rdxInteger :jcLbl8 7 /rdx /al :movbMemDisp8Reg %F0 /al :andbImmReg /rdxInteger :jzLbl8 %20 /al :cmpbImmReg /floatCase :jzLbl32 # TODO: this should handle # on scopes "invalid operand types for arithmetic (2)" ::outputError :ud2 @rdxInteger @intCase # load arguments and test for boxed integers /rcx ::unboxInteger /rdx ::unboxInteger # actual calculation, result expected in rdx intOpcodes _ len dearray /rdx /rax :movqRegReg 32 /rax :shrqImm8Reg /boxResult :jnzLbl8 # push unboxed result 63 /rdx :btsqImm8Reg /rdx :pushqReg /rbx :pushqReg :retn @boxResult /rdx :pushqReg # allocate result ::internalAllocateInteger /rax :movqImmReg /rax :callqReg # save result into boxed int 8 /rax :popqMemDisp8 # push int address on program stack /rax :pushqReg /rbx :pushqReg :retn @floatCase 63 /rdx :btrqImm8Reg /loadFirstArgUnboxedInt :jcLbl8 7 /rdx /al :movbMemDisp8Reg %F0 /al :andbImmReg %20 /al :cmpbImmReg /loadFirstArgFloat :jzLbl8 # @loadFirstArgBoxedInt 8 /rdx :fildqMemDisp8 /loadedFirstArg :jmpLbl8 @loadFirstArgUnboxedInt /rdx :pushqReg 0 /rsp :fildqMemDisp8 /rdx :popqReg /loadedFirstArg :jmpLbl8 @loadFirstArgFloat 8 /rdx :fld64MemDisp8 @loadedFirstArg 63 /rcx :btrqImm8Reg /loadSecondArgUnboxedInt :jcLbl8 7 /rcx /al :movbMemDisp8Reg %F0 /al :andbImmReg %20 /al :cmpbImmReg /loadSecondArgFloat :jzLbl8 # @loadSecondArgBoxedInt 8 /rcx :fildqMemDisp8 /loadedSecondArg :jmpLbl8 @loadSecondArgUnboxedInt /rcx :pushqReg 0 /rsp :fildqMemDisp8 /rcx :popqReg /loadedSecondArg :jmpLbl8 @loadSecondArgFloat 8 /rcx :fld64MemDisp8 @loadedSecondArg floatOpcodes _ len dearray @produceResult comparisonResult { 63 /rdx :btsqImm8Reg /rdx :pushqReg } { ::internalAllocateFloat /rax :movqImmReg /rax :callqReg /rax :pushqReg 8 /rax :fstp64MemDisp8 } ? * /rbx :pushqReg :retn @stringCase 63 /rdx :btqImm8Reg /stringAndIntCase :jcLbl8 7 /rdx /al :movbMemDisp8Reg %F0 /al :andbImmReg %10 /al :cmpbImmReg /bothStringsCase :jzLbl8 @stringAndIntCase "invalid operand types for arithmetic (3)" ::outputError :ud2 @bothStringsCase stringOpcodes _ len dearray /produceResult :jmpLbl32 ]] } /makeFullScalar deff { ==comparisonResult # ==floatOpcodes ==intOpcodes [[ "arithmetic operation not defined on strings" ::outputError :ud2 ]] comparisonResult makeFullScalar } /makeFullArith deff { ==greater ==equal ==smaller [[ 24 /rdx /rsi :leaqMemDisp8Reg 24 /rcx /rdi :leaqMemDisp8Reg 16 /rdx /rdx :movqMemDisp8Reg 16 /rcx /rcx :movqMemDisp8Reg @loop /rdx /rdx :andqRegReg /leftEmpty :jzLbl8 /rcx /rcx :andqRegReg /leftLarger :jzLbl8 :cmpsb /rightLarger :jbLbl8 /leftLarger :jaLbl8 /rcx :decqReg /rdx :decqReg /loop :jmpLbl8 @leftEmpty /rcx /rcx :andqRegReg /bothEqual :jzLbl8 @rightLarger smaller /rdx :movqImmReg /done :jmpLbl8 @leftLarger greater /rdx :movqImmReg /done :jmpLbl8 @bothEqual equal /rdx :movqImmReg @done ]] } /createStringOpcodes deff { ==name name " not available on floats" cat ::outputError :ud2 } /floatUnsupported deff < # equality on ints and strings [[ /rbx :popqReg /rdx :popqReg /rdi :popqReg 63 /rdx :btqImm8Reg /intCase :jcLbl8 63 /rdi :btqImm8Reg /intCase :jcLbl8 %F0 7 /rdx :testbImmMemDisp8 /intCase :jzLbl8 %F0 7 /rdi :testbImmMemDisp8 /intCase :jzLbl8 16 /rdx /rsi :movqMemDisp8Reg 16 /rdi /rcx :movqMemDisp8Reg /rsi /rcx :cmpqRegReg /nonEqualStr :jneLbl8 24 /rdx /rsi :leaqMemDisp8Reg 24 /rdi /rdi :leaqMemDisp8Reg :repz :cmpsb /nonEqualStr :jneLbl8 /rdx /rdx :xorqRegReg /rdx :incqReg /done :jmpLbl8 @nonEqualStr /rdx /rdx :xorqRegReg @done 63 /rdx :btsqImm8Reg /rdx :pushqReg /rbx :pushqReg :retn @intCase /rdi ::unboxInteger /rdx ::unboxInteger /rax /rax :xorqRegReg /rdi /rdx :cmpqRegReg /nonEqual :jnzLbl8 /rax :incqReg @nonEqual 63 /rax :btsqImm8Reg /rax :pushqReg /rbx :pushqReg :retn ]] /eyeq defv [ 8 /r15 :subqImm8Reg /r15 :popqMem /rax :movqImmOOBReg "eyneq" "eyeq" ::linkAbs64 /rax :callqReg 1 0 /rsp :xorbImmMemDisp8 /r15 :pushqMem 8 /r15 :addqImm8Reg :retn ] /eyneq defv # arithmetic functions [ /rcx /rdx :addqRegReg ] [ :faddp ] 0 makeFullArith /eyadd defv [ /rcx /rdx :subqRegReg ] [ :fsubp ] 0 makeFullArith /eysub defv [ /rcx /rdx :andqRegReg ] [[ "band" floatUnsupported ]] 0 makeFullArith /eyband defv [ /rcx /rdx :orqRegReg ] [[ "bor" floatUnsupported ]] 0 makeFullArith /eybor defv [ /rcx /rdx :xorqRegReg ] [[ "bxor" floatUnsupported ]] 0 makeFullArith /eybxor defv [ /rdi /rdi :xorqRegReg 1 /rsi :movqImmReg /rdx /rcx :cmpqRegReg /rsi /rdx :movqRegReg /rdi /rdx :cmovngqRegReg ] [ 1 /rdi :movqImmReg /rdx /rdx :xorqRegReg :fcomip :fstp /rdi /rdx :cmovaqRegReg ] 1 0 0 createStringOpcodes -210210 1 makeFullScalar /eylt defv { [ 1 /rdx :xorqImm8Reg ] cat } -30*20*10* 1 makeFullScalar /eyge defv [ /rdi /rdi :xorqRegReg 1 /rsi :movqImmReg /rdx /rcx :cmpqRegReg /rsi /rdx :movqRegReg /rdi /rdx :cmovngeqRegReg ] [ 1 /rdi :movqImmReg /rdx /rdx :xorqRegReg :fcomip :fstp /rdi /rdx :cmovaeqRegReg ] 1 1 0 createStringOpcodes -210210 1 makeFullScalar /eyle defv { [ 1 /rdx :xorqImm8Reg ] cat } -30*20*10* 1 makeFullScalar /eygt defv [ /rax :pushqReg /rcx /rax :movqRegReg /rdx :mulqReg /rax /rdx :movqRegReg /rax :popqReg ] [ :fmulp ] 0 makeFullArith /eymul defv [[ /rax :pushqReg /rdx /rax :movqRegReg :cqo /rcx :idivqReg 0 /rdx :cmpqImm8Reg /positive :jgeLbl8 /rcx /rdx :addqRegReg @positive /rax :popqReg ]] [[ "mod" floatUnsupported ]] 0 makeFullArith /eymod defv [ /rax :pushqReg /rdx /rax :movqRegReg :cqo /rcx :idivqReg /rax /rdx :movqRegReg /rax :popqReg ] [ :fdivp ] 0 makeFullArith /eydiv defv [[ /rax :pushqReg /rdx /rax :movqRegReg /rdx /rdx :xorqRegReg /rcx :divqReg /rax :popqReg ]] [[ "umod" floatUnsupported ]] 0 makeFullArith /eyumod defv [ /rax :pushqReg /rdx /rax :movqRegReg /rdx /rdx :xorqRegReg /rcx :divqReg /rax /rdx :movqRegReg /rax :popqReg ]] [[ "udiv" floatUnsupported ]] 0 makeFullArith /eyudiv defv [[ /rcx /rcx :testqRegReg /no :jzLbl8 /rdx /rdx :testqRegReg /no :jzLbl8 1 /rdx :movqImmReg /done :jmpLbl8 @no /rdx /rdx :xorqRegReg @done ]] [[ "and" floatUnsupported ]] 0 makeFullArith /eyand defv [[ /rcx /rcx :testqRegReg /yes :jnzLbl8 /rdx /rdx :testqRegReg /yes :jnzLbl8 /rdx /rdx :xorqRegReg /done :jmpLbl8 @yes 1 /rdx :movqImmReg @done ]] [[ "or" floatUnsupported ]] 0 makeFullArith /eyor defv [[ /rcx /rcx :testqRegReg /first :jnzLbl8 # @firstNot /rdx /rdx :testqRegReg /yes :jnzLbl8 /rdx /rdx :xorqRegReg /done :jmpLbl8 @first /rdx /rdx :testqRegReg /yes :jzLbl8 /rdx /rdx :xorqRegReg /done :jmpLbl8 @yes 1 /rdx :movqImmReg @done ]] [[ "xor" floatUnsupported ]] 0 makeFullArith /eyxor defv > _ =globalT11t1Functions { defv }' ::allocateOffsetStruct < # 0 -> integer # 0 <- the bitwise negated integer [[ /rbx :popqReg # allocate result int ::internalAllocateInteger /rax :movqImmReg /rax :callqReg # actual negation /rcx :popqReg /rcx ::unboxInteger /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 # actual negation /rcx :popqReg /rcx ::unboxInteger /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 # actual negation /rcx :popqReg /rcx ::unboxInteger /rdx /rdx :xorqRegReg /rcx /rcx :testqRegReg /zero :jnzLbl8 /rdx :incqReg @zero # push int on program stack 63 /rdx :btsqImm8Reg /rdx :pushqReg /rbx :pushqReg :retn ]] /eynot defv > _ =globalT1t1Functions { defv }' ::allocateOffsetStruct { | }' ::linkResolve { =*resolve ==createScopeEntry { ==name # create function name resolve 16 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 not { "could not extract client-side name" die } rep ::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 16 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 not { "could not extract client-side name" die } rep ::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 | 16 sub /rdi :movqImmReg # adjust for expected (but non-existent) code block header size /r14 /rsi :movqRegReg /rdx /rdx :xorqRegReg # untyped ::internalAllocateFunction /rax :movqImmReg /rax :callqReg /rax :pushqReg # create string name "ey(.*)" regex not { "could not extract client-side name" die } rep ::constStringCode _ len dearray # enter into current scope |eydeff /rax :movqImmReg /rax :callqReg } 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 globalMacros keys len add globalT11t1Functions keys len add globalT1t1Functions keys len add /rdi :movqImmReg /rsi /rsi :xorqRegReg ::internalAllocateScope /rax :movqImmReg /rax :callqReg /rax /r14 :movqRegReg 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 ]] :execute { ==name [[ ::INITIALSCOPESIZE /rdi :movqImmReg 8 /r15 :subqImm8Reg /r14 /r15 :movqRegMem # save scope /r14 /rsi :movqRegReg ::internalAllocateScope /rax :movqImmReg /rax :callqReg /rax :pushqReg /rax :pushqReg name ::constStringCode _ len dearray |eydefvc /rax :movqImmReg /rax :callqReg /r14 :popqReg ]] :execute } /enterSubScope deff { [[ /r15 /r14 :movqMemReg 8 /r15 :addqImm8Reg ]] :execute } /leaveSubScope deff "elymasGlobalSys.ey" include "elymasGlobalStr.ey" include > /global defv # vim: syn=elymas