diff options
| author | Drahflow <drahflow@gmx.de> | 2013-01-18 17:30:53 +0100 |
|---|---|---|
| committer | Drahflow <drahflow@gmx.de> | 2013-01-18 17:30:53 +0100 |
| commit | b7a44c57268d42b1abb40b0faea1bd2cc071894f (patch) | |
| tree | 83696b1badf1bb6a9937167c3b32269d959fd370 | |
| parent | 99635bdbd50bf215c53727ff2f50df935e4fdd04 (diff) | |
Quoting in unquoted contexts now works
... in principle. The new function does not yet create
its own scope.
| -rw-r--r-- | compiler/elymasAsm.ey | 114 | ||||
| -rw-r--r-- | compiler/elymasAsmLib.ey | 459 | ||||
| -rw-r--r-- | compiler/elymasGlobal.ey | 46 | ||||
| -rw-r--r-- | examples/working/exec.ey | 1 | ||||
| -rw-r--r-- | notes | 2 |
5 files changed, 500 insertions, 122 deletions
diff --git a/compiler/elymasAsm.ey b/compiler/elymasAsm.ey index b307589..390329a 100644 --- a/compiler/elymasAsm.ey +++ b/compiler/elymasAsm.ey @@ -17,8 +17,11 @@ < [ /eax /ecx /edx /ebx /esp /ebp /esi /edi /r8d /r9d /r10d /r11d /r12d /r13d /r14d /r15d ] { 1 -01 defv }' each > ==bit32table { bit32table -01 . -- } /bit32assert deff - { [ /ax /cx /dx /bx /sp /bp /si /di /r8w /r9w /r10w /r11w /r12w /r13w /r14w /r15w ] streq any } /bit16 deff - { [ /al /cl /dl /bl /spl /ah /bpl /ch /sil /dh /dil /bh /r8b /r9b /r10b /r11b /r12b /r13b /r14b /r15b ] streq any } /bit8 deff + < [ /ax /cx /dx /bx /sp /bp /si /di /r8w /r9w /r10w /r11w /r12w /r13w /r14w /r15w ] { 1 -01 defv }' each > ==bit16table + { bit16table -01 . -- } /bit16assert deff + + < [ /al /cl /dl /bl /spl /ah /bpl /ch /sil /dh /dil /bh /r8b /r9b /r10b /r11b /r12b /r13b /r14b /r15b ] { 1 -01 defv }' each > ==bit8table + { bit8table -01 . -- } /bit8assert deff < [ /zero /al /ax /eax /rax /none ] { 0 -01 defv }' each @@ -194,6 +197,16 @@ src dst modrm11 } /addqRegReg deff + { ==reg =i + reg bit8assert + i 256 lt assert + + reg regno %07 gt { 0 /none /none reg rex } rep + %80 + /four reg modrm11 + i imm8 + } /andbImmReg deff + { ==dst ==src dst bit64assert src bit64assert @@ -230,6 +243,16 @@ %A7 } /cmpsq deff + { ==reg =i + reg bit8assert + i 256 lt assert + + reg regno %07 gt { 0 /none /none reg rex } rep + %80 + /seven reg modrm11 + i imm8 + } /cmpbImmReg deff + { ==mem ==reg reg bit32assert mem bit64assert @@ -287,6 +310,14 @@ src dst modrm11 } /cmpqRegReg deff + { ==mem + mem bit64assert + + 1 /none /none mem rex + %FF + /one mem modrm00 + } /decqMem deff + { ==reg reg bit64assert @@ -295,6 +326,14 @@ /one reg modrm11 } /decqReg deff + { ==mem + mem bit64assert + + 1 /none /none mem rex + %FF + /zero mem modrm00 + } /incqMem deff + { ==reg reg bit64assert @@ -327,6 +366,60 @@ disp imm8 } /leaqMemDisp8Reg deff + { ==mem ==i + mem bit64assert + i 256 lt assert + + mem regno %07 gt { 0 /none /none mem rex } rep + %C6 + /zero mem modrm00 + i imm8 + } /movbImmMem deff + + { ==mem ==disp ==i + mem bit64assert + disp 256 lt assert + i 256 lt assert + + mem regno %07 gt { 0 /none /none mem rex } rep + %C6 + /zero mem modrm01 + disp imm8 + i imm8 + } /movbImmMemDisp8 deff + + { ==reg ==mem ==disp + reg bit8assert + mem bit64assert + disp 128 lt assert + + reg regno %07 gt mem regno %07 gt or { 0 reg /none mem rex } rep + %8A + reg mem modrm01 + disp imm8 + } /movbMemDisp8Reg deff + + { ==mem ==i + mem bit64assert + i 65536 lt assert + + mem regno %07 gt { 0 /none /none mem rex } rep + %66 + %C7 + /zero mem modrm00 + i imm16 + } /movwImmMem deff + + { ==mem ==i + mem bit64assert + i 65536 65536 mul lt assert + + mem regno %07 gt { 0 /none /none mem rex } rep + %C7 + /zero mem modrm00 + i imm32 + } /movlImmMem deff + { ==reg ==mem reg bit32assert mem bit64assert @@ -434,6 +527,10 @@ src dst modrm11 } /movqRegReg deff + { + %A4 + } /movsb deff + { ==reg ==mem reg bit64assert mem bit64assert @@ -497,6 +594,13 @@ /six mem modrm00 } /pushqMem deff + { ==mem ==disp + mem regno %07 gt { 1 /none /none mem rex } rep + %FF + /six mem modrm01 + disp imm8 + } /pushqMemDisp8 deff + { ==mem ==idx ==scale mem regno %07 gt idx regno %07 gt or { 1 /none idx mem rex } rep %FF @@ -516,6 +620,10 @@ { %F3 + } /reprcx deff + + { + %F3 } /repz deff { @@ -678,6 +786,8 @@ > -12 == }' each + STACKSIZE sys .asm .alloc .base ==quoteEncodingBuffer + { ==opcodes opcodes len 1 sub PAGESIZE div 1 add PAGESIZE mul sys .asm .alloc /codearea defv sys .asm .|poke =*poke diff --git a/compiler/elymasAsmLib.ey b/compiler/elymasAsmLib.ey index bc4d0d2..62f48c6 100644 --- a/compiler/elymasAsmLib.ey +++ b/compiler/elymasAsmLib.ey @@ -33,6 +33,9 @@ # current parser scope [ %00 %00 %00 %00 %00 %00 %00 %00 ] ==currentScope + + # current parser quote state + [ %00 %00 %00 %00 %00 %00 %00 %00 ] ==currentQuoted > { defv }' allocateOffsetStruct # internal functions, ABI follows SysV standards @@ -169,7 +172,6 @@ /rax /rdx :xchgqRegReg :retn ] :labelResolve /internalResolve defv - > { defv }' allocateOffsetStruct # TODO: link internal functions statically with relative calls @@ -239,6 +241,19 @@ :retn ] /internalAllocateFunction defv + # allocate code block + # rdi -> number of code bytes + # rax <- address of code block on heap + [ + 8 /rdi :addqImm8Reg + internalAllocate /rax :movqImmReg + /rax :callqReg + + # set type + %60 7 /rax :orbImmMemDisp8 + :retn + ] /internalAllocateCode defv + # allocate array, expecting rdi/8 entries # rdi -> expected number of entry bytes # rax <- address of array on the heap @@ -257,6 +272,7 @@ # elymas functions, stack based ABI 1 ==ARRAYMARKER + 2 ==QUOTEMARKER # 0 -> integer # 1 -> integer @@ -322,100 +338,104 @@ [ /rcx /rdx :orqRegReg ] makeArith /eybor defv [ /rcx /rdx :xorqRegReg ] makeArith /eybxor defv - # create a new entry in the current scope for the given name - # mark that entry as default-active - # 0 -> name, string - # 1 -> object - [ - /rcx :popqReg - /rdi :popqReg - - # 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 - /rdi /rsi :movqRegMem - 1 8 /rsi :movqImm32MemDisp8 # set default activation mode to execute - 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 - # FIXME - :ud2 - - @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 # TODO this fails for > 4 GB scopes - /inDataArea :jnbLbl8 - - # update within extension area - /rbx /edx :sublMemReg # substract scope length - 24 /rbx /rbx :movqMemDisp8Reg # load extension area pointer - 8 /rdx :addqImm8Reg # add extension area header length - - # if extension area is full, double size - /edx /rbx :cmplRegMem - /inExtensionArea :jnbLbl8 - - # FIXME - :ud2 - - @inExtensionArea - @inDataArea - - /rax :popqReg - /rax /rbx /rdx :movqRegMemIndex # save entry pointer - - /rcx :pushqReg - :retn - ] :labelResolve /eydeff defv + { ==activation + # create a new entry in the current scope for the given name + # mark that entry's default action according to activation + # 0 -> name, string + # 1 -> object + [ + /rcx :popqReg + /rdi :popqReg + + # 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 + /rdi /rsi :movqRegMem + activation 8 /rsi :movqImm32MemDisp8 # 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 + # FIXME + :ud2 + + @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 # TODO this fails for > 4 GB scopes + /inDataArea :jnbLbl8 + + # update within extension area + /rbx /edx :sublMemReg # substract scope length + 24 /rbx /rbx :movqMemDisp8Reg # load extension area pointer + 8 /rdx :addqImm8Reg # add extension area header length + + # if extension area is full, double size + /edx /rbx :cmplRegMem + /inExtensionArea :jnbLbl8 + + # FIXME + :ud2 + + @inExtensionArea + @inDataArea + + /rax :popqReg + /rax /rbx /rdx :movqRegMemIndex # save entry pointer + + /rcx :pushqReg + :retn + ] :labelResolve + } 0 -101* /eydefv defv + 1 -101* /eydeff defv + 2 -01* /eydefq defv # execute top stack element [ @@ -594,8 +614,210 @@ 8 /r15 :addqImm8Reg :retn ] :labelResolve /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 + + @loop + /rcx /r15 :movqRegMem + + 8 /r15 :pushqMemDisp8 + |ey* /rax :movqImmReg + /rax :callqReg + + /r15 /rcx :movqMemReg + /loop :loopLbl8 + + 16 /r15 :addqImm8Reg + + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ] :labelResolve /eyrep defv > _ ==globalFunctions2 { defv }' allocateOffsetStruct + < + # quote construction, push begin marker on stack + [ + /rax :popqReg + QUOTEMARKER :pushqImm32 + currentQuoted /rcx :movqImmReg + /rcx :incqMem + /rax :pushqReg + :retn + ] /ey{ defv + + < + # FIXME: open a new function scope + [ + 8 /r15 :subqImm8Reg + /r15 :popqMem + 8 /r15 :subqImm8Reg + currentScope /rax :movqImmReg + /rax /rax :movqMemReg + /rax /r15 :movqRegMem + ] /functionHeader defv + + [ + /r15 /rcx :movqMemReg + currentScope /rax :movqImmReg + /rcx /rax :movqRegMem + 8 /r15 :addqImm8Reg + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ] /functionFooter defv + + { _ =*array len _ 4 div ==largeMoves + 4 mod ==smallMoves + 0 ==i + largeMoves { + i _ 4 add =i + [ 3 2 1 0 ] add array { -01 256 mul add } fold /rdi :movlImmMem + 4 /rdi :addqImm8Reg + } rep + smallMoves { + i _ 1 add =i + array /rdi :movbImmMem + /rdi :incqReg + } rep + } /loadToRdi deff + + # quote construction, create function from begin marker onwards + [ + 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 + + functionHeader loadToRdi + + @search + 8 /rdx :subqImm8Reg + /rdx /rcx :cmpqMemReg + /markerFound :jeLbl8 + + /rdx /rsi :movqMemReg + 7 /rsi /al :movbMemDisp8Reg + %F0 /al :andbImmReg + /immediateFound :jzLbl8 + %50 /al :cmpbImmReg + /functionFound :jzLbl8 + %70 /al :cmpbImmReg + /arrayFound :jzLbl8 + + # TODO: "invalid object during quote construction" + :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 :jmpLbl8 + + @functionFound + [ /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 :jmpLbl8 + + @arrayFound + # FIXME allow macros to put byte arrays into quoted contexts and thereby generate assembly + :ud2 + /search :jmpLbl8 + + @markerFound + + functionFooter loadToRdi + + :quoteEncodingBuffer /rax :movqImmReg + /rax /rdi :subqRegReg + /rdi :pushqReg # store opcode byte count + + /rdi :decqReg + 3 /rdi :shrqImm8Reg + /rdi :incqReg + 3 /rdi :shlqImm8Reg + internalAllocateCode /rax :movqImmReg + /rax :callqReg + + # rax == code block on heap + + # copy opcodes + :quoteEncodingBuffer /rsi :movqImmReg + 8 /rax /rdi :leaqMemDisp8Reg + /rcx :popqReg + :reprcx :movsb + + # create function object + /rax /rdi :movqRegReg + currentScope /rax :movqImmReg + /rax /rsi :movqMemReg + /rdx /rdx :xorqRegReg + internalAllocateFunction /rax :movqImmReg + /rax :callqReg + + # 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 + + currentQuoted /rcx :movqImmReg + /rcx /rcx :movqMemReg + /rcx /rcx :testqRegReg + /unquoted :jzLbl8 + + :ud2 + # FIXME: quote once more + + @unquoted + /r15 :pushqMem + 8 /r15 :addqImm8Reg + :retn + ] :labelResolve + > -- /ey} defv + > _ ==globalMacros { defv }' allocateOffsetStruct + { strToUTF8Bytes _ =*v len _ ==exactLength 1 sub 8 div 4 add 8 mul ==memoryLength @@ -633,35 +855,38 @@ ] } /constStringCode deff - globalFunctions keys globalFunctions2 keys cat ==globalFunctionNames - [ - globalFunctionNames len /rdi :movqImmReg + globalFunctions keys len globalFunctions2 keys len globalMacros keys len add add /rdi :movqImmReg internalAllocateScope /rax :movqImmReg /rax :callqReg currentScope /rdi :movqImmReg /rax /rdi :movqRegMem - globalFunctionNames { ==name - # create function - name | 8 sub /rdi :movqImmReg - currentScope /rsi :movqImmReg - /rsi /rsi :movqMemReg - # 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 - eydeff /rax :movqImmReg - /rax :callqReg - } each + { ==createScopeEntry + { ==name + # create function + name | 8 sub /rdi :movqImmReg + currentScope /rsi :movqImmReg + /rsi /rsi :movqMemReg + # 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 + globalFunctions keys eydeff createScopeEntries + globalFunctions2 keys eydeff createScopeEntries + globalMacros keys eydefq createScopeEntries ] :execute < diff --git a/compiler/elymasGlobal.ey b/compiler/elymasGlobal.ey index a6dcfb8..64f943a 100644 --- a/compiler/elymasGlobal.ey +++ b/compiler/elymasGlobal.ey @@ -14,6 +14,7 @@ < { assembler -01 . } ":" deff { assemblerLibrary -01 . } "::" deff + assembler .|label "@" deff "%" _ : -01 deff { .value base10decode ==v @@ -45,13 +46,54 @@ /rsi :popqReg ::internalResolve /rax :movqImmReg /rax :callqReg + + /rax /rax :testqRegReg + /unresolved :jzLbl8 /rax :pushqReg - /rdx /rdx :testqRegReg + 0 /rdx :cmpqImm8Reg /inactive :jzLbl8 + 1 /rdx :cmpqImm8Reg + /active :jzLbl8 + 2 /rdx :cmpqImm8Reg + /quoteActive :jzLbl8 + :ud2 + + @unresolved + :ud2 + + @quoteActive + ::ey* /rax :movqImmReg + /rax :callqReg + /done :jmpLbl8 + + @active + ::currentQuoted /rax :movqImmReg + /rax /rax :movqMemReg + /rax /rax :testqRegReg + /activeQuoted :jnzLbl8 ::ey* /rax :movqImmReg /rax :callqReg - /inactive :label + /done :jmpLbl8 + + @activeQuoted + # FIXME: actually, this should re-resolve as if unresolved + /done :jmpLbl8 + + @inactive + ::currentQuoted /rax :movqImmReg + /rax /rax :movqMemReg + /rax /rax :testqRegReg + /inactiveQuoted :jnzLbl8 + /done :jmpLbl8 + + @inactiveQuoted + :ud2 + +# ::ey* /rax :movqImmReg +# /rax :callqReg + + @done ] :labelResolve cat :execute } /TOKID > -- 3 |defv rep diff --git a/examples/working/exec.ey b/examples/working/exec.ey index 6977e86..bc1614c 100644 --- a/examples/working/exec.ey +++ b/examples/working/exec.ey @@ -1,4 +1,5 @@ #!/usr/bin/env elymas 1 1 |dump -110 * add dump +3 { 4 add } * dump 4 3 { 1 add } rep dump @@ -177,7 +177,7 @@ Small set in between * Length in bytes (including header) bit 63-60: 0 1 0 1 bit 59: reserved for GC -* scope pointer (0 if non-capturing function) +* captured scope pointer (0 if non-capturing function) * type pointer (0 if untyped) * code pointer |
