Compare commits

...
953 Commits
Author SHA1 Message Date
GenericHeroGuy 744dc87c16 In rehashtab, do counthash before adding asize
Thanks alug!
2025-01-29 22:25:24 +01:00
GenericHeroGuy b400655f3c Add cleanjit target
Recompiling the whole game after changing a single flag is pretty tiring
2025-01-06 00:02:11 +01:00
GenericHeroGuy 314ab9e9f0 Fix some functions leaking doubles in INTONLY 2025-01-05 23:48:40 +01:00
GenericHeroGuy 0fbc448013 Use references instead of upvalues for original I/O functions
No more unrestricted I/O through debug.getupvalue
2025-01-03 22:16:11 +01:00
GenericHeroGuy eb9d1982fa Update to BLUAJIT 449b76f 2025-01-03 20:12:26 +01:00
GenericHeroGuy 0bf0441f49 Unify I/O library modifications 2024-11-15 15:54:07 +01:00
GenericHeroGuy 0c66ac97e8 Disable bytecode (1930cc9) 2024-11-15 14:18:56 +01:00
GenericHeroGuy 8c261dba73 Fix building with NOBLUAJIT 2024-11-15 00:24:19 +01:00
GenericHeroGuy 6e3b6cb0c1 Check division/modulo by zero (a74a4eb) 2024-11-15 00:00:51 +01:00
GenericHeroGuy 11155cc609 Standard library wipeout (1d1b7ec) 2024-11-13 17:15:08 +01:00
GenericHeroGuy a5baa052e2 Fix building on Windows (hopefully) 2024-11-12 00:43:25 +01:00
GenericHeroGuy 71021982ed Two fixes from master 2024-11-10 22:02:46 +01:00
GenericHeroGuy 4d9c1f7a65 Disable FFI 2024-11-10 19:37:05 +01:00
GenericHeroGuy 406e9dcaf2 HUD interpolation for BLUAJIT
Still glitches for a single tic with JIT on...
2024-11-10 17:56:00 +01:00
GenericHeroGuy d3b0d845eb Fix consolelib once and for all
LuaJIT does not tolerate lightuserdata in luaL_checkudata,
so now cvars are userdata like everything else
2024-11-10 17:47:43 +01:00
GenericHeroGuy 335b977cd4 Fix API assert in LUA_EvalMath 2024-11-10 17:41:00 +01:00
GenericHeroGuy 3554c91b2b Library stuff, cvar, etc 2024-11-10 17:38:41 +01:00
GenericHeroGuy 460dab0342 BLUAJIT makefiles 2024-11-10 17:38:41 +01:00
GenericHeroGuy fb9b04c192 Import BLUAJIT (cb36ab5) 2024-11-10 17:38:37 +01:00
indev 38abb4c9e4 That didn't work in spectator camera, oops 2024-11-10 03:26:15 +03:00
indev fc469d6433 Fix spectating other players setting wrong angle when returning back to local player 2024-11-10 03:18:01 +03:00
indev f4703be2ca Fix r_portal.c and r_portal.h missing from src/CMakeLists.txt 2024-11-08 11:47:58 +03:00
Alug 7c78cf067c forgor ifdef here 2024-11-03 15:35:03 +01:00
Alug c451f0f1a6 windoze 2024-11-03 14:23:26 +01:00
Alug 35b85bec36 bleh pls 2024-11-03 14:18:59 +01:00
Alug b0c64be31d try to simplify this alteast a little
shit is awful
2024-11-03 03:40:55 +01:00
Alug d09a28e3da missed this 2024-11-03 03:13:15 +01:00
Alug 550c66b25b add some more checks for this 2024-11-03 02:59:23 +01:00
Alug dfec9e24f3 add just a little more extra safety for fbo 2024-11-03 02:44:42 +01:00
indev 2350889445 Fix normal skin being unable to load if localskins limit is reached (thx Alug for pointing out <3) 2024-11-03 00:26:18 +03:00
indev 990854e176 Fix localskins being unable to load if normal skin limit is reached 2024-11-03 00:16:15 +03:00
Alug 8c727b979c initialise this to null aswell
just in case
2024-11-02 14:19:53 +01:00
Alug 60de48ad65 add accurate fps counter crap to menu + rename it to force it back on
since shit more or less was broken in saturn before and always showed the more accurate one, force it again since stuff caused confusion
2024-11-02 12:57:17 +01:00
Alug 2fd1abce5c v7.2 2024-11-02 01:20:02 +01:00
Alug 691a61de72 oops 2024-11-02 01:12:56 +01:00
Alug 3a153c3abe Merge pull request #137 from Indev450/refactorogl
Cleanup and slightly refactor ogl files
2024-11-02 00:57:49 +01:00
Alug d22645e56a use a "-" here for consistancy 2024-11-02 00:50:28 +01:00
Alug 08fe3beef1 respect cv_showdirectorhud 2024-11-02 00:49:35 +01:00
Alug 2c54c92e14 spec cam disables director, but you can toggle it from speccam
uhhhhhhh
2024-11-02 00:49:32 +01:00
Alug c127cd9016 fix wanted reticle offsets
Zzz...
2024-11-01 20:29:33 +01:00
Alug 9cb790ac23 oops broke encore 2024-11-01 20:01:50 +01:00
Alug c2c7381bc1 use precalced minimap stuff for v.drawOnMinimap 2024-11-01 19:55:23 +01:00
Alug 1e4eeb2bcf fix some issues with cv_minihead and minimap icon drawing 2024-11-01 19:55:20 +01:00
Alug b1f99f8d2f fix minimap not being initialised
causes issues when you switch to maps that dont have a minimap
2024-11-01 18:39:36 +01:00
Alug f752da7d03 formatting stuff lul 2024-10-31 12:02:48 +01:00
Alug 7ddcf6d0d4 Merge branch 'Saturn-Next' into refactorogl 2024-10-31 11:59:33 +01:00
indev b21776183e Add shift+insert shortcut for pasting text 2024-10-30 22:14:17 +03:00
indev 9c0dcac5c6 Fix mapmusname global in lua being renamed to (*mapmusname) 2024-10-30 19:21:07 +01:00
indev 1b75d8b8e2 Fix mapmusname global in lua being renamed to (*mapmusname) 2024-10-30 20:35:17 +03:00
Alug 145e305494 Merge branch 'Saturn-Next' into refactorogl 2024-10-30 16:04:06 +01:00
Alug 8f4d185ea6 Revert "use highly optmized (but slightly inaccurate) version of R_PointOnSide for rendering"
This reverts commit 9314a24cb2.
2024-10-30 16:03:35 +01:00
Alug 4b5ff6be5d Merge branch 'Saturn-Next' into refactorogl 2024-10-30 15:34:43 +01:00
Alug d27ef85b9e remove some unused stuff in portal struct 2024-10-30 13:52:06 +01:00
Alug 1ac210c2fc improve ogl portal clipping 2024-10-30 13:05:30 +01:00
Alug 878b7f4b43 fix portal culling 2024-10-28 20:25:03 +01:00
Alug 7cbac66935 throw this into an inline func 2024-10-28 20:25:01 +01:00
Alug 7e09223e6e gu 2024-10-28 16:36:04 +01:00
Alug b4e1be5bee dont always call HWR_Startup again 2024-10-28 16:35:44 +01:00
Alug d3e5e236ac those do nothing 2024-10-28 16:34:40 +01:00
Alug 238ce98c44 dont always call HWR_Startup again 2024-10-28 07:21:13 +01:00
Alug 2824e5d850 no need to update this witouth water ripples 2024-10-28 06:49:09 +01:00
Alug cd154d5748 grey out some stuffs in the ogl and advanced video menus 2024-10-28 06:40:23 +01:00
Alug c0a8153a10 sort those a bit 2024-10-28 06:40:19 +01:00
Alug 3433fc7651 those should be disabled 2024-10-28 06:40:17 +01:00
Alug 22d1ee8f60 move CV_PossibleValue_t to their own section like other files 2024-10-28 06:40:14 +01:00
Alug 5155958ade add "gl" to secbright and lightdither cvars
theyre only used in ogl so follow the naming convention
2024-10-28 05:40:59 +01:00
Alug 5fdd486bab reorder all of this to be in same order lol 2024-10-28 05:40:56 +01:00
Alug 4672037bcd check if those are already off before trying to turn them off lol 2024-10-28 05:40:54 +01:00
Alug 2281b82b5a replace last remaining "gr" 2024-10-28 04:28:25 +01:00
Alug 3fe096c7d4 gr -> gl
this has been annoying me since ages lol
2024-10-28 04:23:15 +01:00
Alug dd3ca0e161 change cvar register order for ogl stuff 2024-10-28 03:39:05 +01:00
Alug d8da78f900 more cleanup 2024-10-28 03:38:52 +01:00
Alug 9325e7be8f make a bunch of hwr stuff static and cleanup 2024-10-28 03:38:48 +01:00
Alug f3f94bf80e fr*nch 2024-10-28 03:38:36 +01:00
Alug 506dc2455a fr*nch 2024-10-26 23:24:01 +02:00
Alug 94d6ee15b5 this should be portalcullsector lol 2024-10-26 19:44:32 +02:00
Alug 2d918d32a1 reduce the scope of this since not needed 2024-10-26 19:44:28 +02:00
Alug dd516b573b rename this to avoid confusion 2024-10-26 19:31:14 +02:00
Alug de9698efc8 just use the same as software lol
i never saw any differernce except in performance for this
also viewsin and viewcos get calced in r_fps so no need to do here again
2024-10-26 19:29:53 +02:00
Alug 14b026f04b slight cleanup ogl portals again 2024-10-26 19:29:51 +02:00
Alug 9dd45440c0 rename and slight cleanup 2024-10-26 19:29:46 +02:00
Alug c59e8387ca smth smth shadows a global declaration 2024-10-26 19:29:35 +02:00
Alug 772ad9f04f throw ogl portals into their own files 2024-10-26 19:29:32 +02:00
Alug 6053c2c619 readd mobj null check here 2024-10-26 16:40:08 +02:00
Alug a515b133c5 inline this since its super smol 2024-10-26 16:40:04 +02:00
Alug 240dae9a1a move chasecam postimg stuff into own function + add comments for what stuff does lol
shit got me really confused
2024-10-26 16:12:43 +02:00
Alug b8a703233a forgor to remove this 2024-10-26 00:51:58 +02:00
Alug bf44c95d00 clean up portals 2024-10-26 00:51:55 +02:00
Alug c3dd1755dc port srb2 software portal refactor 2024-10-26 00:51:44 +02:00
indev b6e766ee44 Fix A_Lua not removing error handler from lua stack 2024-10-25 23:15:52 +03:00
Alug 5437040b78 move the return ealier in V_DoPostProcessor 2024-10-25 20:21:10 +02:00
Alug c786569981 Merge branch 'refactorpostimg' into Saturn-Next 2024-10-25 20:12:56 +02:00
Alug 7064b14539 Merge branch 'autoloadagain' into Saturn-Next 2024-10-25 20:12:53 +02:00
Alug f275ae98f5 this is needed for postimg stuff in first person
lol
also adds break in splitscreen lööp
2024-10-25 20:12:14 +02:00
Alug ef07d89e29 Revert "update lzf compression to 1.6"
This reverts commit 48e71afec1.
2024-10-25 19:50:16 +02:00
Alug b9bbd45e15 Revert "shut up mingw"
This reverts commit 75637e361c.
2024-10-25 19:50:10 +02:00
Alug 2bda27b80d Revert "those should be size_t"
This reverts commit b357c09171.
2024-10-25 19:49:26 +02:00
Alug 6ebf90cc50 Merge branch 'Saturn-Next' into autoloadagain 2024-10-25 03:28:43 +02:00
Alug ea00bebb04 Merge branch 'Saturn-Next' into refactorpostimg 2024-10-25 03:28:20 +02:00
Alug b862d835a5 save one calc lol 2024-10-25 03:27:51 +02:00
Alug d6602747ae oops forgor lol 2024-10-25 03:26:22 +02:00
Alug 9f79429d03 slight cleanup + make static + smol optimize ogl sprite drawers 2024-10-25 03:26:19 +02:00
Alug 5ff0c09868 just check for noencore bool in hwr_processseg instead of checked line flags everytime 2024-10-23 21:33:31 +02:00
Alug ad1c3e63a4 why not reuse those? 2024-10-23 21:33:28 +02:00
Alug 24dd6ba675 cleanup HWR_ProcessSeg
stuff was quite the mess
2024-10-23 21:33:21 +02:00
Alug 85f036a45b dont always calc this twice 2024-10-23 21:33:14 +02:00
Alug 6f8342b9a8 remove cv_splitwallfix
tbh i dont think anyone even knows about this, never heard any complains, never had any issues, neither visually or performancewise.
its just clutter at this point
2024-10-23 21:33:04 +02:00
Alug c5c6f6b820 this does nothing 2024-10-23 21:30:21 +02:00
Alug 3d472c34a1 no need to check stuff in already postload marked addons 2024-10-23 15:48:44 +02:00
Alug 63ca366bd8 dont play rain sounds when weather is disabled 2024-10-23 13:00:36 +02:00
Alug e9e888ab7f remove debug print 2024-10-23 02:41:28 +02:00
indev 5ea55b3e3a Add W_CheckFileContains for W_CheckPostLoadList 2024-10-23 02:41:25 +02:00
Alug 8b1797927a attempt to check for things in file for postload detection 2024-10-23 02:41:23 +02:00
Alug 05a98964fb split auto and postload, let autoload run on gamestart again
prep for smth
2024-10-23 02:41:20 +02:00
Alug 8cbf798de8 redo rain sound overflow fix
https://git.do.srb2.org/KartKrew/RingRacers/-/commit/3eac1fed0f44a8285a9f6b82a12e86997bbb0d34
2024-10-23 02:37:32 +02:00
Alug 9314a24cb2 use highly optmized (but slightly inaccurate) version of R_PointOnSide for rendering 2024-10-23 02:37:08 +02:00
Alug 19b1683e61 make those not look terrible thx 2024-10-22 01:18:13 +02:00
Alug d029107e75 refactor postimg stuff so it can be combined with each other better
thx much indev! <3
everything now works with encore!
software now also supports screen effects in splitscreen!
2024-10-22 01:17:57 +02:00
Alug bc97e0b703 actually remove "renderflags" lol 2024-10-21 22:53:44 +02:00
Alug f47c663f79 remove renderflags
those literally did nothing
2024-10-21 22:47:32 +02:00
Alug 6f9d41eadb fix R_ThingVisible
those are "eflags" in kart smh
2024-10-21 22:46:59 +02:00
Alug 1b512edc56 add proper null check here too 2024-10-21 21:28:08 +02:00
Alug 884a6da2bd dont use cv_sloperolldist in splitscreen + save some assignments and one fixedhypot call
also use tabs lul
2024-10-21 21:07:32 +02:00
Alug 7a3d958fc1 tab pls 2024-10-21 18:43:08 +02:00
Alug 7223581539 Clarify we're calculating a cross product 2024-10-21 18:10:29 +02:00
Alug 664bd2de3f dont draw fadescreen when minimap iss active 2024-10-21 17:47:44 +02:00
indev 63568e3861 Fix off-by-one error for using '?' as map name 2024-10-21 18:43:37 +03:00
indev f149d058a1 Fix off-by-one error in lib_setSfxInfo 2024-10-21 18:06:35 +03:00
Alug 970251ced3 also check here ig? 2024-10-21 17:01:27 +02:00
Alug dba7a7dc3c prevent map command crash from maps with invalid or non existing mapinfo 2024-10-21 15:37:44 +02:00
Alug 393c0be407 Revert "attempt to optimize some p_maputl stuff"
This reverts commit 81d415c5ba.
2024-10-21 14:19:35 +02:00
Alug 5e9ea2429b replace those two P_MobjWasRemoved with simple null check insteead
since those may actually segfault if null anyways
2024-10-21 06:23:14 +02:00
Alug 81a14995da trailing space hell 2024-10-21 06:14:24 +02:00
Alug 4267ac9a8d remove more P_MobjWasRemoved checks
same as before, those may be not synchsafe
2024-10-21 06:04:47 +02:00
Alug bcf72cc0e8 revert some P_MobjWasRemoved checks i forgor about
those may NOT be vanilla netsafe
2024-10-21 06:04:17 +02:00
Alug 54d9a98090 rotsprite stuff also should be SHORT 2024-10-20 19:11:54 +02:00
Alug 81d415c5ba attempt to optimize some p_maputl stuff 2024-10-20 16:25:12 +02:00
Alug de1b801bda try to take some registers for span drawers too 2024-10-20 16:24:02 +02:00
Alug 2c665fef6f remove this again 2024-10-20 15:21:42 +02:00
Alug c6fbf405bf optimize R_PointOnSegSide
its only used for 2 rendering functions, so being potentially inaccurate is not that dangerous and the speedup in some instances might be worth the tradeoff
2024-10-20 15:16:37 +02:00
Alug 7076c35521 HWR_RenderPlane can be static 2024-10-20 14:57:28 +02:00
Alug 86ed1b709e fix some rendering issues and crashes in software renderer
- Increase MINZ from 4 fracunits to 16
- R_StoreWallRange: do not render textures with holes
- fix off-by-one error in R_ProjectSprite
- Avoid rendering unused left/right edges of screen while rolling
- Clamp patch column post drawing bounds
- Vissprites: set dc.texheight
- Add null check for column in R_DrawMaskedColumn
2024-10-20 14:57:22 +02:00
Alug d30c96e8cb fix a maybe-uninitialized warning 2024-10-20 00:22:06 +02:00
Alug 0af52ba3ae dont need to always check this 16 times if we already know theres more than one player ingame 2024-10-19 21:15:11 +02:00
Alug fbe97556de change versionstring
also remove the fbo one, its honestly not necessary anymore
2024-10-18 20:36:16 +02:00
Alug 7a6f43bece dont show encore toggle text in record attack menu
dont think you can even record attack in encore hmm
2024-10-18 20:34:22 +02:00
Alug afca521fe5 dont run director if theres only one player ingame
idk if this is good lol
2024-10-18 19:53:44 +02:00
Alug d3e2875c94 those can be registered in lööp 2024-10-16 13:14:31 +02:00
Alug 1daac9a124 revert all the cam things for now here
Dont wanna deal with this shit for 7.1 anymore
2024-10-14 22:15:27 +02:00
Alug 38f3e48aed only do this in software renderer
doesent work even with pal rendering in ogl
2024-10-13 23:07:37 +02:00
indev 4cf4d49f48 Fix error handler staying on lua stack after lua commands being called 2024-10-13 15:37:39 +03:00
indev a19c4dc5e5 Fix game crashing when using P_DoPlayerExit on player without mobj 2024-10-13 15:37:39 +03:00
Alug d37505ff06 this should be SHORT 2024-10-13 02:59:10 +02:00
Alug 7f6ce1f299 this uhhh actually makes things crash lol 2024-10-13 02:47:57 +02:00
Alug 262a84aac6 fix ogl shearing
no clue wtf kart was doing here lmao
2024-10-13 02:42:37 +02:00
Alug 3f12ebb2bd only interp cam during pause for replay freecam to not jitter during pause 2024-10-13 01:11:59 +02:00
Alug b58fcf331c ignore keepmusic when called from P_RestoreMusic
most of the sound handling just calls this and this may just stop the music entirely on some occasions so just ignore keepmusic for that
2024-10-13 00:40:51 +02:00
Alug fe51278295 Merge branch 'newmusicstuff' into Saturn-Next 2024-10-13 00:04:59 +02:00
Alug c3fb84981e Merge branch 'pakcheck' into Saturn-Next 2024-10-13 00:02:32 +02:00
Alug 919aad4f30 Merge branch 'vres-skip-map-marker' into Saturn-Next 2024-10-12 23:57:27 +02:00
Alug 818e6046b7 Merge branch 'Saturn-Next' into vres-skip-map-marker 2024-10-12 23:30:03 +02:00
Alug f01d2a0ba6 print saturnpak print into debfile instead of console 2024-10-12 23:29:11 +02:00
Alug 8df0a2d059 Merge branch 'Saturn-Next' into pakcheck 2024-10-12 23:28:05 +02:00
Alug d7ed91af1d Refactor TTY input handling
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2451#b2f76b3273f1780347c35ec752bcde560c5f73a5
2024-10-12 23:26:14 +02:00
Alug 081dcc021b fix tty converting everything to lowercase 2024-10-12 23:21:11 +02:00
Alug 70ebd0d475 Merge remote-tracking branch 'origin/unified-text-input' into Saturn-Next 2024-10-12 23:19:38 +02:00
Alug 02bbb38606 Fix insane TTY input latency
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2360
2024-10-12 23:16:42 +02:00
indev d00014ea59 If corrupted save received, leave netgame 2024-10-12 22:10:58 +02:00
indev 210d6ac8ac Add few checks to prevent game crashing if netgame archive becomes corrupted 2024-10-12 22:10:48 +02:00
indev 55248e7fcf Attempt to fix a lua panic when unarchiveing extvars (print error to console instead. Not sure if it would be safe for game to read from save afterwards though) 2024-10-12 22:09:51 +02:00
Alug 23b36b5074 oops 2024-10-12 21:29:49 +02:00
Alug 2e7f0721b9 make s_sound a little prettier 2024-10-12 21:24:43 +02:00
Alug 4927e55c7e fix some warnings when compiling with older sdl version 2024-10-12 21:24:04 +02:00
Alug c51d33fa6e save 1 G_BuildMapTitle call kek 2024-10-12 20:19:53 +02:00
Alug 8630d8cd47 clean bird music stuff again
we dont need to return everywhere but instead stuff can be mostly just set to 0
this also somewhat ensures stuff works after toggling without having to restart the game or map
2024-10-12 19:55:02 +02:00
Alug 659243baa1 always assign stutter_threshold 2024-10-12 19:44:21 +02:00
Alug b6a84c1646 readd music_resync_powerups_only 2024-10-12 19:40:12 +02:00
Alug c33afa4a3b shut up mingw 2024-10-11 19:09:49 +02:00
Alug 1428c3c2bf fix spec cam bug + more cleanup 2024-10-11 21:00:13 +02:00
Alug aa0cbfda74 Revert "rendertimefrac_unpaused should be fracunit on netlag"
This reverts commit 6722b43244.
2024-10-09 15:33:19 +02:00
Alug 9d13ff3c9f proper inline P_MobjWasRemoved 2024-10-07 23:01:52 +02:00
Alug e47c13b7ac proper inline M_Memcpy 2024-10-07 23:01:45 +02:00
Alug 3f5b96bd45 this shouldnt be here lol 2024-10-07 13:15:08 +02:00
Alug 63c1372c34 keep debug print for now 2024-10-07 12:57:55 +02:00
Alug 8b915f9ac1 make this less ugly 2024-10-07 12:53:31 +02:00
Alug f3a18a0655 false 2024-10-07 12:48:36 +02:00
Alug e8351d44b6 add crap to menu 2024-10-07 12:45:03 +02:00
Alug 297af069cb doubt anyone wants this
also psure this will cause some weird issues somewhere idk
2024-10-07 12:41:59 +02:00
Alug baa5d6630d Merge branch 'Saturn-Next' into newmusicstuff 2024-10-07 12:39:41 +02:00
Alug 0c30730ef6 Merge branch 'Saturn-Next' into pakcheck 2024-10-06 18:52:24 +02:00
Alug c82148fafc prevent this from become super large somehow lol
just like cap it at 19 it works just fine
2024-10-06 18:50:32 +02:00
Alug d1346dee53 shouldnt that be a bool? 2024-10-06 18:31:54 +02:00
Alug 6722b43244 rendertimefrac_unpaused should be fracunit on netlag
makes this a little more sane tbh
2024-10-06 18:31:51 +02:00
Alug cfdbf1f4ad hopefully fix awayview cam interp crap 2024-10-06 14:53:10 +02:00
Alug 48a00ba911 this needs to be set twice
Zzz...
2024-10-06 14:52:54 +02:00
Alug 4b1102357a only do this in replays
otherwise shit will jitter during netlag
2024-10-06 14:46:11 +02:00
Alug e3b0204b2c fix main menu interpolation
apparently in main menu, opening the menu pauses the game so rendertimefrac was FRACUNIT and didnt interpolate
2024-10-06 14:46:06 +02:00
Alug a2799ddcca Interpolate view, even when paused
https://github.com/KartKrewDev/RingRacers/commit/3320faec8cebecb124882d38c7ec0ad37b79340a#diff-607b68058edc6124b3061267d902aabeddb6ba338c6483df0af8b1a7cf796a01R43
2024-10-06 14:46:03 +02:00
Alug 76198f61de add missing break 2024-10-06 14:45:50 +02:00
Alug ff2006ad74 smol fix 2024-10-06 12:40:01 +02:00
Alug 55c9c7297f throw this into own function too 2024-10-06 12:39:56 +02:00
Alug 4b083ee72e make function for quakes, scale with mobjscale 2024-10-06 12:39:54 +02:00
Alug 6574ec2fb9 attempt to cleanup R_SetupFrame 2024-10-06 12:39:48 +02:00
Alug f54bb349b5 add G_FixCamera 2024-10-06 12:39:44 +02:00
Alug 6f1252e27d set timeinmap for demo rewind
idk maybe this helps with that feature desynching all the time lol
2024-10-06 12:39:26 +02:00
Alug 7d65b5369f add some brackets lul 2024-10-06 12:34:51 +02:00
Alug 4877c81728 comment this out for now so v7 clients dont use vanilla resynch system
keep sending PT_WILLRESENDGAMESTATE packets to everyone for now
saturnpak will still mark the right clients so they will use the right consistency check without having to desynch first
2024-10-06 12:32:57 +02:00
Alug 5cb207edfa add debfile prints whenever gamestate counter changes 2024-10-06 12:14:32 +02:00
Alug fc39a0dedf make the debug print a little better 2024-10-06 12:12:59 +02:00
Alug 0b3e7240a8 use saturn packet to determine if client can receive gamestate
before the server always assumed every client cant receive the gamestate using the vanilla consistency check for everyone.
aswell as before the first resynch it tried to send the gamestate resend packets to everyone
2024-10-06 12:07:17 +02:00
Alug f32c346534 this needs gamestate check
sometimes the title music kept playing
2024-10-05 06:56:31 +02:00
Alug 3165004d0e add comment to try and explain this crap 2024-10-03 18:15:19 +02:00
Alug ec3b1cf130 make this more readable 2024-10-03 17:55:08 +02:00
Alug a0437713bf smol dupe 2024-10-02 14:40:03 +02:00
Alug 96f7ff550c prevent this from overflowing
ye well idk anymore.
2024-10-02 14:22:48 +02:00
Alug 837216d78e we dont need any of this in ogl 2024-10-02 14:22:39 +02:00
Alug dfb6006f9c fix up old fps counter 2024-10-02 12:14:40 +02:00
indev fb0765a5f3 Fix selection in replay save prompt 2024-10-01 20:55:27 +03:00
indev 2e8769496f Use textinput_t for replay save prompt too 2024-10-01 20:39:04 +03:00
Alug bdb39fcd8d dont leak pls 2024-10-01 17:57:45 +02:00
Alug 31516c7987 fix G_BuildMapTitle leaks 2024-10-01 17:56:15 +02:00
Alug b985ce06a2 lol 2024-10-01 16:03:56 +02:00
Alug 12d6546062 dumb special case for wandering balls Zzz... 2024-10-01 16:03:00 +02:00
indev fb71da3627 Remove debug print 2024-10-01 16:50:44 +03:00
indev a90ffff320 Fix (hopefully) all other menu types that use IT_CV_STRING 2024-10-01 16:49:59 +03:00
Alug 9abf2bca75 fix some stuff 2024-10-01 15:46:22 +02:00
indev 3db6770dfd Fix IT_CV_STRING crashing game in M_DrawGenericMenu 2024-10-01 16:24:14 +03:00
Alug 3a951576ee use stricmp for this 2024-10-01 15:22:29 +02:00
Alug 6b0d67ac36 more 2024-10-01 15:22:25 +02:00
Alug d06b8ac398 cleanup + comments 2024-10-01 15:22:22 +02:00
Alug 67435ebf9e work around encore music again
S_InitMapMusic would play before the level actually started thus playing a smol bit of non encore music in encore
2024-10-01 15:22:19 +02:00
Alug 2ee29630fb fix encore music again lol 2024-10-01 15:22:16 +02:00
Alug 7fa21e9aea work around custom vote theme music + rename a bunch of stuff
please help me
2024-10-01 15:22:08 +02:00
Alug b4b206f575 encoremusic... 2024-10-01 15:22:04 +02:00
Alug f363663b3e fix up everything and make stuff work
i hope lmao
2024-10-01 15:22:01 +02:00
Alug 42d957e21b change how keepmusic works
compare map and encore instead of the music itself
2024-10-01 15:21:57 +02:00
Alug 07f9756bc8 forgor about encore music 2024-10-01 15:21:54 +02:00
Alug e958e43b49 update comments a little 2024-10-01 15:21:51 +02:00
Alug 0d150e4b08 add some basics of what i wanna have for music stuff
- basic keepmusic implementation (currently checks for if the song changes instead of the map, idk if i keep this, since this allows certain maps to change the music on start, ex abstract avenue or wandering balls)
- Toggle to ignore any kind of music change during the level (includes intermission music, depends on how custom intermission music works)
-toggle to start map music instantly on levelload and skip the intro fanfare (also skips any linedef executed sound so some map intros dont interfere with this)
2024-10-01 15:21:47 +02:00
Alug 0deff73a46 make a function for the music level start stuff 2024-10-01 15:21:43 +02:00
Alug b24caf397a add "map ?" shortcut for random map 2024-10-01 14:49:46 +02:00
Alug f051e33a0c cv_showdirectorhud didnt save Zzz... 2024-09-30 23:00:39 +02:00
indev ff2b28ac73 Use m_textinput for chat too 2024-09-30 12:13:25 +03:00
indev e2367d26d1 Use same keyboardlayout code as in chat for textinput, also add a null terminator after ctrl-v just in case string is not always zeroed out already 2024-09-30 12:08:21 +03:00
indev e1a65add5d Put all text input logic into separate file and use it for all text input fields 2024-09-30 10:35:27 +03:00
Alug 913426bfdb let SOC also use PRECIP_BLANK/ weather = 4
no idea why it couldnt doesent make any sense
2024-09-29 22:28:35 +02:00
Alug d7b0726e42 no need to even traverse part of the blockmap when PRECIP_STORM_NORAIN and PRECIP_BLANK 2024-09-29 22:28:31 +02:00
Alug cadb67e6c9 move this stuff
so dont need check for renderisnewtic multiple  times and dont need to check for menu and dpad stuff every single frame
2024-09-29 15:15:53 +02:00
Alug 564838a439 only draw lua hud stuff when patch exists 2024-09-29 15:15:49 +02:00
Alug 4554bcc565 reset rumble on some conditions 2024-09-28 03:29:12 +02:00
Alug fd48335688 Replace portalline boolean with g_portal pointer to current portal Beta 2024-09-28 03:29:09 +02:00
Alug 222f56d1b2 smol director stuffs 2024-09-28 01:03:44 +02:00
Alug b71870f57b this needs no dedi check actually 2024-09-28 01:03:41 +02:00
Alug 01c9632025 set those in P_SpawnGhostMobj too 2024-09-28 01:03:39 +02:00
Alug 1533e13d68 let player pointer be const in P_IsLocalPlayer and P_IsDisplayPlayer 2024-09-28 01:03:34 +02:00
Alug 89965ad718 forgor remove this 2024-09-28 01:03:31 +02:00
Alug eb74f3525a consolidate this 2024-09-28 01:03:29 +02:00
Alug 536f88dee0 this does nothing 2024-09-28 01:03:26 +02:00
Alug 2622ba286e z 2024-09-28 01:03:18 +02:00
Alug a1d490cb49 R_DrawMaskedColumn: do not draw zero length column 2024-09-28 01:03:15 +02:00
Alug b357c09171 those should be size_t 2024-09-28 01:03:11 +02:00
Alug 48e71afec1 update lzf compression to 1.6 2024-09-28 01:03:08 +02:00
Alug 1c6fce9339 fix encore minimap 2024-09-27 15:05:38 +02:00
Alug 96551d3b75 use qs22j here again
it is really faster
thought it wasnt in this case
2024-09-27 15:05:34 +02:00
Alug 7a832df4d3 cleanup + reformatting 2024-09-27 15:05:31 +02:00
Alug c3b6121968 forgor this 2024-09-27 15:04:15 +02:00
Alug b3b2b65c5f reformat this 2024-09-27 15:04:12 +02:00
Alug 7a3ccec38d ; 2024-09-26 18:18:42 +02:00
Alug d8da0a11a2 gamestate resend counter was never proper reset for nodes
means it would carry over to the next person occupieing that node and made them have less chances to get the gamestate resent
2024-09-25 19:31:25 +02:00
Alug d5c3332635 those can be static 2024-09-24 22:23:29 +02:00
Alug 0137f2254d add toggle for water ripples Zzz... 2024-09-24 22:18:27 +02:00
Alug da769ce524 only allow director toggling with button when you spec someone 2024-09-24 16:57:25 +02:00
Alug 2e99636bb0 make director text disappear after 13 seconds, and in replays after 4 2024-09-24 15:25:56 +02:00
indev ff7f68f5b4 Expose demo.freecam as replayfreecam 2024-09-24 16:05:22 +03:00
Alug 14eec0c902 dont show director text when in replay freecam 2024-09-24 15:03:31 +02:00
Alug b064c534d8 hide viewpoint text when in replay freecam 2024-09-24 15:03:28 +02:00
Alug e7c0f322ee dont show driftgauge when in replay freecam 2024-09-24 15:03:14 +02:00
Alug 725754c427 dont run director when you use spectator freecam 2024-09-24 15:03:07 +02:00
Alug 9a6c0a0280 check vres data before freeing it 2024-09-23 23:13:08 +02:00
Alug 26d8c05ce7 forgor some casting 2024-09-23 23:13:05 +02:00
indev 91a9f20af7 Skip map marker in vres_GetMap 2024-09-24 00:08:48 +03:00
indev 90745d91aa Add showdownloadprompt cvar, so addon download prompt can be disabled 2024-09-23 23:39:25 +03:00
Alug 0dbae34998 completely forgor to revert this lol 2024-09-23 15:53:05 +02:00
Alug eec93b8013 Revert "beta hud driftgauge"
This reverts commit 26e8c2ca2b.
2024-09-23 01:35:14 +02:00
Alug cfe3f01b32 Revert "extra check"
This reverts commit 0bb1efcd50.
2024-09-23 01:35:11 +02:00
Alug 43452e1af4 dont actually call Nullprecipthinker 2024-09-23 01:03:59 +02:00
Alug a4706e0785 read precip row in perfstats 2 2024-09-23 01:03:24 +02:00
Alug c921ab463c dont count precip towards thinkers in perfstats 2024-09-23 01:03:20 +02:00
Alug 892816dadf fix precip performance issuess on certain maps 2024-09-23 01:03:17 +02:00
Alug e7e1fd711e dont check consistency/attempt to resend the gamestate while a client is currently getting the save resend
perhaps that makes mass synchs less bad
2024-09-22 22:16:21 +02:00
Alug ba5459eeb6 Revert "clean up leveload a bit"
This reverts commit c14af4a136.
2024-09-22 17:52:26 +02:00
Alug 0bd9c696df try to prevent unknown packet type spam when client attempt to connect while levelloading 2024-09-22 16:53:31 +02:00
Alug c14af4a136 clean up leveload a bit 2024-09-22 16:53:25 +02:00
Alug 8dfa841a7b Load palette before map data 2024-09-22 16:52:07 +02:00
Alug a6de843c75 cleanup r_draw8 2024-09-22 16:52:04 +02:00
Alug 0bb1efcd50 extra check 2024-09-22 04:14:31 +02:00
Alug 26e8c2ca2b beta hud driftgauge
eh needs some stuff for menu still
also should replace driftgauge gfx sometime
2024-09-22 04:13:53 +02:00
Alug 12ffca7374 precalc automap and minimap stuff on mapload instead of every frame 2024-09-22 04:13:02 +02:00
Alug 6ecf65d83a Merge remote-tracking branch 'origin/Saturn-Next' into Saturn-Next 2024-09-21 16:03:17 +02:00
Alug 231c173545 move this so speccing resets your laptime 2024-09-21 16:03:13 +02:00
Alug f12b7fd772 move this 2024-09-19 12:41:40 +02:00
Alug 14ea041c72 always reset cam subsector regardless of splitscreen 2024-09-18 12:11:14 +02:00
Alug 6fb804292c Prevent integer div by 0 in curl progress callback 2024-09-18 01:07:43 +02:00
Alug f77f7361a9 this also does nothing 2024-09-18 01:06:54 +02:00
Alug d6d19d5dab smol cleanup 2024-09-18 01:02:42 +02:00
Alug 8074bfacb6 this does nothing 2024-09-18 00:58:37 +02:00
Alug f5f7b99479 Fix crash if a packet fails to reach the client
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2480 but keeps the returns;
2024-09-17 21:02:05 +02:00
Alug f0a8c27829 Fix crash when trying to send to an unreachable client
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2232
2024-09-17 20:58:23 +02:00
Alug 30024f2341 this is the correct value 2024-09-17 19:47:30 +02:00
Alug ff0dcafeea make ticcmds on gamestateresend
resynch will still stop making em
should hopefully fix some weird issues where you might end up somewhere weird if the resend takes a little longer
2024-09-17 16:47:34 +02:00
Alug 8580451bce properly reset all splitscreen cameras on resynch
also fix some casting
2024-09-17 16:47:31 +02:00
Alug d867868854 Revert "dont run playerjoin hook on resynch"
This reverts commit 5f7bf4164d.
2024-09-17 16:43:25 +02:00
indev b1644d4817 Ignore case here 2024-09-17 17:23:16 +03:00
indev a9a3a04379 Add proper skin search in skin command 2024-09-17 17:16:35 +03:00
Alug 7ac9f0cbef dont rerun mapload hook on resynch 2024-09-16 00:54:29 +02:00
Alug 5f7bf4164d dont run playerjoin hook on resynch 2024-09-16 00:54:26 +02:00
Alug 43690c9b2c fix sound bug lol 2024-09-16 00:08:21 +02:00
Alug 02c14bfa5c Merge branch 'Saturn' into Saturn-Next 2024-09-16 00:08:11 +02:00
Alug 0544811c7d Merge pull request #135 from Indev450/Saturn-Next
Saturn v7
2024-09-15 13:02:42 +02:00
Alug e079bac283 make advanced server menu scroll menu
grrrrr green res
2024-09-15 12:03:20 +02:00
Alug 862f1fce2c ... 2024-09-15 12:03:16 +02:00
Alug 5aeb78f2a5 Merge pull request #134 from Indev450/absolutehell
Huge Netcode/Resynchcode changes
2024-09-15 11:45:35 +02:00
Alug cb42bc581b squish options menu a little
im honestly too lazy too move shit around just before release lmao
2024-09-15 11:43:44 +02:00
Alug 5fc9410b59 Merge branch 'Saturn-Next' into absolutehell 2024-09-14 22:23:51 +02:00
Alug 84d3ee7170 maths..... 2024-09-14 22:23:11 +02:00
Alug accef8f1e1 version change 2024-09-14 21:10:55 +02:00
Alug 4a8edff694 Merge remote-tracking branch 'origin/Saturn-Next' into absolutehell 2024-09-14 21:01:08 +02:00
Alug aac3b8d025 forgor this one 2024-09-14 19:45:23 +02:00
Alug 4034658e44 some cleanup 2024-09-14 19:44:01 +02:00
Alug 7d4898dd8b remove code dupe in r_segs 2024-09-14 18:43:13 +02:00
indev 71fe6ec9da should be != here 2024-09-14 19:04:51 +03:00
indev 075097c219 Don't default to sonic if skin was changed to unknown skin, use current skin instead 2024-09-14 16:40:17 +03:00
Alug f70ec60ae4 use continues in hooklib loops too
idk if this is any faster, but it makes smth i wanna port over potentally easier
2024-09-14 12:35:29 +02:00
Alug aeafd46f24 smol m_menu cleanup 2024-09-13 14:17:13 +02:00
Alug 5f57044118 replace tooltip crap with a macro + fix adv video options tooltips 2024-09-13 14:02:15 +02:00
Alug 65006c11d3 move credits a tiny bit 2024-09-13 13:37:10 +02:00
Alug 76bc184f6c whoops wrong tooltip 2024-09-13 13:35:18 +02:00
Alug dd39a444f2 add smol comment 2024-09-13 13:30:30 +02:00
Alug 1a16012a5c this used to be const 2024-09-13 13:22:51 +02:00
Alug c49aae8d49 no need to save saturnjoin value + smol cleanup 2024-09-13 13:21:25 +02:00
Alug d5dc52d3d3 super smol optimization R_ThingWithinDist
no need to run fixedhypot on every sprite when you dont use draw distance limit
2024-09-13 12:44:38 +02:00
Alug 4f1f1ede97 smol menu visual cleanup 2024-09-13 12:33:49 +02:00
Alug c98b896fc8 add old line whatever in intermission add beta intermission visual to menu 2024-09-13 12:33:02 +02:00
Alug 3714735c2a small cleanup intermission drawer 2024-09-13 12:32:59 +02:00
Alug 025cc093db Merge remote-tracking branch 'origin/Saturn-Next' into absolutehell 2024-09-13 10:48:34 +02:00
Alug 924d79c20d only need to check all this when in splitscreen
retains vanilla behaviour
2024-09-13 00:23:07 +02:00
Alug 0926f68776 clean up sprite stuff 2024-09-13 00:16:35 +02:00
Alug 26f3806b3c fix wöter shader interpolation
accidentally reverted that when redoing palette rendering
2024-09-12 22:43:14 +02:00
Alug d628320c8d forgor this 2024-09-12 01:05:07 +02:00
Alug 41fc4c7cfd delete DEH_WriteUndoline
it literally does nothing lol
2024-09-12 01:05:05 +02:00
Alug 1c8ca2b110 apparently this always runs
i am in pain
2024-09-11 21:10:41 +02:00
Alug 241d107485 let item button toggle encore in mapselect screen
guh
2024-09-11 21:10:38 +02:00
Alug 8d0601c2ad add missing masterserver ifdef 2024-09-11 21:10:35 +02:00
Alug 31118254a0 this can be int16 2024-09-10 19:56:52 +02:00
Alug 85a1636776 Revert "smol optimization to HWR_AddLine"
This reverts commit 77c9badeca.
2024-09-10 10:58:15 +02:00
Alug 3b227932e9 Revert "smol optimization R_AddLine"
This reverts commit 677cdc77e4.
2024-09-10 10:58:12 +02:00
Alug ff591bce04 Revert "Zzz..."
This reverts commit c3a03d89c4.
2024-09-10 10:58:09 +02:00
Alug c3a03d89c4 Zzz... 2024-09-10 10:31:25 +02:00
indev dd405532af Snap title demo logo to bottom right corner 2024-09-09 23:56:53 +03:00
Alug 677cdc77e4 smol optimization R_AddLine 2024-09-09 22:57:21 +02:00
Alug f9463d8efa smol cleanup 2024-09-09 22:57:18 +02:00
Alug 77c9badeca smol optimization to HWR_AddLine 2024-09-09 22:57:15 +02:00
Alug 926287eb97 remove redundant check 2024-09-09 22:57:12 +02:00
Alug 7a91b19962 only change lightlevel/colormap behaviour in palette rendering 2024-09-09 21:51:09 +02:00
Alug c148ff5a05 fix off by one in sprite lightlevels 2024-09-09 21:51:06 +02:00
Alug ef7e658f9d Merge branch 'Saturn-Next' into absolutehell 2024-09-09 18:51:37 +02:00
Alug 0e9b9d15ea revert this ig 2024-09-09 18:51:23 +02:00
Alug dd2d437a21 Merge branch 'Saturn-Next' into absolutehell 2024-09-09 16:05:16 +02:00
Alug b9779d4dba add toggle for director prompt
cause ik some ppl will complain lol
2024-09-09 16:05:08 +02:00
Alug 1d40d8c4ef make this less complicated lol 2024-09-09 15:58:45 +02:00
Alug 847b1f5cb7 fade director hud after 4 secs after toggling it 2024-09-09 15:58:43 +02:00
Alug 9448a98573 disable director on title screen and record attack demos 2024-09-09 09:25:06 +02:00
Alug 14bce36b95 make it static actually 2024-09-08 23:36:57 +02:00
Alug ba4c54004a turn off director by default when playing replays and restore the setting when done
you can  still toggle it in replays no issues
but you mostly want to watch yourself or a certain person during replays, so having to manually toggle it off always is weird
2024-09-08 23:34:35 +02:00
Alug 9fdfc09229 dont trigger rumble in offroad when under hyu effect 2024-09-08 23:09:17 +02:00
Alug b19bc7d77e slight portal cleanup 2024-09-08 16:53:52 +02:00
Alug 58815ae9c4 fix potential rendering issues on large maps 2024-09-08 16:45:50 +02:00
Alug 0b12c9b5a8 smol cleanup 2024-09-08 16:45:48 +02:00
Alug 863abe86ca oops 2024-09-07 20:09:49 +02:00
Alug f54d2fb0fe clean up and improve ogl portals 2024-09-07 20:09:45 +02:00
Alug 8824ba3824 this is literally broken and noone knows about it anyways lol 2024-09-07 17:52:24 +02:00
Alug 8a8db796be Show a console error if the gamestate contains too many tables 2024-09-07 17:30:08 +02:00
Alug 4f532b766f this needs to be shifted 2024-09-07 17:04:06 +02:00
Alug e175a4e00b guh 2024-09-07 16:57:41 +02:00
Alug 473e843142 this should use angleturn
uhhh
2024-09-07 16:46:29 +02:00
Alug ef8e71cb11 set camera angle to player angle in CL_ReloadReceivedSavegame
hope i did this right lol
should hopefully fix more jarring visual stuffs
2024-09-07 16:28:17 +02:00
Alug ea985151dd dont rerun levelload executors when gamestate resent 2024-09-07 16:27:35 +02:00
Alug 62fae0ad8b dont print "Map is now" everytime you resynch from gamestate resend 2024-09-07 16:27:32 +02:00
Alug f9210ee3bc smol fixes for gamestate resend in P_SetupLevel
- dont reset cameras during gamestate resynch
- dont reinit director during gamesate resynch
- dont reset view interpolators aswell
- dont reset localaiming aswell

should make resynching less jarring visually hopefully
2024-09-07 15:35:41 +02:00
indev d5101dd0b2 Document changes to lua P_PlayRinglossSound and K_PlayHitEmSound functions 2024-09-07 11:47:09 +03:00
Alug 2a7940bfd1 Merge branch 'Saturn-Next' into absolutehell 2024-09-06 22:37:53 +02:00
Alug 047d38daab Merge branch 'noZ_unlock' into Saturn-Next 2024-09-06 22:37:39 +02:00
Alug 2d61f5c861 add compiler flags NOSATURNSYNCH, NOSATURNJOIN and NOSATURNPAK
not building with SATURNSYNCH also will disable SATURNJOIN since it makes not much sense to have that when synch stuff is unused
2024-09-06 21:41:53 +02:00
Alug 750f305c46 % 2024-09-06 21:06:06 +02:00
Alug 51b79e58d3 smol cleanup + add comments 2024-09-06 21:05:33 +02:00
Alug 915b4e9d15 set netgame save stuff to false for replays
to retain max vanilla compat for replays
dont want those breaking between clients
2024-09-06 21:05:30 +02:00
Alug c9c0c06763 reserve saturn packet even if unused
to not cause any weird isssues if either one is undefined and stuff like that
2024-09-06 20:36:27 +02:00
Alug 406037dabe menu offset stuff for if not using SATURNSYNCH 2024-09-06 20:06:57 +02:00
Alug d9affe2331 oops again 2024-09-06 19:59:45 +02:00
Alug 6df675523f hide gamestate resynch stuff behind SATURNSYNCH ifdef 2024-09-06 19:55:34 +02:00
Alug 65e66e8ace oops 2024-09-06 19:55:32 +02:00
Alug 5efb0c7136 put saturn specific join allow stuff behind SATURNJOIN define
so it can be seperate from SATURNPAK
2024-09-06 19:25:02 +02:00
Alug 1793340474 Merge branch 'Saturn-Next' into absolutehell 2024-09-06 19:13:31 +02:00
Alug d10db6d1d2 make this completely toggable actually 2024-09-06 18:51:06 +02:00
Alug 9eefbcea72 only save demo in map command if you atleast spend 35 seconds in one map 2024-09-05 18:34:50 +02:00
Alug d56b70a8e7 toggle for saving replays on changing to same map 2024-09-05 10:52:45 +02:00
Alug 54ebb9dfec test also save replay on mapchange command 2024-09-05 10:52:42 +02:00
Alug 43b6597ec0 this should also check for screentex cvar value 2
dont run certain postprocessor effects when you dont have screentextures enabled
2024-09-04 23:45:08 +02:00
Alug b7d887d610 add a little bit of safety to R_SetupFrame 2024-09-04 23:31:54 +02:00
Alug ff9b35ab45 remove IFCHANGED macro, check directly in R_Lerp funcs + inline those
basically does the same thing lol just looks better
2024-09-04 18:49:16 +02:00
Alug 20b5175180 scale precip momz with mobjscale when cv_mobjscaleprecip enabled 2024-09-04 18:48:13 +02:00
Alug 596c8e2ecc also scale precip sprite with mobjscale when cv_mobjscaleprecip enabled 2024-09-04 18:48:08 +02:00
Alug 94218a6549 only call HWR_RenderPlayerView in ogl explictly 2024-09-04 18:48:05 +02:00
Alug 2d36f798e7 Merge branch 'Saturn-Next' into absolutehell 2024-09-04 15:26:42 +02:00
Alug 853004dad9 smol cleanup for led stuff again 2024-09-04 15:26:31 +02:00
Alug 0cc86430ca smol cleanup hw_shaders 2024-09-04 15:26:28 +02:00
Alug 8760886f57 smol cleanup p_map 2024-09-04 15:26:24 +02:00
Alug 821669d03d Revert "optimize z position checking for mobjs without collision and camera"
This reverts commit c11d925580.
2024-09-04 15:23:28 +02:00
Alug 17f8996afc revert pretty much all mobj changes for now
might reapply them some other time, but since we need to maintain vanilla compat as much as possible gonna revert crap
kinda sick of desynching stuffs and honestly most the mobj stuff rarely ever crashes
2024-09-04 15:23:14 +02:00
Alug 7ef4eedd06 Revert "optimize pointon functions"
This reverts commit 94ddd01427.

may be readded in v7.1 
since this is pretty sensitive code and i dont want to desynch or crap so this def needs more testing
2024-09-04 15:04:54 +02:00
indev df6a31767e Make server send serverinfo packet so client can know server name even when connecting just by ip 2024-09-02 21:47:02 +03:00
Alug 882a3b7824 revert this 2024-09-02 17:58:35 +02:00
Alug 94ddd01427 optimize pointon functions 2024-09-02 17:46:41 +02:00
Alug e614decae0 optimize MT_TUBEWAYPOINT
Store waypoints at map load instead of iterating through the thinker list to find them

https://git.do.srb2.org/STJr/SRB2/-/merge_requests/938
2024-09-02 17:45:57 +02:00
Alug e0f46ea80d oop 2024-09-02 17:44:55 +02:00
Alug 3391018606 some stuffs from lugstuff
mostly just cleanup and smoler optimizations
2024-09-02 17:40:05 +02:00
Alug 61fd11f7cd those are unused 2024-09-02 14:23:24 +02:00
Alug 4a469aebdc dont draw precip in skyboxes in opengl like software does 2024-09-02 14:23:22 +02:00
Alug 341815c0ed this can be static 2024-09-02 14:23:19 +02:00
Alug 5830270bda optimize polyobject spawn
should speed up level loading with maps with polyobjects
thx geezeedoom
2024-09-02 14:23:16 +02:00
Alug 8a1ff58dff free texture patchlumps proper in R_LoadTextures
drastically reduces ram usage
2024-09-01 20:43:40 +02:00
Alug 0523d98a1c Test: remove Z_Unlock and proper free some stuff 2024-09-01 20:41:42 +02:00
Alug 983af4e7a1 Merge branch 'Saturn-Next' into absolutehell 2024-08-31 20:19:42 +02:00
Alug f8bec7296c no idea why i put those here 2024-08-31 20:19:12 +02:00
Alug 2be4bd3d6a update camera when paused and changing cam dist or height 2024-08-31 20:15:41 +02:00
Alug 7d74296604 throw menu bg conditions into own function since it s terrible 2024-08-31 19:53:09 +02:00
Alug 0504a355d2 add camera options menu 2024-08-31 19:52:35 +02:00
Alug 036df817f1 give camera lookback a toggle + extra option 2024-08-31 18:46:01 +02:00
Alug ba331caff6 when looking back camera momentum should inherit the mom of the player
makes using shoes or any boost stuff less jarring when looking back
2024-08-31 18:45:58 +02:00
Alug e2ac9708cb super tiny cleanup m_menu again 2024-08-31 18:45:55 +02:00
Alug 783ce7bada give camera lookback a toggle + extra option 2024-08-31 18:45:47 +02:00
Alug 594931e07e when looking back camera momentum should inherit the mom of the player
makes using shoes or any boost stuff less jarring when looking back
2024-08-31 18:45:43 +02:00
Alug 3e245d49d8 super tiny cleanup m_menu again 2024-08-31 18:45:36 +02:00
Alug 76ed4aae12 forgor speedo doesent draw in splitscreen + change offsets 2024-08-31 18:11:06 +02:00
Alug 565f36d4b7 forgor speedo doesent draw in splitscreen + change offsets 2024-08-31 18:10:59 +02:00
Alug 75a94b050d Merge branch 'Saturn-Next' into absolutehell 2024-08-31 18:01:34 +02:00
Alug 91fac0880d add battlespeedometer to saturn hud menu + apply offset to bumper gfx when enabled 2024-08-31 18:01:22 +02:00
Alug 42fa29f78b make timer flash at 99´59´99 again 2024-08-31 17:39:30 +02:00
Alug 28d8e84d6b this can be static and inlined 2024-08-31 16:53:33 +02:00
Alug c11d925580 optimize z position checking for mobjs without collision and camera
idk how much this does tbh
only for stuff without collision since it may desynch otherwise

based on
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2214

and

https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2250
2024-08-28 02:35:42 +02:00
Alug d7c1b12dbd changes to saturn menu
-Add new Saturn Hud options menu to declutter normal saturn options
- If in any of the hud options the game will force display the kart hud and disable the fade background
- i hate m_menu
2024-08-27 18:26:18 +02:00
Alug e2c3d5b20d respawn precip when toggling any of its settings 2024-08-27 16:41:19 +02:00
Alug 8581d87e41 toggle to scale weather with mobjscale
toggle since it may tank performance on certain maps for some + may make visability worse
2024-08-27 16:27:28 +02:00
Alug fe853d4bee fix compileur warnings
idk if this is right lol
2024-08-27 06:07:38 +02:00
Alug b8038130b8 fix conflict 2024-08-27 05:51:35 +02:00
Alug 31c5d8d67c fix precip switching 2024-08-27 05:44:31 +02:00
Alug a2f4430378 stuff 2024-08-27 05:44:27 +02:00
Alug a8e4f6e2ea Reapply "lol"
This reverts commit 340450a67e.
2024-08-27 05:44:20 +02:00
Alug aac89f270b Reapply "optimize precip thinker"
This reverts commit dd73787c8b.
2024-08-27 05:44:13 +02:00
Alug 9022e02ccd fix potential crash in P_TryCameraMove for dedi servers 2024-08-23 15:31:58 +02:00
Alug 5ddd2e4fbc cleanup P_DoSuperTransformation
its still exposed to lua for whatever reason
so cant really remove crap kek
2024-08-23 15:31:55 +02:00
Alug 3b500add73 cleanup birdmusic crap again
music_resync_powerups_only literally didnt do shit lol
removed some other unused crap
changed some conditions to better check for stuff
etc idk
i just rather remove this whole thing at this point but oh well
2024-08-23 15:31:52 +02:00
Alug 4a6635f8a8 Revert "smol interp fixes"
This reverts commit 77a2976d05.
2024-08-22 14:54:43 +02:00
Alug af6393af50 forgor 2024-08-21 15:38:46 +02:00
Alug 6a14543e9e cleanup FBO on shutdown + make some stuff static 2024-08-20 23:26:43 +02:00
Alug 3d827570e6 more changes to FBO stuff
now it wont ever do anything when disabled
also properly deletes the FBO when disabling it
2024-08-20 23:18:35 +02:00
Alug 9f8eb07442 revert this in y_inter 2024-08-20 21:33:41 +02:00
Alug 31c64b63de make this more robust ig 2024-08-20 03:57:49 +02:00
Alug cf5c0ca5f7 forgor return 2024-08-19 21:54:22 +02:00
Alug f0d91a9708 do not constantly query ogl extensions 2024-08-19 21:48:56 +02:00
Alug 0f94a26dc6 dumbass workaround for issues on xwayland with nvidia
this will run automatically when it detects an nvidia gpu even with gr_framebuffer disabled lol

we have safeguards everywhere so shouldnt be an issue
2024-08-19 19:37:02 +02:00
Alug cded0af061 change some stuff for saturn 2024-08-19 17:51:35 +02:00
NepDisk fffa7e44c5 Appimage compile pt2 2024-08-19 17:51:31 +02:00
NepDisk a38aee7fe3 Appimage compile pt1 2024-08-19 17:51:29 +02:00
Alug 4d03fa06e1 raise maxpng res 2024-08-19 17:51:26 +02:00
Alug dcd470b2e1 Merge branch 'Saturn-Next' of https://github.com/Indev450/SRB2Kart-Saturn into Saturn-Next 2024-08-19 14:58:08 +02:00
Alug 2259ef3f71 Update LUASTUFF
idk i suck at explaining lmao
but atleast those should be mentioned
2024-08-19 14:58:01 +02:00
indev af18e2b7d1 Don't execute exitgame command on dedicated servers 2024-08-19 14:14:59 +03:00
indev 9e8d79f246 Fix compilation when SDL_VERSION_ATLEAST(2,0,18) is false (if its false then 'else' statement would not be valid) 2024-08-19 14:14:17 +03:00
Alug 5b480be6dc smol cleanup for downsample stuff 2024-08-19 12:16:32 +02:00
Alug 54d897fc33 smol i_video cleanup 2024-08-19 12:15:47 +02:00
Alug cfebe422d3 Fix typo 2024-08-19 12:00:27 +02:00
NepDisk fcc5c13274 Fix Compile without with out of date SDL 2024-08-19 11:59:48 +02:00
Alug 707448193b Fix some tooltips so they don't go offscreen
grr git not crediting neppy for some reason
2024-08-19 11:59:45 +02:00
NepDisk 84a1f86037 Allow the control binds menu to use lower case 2024-08-19 11:59:42 +02:00
NepDisk b2129011c2 Fix gamepad menus for green reses via scrolling 2024-08-19 11:59:38 +02:00
Alug 9d359ef8c5 use qsort instead of qs22j for vissprite sorting
seems to be actually faster in this case
2024-08-19 11:59:35 +02:00
Alug 87a2b74a88 this should not be in HWRENDER ifdef 2024-08-19 11:59:33 +02:00
Alug d5388e8dad fix NOHW compile 2024-08-19 11:59:29 +02:00
Alug fe7677c5c8 Revert "Do not access memory on misaligned addresses"
This reverts commit 112716dae5.
2024-08-19 11:59:25 +02:00
Alug f36ac0bb4b this should not be in HWRENDER ifdef 2024-08-17 20:03:35 +02:00
Alug d24bcc9fd7 fix NOHW compile 2024-08-17 20:01:46 +02:00
Alug daf8151a32 Revert "Do not access memory on misaligned addresses"
This reverts commit 112716dae5.
2024-08-17 19:56:14 +02:00
Alug b432491d34 throw saturnpacket and join stuff behind "SATURNPAK" ifdef, disable it for now 2024-08-17 19:54:56 +02:00
Alug 1313b4c112 Merge branch 'Saturn-Next' into absolutehell 2024-08-17 19:43:42 +02:00
Alug 164d7399d2 smol fix to slope light 2024-08-17 16:31:09 +02:00
Alug 87176cfd0b better slope light 2024-08-17 16:09:43 +02:00
Alug bab96b73e0 smol changes 2024-08-17 16:09:40 +02:00
Alug f10db3900a Use a const for the contrast 2024-08-17 16:09:37 +02:00
Alug 7d4b1d0852 Update light offset on polyobjects when they rotate 2024-08-17 16:09:34 +02:00
Alug 6ab99218f2 precalc fakecontrast on mapload 2024-08-17 16:09:31 +02:00
indev 1959edf357 Always allow typing replay search query, similar to addon search 2024-08-16 01:58:33 +03:00
indev 6fc2681b34 Add 'Hit Em Delay' option in menu 2024-08-16 01:51:29 +03:00
indev 02dcf85c46 Prioritize display players when assigning delayed 'hit em' 2024-08-16 01:51:29 +03:00
indev 89f0521cce Oops forgot to change that
Dunno if this function ever gets called for non-player objects but just in case
2024-08-16 01:51:28 +03:00
indev 35029e826f Add delayed hit em sound (like in DRRR), togglable via 'karthitemdialog' cvar 2024-08-16 01:51:28 +03:00
Alug f6c170b53c add onchange func for led + fix rumble onchange 2024-08-16 00:34:16 +02:00
Alug 7991a5ce5e Merge branch 'Saturn-Next' into absolutehell 2024-08-16 00:09:46 +02:00
Alug 3973851dd2 add toggles for gamepad led stuff 2024-08-16 00:09:08 +02:00
Alug f6361e29bd reset rumble when player is exiting 2024-08-16 00:08:52 +02:00
Alug 9f8db631f0 reset rumble when player is exiting 2024-08-15 23:46:02 +02:00
Alug ada1de7ad6 dont change connect behaviour regardless of client + smol cleanup and fixes
should hopefully fix any remaining issues
2024-08-15 23:44:48 +02:00
Alug ac55d473e7 smol cleanup 2024-08-15 17:34:58 +02:00
Alug 2100f11af7 remove duplicates in ResetNode 2024-08-15 17:34:55 +02:00
Alug ea1b5cd1a9 Merge branch 'Saturn-Next' into absolutehell 2024-08-15 17:34:50 +02:00
Alug e100fff230 check for changed state before everything else 2024-08-15 16:38:19 +02:00
Alug 5393ac526a move this in hw_main 2024-08-15 16:38:12 +02:00
Alug 808f7baf53 move this in coindition 2024-08-15 16:38:08 +02:00
Alug 35f54822be smol cleanup HWR_RenderPlane 2024-08-15 16:38:05 +02:00
indev 94714fe571 Fix increasing number of viewpoints in replays by more than 1 (like pressing '3' with only one viewpoint) crashing game 2024-08-14 16:08:39 +03:00
Alug 5bdf8698bd completely disable director in splitscreen
will eventually get to splitscreen support lul
2024-08-14 14:45:42 +02:00
Alug 2398e60e89 fix director lol 2024-08-14 14:10:40 +02:00
Alug b4e563bfd6 Merge remote-tracking branch 'origin/Saturn-Next' into absolutehell 2024-08-11 11:22:21 +02:00
indev a56ce09923 Fix LUA_EvalMath warnings being broken sometimes 2024-08-11 12:01:10 +03:00
Alug 68c7a6bd93 Merge branch 'Saturn-Next' into absolutehell 2024-08-09 19:48:28 +02:00
indev b4612d6bd4 Fix smol memory leak in replay search thread oops 2024-08-09 19:45:16 +03:00
indev c2cfc96d87 Load replay titles in separate thread 2024-08-09 16:05:48 +03:00
indev 8db99291ac Visual improvements for replay search 2024-08-08 22:40:22 +03:00
indev c9aa764444 Add alternative button ('/') to open replay search 2024-08-08 22:09:30 +03:00
indev ee4869993d Oops shouldn't z_free that 2024-08-08 22:03:00 +03:00
indev 0758cf39c2 Greatly improve replay search perfomance by only reading replay name, and not entire file. Increase default search rate up to 1000 2024-08-08 22:01:19 +03:00
indev bb0c777cac Fix M_HutCheckReplays still being called in menu (hopefully) 2024-08-08 21:31:09 +03:00
indev 0bd2c49dae Search replays using title instead of filename 2024-08-08 18:43:03 +03:00
indev d25c6fa0b2 Test replay search 2024-08-08 16:51:39 +03:00
Alug 8f2d36aab0 smol cleanup 2024-08-05 12:40:06 +02:00
indev 6c764a8487 Fix chat not saving in console
Not sure why it was working before but broke now, maybe making va use snprintf instead of sprintf broke that
2024-08-04 16:57:24 +03:00
Alug dd6056a07a check if theres even controllers in rumble ticker 2024-08-04 14:53:24 +02:00
Alug a83d364ba7 update led status in main loop
makes this whole ordeal alot less hacky tbh
player color always gets updated if it changes
still allows for directly setting led color elsewhere by using G_SetPlayerGamepadIndicatorColor directly
hoping crap doesent cost any perf but honestly shouldnt
2024-08-04 14:53:21 +02:00
Alug 9c4b2b0abf no need for this 2024-08-04 14:53:18 +02:00
Alug 4235801ae4 proper pass fwrapv to gcc 2024-08-04 14:53:16 +02:00
Alug 6791f2e883 forgor 2024-08-04 12:50:39 +02:00
Alug caeec35c66 fix warning in director 2024-08-04 12:50:02 +02:00
Alug 7b95df150a support gcc 14.2.1 + fix some stuff 2024-08-04 12:49:59 +02:00
Alug 852651cefe better statdisplay offsets in splitscreen
lots of trial and error.....
2024-08-03 23:50:03 +02:00
Alug 22b9915ad7 smol fix to viewroll interp 2024-08-03 22:50:46 +02:00
Alug 0f994a0676 expose viewroll to lua 2024-08-03 22:50:42 +02:00
indev 5d68fd690b Add ctrl-w (delete word), ctrl-left (move to word beginning) and ctrl-right (move to word end) shortcuts for console 2024-08-03 23:19:54 +03:00
Alug c55bc6db4d Merge branch 'Saturn-Next' into absolutehell 2024-08-03 21:46:13 +02:00
Alug a77d8b4762 fix spriteshadows 2024-08-03 21:44:28 +02:00
Alug 23596d2516 add controller rumble to menu 2024-08-03 21:26:08 +02:00
indev 352b958da1 Fix few remaining uses of this_scale and ty
Not too sure if this is correct tho
2024-08-03 22:06:18 +03:00
Alug e9f2ef1422 Merge branch 'Saturn-Next' into absolutehell 2024-08-03 20:48:37 +02:00
Alug 7baa711744 this somehow was not reverted 2024-08-03 20:48:31 +02:00
indev 65e274a65f Smol safeguard for R_PointToDist2 2024-08-03 21:27:25 +03:00
Alug a874691bce Merge branch 'Saturn-Next' into absolutehell 2024-08-03 18:02:42 +02:00
Alug d60d101e75 dont set localangle or smth 2024-08-03 18:02:36 +02:00
Alug 8d9a648dce misplaced this 2024-08-03 18:02:21 +02:00
Alug 2332cc76ee Merge branch 'Saturn-Next' into absolutehell 2024-08-03 17:44:05 +02:00
Alug 5c3a2bf5be make inline macros for pointtodist 2024-08-03 17:43:57 +02:00
Alug 5e2b50c49e add very light rumble to brakedrift 2024-08-03 17:43:53 +02:00
Alug 3a56bf2bb5 fix up ogl sprite drawers, fix floor clip fix remove ty and reduntand hires stuff 2024-08-03 17:43:47 +02:00
Alug 3f4afb604a check if displayplayer skincolor is availible before returning it 2024-08-03 17:43:25 +02:00
Alug 77a2976d05 smol interp fixes 2024-08-03 17:43:17 +02:00
Alug 0eda508cf6 revert some lightlevel stuff in hw_main 2024-08-03 17:43:13 +02:00
Alug 4301e0f750 make this more explicit 2024-08-03 17:43:09 +02:00
Alug c5eb81c26a remove redundant check 2024-08-03 17:43:05 +02:00
Alug 47d3cf3e62 change rumble ticker loop a bit 2024-08-03 17:42:59 +02:00
Alug 41dc34efe8 set default duration to 84 2024-08-03 17:42:53 +02:00
Alug 4acbca4c8f do not constantly reset rumble
so it can work from lua
2024-08-03 17:42:47 +02:00
Alug 11329d5794 throw rumble ticker into right place 2024-08-03 17:42:44 +02:00
Alug b0880607d4 fix cassting, make one tic duration default, but can still pass ms to it 2024-08-03 17:42:39 +02:00
Alug 2afa18bbdd add duration field to G_PlayerDeviceRumble
duration is in ms
2024-08-03 17:42:35 +02:00
Alug acad230daa expose rumble and led to lua 2024-08-03 17:42:31 +02:00
Alug 49fcf3e486 rename to G_SetPlayerGamepadIndicatorColor 2024-08-03 17:42:26 +02:00
Alug acb0144742 splitscreen support for rumble 2024-08-03 17:42:21 +02:00
Alug 6efc8fdad3 add splitscreen support to gamepad led
also add more proper device check
2024-08-03 17:42:18 +02:00
Alug c75e6ba63c add basic rumble support for gamepads 2024-08-03 17:42:14 +02:00
Alug 7bd1808c88 change gamepad rgb color when switching viewpoints 2024-08-03 17:42:04 +02:00
Alug fe8e00895a simplify reduntand condition 2024-08-03 17:42:00 +02:00
Alug 9dc5e3d338 ressting to defaultcolor should also set led color 2024-08-03 17:41:29 +02:00
Alug 694c1ad808 change color light when you cycle between colors in player setup 2024-08-03 17:41:18 +02:00
Alug 754b028623 give rgb custom color support, change rgb light color earlier in Color_OnChange
so it always unconditionally changes the color
also
2024-08-03 17:41:14 +02:00
Alug 4423fb300f set controller rgb to playercolor
eh only for 1st player now no splitscreen support
idk if everything here is even correct
2024-08-03 17:41:06 +02:00
Alug 5c7d9327e3 SDL: only react to window focus changes if state actually changes 2024-08-03 17:40:41 +02:00
Alug cd72bce3cb dont reload palette until config was loaded 2024-08-03 17:40:34 +02:00
Alug 64ef0465d5 calloc soundchannels insteal of mallocing 2024-08-03 17:40:28 +02:00
Alug fe6ad4f762 Do not run ST_Ticker if dedicated 2024-08-03 17:39:54 +02:00
Alug 4b69b39d39 HMS_fetch_rules: Return NULL if the curl connection failed, instead of producing garbled rules 2024-08-03 17:39:44 +02:00
Alug a6fc237c88 try to prevent potential infinite SIGARBT hang in signal handler 2024-08-03 17:39:40 +02:00
Alug 2448a0b735 Cache pk3 central directory and Refactor ResFindSignature to work in chunks
https://github.com/KartKrewDev/RingRacers/commit/8ca2dc77e75b1ba8c511380257f0bbaf6d21c27b
https://github.com/KartKrewDev/RingRacers/commit/dedd0047bd8f9f73aba4defc19c429af7c987983
2024-08-03 17:39:36 +02:00
Alug 685220140a fix potential crash on nix while quitting 2024-08-03 17:39:32 +02:00
Alug 99779629d0 dont always reset texture depth in ogl 2024-08-03 17:39:27 +02:00
Alug 9fceabed8f Ensure Z_Malloc provides same alignment as libc 2024-08-03 17:39:22 +02:00
Alug e11363db3a Fix sound falloff calculation overflow 2024-08-03 17:39:17 +02:00
Alug 023cade51d smol fix to frameskipping 2024-08-03 17:39:12 +02:00
Alug d675b98330 Revert "Fix mobj reference management of player->mo"
This reverts commit c5ec61baa5.
2024-08-03 17:38:15 +02:00
Alug b3f16e935d Revert "more mobj reference fixes + cleanup"
This reverts commit bd8ff77fe0.
2024-08-03 17:37:46 +02:00
Alug 5b9e179017 Revert "dont access delayremoved thinkers"
This reverts commit df9ad5a31f.
2024-08-03 17:37:12 +02:00
Alug 6f53263107 Revert "Clean up mobj and thinker removal"
This reverts commit 048ccf52b0.
2024-08-03 17:37:06 +02:00
Alug fd797436fa Revert "fix declaration"
This reverts commit 8f195530b5.
2024-08-03 17:36:53 +02:00
Alug 96ee117657 Revert "more reference fixes"
This reverts commit 94bd1cb37b.
2024-08-03 17:36:31 +02:00
Alug 8b60fb6b6c revert this 2024-08-03 17:36:07 +02:00
Alug 67542d3cf1 i didnt knew k_positiondelay exists 2024-07-29 20:16:21 +02:00
Alug 41e97ffa79 another smol fix to director 2024-07-29 16:40:43 +02:00
Alug ffcff99a79 lower breakawaydist in director 2024-07-29 15:42:20 +02:00
Alug 48bcaacada fix K_DrawDirectorDebugger 2024-07-29 15:42:17 +02:00
Alug 01b060b0fe cleanup k_director 2024-07-29 15:42:15 +02:00
Alug 51ce092a6a lower pinchdist in director
since we cant get an accurate value for distance to finish line, this should do it perhaps
2024-07-29 15:42:12 +02:00
Alug d09e02721b e 2024-07-27 15:56:56 +02:00
Alug 88b81aa28b e 2024-07-27 15:56:51 +02:00
Alug 84c4f4f428 Merge branch 'Saturn-Next' into absolutehell 2024-07-27 15:49:46 +02:00
Alug ab5bc92a95 Revert "raise MAXVISSPRITES for 64-bit again"
This reverts commit d5258786e5.
2024-07-27 15:49:39 +02:00
Alug b44dd3edf0 Merge branch 'Saturn-Next' into absolutehell 2024-07-27 15:04:09 +02:00
Alug 80498a78ea lagless cam toggle 2024-07-27 15:03:59 +02:00
Alug 40663eb2b5 lagless cam test 2024-07-27 15:03:55 +02:00
Alug dca2827154 this is not a server cvar lol 2024-07-27 15:03:43 +02:00
Alug eec069b4e8 Merge branch 'rrdirectorport' into Saturn-Next 2024-07-27 14:42:26 +02:00
Alug 26eedc3341 small change to director for battle 2024-07-27 14:39:08 +02:00
Alug b19cefee3c Merge branch 'Saturn-Next' into rrdirectorport 2024-07-27 14:39:04 +02:00
Alug fb54b969d1 toggle for laptimes 2024-07-27 14:38:58 +02:00
Alug 034724b03e Show last lap time on HUD
god this is kinda ass lol
doesent work when you join midgame so disabled for there
2024-07-27 14:38:53 +02:00
Alug b80762eaf5 rename draw dist settings 2024-07-27 14:38:45 +02:00
Alug d5258786e5 raise MAXVISSPRITES for 64-bit again 2024-07-27 14:38:42 +02:00
Alug 9bfe2d3138 add more sprite draw dist settings for 64bit clients 2024-07-27 14:38:38 +02:00
Alug ae3b3f750d when no autoload config is found skip everything in D_AddAutoloadFiles
stuff doesent need to run if theres nothing to autoload so things can be skipped
2024-07-26 15:03:17 +02:00
Alug f83090e299 when no autoload config is found skip everything in D_AddAutoloadFiles
stuff doesent need to run if theres nothing to autoload so things can be skipped
2024-07-26 15:03:12 +02:00
Alug 3e4f497cbc Merge branch 'Saturn-Next' into absolutehell 2024-07-26 14:29:26 +02:00
Alug ce2398fdb7 add some extra safety to orbit and bananachain funcs 2024-07-26 14:29:14 +02:00
indev f545cce6fe Add check for if lua state exist in UnArchiveExtVars, since server can have local luas that may add player/mobj fields into savegame 2024-07-26 14:29:10 +02:00
Alug f614725fcb some cleanup 2024-07-26 14:29:03 +02:00
Alug 59e4f9ce4a let autoload run later to mitigate server join issues
itll now run at a similar place to postautoload
this may hopefully prevent some issuess with freeslotting lua
however sadly this makes menu replacements not work at startup anymore
2024-07-26 14:29:00 +02:00
Alug dff6b15263 fix fail condition 2024-07-26 14:28:57 +02:00
Alug 977ee8ccfc make backup of kartconfig before writing to it 2024-07-26 14:28:54 +02:00
Alug 161815e6fb Merge branch 'Saturn-Next' into absolutehell 2024-07-24 15:02:42 +02:00
Alug 8dda864909 toggle palrendering and fbo off if screen textures are disabled 2024-07-23 20:32:18 +02:00
Alug f6f9542d6e add cam check here 2024-07-23 20:32:16 +02:00
Alug 6655c0d881 reset tilt when respawning 2024-07-23 20:32:13 +02:00
Alug 98c8176d59 simplify this 2024-07-23 20:32:10 +02:00
Alug 2e7f64458d forgor this 2024-07-23 20:32:07 +02:00
Alug d6a9cdc452 fix up bird screen tilting
removes old lerp variables that did nothing
properly interpolated viewroll
made it proper adjust to mobjscale
doesent roll view when spectating
general cleanup
2024-07-23 20:32:05 +02:00
Alug 17dbe77cd3 allowjoin now sets saturnjoin to its value use CV_StealthSet to prevent
its only for scripts pretty much so no need to toggle it seperately
2024-07-23 17:45:27 +02:00
Alug 4b71d9a48d add "allowsaturnjoin" cvar to let toggle allowjoin for saturn clients seperately 2024-07-23 17:45:25 +02:00
Alug 1f41cb9a3f e 2024-07-23 00:59:20 +02:00
Alug c6351c6c53 add to menu 2024-07-23 00:55:55 +02:00
Alug 283218f2d6 changuer how this works
counter decrements - 1 double the cooldown time
2024-07-23 00:47:39 +02:00
Alug 4de22e9d66 add gamestateresendattempts
so you can specify how often the game tries to resend gamestate to player in given time
so they dont get stuck in a synch loop
this is gamestateresendattempts value in the time of resynchcooldown *2
2024-07-23 00:47:34 +02:00
Alug b4a737d910 Test: Restore save_p after P_LoadLevel
P_LoadLevel calls some functions that save gamedata and
unset save_p.

this is kinda hacky but i perhaps will port the redone save buffer sometime
2024-07-23 00:47:13 +02:00
Alug 0f2c17324a Merge branch 'Saturn-Next' into absolutehell 2024-07-23 00:47:03 +02:00
Alug 6a1b10eaf9 Make polyobjects agree with sector lighting/colormap like a FOF. 2024-07-23 00:46:58 +02:00
Alug 824211c2f6 prevent potential level load crash 2024-07-23 00:46:54 +02:00
Alug 02d115f119 don't check flippedness in HWR_RotateSpritePolyToAim if the mobj is actually a precipmobj! 2024-07-23 00:46:52 +02:00
Alug b44617413b gitignore deez 2024-07-22 12:59:07 +02:00
Alug c447f25e0a add missing copyright stuff to k_director 2024-07-22 12:57:11 +02:00
Alug 34ce92d9fa Merge branch 'Saturn-Next' into absolutehell 2024-07-21 23:29:11 +02:00
Alug 7ad5dc61ac Revert "Free mipmaps before freeing tags"
This reverts commit 2437c5a19a.
2024-07-21 23:25:10 +02:00
Alug 7072332ab7 clean director up a little
toggling director now resets cooldown so it switches players immediately
also consolidated condition to be active
and ensure DirectorFollowAttack doesent always run when it doesent need to be
2024-07-21 22:50:04 +02:00
indev 60e933eb00 Add director hud indicator 2024-07-21 22:49:59 +02:00
Alug 43e3d07acb fix cmake 2024-07-21 22:49:54 +02:00
indev 228252ee6f Add bind for director toggle 2024-07-21 22:49:51 +02:00
Alug 56a919eb60 oops 2024-07-21 22:49:47 +02:00
Alug bfcb906b12 add stuff for directordebugger i forgor 2024-07-21 22:49:41 +02:00
Alug b94776063f only update director if consoleplayers specs or in demo playback
dont need to update this ever if we dont even use it lol
2024-07-21 22:49:38 +02:00
Alug 3f412373bc fix crash if everyone spectates 2024-07-21 22:49:35 +02:00
Alug e7d1858052 port director from RR 2024-07-21 22:49:31 +02:00
Alug bd106308fc revert this
doesent do anything but complicate stuff lol
2024-07-21 22:46:07 +02:00
Alug 6ec96b37bd remove hw_light 2024-07-21 22:38:57 +02:00
Alug 3653786e14 cleanup hw_main 2024-07-21 22:24:55 +02:00
Alug 5824d9e803 cleanup r_things a little 2024-07-21 22:24:51 +02:00
Alug 3ad3cdfa38 stop yelling clang 2024-07-21 22:24:49 +02:00
Alug efcd1df365 fix this oops 2024-07-21 22:24:46 +02:00
Alug aef62c45de smol cleanup
also check for splitscreen and if not dont run a for loop lul
2024-07-21 22:24:44 +02:00
Alug 94bd1cb37b more reference fixes 2024-07-21 22:24:41 +02:00
Alug f7bf3fe510 cleanup hw_main 2024-07-21 22:24:28 +02:00
Alug a771ebf0e8 cleanup r_things a little 2024-07-21 22:24:21 +02:00
Alug 6b4d02ae99 stop yelling clang 2024-07-21 22:24:15 +02:00
Alug 3e6cab1ec9 fix this oops 2024-07-21 22:24:11 +02:00
Alug 147c59c26b smol cleanup
also check for splitscreen and if not dont run a for loop lul
2024-07-21 22:24:09 +02:00
Alug db6f76d12d more reference fixes 2024-07-21 22:24:01 +02:00
Alug 86950c26d0 add check here too 2024-07-21 11:49:48 +02:00
Alug e1d4f10223 add "gamestatecooldown" cvar
to be able to change the cooldown between gamestate resends
2024-07-21 11:49:21 +02:00
Alug 01c1ae42a1 fix saturn packet going the wrong way 2024-07-20 18:30:10 +02:00
Alug 550871f576 smol cleanup 2024-07-20 18:21:19 +02:00
Alug 56fcca1f6b mark if node can receive savegame so it doesent run resynch code on em
should prevent some issues for when a client received gamestate but thinks it needs to be resynched getting stuck
2024-07-20 18:15:42 +02:00
Alug 930bde785c just reset everything resynchwise here 2024-07-20 16:24:36 +02:00
Alug 13aadc41ff should reset those here perhaps 2024-07-20 16:22:51 +02:00
Alug ea4998f666 add gamestate resend ontop of resynch code lmao
absolute hell
will fallback to just normal resynching when the client doesent send gamestate request packet
2024-07-20 16:17:19 +02:00
Alug 6f0e92e0d1 Merge branch 'Saturn-Next' into absolutehell 2024-07-20 15:02:41 +02:00
Alug a4085cb155 fix hoop midjoin crash in the dumbest way possible
cant figure out why it crashes so thisll do lol
2024-07-19 22:57:18 +02:00
Alug b7e77e10b6 improve virtual resource management 2024-07-19 22:57:16 +02:00
Alug 8f195530b5 fix declaration 2024-07-19 21:29:10 +02:00
Alug 048ccf52b0 Clean up mobj and thinker removal 2024-07-19 21:26:42 +02:00
Alug df9ad5a31f dont access delayremoved thinkers
uhhh
2024-07-19 21:26:02 +02:00
Alug 0b3284e23c fix ScreenCoords on 2 plyr splitscreen and shearing
+ remove non 16:10 hack since that issue was fixed elsewhere
2024-07-19 19:25:20 +02:00
Alug 36d598440a disable hudoffsets in splitscreen 2024-07-19 19:25:18 +02:00
indev 9cc42e6430 Add option to play power items sfx for growmusic and supermusic 2024-07-19 19:03:47 +03:00
Alug 3f5c19bffd add boolean to tell if node is saturn 2024-07-19 15:01:30 +02:00
Alug 800dbf5e78 add packet into packettypename 2024-07-19 15:00:45 +02:00
Alug 2b5db9ff3f make saturn packet reliable 2024-07-19 14:46:24 +02:00
Alug b07c8848ca make smol function for now 2024-07-19 14:43:19 +02:00
Alug 9bff8dd91f whoopss remove test stuff 2024-07-19 14:40:25 +02:00
Alug 19eee66c39 make a packet to tell if a joined client is on saturn
initial stuff
works and seems to be vanilla compatible
needs its own function and other things to be useful
2024-07-19 14:40:23 +02:00
Alug fbf7be8808 add audio buffer size into sound menu 2024-07-18 14:43:14 +02:00
Alug fcda4c1188 revert this in teleport 2024-07-17 22:19:11 +02:00
Alug deae234afa Revert "clean up mapload code a little more"
This reverts commit 79a5d174a5.
2024-07-17 12:21:05 +02:00
indev 82e33fd4e4 Attempt to fix possible use-after-free for awayviewmobj 2024-07-17 12:30:34 +03:00
Alug 15914c2f25 Skip over empty entries when populating vres, saving memory 2024-07-17 11:13:07 +02:00
Alug da64d3ccbf vres_GetMap: Count resources in folders up until next 0-length lump
justs in case the order of stuff may be weird
fixes keepmapmusic crash on some maps
2024-07-17 11:12:58 +02:00
Alug 79a5d174a5 clean up mapload code a little more 2024-07-17 09:21:15 +02:00
indev 295d9768ce Fix linedef 415 executing random text if script lump doesn't have null terminator 2024-07-16 16:42:32 +03:00
Alug 9490b1235d did not mean to add this lol 2024-07-16 10:43:55 +02:00
Alug 55eb984ccd remove this check 2024-07-15 21:58:00 +02:00
Alug 4b1a82e14e fix more warnings 2024-07-15 21:43:25 +02:00
Alug 3c224923e9 fix some warnings in clang 2024-07-15 21:19:25 +02:00
Alug 2c4f5a68b9 fix A_ action protottypes 2024-07-15 21:10:11 +02:00
Alug d324c917ad Revert "fix some clang warnings"
This reverts commit fea89de037.
2024-07-15 20:57:09 +02:00
Alug bd8ff77fe0 more mobj reference fixes + cleanup 2024-07-15 13:56:28 +02:00
Alug 35d40e1d37 ndef 2024-07-14 17:30:52 +02:00
Alug e9e281fd2a clean up some net stuff 2024-07-14 17:22:25 +02:00
Alug 2437c5a19a Free mipmaps before freeing tags
ŝhould hopefully fix some random Z_free crashes
2024-07-14 17:17:01 +02:00
Alug b9b4de929d this does nothing lol 2024-07-14 17:15:43 +02:00
indev 28fc55b653 Refactor music name scrolling in music test 2024-07-14 15:33:31 +03:00
Alug 8f4df0ceca version string otherwise i forger 2024-07-14 10:18:27 +02:00
Alug ecde8a5e8b shut up 32bit gcc 2024-07-14 10:17:47 +02:00
Alug 715b106c9e shut up windoze 2024-07-14 09:51:13 +02:00
Alug 2114afa536 inline M_Memcpy 2024-07-13 16:04:43 +02:00
Alug c78816a8d1 also use IFCHANGED macro for levelinterpolators
just looks a bit neater
2024-07-13 16:04:41 +02:00
Alug 28516c4833 fix NOHW compile 2024-07-13 14:55:10 +02:00
Alug 837ed3535d Revert "smol optimization to HWR_Addline"
This reverts commit e6359663b1.
2024-07-13 13:06:45 +02:00
Alug bcb332e88f Revert "shut up gcc"
This reverts commit 17a5c6ed06.
2024-07-13 13:06:42 +02:00
Alug f4be7a8034 Revert "dont do this with portals"
This reverts commit f949fa54af.
2024-07-13 13:06:39 +02:00
Alug e69413f1e8 smol cleanup 2024-07-10 19:31:35 +02:00
Alug ee6dcfc678 fix conflict 2024-07-10 19:31:22 +02:00
Alug d4370a1811 clean up P_SetupLevel a little more 2024-07-10 19:31:17 +02:00
Alug babf4ca06a Map data lump interface
cleans up code alot and stuff

https://git.do.srb2.org/STJr/SRB2/-/merge_requests/535
2024-07-10 19:30:38 +02:00
Alug ccf0905469 change when dynamic slopes run depending on if you joined midgame 2024-07-10 19:29:48 +02:00
Alug 970130e02b mitigate dynamic slope desynchs
Perform dynamic slope thinking before other thinkers.
2024-07-10 19:28:44 +02:00
Alug 6088fa5134 Clean up graphic menus
- Renamed Experimental Options to Advanced Options
- Fixed the tooltips not displaying
- Made it look good again
2024-07-10 19:25:49 +02:00
indev 33bc484d69 Call ServerJoin hook when consoleplayer becomes available, since it is needed for configs (which what this hook is created for) 2024-07-10 19:09:14 +02:00
indev 6bf113d0ff Add info about ServerJoin into LUASTUFF.md (so i don't forget to do it later) 2024-07-10 19:09:11 +02:00
indev 630d910a9e Add ServerJoin lua hook, which gets called when client joins a server (listen server hosts joining their server also count) 2024-07-10 19:09:08 +02:00
Alug 3c70963f56 only interpolate pitch and roll when using 3d models
sprites dont need this for now
2024-07-10 18:58:55 +02:00
Alug 4c4f6f6d80 dont think precip mobj angle ever changes 2024-07-10 18:58:52 +02:00
Alug f949fa54af dont do this with portals 2024-07-10 18:58:05 +02:00
Alug 17a5c6ed06 shut up gcc 2024-07-10 18:58:02 +02:00
Alug e6359663b1 smol optimization to HWR_Addline 2024-07-10 18:57:59 +02:00
Alug 405cef6a01 fix IFCHANGED macro 2024-07-10 18:32:22 +02:00
Alug d4886f8923 forgor this 2024-07-10 10:18:50 +02:00
Alug c5ec61baa5 Fix mobj reference management of player->mo
https://git.do.srb2.org/KartKrew/RingRacers/-/commit/d0719ef5ba86a1da32fed171d74eb76c7254f4f6
2024-07-10 10:18:46 +02:00
Alug 7a9ffa7ee8 test remove all the networking crap from rendering code 2024-07-10 10:13:53 +02:00
Alug 5ff665a073 remove those 2 from experimental video menu
no reason to ever toggle them off
2024-07-10 10:08:19 +02:00
Alug 3d4e078a90 another m_menu moment 2024-07-10 10:07:51 +02:00
Alug 8ef613ef9b remove cv_mobjssector
idk why it even checks for pointinsubsector
2024-07-10 10:06:31 +02:00
Alug 988a672dea remove cv_grfofcut
same story
2024-07-10 09:59:50 +02:00
Alug cca9c51315 remove cv_slopepegfix
same as the other ones
2024-07-10 09:57:23 +02:00
Alug 18aa3689d9 m_menu moment 2024-07-10 09:54:43 +02:00
Alug 59ab6572b1 remove cv_fofzfightfix
more bloat
2024-07-10 09:54:03 +02:00
Alug b6cf933159 remove R_Pointtoangle toggle
its bloat, the difference is negigble at best
2024-07-10 09:50:25 +02:00
Alug 48f36ca8f3 35/2 != 17 = 17.5 ? 2024-07-10 04:55:01 +02:00
Alug fea89de037 fix some clang warnings 2024-07-10 04:53:28 +02:00
Alug e2f1dd1ce8 a 2024-07-10 04:51:59 +02:00
Alug 48ac3353cb Maybe hopefully fix ogl masterserver crash thing
port from durr
2024-07-10 04:51:52 +02:00
Alug 63015c3a93 Merge branch 'Saturn-Next' of https://github.com/Indev450/SRB2Kart-Saturn into Saturn-Next 2024-07-10 04:50:06 +02:00
Alug c7bd402e54 Merge remote-tracking branch 'origin/packetstat' into Saturn-Next 2024-07-10 04:49:58 +02:00
Alug 0c6f9b6cc1 basic frame skipping system 2024-07-10 04:49:32 +02:00
Alug b5d7b84c1e more changes to dither
use interger for distance scales
start z factor earlier
rename halfResolution to endResolution
2024-07-09 09:06:19 +02:00
Alug cbbde8dea5 more tweaks 2024-07-08 21:43:06 +02:00
Alug 58dd0b7591 oops that actually didnt fade out at all lol 2024-07-08 21:43:03 +02:00
Alug d9f2535402 scale and fade out dither pattern
makes the image a bit cleaner and easier to look at in palrender
2024-07-08 21:43:00 +02:00
Alug 66eb201466 simplify this a little 2024-07-08 21:42:53 +02:00
Alug edbf20d975 oops this should be min 2024-07-08 21:42:49 +02:00
Alug 711d7dcfcc Always use system-specific path seperator
https://git.srb2.org/KartKrew/RingRacers/-/commit/0f16c61d04f42b463db5c8987571fc986ae6ce9f
2024-07-08 21:42:38 +02:00
Alug 219979e20b dont think kart even supports trivial maps
so no need to constantly check for this
2024-07-08 21:42:36 +02:00
Alug 27917a0e85 shut up gcc 2024-07-03 17:37:29 +02:00
Alug 4b4b2d5cbc some crap from asan 2024-07-03 17:37:16 +02:00
Alug 8d968d7f89 fix some clang warnings 2024-07-03 17:36:37 +02:00
Alug 9090a5cd73 Merge pull request #131 from Indev450/optimizeluaactions
Only call the Lua API for overridden actions
2024-07-03 11:10:15 +00:00
Alug 59a50994b8 Merge branch 'Saturn-Next' into optimizeluaactions 2024-07-03 13:10:03 +02:00
Alug ac99a6ac3c Merge pull request #132 from Indev450/lua-hooks-table
Store hooks in a table with integer keys instead of registry with string keys
2024-07-03 11:08:58 +00:00
Alug fa2257ad3b Merge pull request #133 from Indev450/luafieldlookup
Optimize field lookups in Lua metatables
2024-07-03 11:08:44 +00:00
NepDisk 66ce0871bc Fix automap multiplayer crash
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2488
2024-07-03 13:07:29 +02:00
Alug c59564723c Clamp lindex during vissprite light calculation
Mitigates against negative or very large xscale values causing lindex
to evaluate < 0, preventing a potential colormap indexing-related crash.
2024-07-03 13:07:17 +02:00
Alug 606717d253 prevent potential crash when trying to kill bananachain 2024-07-03 13:07:13 +02:00
Alug f73e84e0ad stuff 2024-07-03 13:07:04 +02:00
Alug fc01453544 scale dithering a little diff for a little smoother "fade" in pal render 2024-07-03 13:07:00 +02:00
Alug d37a1c799f change dither matrix to 4x4
a little grittier also smol cleanup
2024-07-03 13:06:57 +02:00
indev 3456ef96a7 Use a fake 2d array in dither shader so it compiles with older glsl versions (1.20 at least) 2024-07-03 13:06:53 +02:00
indev 40143375fc If shader compilation failed, print info log 2024-07-03 13:06:50 +02:00
Alug 7f34a1d83e add gr_lightdithering to shader
mhhm dithering
2024-07-03 13:06:47 +02:00
Alug 2316c117b1 improve teleport interpolation stuff 2024-07-03 13:06:44 +02:00
Alug 31b7482c3a small optimization to batching 2024-07-03 13:06:40 +02:00
Alug 0974625769 no need for this 2024-07-03 13:06:36 +02:00
Alug 266f5149b5 smoller opitmizations 2024-07-03 13:06:25 +02:00
Alug 008a9b9b3f optimize ogl polyobjs slightly 2024-07-03 13:06:22 +02:00
Alug ec2fd5b38f prevent crash in hw bsp 2024-07-03 13:06:19 +02:00
Alug d449a1b714 remove this again 2024-07-03 13:06:16 +02:00
NepDisk 0bd5ca5e3f Allow Users to Connect to Servers While In-Game
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2401/
2024-07-03 13:06:12 +02:00
NepDisk 06248e5388 Linux customshader compilation fix
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2418/
2024-07-03 13:06:09 +02:00
Alug 9c5a0ed7ee move HWR_LoadLevel to hw_main 2024-07-03 13:06:04 +02:00
Alug b199354167 this should be called on mapload 2024-07-03 13:06:02 +02:00
Alug 74ce725e3d oops 2 2024-07-03 13:05:59 +02:00
Alug 3d5e033158 oops 2024-07-03 13:05:56 +02:00
Alug ca58c1dee2 these appear to be unused so comment them out
dont need 6 arrays being allocated with MAXSKINS for nothing lul
2024-07-03 13:05:53 +02:00
Alug d51a69b052 Merge remote-tracking branch 'origin/lua-enumlib-sfxslotsfix' into Saturn-Next 2024-07-03 13:05:48 +02:00
Alug 1a96d96837 forgor this 2024-07-03 13:05:45 +02:00
Alug 2e7cd51ff8 limit localskins to 32
hope this doesent just die lol
2024-07-03 13:05:42 +02:00
Alug 112716dae5 Do not access memory on misaligned addresses
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2438
2024-07-03 13:05:39 +02:00
indev c13e780f29 Try fix glib preallocating too much space for sound freeslots 2024-06-20 16:55:58 +03:00
Alug c35887f5ee Revert "fix some interpolation issues"
This reverts commit e19f6f6656.
2024-06-17 12:52:09 +02:00
Alug 2f55c10ce3 Revert "more interp fixes"
This reverts commit 3a1a58bcfc.
2024-06-17 12:52:00 +02:00
Alug 0068312ce3 Revert "revert this part"
This reverts commit efe7dd23b6.
2024-06-17 12:51:57 +02:00
Alug ea49d92932 add missing HAVE_THREADS 2024-06-13 14:47:28 +02:00
Alug efe7dd23b6 revert this part
idk if that was netsafe so
2024-06-12 22:36:03 +02:00
Alug 3a1a58bcfc more interp fixes 2024-06-12 22:35:21 +02:00
Alug 953862f133 change this to int64 cause it fixes the intermission thing on high res
idk why that fixes it tbh but it does
2024-06-12 22:34:02 +02:00
Alug 41eb2ee969 fix oopsie on titled software wöter 2024-06-12 22:33:51 +02:00
Alug 225ecce676 lower min audio buffersize to 256 2024-06-12 22:33:44 +02:00
Alug 335b10a694 forgor 2024-06-12 22:33:36 +02:00
Alug 967220178c remove windows timing crap again
it actually made stuff a little wonky so revert that
2024-06-12 22:32:54 +02:00
Alug be7461ad51 use sdl ogl render instead of software for software mode on nix
oops
2024-06-12 22:31:53 +02:00
indev 5af7cf850a Fix string format warning for packetstat 2024-06-12 21:26:41 +03:00
indev 86395d4d8b Add a way to count number of handled packets (for debugging) 2024-06-12 21:05:21 +03:00
Alug 3412bb5380 fix encore flipcam with ogl shearing 2024-06-09 22:02:52 +02:00
Alug d66e7e660d reset those here ig
need a better place tbh
but those occasionally could get stuck for some reason
so just reset them when the menu gets opened
2024-06-09 18:56:18 +02:00
Alug 07d631e320 e 2024-06-09 18:55:52 +02:00
Alug 6ffb50530d add mobj check here 2024-06-09 18:55:49 +02:00
Alug bd7103d109 add check earlier in p_killmobj 2024-06-09 18:55:46 +02:00
Alug 4abc2ab5bd fix redifinition warning 2024-06-06 18:58:03 +02:00
Alug f8a8b8ac6e disable upx on nix by default 2024-06-06 18:58:00 +02:00
Alug cfe6e08168 fix masterserver ifdef 2024-06-06 18:57:57 +02:00
Alug 5139259037 fix HAVE_CURL 2024-06-06 18:57:55 +02:00
Alug 1503daf02b more minor loop stuff 2024-06-06 18:57:52 +02:00
Alug 4246e42948 minor sprite opitmizations 2024-06-06 18:57:31 +02:00
Alug 9b3eaa6fe8 smol optimization to skin loading 2024-06-06 18:57:25 +02:00
Alug 716685d809 zzz... 2024-06-03 17:15:43 +02:00
Alug dd72871ba6 Revert "use shader to prevent sprite floor clipping"
This reverts commit ee2ec01eb9.
2024-06-03 17:15:39 +02:00
Alug ea510f95b8 Revert "fix le dispoffset"
This reverts commit f977af6a80.
2024-06-03 17:15:36 +02:00
Alug 9de3db7c97 add shader for shadows to also fix sprite shadows in pal render 2024-06-03 16:52:25 +02:00
Alug 1ab7a2acf4 add toggle for beta intermission screen + smol cleanup 2024-06-03 15:13:46 +02:00
Alug f977af6a80 fix le dispoffset 2024-06-03 15:13:39 +02:00
indev cae40928ad Use Z_Calloc to allocate wadfile_t to avoid having uninitialized fields 2024-06-03 00:18:11 +03:00
Alug ee2ec01eb9 use shader to prevent sprite floor clipping
from durr lul
2024-06-02 22:16:09 +02:00
Alug bf75644144 make r_fps if else hell a bit more bearable to look at
lol lmao
2024-06-02 22:12:39 +02:00
indev 0e927ce4bd Make sfxinfo_t and state_t use field tables too 2024-06-02 00:43:42 +03:00
indev 1747ebf481 Lua_optoption shouldn't change stack state at the end of call now 2024-06-02 00:43:09 +03:00
indev da9d57a624 Fix compilation for some gcc versions 2024-06-02 00:39:22 +03:00
Alug 38633a8516 stuffs 2024-06-01 17:03:39 +02:00
Alug 957159d485 forgor to remove that 2024-06-01 16:31:55 +02:00
Alug 8052eb1c3a fix papersprites in software (hopefully)
lul
2024-06-01 16:30:03 +02:00
Alug 37a394ebaa flexible array stuff for columnofs
hopefully this fixes some crashes or smth
2024-06-01 16:29:55 +02:00
Alug b01a2836ea cleanup some super old stuff that did nothing
lul
2024-06-01 16:29:40 +02:00
Alug dc03359f3a theres no value 3 oops
i shouldnt do stuff after waking up at 4 in the morning lol
2024-05-30 19:59:14 +02:00
indev 6269c7c827 Use tmp variable for searchWad since envstr doesn't get changed 2024-05-30 19:32:18 +03:00
indev 040ddb1f40 Revert "Revert "Don't traverse the entire HOME directory to find wads""
This reverts commit 443905ffb3.
2024-05-30 19:23:14 +03:00
Alug faa5dbd0e7 split sprite draw loops
so crap doesent constantly check for papersprites on all sprites
2024-05-28 23:53:28 +02:00
Alug 37d3e2ae1a scale sprite draw distance with mapobjscale 2024-05-28 23:52:13 +02:00
Alug 455bbe47c2 smth smth encore magic numbers idk 2024-05-28 22:55:43 +02:00
Alug 4847e4e3cb that should be there lul 2024-05-28 22:55:40 +02:00
Alug 086d0113c5 Optimize field lookups in Lua metatables
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/2024#cd5b5ee262bf5129c4d400ad60d006e1fa917c1f
2024-05-28 18:16:43 +02:00
Alug 67aa71170f when not using screentextures draw kart bg on intermission screen 2024-05-28 00:52:52 +02:00
Alug ddddc7a898 draw a black screen instead of "nothing" during wipes on disabled screentextures
should resolve the intense flashing that can occur
2024-05-28 00:52:48 +02:00
indev 7c17f3a93c Merge pull request #130 from GenericHeroGuy/lua-hudinterpolate-redux
Lua HUD interpolation
2024-05-25 19:09:02 +03:00
GenericHeroGuy 05a5651260 Finishing touches
Some cleanup, also interpolate drawfill size
(dunno why it wasn't before)
2024-05-25 17:05:08 +02:00
Alug 8cf6050d10 Only call the Lua API for overridden actions 2024-05-25 16:01:34 +02:00
indev b310168c12 Store hooks in a table with integer keys instead of registry with string keys 2024-05-25 16:39:16 +03:00
Alug 8774b14fdf move some cvars to be registerrerd latur in ogl 2024-05-25 14:52:58 +02:00
Alug 518ac3ca28 Turn of FBO downsampling when you turn off screen textures
fbo downsampling needs those and if theyre disabled youre essentially seeing nothing at all lol
2024-05-25 14:44:03 +02:00
Alug 157c95a785 super smol optimization to R_DrawRepeatMaskedColumn
only maths once not twice lul
2024-05-25 14:44:00 +02:00
GenericHeroGuy 142c01f516 Update docs for interpLatch 2024-05-25 14:09:20 +02:00
GenericHeroGuy a17a5387ff Rename interpString to interpLatch 2024-05-25 14:08:52 +02:00
Alug d794de3e83 Cull BSP behind a raised floor or lowered ceiling that covers the entire screen
https://git.do.srb2.org/KartKrew/RingRacers/-/commit/7b8a564f69688515319ccd425f2b88ffe8b7b120
2024-05-25 02:21:04 +02:00
Alug 837746c0a9 declare outside of lööp also add const in r_ 2024-05-25 02:14:20 +02:00
Alug 9f692c1f6a change names to be less basic 2024-05-23 23:28:54 +02:00
Alug 8de340edbe allow gamepad dpad to hold scroll shit in menu aaa
absolute arsepain cant wait to see this breaking kek
2024-05-23 23:28:47 +02:00
GenericHeroGuy 9cd1233c32 Dust this crap off a bit 2024-05-23 16:47:29 +02:00
GenericHeroGuy 3f6575e41f Merge branch 'Saturn-Next' into lua-hudinterpolate-redux 2024-05-23 15:44:46 +02:00
Alug f939b02fd3 Merge branch 'Saturn' into Saturn-Next 2024-05-21 21:01:11 +02:00
Alug 73d0154b6c encore flipcam support 2024-05-21 21:00:33 +02:00
Alug cda7475058 unhack the animated votescreen a little
also make it pause when the game is paused like it was intended originally
2024-05-20 18:42:03 +02:00
Alug 33a31d0ad8 this should be here aswell i suppose 2024-05-20 13:31:13 +02:00
Alug 8dafc2d3d9 Merge pull request #129 from Indev450/Saturn-Next
Saturn v6.2
2024-05-20 13:21:16 +02:00
Alug 5f36557a18 change version string stuff per define lul 2024-05-19 21:31:05 +02:00
Alug 9b4e64011b make this a scroll menu
tbh not gonna bother with moving stuff depending on renderer
2024-05-19 18:43:12 +02:00
Alug 3ca313c14d Merge pull request #125 from Indev450/fborender
Use FBO to allow downsampling in Opengl
2024-05-19 18:20:01 +02:00
Alug 6fcea2f98e RefreshOGLSDLSurface
to make it a little more clearer this is ogl only
2024-05-18 23:52:05 +02:00
Alug c605906408 some stuffs 2024-05-18 23:49:36 +02:00
Alug de6511abe0 dont compile with that with NOHW 2024-05-18 23:40:28 +02:00
Alug c966b5defb forgor 2024-05-18 23:38:04 +02:00
Alug 3c8c273e51 add ogl version check + grey out in menu + turn it off when not avilible 2024-05-18 23:34:27 +02:00
Alug eaeb2575f7 add stuff to experimental menu 2024-05-18 23:22:30 +02:00
Alug 978cc57889 Add NOSCREENFBO compiler flag to be able to build without fbo support 2024-05-18 22:57:25 +02:00
Alug 6db73bfd63 Merge branch 'Saturn-Next' into fborender 2024-05-18 22:33:41 +02:00
Alug af5c3e4201 revert this thing 2024-05-15 17:56:58 +02:00
Alug 39e6668e20 change version 2024-05-15 17:51:11 +02:00
Alug 1ab63613a9 forgor this crap 2024-05-15 16:54:27 +02:00
Alug 57e72db1f8 support gcc14 ig 2024-05-15 16:46:59 +02:00
Alug d1d00d7ec6 shut up compiler 2024-05-05 22:00:22 +02:00
Alug 169e7cd462 Render precip through blockmap instead of during BSP
from RR
2024-05-05 21:54:00 +02:00
Alug e19f6f6656 fix some interpolation issues
minus P_spec change since that aint netsafe
2024-05-05 20:52:06 +02:00
Alug 13249f7ad4 fix potential crash in ogl vissprite sorting 2024-05-05 20:50:36 +02:00
Alug 22166ceccb fix precip overflow 2024-05-05 20:50:32 +02:00
Alug 75ed11a8b6 simplify SOFTLIGHT alot
also should make sure it gets applied everywhere lul
2024-04-29 10:12:58 +02:00
Alug 641cd6b8db use bigfloat for driftgauge offset too 2024-04-27 20:32:52 +02:00
Alug 62fa60e399 fix rare precip crash 2024-04-27 20:03:38 +02:00
Alug 17a6c4191d Merge pull request #128 from Indev450/it-cv-bigfloat
Add IT_CV_BIGFLOAT to use bigger increment for some CV_FLOAT cvars (a…
2024-04-27 20:01:57 +02:00
Alug 3acdcb09f1 inline those 2024-04-24 11:02:25 +02:00
GenericHeroGuy 1abf6a4ce1 Add interpolation docs to LUASTUFF 2024-04-23 21:24:47 +02:00
Alug 836890968c Revert "Merge pull request #121 from Indev450/texload"
This reverts commit b6a5c5b720, reversing
changes made to bcf2b3bab2.
2024-04-23 09:06:51 +02:00
Alug 7110de4b5b Merge branch 'Saturn' into Saturn-Next 2024-04-22 05:25:52 +02:00
Alug b4dfebac58 fix some visual issues with fofs 2024-04-22 05:25:46 +02:00
Alug 38d5ee5ae7 a 2024-04-20 22:54:03 +02:00
Alug d0c50006bc some stuff from ceepeepeecheck 2024-04-20 22:54:00 +02:00
indev 2147951a16 Add IT_CV_BIGFLOAT to use bigger increment for some CV_FLOAT cvars (added only to fov atm) 2024-04-20 11:41:17 +03:00
indev ea0cc41d04 For MIN/MAX value of cvar, convert it to float before saving for CV_FLOAT variables 2024-04-20 10:30:34 +03:00
Alug b6a5c5b720 Merge pull request #121 from Indev450/texload
Do not reload every texture when adding a wad
2024-04-20 01:33:50 +02:00
Alug bcf2b3bab2 disable palette rendering if screentextures aint enabled 2024-04-19 06:23:12 +02:00
Alug a238b19c75 z 2024-04-19 06:22:48 +02:00
Alug 9317ccd0be more things
-Fix a division by zero in BCZ2 Metal Sonic's routine
-Fix a bug where adding the same mod multiple times counted towards the mod limit
and other thigns
2024-04-19 06:22:44 +02:00
Alug 463dccab8b some smol fixes 2024-04-19 06:22:22 +02:00
Alug 2ccf91fbfc Make FixedRem less laggy by just using the modulo operator. 2024-04-19 06:22:20 +02:00
indev 36e06e5d6b Fix possible buffer overflow in 'va' function 2024-04-13 21:55:22 +03:00
Alug 45d73a2ad6 add qs22j to cmakelist 2024-04-13 18:40:00 +02:00
GenericHeroGuy 995777c676 Exclude string mode flags from olditem search 2024-04-12 22:36:23 +02:00
Alug dacfe376e1 smth smth paranthesis 2024-04-12 21:55:53 +02:00
GenericHeroGuy 60e42472e3 Do string coordinate calcs on all functions (and fix) 2024-04-12 21:00:54 +02:00
Alug c92ef4d757 fix software crash
Zzz...
2024-04-12 20:41:25 +02:00
indev 7cd6a031cd Fix compilation warning regarding calloc and sizeof 2024-04-11 19:12:14 +03:00
indev af265d017d Fix potential negative array index in V_ThinStringWidth 2024-04-11 18:55:55 +03:00
Alug 9e104a8632 ok dont use this at all then 2024-04-10 18:18:47 +02:00
Alug 4a1523da57 Zzz... 2024-04-10 18:15:29 +02:00
Alug 6a3987c8f7 fix ifdefs 2024-04-10 17:57:55 +02:00
Alug 1df6c4d4da move this to first init too 2024-04-10 17:47:37 +02:00
Alug 3cab29085a Merge branch 'Saturn-Next' into fborender 2024-04-10 17:46:40 +02:00
Alug 1391e556d6 that wasnt the onchange im sleepy 2024-04-10 17:40:43 +02:00
Alug 94340e6634 forgor to remove those Zzz... 2024-04-10 17:32:13 +02:00
Alug 64f10c36fa should throw that into onchange oops 2024-04-10 17:29:16 +02:00
Alug 955f73d9e8 throw stuff into own function, also check on game start 2024-04-10 17:24:46 +02:00
Alug 40c356395a simplify this crap 2024-04-10 07:02:18 +02:00
indev aac74cf93a Don't call menu drawer in wipes on dedicated servers 2024-04-06 01:31:43 +03:00
GenericHeroGuy 18e0485f39 Make this less insufferable
* Zero is now a valid tag for v.interpolate
* Reset lerp coordinates when v.interpString is called again
* Leaving string mode enabled on exit no longer breaks other scripts
* Fix fadeScreen having an uninitialized ID
2024-04-04 23:39:23 +02:00
GenericHeroGuy aeb5ae994e Subpixel interpolation for strings and drawfill 2024-04-04 00:27:47 +02:00
GenericHeroGuy b2f9a29eb0 Lua HUD interpolation 2024-04-02 21:00:23 +02:00
GenericHeroGuy 5f69bfcf22 Split game drawlist per displayplayer 2024-04-02 03:22:24 +02:00
GenericHeroGuy 9442a463d4 Shrink drawlists, take 2
Approximately 2/3rds smaller
2024-04-01 23:24:09 +02:00
Alug d7a1cc6702 Read only header bytes when creating textures list 2024-03-27 21:31:56 +01:00
Alug a779191feb beter 2024-03-27 18:45:59 +01:00
Alug 23cc0dfc3a add some comments cause i WILL forger what this crap even does 2024-03-27 18:44:32 +01:00
Alug c7a258f32f clean up 2024-03-27 18:34:58 +01:00
Alug a28f025d40 Stuff from displaycrap branch to detect downsampling automatically 2024-03-27 18:33:29 +01:00
Alug 91a3b288ef conflict moment 2024-03-27 18:08:09 +01:00
Alug 200d971d35 Toggle to render to screenFBO
fixes downsampling from higher resolutions
TODO: make this activate automatically if game detects it runs at higher res than desktop res
2024-03-27 18:05:48 +01:00
indev 54ee3f2961 R_LoadTexturesPwad: don't do anything wad has no textures 2024-03-26 20:40:11 +03:00
Alug c3a71b60b0 Do not reload every texture when adding a wad
https://git.do.srb2.org/STJr/SRB2/-/merge_requests/1725?commit_id=37add34b9c729b21e624e22d64159073c9258e25
2024-03-26 14:12:05 +01:00
Alug 205bfc0262 Split R_LoadTextures 2024-03-26 14:11:49 +01:00
355 changed files with 157462 additions and 13995 deletions

No files matched your search

+346
View File
@@ -0,0 +1,346 @@
#!/bin/bash
set -e # Enable auto-exit for debugging :))
# Make Linux AppImage program data
# https://docs.appimage.org/reference/appdir.html
# PWD: {repo_root}/build
# See deployer.sh for usage
# Terminal stuff
RESET="$(tput sgr0)" #"\e[0m" # Resets terminal colors
# Colors for various information types
FAILURE="$(tput setaf 1)" #"\e[91m"
SUCCESS="$(tput setaf 2)" #"\e[92m"
NOTICE="$(tput setaf 3)" #"\e[93m"
VERBOSE="$(tput setaf 4)" #"\e[94m"
verbosity=0 # By default don't print anything unless it's *ultra* important.
quiet=0 # Also don't print anything if they supplied the quiet argument
# URL from which to download appimagetool if there isn't one available in your $PATH
# at time of writing only aarch64, armhf, i686, and x86_64 versions are available via this method
# in those cases, and honestly even outside of those cases, it's better to just put a working one in your $PATH yourself..
url="https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-$(uname -m).AppImage"
# A whitelist of libraries to include into SRB2's AppImage if SRB2 is dynamically linked.
# please don't add a newline at the end of this or i will cry :(
libraryWhitelist="
libbacktrace
libnsl
libSDL2
libSDL2_mixer
libgme
libopenmpt
libpng
libfluidsynth
libpulse
libmodplug
libvorbisfile
libopusfile
libFLAC
libmad
libmpg123
libvorbis
libpulsecommon
libsndfile
libsndio
libogg
libvorbisenc
libjson
libreadline
libwrap
libtinfo
libtirpc
libpng16"
# these kinda look like macros don't they
function print { (( "$quiet" == 0 )) && echo "$@" || :; } # echo if not quiet
function coloredText { printf "$1"; print "${@:2}"; printf "$RESET"; } # use print to inherit quiet
function success { coloredText "$SUCCESS" "$@"; } # use coloredText to inherit quiet
function important { coloredText "$NOTICE" "$@"; } # use coloredText to inherit quiet
function verboseOnly { (( "$verbosity" >= $1 )) && (coloredText "$VERBOSE" "${@:2}") || :; } # use coloredText to inherit quiet
# Parses an argument with a single dash
function parseSingleDashArg() {
while read -n 1 char; do
if [[ "$char" == '-' || "$char" == '' ]]; then
:
elif [[ "$char" == 'h' ]]; then
helppassed=1
elif [[ "$char" == 'q' ]]; then
quiet=1
elif [[ "$char" == 'v' ]]; then
verbosity="$((verbosity + 1))"
elif [[ "$char" == 'd' ]]; then
dry=1
elif [[ "$char" == 's' ]]; then
small=1
else
echo "$0: invalid option -- '$1'"
echo "Try '$0 --help' for more information."
return 1
fi
done <<<"$1"
}
# Simple help argument checker.
currentarg=1; # Which argument is --help...
# For $arg in the argument array...
for arg in "$@"; do
# Is it a help argument?
if [[ "$arg" == "--help" ]]; then
helppassed=1; # Help is passed, set $helppassed!
set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}" # Remove argument from list
elif [[ "$arg" == "--quiet" ]]; then
quiet=1
set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}"
elif [[ "$arg" == "--verbose" ]]; then
verbosity="$((verbosity + 1))" # Increase verbosity!
set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}"
elif [[ "$arg" == "--dry" ]]; then
dry=1; # Show parameters instead of using them.
set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}"
elif [[ "$arg" == "--small" ]]; then
small=1; # Don't copy assets to save on bandwidth.
set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}"
elif [[ ! "$arg" == *'--'* && "$arg" == *'-'* ]]; then
parseSingleDashArg "$arg"
if [[ "$?" == 0 ]]; then
set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}" # Remove argument from list
fi
elif [[ $arg == *'--'* ]]; then
print "$0: invalid option -- '$1'"
print "Try '$0 --help' for more information."
return 1
else
currentarg="$((currentarg+1))" # Increment current argument number otherwise...
fi
done
important "SRB2Kart AppImage Packager v1.0 modified for kart by NepDisk."
important "Orignal for SRB2 my mazmazz and Golden."
# Get root directory from the full path of this script.
__ROOT_DIR="$3"
if [[ -z "$3" ]]; then
# finds out where this script is and goes to that directory and goes up one for the root
scriptdir="$(dirname "${BASH_SOURCE[0]}")"
scriptbase="$(basename "${BASH_SOURCE[0]}")"
__ROOT_DIR="$(cd "$scriptdir" && pwd -P)"
fi
# If it starts with '.', put the current working directory behind it so things work.
if [[ "$__ROOT_DIR" == '.' || "$__ROOT_DIR" == '..' ]]; then
__ROOT_DIR="$PWD/$__ROOT_DIR"
fi
# Set up defaults
__PROGRAM_NAME="${PROGRAM_NAME:-"SRB2Kart Saturn"}"
__PROGRAM_DESCRIPTION="${PROGRAM_DESCRIPTION:-"Modded version of SRB2kart with more features."}"
__PROGRAM_FILENAME="${PROGRAM_FILENAME:-"lsdl2srb2kart"}"
__PROGRAM_ASSETS="${PROGRAM_ASSETS:-"$__ROOT_DIR/assets/installer"}"
__BUILD_DIR="${1:-"$__ROOT_DIR/bin"}"
__OUTPUT_FILENAME="${2:-"$__PROGRAM_FILENAME.AppImage"}"
__APPIMAGETOOL="${4:-"appimagetool"}"
if (! command -v "$__APPIMAGETOOL" &> /dev/null); then
__APPIMAGETOOL=
fi
# Stuff that prints and exits.
# Prints setup text using method given by arguments.
# Example: printSetup "print" # print "Setup for AppImage...
function printSetup {
$@ "Setup for AppImage in BUILD_DIR: '$__BUILD_DIR'..."
$@ "With the OUTPUT_FILENAME: '$__OUTPUT_FILENAME'"
$@ "And SRB2 Repository Root ROOT_DIR: '$__ROOT_DIR'"
$@ "Using APPIMAGETOOL: '$([ -z "$__APPIMAGETOOL" ] && echo '(download)' || echo $__APPIMAGETOOL)'"
$@ ""
$@ "This should be run from a Makefile or from the directory of the build. If it is not, then change to that directory or specify that directory as an argument."
$@ "If ROOT_DIR isn't SRB2's repository root, specify that as an argument too."
$@ "Make must have built the program before you run this script."
$@ ""
$@ "Make sure these Environment Variables are correct."
$@ "If not, then enter: export PROGRAM_VARIABLE=value"
$@ "PROGRAM_NAME: $__PROGRAM_NAME"
$@ "PROGRAM_DESCRIPTION: $__PROGRAM_DESCRIPTION"
$@ "PROGRAM_FILENAME: $__PROGRAM_FILENAME"
$@ "PROGRAM_ASSETS: $__PROGRAM_ASSETS"
}
if [[ "$helppassed" ]]; then
print "Usage: $(basename "$0") [OPTION]... [BUILD_DIR] [OUTPUT_NAME] [ROOT_DIR] [APPIMAGETOOL]"
print "Packages a SRB2 binary into an AppImage."
print "OPTIONs may be included anywhere within the arguments."
print ""
print "Arguments:"
print " -h, --help display this help and exit."
print " -q, --quiet don't display any text."
print " -v, --verbose make commands more verbose, will always print."
print " -s, --small don't copy SRB2 assets to save on bandwidth."
print " parameters regardless of --dry."
print " -d, --dry print parameters and exit."
print ""
if (( "$verbosity" > 0 )) || [[ "$dry" ]]; then
printSetup "print"
else
print "This should be run from a Makefile or from the directory of the build."
print "Make must have built the program before you run this script."
fi
exit;
fi
if (( "$verbosity" > 0 )) || [[ "$dry" ]]; then
printSetup "verboseOnly" "0"
verboseOnly 0 ""
if [[ "$dry" ]]; then
set -n # Enable debug mode and verbose for dry run.
fi
fi
# End stuff that prints and exits.
if (( "$verbosity" >= 4 )); then
set -v # Really verbose? Print *everything*!
fi
# Define AppDir structure
mkdir -p "$__BUILD_DIR/AppDir/usr/bin"
mkdir -p "$__BUILD_DIR/AppDir/lib"
mkdir -p "$__BUILD_DIR/AppDir/usr/share/applications"
mkdir -p "$__BUILD_DIR/AppDir/usr/share/icons/hicolor/256x256/apps"
# Copy program data
if [[ ! $small ]]; then
verboseOnly 1 "Packaging program assets..."
cp -r "$__PROGRAM_ASSETS"/* "$__BUILD_DIR/AppDir/usr/bin/"
cp -r "$__BUILD_DIR/$__PROGRAM_FILENAME" "$__BUILD_DIR/AppDir/usr/bin"
else
verboseOnly 1 "Skipping program asset packing, --small or -s passed..."
fi
verboseOnly 1 "Packaging SRB2..."
verboseOnly 1 "Assuming executable name $__PROGRAM_FILENAME"
cp -r "$__BUILD_DIR/$__PROGRAM_FILENAME" "$__BUILD_DIR/AppDir/usr/bin"
# Copy required dependencies, but only if the program is dynamically linked.
verboseOnly 1 "Testing if this build is dynamically linked..."
set +e # Disable auto-exit for ldd.
srb2Libraries="$(ldd "$__BUILD_DIR/$__PROGRAM_FILENAME")"
exitcode="$?"
set -e # Enable it again!
if (( $exitcode == 0 )); then
verboseOnly 1 "This build *is* dynamically linked! Packaging dependencies."
# read the dynamic libraries of srb2, trim off beginning whitespace, and get the third field seperated by spaces
# this gives us a newline-seperated list of libraries with their full paths.
srb2Libraries="$(echo "$srb2Libraries" | cut -f 2 | cut -d ' ' -f 3)"
# remove any extraneous newlines around the string
libraryWhitelist="$(echo $libraryWhitelist | head -c -1 | tr ' ' '\n')"
# replace e.g. 'abc' with '(/abc\b)', and replace newlines with '|'.
# this converts it into a grep regular expression to check for any whitelisted library names.
libraryWhitelist="$(printf "%s" "$libraryWhitelist" | sed 's|.*|(/\0\\b)|' | tr '\n' '|')"
# grab only the entries that match the regex
__LDD_LIST="$(printf "%s" "$srb2Libraries" | grep -E "$libraryWhitelist")"
# use echo to convert the newline-seperated list into an argument list
__LDD_LIST="$(echo $__LDD_LIST)"
# read into an array because i can't be bothered iterating the lines of a string today
# there's so many other things in this file that'd need to be adjusted to be POSIX-compliant anyway
IFS=' ' read -r -a paths <<< "$__LDD_LIST"
for path in "${paths[@]}"; do
if [ -f "$path" ]; then
verboseOnly 2 "Packaging dependency $(basename "$path")..."
cp "$path" $__BUILD_DIR/AppDir/lib/
else
verboseOnly 2 "Dependency $(basename "$path") not found"
fi
done
else
verboseOnly 1 "This SRB2 build is statically linked, skipping dependency packing."
fi
cd "$__BUILD_DIR/AppDir"
# Copy icons
verboseOnly 1 "Packaging resources..."
cp "$__ROOT_DIR/srb2.png" "./usr/share/icons/hicolor/256x256/apps/$__PROGRAM_FILENAME.png"
ln -sf "./usr/share/icons/hicolor/256x256/apps/$__PROGRAM_FILENAME.png" "./.DirIcon"
ln -sf "./usr/share/icons/hicolor/256x256/apps/$__PROGRAM_FILENAME.png" "./$__PROGRAM_FILENAME.png"
# Make desktop descriptor
cat > "./usr/share/applications/$__PROGRAM_FILENAME.desktop" <<EOF
[Desktop Entry]
Type=Application
Name=$__PROGRAM_NAME
Comment=$__PROGRAM_DESCRIPTION
Icon=$__PROGRAM_FILENAME
Exec=AppRun %F
Categories=Game;
EOF
ln -sf "./usr/share/applications/$__PROGRAM_FILENAME.desktop" "./$__PROGRAM_FILENAME.desktop"
# Make entry point
echo -e '#!'"$(dirname "$SHELL")/sh" > ./AppRun
echo -e 'HERE="$(dirname "$(readlink -f "${0}")")"' >> ./AppRun
echo -e 'SRB2WADDIR=$HERE/usr/bin LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HERE/lib exec $HERE/usr/bin/'"$__PROGRAM_FILENAME"' "$@"' >> ./AppRun
chmod +x ./AppRun
cd .. # now in $__BUILD_DIR
# Package AppImage
if [ -z "$__APPIMAGETOOL" ]; then
verboseOnly 1 "No valid appimagetool path given or detected, downloading appimagetool..."
# Print notice for internet connection.
important "If the command hangs here, check your internet connection, or download appimagetool and add it to your \$PATH and try compiling again."
(( "$verbosity" >= 3 )) && wget "$url" || wget -q "$url"
APPIMAGETOOL="./$(basename "$url")"
chmod a+x "$APPIMAGETOOL"
else
verboseOnly 1 "appimagetool path given or detected, no download required."
APPIMAGETOOL="$__APPIMAGETOOL"
fi
verboseOnly 1 "Packing AppImage $__OUTPUT_FILENAME"
if (( verbosity >= 3 )); then
"$APPIMAGETOOL" ./AppDir "$__OUTPUT_FILENAME"
elif (( verbosity >= 2 )); then
"$APPIMAGETOOL" ./AppDir "$__OUTPUT_FILENAME" >/dev/null
else
"$APPIMAGETOOL" ./AppDir "$__OUTPUT_FILENAME" >/dev/null 2>&1
fi
success "AppImage ready!"
verboseOnly 1 "Cleaning up files..."
rm -r ./AppDir
if [ -z "$__APPIMAGETOOL" ]; then
rm "$APPIMAGETOOL"
fi
cd "$__ROOT_DIR" # snap back to reality
+97
View File
@@ -52,6 +52,70 @@ Returns the displayplayer's HUD color.
Returns true if colorization is enabled, false otherwise.
## v.interpolate(true)
Enables HUD interpolation. Each call to a drawing function will have its coordinates interpolated
by assigning an unique ID to every call.
For example, three successive calls to `v.draw` will each have their own ID and interpolation offsets.
Pass `true` to enable interpolation, `false` to disable.
Alternatively, pass a number to enable interpolation with the specified tag.
Tags allow HUD items drawn by the same call to a drawing function to be differentiated.
Valid tags range from 0-255.
For example, when iterating players, use a unique tag for each player to avoid artifacting:
```lua
for p in players.iterate do
-- enable interpolation, using player numbers as the tag
-- every draw will have different interp offsets per player
v.interpolate(#p)
-- doesn't matter for unconditional draws like this one...
v.draw(...)
-- but it does matter if there's a condition!
-- without tags, this patch would warp between players
-- whenever their `someVar` changes
if p.someVar then v.draw(...) end
end
-- don't want interpolation anymore? then disable it
v.interpolate(false)
```
NOTE: The default tag for `true` is 0.
## v.interpLatch(true)
Enables interpolation offset latching. The next call to a drawing function will have its lerp offsets
saved and reused for all following draw calls. Disable with `false` when done.
Interpolation cannot easily "snap" between two points; latching can help overcome this by manually
setting the lerp offsets.
```lua
v.interpolate(true)
-- X coordinate for the HUD item
-- every so often, this will wrap around to zero
local x = (leveltime*4) % 256
-- draw an interpolated patch, but... when X rolls back to zero,
-- the patch will slide all the way across the screen!
v.draw(x, 100, ...)
-- this is where interpLatch comes into play
-- enable latching, then draw an invisible patch,
-- moving at the same speed as the visible patch
-- the exact coordinates don't matter, it just has to move at the right speed
v.interpLatch(true)
v.draw(leveltime*4, 0, v.cachePatch("K_TRNULL"))
-- now we can draw the patch again, and when X becomes zero,
-- it'll snap right back without sliding across the screen
v.draw(x, 150, ...)
-- don't forget to turn off latching!
v.interpLatch(false)
```
When using a custom string drawer, enable this mode to avoid interpolation artifacting when the string changes.
## mobj.spritexscale, mobj.spriteyscale, mobj.spritexoffset, mobj.spriteyoffset, mobj.rollangle, mobj.sloperoll, mobj.rollmodel fields
Same fields as in SRB2 2.2
@@ -66,3 +130,36 @@ if rawget(_G, "S_StopSoundByNum") ~= nil then
... -- Can use it
end
```
## addHook("ServerJoin", function())
ServerJoin hook called when client joins server (starting a listen server also calls it for host).
Generally it was made to make loading custom config files less hacky, but can be used for anything else too.
## player.viewrollangle field
Returns player's current view roll angle for the Screen Tilting feature, useful for HUD elements.
## G_SetPlayerGamepadIndicatorColor(player, skincolor)
Set a custom color for Supported Gamepads with RGB LED functionality.
To be used with Displayplayers.
Only takes Skincolors.
Best to be used in a Loop to ensure the color wont get overwritten by the game.
## G_PlayerDeviceRumble(player, low_strength, high_strength, -optional- duration)
Add Gamepad Rumble support for things.
To be used with Displayplayers.
Duration is in milliseconds and is optional to set, default value is 84ms.
# Other changes
## P_PlayRinglossSound(source, damager)
Add optional `damager` argument (should be `mobj_t`), which causes hurt sound also play for damager
if `karthitemdialog` option is enabled
## K_PlayHitEmSound(mobj, victim)
Add optional `victim` argument (should be a player's `mobj_t`), which causes "hit em" sound to be
delayed and played for victim too if `karthitemdialog` option is enabled
+1 -1
View File
@@ -1 +1 @@
/lsdlsrb2
/lsdl2srb2kart
+3
View File
@@ -3,6 +3,9 @@ SRB2.res
depend.dep
depend.ped
*.o
buildvm*
minilua*
lj_vm.S
#VC9 folder only
/VC9/Win32
/VC9/x64
+1
View File
@@ -28,6 +28,7 @@ LOCAL_SRC_FILES := am_map.c \
m_cheat.c \
m_fixed.c \
m_menu.c \
m_textinput.c \
m_misc.c \
m_queue.c \
m_random.c \
+557 -543
View File
File diff suppressed because it is too large. Load diff
+89 -5
View File
@@ -106,6 +106,8 @@ ifeq ($(OS),Windows_NT) # all windows are Windows_NT...
else # if you on the *nix
NOUPX=1
system:=$(shell uname -s)
ifeq ($(system),Linux)
@@ -199,6 +201,24 @@ ifndef NOOPENMPT
HAVE_OPENMPT=1
endif
ifndef NOHW
ifndef NOSCREENFBO
USE_FBO_OGL=1
endif
endif
ifndef NONET
ifndef NOSATURNSYNCH
DOSATURNSYNCH=1
ifndef NOSATURNJOIN
DOSATURNJOIN=1
endif
ifndef NOSATURNPAK
DOSATURNPAK=1
endif
endif
endif
ifdef MINGW
include win32/Makefile.cfg
endif #ifdef MINGW
@@ -240,6 +260,10 @@ endif
MSGFMT?=msgfmt
ifndef NOBLUAJIT
include bluajit/Makefile.cfg
endif
ifndef ECHO
REMOVE:=@$(REMOVE)
CC:=@$(CC)
@@ -272,12 +296,12 @@ ifdef NOHW
OPTS+=-DNOHW
else
OPTS+=-DHWRENDER
OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \
$(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o \
OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o \
$(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o $(OBJDIR)/hw_portal.o\
$(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o $(OBJDIR)/hw_shaders.o
endif
OPTS += -DCOMPVERSION
OPTS += -DCOMPVERSION -fwrapv
ifndef NONX86
ifndef GCC29
@@ -372,6 +396,24 @@ ifdef STATIC
LIBS:=-static $(LIBS)
endif
ifndef NOHW
ifdef USE_FBO_OGL
OPTS+=-DUSE_FBO_OGL
endif
endif
ifndef NONET
ifndef NOSATURNSYNCH
OPTS+=-DDOSATURNSYNCH
ifndef NOSATURNJOIN
OPTS+=-DDOSATURNJOIN
endif
ifndef NOSATURNPAK
OPTS+=-DDOSATURNPAK
endif
endif
endif
ifdef HAVE_MINIUPNPC
ifdef NONET
HAVE_MINIUPNPC=''
@@ -390,7 +432,10 @@ CFLAGS+=-DHAVE_DISCORDRPC -DUSE_STUN
OBJS+=$(OBJDIR)/discord.o $(OBJDIR)/stun.o
endif
ifdef NOBLUAJIT
OPTS+=-DNOBLUAJIT
include blua/Makefile.cfg
endif
ifdef NOMD5
OPTS+=-DNOMD5
@@ -480,6 +525,7 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/hu_stuff.o \
$(OBJDIR)/y_inter.o \
$(OBJDIR)/st_stuff.o \
$(OBJDIR)/k_director.o \
$(OBJDIR)/k_kart.o \
$(OBJDIR)/m_aatree.o \
$(OBJDIR)/m_anigif.o \
@@ -490,6 +536,7 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/m_fixed.o \
$(OBJDIR)/m_menu.o \
$(OBJDIR)/m_misc.o \
$(OBJDIR)/m_textinput.o \
$(OBJDIR)/m_perfstats.o \
$(OBJDIR)/m_random.o \
$(OBJDIR)/m_queue.o \
@@ -523,6 +570,7 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/r_splats.o \
$(OBJDIR)/r_patch.o \
$(OBJDIR)/r_things.o \
$(OBJDIR)/r_portal.o \
$(OBJDIR)/screen.o \
$(OBJDIR)/v_video.o \
$(OBJDIR)/s_sound.o \
@@ -582,6 +630,13 @@ endif
clean:
$(REMOVE) *~ *.flc
$(REMOVE) $(OBJDIR)/*.o
ifndef NOBLUAJIT
$(REMOVE) $(OBJDIR)/buildvm* $(OBJDIR)/minilua* $(OBJDIR)/lj_vm* $(ALL_HDRGEN)
cleanjit:
$(REMOVE) $(LJVMCORE_O) $(ALL_GEN)
$(REMOVE) $(OBJDIR)/buildvm* $(OBJDIR)/minilua* $(OBJDIR)/lj_vm* $(ALL_HDRGEN)
endif
ifdef MINGW
$(REMOVE) $(OBJDIR)/*.res
@@ -618,6 +673,17 @@ ifndef NOUPX
-$(UPX) $(UPX_OPTS) $(BIN)/$(EXENAME)
endif
endif
ifdef APPIMAGE
@echo Building AppImage...
ifdef APPIMAGE_NOASSETS
$(.)../AppImage_build.sh --small --quiet $(BIN)/
else
$(.)../AppImage_build.sh -q $(BIN)/
endif
@echo AppImage build complete, please look for $(EXENAME).AppImage in $(BIN)
endif
@echo Build is done, please look for $(EXENAME) in $(BIN), \(checking for post steps\)
reobjdump:
@@ -687,7 +753,7 @@ ifdef MINGW
$(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \
doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \
command.h hardware/hw_data.h hardware/hw_defs.h hardware/hw_md2.h \
hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \
hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h hardware/hw_portal.h\
hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \
am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \
p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h
@@ -696,7 +762,7 @@ else
$(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \
doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \
command.h hardware/hw_data.h hardware/hw_defs.h hardware/hw_md2.h \
hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \
hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h hardware/hw_portal.h \
hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \
am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \
p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h
@@ -722,7 +788,21 @@ ifndef NOHW
$(CC) $(CFLAGS) -MM hardware/*.c >> $(OBJDIR)/depend.ped
endif
ifdef NOBLUAJIT
$(CC) $(CFLAGS) -MM blua/*.c >> $(OBJDIR)/depend.ped
else
@for file in $(ALL_HDRGEN); do \
test -f $$file || touch $$file; \
done
@$(HOST_CC) $(HOST_ACFLAGS) -MM bluajit/*.c bluajit/host/*.c | \
sed -e "s| [^ ]*/dasm_\S*\.h||g" \
-e "s| lj_target_\S*\.h| lj_target_*.h|g" \
-e "s| lj_emit_\S*\.h| lj_emit_*.h|g" \
-e "s| lj_asm_\S*\.h| lj_asm_*.h|g" >>$(OBJDIR)/depend.ped
@for file in $(ALL_HDRGEN); do \
test -s $$file || $(HOST_RM) $$file; \
done
endif
@sed -e 's,\(.*\)\.o: ,$(subst /,\/,$(OBJDIR))\/&,g' < $(OBJDIR)/depend.ped > $(OBJDIR)/depend.dep
$(REMOVE) $(OBJDIR)/depend.ped
@@ -754,8 +834,12 @@ endif
$(OBJDIR)/%.o: hardware/%.c
$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
ifdef NOBLUAJIT
$(OBJDIR)/%.o: blua/%.c
$(CC) $(CFLAGS) $(LUA_CFLAGS) $(WFLAGS) -c $< -o $@
else
include bluajit/Makefile.cfg2
endif
$(OBJDIR)/%.o: %.s
$(CC) $(OPTS) -x assembler-with-cpp -c $< -o $@
+18 -4
View File
@@ -12,6 +12,7 @@
# to avoid a false positive with the version detection...
SUPPORTED_GCC_VERSIONS:=\
142 141 140 14\
132 131 130 13\
123 122 121 120 12\
114 113 112 111 110 11\
@@ -23,7 +24,7 @@ SUPPORTED_GCC_VERSIONS:=\
55 54 53 52 51 50\
49 48 47 46 45 44 43 42 41 40
LATEST_GCC_VERSION=13.2
LATEST_GCC_VERSION=14.2.1
# gcc or g++
ifdef PREFIX
@@ -77,6 +78,22 @@ ifeq (,$(filter GCC%,$(.VARIABLES)))
endif
endif
ifdef GCC142
GCC141=1
endif
ifdef GCC141
GCC140=1
endif
ifdef GCC14
GCC140=1
endif
ifdef GCC140
GCC132=1
endif
ifdef GCC132
GCC131=1
endif
@@ -428,9 +445,6 @@ endif
ifdef GCC44
WFLAGS+=-Wno-error=array-bounds
endif
ifdef GCC45
opts+=-fwrapv
endif
ifdef GCC46
WFLAGS+=-Wno-error=suggest-attribute=noreturn
endif
+10 -17
View File
@@ -260,25 +260,15 @@ static inline void AM_restoreScaleAndLoc(void)
*/
static void AM_findMinMaxBoundaries(void)
{
size_t i;
fixed_t a;
fixed_t b;
fixed_t a, b;
min_x = min_y = +INT32_MAX;
max_x = max_y = -INT32_MAX;
min_x = minimapinfo.min_x << MAPBITS;
max_x = minimapinfo.max_x << MAPBITS;
min_y = minimapinfo.min_y << MAPBITS;
max_y = minimapinfo.max_y << MAPBITS;
for (i = 0; i < numvertexes; i++)
{
if (vertexes[i].x < min_x)
min_x = vertexes[i].x;
else if (vertexes[i].x > max_x)
max_x = vertexes[i].x;
if (vertexes[i].y < min_y)
min_y = vertexes[i].y;
else if (vertexes[i].y > max_y)
max_y = vertexes[i].y;
}
max_w = minimapinfo.map_w << MAPBITS;
max_h = minimapinfo.map_h << MAPBITS;
max_w = (max_x >>= FRACTOMAPBITS) - (min_x >>= FRACTOMAPBITS);
max_h = (max_y >>= FRACTOMAPBITS) - (min_y >>= FRACTOMAPBITS);
@@ -1015,6 +1005,9 @@ static inline void AM_drawPlayers(void)
{
if (!playeringame[i] || players[i].spectator)
continue;
if (!players[i].mo)
continue;
p = &players[i];
if (p->skincolor > 0)
+1 -1
View File
@@ -71,7 +71,7 @@ apng_create_info_struct (png_structp pngp)
{
apng_infop ainfop;
(void)pngp;
if (( ainfop = calloc(sizeof (apng_info),1) ))
if (( ainfop = calloc(1, sizeof (apng_info)) ))
{
apng_set_write_fn(pngp, ainfop, 0, 0, 0, 0, 0);
apng_set_set_acTL_fn(pngp, ainfop, 0);
+5 -70
View File
@@ -17,27 +17,14 @@
#include "lauxlib.h"
#include "lualib.h"
#include "../i_system.h"
#include "../doomdef.h"
#include "../d_main.h"
#include "../m_misc.h"
#define IO_INPUT 1
#define IO_OUTPUT 2
#define FILELIMIT 1024*1024 // Size limit for reading/writing files
static const char *const fnames[] = {"input", "output"};
static const char *whitelist[] = { // Allow scripters to write files of these types to SRB2's folder
".txt",
".sav2",
".cfg",
".png",
".bmp"
};
static int pushresult (lua_State *L, int i, const char *filename) {
@@ -159,59 +146,12 @@ static int io_tostring (lua_State *L) {
return 1;
}
static int StartsWith(const char *a, const char *b) // this is wolfs being lazy yet again
{
if(strncmp(a, b, strlen(b)) == 0) return 1;
return 0;
}
static int io_open (lua_State *L) {
FILE **pf;
const char *filename = luaL_checkstring(L, 1);
int pass = 0;
size_t i;
int length = strlen(filename);
char *splitter, *forward, *backward;
char *destFilename;
const char *mode = luaL_optstring(L, 2, "r");
for (i = 0; i < (sizeof (whitelist) / sizeof(const char *)); i++)
{
if (!stricmp(&filename[length - strlen(whitelist[i])], whitelist[i]))
{
pass = 1;
break;
}
}
if (strstr(filename, "..") || strchr(filename, ':') || StartsWith(filename, "\\")
|| StartsWith(filename, "/") || !pass)
{
luaL_error(L,"access denied to %s", filename);
return pushresult(L,0,filename);
}
destFilename = va("%s"PATHSEP"luafiles"PATHSEP"%s", srb2home, filename);
// Make directories as needed
splitter = destFilename;
forward = strchr(splitter, '/');
backward = strchr(splitter, '\\');
while ((splitter = (forward && backward) ? min(forward, backward) : (forward ?: backward)))
{
*splitter = 0;
I_mkdir(destFilename, 0755);
*splitter = '/';
splitter++;
forward = strchr(splitter, '/');
backward = strchr(splitter, '\\');
}
pf = newfile(L);
*pf = fopen(destFilename, mode);
return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
FILE **pf = newfile(L);
*pf = fopen(filename, mode);
return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
}
@@ -454,11 +394,6 @@ static int g_write (lua_State *L, FILE *f, int arg) {
else {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
if (ftell(f) + l > FILELIMIT)
{
luaL_error(L,"write limit bypassed in file. Changes have been discarded.");
break;
}
status = status && (fwrite(s, sizeof(char), l, f) == l);
}
}
+9
View File
@@ -0,0 +1,9 @@
luajit
luajit.h
luajit_relver.txt
lj_bcdef.h
lj_ffdef.h
lj_libdef.h
lj_recdef.h
lj_folddef.h
lj_vm.[sS]
+406
View File
@@ -0,0 +1,406 @@
##############################################################################
# LuaJIT Makefile. Requires GNU Make.
#
# Please read doc/install.html before changing any variables!
#
# Suitable for POSIX platforms (Linux, *BSD, OSX etc.).
# Also works with MinGW and Cygwin on Windows.
# Please check msvcbuild.bat for building with MSVC on Windows.
#
# Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
##############################################################################
# this is a very dumbed down version of the LuaJIT makefile.
# to get the original makefile, visit
# https://github.com/GenericHeroGuy/bluajit
XCFLAGS=
XCFLAGS+= -DLUAJIT_DISABLE_FFI
#XCFLAGS+= -DLUAJIT_ENABLE_LUA52COMPAT
#XCFLAGS+= -DLUAJIT_DISABLE_JIT
#XCFLAGS+= -DLUAJIT_USE_SYSMALLOC
#XCFLAGS+= -DLUAJIT_USE_VALGRIND
#XCFLAGS+= -DLUAJIT_USE_GDBJIT
#XCFLAGS+= -DLUA_USE_APICHECK
#XCFLAGS+= -DLUA_USE_ASSERT
XCFLAGS+= -DLUAJIT_DISABLE_BYTECODE
# load standard libraries in debug mode, so jit.dump etc works
ifndef DEBUGMODE
XCFLAGS+= -DLUAJIT_SRB2LIB -DLUAJIT_DISABLE_BUFFER
endif
# additional functions
#XCFLAGS+= -DLUAJIT_SRB2LIB_OS
XCFLAGS+= -DLUAJIT_SRB2LIB_DEBUG
XCFLAGS+= -DLUAJIT_SRB2LIB_IO
# don't touch these unless you wanna have a bad time
XCFLAGS+= -DLUAJIT_NUMMODE=2
XCFLAGS+= -DLUAJIT_INTONLY
# needed for the headers
OPTS+=-DLUAJIT_INTONLY
ifdef MINGW
TARGET_SYS= Windows
HOST_MSYS= mingw
endif
ifeq (Windows,$(findstring Windows,$(OS))$(MSYSTEM)$(TERM))
HOST_SYS= Windows
else
HOST_SYS:= $(shell uname -s)
ifneq (,$(findstring MINGW,$(HOST_SYS)))
HOST_SYS= Windows
HOST_MSYS= mingw
endif
ifneq (,$(findstring MSYS,$(HOST_SYS)))
HOST_SYS= Windows
HOST_MSYS= mingw
endif
ifneq (,$(findstring CYGWIN,$(HOST_SYS)))
HOST_SYS= Windows
HOST_MSYS= cygwin
endif
endif
ASOPTIONS= $(CCOPT) $(XCFLAGS) $(CFLAGS)
CCOPTIONS= $(ASOPTIONS)
HOST_CC= $(CC)
HOST_RM?= rm -f
HOST_XCFLAGS= -Ibluajit
HOST_XLIBS=
HOST_ACFLAGS= $(XCFLAGS) $(HOST_XCFLAGS) $(TARGET_ARCH)
TARGET_CC= $(CROSS)$(CC)
TARGET_LFSFLAGS= -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
TARGET_XCFLAGS= $(TARGET_LFSFLAGS) -U_FORTIFY_SOURCE
TARGET_XLIBS= -lm
TARGET_ACFLAGS= $(CCOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS)
TARGET_ASFLAGS= $(ASOPTIONS) $(TARGET_XCFLAGS) $(TARGET_FLAGS)
TARGET_ACFLAGS+= $(LUA_CFLAGS)
TARGET_TESTARCH:=$(shell $(TARGET_CC) $(TARGET_ACFLAGS) -E bluajit/lj_arch.h -dM)
ifneq (,$(findstring LJ_TARGET_X64 ,$(TARGET_TESTARCH)))
TARGET_LJARCH= x64
else
ifneq (,$(findstring LJ_TARGET_X86 ,$(TARGET_TESTARCH)))
TARGET_LJARCH= x86
else
ifneq (,$(findstring LJ_TARGET_ARM ,$(TARGET_TESTARCH)))
TARGET_LJARCH= arm
else
ifneq (,$(findstring LJ_TARGET_ARM64 ,$(TARGET_TESTARCH)))
ifneq (,$(findstring __AARCH64EB__ ,$(TARGET_TESTARCH)))
TARGET_ARCH= -D__AARCH64EB__=1
endif
TARGET_LJARCH= arm64
else
ifneq (,$(findstring LJ_TARGET_PPC ,$(TARGET_TESTARCH)))
ifneq (,$(findstring LJ_LE 1,$(TARGET_TESTARCH)))
TARGET_ARCH= -DLJ_ARCH_ENDIAN=LUAJIT_LE
else
TARGET_ARCH= -DLJ_ARCH_ENDIAN=LUAJIT_BE
endif
TARGET_LJARCH= ppc
else
ifneq (,$(findstring LJ_TARGET_MIPS ,$(TARGET_TESTARCH)))
ifneq (,$(findstring MIPSEL ,$(TARGET_TESTARCH)))
TARGET_ARCH= -D__MIPSEL__=1
endif
ifneq (,$(findstring LJ_TARGET_MIPS64 ,$(TARGET_TESTARCH)))
TARGET_LJARCH= mips64
else
TARGET_LJARCH= mips
endif
else
$(error Unsupported target architecture)
endif
endif
endif
endif
endif
endif
ifneq (,$(findstring LJ_TARGET_PS3 1,$(TARGET_TESTARCH)))
TARGET_SYS= PS3
TARGET_ARCH+= -D__CELLOS_LV2__
TARGET_XCFLAGS+= -DLUAJIT_USE_SYSMALLOC
TARGET_XLIBS+= -lpthread
endif
TARGET_ARCH+= $(patsubst %,-DLUAJIT_TARGET=LUAJIT_ARCH_%,$(TARGET_LJARCH))
ifneq (,$(PREFIX))
ifneq (/usr/local,$(PREFIX))
TARGET_XCFLAGS+= -DLUA_ROOT=\"$(PREFIX)\"
endif
endif
ifneq (,$(MULTILIB))
TARGET_XCFLAGS+= -DLUA_MULTILIB=\"$(MULTILIB)\"
endif
ifneq (,$(LMULTILIB))
TARGET_XCFLAGS+= -DLUA_LMULTILIB=\"$(LMULTILIB)\"
endif
ifneq (,$(INSTALL_LJLIBD))
TARGET_XCFLAGS+= -DLUA_LJDIR=\"$(INSTALL_LJLIBD)\"
endif
##############################################################################
# Target system detection.
##############################################################################
TARGET_SYS?= $(HOST_SYS)
ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1))
TARGET_XCFLAGS+= -fno-stack-protector
endif
ifeq (Darwin,$(TARGET_SYS))
ifeq (,$(MACOSX_DEPLOYMENT_TARGET))
$(error missing: export MACOSX_DEPLOYMENT_TARGET=XX.YY)
endif
TARGET_XCFLAGS+= -DLUAJIT_UNWIND_EXTERNAL
else
ifeq (iOS,$(TARGET_SYS))
ifeq (arm64,$(TARGET_LJARCH))
TARGET_XCFLAGS+= -fno-omit-frame-pointer
endif
else
ifeq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH)))
# Find out whether the target toolchain always generates unwind tables.
TARGET_TESTUNWIND=$(shell exec 2>/dev/null; echo 'extern void b(void);int a(void){b();return 0;}' | $(TARGET_CC) -c -x c - -o tmpunwind.o && { grep -qa -e eh_frame -e __unwind_info tmpunwind.o || grep -qU -e eh_frame -e __unwind_info tmpunwind.o; } && echo E; rm -f tmpunwind.o)
ifneq (,$(findstring E,$(TARGET_TESTUNWIND)))
TARGET_XCFLAGS+= -DLUAJIT_UNWIND_EXTERNAL
endif
endif
ifeq (Linux,$(TARGET_SYS))
TARGET_XLIBS+= -ldl
endif
ifeq (GNU/kFreeBSD,$(TARGET_SYS))
TARGET_XLIBS+= -ldl
endif
endif
endif
ifneq ($(HOST_SYS),$(TARGET_SYS))
ifeq (Windows,$(TARGET_SYS))
HOST_XCFLAGS+= -malign-double -DLUAJIT_OS=LUAJIT_OS_WINDOWS
else
ifeq (Linux,$(TARGET_SYS))
HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_LINUX
else
ifeq (Darwin,$(TARGET_SYS))
HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OSX
else
ifeq (iOS,$(TARGET_SYS))
HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OSX -DTARGET_OS_IPHONE=1
else
HOST_XCFLAGS+= -DLUAJIT_OS=LUAJIT_OS_OTHER
endif
endif
endif
endif
endif
##############################################################################
# Files and pathnames.
##############################################################################
MINILUA_O= $(OBJDIR)/minilua.o
MINILUA_LIBS= -lm
MINILUA_T= $(OBJDIR)/minilua
MINILUA_X= $(MINILUA_T)
MINILUA_DEP=
HOST_LUA= $(MINILUA_X)
MINILUA_DEP= $(MINILUA_T)
DASM_DIR= bluajit/dynasm
DASM= $(HOST_LUA) $(DASM_DIR)/dynasm.lua
DASM_XFLAGS=
DASM_AFLAGS=
DASM_ARCH= $(TARGET_LJARCH)
ifneq (,$(findstring LJ_LE 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D ENDIAN_LE
else
DASM_AFLAGS+= -D ENDIAN_BE
endif
ifneq (,$(findstring LJ_ARCH_BITS 64,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D P64
endif
ifneq (,$(findstring LJ_HASJIT 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D JIT
endif
ifneq (,$(findstring LJ_HASFFI 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D FFI
endif
ifneq (,$(findstring LJ_DUALNUM 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D DUALNUM
endif
ifneq (,$(findstring LJ_INTONLY 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D INTONLY
endif
ifneq (,$(findstring LJ_ARCH_HASFPU 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D FPU
TARGET_ARCH+= -DLJ_ARCH_HASFPU=1
else
TARGET_ARCH+= -DLJ_ARCH_HASFPU=0
endif
ifeq (,$(findstring LJ_ABI_SOFTFP 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D HFABI
TARGET_ARCH+= -DLJ_ABI_SOFTFP=0
else
TARGET_ARCH+= -DLJ_ABI_SOFTFP=1
endif
ifneq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D NO_UNWIND
TARGET_ARCH+= -DLUAJIT_NO_UNWIND
endif
ifneq (,$(findstring LJ_ABI_PAUTH 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D PAUTH
TARGET_ARCH+= -DLJ_ABI_PAUTH=1
endif
DASM_AFLAGS+= -D VER=$(subst LJ_ARCH_VERSION_,,$(filter LJ_ARCH_VERSION_%,$(subst LJ_ARCH_VERSION ,LJ_ARCH_VERSION_,$(TARGET_TESTARCH))))
ifeq (Windows,$(TARGET_SYS))
DASM_AFLAGS+= -D WIN
endif
ifeq (x64,$(TARGET_LJARCH))
ifeq (,$(findstring LJ_FR2 1,$(TARGET_TESTARCH)))
DASM_ARCH= x86
endif
else
ifeq (arm,$(TARGET_LJARCH))
ifeq (iOS,$(TARGET_SYS))
DASM_AFLAGS+= -D IOS
endif
else
ifneq (,$(findstring LJ_TARGET_MIPSR6 ,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D MIPSR6
endif
ifeq (ppc,$(TARGET_LJARCH))
ifneq (,$(findstring LJ_ARCH_SQRT 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D SQRT
endif
ifneq (,$(findstring LJ_ARCH_ROUND 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D ROUND
endif
ifneq (,$(findstring LJ_ARCH_PPC32ON64 1,$(TARGET_TESTARCH)))
DASM_AFLAGS+= -D GPR64
endif
ifeq (PS3,$(TARGET_SYS))
DASM_AFLAGS+= -D PPE -D TOC
endif
endif
endif
endif
DASM_FLAGS= $(DASM_XFLAGS) $(DASM_AFLAGS)
DASM_DASC= bluajit/vm_$(DASM_ARCH).dasc
GIT= git
ifeq (Windows,$(HOST_SYS)$(HOST_MSYS))
GIT_RELVER= if exist ..\.git ( $(GIT) show -s --format=%%ct >bluajit/luajit_relver.txt ) else ( type ..\.relver >bluajit/luajit_relver.txt )
else
GIT_RELVER= [ -e ../.git ] && $(GIT) show -s --format=%ct >bluajit/luajit_relver.txt 2>/dev/null || cat ../.relver >bluajit/luajit_relver.txt 2>/dev/null || :
endif
GIT_DEP= $(wildcard ../.git/HEAD ../.git/refs/heads/*)
BUILDVM_O= $(OBJDIR)/buildvm.o $(OBJDIR)/buildvm_asm.o $(OBJDIR)/buildvm_peobj.o \
$(OBJDIR)/buildvm_lib.o $(OBJDIR)/buildvm_fold.o
BUILDVM_T= $(OBJDIR)/buildvm
BUILDVM_X= $(BUILDVM_T)
HOST_O= $(MINILUA_O) $(BUILDVM_O)
HOST_T= $(MINILUA_T) $(BUILDVM_T)
LJVM_S= $(OBJDIR)/lj_vm.S
LJVM_O= $(OBJDIR)/lj_vm.o
LJVM_BOUT= $(LJVM_S)
LJVM_MODE= elfasm
LJLIB_O= lib_base.o lib_string.o lib_table.o lib_io.o lib_jit.o
ifeq (,$(filter -DLUAJIT_SRB2LIB,$(XCFLAGS)))
LJLIB_O+= lib_math.o lib_bit.o lib_os.o lib_package.o lib_debug.o lib_ffi.o lib_buffer.o
else
ifneq (,$(filter -DLUAJIT_SRB2LIB_OS,$(XCFLAGS)))
LJLIB_O+= lib_os.o
endif
ifneq (,$(filter -DLUAJIT_SRB2LIB_DEBUG,$(XCFLAGS)))
LJLIB_O+= lib_debug.o
endif
endif
LJLIB_C= $(addprefix bluajit/,$(LJLIB_O:.o=.c))
LJCORE_O= lj_assert.o lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \
lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
lj_prng.o lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o \
lj_strscan.o lj_strfmt.o lj_strfmt_num.o lj_serialize.o \
lj_api.o lj_profile.o \
lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \
lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \
lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \
lj_asm.o lj_trace.o lj_gdbjit.o \
lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_ccallback.o \
lj_carith.o lj_clib.o lj_cparse.o \
lj_lib.o lj_alloc.o lib_aux.o \
$(LJLIB_O) lib_init.o
LJCORE_O:= $(addprefix $(OBJDIR)/,$(LJCORE_O))
LJVMCORE_O= $(LJVM_O) $(LJCORE_O)
LIB_VMDEF= bluajit/jit/vmdef.lua
LIB_VMDEFP= $(LIB_VMDEF)
ALL_T= $(HOST_T)
ALL_HDRGEN:= lj_bcdef.h lj_ffdef.h lj_libdef.h lj_recdef.h lj_folddef.h \
host/buildvm_arch.h luajit.h
ALL_HDRGEN:= $(addprefix bluajit/,$(ALL_HDRGEN))
ALL_GEN= $(LJVM_S) $(ALL_HDRGEN) bluajit/luajit_relver.txt $(LIB_VMDEFP)
##############################################################################
# Build mode handling.
##############################################################################
ifeq (Windows,$(TARGET_SYS))
LJVM_MODE= peobj
LJVM_BOUT= $(LJVM_O)
endif
ifeq (Darwin,$(TARGET_SYS))
LJVM_MODE= machasm
endif
ifeq (iOS,$(TARGET_SYS))
LJVM_MODE= machasm
endif
ifeq (Windows,$(TARGET_SYS))
MINILUA_T= $(OBJDIR)/minilua.exe
BUILDVM_T= $(OBJDIR)/buildvm.exe
ifeq (,$(HOST_MSYS))
MINILUA_X= $(OBJDIR)\minilua
BUILDVM_X= $(OBJDIR)\buildvm
HOST_RM= del
endif
endif
OBJS:=$(OBJS) \
$(LJVMCORE_O) \
$(OBJDIR)/lua_script.o \
$(OBJDIR)/lua_baselib.o \
$(OBJDIR)/lua_blockmaplib.o \
$(OBJDIR)/lua_mathlib.o \
$(OBJDIR)/lua_hooklib.o \
$(OBJDIR)/lua_consolelib.o \
$(OBJDIR)/lua_infolib.o \
$(OBJDIR)/lua_mobjlib.o \
$(OBJDIR)/lua_playerlib.o \
$(OBJDIR)/lua_skinlib.o \
$(OBJDIR)/lua_thinkerlib.o \
$(OBJDIR)/lua_maplib.o \
$(OBJDIR)/lua_hudlib.o \
$(OBJDIR)/lua_hudlib_drawlist.o \
$(OBJDIR)/lua_udatalib.o \
$(OBJDIR)/lua_glib.o
+63
View File
@@ -0,0 +1,63 @@
Q= @
E= @true
#Q=
#E= @:
$(MINILUA_T): $(MINILUA_O)
$(E) "HOSTLINK $@"
$(HOST_CC) -o $@ $(MINILUA_O) $(MINILUA_LIBS)
bluajit/luajit.h: $(MINILUA_DEP) $(GIT_DEP) bluajit/luajit_rolling.h
$(E) "VERSION $@"
$(Q)$(GIT_RELVER)
$(Q)cd bluajit && ../$(HOST_LUA) host/genversion.lua
bluajit/host/buildvm_arch.h: $(DASM_DASC) $(MINILUA_DEP) bluajit/lj_arch.h bluajit/lua.h bluajit/luaconf.h
$(E) "DYNASM $@"
$(Q)$(DASM) $(DASM_FLAGS) -o $@ $(DASM_DASC)
$(OBJDIR)/buildvm.o: $(DASM_DIR)/dasm_*.h
$(BUILDVM_T): $(BUILDVM_O)
$(E) "HOSTLINK $@"
$(HOST_CC) -o $@ $(BUILDVM_O)
$(LJVM_BOUT): $(BUILDVM_T)
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m $(LJVM_MODE) -o $@
bluajit/lj_bcdef.h: $(BUILDVM_T) $(LJLIB_C)
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m bcdef -o $@ $(LJLIB_C)
bluajit/lj_ffdef.h: $(BUILDVM_T) $(LJLIB_C)
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m ffdef -o $@ $(LJLIB_C)
bluajit/lj_libdef.h: $(BUILDVM_T) $(LJLIB_C)
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m libdef -o $@ $(LJLIB_C)
bluajit/lj_recdef.h: $(BUILDVM_T) $(LJLIB_C)
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m recdef -o $@ $(LJLIB_C)
$(LIB_VMDEF): $(BUILDVM_T) $(LJLIB_C)
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m vmdef -o $(LIB_VMDEFP) $(LJLIB_C)
bluajit/lj_folddef.h: $(BUILDVM_T) bluajit/lj_opt_fold.c
$(E) "BUILDVM $@"
$(Q)$(BUILDVM_X) -m folddef -o $@ bluajit/lj_opt_fold.c
$(OBJDIR)/%.o: bluajit/%.c
$(E) "CC $@"
$(TARGET_CC) $(TARGET_ACFLAGS) -c -o $@ $<
$(OBJDIR)/%.o: $(OBJDIR)/lj_vm.S
$(E) "ASM $@"
$(TARGET_CC) $(TARGET_ASFLAGS) -c -o $@ $<
$(HOST_O): $(OBJDIR)/%.o: bluajit/host/%.c
$(E) "HOSTCC $@"
$(HOST_CC) $(HOST_ACFLAGS) -c -o $@ $<
+456
View File
@@ -0,0 +1,456 @@
/*
** DynASM ARM encoding engine.
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define DASM_ARCH "arm"
#ifndef DASM_EXTERN
#define DASM_EXTERN(a,b,c,d) 0
#endif
/* Action definitions. */
enum {
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
/* The following actions need a buffer position. */
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
/* The following actions also have an argument. */
DASM_REL_PC, DASM_LABEL_PC,
DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8,
DASM__MAX
};
/* Maximum number of section buffer positions for a single dasm_put() call. */
#define DASM_MAXSECPOS 25
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
#define DASM_S_OK 0x00000000
#define DASM_S_NOMEM 0x01000000
#define DASM_S_PHASE 0x02000000
#define DASM_S_MATCH_SEC 0x03000000
#define DASM_S_RANGE_I 0x11000000
#define DASM_S_RANGE_SEC 0x12000000
#define DASM_S_RANGE_LG 0x13000000
#define DASM_S_RANGE_PC 0x14000000
#define DASM_S_RANGE_REL 0x15000000
#define DASM_S_UNDEF_LG 0x21000000
#define DASM_S_UNDEF_PC 0x22000000
/* Macros to convert positions (8 bit section + 24 bit index). */
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
#define DASM_SEC2POS(sec) ((sec)<<24)
#define DASM_POS2SEC(pos) ((pos)>>24)
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
/* Action list type. */
typedef const unsigned int *dasm_ActList;
/* Per-section structure. */
typedef struct dasm_Section {
int *rbuf; /* Biased buffer pointer (negative section bias). */
int *buf; /* True buffer pointer. */
size_t bsize; /* Buffer size in bytes. */
int pos; /* Biased buffer position. */
int epos; /* End of biased buffer position - max single put. */
int ofs; /* Byte offset into section. */
} dasm_Section;
/* Core structure holding the DynASM encoding state. */
struct dasm_State {
size_t psize; /* Allocated size of this structure. */
dasm_ActList actionlist; /* Current actionlist pointer. */
int *lglabels; /* Local/global chain/pos ptrs. */
size_t lgsize;
int *pclabels; /* PC label chains/pos ptrs. */
size_t pcsize;
void **globals; /* Array of globals. */
dasm_Section *section; /* Pointer to active section. */
size_t codesize; /* Total size of all code sections. */
int maxsection; /* 0 <= sectionidx < maxsection. */
int status; /* Status code. */
dasm_Section sections[1]; /* All sections. Alloc-extended. */
};
/* The size of the core structure depends on the max. number of sections. */
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
/* Initialize DynASM state. */
void dasm_init(Dst_DECL, int maxsection)
{
dasm_State *D;
size_t psz = 0;
Dst_REF = NULL;
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
D = Dst_REF;
D->psize = psz;
D->lglabels = NULL;
D->lgsize = 0;
D->pclabels = NULL;
D->pcsize = 0;
D->globals = NULL;
D->maxsection = maxsection;
memset((void *)D->sections, 0, maxsection * sizeof(dasm_Section));
}
/* Free DynASM state. */
void dasm_free(Dst_DECL)
{
dasm_State *D = Dst_REF;
int i;
for (i = 0; i < D->maxsection; i++)
if (D->sections[i].buf)
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
DASM_M_FREE(Dst, D, D->psize);
}
/* Setup global label array. Must be called before dasm_setup(). */
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
{
dasm_State *D = Dst_REF;
D->globals = gl;
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
}
/* Grow PC label array. Can be called after dasm_setup(), too. */
void dasm_growpc(Dst_DECL, unsigned int maxpc)
{
dasm_State *D = Dst_REF;
size_t osz = D->pcsize;
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
}
/* Setup encoder. */
void dasm_setup(Dst_DECL, const void *actionlist)
{
dasm_State *D = Dst_REF;
int i;
D->actionlist = (dasm_ActList)actionlist;
D->status = DASM_S_OK;
D->section = &D->sections[0];
memset((void *)D->lglabels, 0, D->lgsize);
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
for (i = 0; i < D->maxsection; i++) {
D->sections[i].pos = DASM_SEC2POS(i);
D->sections[i].rbuf = D->sections[i].buf - D->sections[i].pos;
D->sections[i].ofs = 0;
}
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) { \
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
#define CKPL(kind, st) \
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
#else
#define CK(x, st) ((void)0)
#define CKPL(kind, st) ((void)0)
#endif
static int dasm_imm12(unsigned int n)
{
int i;
for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30))
if (n <= 255) return (int)(n + (i << 8));
return -1;
}
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
void dasm_put(Dst_DECL, int start, ...)
{
va_list ap;
dasm_State *D = Dst_REF;
dasm_ActList p = D->actionlist + start;
dasm_Section *sec = D->section;
int pos = sec->pos, ofs = sec->ofs;
int *b;
if (pos >= sec->epos) {
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
}
b = sec->rbuf;
b[pos++] = start;
va_start(ap, start);
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
if (action >= DASM__MAX) {
ofs += 4;
} else {
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
switch (action) {
case DASM_STOP: goto stop;
case DASM_SECTION:
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
D->section = &D->sections[n]; goto stop;
case DASM_ESC: p++; ofs += 4; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
case DASM_REL_LG:
n = (ins & 2047) - 10; pl = D->lglabels + n;
/* Bkwd rel or global. */
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
pl += 10; n = *pl;
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
goto linkrel;
case DASM_REL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putrel:
n = *pl;
if (n < 0) { /* Label exists. Get label pos and store it. */
b[pos] = -n;
} else {
linkrel:
b[pos] = n; /* Else link to rel chain, anchored at label. */
*pl = pos;
}
pos++;
break;
case DASM_LABEL_LG:
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
case DASM_LABEL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putlabel:
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
}
*pl = -pos; /* Label exists now. */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_IMM:
case DASM_IMM16:
#ifdef DASM_CHECKS
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
if ((ins & 0x8000))
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
else
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
#endif
b[pos++] = n;
break;
case DASM_IMMV8:
CK((n & 3) == 0, RANGE_I);
n >>= 2;
/* fallthrough */
case DASM_IMML8:
case DASM_IMML12:
CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) :
(((-n)>>((ins>>5)&31)) == 0), RANGE_I);
b[pos++] = n;
break;
case DASM_IMM12:
CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
b[pos++] = n;
break;
}
}
}
stop:
va_end(ap);
sec->pos = pos;
sec->ofs = ofs;
}
#undef CK
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
int dasm_link(Dst_DECL, size_t *szp)
{
dasm_State *D = Dst_REF;
int secnum;
int ofs = 0;
#ifdef DASM_CHECKS
*szp = 0;
if (D->status != DASM_S_OK) return D->status;
{
int pc;
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
}
#endif
{ /* Handle globals not defined in this translation unit. */
int idx;
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
int n = D->lglabels[idx];
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
}
}
/* Combine all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->rbuf;
int pos = DASM_SEC2POS(secnum);
int lastpos = sec->pos;
while (pos != lastpos) {
dasm_ActList p = D->actionlist + b[pos++];
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: p++; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
case DASM_IMM: case DASM_IMM12: case DASM_IMM16:
case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break;
}
}
stop: (void)0;
}
ofs += sec->ofs; /* Next section starts right after current section. */
}
D->codesize = ofs; /* Total size of all code sections */
*szp = ofs;
return DASM_S_OK;
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
#else
#define CK(x, st) ((void)0)
#endif
/* Pass 3: Encode sections. */
int dasm_encode(Dst_DECL, void *buffer)
{
dasm_State *D = Dst_REF;
char *base = (char *)buffer;
unsigned int *cp = (unsigned int *)buffer;
int secnum;
/* Encode all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->buf;
int *endb = sec->rbuf + sec->pos;
while (b != endb) {
dasm_ActList p = D->actionlist + *b++;
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: *cp++ = *p++; break;
case DASM_REL_EXT:
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
goto patchrel;
case DASM_ALIGN:
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
break;
case DASM_REL_LG:
if (n < 0) {
n = (int)((ptrdiff_t)D->globals[-n-10] - (ptrdiff_t)cp - 4);
goto patchrel;
}
/* fallthrough */
case DASM_REL_PC:
CK(n >= 0, UNDEF_PC);
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4;
patchrel:
if ((ins & 0x800) == 0) {
CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL);
cp[-1] |= ((n >> 2) & 0x00ffffff);
} else if ((ins & 0x1000)) {
CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL);
goto patchimml8;
} else if ((ins & 0x2000) == 0) {
CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL);
goto patchimml;
} else {
CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL);
n >>= 2;
goto patchimml;
}
break;
case DASM_LABEL_LG:
ins &= 2047; if (ins >= 20) D->globals[ins-20] = (void *)(base + n);
break;
case DASM_LABEL_PC: break;
case DASM_IMM:
cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31);
break;
case DASM_IMM12:
cp[-1] |= dasm_imm12((unsigned int)n);
break;
case DASM_IMM16:
cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff);
break;
case DASM_IMML8: patchimml8:
cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) :
((-n & 0x0f) | ((-n & 0xf0) << 4));
break;
case DASM_IMML12: case DASM_IMMV8: patchimml:
cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n);
break;
default: *cp++ = ins; break;
}
}
stop: (void)0;
}
}
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
return DASM_S_PHASE;
return DASM_S_OK;
}
#undef CK
/* Get PC label offset. */
int dasm_getpclabel(Dst_DECL, unsigned int pc)
{
dasm_State *D = Dst_REF;
if (pc*sizeof(int) < D->pcsize) {
int pos = D->pclabels[pc];
if (pos < 0) return *DASM_POS2PTR(D, -pos);
if (pos > 0) return -1; /* Undefined. */
}
return -2; /* Unused or out of range. */
}
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
int dasm_checkstep(Dst_DECL, int secmatch)
{
dasm_State *D = Dst_REF;
if (D->status == DASM_S_OK) {
int i;
for (i = 1; i <= 9; i++) {
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
D->lglabels[i] = 0;
}
}
if (D->status == DASM_S_OK && secmatch >= 0 &&
D->section != &D->sections[secmatch])
D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
return D->status;
}
#endif
File diff suppressed because it is too large. Load diff
+558
View File
@@ -0,0 +1,558 @@
/*
** DynASM ARM64 encoding engine.
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define DASM_ARCH "arm64"
#ifndef DASM_EXTERN
#define DASM_EXTERN(a,b,c,d) 0
#endif
/* Action definitions. */
enum {
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
/* The following actions need a buffer position. */
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
/* The following actions also have an argument. */
DASM_REL_PC, DASM_LABEL_PC, DASM_REL_A,
DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML,
DASM_IMMV, DASM_VREG,
DASM__MAX
};
/* Maximum number of section buffer positions for a single dasm_put() call. */
#define DASM_MAXSECPOS 25
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
#define DASM_S_OK 0x00000000
#define DASM_S_NOMEM 0x01000000
#define DASM_S_PHASE 0x02000000
#define DASM_S_MATCH_SEC 0x03000000
#define DASM_S_RANGE_I 0x11000000
#define DASM_S_RANGE_SEC 0x12000000
#define DASM_S_RANGE_LG 0x13000000
#define DASM_S_RANGE_PC 0x14000000
#define DASM_S_RANGE_REL 0x15000000
#define DASM_S_RANGE_VREG 0x16000000
#define DASM_S_UNDEF_LG 0x21000000
#define DASM_S_UNDEF_PC 0x22000000
/* Macros to convert positions (8 bit section + 24 bit index). */
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
#define DASM_SEC2POS(sec) ((sec)<<24)
#define DASM_POS2SEC(pos) ((pos)>>24)
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
/* Action list type. */
typedef const unsigned int *dasm_ActList;
/* Per-section structure. */
typedef struct dasm_Section {
int *rbuf; /* Biased buffer pointer (negative section bias). */
int *buf; /* True buffer pointer. */
size_t bsize; /* Buffer size in bytes. */
int pos; /* Biased buffer position. */
int epos; /* End of biased buffer position - max single put. */
int ofs; /* Byte offset into section. */
} dasm_Section;
/* Core structure holding the DynASM encoding state. */
struct dasm_State {
size_t psize; /* Allocated size of this structure. */
dasm_ActList actionlist; /* Current actionlist pointer. */
int *lglabels; /* Local/global chain/pos ptrs. */
size_t lgsize;
int *pclabels; /* PC label chains/pos ptrs. */
size_t pcsize;
void **globals; /* Array of globals. */
dasm_Section *section; /* Pointer to active section. */
size_t codesize; /* Total size of all code sections. */
int maxsection; /* 0 <= sectionidx < maxsection. */
int status; /* Status code. */
dasm_Section sections[1]; /* All sections. Alloc-extended. */
};
/* The size of the core structure depends on the max. number of sections. */
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
/* Initialize DynASM state. */
void dasm_init(Dst_DECL, int maxsection)
{
dasm_State *D;
size_t psz = 0;
Dst_REF = NULL;
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
D = Dst_REF;
D->psize = psz;
D->lglabels = NULL;
D->lgsize = 0;
D->pclabels = NULL;
D->pcsize = 0;
D->globals = NULL;
D->maxsection = maxsection;
memset((void *)D->sections, 0, maxsection * sizeof(dasm_Section));
}
/* Free DynASM state. */
void dasm_free(Dst_DECL)
{
dasm_State *D = Dst_REF;
int i;
for (i = 0; i < D->maxsection; i++)
if (D->sections[i].buf)
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
DASM_M_FREE(Dst, D, D->psize);
}
/* Setup global label array. Must be called before dasm_setup(). */
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
{
dasm_State *D = Dst_REF;
D->globals = gl;
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
}
/* Grow PC label array. Can be called after dasm_setup(), too. */
void dasm_growpc(Dst_DECL, unsigned int maxpc)
{
dasm_State *D = Dst_REF;
size_t osz = D->pcsize;
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
}
/* Setup encoder. */
void dasm_setup(Dst_DECL, const void *actionlist)
{
dasm_State *D = Dst_REF;
int i;
D->actionlist = (dasm_ActList)actionlist;
D->status = DASM_S_OK;
D->section = &D->sections[0];
memset((void *)D->lglabels, 0, D->lgsize);
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
for (i = 0; i < D->maxsection; i++) {
D->sections[i].pos = DASM_SEC2POS(i);
D->sections[i].rbuf = D->sections[i].buf - D->sections[i].pos;
D->sections[i].ofs = 0;
}
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) { \
D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0)
#define CKPL(kind, st) \
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
D->status = DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0)
#else
#define CK(x, st) ((void)0)
#define CKPL(kind, st) ((void)0)
#endif
static int dasm_imm12(unsigned int n)
{
if ((n >> 12) == 0)
return n;
else if ((n & 0xff000fff) == 0)
return (n >> 12) | 0x1000;
else
return -1;
}
static int dasm_ffs(unsigned long long x)
{
int n = -1;
while (x) { x >>= 1; n++; }
return n;
}
static int dasm_imm13(int lo, int hi)
{
int inv = 0, w = 64, s = 0xfff, xa, xb;
unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo;
unsigned long long m = 1ULL, a, b, c;
if (n & 1) { n = ~n; inv = 1; }
a = n & (unsigned long long)-(long long)n;
b = (n+a)&(unsigned long long)-(long long)(n+a);
c = (n+a-b)&(unsigned long long)-(long long)(n+a-b);
xa = dasm_ffs(a); xb = dasm_ffs(b);
if (c) {
w = dasm_ffs(c) - xa;
if (w == 32) m = 0x0000000100000001UL;
else if (w == 16) m = 0x0001000100010001UL;
else if (w == 8) m = 0x0101010101010101UL;
else if (w == 4) m = 0x1111111111111111UL;
else if (w == 2) m = 0x5555555555555555UL;
else return -1;
s = (-2*w & 0x3f) - 1;
} else if (!a) {
return -1;
} else if (xb == -1) {
xb = 64;
}
if ((b-a) * m != n) return -1;
if (inv) {
return ((w - xb) << 6) | (s+w+xa-xb);
} else {
return ((w - xa) << 6) | (s+xb-xa);
}
return -1;
}
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
void dasm_put(Dst_DECL, int start, ...)
{
va_list ap;
dasm_State *D = Dst_REF;
dasm_ActList p = D->actionlist + start;
dasm_Section *sec = D->section;
int pos = sec->pos, ofs = sec->ofs;
int *b;
if (pos >= sec->epos) {
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
}
b = sec->rbuf;
b[pos++] = start;
va_start(ap, start);
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
if (action >= DASM__MAX) {
ofs += 4;
} else {
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
switch (action) {
case DASM_STOP: goto stop;
case DASM_SECTION:
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
D->section = &D->sections[n]; goto stop;
case DASM_ESC: p++; ofs += 4; break;
case DASM_REL_EXT: if ((ins & 0x8000)) ofs += 8; break;
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
case DASM_REL_LG:
n = (ins & 2047) - 10; pl = D->lglabels + n;
/* Bkwd rel or global. */
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
pl += 10; n = *pl;
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
goto linkrel;
case DASM_REL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putrel:
n = *pl;
if (n < 0) { /* Label exists. Get label pos and store it. */
b[pos] = -n;
} else {
linkrel:
b[pos] = n; /* Else link to rel chain, anchored at label. */
*pl = pos;
}
pos++;
if ((ins & 0x8000)) ofs += 8;
break;
case DASM_REL_A:
b[pos++] = n;
b[pos++] = va_arg(ap, int);
break;
case DASM_LABEL_LG:
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
case DASM_LABEL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putlabel:
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
}
*pl = -pos; /* Label exists now. */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_IMM:
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
n >>= ((ins>>10)&31);
#ifdef DASM_CHECKS
if ((ins & 0x8000))
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
else
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
#endif
b[pos++] = n;
break;
case DASM_IMM6:
CK((n >> 6) == 0, RANGE_I);
b[pos++] = n;
break;
case DASM_IMM12:
CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
b[pos++] = n;
break;
case DASM_IMM13W:
CK(dasm_imm13(n, n) != -1, RANGE_I);
b[pos++] = n;
break;
case DASM_IMM13X: {
int m = va_arg(ap, int);
CK(dasm_imm13(n, m) != -1, RANGE_I);
b[pos++] = n;
b[pos++] = m;
break;
}
case DASM_IMML: {
#ifdef DASM_CHECKS
int scale = (ins & 3);
CK((!(n & ((1<<scale)-1)) && (unsigned int)(n>>scale) < 4096) ||
(unsigned int)(n+256) < 512, RANGE_I);
#endif
b[pos++] = n;
break;
}
case DASM_IMMV:
ofs += 4;
b[pos++] = n;
break;
case DASM_VREG:
CK(n < 32, RANGE_VREG);
b[pos++] = n;
break;
}
}
}
stop:
va_end(ap);
sec->pos = pos;
sec->ofs = ofs;
}
#undef CK
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
int dasm_link(Dst_DECL, size_t *szp)
{
dasm_State *D = Dst_REF;
int secnum;
int ofs = 0;
#ifdef DASM_CHECKS
*szp = 0;
if (D->status != DASM_S_OK) return D->status;
{
int pc;
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
}
#endif
{ /* Handle globals not defined in this translation unit. */
int idx;
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
int n = D->lglabels[idx];
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
}
}
/* Combine all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->rbuf;
int pos = DASM_SEC2POS(secnum);
int lastpos = sec->pos;
while (pos != lastpos) {
dasm_ActList p = D->actionlist + b[pos++];
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: p++; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
case DASM_IMM: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W:
case DASM_IMML: case DASM_IMMV: case DASM_VREG: pos++; break;
case DASM_IMM13X: case DASM_REL_A: pos += 2; break;
}
}
stop: (void)0;
}
ofs += sec->ofs; /* Next section starts right after current section. */
}
D->codesize = ofs; /* Total size of all code sections */
*szp = ofs;
return DASM_S_OK;
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) return DASM_S_##st|(int)(p-D->actionlist-1); } while (0)
#else
#define CK(x, st) ((void)0)
#endif
/* Pass 3: Encode sections. */
int dasm_encode(Dst_DECL, void *buffer)
{
dasm_State *D = Dst_REF;
char *base = (char *)buffer;
unsigned int *cp = (unsigned int *)buffer;
int secnum;
/* Encode all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->buf;
int *endb = sec->rbuf + sec->pos;
while (b != endb) {
dasm_ActList p = D->actionlist + *b++;
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: *cp++ = *p++; break;
case DASM_REL_EXT:
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
goto patchrel;
case DASM_ALIGN:
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xd503201f;
break;
case DASM_REL_LG:
if (n < 0) {
ptrdiff_t na = (ptrdiff_t)D->globals[-n-10] - (ptrdiff_t)cp + 4;
n = (int)na;
CK((ptrdiff_t)n == na, RANGE_REL);
goto patchrel;
}
/* fallthrough */
case DASM_REL_PC:
CK(n >= 0, UNDEF_PC);
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4;
patchrel:
if (!(ins & 0xf800)) { /* B, BL */
CK((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, RANGE_REL);
cp[-1] |= ((n >> 2) & 0x03ffffff);
} else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */
CK((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, RANGE_REL);
cp[-1] |= ((n << 3) & 0x00ffffe0);
} else if ((ins & 0x3000) == 0x2000) { /* ADR */
CK(((n+0x00100000) >> 21) == 0, RANGE_REL);
cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29);
} else if ((ins & 0x3000) == 0x3000) { /* ADRP */
cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29);
} else if ((ins & 0x1000)) { /* TBZ, TBNZ */
CK((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, RANGE_REL);
cp[-1] |= ((n << 3) & 0x0007ffe0);
} else if ((ins & 0x8000)) { /* absolute */
cp[0] = (unsigned int)((ptrdiff_t)cp - 4 + n);
cp[1] = (unsigned int)(((ptrdiff_t)cp - 4 + n) >> 32);
cp += 2;
}
break;
case DASM_REL_A: {
ptrdiff_t na = (((ptrdiff_t)(*b++) << 32) | (unsigned int)n);
if ((ins & 0x3000) == 0x3000) { /* ADRP */
ins &= ~0x1000;
na = (na >> 12) - (((ptrdiff_t)cp - 4) >> 12);
} else {
na = na - (ptrdiff_t)cp + 4;
}
n = (int)na;
CK((ptrdiff_t)n == na, RANGE_REL);
goto patchrel;
}
case DASM_LABEL_LG:
ins &= 2047; if (ins >= 20) D->globals[ins-20] = (void *)(base + n);
break;
case DASM_LABEL_PC: break;
case DASM_IMM:
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
break;
case DASM_IMM6:
cp[-1] |= ((n&31) << 19) | ((n&32) << 26);
break;
case DASM_IMM12:
cp[-1] |= (dasm_imm12((unsigned int)n) << 10);
break;
case DASM_IMM13W:
cp[-1] |= (dasm_imm13(n, n) << 10);
break;
case DASM_IMM13X:
cp[-1] |= (dasm_imm13(n, *b++) << 10);
break;
case DASM_IMML: {
int scale = (ins & 3);
cp[-1] |= (!(n & ((1<<scale)-1)) && (unsigned int)(n>>scale) < 4096) ?
((n << (10-scale)) | 0x01000000) : ((n & 511) << 12);
break;
}
case DASM_IMMV:
*cp++ = n;
break;
case DASM_VREG:
cp[-1] |= (n & 0x1f) << (ins & 0x1f);
break;
default: *cp++ = ins; break;
}
}
stop: (void)0;
}
}
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
return DASM_S_PHASE;
return DASM_S_OK;
}
#undef CK
/* Get PC label offset. */
int dasm_getpclabel(Dst_DECL, unsigned int pc)
{
dasm_State *D = Dst_REF;
if (pc*sizeof(int) < D->pcsize) {
int pos = D->pclabels[pc];
if (pos < 0) return *DASM_POS2PTR(D, -pos);
if (pos > 0) return -1; /* Undefined. */
}
return -2; /* Unused or out of range. */
}
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
int dasm_checkstep(Dst_DECL, int secmatch)
{
dasm_State *D = Dst_REF;
if (D->status == DASM_S_OK) {
int i;
for (i = 1; i <= 9; i++) {
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
D->lglabels[i] = 0;
}
}
if (D->status == DASM_S_OK && secmatch >= 0 &&
D->section != &D->sections[secmatch])
D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections);
return D->status;
}
#endif
File diff suppressed because it is too large. Load diff
+419
View File
@@ -0,0 +1,419 @@
/*
** DynASM MIPS encoding engine.
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define DASM_ARCH "mips"
#ifndef DASM_EXTERN
#define DASM_EXTERN(a,b,c,d) 0
#endif
/* Action definitions. */
enum {
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
/* The following actions need a buffer position. */
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
/* The following actions also have an argument. */
DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMS,
DASM__MAX
};
/* Maximum number of section buffer positions for a single dasm_put() call. */
#define DASM_MAXSECPOS 25
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
#define DASM_S_OK 0x00000000
#define DASM_S_NOMEM 0x01000000
#define DASM_S_PHASE 0x02000000
#define DASM_S_MATCH_SEC 0x03000000
#define DASM_S_RANGE_I 0x11000000
#define DASM_S_RANGE_SEC 0x12000000
#define DASM_S_RANGE_LG 0x13000000
#define DASM_S_RANGE_PC 0x14000000
#define DASM_S_RANGE_REL 0x15000000
#define DASM_S_UNDEF_LG 0x21000000
#define DASM_S_UNDEF_PC 0x22000000
/* Macros to convert positions (8 bit section + 24 bit index). */
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
#define DASM_SEC2POS(sec) ((sec)<<24)
#define DASM_POS2SEC(pos) ((pos)>>24)
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
/* Action list type. */
typedef const unsigned int *dasm_ActList;
/* Per-section structure. */
typedef struct dasm_Section {
int *rbuf; /* Biased buffer pointer (negative section bias). */
int *buf; /* True buffer pointer. */
size_t bsize; /* Buffer size in bytes. */
int pos; /* Biased buffer position. */
int epos; /* End of biased buffer position - max single put. */
int ofs; /* Byte offset into section. */
} dasm_Section;
/* Core structure holding the DynASM encoding state. */
struct dasm_State {
size_t psize; /* Allocated size of this structure. */
dasm_ActList actionlist; /* Current actionlist pointer. */
int *lglabels; /* Local/global chain/pos ptrs. */
size_t lgsize;
int *pclabels; /* PC label chains/pos ptrs. */
size_t pcsize;
void **globals; /* Array of globals. */
dasm_Section *section; /* Pointer to active section. */
size_t codesize; /* Total size of all code sections. */
int maxsection; /* 0 <= sectionidx < maxsection. */
int status; /* Status code. */
dasm_Section sections[1]; /* All sections. Alloc-extended. */
};
/* The size of the core structure depends on the max. number of sections. */
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
/* Initialize DynASM state. */
void dasm_init(Dst_DECL, int maxsection)
{
dasm_State *D;
size_t psz = 0;
Dst_REF = NULL;
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
D = Dst_REF;
D->psize = psz;
D->lglabels = NULL;
D->lgsize = 0;
D->pclabels = NULL;
D->pcsize = 0;
D->globals = NULL;
D->maxsection = maxsection;
memset((void *)D->sections, 0, maxsection * sizeof(dasm_Section));
}
/* Free DynASM state. */
void dasm_free(Dst_DECL)
{
dasm_State *D = Dst_REF;
int i;
for (i = 0; i < D->maxsection; i++)
if (D->sections[i].buf)
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
DASM_M_FREE(Dst, D, D->psize);
}
/* Setup global label array. Must be called before dasm_setup(). */
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
{
dasm_State *D = Dst_REF;
D->globals = gl;
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
}
/* Grow PC label array. Can be called after dasm_setup(), too. */
void dasm_growpc(Dst_DECL, unsigned int maxpc)
{
dasm_State *D = Dst_REF;
size_t osz = D->pcsize;
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
}
/* Setup encoder. */
void dasm_setup(Dst_DECL, const void *actionlist)
{
dasm_State *D = Dst_REF;
int i;
D->actionlist = (dasm_ActList)actionlist;
D->status = DASM_S_OK;
D->section = &D->sections[0];
memset((void *)D->lglabels, 0, D->lgsize);
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
for (i = 0; i < D->maxsection; i++) {
D->sections[i].pos = DASM_SEC2POS(i);
D->sections[i].rbuf = D->sections[i].buf - D->sections[i].pos;
D->sections[i].ofs = 0;
}
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) { \
D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0)
#define CKPL(kind, st) \
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
D->status = DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0)
#else
#define CK(x, st) ((void)0)
#define CKPL(kind, st) ((void)0)
#endif
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
void dasm_put(Dst_DECL, int start, ...)
{
va_list ap;
dasm_State *D = Dst_REF;
dasm_ActList p = D->actionlist + start;
dasm_Section *sec = D->section;
int pos = sec->pos, ofs = sec->ofs;
int *b;
if (pos >= sec->epos) {
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
}
b = sec->rbuf;
b[pos++] = start;
va_start(ap, start);
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16) - 0xff00;
if (action >= DASM__MAX) {
ofs += 4;
} else {
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
switch (action) {
case DASM_STOP: goto stop;
case DASM_SECTION:
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
D->section = &D->sections[n]; goto stop;
case DASM_ESC: p++; ofs += 4; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
case DASM_REL_LG:
n = (ins & 2047) - 10; pl = D->lglabels + n;
/* Bkwd rel or global. */
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
pl += 10; n = *pl;
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
goto linkrel;
case DASM_REL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putrel:
n = *pl;
if (n < 0) { /* Label exists. Get label pos and store it. */
b[pos] = -n;
} else {
linkrel:
b[pos] = n; /* Else link to rel chain, anchored at label. */
*pl = pos;
}
pos++;
break;
case DASM_LABEL_LG:
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
case DASM_LABEL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putlabel:
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
}
*pl = -pos; /* Label exists now. */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_IMM: case DASM_IMMS:
#ifdef DASM_CHECKS
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
#endif
n >>= ((ins>>10)&31);
#ifdef DASM_CHECKS
if (ins & 0x8000)
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
else
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
#endif
b[pos++] = n;
break;
}
}
}
stop:
va_end(ap);
sec->pos = pos;
sec->ofs = ofs;
}
#undef CK
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
int dasm_link(Dst_DECL, size_t *szp)
{
dasm_State *D = Dst_REF;
int secnum;
int ofs = 0;
#ifdef DASM_CHECKS
*szp = 0;
if (D->status != DASM_S_OK) return D->status;
{
int pc;
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
}
#endif
{ /* Handle globals not defined in this translation unit. */
int idx;
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
int n = D->lglabels[idx];
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
}
}
/* Combine all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->rbuf;
int pos = DASM_SEC2POS(secnum);
int lastpos = sec->pos;
while (pos != lastpos) {
dasm_ActList p = D->actionlist + b[pos++];
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16) - 0xff00;
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: p++; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
case DASM_IMM: case DASM_IMMS: pos++; break;
}
}
stop: (void)0;
}
ofs += sec->ofs; /* Next section starts right after current section. */
}
D->codesize = ofs; /* Total size of all code sections */
*szp = ofs;
return DASM_S_OK;
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) return DASM_S_##st|(int)(p-D->actionlist-1); } while (0)
#else
#define CK(x, st) ((void)0)
#endif
/* Pass 3: Encode sections. */
int dasm_encode(Dst_DECL, void *buffer)
{
dasm_State *D = Dst_REF;
char *base = (char *)buffer;
unsigned int *cp = (unsigned int *)buffer;
int secnum;
/* Encode all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->buf;
int *endb = sec->rbuf + sec->pos;
while (b != endb) {
dasm_ActList p = D->actionlist + *b++;
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16) - 0xff00;
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: *cp++ = *p++; break;
case DASM_REL_EXT:
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1);
goto patchrel;
case DASM_ALIGN:
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
break;
case DASM_REL_LG:
if (n < 0) {
n = (int)((ptrdiff_t)D->globals[-n-10] - (ptrdiff_t)cp);
goto patchrel;
}
/* fallthrough */
case DASM_REL_PC:
CK(n >= 0, UNDEF_PC);
n = *DASM_POS2PTR(D, n);
if (ins & 2048)
n = (n + (int)(size_t)base) & 0x0fffffff;
else
n = n - (int)((char *)cp - base);
patchrel: {
unsigned int e = 16 + ((ins >> 12) & 15);
CK((n & 3) == 0 &&
((n + ((ins & 2048) ? 0 : (1<<(e+1)))) >> (e+2)) == 0, RANGE_REL);
cp[-1] |= ((n>>2) & ((1<<e)-1));
}
break;
case DASM_LABEL_LG:
ins &= 2047; if (ins >= 20) D->globals[ins-20] = (void *)(base + n);
break;
case DASM_LABEL_PC: break;
case DASM_IMMS:
cp[-1] |= ((n>>3) & 4); n &= 0x1f;
/* fallthrough */
case DASM_IMM:
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
break;
default: *cp++ = ins; break;
}
}
stop: (void)0;
}
}
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
return DASM_S_PHASE;
return DASM_S_OK;
}
#undef CK
/* Get PC label offset. */
int dasm_getpclabel(Dst_DECL, unsigned int pc)
{
dasm_State *D = Dst_REF;
if (pc*sizeof(int) < D->pcsize) {
int pos = D->pclabels[pc];
if (pos < 0) return *DASM_POS2PTR(D, -pos);
if (pos > 0) return -1; /* Undefined. */
}
return -2; /* Unused or out of range. */
}
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
int dasm_checkstep(Dst_DECL, int secmatch)
{
dasm_State *D = Dst_REF;
if (D->status == DASM_S_OK) {
int i;
for (i = 1; i <= 9; i++) {
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
D->lglabels[i] = 0;
}
}
if (D->status == DASM_S_OK && secmatch >= 0 &&
D->section != &D->sections[secmatch])
D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections);
return D->status;
}
#endif
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
------------------------------------------------------------------------------
-- DynASM MIPS64 module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- See dynasm.lua for full copyright notice.
------------------------------------------------------------------------------
-- This module just sets 64 bit mode for the combined MIPS/MIPS64 module.
-- All the interesting stuff is there.
------------------------------------------------------------------------------
mips64 = true -- Using a global is an ugly, but effective solution.
return require("dasm_mips")
+418
View File
@@ -0,0 +1,418 @@
/*
** DynASM PPC/PPC64 encoding engine.
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define DASM_ARCH "ppc"
#ifndef DASM_EXTERN
#define DASM_EXTERN(a,b,c,d) 0
#endif
/* Action definitions. */
enum {
DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
/* The following actions need a buffer position. */
DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
/* The following actions also have an argument. */
DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMSH,
DASM__MAX
};
/* Maximum number of section buffer positions for a single dasm_put() call. */
#define DASM_MAXSECPOS 25
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
#define DASM_S_OK 0x00000000
#define DASM_S_NOMEM 0x01000000
#define DASM_S_PHASE 0x02000000
#define DASM_S_MATCH_SEC 0x03000000
#define DASM_S_RANGE_I 0x11000000
#define DASM_S_RANGE_SEC 0x12000000
#define DASM_S_RANGE_LG 0x13000000
#define DASM_S_RANGE_PC 0x14000000
#define DASM_S_RANGE_REL 0x15000000
#define DASM_S_UNDEF_LG 0x21000000
#define DASM_S_UNDEF_PC 0x22000000
/* Macros to convert positions (8 bit section + 24 bit index). */
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
#define DASM_SEC2POS(sec) ((sec)<<24)
#define DASM_POS2SEC(pos) ((pos)>>24)
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
/* Action list type. */
typedef const unsigned int *dasm_ActList;
/* Per-section structure. */
typedef struct dasm_Section {
int *rbuf; /* Biased buffer pointer (negative section bias). */
int *buf; /* True buffer pointer. */
size_t bsize; /* Buffer size in bytes. */
int pos; /* Biased buffer position. */
int epos; /* End of biased buffer position - max single put. */
int ofs; /* Byte offset into section. */
} dasm_Section;
/* Core structure holding the DynASM encoding state. */
struct dasm_State {
size_t psize; /* Allocated size of this structure. */
dasm_ActList actionlist; /* Current actionlist pointer. */
int *lglabels; /* Local/global chain/pos ptrs. */
size_t lgsize;
int *pclabels; /* PC label chains/pos ptrs. */
size_t pcsize;
void **globals; /* Array of globals. */
dasm_Section *section; /* Pointer to active section. */
size_t codesize; /* Total size of all code sections. */
int maxsection; /* 0 <= sectionidx < maxsection. */
int status; /* Status code. */
dasm_Section sections[1]; /* All sections. Alloc-extended. */
};
/* The size of the core structure depends on the max. number of sections. */
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
/* Initialize DynASM state. */
void dasm_init(Dst_DECL, int maxsection)
{
dasm_State *D;
size_t psz = 0;
Dst_REF = NULL;
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
D = Dst_REF;
D->psize = psz;
D->lglabels = NULL;
D->lgsize = 0;
D->pclabels = NULL;
D->pcsize = 0;
D->globals = NULL;
D->maxsection = maxsection;
memset((void *)D->sections, 0, maxsection * sizeof(dasm_Section));
}
/* Free DynASM state. */
void dasm_free(Dst_DECL)
{
dasm_State *D = Dst_REF;
int i;
for (i = 0; i < D->maxsection; i++)
if (D->sections[i].buf)
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
DASM_M_FREE(Dst, D, D->psize);
}
/* Setup global label array. Must be called before dasm_setup(). */
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
{
dasm_State *D = Dst_REF;
D->globals = gl;
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
}
/* Grow PC label array. Can be called after dasm_setup(), too. */
void dasm_growpc(Dst_DECL, unsigned int maxpc)
{
dasm_State *D = Dst_REF;
size_t osz = D->pcsize;
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
}
/* Setup encoder. */
void dasm_setup(Dst_DECL, const void *actionlist)
{
dasm_State *D = Dst_REF;
int i;
D->actionlist = (dasm_ActList)actionlist;
D->status = DASM_S_OK;
D->section = &D->sections[0];
memset((void *)D->lglabels, 0, D->lgsize);
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
for (i = 0; i < D->maxsection; i++) {
D->sections[i].pos = DASM_SEC2POS(i);
D->sections[i].rbuf = D->sections[i].buf - D->sections[i].pos;
D->sections[i].ofs = 0;
}
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) { \
D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
#define CKPL(kind, st) \
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
#else
#define CK(x, st) ((void)0)
#define CKPL(kind, st) ((void)0)
#endif
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
void dasm_put(Dst_DECL, int start, ...)
{
va_list ap;
dasm_State *D = Dst_REF;
dasm_ActList p = D->actionlist + start;
dasm_Section *sec = D->section;
int pos = sec->pos, ofs = sec->ofs;
int *b;
if (pos >= sec->epos) {
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
}
b = sec->rbuf;
b[pos++] = start;
va_start(ap, start);
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
if (action >= DASM__MAX) {
ofs += 4;
} else {
int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
switch (action) {
case DASM_STOP: goto stop;
case DASM_SECTION:
n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
D->section = &D->sections[n]; goto stop;
case DASM_ESC: p++; ofs += 4; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
case DASM_REL_LG:
n = (ins & 2047) - 10; pl = D->lglabels + n;
/* Bkwd rel or global. */
if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
pl += 10; n = *pl;
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
goto linkrel;
case DASM_REL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putrel:
n = *pl;
if (n < 0) { /* Label exists. Get label pos and store it. */
b[pos] = -n;
} else {
linkrel:
b[pos] = n; /* Else link to rel chain, anchored at label. */
*pl = pos;
}
pos++;
break;
case DASM_LABEL_LG:
pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
case DASM_LABEL_PC:
pl = D->pclabels + n; CKPL(pc, PC);
putlabel:
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
}
*pl = -pos; /* Label exists now. */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_IMM:
#ifdef DASM_CHECKS
CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
#endif
n >>= ((ins>>10)&31);
#ifdef DASM_CHECKS
if (ins & 0x8000)
CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
else
CK((n>>((ins>>5)&31)) == 0, RANGE_I);
#endif
b[pos++] = n;
break;
case DASM_IMMSH:
CK((n >> 6) == 0, RANGE_I);
b[pos++] = n;
break;
}
}
}
stop:
va_end(ap);
sec->pos = pos;
sec->ofs = ofs;
}
#undef CK
/* Pass 2: Link sections, shrink aligns, fix label offsets. */
int dasm_link(Dst_DECL, size_t *szp)
{
dasm_State *D = Dst_REF;
int secnum;
int ofs = 0;
#ifdef DASM_CHECKS
*szp = 0;
if (D->status != DASM_S_OK) return D->status;
{
int pc;
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
}
#endif
{ /* Handle globals not defined in this translation unit. */
int idx;
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
int n = D->lglabels[idx];
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
}
}
/* Combine all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->rbuf;
int pos = DASM_SEC2POS(secnum);
int lastpos = sec->pos;
while (pos != lastpos) {
dasm_ActList p = D->actionlist + b[pos++];
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: p++; break;
case DASM_REL_EXT: break;
case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
case DASM_REL_LG: case DASM_REL_PC: pos++; break;
case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
case DASM_IMM: case DASM_IMMSH: pos++; break;
}
}
stop: (void)0;
}
ofs += sec->ofs; /* Next section starts right after current section. */
}
D->codesize = ofs; /* Total size of all code sections */
*szp = ofs;
return DASM_S_OK;
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
#else
#define CK(x, st) ((void)0)
#endif
/* Pass 3: Encode sections. */
int dasm_encode(Dst_DECL, void *buffer)
{
dasm_State *D = Dst_REF;
char *base = (char *)buffer;
unsigned int *cp = (unsigned int *)buffer;
int secnum;
/* Encode all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->buf;
int *endb = sec->rbuf + sec->pos;
while (b != endb) {
dasm_ActList p = D->actionlist + *b++;
while (1) {
unsigned int ins = *p++;
unsigned int action = (ins >> 16);
int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
switch (action) {
case DASM_STOP: case DASM_SECTION: goto stop;
case DASM_ESC: *cp++ = *p++; break;
case DASM_REL_EXT:
n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4;
goto patchrel;
case DASM_ALIGN:
ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
break;
case DASM_REL_LG:
if (n < 0) {
n = (int)((ptrdiff_t)D->globals[-n-10] - (ptrdiff_t)cp);
goto patchrel;
}
/* fallthrough */
case DASM_REL_PC:
CK(n >= 0, UNDEF_PC);
n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base);
patchrel:
CK((n & 3) == 0 &&
(((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >>
((ins & 2048) ? 16 : 26)) == 0, RANGE_REL);
cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc));
break;
case DASM_LABEL_LG:
ins &= 2047; if (ins >= 20) D->globals[ins-20] = (void *)(base + n);
break;
case DASM_LABEL_PC: break;
case DASM_IMM:
cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
break;
case DASM_IMMSH:
cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32);
break;
default: *cp++ = ins; break;
}
}
stop: (void)0;
}
}
if (base + D->codesize != (char *)cp) /* Check for phase errors. */
return DASM_S_PHASE;
return DASM_S_OK;
}
#undef CK
/* Get PC label offset. */
int dasm_getpclabel(Dst_DECL, unsigned int pc)
{
dasm_State *D = Dst_REF;
if (pc*sizeof(int) < D->pcsize) {
int pos = D->pclabels[pc];
if (pos < 0) return *DASM_POS2PTR(D, -pos);
if (pos > 0) return -1; /* Undefined. */
}
return -2; /* Unused or out of range. */
}
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
int dasm_checkstep(Dst_DECL, int secmatch)
{
dasm_State *D = Dst_REF;
if (D->status == DASM_S_OK) {
int i;
for (i = 1; i <= 9; i++) {
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
D->lglabels[i] = 0;
}
}
if (D->status == DASM_S_OK && secmatch >= 0 &&
D->section != &D->sections[secmatch])
D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
return D->status;
}
#endif
File diff suppressed because it is too large. Load diff
+83
View File
@@ -0,0 +1,83 @@
/*
** DynASM encoding engine prototypes.
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#ifndef _DASM_PROTO_H
#define _DASM_PROTO_H
#include <stddef.h>
#include <stdarg.h>
#define DASM_IDENT "DynASM 1.5.0"
#define DASM_VERSION 10500 /* 1.5.0 */
#ifndef Dst_DECL
#define Dst_DECL dasm_State **Dst
#endif
#ifndef Dst_REF
#define Dst_REF (*Dst)
#endif
#ifndef DASM_FDEF
#define DASM_FDEF extern
#endif
#ifndef DASM_M_GROW
#define DASM_M_GROW(ctx, t, p, sz, need) \
do { \
size_t _sz = (sz), _need = (need); \
if (_sz < _need) { \
if (_sz < 16) _sz = 16; \
while (_sz < _need) _sz += _sz; \
(p) = (t *)realloc((p), _sz); \
if ((p) == NULL) exit(1); \
(sz) = _sz; \
} \
} while(0)
#endif
#ifndef DASM_M_FREE
#define DASM_M_FREE(ctx, p, sz) free(p)
#endif
/* Internal DynASM encoder state. */
typedef struct dasm_State dasm_State;
/* Initialize and free DynASM state. */
DASM_FDEF void dasm_init(Dst_DECL, int maxsection);
DASM_FDEF void dasm_free(Dst_DECL);
/* Setup global array. Must be called before dasm_setup(). */
DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl);
/* Grow PC label array. Can be called after dasm_setup(), too. */
DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc);
/* Setup encoder. */
DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist);
/* Feed encoder with actions. Calls are generated by pre-processor. */
DASM_FDEF void dasm_put(Dst_DECL, int start, ...);
/* Link sections and return the resulting size. */
DASM_FDEF int dasm_link(Dst_DECL, size_t *szp);
/* Encode sections into buffer. */
DASM_FDEF int dasm_encode(Dst_DECL, void *buffer);
/* Get PC label offset. */
DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc);
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch);
#else
#define dasm_checkstep(a, b) 0
#endif
#endif /* _DASM_PROTO_H */
+12
View File
@@ -0,0 +1,12 @@
------------------------------------------------------------------------------
-- DynASM x64 module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- See dynasm.lua for full copyright notice.
------------------------------------------------------------------------------
-- This module just sets 64 bit mode for the combined x86/x64 module.
-- All the interesting stuff is there.
------------------------------------------------------------------------------
x64 = true -- Using a global is an ugly, but effective solution.
return require("dasm_x86")
+523
View File
@@ -0,0 +1,523 @@
/*
** DynASM x86 encoding engine.
** Copyright (C) 2005-2023 Mike Pall. All rights reserved.
** Released under the MIT license. See dynasm.lua for full copyright notice.
*/
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define DASM_ARCH "x86"
#ifndef DASM_EXTERN
#define DASM_EXTERN(a,b,c,d) 0
#endif
/* Action definitions. DASM_STOP must be 255. */
enum {
DASM_DISP = 233,
DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB,
DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC,
DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN,
DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP
};
/* Maximum number of section buffer positions for a single dasm_put() call. */
#define DASM_MAXSECPOS 25
/* DynASM encoder status codes. Action list offset or number are or'ed in. */
#define DASM_S_OK 0x00000000
#define DASM_S_NOMEM 0x01000000
#define DASM_S_PHASE 0x02000000
#define DASM_S_MATCH_SEC 0x03000000
#define DASM_S_RANGE_I 0x11000000
#define DASM_S_RANGE_SEC 0x12000000
#define DASM_S_RANGE_LG 0x13000000
#define DASM_S_RANGE_PC 0x14000000
#define DASM_S_RANGE_VREG 0x15000000
#define DASM_S_UNDEF_L 0x21000000
#define DASM_S_UNDEF_PC 0x22000000
/* Macros to convert positions (8 bit section + 24 bit index). */
#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
#define DASM_SEC2POS(sec) ((sec)<<24)
#define DASM_POS2SEC(pos) ((pos)>>24)
#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
/* Action list type. */
typedef const unsigned char *dasm_ActList;
/* Per-section structure. */
typedef struct dasm_Section {
int *rbuf; /* Biased buffer pointer (negative section bias). */
int *buf; /* True buffer pointer. */
size_t bsize; /* Buffer size in bytes. */
int pos; /* Biased buffer position. */
int epos; /* End of biased buffer position - max single put. */
int ofs; /* Byte offset into section. */
} dasm_Section;
/* Core structure holding the DynASM encoding state. */
struct dasm_State {
size_t psize; /* Allocated size of this structure. */
dasm_ActList actionlist; /* Current actionlist pointer. */
int *lglabels; /* Local/global chain/pos ptrs. */
size_t lgsize;
int *pclabels; /* PC label chains/pos ptrs. */
size_t pcsize;
void **globals; /* Array of globals. */
dasm_Section *section; /* Pointer to active section. */
size_t codesize; /* Total size of all code sections. */
int maxsection; /* 0 <= sectionidx < maxsection. */
int status; /* Status code. */
dasm_Section sections[1]; /* All sections. Alloc-extended. */
};
/* The size of the core structure depends on the max. number of sections. */
#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
/* Initialize DynASM state. */
void dasm_init(Dst_DECL, int maxsection)
{
dasm_State *D;
size_t psz = 0;
Dst_REF = NULL;
DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
D = Dst_REF;
D->psize = psz;
D->lglabels = NULL;
D->lgsize = 0;
D->pclabels = NULL;
D->pcsize = 0;
D->globals = NULL;
D->maxsection = maxsection;
memset((void *)D->sections, 0, maxsection * sizeof(dasm_Section));
}
/* Free DynASM state. */
void dasm_free(Dst_DECL)
{
dasm_State *D = Dst_REF;
int i;
for (i = 0; i < D->maxsection; i++)
if (D->sections[i].buf)
DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
DASM_M_FREE(Dst, D, D->psize);
}
/* Setup global label array. Must be called before dasm_setup(). */
void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
{
dasm_State *D = Dst_REF;
D->globals = gl;
DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
}
/* Grow PC label array. Can be called after dasm_setup(), too. */
void dasm_growpc(Dst_DECL, unsigned int maxpc)
{
dasm_State *D = Dst_REF;
size_t osz = D->pcsize;
DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
}
/* Setup encoder. */
void dasm_setup(Dst_DECL, const void *actionlist)
{
dasm_State *D = Dst_REF;
int i;
D->actionlist = (dasm_ActList)actionlist;
D->status = DASM_S_OK;
D->section = &D->sections[0];
memset((void *)D->lglabels, 0, D->lgsize);
if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
for (i = 0; i < D->maxsection; i++) {
D->sections[i].pos = DASM_SEC2POS(i);
D->sections[i].rbuf = D->sections[i].buf - D->sections[i].pos;
D->sections[i].ofs = 0;
}
}
#ifdef DASM_CHECKS
#define CK(x, st) \
do { if (!(x)) { \
D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0)
#define CKPL(kind, st) \
do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0)
#else
#define CK(x, st) ((void)0)
#define CKPL(kind, st) ((void)0)
#endif
/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
void dasm_put(Dst_DECL, int start, ...)
{
va_list ap;
dasm_State *D = Dst_REF;
dasm_ActList p = D->actionlist + start;
dasm_Section *sec = D->section;
int pos = sec->pos, ofs = sec->ofs, mrm = -1;
int *b;
if (pos >= sec->epos) {
DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
}
b = sec->rbuf;
b[pos++] = start;
va_start(ap, start);
while (1) {
int action = *p++;
if (action < DASM_DISP) {
ofs++;
} else if (action <= DASM_REL_A) {
int n = va_arg(ap, int);
b[pos++] = n;
switch (action) {
case DASM_DISP:
if (n == 0) { if (mrm < 0) mrm = p[-2]; if ((mrm&7) != 5) break; }
/* fallthrough */
case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */
case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */
case DASM_IMM_D: ofs += 4; break;
case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob;
case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break;
case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */
case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break;
case DASM_SPACE: p++; ofs += n; break;
case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */
case DASM_VREG: CK((n&-16) == 0 && (n != 4 || (*p>>5) != 2), RANGE_VREG);
if (*p < 0x40 && p[1] == DASM_DISP) mrm = n;
if (*p < 0x20 && (n&7) == 4) ofs++;
switch ((*p++ >> 3) & 3) {
case 3: n |= b[pos-3]; /* fallthrough */
case 2: n |= b[pos-2]; /* fallthrough */
case 1: if (n <= 7) { b[pos-1] |= 0x10; ofs--; }
}
continue;
}
mrm = -1;
} else {
int *pl, n;
switch (action) {
case DASM_REL_LG:
case DASM_IMM_LG:
n = *p++; pl = D->lglabels + n;
/* Bkwd rel or global. */
if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
pl -= 246; n = *pl;
if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
goto linkrel;
case DASM_REL_PC:
case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
putrel:
n = *pl;
if (n < 0) { /* Label exists. Get label pos and store it. */
b[pos] = -n;
} else {
linkrel:
b[pos] = n; /* Else link to rel chain, anchored at label. */
*pl = pos;
}
pos++;
ofs += 4; /* Maximum offset needed. */
if (action == DASM_REL_LG || action == DASM_REL_PC) {
b[pos++] = ofs; /* Store pass1 offset estimate. */
} else if (sizeof(ptrdiff_t) == 8) {
ofs += 4;
}
break;
case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel;
case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
putlabel:
n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; }
*pl = -pos; /* Label exists now. */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_ALIGN:
ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */
b[pos++] = ofs; /* Store pass1 offset estimate. */
break;
case DASM_EXTERN: p += 2; ofs += 4; break;
case DASM_ESC: p++; ofs++; break;
case DASM_MARK: mrm = p[-2]; break;
case DASM_SECTION:
n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n];
case DASM_STOP: goto stop;
}
}
}
stop:
va_end(ap);
sec->pos = pos;
sec->ofs = ofs;
}
#undef CK
/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */
int dasm_link(Dst_DECL, size_t *szp)
{
dasm_State *D = Dst_REF;
int secnum;
int ofs = 0;
#ifdef DASM_CHECKS
*szp = 0;
if (D->status != DASM_S_OK) return D->status;
{
int pc;
for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
}
#endif
{ /* Handle globals not defined in this translation unit. */
int idx;
for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
int n = D->lglabels[idx];
/* Undefined label: Collapse rel chain and replace with marker (< 0). */
while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
}
}
/* Combine all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->rbuf;
int pos = DASM_SEC2POS(secnum);
int lastpos = sec->pos;
while (pos != lastpos) {
dasm_ActList p = D->actionlist + b[pos++];
int op = 0;
while (1) {
int action = *p++;
switch (action) {
case DASM_REL_LG: p++;
/* fallthrough */
case DASM_REL_PC: {
int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0);
if (shrink) { /* Shrinkable branch opcode? */
int lofs, lpos = b[pos];
if (lpos < 0) goto noshrink; /* Ext global? */
lofs = *DASM_POS2PTR(D, lpos);
if (lpos > pos) { /* Fwd label: add cumulative section offsets. */
int i;
for (i = secnum; i < DASM_POS2SEC(lpos); i++)
lofs += D->sections[i].ofs;
} else {
lofs -= ofs; /* Bkwd label: unfix offset. */
}
lofs -= b[pos+1]; /* Short branch ok? */
if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */
else { noshrink: shrink = 0; } /* No, cannot shrink op. */
}
b[pos+1] = shrink;
pos += 2;
break;
}
/* fallthrough */
case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++;
/* fallthrough */
case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W:
case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB:
case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break;
case DASM_LABEL_LG: p++;
/* fallthrough */
case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */
case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */
case DASM_EXTERN: p += 2; break;
case DASM_ESC: op = *p++; break;
case DASM_MARK: break;
case DASM_SECTION: case DASM_STOP: goto stop;
default: op = action; break;
}
}
stop: (void)0;
}
ofs += sec->ofs; /* Next section starts right after current section. */
}
D->codesize = ofs; /* Total size of all code sections */
*szp = ofs;
return DASM_S_OK;
}
#define dasmb(x) *cp++ = (unsigned char)(x)
#ifndef DASM_ALIGNED_WRITES
#define dasmw(x) \
do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0)
#define dasmd(x) \
do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0)
#define dasmq(x) \
do { *((unsigned long long *)cp) = (unsigned long long)(x); cp+=8; } while (0)
#else
#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0)
#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0)
#define dasmq(x) do { dasmd(x); dasmd((x)>>32); } while (0)
#endif
static unsigned char *dasma_(unsigned char *cp, ptrdiff_t x)
{
if (sizeof(ptrdiff_t) == 8)
dasmq((unsigned long long)x);
else
dasmd((unsigned int)x);
return cp;
}
#define dasma(x) (cp = dasma_(cp, (x)))
/* Pass 3: Encode sections. */
int dasm_encode(Dst_DECL, void *buffer)
{
dasm_State *D = Dst_REF;
unsigned char *base = (unsigned char *)buffer;
unsigned char *cp = base;
int secnum;
/* Encode all code sections. No support for data sections (yet). */
for (secnum = 0; secnum < D->maxsection; secnum++) {
dasm_Section *sec = D->sections + secnum;
int *b = sec->buf;
int *endb = sec->rbuf + sec->pos;
while (b != endb) {
dasm_ActList p = D->actionlist + *b++;
unsigned char *mark = NULL;
while (1) {
int action = *p++;
int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0;
switch (action) {
case DASM_DISP: if (!mark) mark = cp; {
unsigned char *mm = mark;
if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL;
if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7;
if (mrm != 5) { mm[-1] -= 0x80; break; } }
if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40;
}
/* fallthrough */
case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break;
case DASM_IMM_DB: if (((n+128)&-256) == 0) {
db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb;
} else mark = NULL;
/* fallthrough */
case DASM_IMM_D: wd: dasmd(n); break;
case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL;
/* fallthrough */
case DASM_IMM_W: dasmw(n); break;
case DASM_VREG: {
int t = *p++;
unsigned char *ex = cp - (t&7);
if ((n & 8) && t < 0xa0) {
if (*ex & 0x80) ex[1] ^= 0x20 << (t>>6); else *ex ^= 1 << (t>>6);
n &= 7;
} else if (n & 0x10) {
if (*ex & 0x80) {
*ex = 0xc5; ex[1] = (ex[1] & 0x80) | ex[2]; ex += 2;
}
while (++ex < cp) ex[-1] = *ex;
if (mark) mark--;
cp--;
n &= 7;
}
if (t >= 0xc0) n <<= 4;
else if (t >= 0x40) n <<= 3;
else if (n == 4 && t < 0x20) { cp[-1] ^= n; *cp++ = 0x20; }
cp[-1] ^= n;
break;
}
case DASM_REL_LG: p++; if (n >= 0) goto rel_pc;
b++; n = (int)(ptrdiff_t)D->globals[-n-10];
/* fallthrough */
case DASM_REL_A: rel_a:
n -= (unsigned int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */
case DASM_REL_PC: rel_pc: {
int shrink = *b++;
int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; }
n = *pb - ((int)(cp-base) + 4-shrink);
if (shrink == 0) goto wd;
if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb;
goto wb;
}
case DASM_IMM_LG:
p++;
if (n < 0) { dasma((ptrdiff_t)D->globals[-n-10]); break; }
/* fallthrough */
case DASM_IMM_PC: {
int *pb = DASM_POS2PTR(D, n);
dasma(*pb < 0 ? (ptrdiff_t)pb[1] : (*pb + (ptrdiff_t)base));
break;
}
case DASM_LABEL_LG: {
int idx = *p++;
if (idx >= 10)
D->globals[idx-10] = (void *)(base + (*p == DASM_SETLABEL ? *b : n));
break;
}
case DASM_LABEL_PC: case DASM_SETLABEL: break;
case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; }
case DASM_ALIGN:
n = *p++;
while (((cp-base) & n)) *cp++ = 0x90; /* nop */
break;
case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd;
case DASM_MARK: mark = cp; break;
case DASM_ESC: action = *p++;
/* fallthrough */
default: *cp++ = action; break;
case DASM_SECTION: case DASM_STOP: goto stop;
}
}
stop: (void)0;
}
}
if (base + D->codesize != cp) /* Check for phase errors. */
return DASM_S_PHASE;
return DASM_S_OK;
}
/* Get PC label offset. */
int dasm_getpclabel(Dst_DECL, unsigned int pc)
{
dasm_State *D = Dst_REF;
if (pc*sizeof(int) < D->pcsize) {
int pos = D->pclabels[pc];
if (pos < 0) return *DASM_POS2PTR(D, -pos);
if (pos > 0) return -1; /* Undefined. */
}
return -2; /* Unused or out of range. */
}
#ifdef DASM_CHECKS
/* Optional sanity checker to call between isolated encoding steps. */
int dasm_checkstep(Dst_DECL, int secmatch)
{
dasm_State *D = Dst_REF;
if (D->status == DASM_S_OK) {
int i;
for (i = 1; i <= 9; i++) {
if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; }
D->lglabels[i] = 0;
}
}
if (D->status == DASM_S_OK && secmatch >= 0 &&
D->section != &D->sections[secmatch])
D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections);
return D->status;
}
#endif
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+3
View File
@@ -0,0 +1,3 @@
minilua
buildvm
buildvm_arch.h
+4
View File
@@ -0,0 +1,4 @@
The files in this directory are only used during the build process of LuaJIT.
For cross-compilation, they must be executed on the host, not on the target.
These files should NOT be installed!
+529
View File
@@ -0,0 +1,529 @@
/*
** LuaJIT VM builder.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** This is a tool to build the hand-tuned assembler code required for
** LuaJIT's bytecode interpreter. It supports a variety of output formats
** to feed different toolchains (see usage() below).
**
** This tool is not particularly optimized because it's only used while
** _building_ LuaJIT. There's no point in distributing or installing it.
** Only the object code generated by this tool is linked into LuaJIT.
**
** Caveat: some memory is not free'd, error handling is lazy.
** It's a one-shot tool -- any effort fixing this would be wasted.
*/
#include "buildvm.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_bc.h"
#if LJ_HASJIT
#include "lj_ir.h"
#include "lj_ircall.h"
#endif
#include "lj_frame.h"
#include "lj_dispatch.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_ccall.h"
#endif
#include "luajit.h"
#if defined(_WIN32)
#include <fcntl.h>
#include <io.h>
#endif
/* ------------------------------------------------------------------------ */
/* DynASM glue definitions. */
#define Dst ctx
#define Dst_DECL BuildCtx *ctx
#define Dst_REF (ctx->D)
#define DASM_CHECKS 1
#include "../dynasm/dasm_proto.h"
/* Glue macros for DynASM. */
static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type);
#define DASM_EXTERN(ctx, addr, idx, type) \
collect_reloc(ctx, addr, idx, type)
/* ------------------------------------------------------------------------ */
/* Avoid trouble if cross-compiling for an x86 target. Speed doesn't matter. */
#define DASM_ALIGNED_WRITES 1
/* Embed architecture-specific DynASM encoder. */
#if LJ_TARGET_X86ORX64
#include "../dynasm/dasm_x86.h"
#elif LJ_TARGET_ARM
#include "../dynasm/dasm_arm.h"
#elif LJ_TARGET_ARM64
#include "../dynasm/dasm_arm64.h"
#elif LJ_TARGET_PPC
#include "../dynasm/dasm_ppc.h"
#elif LJ_TARGET_MIPS
#include "../dynasm/dasm_mips.h"
#else
#error "No support for this architecture (yet)"
#endif
/* Embed generated architecture-specific backend. */
#include "buildvm_arch.h"
/* ------------------------------------------------------------------------ */
void owrite(BuildCtx *ctx, const void *ptr, size_t sz)
{
if (fwrite(ptr, 1, sz, ctx->fp) != sz) {
fprintf(stderr, "Error: cannot write to output file: %s\n",
strerror(errno));
exit(1);
}
}
/* ------------------------------------------------------------------------ */
/* Emit code as raw bytes. Only used for DynASM debugging. */
static void emit_raw(BuildCtx *ctx)
{
owrite(ctx, ctx->code, ctx->codesz);
}
/* -- Build machine code -------------------------------------------------- */
static const char *sym_decorate(BuildCtx *ctx,
const char *prefix, const char *suffix)
{
char name[256];
char *p;
#if LJ_64
const char *symprefix = ctx->mode == BUILD_machasm ? "_" : "";
#elif LJ_TARGET_XBOX360
const char *symprefix = "";
#else
const char *symprefix = ctx->mode != BUILD_elfasm ? "_" : "";
#endif
sprintf(name, "%s%s%s", symprefix, prefix, suffix);
p = strchr(name, '@');
if (p) {
#if LJ_TARGET_X86ORX64
if (!LJ_64 && (ctx->mode == BUILD_coffasm || ctx->mode == BUILD_peobj))
name[0] = name[1] == 'R' ? '_' : '@'; /* Just for _RtlUnwind@16. */
else
*p = '\0';
#elif LJ_TARGET_PPC && !LJ_TARGET_CONSOLE
/* Keep @plt etc. */
#else
*p = '\0';
#endif
}
p = (char *)malloc(strlen(name)+1); /* MSVC doesn't like strdup. */
strcpy(p, name);
return p;
}
#define NRELOCSYM (sizeof(extnames)/sizeof(extnames[0])-1)
static int relocmap[NRELOCSYM];
/* Collect external relocations. */
static int collect_reloc(BuildCtx *ctx, uint8_t *addr, int idx, int type)
{
if (ctx->nreloc >= BUILD_MAX_RELOC) {
fprintf(stderr, "Error: too many relocations, increase BUILD_MAX_RELOC.\n");
exit(1);
}
if (relocmap[idx] < 0) {
relocmap[idx] = ctx->nrelocsym;
ctx->relocsym[ctx->nrelocsym] = sym_decorate(ctx, "", extnames[idx]);
ctx->nrelocsym++;
}
ctx->reloc[ctx->nreloc].ofs = (int32_t)(addr - ctx->code);
ctx->reloc[ctx->nreloc].sym = relocmap[idx];
ctx->reloc[ctx->nreloc].type = type;
ctx->nreloc++;
#if LJ_TARGET_XBOX360
return (int)(ctx->code - addr) + 4; /* Encode symbol offset of .text. */
#else
return 0; /* Encode symbol offset of 0. */
#endif
}
/* Naive insertion sort. Performance doesn't matter here. */
static void sym_insert(BuildCtx *ctx, int32_t ofs,
const char *prefix, const char *suffix)
{
ptrdiff_t i = ctx->nsym++;
while (i > 0) {
if (ctx->sym[i-1].ofs <= ofs)
break;
ctx->sym[i] = ctx->sym[i-1];
i--;
}
ctx->sym[i].ofs = ofs;
ctx->sym[i].name = sym_decorate(ctx, prefix, suffix);
}
/* Build the machine code. */
static int build_code(BuildCtx *ctx)
{
int status;
int i;
/* Initialize DynASM structures. */
ctx->nglob = GLOB__MAX;
ctx->glob = (void **)malloc(ctx->nglob*sizeof(void *));
memset(ctx->glob, 0, ctx->nglob*sizeof(void *));
ctx->nreloc = 0;
ctx->globnames = globnames;
ctx->extnames = extnames;
ctx->relocsym = (const char **)malloc(NRELOCSYM*sizeof(const char *));
ctx->nrelocsym = 0;
for (i = 0; i < (int)NRELOCSYM; i++) relocmap[i] = -1;
ctx->dasm_ident = DASM_IDENT;
ctx->dasm_arch = DASM_ARCH;
dasm_init(Dst, DASM_MAXSECTION);
dasm_setupglobal(Dst, ctx->glob, ctx->nglob);
dasm_setup(Dst, build_actionlist);
/* Call arch-specific backend to emit the code. */
ctx->npc = build_backend(ctx);
/* Finalize the code. */
(void)dasm_checkstep(Dst, -1);
if ((status = dasm_link(Dst, &ctx->codesz))) return status;
ctx->code = (uint8_t *)malloc(ctx->codesz);
if ((status = dasm_encode(Dst, (void *)ctx->code))) return status;
/* Allocate symbol table and bytecode offsets. */
ctx->beginsym = sym_decorate(ctx, "", LABEL_PREFIX "vm_asm_begin");
ctx->sym = (BuildSym *)malloc((ctx->npc+ctx->nglob+1)*sizeof(BuildSym));
ctx->nsym = 0;
ctx->bc_ofs = (int32_t *)malloc(ctx->npc*sizeof(int32_t));
/* Collect the opcodes (PC labels). */
for (i = 0; i < ctx->npc; i++) {
int32_t ofs = dasm_getpclabel(Dst, i);
if (ofs < 0) return 0x22000000|i;
ctx->bc_ofs[i] = ofs;
if ((LJ_HASJIT ||
!(i == BC_JFORI || i == BC_JFORL || i == BC_JITERL || i == BC_JLOOP ||
i == BC_IFORL || i == BC_IITERL || i == BC_ILOOP)) &&
(LJ_HASFFI || i != BC_KCDATA))
sym_insert(ctx, ofs, LABEL_PREFIX_BC, bc_names[i]);
}
/* Collect the globals (named labels). */
for (i = 0; i < ctx->nglob; i++) {
const char *gl = globnames[i];
int len = (int)strlen(gl);
if (!ctx->glob[i]) {
fprintf(stderr, "Error: undefined global %s\n", gl);
exit(2);
}
/* Skip the _Z symbols. */
if (!(len >= 2 && gl[len-2] == '_' && gl[len-1] == 'Z'))
sym_insert(ctx, (int32_t)((uint8_t *)(ctx->glob[i]) - ctx->code),
LABEL_PREFIX, globnames[i]);
}
/* Close the address range. */
sym_insert(ctx, (int32_t)ctx->codesz, "", "");
ctx->nsym--;
dasm_free(Dst);
return 0;
}
/* -- Generate VM enums --------------------------------------------------- */
const char *const bc_names[] = {
#define BCNAME(name, ma, mb, mc, mt) #name,
BCDEF(BCNAME)
#undef BCNAME
NULL
};
#if LJ_HASJIT
const char *const ir_names[] = {
#define IRNAME(name, m, m1, m2) #name,
IRDEF(IRNAME)
#undef IRNAME
NULL
};
const char *const irt_names[] = {
#define IRTNAME(name, size) #name,
IRTDEF(IRTNAME)
#undef IRTNAME
NULL
};
const char *const irfpm_names[] = {
#define FPMNAME(name) #name,
IRFPMDEF(FPMNAME)
#undef FPMNAME
NULL
};
const char *const irfield_names[] = {
#define FLNAME(name, ofs) #name,
IRFLDEF(FLNAME)
#undef FLNAME
NULL
};
const char *const ircall_names[] = {
#define IRCALLNAME(cond, name, nargs, kind, type, flags) #name,
IRCALLDEF(IRCALLNAME)
#undef IRCALLNAME
NULL
};
static const char *const trace_errors[] = {
#define TREDEF(name, msg) msg,
#include "lj_traceerr.h"
NULL
};
#endif
#if LJ_HASJIT
static const char *lower(char *buf, const char *s)
{
char *p = buf;
while (*s) {
*p++ = (*s >= 'A' && *s <= 'Z') ? *s+0x20 : *s;
s++;
}
*p = '\0';
return buf;
}
#endif
/* Emit C source code for bytecode-related definitions. */
static void emit_bcdef(BuildCtx *ctx)
{
int i;
fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_ofs[] = {\n");
for (i = 0; i < ctx->npc; i++) {
if (i != 0)
fprintf(ctx->fp, ",\n");
fprintf(ctx->fp, "%d", ctx->bc_ofs[i]);
}
}
/* Emit VM definitions as Lua code for debug modules. */
static void emit_vmdef(BuildCtx *ctx)
{
#if LJ_HASJIT
char buf[80];
#endif
int i;
fprintf(ctx->fp, "-- This is a generated file. DO NOT EDIT!\n\n");
fprintf(ctx->fp, "assert(require(\"jit\").version == \"%s\", \"LuaJIT core/library version mismatch\")\n\n", LUAJIT_VERSION);
fprintf(ctx->fp, "return {\n\n");
fprintf(ctx->fp, "bcnames = \"");
for (i = 0; bc_names[i]; i++) fprintf(ctx->fp, "%-6s", bc_names[i]);
fprintf(ctx->fp, "\",\n\n");
#if LJ_HASJIT
fprintf(ctx->fp, "irnames = \"");
for (i = 0; ir_names[i]; i++) fprintf(ctx->fp, "%-6s", ir_names[i]);
fprintf(ctx->fp, "\",\n\n");
fprintf(ctx->fp, "irfpm = { [0]=");
for (i = 0; irfpm_names[i]; i++)
fprintf(ctx->fp, "\"%s\", ", lower(buf, irfpm_names[i]));
fprintf(ctx->fp, "},\n\n");
fprintf(ctx->fp, "irfield = { [0]=");
for (i = 0; irfield_names[i]; i++) {
char *p;
lower(buf, irfield_names[i]);
p = strchr(buf, '_');
if (p) *p = '.';
fprintf(ctx->fp, "\"%s\", ", buf);
}
fprintf(ctx->fp, "},\n\n");
fprintf(ctx->fp, "ircall = {\n[0]=");
for (i = 0; ircall_names[i]; i++)
fprintf(ctx->fp, "\"%s\",\n", ircall_names[i]);
fprintf(ctx->fp, "},\n\n");
fprintf(ctx->fp, "traceerr = {\n[0]=");
for (i = 0; trace_errors[i]; i++)
fprintf(ctx->fp, "\"%s\",\n", trace_errors[i]);
fprintf(ctx->fp, "},\n\n");
#endif
}
/* -- Argument parsing ---------------------------------------------------- */
/* Build mode names. */
static const char *const modenames[] = {
#define BUILDNAME(name) #name,
BUILDDEF(BUILDNAME)
#undef BUILDNAME
NULL
};
/* Print usage information and exit. */
static void usage(void)
{
int i;
fprintf(stderr, LUAJIT_VERSION " VM builder.\n");
fprintf(stderr, LUAJIT_COPYRIGHT ", " LUAJIT_URL "\n");
fprintf(stderr, "Target architecture: " LJ_ARCH_NAME "\n\n");
fprintf(stderr, "Usage: buildvm -m mode [-o outfile] [infiles...]\n\n");
fprintf(stderr, "Available modes:\n");
for (i = 0; i < BUILD__MAX; i++)
fprintf(stderr, " %s\n", modenames[i]);
exit(1);
}
/* Parse the output mode name. */
static BuildMode parsemode(const char *mode)
{
int i;
for (i = 0; modenames[i]; i++)
if (!strcmp(mode, modenames[i]))
return (BuildMode)i;
usage();
return (BuildMode)-1;
}
/* Parse arguments. */
static void parseargs(BuildCtx *ctx, char **argv)
{
const char *a;
int i;
ctx->mode = (BuildMode)-1;
ctx->outname = "-";
for (i = 1; (a = argv[i]) != NULL; i++) {
if (a[0] != '-')
break;
switch (a[1]) {
case '-':
if (a[2]) goto err;
i++;
goto ok;
case '\0':
goto ok;
case 'm':
i++;
if (a[2] || argv[i] == NULL) goto err;
ctx->mode = parsemode(argv[i]);
break;
case 'o':
i++;
if (a[2] || argv[i] == NULL) goto err;
ctx->outname = argv[i];
break;
default: err:
usage();
break;
}
}
ok:
ctx->args = argv+i;
if (ctx->mode == (BuildMode)-1) goto err;
}
int main(int argc, char **argv)
{
BuildCtx ctx_;
BuildCtx *ctx = &ctx_;
int status, binmode;
if (sizeof(void *) != 4*LJ_32+8*LJ_64) {
fprintf(stderr,"Error: pointer size mismatch in cross-build.\n");
fprintf(stderr,"Try: make HOST_CC=\"gcc -m32\" CROSS=...\n\n");
return 1;
}
UNUSED(argc);
parseargs(ctx, argv);
if ((status = build_code(ctx))) {
fprintf(stderr,"Error: DASM error %08x\n", status);
return 1;
}
switch (ctx->mode) {
case BUILD_peobj:
case BUILD_raw:
binmode = 1;
break;
default:
binmode = 0;
break;
}
if (ctx->outname[0] == '-' && ctx->outname[1] == '\0') {
ctx->fp = stdout;
#if defined(_WIN32)
if (binmode)
_setmode(_fileno(stdout), _O_BINARY); /* Yuck. */
#endif
} else if (!(ctx->fp = fopen(ctx->outname, binmode ? "wb" : "w"))) {
fprintf(stderr, "Error: cannot open output file '%s': %s\n",
ctx->outname, strerror(errno));
exit(1);
}
switch (ctx->mode) {
case BUILD_elfasm:
case BUILD_coffasm:
case BUILD_machasm:
emit_asm(ctx);
emit_asm_debug(ctx);
break;
case BUILD_peobj:
emit_peobj(ctx);
break;
case BUILD_raw:
emit_raw(ctx);
break;
case BUILD_bcdef:
emit_bcdef(ctx);
emit_lib(ctx);
break;
case BUILD_vmdef:
emit_vmdef(ctx);
emit_lib(ctx);
fprintf(ctx->fp, "}\n\n");
break;
case BUILD_ffdef:
case BUILD_libdef:
case BUILD_recdef:
emit_lib(ctx);
break;
case BUILD_folddef:
emit_fold(ctx);
break;
default:
break;
}
fflush(ctx->fp);
if (ferror(ctx->fp)) {
fprintf(stderr, "Error: cannot write to output file: %s\n",
strerror(errno));
exit(1);
}
fclose(ctx->fp);
return 0;
}
+105
View File
@@ -0,0 +1,105 @@
/*
** LuaJIT VM builder.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _BUILDVM_H
#define _BUILDVM_H
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "lj_def.h"
#include "lj_arch.h"
/* Hardcoded limits. Increase as needed. */
#define BUILD_MAX_RELOC 200 /* Max. number of relocations. */
#define BUILD_MAX_FOLD 4096 /* Max. number of fold rules. */
/* Prefix for scanned library definitions. */
#define LIBDEF_PREFIX "LJLIB_"
/* Prefix for scanned fold definitions. */
#define FOLDDEF_PREFIX "LJFOLD"
/* Prefixes for generated labels. */
#define LABEL_PREFIX "lj_"
#define LABEL_PREFIX_BC LABEL_PREFIX "BC_"
#define LABEL_PREFIX_FF LABEL_PREFIX "ff_"
#define LABEL_PREFIX_CF LABEL_PREFIX "cf_"
#define LABEL_PREFIX_FFH LABEL_PREFIX "ffh_"
#define LABEL_PREFIX_LIBCF LABEL_PREFIX "lib_cf_"
#define LABEL_PREFIX_LIBINIT LABEL_PREFIX "lib_init_"
/* Forward declaration. */
struct dasm_State;
/* Build modes. */
#define BUILDDEF(_) \
_(elfasm) _(coffasm) _(machasm) _(peobj) _(raw) \
_(bcdef) _(ffdef) _(libdef) _(recdef) _(vmdef) \
_(folddef)
typedef enum {
#define BUILDENUM(name) BUILD_##name,
BUILDDEF(BUILDENUM)
#undef BUILDENUM
BUILD__MAX
} BuildMode;
/* Code relocation. */
typedef struct BuildReloc {
int32_t ofs;
int sym;
int type;
} BuildReloc;
typedef struct BuildSym {
const char *name;
int32_t ofs;
} BuildSym;
/* Build context structure. */
typedef struct BuildCtx {
/* DynASM state pointer. Should be first member. */
struct dasm_State *D;
/* Parsed command line. */
BuildMode mode;
FILE *fp;
const char *outname;
char **args;
/* Code and symbols generated by DynASM. */
uint8_t *code;
size_t codesz;
int npc, nglob, nsym, nreloc, nrelocsym;
void **glob;
BuildSym *sym;
const char **relocsym;
int32_t *bc_ofs;
const char *beginsym;
/* Strings generated by DynASM. */
const char *const *globnames;
const char *const *extnames;
const char *dasm_ident;
const char *dasm_arch;
/* Relocations. */
BuildReloc reloc[BUILD_MAX_RELOC];
} BuildCtx;
extern void owrite(BuildCtx *ctx, const void *ptr, size_t sz);
extern void emit_asm(BuildCtx *ctx);
extern void emit_peobj(BuildCtx *ctx);
extern void emit_lib(BuildCtx *ctx);
extern void emit_fold(BuildCtx *ctx);
extern const char *const bc_names[];
extern const char *const ir_names[];
extern const char *const irt_names[];
extern const char *const irfpm_names[];
extern const char *const irfield_names[];
extern const char *const ircall_names[];
#endif
+355
View File
@@ -0,0 +1,355 @@
/*
** LuaJIT VM builder: Assembler source code emitter.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#include "buildvm.h"
#include "lj_bc.h"
/* ------------------------------------------------------------------------ */
#if LJ_TARGET_X86ORX64
/* Emit bytes piecewise as assembler text. */
static void emit_asm_bytes(BuildCtx *ctx, uint8_t *p, int n)
{
int i;
for (i = 0; i < n; i++) {
if ((i & 15) == 0)
fprintf(ctx->fp, "\t.byte %d", p[i]);
else
fprintf(ctx->fp, ",%d", p[i]);
if ((i & 15) == 15) putc('\n', ctx->fp);
}
if ((n & 15) != 0) putc('\n', ctx->fp);
}
/* Emit relocation */
static void emit_asm_reloc(BuildCtx *ctx, int type, const char *sym)
{
switch (ctx->mode) {
case BUILD_elfasm:
if (type)
fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
else
fprintf(ctx->fp, "\t.long %s\n", sym);
break;
case BUILD_coffasm:
fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", sym);
if (type)
fprintf(ctx->fp, "\t.long %s-.-4\n", sym);
else
fprintf(ctx->fp, "\t.long %s\n", sym);
break;
default: /* BUILD_machasm for relative relocations handled below. */
fprintf(ctx->fp, "\t.long %s\n", sym);
break;
}
}
static const char *const jccnames[] = {
"jo", "jno", "jb", "jnb", "jz", "jnz", "jbe", "ja",
"js", "jns", "jpe", "jpo", "jl", "jge", "jle", "jg"
};
/* Emit x86/x64 text relocations. */
static void emit_asm_reloc_text(BuildCtx *ctx, uint8_t *cp, int n,
const char *sym)
{
const char *opname = NULL;
if (--n < 0) goto err;
if (cp[n] == 0xe8) {
opname = "call";
} else if (cp[n] == 0xe9) {
opname = "jmp";
} else if (cp[n] >= 0x80 && cp[n] <= 0x8f && n > 0 && cp[n-1] == 0x0f) {
opname = jccnames[cp[n]-0x80];
n--;
} else {
err:
fprintf(stderr, "Error: unsupported opcode for %s symbol relocation.\n",
sym);
exit(1);
}
emit_asm_bytes(ctx, cp, n);
if (strncmp(sym+(*sym == '_'), LABEL_PREFIX, sizeof(LABEL_PREFIX)-1)) {
/* Various fixups for external symbols outside of our binary. */
if (ctx->mode == BUILD_elfasm) {
if (LJ_32)
fprintf(ctx->fp, "#if __PIC__\n\t%s lj_wrap_%s\n#else\n", opname, sym);
fprintf(ctx->fp, "\t%s %s@PLT\n", opname, sym);
if (LJ_32)
fprintf(ctx->fp, "#endif\n");
return;
} else if (LJ_32 && ctx->mode == BUILD_machasm) {
fprintf(ctx->fp, "\t%s L%s$stub\n", opname, sym);
return;
}
}
fprintf(ctx->fp, "\t%s %s\n", opname, sym);
}
#else
/* Emit words piecewise as assembler text. */
static void emit_asm_words(BuildCtx *ctx, uint8_t *p, int n)
{
int i;
for (i = 0; i < n; i += 4) {
uint32_t ins = *(uint32_t *)(p+i);
#if LJ_TARGET_ARM64 && LJ_BE
ins = lj_bswap(ins); /* ARM64 instructions are always little-endian. */
#endif
if ((i & 15) == 0)
fprintf(ctx->fp, "\t.long 0x%08x", ins);
else
fprintf(ctx->fp, ",0x%08x", ins);
if ((i & 15) == 12) putc('\n', ctx->fp);
}
if ((n & 15) != 0) putc('\n', ctx->fp);
}
/* Emit relocation as part of an instruction. */
static void emit_asm_wordreloc(BuildCtx *ctx, uint8_t *p, int n,
const char *sym)
{
uint32_t ins;
emit_asm_words(ctx, p, n-4);
ins = *(uint32_t *)(p+n-4);
#if LJ_TARGET_ARM
if ((ins & 0xff000000u) == 0xfa000000u) {
fprintf(ctx->fp, "\tblx %s\n", sym);
} else if ((ins & 0x0e000000u) == 0x0a000000u) {
fprintf(ctx->fp, "\t%s%.2s %s\n", (ins & 0x01000000u) ? "bl" : "b",
&"eqnecsccmiplvsvchilsgeltgtle"[2*(ins >> 28)], sym);
} else {
fprintf(stderr,
"Error: unsupported opcode %08x for %s symbol relocation.\n",
ins, sym);
exit(1);
}
#elif LJ_TARGET_ARM64
if ((ins >> 26) == 0x25u) {
fprintf(ctx->fp, "\tbl %s\n", sym);
} else {
fprintf(stderr,
"Error: unsupported opcode %08x for %s symbol relocation.\n",
ins, sym);
exit(1);
}
#elif LJ_TARGET_PPC
#if LJ_TARGET_PS3
#define TOCPREFIX "."
#else
#define TOCPREFIX ""
#endif
if ((ins >> 26) == 16) {
fprintf(ctx->fp, "\t%s %d, %d, " TOCPREFIX "%s\n",
(ins & 1) ? "bcl" : "bc", (ins >> 21) & 31, (ins >> 16) & 31, sym);
} else if ((ins >> 26) == 18) {
fprintf(ctx->fp, "\t%s " TOCPREFIX "%s\n", (ins & 1) ? "bl" : "b", sym);
} else {
fprintf(stderr,
"Error: unsupported opcode %08x for %s symbol relocation.\n",
ins, sym);
exit(1);
}
#elif LJ_TARGET_MIPS
fprintf(stderr,
"Error: unsupported opcode %08x for %s symbol relocation.\n",
ins, sym);
exit(1);
#else
#error "missing relocation support for this architecture"
#endif
}
#endif
#if LJ_TARGET_ARM
#define ELFASM_PX "%%"
#else
#define ELFASM_PX "@"
#endif
/* Emit an assembler label. */
static void emit_asm_label(BuildCtx *ctx, const char *name, int size, int isfunc)
{
switch (ctx->mode) {
case BUILD_elfasm:
#if LJ_TARGET_PS3
if (!strncmp(name, "lj_vm_", 6) &&
strcmp(name, ctx->beginsym) &&
!strstr(name, "hook")) {
fprintf(ctx->fp,
"\n\t.globl %s\n"
"\t.section \".opd\",\"aw\"\n"
"%s:\n"
"\t.long .%s,.TOC.@tocbase32\n"
"\t.size %s,8\n"
"\t.previous\n"
"\t.globl .%s\n"
"\t.hidden .%s\n"
"\t.type .%s, " ELFASM_PX "function\n"
"\t.size .%s, %d\n"
".%s:\n",
name, name, name, name, name, name, name, name, size, name);
break;
}
#endif
fprintf(ctx->fp,
"\n\t.globl %s\n"
"\t.hidden %s\n"
"\t.type %s, " ELFASM_PX "%s\n"
"\t.size %s, %d\n"
"%s:\n",
name, name, name, isfunc ? "function" : "object", name, size, name);
break;
case BUILD_coffasm:
fprintf(ctx->fp, "\n\t.globl %s\n", name);
if (isfunc)
fprintf(ctx->fp, "\t.def %s; .scl 3; .type 32; .endef\n", name);
fprintf(ctx->fp, "%s:\n", name);
break;
case BUILD_machasm:
fprintf(ctx->fp,
"\n\t.private_extern %s\n"
"\t.no_dead_strip %s\n"
"%s:\n", name, name, name);
break;
default:
break;
}
}
/* Emit alignment. */
static void emit_asm_align(BuildCtx *ctx, int bits)
{
switch (ctx->mode) {
case BUILD_elfasm:
case BUILD_coffasm:
fprintf(ctx->fp, "\t.p2align %d\n", bits);
break;
case BUILD_machasm:
fprintf(ctx->fp, "\t.align %d\n", bits);
break;
default:
break;
}
}
/* ------------------------------------------------------------------------ */
/* Emit assembler source code. */
void emit_asm(BuildCtx *ctx)
{
int i, rel;
fprintf(ctx->fp, "\t.file \"buildvm_%s.dasc\"\n", ctx->dasm_arch);
fprintf(ctx->fp, "\t.text\n");
#if LJ_TARGET_MIPS32 && !LJ_ABI_SOFTFP
fprintf(ctx->fp, "\t.module fp=32\n");
#endif
#if LJ_TARGET_MIPS
fprintf(ctx->fp, "\t.set nomips16\n\t.abicalls\n\t.set noreorder\n\t.set nomacro\n");
#endif
emit_asm_align(ctx, 4);
#if LJ_TARGET_PS3
emit_asm_label(ctx, ctx->beginsym, ctx->codesz, 0);
#else
emit_asm_label(ctx, ctx->beginsym, 0, 0);
#endif
if (ctx->mode != BUILD_machasm)
fprintf(ctx->fp, ".Lbegin:\n");
#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
/* This should really be moved into buildvm_arm.dasc. */
#if LJ_ARCH_HASFPU
fprintf(ctx->fp,
".fnstart\n"
".save {r5, r6, r7, r8, r9, r10, r11, lr}\n"
".vsave {d8-d15}\n"
".save {r4}\n"
".pad #28\n");
#else
fprintf(ctx->fp,
".fnstart\n"
".save {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
".pad #28\n");
#endif
#endif
for (i = rel = 0; i < ctx->nsym; i++) {
int32_t ofs = ctx->sym[i].ofs;
int32_t next = ctx->sym[i+1].ofs;
#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND && LJ_HASFFI
if (!strcmp(ctx->sym[i].name, "lj_vm_ffi_call"))
fprintf(ctx->fp,
".globl lj_err_unwind_arm\n"
".personality lj_err_unwind_arm\n"
".fnend\n"
".fnstart\n"
".save {r4, r5, r11, lr}\n"
".setfp r11, sp\n");
#endif
emit_asm_label(ctx, ctx->sym[i].name, next - ofs, 1);
while (rel < ctx->nreloc && ctx->reloc[rel].ofs <= next) {
BuildReloc *r = &ctx->reloc[rel];
int n = r->ofs - ofs;
#if LJ_TARGET_X86ORX64
if (r->type != 0 &&
(ctx->mode == BUILD_elfasm || ctx->mode == BUILD_machasm)) {
emit_asm_reloc_text(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
} else {
emit_asm_bytes(ctx, ctx->code+ofs, n);
emit_asm_reloc(ctx, r->type, ctx->relocsym[r->sym]);
}
ofs += n+4;
#else
emit_asm_wordreloc(ctx, ctx->code+ofs, n, ctx->relocsym[r->sym]);
ofs += n;
#endif
rel++;
}
#if LJ_TARGET_X86ORX64
emit_asm_bytes(ctx, ctx->code+ofs, next-ofs);
#else
emit_asm_words(ctx, ctx->code+ofs, next-ofs);
#endif
}
#if LJ_TARGET_ARM && defined(__GNUC__) && !LJ_NO_UNWIND
fprintf(ctx->fp,
#if !LJ_HASFFI
".globl lj_err_unwind_arm\n"
".personality lj_err_unwind_arm\n"
#endif
".fnend\n");
#endif
fprintf(ctx->fp, "\n");
switch (ctx->mode) {
case BUILD_elfasm:
#if !(LJ_TARGET_PS3 || LJ_TARGET_PSVITA)
fprintf(ctx->fp, "\t.section .note.GNU-stack,\"\"," ELFASM_PX "progbits\n");
#endif
#if LJ_TARGET_PPC && !LJ_TARGET_PS3 && !LJ_ABI_SOFTFP
/* Hard-float ABI. */
fprintf(ctx->fp, "\t.gnu_attribute 4, 1\n");
#endif
/* fallthrough */
case BUILD_coffasm:
fprintf(ctx->fp, "\t.ident \"%s\"\n", ctx->dasm_ident);
break;
case BUILD_machasm:
#if defined(__apple_build_version__) && __apple_build_version__ >= 15000000 && __apple_build_version__ < 15000300
/* Workaround for XCode 15.0 - 15.2. */
fprintf(ctx->fp, "\t.subsections_via_symbols\n");
#endif
fprintf(ctx->fp,
"\t.cstring\n"
"\t.ascii \"%s\\0\"\n", ctx->dasm_ident);
break;
default:
break;
}
fprintf(ctx->fp, "\n");
}
+236
View File
@@ -0,0 +1,236 @@
/*
** LuaJIT VM builder: IR folding hash table generator.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#include "buildvm.h"
#include "lj_obj.h"
#if LJ_HASJIT
#include "lj_ir.h"
/* Context for the folding hash table generator. */
static int lineno;
static uint32_t funcidx;
static uint32_t foldkeys[BUILD_MAX_FOLD];
static uint32_t nkeys;
/* Try to fill the hash table with keys using the hash parameters. */
static int tryhash(uint32_t *htab, uint32_t sz, uint32_t r, int dorol)
{
uint32_t i;
if (dorol && ((r & 31) == 0 || (r>>5) == 0))
return 0; /* Avoid zero rotates. */
memset(htab, 0xff, (sz+1)*sizeof(uint32_t));
for (i = 0; i < nkeys; i++) {
uint32_t key = foldkeys[i];
uint32_t k = key & 0xffffff;
uint32_t h = (dorol ? lj_rol(lj_rol(k, r>>5) - k, r&31) :
(((k << (r>>5)) - k) << (r&31))) % sz;
if (htab[h] != 0xffffffff) { /* Collision on primary slot. */
if (htab[h+1] != 0xffffffff) { /* Collision on secondary slot. */
/* Try to move the colliding key, if possible. */
if (h < sz-1 && htab[h+2] == 0xffffffff) {
uint32_t k2 = htab[h+1] & 0xffffff;
uint32_t h2 = (dorol ? lj_rol(lj_rol(k2, r>>5) - k2, r&31) :
(((k2 << (r>>5)) - k2) << (r&31))) % sz;
if (h2 != h+1) return 0; /* Cannot resolve collision. */
htab[h+2] = htab[h+1]; /* Move colliding key to secondary slot. */
} else {
return 0; /* Collision. */
}
}
htab[h+1] = key;
} else {
htab[h] = key;
}
}
return 1; /* Success, all keys could be stored. */
}
/* Print the generated hash table. */
static void printhash(BuildCtx *ctx, uint32_t *htab, uint32_t sz)
{
uint32_t i;
fprintf(ctx->fp, "static const uint32_t fold_hash[%d] = {\n0x%08x",
sz+1, htab[0]);
for (i = 1; i < sz+1; i++)
fprintf(ctx->fp, ",\n0x%08x", htab[i]);
fprintf(ctx->fp, "\n};\n\n");
}
/* Exhaustive search for the shortest semi-perfect hash table. */
static void makehash(BuildCtx *ctx)
{
uint32_t htab[BUILD_MAX_FOLD*2+1];
uint32_t sz, r;
/* Search for the smallest hash table with an odd size. */
for (sz = (nkeys|1); sz < BUILD_MAX_FOLD*2; sz += 2) {
/* First try all shift hash combinations. */
for (r = 0; r < 32*32; r++) {
if (tryhash(htab, sz, r, 0)) {
printhash(ctx, htab, sz);
fprintf(ctx->fp,
"#define fold_hashkey(k)\t(((((k)<<%u)-(k))<<%u)%%%u)\n\n",
r>>5, r&31, sz);
return;
}
}
/* Then try all rotate hash combinations. */
for (r = 0; r < 32*32; r++) {
if (tryhash(htab, sz, r, 1)) {
printhash(ctx, htab, sz);
fprintf(ctx->fp,
"#define fold_hashkey(k)\t(lj_rol(lj_rol((k),%u)-(k),%u)%%%u)\n\n",
r>>5, r&31, sz);
return;
}
}
}
fprintf(stderr, "Error: search for perfect hash failed\n");
exit(1);
}
/* Parse one token of a fold rule. */
static uint32_t nexttoken(char **pp, int allowlit, int allowany)
{
char *p = *pp;
if (p) {
uint32_t i;
char *q = strchr(p, ' ');
if (q) *q++ = '\0';
*pp = q;
if (allowlit && !strncmp(p, "IRFPM_", 6)) {
for (i = 0; irfpm_names[i]; i++)
if (!strcmp(irfpm_names[i], p+6))
return i;
} else if (allowlit && !strncmp(p, "IRFL_", 5)) {
for (i = 0; irfield_names[i]; i++)
if (!strcmp(irfield_names[i], p+5))
return i;
} else if (allowlit && !strncmp(p, "IRCALL_", 7)) {
for (i = 0; ircall_names[i]; i++)
if (!strcmp(ircall_names[i], p+7))
return i;
} else if (allowlit && !strncmp(p, "IRCONV_", 7)) {
for (i = 0; irt_names[i]; i++) {
const char *r = strchr(p+7, '_');
if (r && !strncmp(irt_names[i], p+7, r-(p+7))) {
uint32_t j;
for (j = 0; irt_names[j]; j++)
if (!strcmp(irt_names[j], r+1))
return (i << 5) + j;
}
}
} else if (allowlit && *p >= '0' && *p <= '9') {
for (i = 0; *p >= '0' && *p <= '9'; p++)
i = i*10 + (*p - '0');
if (*p == '\0')
return i;
} else if (allowany && !strcmp("any", p)) {
return allowany;
} else {
for (i = 0; ir_names[i]; i++)
if (!strcmp(ir_names[i], p))
return i;
}
fprintf(stderr, "Error: bad fold definition token \"%s\" at line %d\n", p, lineno);
exit(1);
}
return 0;
}
/* Parse a fold rule. */
static void foldrule(char *p)
{
uint32_t op = nexttoken(&p, 0, 0);
uint32_t left = nexttoken(&p, 0, 0x7f);
uint32_t right = nexttoken(&p, 1, 0x3ff);
uint32_t key = (funcidx << 24) | (op << 17) | (left << 10) | right;
uint32_t i;
if (nkeys >= BUILD_MAX_FOLD) {
fprintf(stderr, "Error: too many fold rules, increase BUILD_MAX_FOLD.\n");
exit(1);
}
/* Simple insertion sort to detect duplicates. */
for (i = nkeys; i > 0; i--) {
if ((foldkeys[i-1]&0xffffff) < (key & 0xffffff))
break;
if ((foldkeys[i-1]&0xffffff) == (key & 0xffffff)) {
fprintf(stderr, "Error: duplicate fold definition at line %d\n", lineno);
exit(1);
}
foldkeys[i] = foldkeys[i-1];
}
foldkeys[i] = key;
nkeys++;
}
/* Emit C source code for IR folding hash table. */
void emit_fold(BuildCtx *ctx)
{
char buf[256]; /* We don't care about analyzing lines longer than that. */
const char *fname = ctx->args[0];
FILE *fp;
if (fname == NULL) {
fprintf(stderr, "Error: missing input filename\n");
exit(1);
}
if (fname[0] == '-' && fname[1] == '\0') {
fp = stdin;
} else {
fp = fopen(fname, "r");
if (!fp) {
fprintf(stderr, "Error: cannot open input file '%s': %s\n",
fname, strerror(errno));
exit(1);
}
}
fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
fprintf(ctx->fp, "static const FoldFunc fold_func[] = {\n");
lineno = 0;
funcidx = 0;
nkeys = 0;
while (fgets(buf, sizeof(buf), fp) != NULL) {
lineno++;
/* The prefix must be at the start of a line, otherwise it's ignored. */
if (!strncmp(buf, FOLDDEF_PREFIX, sizeof(FOLDDEF_PREFIX)-1)) {
char *p = buf+sizeof(FOLDDEF_PREFIX)-1;
char *q = strchr(p, ')');
if (p[0] == '(' && q) {
p++;
*q = '\0';
foldrule(p);
} else if ((p[0] == 'F' || p[0] == 'X') && p[1] == '(' && q) {
p += 2;
*q = '\0';
if (funcidx)
fprintf(ctx->fp, ",\n");
if (p[-2] == 'X')
fprintf(ctx->fp, " %s", p);
else
fprintf(ctx->fp, " fold_%s", p);
funcidx++;
} else {
buf[strlen(buf)-1] = '\0';
fprintf(stderr, "Error: unknown fold definition tag %s%s at line %d\n",
FOLDDEF_PREFIX, p, lineno);
exit(1);
}
}
}
fclose(fp);
fprintf(ctx->fp, "\n};\n\n");
makehash(ctx);
}
#else
void emit_fold(BuildCtx *ctx)
{
UNUSED(ctx);
}
#endif
+470
View File
@@ -0,0 +1,470 @@
/*
** LuaJIT VM builder: library definition compiler.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#include "buildvm.h"
#include "lj_obj.h"
#include "lj_bc.h"
#include "lj_lib.h"
#include "buildvm_libbc.h"
/* Context for library definitions. */
static uint8_t obuf[8192];
static uint8_t *optr;
static char modname[80];
static size_t modnamelen;
static char funcname[80];
static int modstate, regfunc;
static int ffid, recffid, ffasmfunc;
enum {
REGFUNC_OK,
REGFUNC_NOREG,
REGFUNC_NOREGUV
};
static void libdef_name(const char *p, int kind)
{
size_t n = strlen(p);
if (kind != LIBINIT_STRING) {
if (n > modnamelen && p[modnamelen] == '_' &&
!strncmp(p, modname, modnamelen)) {
p += modnamelen+1;
n -= modnamelen+1;
}
}
if (n > LIBINIT_MAXSTR) {
fprintf(stderr, "Error: string too long: '%s'\n", p);
exit(1);
}
if (optr+1+n+2 > obuf+sizeof(obuf)) { /* +2 for caller. */
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
*optr++ = (uint8_t)(n | kind);
memcpy(optr, p, n);
optr += n;
}
static void libdef_endmodule(BuildCtx *ctx)
{
if (modstate != 0) {
char line[80];
const uint8_t *p;
int n;
if (modstate == 1)
fprintf(ctx->fp, " (lua_CFunction)0");
fprintf(ctx->fp, "\n};\n");
fprintf(ctx->fp, "static const uint8_t %s%s[] = {\n",
LABEL_PREFIX_LIBINIT, modname);
line[0] = '\0';
for (n = 0, p = obuf; p < optr; p++) {
n += sprintf(line+n, "%d,", *p);
if (n >= 75) {
fprintf(ctx->fp, "%s\n", line);
n = 0;
line[0] = '\0';
}
}
fprintf(ctx->fp, "%s%d\n};\n#endif\n\n", line, LIBINIT_END);
}
}
static void libdef_module(BuildCtx *ctx, char *p, int arg)
{
UNUSED(arg);
if (ctx->mode == BUILD_libdef) {
libdef_endmodule(ctx);
optr = obuf;
*optr++ = (uint8_t)ffid;
*optr++ = (uint8_t)ffasmfunc;
*optr++ = 0; /* Hash table size. */
modstate = 1;
fprintf(ctx->fp, "#ifdef %sMODULE_%s\n", LIBDEF_PREFIX, p);
fprintf(ctx->fp, "#undef %sMODULE_%s\n", LIBDEF_PREFIX, p);
fprintf(ctx->fp, "static const lua_CFunction %s%s[] = {\n",
LABEL_PREFIX_LIBCF, p);
}
modnamelen = strlen(p);
if (modnamelen > sizeof(modname)-1) {
fprintf(stderr, "Error: module name too long: '%s'\n", p);
exit(1);
}
strcpy(modname, p);
}
static int find_ffofs(BuildCtx *ctx, const char *name)
{
int i;
for (i = 0; i < ctx->nglob; i++) {
const char *gl = ctx->globnames[i];
if (gl[0] == 'f' && gl[1] == 'f' && gl[2] == '_' && !strcmp(gl+3, name)) {
return (int)((uint8_t *)ctx->glob[i] - ctx->code);
}
}
fprintf(stderr, "Error: undefined fast function %s%s\n",
LABEL_PREFIX_FF, name);
exit(1);
}
static void libdef_func(BuildCtx *ctx, char *p, int arg)
{
if (arg != LIBINIT_CF)
ffasmfunc++;
if (ctx->mode == BUILD_libdef) {
if (modstate == 0) {
fprintf(stderr, "Error: no module for function definition %s\n", p);
exit(1);
}
if (regfunc == REGFUNC_NOREG) {
if (optr+1 > obuf+sizeof(obuf)) {
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
*optr++ = LIBINIT_FFID;
} else {
if (arg != LIBINIT_ASM_) {
if (modstate != 1) fprintf(ctx->fp, ",\n");
modstate = 2;
fprintf(ctx->fp, " %s%s", arg ? LABEL_PREFIX_FFH : LABEL_PREFIX_CF, p);
}
if (regfunc != REGFUNC_NOREGUV) obuf[2]++; /* Bump hash table size. */
libdef_name(regfunc == REGFUNC_NOREGUV ? "" : p, arg);
}
} else if (ctx->mode == BUILD_ffdef) {
fprintf(ctx->fp, "FFDEF(%s)\n", p);
} else if (ctx->mode == BUILD_recdef) {
if (strlen(p) > sizeof(funcname)-1) {
fprintf(stderr, "Error: function name too long: '%s'\n", p);
exit(1);
}
strcpy(funcname, p);
} else if (ctx->mode == BUILD_vmdef) {
int i;
for (i = 1; p[i] && modname[i-1]; i++)
if (p[i] == '_') p[i] = '.';
fprintf(ctx->fp, "\"%s\",\n", p);
} else if (ctx->mode == BUILD_bcdef) {
if (arg != LIBINIT_CF)
fprintf(ctx->fp, ",\n%d", find_ffofs(ctx, p));
}
ffid++;
regfunc = REGFUNC_OK;
}
static uint8_t *libdef_uleb128(uint8_t *p, uint32_t *vv)
{
uint32_t v = *p++;
if (v >= 0x80) {
int sh = 0; v &= 0x7f;
do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80);
}
*vv = v;
return p;
}
static void libdef_fixupbc(uint8_t *p)
{
uint32_t i, sizebc;
p += 4;
p = libdef_uleb128(p, &sizebc);
p = libdef_uleb128(p, &sizebc);
p = libdef_uleb128(p, &sizebc);
for (i = 0; i < sizebc; i++, p += 4) {
uint8_t op = p[libbc_endian ? 3 : 0];
uint8_t ra = p[libbc_endian ? 2 : 1];
uint8_t rc = p[libbc_endian ? 1 : 2];
uint8_t rb = p[libbc_endian ? 0 : 3];
if (!LJ_DUALNUM && op == BC_ISTYPE && rc == ~LJ_TNUMX+1) {
op = BC_ISNUM; rc++;
}
p[LJ_ENDIAN_SELECT(0, 3)] = op;
p[LJ_ENDIAN_SELECT(1, 2)] = ra;
p[LJ_ENDIAN_SELECT(2, 1)] = rc;
p[LJ_ENDIAN_SELECT(3, 0)] = rb;
}
}
static void libdef_lua(BuildCtx *ctx, char *p, int arg)
{
UNUSED(arg);
if (ctx->mode == BUILD_libdef) {
int i;
for (i = 0; libbc_map[i].name != NULL; i++) {
if (!strcmp(libbc_map[i].name, p)) {
int ofs = libbc_map[i].ofs;
int len = libbc_map[i+1].ofs - ofs;
obuf[2]++; /* Bump hash table size. */
*optr++ = LIBINIT_LUA;
libdef_name(p, 0);
memcpy(optr, libbc_code + ofs, len);
libdef_fixupbc(optr);
optr += len;
return;
}
}
fprintf(stderr, "Error: missing libbc definition for %s\n", p);
exit(1);
}
}
static uint32_t find_rec(char *name)
{
char *p = (char *)obuf;
uint32_t n;
for (n = 2; *p; n++) {
if (strcmp(p, name) == 0)
return n;
p += strlen(p)+1;
}
if (p+strlen(name)+1 >= (char *)obuf+sizeof(obuf)) {
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
strcpy(p, name);
return n;
}
static void libdef_rec(BuildCtx *ctx, char *p, int arg)
{
UNUSED(arg);
if (ctx->mode == BUILD_recdef) {
char *q;
uint32_t n;
for (; recffid+1 < ffid; recffid++)
fprintf(ctx->fp, ",\n0");
recffid = ffid;
if (*p == '.') p = funcname;
q = strchr(p, ' ');
if (q) *q++ = '\0';
n = find_rec(p);
if (q)
fprintf(ctx->fp, ",\n0x%02x00+(%s)", n, q);
else
fprintf(ctx->fp, ",\n0x%02x00", n);
}
}
static void memcpy_endian(void *dst, void *src, size_t n)
{
union { uint8_t b; uint32_t u; } host_endian;
host_endian.u = 1;
if (host_endian.b == LJ_ENDIAN_SELECT(1, 0)) {
memcpy(dst, src, n);
} else {
size_t i;
for (i = 0; i < n; i++)
((uint8_t *)dst)[i] = ((uint8_t *)src)[n-i-1];
}
}
static void libdef_push(BuildCtx *ctx, char *p, int arg)
{
UNUSED(arg);
if (ctx->mode == BUILD_libdef) {
int len = (int)strlen(p);
if (*p == '"') {
if (len > 1 && p[len-1] == '"') {
p[len-1] = '\0';
libdef_name(p+1, LIBINIT_STRING);
return;
}
} else if (*p >= '0' && *p <= '9') {
char *ep;
double d = strtod(p, &ep);
if (*ep == '\0') {
if (optr+1+sizeof(double) > obuf+sizeof(obuf)) {
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
*optr++ = LIBINIT_NUMBER;
memcpy_endian(optr, &d, sizeof(double));
optr += sizeof(double);
return;
}
} else if (!strcmp(p, "lastcl")) {
if (optr+1 > obuf+sizeof(obuf)) {
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
*optr++ = LIBINIT_LASTCL;
return;
} else if (len > 4 && !strncmp(p, "top-", 4)) {
if (optr+2 > obuf+sizeof(obuf)) {
fprintf(stderr, "Error: output buffer overflow\n");
exit(1);
}
*optr++ = LIBINIT_COPY;
*optr++ = (uint8_t)atoi(p+4);
return;
}
fprintf(stderr, "Error: bad value for %sPUSH(%s)\n", LIBDEF_PREFIX, p);
exit(1);
}
}
static void libdef_set(BuildCtx *ctx, char *p, int arg)
{
UNUSED(arg);
if (ctx->mode == BUILD_libdef) {
if (p[0] == '!' && p[1] == '\0') p[0] = '\0'; /* Set env. */
libdef_name(p, LIBINIT_STRING);
*optr++ = LIBINIT_SET;
obuf[2]++; /* Bump hash table size. */
}
}
static void libdef_regfunc(BuildCtx *ctx, char *p, int arg)
{
UNUSED(ctx); UNUSED(p);
regfunc = arg;
}
typedef void (*LibDefFunc)(BuildCtx *ctx, char *p, int arg);
typedef struct LibDefHandler {
const char *suffix;
const char *stop;
const LibDefFunc func;
const int arg;
} LibDefHandler;
static const LibDefHandler libdef_handlers[] = {
{ "MODULE_", " \t\r\n", libdef_module, 0 },
{ "CF(", ")", libdef_func, LIBINIT_CF },
{ "ASM(", ")", libdef_func, LIBINIT_ASM },
{ "ASM_(", ")", libdef_func, LIBINIT_ASM_ },
{ "LUA(", ")", libdef_lua, 0 },
{ "REC(", ")", libdef_rec, 0 },
{ "PUSH(", ")", libdef_push, 0 },
{ "SET(", ")", libdef_set, 0 },
{ "NOREGUV", NULL, libdef_regfunc, REGFUNC_NOREGUV },
{ "NOREG", NULL, libdef_regfunc, REGFUNC_NOREG },
{ NULL, NULL, (LibDefFunc)0, 0 }
};
/* Emit C source code for library function definitions. */
void emit_lib(BuildCtx *ctx)
{
const char *fname;
if (ctx->mode == BUILD_ffdef || ctx->mode == BUILD_libdef ||
ctx->mode == BUILD_recdef)
fprintf(ctx->fp, "/* This is a generated file. DO NOT EDIT! */\n\n");
else if (ctx->mode == BUILD_vmdef)
fprintf(ctx->fp, "ffnames = {\n[0]=\"Lua\",\n\"C\",\n");
if (ctx->mode == BUILD_recdef)
fprintf(ctx->fp, "static const uint16_t recff_idmap[] = {\n0,\n0x0100");
recffid = ffid = FF_C+1;
ffasmfunc = 0;
while ((fname = *ctx->args++)) {
char buf[256]; /* We don't care about analyzing lines longer than that. */
FILE *fp;
if (fname[0] == '-' && fname[1] == '\0') {
fp = stdin;
} else {
fp = fopen(fname, "r");
if (!fp) {
fprintf(stderr, "Error: cannot open input file '%s': %s\n",
fname, strerror(errno));
exit(1);
}
}
modstate = 0;
regfunc = REGFUNC_OK;
while (fgets(buf, sizeof(buf), fp) != NULL) {
char *p;
/* Simplistic pre-processor. Only handles top-level #if/#endif. */
if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') {
int ok = 1;
size_t len = strlen(buf);
if (buf[len-1] == '\n') {
buf[len-1] = 0;
if (buf[len-2] == '\r') {
buf[len-2] = 0;
}
}
if (!strcmp(buf, "#if LJ_52"))
ok = LJ_52;
else if (!strcmp(buf, "#if LJ_HASJIT"))
ok = LJ_HASJIT;
else if (!strcmp(buf, "#if LJ_HASFFI"))
ok = LJ_HASFFI;
else if (!strcmp(buf, "#if LJ_HASBUFFER"))
ok = LJ_HASBUFFER;
else if (!strcmp(buf, "#if !LJ_SRB2LIB"))
ok = !LJ_SRB2LIB;
else if (!strcmp(buf, "#if !LJ_SRB2LIB || (LJ_SRB2LIB && LJ_SRB2IO)"))
ok = !LJ_SRB2LIB || (LJ_SRB2LIB && LJ_SRB2IO); /* whacky! */
if (!ok) {
int lvl = 1;
while (fgets(buf, sizeof(buf), fp) != NULL) {
if (buf[0] == '#' && buf[1] == 'e' && buf[2] == 'n') {
if (--lvl == 0) break;
} else if (buf[0] == '#' && buf[1] == 'i' && buf[2] == 'f') {
lvl++;
}
}
continue;
}
}
for (p = buf; (p = strstr(p, LIBDEF_PREFIX)) != NULL; ) {
const LibDefHandler *ldh;
p += sizeof(LIBDEF_PREFIX)-1;
for (ldh = libdef_handlers; ldh->suffix != NULL; ldh++) {
size_t n, len = strlen(ldh->suffix);
if (!strncmp(p, ldh->suffix, len)) {
p += len;
n = ldh->stop ? strcspn(p, ldh->stop) : 0;
if (!p[n]) break;
p[n] = '\0';
ldh->func(ctx, p, ldh->arg);
p += n+1;
break;
}
}
if (ldh->suffix == NULL) {
buf[strlen(buf)-1] = '\0';
fprintf(stderr, "Error: unknown library definition tag %s%s\n",
LIBDEF_PREFIX, p);
exit(1);
}
}
}
fclose(fp);
if (ctx->mode == BUILD_libdef) {
libdef_endmodule(ctx);
}
}
if (ctx->mode == BUILD_ffdef) {
fprintf(ctx->fp, "\n#undef FFDEF\n\n");
fprintf(ctx->fp,
"#ifndef FF_NUM_ASMFUNC\n#define FF_NUM_ASMFUNC %d\n#endif\n\n",
ffasmfunc);
} else if (ctx->mode == BUILD_vmdef) {
fprintf(ctx->fp, "},\n\n");
} else if (ctx->mode == BUILD_bcdef) {
int i;
fprintf(ctx->fp, "\n};\n\n");
fprintf(ctx->fp, "LJ_DATADEF const uint16_t lj_bc_mode[] = {\n");
fprintf(ctx->fp, "BCDEF(BCMODE)\n");
for (i = ffasmfunc-1; i > 0; i--)
fprintf(ctx->fp, "BCMODE_FF,\n");
fprintf(ctx->fp, "BCMODE_FF\n};\n\n");
} else if (ctx->mode == BUILD_recdef) {
char *p = (char *)obuf;
fprintf(ctx->fp, "\n};\n\n");
fprintf(ctx->fp, "static const RecordFunc recff_func[] = {\n"
"recff_nyi,\n"
"recff_c");
while (*p) {
fprintf(ctx->fp, ",\nrecff_%s", p);
p += strlen(p)+1;
}
fprintf(ctx->fp, "\n};\n\n");
}
}
+81
View File
@@ -0,0 +1,81 @@
/* This is a generated file. DO NOT EDIT! */
static const int libbc_endian = 0;
static const uint8_t libbc_code[] = {
#if LJ_FR2
/* math.deg */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,241,135,158,166,3,
220,203,178,130,4,
/* math.rad */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,243,244,148,165,20,
198,190,199,252,3,
/* string.len */ 0,1,2,0,0,0,3,BC_ISTYPE,0,5,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
/* table.foreachi */ 0,2,10,0,0,0,15,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,
BC_KSHORT,2,1,0,BC_LEN,3,0,0,BC_KSHORT,4,1,0,BC_FORI,2,8,128,BC_MOV,6,1,0,
BC_MOV,8,5,0,BC_TGETR,9,5,0,BC_CALL,6,3,2,BC_ISEQP,6,0,0,BC_JMP,7,1,128,
BC_RET1,6,2,0,BC_FORL,2,248,127,BC_RET0,0,1,0,
/* table.foreach */ 0,2,11,0,0,1,16,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,BC_KPRI,
2,0,0,BC_MOV,3,0,0,BC_KNUM,4,0,0,BC_JMP,5,7,128,BC_MOV,7,1,0,BC_MOV,9,5,0,
BC_MOV,10,6,0,BC_CALL,7,3,2,BC_ISEQP,7,0,0,BC_JMP,8,1,128,BC_RET1,7,2,0,
BC_ITERN,5,3,3,BC_ITERL,5,247,127,BC_RET0,0,1,0,1,255,255,249,255,15,
/* table.getn */ 0,1,2,0,0,0,3,BC_ISTYPE,0,12,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
/* table.remove */ 0,2,10,0,0,2,30,BC_ISTYPE,0,12,0,BC_LEN,2,0,0,BC_ISNEP,1,0,
0,BC_JMP,3,7,128,BC_ISEQN,2,0,0,BC_JMP,3,23,128,BC_TGETR,3,2,0,BC_KPRI,4,0,0,
BC_TSETR,4,2,0,BC_RET1,3,2,0,BC_JMP,3,18,128,BC_ISTYPE,1,14,0,BC_KSHORT,3,1,0,
BC_ISGT,3,1,0,BC_JMP,3,14,128,BC_ISGT,1,2,0,BC_JMP,3,12,128,BC_TGETR,3,1,0,
BC_ADDVN,4,1,1,BC_MOV,5,2,0,BC_KSHORT,6,1,0,BC_FORI,4,4,128,BC_SUBVN,8,1,7,
BC_TGETR,9,7,0,BC_TSETR,9,8,0,BC_FORL,4,252,127,BC_KPRI,4,0,0,BC_TSETR,4,2,0,
BC_RET1,3,2,0,BC_RET0,0,1,0,0,2,
/* table.move */ 0,5,12,0,0,0,35,BC_ISTYPE,0,12,0,BC_ISTYPE,1,14,0,BC_ISTYPE,
2,14,0,BC_ISTYPE,3,14,0,BC_ISNEP,4,0,0,BC_JMP,5,1,128,BC_MOV,4,0,0,BC_ISTYPE,
4,12,0,BC_ISGT,1,2,0,BC_JMP,5,24,128,BC_SUBVV,5,1,3,BC_ISLT,2,3,0,BC_JMP,6,4,
128,BC_ISLE,3,1,0,BC_JMP,6,2,128,BC_ISEQV,4,0,0,BC_JMP,6,9,128,BC_MOV,6,1,0,
BC_MOV,7,2,0,BC_KSHORT,8,1,0,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,
BC_TSETR,11,10,4,BC_FORL,6,252,127,BC_JMP,6,8,128,BC_MOV,6,2,0,BC_MOV,7,1,0,
BC_KSHORT,8,255,255,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,BC_TSETR,
11,10,4,BC_FORL,6,252,127,BC_RET1,4,2,0,
#else
/* math.deg */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,241,135,158,166,3,
220,203,178,130,4,
/* math.rad */ 0,1,2,0,0,1,2,BC_MULVN,1,0,0,BC_RET1,1,2,0,243,244,148,165,20,
198,190,199,252,3,
/* string.len */ 0,1,2,0,0,0,3,BC_ISTYPE,0,5,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
/* table.foreachi */ 0,2,9,0,0,0,15,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,
BC_KSHORT,2,1,0,BC_LEN,3,0,0,BC_KSHORT,4,1,0,BC_FORI,2,8,128,BC_MOV,6,1,0,
BC_MOV,7,5,0,BC_TGETR,8,5,0,BC_CALL,6,3,2,BC_ISEQP,6,0,0,BC_JMP,7,1,128,
BC_RET1,6,2,0,BC_FORL,2,248,127,BC_RET0,0,1,0,
/* table.foreach */ 0,2,10,0,0,1,16,BC_ISTYPE,0,12,0,BC_ISTYPE,1,9,0,BC_KPRI,
2,0,0,BC_MOV,3,0,0,BC_KNUM,4,0,0,BC_JMP,5,7,128,BC_MOV,7,1,0,BC_MOV,8,5,0,
BC_MOV,9,6,0,BC_CALL,7,3,2,BC_ISEQP,7,0,0,BC_JMP,8,1,128,BC_RET1,7,2,0,
BC_ITERN,5,3,3,BC_ITERL,5,247,127,BC_RET0,0,1,0,1,255,255,249,255,15,
/* table.getn */ 0,1,2,0,0,0,3,BC_ISTYPE,0,12,0,BC_LEN,1,0,0,BC_RET1,1,2,0,
/* table.remove */ 0,2,10,0,0,2,30,BC_ISTYPE,0,12,0,BC_LEN,2,0,0,BC_ISNEP,1,0,
0,BC_JMP,3,7,128,BC_ISEQN,2,0,0,BC_JMP,3,23,128,BC_TGETR,3,2,0,BC_KPRI,4,0,0,
BC_TSETR,4,2,0,BC_RET1,3,2,0,BC_JMP,3,18,128,BC_ISTYPE,1,14,0,BC_KSHORT,3,1,0,
BC_ISGT,3,1,0,BC_JMP,3,14,128,BC_ISGT,1,2,0,BC_JMP,3,12,128,BC_TGETR,3,1,0,
BC_ADDVN,4,1,1,BC_MOV,5,2,0,BC_KSHORT,6,1,0,BC_FORI,4,4,128,BC_SUBVN,8,1,7,
BC_TGETR,9,7,0,BC_TSETR,9,8,0,BC_FORL,4,252,127,BC_KPRI,4,0,0,BC_TSETR,4,2,0,
BC_RET1,3,2,0,BC_RET0,0,1,0,0,2,
/* table.move */ 0,5,12,0,0,0,35,BC_ISTYPE,0,12,0,BC_ISTYPE,1,14,0,BC_ISTYPE,
2,14,0,BC_ISTYPE,3,14,0,BC_ISNEP,4,0,0,BC_JMP,5,1,128,BC_MOV,4,0,0,BC_ISTYPE,
4,12,0,BC_ISGT,1,2,0,BC_JMP,5,24,128,BC_SUBVV,5,1,3,BC_ISLT,2,3,0,BC_JMP,6,4,
128,BC_ISLE,3,1,0,BC_JMP,6,2,128,BC_ISEQV,4,0,0,BC_JMP,6,9,128,BC_MOV,6,1,0,
BC_MOV,7,2,0,BC_KSHORT,8,1,0,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,
BC_TSETR,11,10,4,BC_FORL,6,252,127,BC_JMP,6,8,128,BC_MOV,6,2,0,BC_MOV,7,1,0,
BC_KSHORT,8,255,255,BC_FORI,6,4,128,BC_ADDVV,10,5,9,BC_TGETR,11,9,0,BC_TSETR,
11,10,4,BC_FORL,6,252,127,BC_RET1,4,2,0,
#endif
0
};
static const struct { const char *name; int ofs; } libbc_map[] = {
{"math_deg",0},
{"math_rad",25},
{"string_len",50},
{"table_foreachi",69},
{"table_foreach",136},
{"table_getn",213},
{"table_remove",232},
{"table_move",361},
{NULL,508}
};
+473
View File
@@ -0,0 +1,473 @@
/*
** LuaJIT VM builder: PE object emitter.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** Only used for building on Windows, since we cannot assume the presence
** of a suitable assembler. The host and target byte order must match.
*/
#include "buildvm.h"
#include "lj_bc.h"
#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
/* Context for PE object emitter. */
static char *strtab;
static size_t strtabofs;
/* -- PE object definitions ----------------------------------------------- */
/* PE header. */
typedef struct PEheader {
uint16_t arch;
uint16_t nsects;
uint32_t time;
uint32_t symtabofs;
uint32_t nsyms;
uint16_t opthdrsz;
uint16_t flags;
} PEheader;
/* PE section. */
typedef struct PEsection {
char name[8];
uint32_t vsize;
uint32_t vaddr;
uint32_t size;
uint32_t ofs;
uint32_t relocofs;
uint32_t lineofs;
uint16_t nreloc;
uint16_t nline;
uint32_t flags;
} PEsection;
/* PE relocation. */
typedef struct PEreloc {
uint32_t vaddr;
uint32_t symidx;
uint16_t type;
} PEreloc;
/* Cannot use sizeof, because it pads up to the max. alignment. */
#define PEOBJ_RELOC_SIZE (4+4+2)
/* PE symbol table entry. */
typedef struct PEsym {
union {
char name[8];
uint32_t nameref[2];
} n;
uint32_t value;
int16_t sect;
uint16_t type;
uint8_t scl;
uint8_t naux;
} PEsym;
/* PE symbol table auxiliary entry for a section. */
typedef struct PEsymaux {
uint32_t size;
uint16_t nreloc;
uint16_t nline;
uint32_t cksum;
uint16_t assoc;
uint8_t comdatsel;
uint8_t unused[3];
} PEsymaux;
/* Cannot use sizeof, because it pads up to the max. alignment. */
#define PEOBJ_SYM_SIZE (8+4+2+2+1+1)
/* PE object CPU specific defines. */
#if LJ_TARGET_X86
#define PEOBJ_ARCH_TARGET 0x014c
#define PEOBJ_RELOC_REL32 0x14 /* MS: REL32, GNU: DISP32. */
#define PEOBJ_RELOC_DIR32 0x06
#define PEOBJ_RELOC_OFS 0
#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
#elif LJ_TARGET_X64
#define PEOBJ_ARCH_TARGET 0x8664
#define PEOBJ_RELOC_REL32 0x04 /* MS: REL32, GNU: DISP32. */
#define PEOBJ_RELOC_DIR32 0x02
#define PEOBJ_RELOC_ADDR32NB 0x03
#define PEOBJ_RELOC_OFS 0
#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
#define PEOBJ_PDATA_NRELOC 6
#define PEOBJ_XDATA_SIZE (8*2+4+6*2)
#elif LJ_TARGET_ARM64
#define PEOBJ_ARCH_TARGET 0xaa64
#define PEOBJ_RELOC_REL32 0x03 /* MS: BRANCH26. */
#define PEOBJ_RELOC_DIR32 0x01
#define PEOBJ_RELOC_ADDR32NB 0x02
#define PEOBJ_RELOC_OFS (-4)
#define PEOBJ_TEXT_FLAGS 0x60500020 /* 60=r+x, 50=align16, 20=code. */
#define PEOBJ_PDATA_NRELOC 4
#define PEOBJ_XDATA_SIZE (4+24+4 +4+8)
#endif
/* Section numbers (0-based). */
enum {
PEOBJ_SECT_ABS = -2,
PEOBJ_SECT_UNDEF = -1,
PEOBJ_SECT_TEXT,
#ifdef PEOBJ_PDATA_NRELOC
PEOBJ_SECT_PDATA,
PEOBJ_SECT_XDATA,
#elif LJ_TARGET_X86
PEOBJ_SECT_SXDATA,
#endif
PEOBJ_SECT_RDATA_Z,
PEOBJ_NSECTIONS
};
/* Symbol types. */
#define PEOBJ_TYPE_NULL 0
#define PEOBJ_TYPE_FUNC 0x20
/* Symbol storage class. */
#define PEOBJ_SCL_EXTERN 2
#define PEOBJ_SCL_STATIC 3
/* -- PE object emitter --------------------------------------------------- */
/* Emit PE object symbol. */
static void emit_peobj_sym(BuildCtx *ctx, const char *name, uint32_t value,
int sect, int type, int scl)
{
PEsym sym;
size_t len = strlen(name);
if (!strtab) { /* Pass 1: only calculate string table length. */
if (len > 8) strtabofs += len+1;
return;
}
if (len <= 8) {
memcpy(sym.n.name, name, len);
memset(sym.n.name+len, 0, 8-len);
} else {
sym.n.nameref[0] = 0;
sym.n.nameref[1] = (uint32_t)strtabofs;
memcpy(strtab + strtabofs, name, len);
strtab[strtabofs+len] = 0;
strtabofs += len+1;
}
sym.value = value;
sym.sect = (int16_t)(sect+1); /* 1-based section number. */
sym.type = (uint16_t)type;
sym.scl = (uint8_t)scl;
sym.naux = 0;
owrite(ctx, &sym, PEOBJ_SYM_SIZE);
}
/* Emit PE object section symbol. */
static void emit_peobj_sym_sect(BuildCtx *ctx, PEsection *pesect, int sect)
{
PEsym sym;
PEsymaux aux;
if (!strtab) return; /* Pass 1: no output. */
memcpy(sym.n.name, pesect[sect].name, 8);
sym.value = 0;
sym.sect = (int16_t)(sect+1); /* 1-based section number. */
sym.type = PEOBJ_TYPE_NULL;
sym.scl = PEOBJ_SCL_STATIC;
sym.naux = 1;
owrite(ctx, &sym, PEOBJ_SYM_SIZE);
memset(&aux, 0, sizeof(PEsymaux));
aux.size = pesect[sect].size;
aux.nreloc = pesect[sect].nreloc;
owrite(ctx, &aux, PEOBJ_SYM_SIZE);
}
/* Emit Windows PE object file. */
void emit_peobj(BuildCtx *ctx)
{
PEheader pehdr;
PEsection pesect[PEOBJ_NSECTIONS];
uint32_t sofs;
int i, nrsym;
union { uint8_t b; uint32_t u; } host_endian;
#ifdef PEOBJ_PDATA_NRELOC
uint32_t fcofs = (uint32_t)ctx->sym[ctx->nsym-1].ofs;
#endif
sofs = sizeof(PEheader) + PEOBJ_NSECTIONS*sizeof(PEsection);
/* Fill in PE sections. */
memset(&pesect, 0, PEOBJ_NSECTIONS*sizeof(PEsection));
memcpy(pesect[PEOBJ_SECT_TEXT].name, ".text", sizeof(".text")-1);
pesect[PEOBJ_SECT_TEXT].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_TEXT].size = (uint32_t)ctx->codesz);
pesect[PEOBJ_SECT_TEXT].relocofs = sofs;
sofs += (pesect[PEOBJ_SECT_TEXT].nreloc = (uint16_t)ctx->nreloc) * PEOBJ_RELOC_SIZE;
/* Flags: 60 = read+execute, 50 = align16, 20 = code. */
pesect[PEOBJ_SECT_TEXT].flags = PEOBJ_TEXT_FLAGS;
#ifdef PEOBJ_PDATA_NRELOC
memcpy(pesect[PEOBJ_SECT_PDATA].name, ".pdata", sizeof(".pdata")-1);
pesect[PEOBJ_SECT_PDATA].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_PDATA].size = PEOBJ_PDATA_NRELOC*4);
pesect[PEOBJ_SECT_PDATA].relocofs = sofs;
sofs += (pesect[PEOBJ_SECT_PDATA].nreloc = PEOBJ_PDATA_NRELOC) * PEOBJ_RELOC_SIZE;
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
pesect[PEOBJ_SECT_PDATA].flags = 0x40300040;
memcpy(pesect[PEOBJ_SECT_XDATA].name, ".xdata", sizeof(".xdata")-1);
pesect[PEOBJ_SECT_XDATA].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_XDATA].size = PEOBJ_XDATA_SIZE); /* See below. */
pesect[PEOBJ_SECT_XDATA].relocofs = sofs;
sofs += (pesect[PEOBJ_SECT_XDATA].nreloc = 1) * PEOBJ_RELOC_SIZE;
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
pesect[PEOBJ_SECT_XDATA].flags = 0x40300040;
#elif LJ_TARGET_X86
memcpy(pesect[PEOBJ_SECT_SXDATA].name, ".sxdata", sizeof(".sxdata")-1);
pesect[PEOBJ_SECT_SXDATA].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_SXDATA].size = 4);
pesect[PEOBJ_SECT_SXDATA].relocofs = sofs;
/* Flags: 40 = read, 30 = align4, 02 = lnk_info, 40 = initialized data. */
pesect[PEOBJ_SECT_SXDATA].flags = 0x40300240;
#endif
memcpy(pesect[PEOBJ_SECT_RDATA_Z].name, ".rdata$Z", sizeof(".rdata$Z")-1);
pesect[PEOBJ_SECT_RDATA_Z].ofs = sofs;
sofs += (pesect[PEOBJ_SECT_RDATA_Z].size = (uint32_t)strlen(ctx->dasm_ident)+1);
/* Flags: 40 = read, 30 = align4, 40 = initialized data. */
pesect[PEOBJ_SECT_RDATA_Z].flags = 0x40300040;
/* Fill in PE header. */
pehdr.arch = PEOBJ_ARCH_TARGET;
pehdr.nsects = PEOBJ_NSECTIONS;
pehdr.time = 0; /* Timestamp is optional. */
pehdr.symtabofs = sofs;
pehdr.opthdrsz = 0;
pehdr.flags = 0;
/* Compute the size of the symbol table:
** @feat.00 + nsections*2
** + asm_start + nsym
** + nrsym
*/
nrsym = ctx->nrelocsym;
pehdr.nsyms = 1+PEOBJ_NSECTIONS*2 + 1+ctx->nsym + nrsym;
#ifdef PEOBJ_PDATA_NRELOC
pehdr.nsyms += 1; /* Symbol for lj_err_unwind_win. */
#endif
/* Write PE object header and all sections. */
owrite(ctx, &pehdr, sizeof(PEheader));
owrite(ctx, &pesect, sizeof(PEsection)*PEOBJ_NSECTIONS);
/* Write .text section. */
host_endian.u = 1;
if (host_endian.b != LJ_ENDIAN_SELECT(1, 0)) {
fprintf(stderr, "Error: different byte order for host and target\n");
exit(1);
}
owrite(ctx, ctx->code, ctx->codesz);
for (i = 0; i < ctx->nreloc; i++) {
PEreloc reloc;
reloc.vaddr = (uint32_t)ctx->reloc[i].ofs + PEOBJ_RELOC_OFS;
reloc.symidx = 1+2+ctx->reloc[i].sym; /* Reloc syms are after .text sym. */
reloc.type = ctx->reloc[i].type ? PEOBJ_RELOC_REL32 : PEOBJ_RELOC_DIR32;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
#if LJ_TARGET_X64
{ /* Write .pdata section. */
uint32_t pdata[3]; /* Start of .text, end of .text and .xdata. */
PEreloc reloc;
pdata[0] = 0; pdata[1] = fcofs; pdata[2] = 0;
owrite(ctx, &pdata, sizeof(pdata));
pdata[0] = fcofs; pdata[1] = (uint32_t)ctx->codesz; pdata[2] = 20;
owrite(ctx, &pdata, sizeof(pdata));
reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 16; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 20; reloc.symidx = 1+2+nrsym+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
{ /* Write .xdata section. */
uint16_t xdata[8+2+6];
PEreloc reloc;
xdata[0] = 0x01|0x08|0x10; /* Ver. 1, uhandler/ehandler, prolog size 0. */
xdata[1] = 0x0005; /* Number of unwind codes, no frame pointer. */
xdata[2] = 0x4200; /* Stack offset 4*8+8 = aword*5. */
xdata[3] = 0x3000; /* Push rbx. */
xdata[4] = 0x6000; /* Push rsi. */
xdata[5] = 0x7000; /* Push rdi. */
xdata[6] = 0x5000; /* Push rbp. */
xdata[7] = 0; /* Alignment. */
xdata[8] = xdata[9] = 0; /* Relocated address of exception handler. */
xdata[10] = 0x01; /* Ver. 1, no handler, prolog size 0. */
xdata[11] = 0x1504; /* Number of unwind codes, fp = rbp, fpofs = 16. */
xdata[12] = 0x0300; /* set_fpreg. */
xdata[13] = 0x0200; /* stack offset 0*8+8 = aword*1. */
xdata[14] = 0x3000; /* Push rbx. */
xdata[15] = 0x5000; /* Push rbp. */
owrite(ctx, &xdata, sizeof(xdata));
reloc.vaddr = 2*8; reloc.symidx = 1+2+nrsym+2+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
#elif LJ_TARGET_ARM64
/* https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling */
{ /* Write .pdata section. */
uint32_t pdata[4];
PEreloc reloc;
pdata[0] = 0;
pdata[1] = 0;
pdata[2] = fcofs;
pdata[3] = 4+24+4;
owrite(ctx, &pdata, sizeof(pdata));
/* Start of .text and start of .xdata. */
reloc.vaddr = 0; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 4; reloc.symidx = 1+2+nrsym+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
/* Start of vm_ffi_call and start of second part of .xdata. */
reloc.vaddr = 8; reloc.symidx = 1+2+nrsym+2+2+1;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
reloc.vaddr = 12; reloc.symidx = 1+2+nrsym+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
{ /* Write .xdata section. */
uint32_t u32;
uint8_t *p, uwc[24];
PEreloc reloc;
#define CBE16(x) (*p = ((x) >> 8) & 0xff, p[1] = (x) & 0xff, p += 2)
#define CALLOC_S(s) (*p++ = ((s) >> 4)) /* s < 512 */
#define CSAVE_FPLR(o) (*p++ = 0x40 | ((o) >> 3)) /* o <= 504 */
#define CSAVE_REGP(r,o) CBE16(0xc800 | (((r) - 19) << 6) | ((o) >> 3))
#define CSAVE_REGS(r1,r2,o1) do { \
int r, o; for (r = r1, o = o1; r <= r2; r += 2, o -= 16) CSAVE_REGP(r, o); \
} while (0)
#define CSAVE_REGPX(r,o) CBE16(0xcc00 | (((r) - 19) << 6) | (~(o) >> 3))
#define CSAVE_FREGP(r,o) CBE16(0xd800 | (((r) - 8) << 6) | ((o) >> 3))
#define CSAVE_FREGS(r1,r2,o1) do { \
int r, o; for (r = r1, o = o1; r <= r2; r += 2, o -= 16) CSAVE_FREGP(r, o); \
} while (0)
#define CADD_FP(s) CBE16(0xe200 | ((s) >> 3)) /* s < 8*256 */
#define CODE_NOP 0xe3
#define CODE_END 0xe4
#define CEND_ALIGN do { \
*p++ = CODE_END; \
while ((p - uwc) & 3) *p++ = CODE_NOP; \
} while (0)
/* Unwind codes for .text section with handler. */
p = uwc;
CADD_FP(192); /* +2 */
CSAVE_REGS(19, 28, 176); /* +5*2 */
CSAVE_FREGS(8, 15, 96); /* +4*2 */
CSAVE_FPLR(192); /* +1 */
CALLOC_S(208); /* +1 */
CEND_ALIGN; /* +1 +1 -> 24 */
u32 = ((24u >> 2) << 27) | (1u << 20) | (fcofs >> 2);
owrite(ctx, &u32, 4);
owrite(ctx, &uwc, 24);
u32 = 0; /* Handler RVA to be relocated at 4 + 24. */
owrite(ctx, &u32, 4);
/* Unwind codes for vm_ffi_call without handler. */
p = uwc;
CADD_FP(16); /* +2 */
CSAVE_FPLR(16); /* +1 */
CSAVE_REGPX(19, -32); /* +2 */
CEND_ALIGN; /* +1 +2 -> 8 */
u32 = ((8u >> 2) << 27) | (((uint32_t)ctx->codesz - fcofs) >> 2);
owrite(ctx, &u32, 4);
owrite(ctx, &uwc, 8);
reloc.vaddr = 4 + 24; reloc.symidx = 1+2+nrsym+2+2;
reloc.type = PEOBJ_RELOC_ADDR32NB;
owrite(ctx, &reloc, PEOBJ_RELOC_SIZE);
}
#elif LJ_TARGET_X86
/* Write .sxdata section. */
for (i = 0; i < nrsym; i++) {
if (!strcmp(ctx->relocsym[i], "_lj_err_unwind_win")) {
uint32_t symidx = 1+2+i;
owrite(ctx, &symidx, 4);
break;
}
}
if (i == nrsym) {
fprintf(stderr, "Error: extern lj_err_unwind_win not used\n");
exit(1);
}
#endif
/* Write .rdata$Z section. */
owrite(ctx, ctx->dasm_ident, strlen(ctx->dasm_ident)+1);
/* Write symbol table. */
strtab = NULL; /* 1st pass: collect string sizes. */
for (;;) {
strtabofs = 4;
/* Mark as SafeSEH compliant. */
emit_peobj_sym(ctx, "@feat.00", 1,
PEOBJ_SECT_ABS, PEOBJ_TYPE_NULL, PEOBJ_SCL_STATIC);
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_TEXT);
for (i = 0; i < nrsym; i++)
emit_peobj_sym(ctx, ctx->relocsym[i], 0,
PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
#ifdef PEOBJ_PDATA_NRELOC
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_PDATA);
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_XDATA);
emit_peobj_sym(ctx, "lj_err_unwind_win", 0,
PEOBJ_SECT_UNDEF, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
#elif LJ_TARGET_X86
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_SXDATA);
#endif
emit_peobj_sym(ctx, ctx->beginsym, 0,
PEOBJ_SECT_TEXT, PEOBJ_TYPE_NULL, PEOBJ_SCL_EXTERN);
for (i = 0; i < ctx->nsym; i++)
emit_peobj_sym(ctx, ctx->sym[i].name, (uint32_t)ctx->sym[i].ofs,
PEOBJ_SECT_TEXT, PEOBJ_TYPE_FUNC, PEOBJ_SCL_EXTERN);
emit_peobj_sym_sect(ctx, pesect, PEOBJ_SECT_RDATA_Z);
if (strtab)
break;
/* 2nd pass: alloc strtab, write syms and copy strings. */
strtab = (char *)malloc(strtabofs);
*(uint32_t *)strtab = (uint32_t)strtabofs;
}
/* Write string table. */
owrite(ctx, strtab, strtabofs);
}
#else
void emit_peobj(BuildCtx *ctx)
{
UNUSED(ctx);
fprintf(stderr, "Error: no PE object support for this target\n");
exit(1);
}
#endif
+234
View File
@@ -0,0 +1,234 @@
----------------------------------------------------------------------------
-- Lua script to dump the bytecode of the library functions written in Lua.
-- The resulting 'buildvm_libbc.h' is used for the build process of LuaJIT.
----------------------------------------------------------------------------
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
local ffi = require("ffi")
local bit = require("bit")
local vmdef = require("jit.vmdef")
local bcnames = vmdef.bcnames
local format = string.format
local isbe = (string.byte(string.dump(function() end), 5) % 2 == 1)
local function usage(arg)
io.stderr:write("Usage: ", arg and arg[0] or "genlibbc",
" [-o buildvm_libbc.h] lib_*.c\n")
os.exit(1)
end
local function parse_arg(arg)
local outfile = "-"
if not (arg and arg[1]) then
usage(arg)
end
if arg[1] == "-o" then
outfile = arg[2]
if not outfile then usage(arg) end
table.remove(arg, 1)
table.remove(arg, 1)
end
return outfile
end
local function read_files(names)
local src = ""
for _,name in ipairs(names) do
local fp = assert(io.open(name))
src = src .. fp:read("*a")
fp:close()
end
return src
end
local function transform_lua(code)
local fixup = {}
local n = -30000
code = string.gsub(code, "CHECK_(%w*)%((.-)%)", function(tp, var)
n = n + 1
fixup[n] = { "CHECK", tp }
return format("%s=%d", var, n)
end)
code = string.gsub(code, "PAIRS%((.-)%)", function(var)
fixup.PAIRS = true
return format("nil, %s, 0x4dp80", var)
end)
return "return "..code, fixup
end
local function read_uleb128(p)
local v = p[0]; p = p + 1
if v >= 128 then
local sh = 7; v = v - 128
repeat
local r = p[0]
v = v + bit.lshift(bit.band(r, 127), sh)
sh = sh + 7
p = p + 1
until r < 128
end
return p, v
end
-- ORDER LJ_T
local name2itype = {
str = 5, func = 9, tab = 12, int = 14, num = 15
}
local BC, BCN = {}, {}
for i=0,#bcnames/6-1 do
local name = bcnames:sub(i*6+1, i*6+6):gsub(" ", "")
BC[name] = i
BCN[i] = name
end
local xop, xra = isbe and 3 or 0, isbe and 2 or 1
local xrc, xrb = isbe and 1 or 2, isbe and 0 or 3
local function fixup_dump(dump, fixup)
local buf = ffi.new("uint8_t[?]", #dump+1, dump)
local p = buf+5
local n, sizebc
p, n = read_uleb128(p)
local start = p
p = p + 4
p = read_uleb128(p)
p = read_uleb128(p)
p, sizebc = read_uleb128(p)
local startbc = tonumber(p - start)
local rawtab = {}
for i=0,sizebc-1 do
local op = p[xop]
if op == BC.KSHORT then
local rd = p[xrc] + 256*p[xrb]
rd = bit.arshift(bit.lshift(rd, 16), 16)
local f = fixup[rd]
if f then
if f[1] == "CHECK" then
local tp = f[2]
if tp == "tab" then rawtab[p[xra]] = true end
p[xop] = tp == "num" and BC.ISNUM or BC.ISTYPE
p[xrb] = 0
p[xrc] = name2itype[tp]
else
error("unhandled fixup type: "..f[1])
end
end
elseif op == BC.TGETV then
if rawtab[p[xrb]] then
p[xop] = BC.TGETR
end
elseif op == BC.TSETV then
if rawtab[p[xrb]] then
p[xop] = BC.TSETR
end
elseif op == BC.ITERC then
if fixup.PAIRS then
p[xop] = BC.ITERN
end
end
p = p + 4
end
local ndump = ffi.string(start, n)
-- Fixup hi-part of 0x4dp80 to LJ_KEYINDEX.
ndump = ndump:gsub("\x80\x80\xcd\xaa\x04", "\xff\xff\xf9\xff\x0f")
return { dump = ndump, startbc = startbc, sizebc = sizebc }
end
local function find_defs(src, mode)
local defs = {}
for name, code in string.gmatch(src, "LJLIB_LUA%(([^)]*)%)%s*/%*(.-)%*/") do
local tcode, fixup = transform_lua(code)
local func = assert(load(tcode, "", mode))
defs[name] = fixup_dump(string.dump(func, mode), fixup)
defs[#defs+1] = name
end
return defs
end
local function gen_header(defs32, defs64)
local t = {}
local function w(x) t[#t+1] = x end
w("/* This is a generated file. DO NOT EDIT! */\n\n")
w("static const int libbc_endian = ") w(isbe and 1 or 0) w(";\n\n")
for j,defs in ipairs{defs64, defs32} do
local s, sb = "", ""
for i,name in ipairs(defs) do
local d = defs[name]
s = s .. d.dump
sb = sb .. string.char(i) .. ("\0"):rep(d.startbc - 1)
.. (isbe and "\0\0\0\255" or "\255\0\0\0"):rep(d.sizebc)
.. ("\0"):rep(#d.dump - d.startbc - d.sizebc*4)
end
if j == 1 then
w("static const uint8_t libbc_code[] = {\n#if LJ_FR2\n")
else
w("\n#else\n")
end
local n = 0
for i=1,#s do
local x = string.byte(s, i)
local xb = string.byte(sb, i)
if xb == 255 then
local name = BCN[x]
local m = #name + 4
if n + m > 78 then n = 0; w("\n") end
n = n + m
w("BC_"); w(name)
else
local m = x < 10 and 2 or (x < 100 and 3 or 4)
if xb == 0 then
if n + m > 78 then n = 0; w("\n") end
else
local name = defs[xb]:gsub("_", ".")
if n ~= 0 then w("\n") end
w("/* "); w(name); w(" */ ")
n = #name + 7
end
n = n + m
w(x)
end
w(",")
end
end
w("\n#endif\n0\n};\n\n")
w("static const struct { const char *name; int ofs; } libbc_map[] = {\n")
local m32, m64 = 0, 0
for i,name in ipairs(defs32) do
assert(name == defs64[i])
w('{"'); w(name); w('",'); w(m32) w('},\n')
m32 = m32 + #defs32[name].dump
m64 = m64 + #defs64[name].dump
assert(m32 == m64)
end
w("{NULL,"); w(m32); w("}\n};\n\n")
return table.concat(t)
end
local function write_file(name, data)
if name == "-" then
assert(io.write(data))
assert(io.flush())
else
local fp = io.open(name)
if fp then
local old = fp:read("*a")
fp:close()
if data == old then return end
end
fp = assert(io.open(name, "w"))
assert(fp:write(data))
assert(fp:close())
end
end
local outfile = parse_arg(arg)
local src = read_files(arg)
local defs32 = find_defs(src, "Wdts")
local defs64 = find_defs(src, "Xdts")
local hdr = gen_header(defs32, defs64)
write_file(outfile, hdr)
+436
View File
@@ -0,0 +1,436 @@
----------------------------------------------------------------------------
-- Lua script to generate a customized, minified version of Lua.
-- The resulting 'minilua' is used for the build process of LuaJIT.
----------------------------------------------------------------------------
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
local sub, match, gsub = string.sub, string.match, string.gsub
local LUA_VERSION = "5.1.5"
local LUA_SOURCE
local function usage()
io.stderr:write("Usage: ", arg and arg[0] or "genminilua",
" lua-", LUA_VERSION, "-source-dir\n")
os.exit(1)
end
local function find_sources()
LUA_SOURCE = arg and arg[1]
if not LUA_SOURCE then usage() end
if sub(LUA_SOURCE, -1) ~= "/" then LUA_SOURCE = LUA_SOURCE.."/" end
local fp = io.open(LUA_SOURCE .. "lua.h")
if not fp then
LUA_SOURCE = LUA_SOURCE.."src/"
fp = io.open(LUA_SOURCE .. "lua.h")
if not fp then usage() end
end
local all = fp:read("*a")
fp:close()
if not match(all, 'LUA_RELEASE%s*"Lua '..LUA_VERSION..'"') then
io.stderr:write("Error: version mismatch\n")
usage()
end
end
local LUA_FILES = {
"lmem.c", "lobject.c", "ltm.c", "lfunc.c", "ldo.c", "lstring.c", "ltable.c",
"lgc.c", "lstate.c", "ldebug.c", "lzio.c", "lopcodes.c",
"llex.c", "lcode.c", "lparser.c", "lvm.c", "lapi.c", "lauxlib.c",
"lbaselib.c", "ltablib.c", "liolib.c", "loslib.c", "lstrlib.c", "linit.c",
}
local REMOVE_LIB = {}
gsub([[
collectgarbage dofile gcinfo getfenv getmetatable load print rawequal rawset
select tostring xpcall
foreach foreachi getn maxn setn
popen tmpfile seek setvbuf __tostring
clock date difftime execute getenv rename setlocale time tmpname
dump gfind len reverse
LUA_LOADLIBNAME LUA_MATHLIBNAME LUA_DBLIBNAME
]], "%S+", function(name)
REMOVE_LIB[name] = true
end)
local REMOVE_EXTINC = { ["<assert.h>"] = true, ["<locale.h>"] = true, }
local CUSTOM_MAIN = [[
typedef unsigned int UB;
static UB barg(lua_State *L,int idx){
union{lua_Number n;U64 b;}bn;
bn.n=lua_tonumber(L,idx)+6755399441055744.0;
if (bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number");
return(UB)bn.b;
}
#define BRET(b) lua_pushnumber(L,(lua_Number)(int)(b));return 1;
static int tobit(lua_State *L){
BRET(barg(L,1))}
static int bnot(lua_State *L){
BRET(~barg(L,1))}
static int band(lua_State *L){
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)}
static int bor(lua_State *L){
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)}
static int bxor(lua_State *L){
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)}
static int lshift(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET(b<<n)}
static int rshift(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET(b>>n)}
static int arshift(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)}
static int rol(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET((b<<n)|(b>>(32-n)))}
static int ror(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))}
static int bswap(lua_State *L){
UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)}
static int tohex(lua_State *L){
UB b=barg(L,1);
int n=lua_isnone(L,2)?8:(int)barg(L,2);
const char *hexdigits="0123456789abcdef";
char buf[8];
int i;
if(n<0){n=-n;hexdigits="0123456789ABCDEF";}
if(n>8)n=8;
for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;}
lua_pushlstring(L,buf,(size_t)n);
return 1;
}
static const struct luaL_Reg bitlib[] = {
{"tobit",tobit},
{"bnot",bnot},
{"band",band},
{"bor",bor},
{"bxor",bxor},
{"lshift",lshift},
{"rshift",rshift},
{"arshift",arshift},
{"rol",rol},
{"ror",ror},
{"bswap",bswap},
{"tohex",tohex},
{NULL,NULL}
};
int main(int argc, char **argv){
lua_State *L = luaL_newstate();
int i;
luaL_openlibs(L);
luaL_register(L, "bit", bitlib);
if (argc < 2) return sizeof(void *);
lua_createtable(L, 0, 1);
lua_pushstring(L, argv[1]);
lua_rawseti(L, -2, 0);
lua_setglobal(L, "arg");
if (luaL_loadfile(L, argv[1]))
goto err;
for (i = 2; i < argc; i++)
lua_pushstring(L, argv[i]);
if (lua_pcall(L, argc - 2, 0, 0)) {
err:
fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
return 1;
}
lua_close(L);
return 0;
}
]]
local function read_sources()
local t = {}
for i, name in ipairs(LUA_FILES) do
local fp = assert(io.open(LUA_SOURCE..name, "r"))
t[i] = fp:read("*a")
assert(fp:close())
end
t[#t+1] = CUSTOM_MAIN
return table.concat(t)
end
local includes = {}
local function merge_includes(src)
return gsub(src, '#include%s*"([^"]*)"%s*\n', function(name)
if includes[name] then return "" end
includes[name] = true
local fp = assert(io.open(LUA_SOURCE..name, "r"))
local inc = fp:read("*a")
assert(fp:close())
inc = gsub(inc, "#ifndef%s+%w+_h\n#define%s+%w+_h\n", "")
inc = gsub(inc, "#endif%s*$", "")
return merge_includes(inc)
end)
end
local function get_license(src)
return match(src, "/%*+\n%* Copyright %(.-%*/\n")
end
local function fold_lines(src)
return gsub(src, "\\\n", " ")
end
local strings = {}
local function save_str(str)
local n = #strings+1
strings[n] = str
return "\1"..n.."\2"
end
local function save_strings(src)
src = gsub(src, '"[^"\n]*"', save_str)
return gsub(src, "'[^'\n]*'", save_str)
end
local function restore_strings(src)
return gsub(src, "\1(%d+)\2", function(numstr)
return strings[tonumber(numstr)]
end)
end
local function def_istrue(def)
return def == "INT_MAX > 2147483640L" or
def == "LUAI_BITSINT >= 32" or
def == "SIZE_Bx < LUAI_BITSINT-1" or
def == "cast" or
def == "defined(LUA_CORE)" or
def == "MINSTRTABSIZE" or
def == "LUA_MINBUFFER" or
def == "HARDSTACKTESTS" or
def == "UNUSED"
end
local head, defs = {[[
#ifdef _MSC_VER
typedef unsigned __int64 U64;
#else
typedef unsigned long long U64;
#endif
int _CRT_glob = 0;
]]}, {}
local function preprocess(src)
local t = { match(src, "^(.-)#") }
local lvl, on, oldon = 0, true, {}
for pp, def, txt in string.gmatch(src, "#(%w+) *([^\n]*)\n([^#]*)") do
if pp == "if" or pp == "ifdef" or pp == "ifndef" then
lvl = lvl + 1
oldon[lvl] = on
on = def_istrue(def)
elseif pp == "else" then
if oldon[lvl] then
if on == false then on = true else on = false end
end
elseif pp == "elif" then
if oldon[lvl] then
on = def_istrue(def)
end
elseif pp == "endif" then
on = oldon[lvl]
lvl = lvl - 1
elseif on then
if pp == "include" then
if not head[def] and not REMOVE_EXTINC[def] then
head[def] = true
head[#head+1] = "#include "..def.."\n"
end
elseif pp == "define" then
local k, sp, v = match(def, "([%w_]+)(%s*)(.*)")
if k and not (sp == "" and sub(v, 1, 1) == "(") then
defs[k] = gsub(v, "%a[%w_]*", function(tok)
return defs[tok] or tok
end)
else
t[#t+1] = "#define "..def.."\n"
end
elseif pp ~= "undef" then
error("unexpected directive: "..pp.." "..def)
end
end
if on then t[#t+1] = txt end
end
return gsub(table.concat(t), "%a[%w_]*", function(tok)
return defs[tok] or tok
end)
end
local function merge_header(src, license)
local hdr = string.format([[
/* This is a heavily customized and minimized copy of Lua %s. */
/* It's only used to build LuaJIT. It does NOT have all standard functions! */
]], LUA_VERSION)
return hdr..license..table.concat(head)..src
end
local function strip_unused1(src)
return gsub(src, '( {"?([%w_]+)"?,%s+%a[%w_]*},\n)', function(line, func)
return REMOVE_LIB[func] and "" or line
end)
end
local function strip_unused2(src)
return gsub(src, "Symbolic Execution.-}=", "")
end
local function strip_unused3(src)
src = gsub(src, "extern", "static")
src = gsub(src, "\nstatic([^\n]-)%(([^)]*)%)%(", "\nstatic%1 %2(")
src = gsub(src, "#define lua_assert[^\n]*\n", "")
src = gsub(src, "lua_assert%b();?", "")
src = gsub(src, "default:\n}", "default:;\n}")
src = gsub(src, "lua_lock%b();", "")
src = gsub(src, "lua_unlock%b();", "")
src = gsub(src, "luai_threadyield%b();", "")
src = gsub(src, "luai_userstateopen%b();", "{}")
src = gsub(src, "luai_userstate%w+%b();", "")
src = gsub(src, "%(%(c==.*luaY_parser%)", "luaY_parser")
src = gsub(src, "trydecpoint%(ls,seminfo%)",
"luaX_lexerror(ls,\"malformed number\",TK_NUMBER)")
src = gsub(src, "int c=luaZ_lookahead%b();", "")
src = gsub(src, "luaL_register%(L,[^,]*,co_funcs%);\nreturn 2;",
"return 1;")
src = gsub(src, "getfuncname%b():", "NULL:")
src = gsub(src, "getobjname%b():", "NULL:")
src = gsub(src, "if%([^\n]*hookmask[^\n]*%)\n[^\n]*\n", "")
src = gsub(src, "if%([^\n]*hookmask[^\n]*%)%b{}\n", "")
src = gsub(src, "if%([^\n]*hookmask[^\n]*&&\n[^\n]*%b{}\n", "")
src = gsub(src, "(twoto%b()%()", "%1(size_t)")
src = gsub(src, "i<sizenode", "i<(int)sizenode")
src = gsub(src, "cast%(unsigned int,key%-1%)", "cast(unsigned int,key)-1")
return gsub(src, "\n\n+", "\n")
end
local function strip_comments(src)
return gsub(src, "/%*.-%*/", " ")
end
local function strip_whitespace(src)
src = gsub(src, "^%s+", "")
src = gsub(src, "%s*\n%s*", "\n")
src = gsub(src, "[ \t]+", " ")
src = gsub(src, "(%W) ", "%1")
return gsub(src, " (%W)", "%1")
end
local function rename_tokens1(src)
src = gsub(src, "getline", "getline_")
src = gsub(src, "struct ([%w_]+)", "ZX%1")
return gsub(src, "union ([%w_]+)", "ZY%1")
end
local function rename_tokens2(src)
src = gsub(src, "ZX([%w_]+)", "struct %1")
return gsub(src, "ZY([%w_]+)", "union %1")
end
local function fix_bugs_and_warnings(src)
src = gsub(src, "(luaD_checkstack%(L,p%->maxstacksize)%)", "%1+p->numparams)")
src = gsub(src, "if%(sep==%-1%)(return'%[';)\nelse (luaX_lexerror%b();)", "if (sep!=-1)%2\n%1")
return gsub(src, "(default:{\nNode%*n=mainposition)", "/*fallthrough*/\n%1")
end
local function func_gather(src)
local nodes, list = {}, {}
local pos, len = 1, #src
while pos < len do
local d, w = match(src, "^(#define ([%w_]+)[^\n]*\n)", pos)
if d then
local n = #list+1
list[n] = d
nodes[w] = n
else
local s
d, w, s = match(src, "^(([%w_]+)[^\n]*([{;])\n)", pos)
if not d then
d, w, s = match(src, "^(([%w_]+)[^(]*%b()([{;])\n)", pos)
if not d then d = match(src, "^[^\n]*\n", pos) end
end
if s == "{" then
d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
if sub(d, -2) == "{\n" then
d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
end
end
local k, v = nil, d
if w == "typedef" then
if match(d, "^typedef enum") then
head[#head+1] = d
else
k = match(d, "([%w_]+);\n$")
if not k then k = match(d, "^.-%(.-([%w_]+)%)%(") end
end
elseif w == "enum" then
head[#head+1] = v
elseif w ~= nil then
k = match(d, "^[^\n]-([%w_]+)[(%[=]")
if k then
if w ~= "static" and k ~= "main" then v = "static "..d end
else
k = w
end
end
if w and k then
local o = nodes[k]
if o then nodes["*"..k] = o end
local n = #list+1
list[n] = v
nodes[k] = n
end
end
pos = pos + #d
end
return nodes, list
end
local function func_visit(nodes, list, used, n)
local i = nodes[n]
for m in string.gmatch(list[i], "[%w_]+") do
if nodes[m] then
local j = used[m]
if not j then
used[m] = i
func_visit(nodes, list, used, m)
elseif i < j then
used[m] = i
end
end
end
end
local function func_collect(src)
local nodes, list = func_gather(src)
local used = {}
func_visit(nodes, list, used, "main")
for n,i in pairs(nodes) do
local j = used[n]
if j and j < i then used["*"..n] = j end
end
for n,i in pairs(nodes) do
if not used[n] then list[i] = "" end
end
return table.concat(list)
end
find_sources()
local src = read_sources()
src = merge_includes(src)
local license = get_license(src)
src = fold_lines(src)
src = strip_unused1(src)
src = save_strings(src)
src = strip_unused2(src)
src = strip_comments(src)
src = preprocess(src)
src = strip_whitespace(src)
src = strip_unused3(src)
src = rename_tokens1(src)
src = func_collect(src)
src = rename_tokens2(src)
src = restore_strings(src)
src = fix_bugs_and_warnings(src)
src = merge_header(src, license)
io.write(src)
+45
View File
@@ -0,0 +1,45 @@
----------------------------------------------------------------------------
-- Lua script to embed the rolling release version in luajit.h.
----------------------------------------------------------------------------
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
local arg = {...}
local FILE_ROLLING_H = arg[1] or "luajit_rolling.h"
local FILE_RELVER_TXT = arg[2] or "luajit_relver.txt"
local FILE_LUAJIT_H = arg[3] or "luajit.h"
local function file_read(file)
local fp = assert(io.open(file, "rb"), "run from the wrong directory")
local data = assert(fp:read("*a"))
fp:close()
return data
end
local function file_write_mod(file, data)
local fp = io.open(file, "rb")
if fp then
local odata = assert(fp:read("*a"))
fp:close()
if odata == data then return end
end
fp = assert(io.open(file, "wb"))
assert(fp:write(data))
assert(fp:close())
end
local text = file_read(FILE_ROLLING_H):gsub("#error.-\n", "")
local relver = file_read(FILE_RELVER_TXT):match("(%d+)")
if relver then
text = text:gsub("ROLLING", relver)
else
io.stderr:write([[
**** WARNING Cannot determine rolling release version from git log.
**** WARNING The 'git' command must be available during the build.
]])
file_write_mod(FILE_RELVER_TXT, "ROLLING\n") -- Fallback for install target.
end
file_write_mod(FILE_LUAJIT_H, text)
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
vmdef.lua
+189
View File
@@ -0,0 +1,189 @@
----------------------------------------------------------------------------
-- LuaJIT bytecode listing module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module lists the bytecode of a Lua function. If it's loaded by -jbc
-- it hooks into the parser and lists all functions of a chunk as they
-- are parsed.
--
-- Example usage:
--
-- luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)'
-- luajit -jbc=- foo.lua
-- luajit -jbc=foo.list foo.lua
--
-- Default output is to stderr. To redirect the output to a file, pass a
-- filename as an argument (use '-' for stdout) or set the environment
-- variable LUAJIT_LISTFILE. The file is overwritten every time the module
-- is started.
--
-- This module can also be used programmatically:
--
-- local bc = require("jit.bc")
--
-- local function foo() print("hello") end
--
-- bc.dump(foo) --> -- BYTECODE -- [...]
-- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello"
--
-- local out = {
-- -- Do something with each line:
-- write = function(t, ...) io.write(...) end,
-- close = function(t) end,
-- flush = function(t) end,
-- }
-- bc.dump(foo, out)
--
------------------------------------------------------------------------------
-- Cache some library functions and objects.
local jit = require("jit")
local jutil = require("jit.util")
local vmdef = require("jit.vmdef")
local bit = require("bit")
local sub, gsub, format = string.sub, string.gsub, string.format
local byte, band, shr = string.byte, bit.band, bit.rshift
local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck
local funcuvname = jutil.funcuvname
local bcnames = vmdef.bcnames
local stdout, stderr = io.stdout, io.stderr
------------------------------------------------------------------------------
local function ctlsub(c)
if c == "\n" then return "\\n"
elseif c == "\r" then return "\\r"
elseif c == "\t" then return "\\t"
else return format("\\%03d", byte(c))
end
end
-- Return one bytecode line.
local function bcline(func, pc, prefix)
local ins, m = funcbc(func, pc)
if not ins then return end
local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128)
local a = band(shr(ins, 8), 0xff)
local oidx = 6*band(ins, 0xff)
local op = sub(bcnames, oidx+1, oidx+6)
local s = format("%04d %s %-6s %3s ",
pc, prefix or " ", op, ma == 0 and "" or a)
local d = shr(ins, 16)
if mc == 13*128 then -- BCMjump
return format("%s=> %04d\n", s, pc+d-0x7fff)
end
if mb ~= 0 then
d = band(d, 0xff)
elseif mc == 0 then
return s.."\n"
end
local kc
if mc == 10*128 then -- BCMstr
kc = funck(func, -d-1)
kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub))
elseif mc == 9*128 then -- BCMnum
kc = funck(func, d)
if op == "TSETM " then kc = kc - 2^52 end
elseif mc == 12*128 then -- BCMfunc
local fi = funcinfo(funck(func, -d-1))
if fi.ffid then
kc = vmdef.ffnames[fi.ffid]
else
kc = fi.loc
end
elseif mc == 5*128 then -- BCMuv
kc = funcuvname(func, d)
end
if ma == 5 then -- BCMuv
local ka = funcuvname(func, a)
if kc then kc = ka.." ; "..kc else kc = ka end
end
if mb ~= 0 then
local b = shr(ins, 24)
if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end
return format("%s%3d %3d\n", s, b, d)
end
if kc then return format("%s%3d ; %s\n", s, d, kc) end
if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits
return format("%s%3d\n", s, d)
end
-- Collect branch targets of a function.
local function bctargets(func)
local target = {}
for pc=1,1000000000 do
local ins, m = funcbc(func, pc)
if not ins then break end
if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end
end
return target
end
-- Dump bytecode instructions of a function.
local function bcdump(func, out, all)
if not out then out = stdout end
local fi = funcinfo(func)
if all and fi.children then
for n=-1,-1000000000,-1 do
local k = funck(func, n)
if not k then break end
if type(k) == "proto" then bcdump(k, out, true) end
end
end
out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined))
local target = bctargets(func)
for pc=1,1000000000 do
local s = bcline(func, pc, target[pc] and "=>")
if not s then break end
out:write(s)
end
out:write("\n")
out:flush()
end
------------------------------------------------------------------------------
-- Active flag and output file handle.
local active, out
-- List handler.
local function h_list(func)
return bcdump(func, out)
end
-- Detach list handler.
local function bclistoff()
if active then
active = false
jit.attach(h_list)
if out and out ~= stdout and out ~= stderr then out:close() end
out = nil
end
end
-- Open the output file and attach list handler.
local function bcliston(outfile)
if active then bclistoff() end
if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end
if outfile then
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
else
out = stderr
end
jit.attach(h_list, "bc")
active = true
end
-- Public module functions.
return {
line = bcline,
dump = bcdump,
targets = bctargets,
on = bcliston,
off = bclistoff,
start = bcliston -- For -j command line option.
}
+629
View File
@@ -0,0 +1,629 @@
----------------------------------------------------------------------------
-- LuaJIT module to save/list bytecode.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module saves or lists the bytecode for an input file.
-- It's run by the -b command line option.
--
------------------------------------------------------------------------------
local jit = require("jit")
assert(jit.version_num == 20199, "LuaJIT core/library version mismatch")
local bit = require("bit")
-- Symbol name prefix for LuaJIT bytecode.
local LJBC_PREFIX = "luaJIT_BC_"
local type, assert = type, assert
local format = string.format
local tremove, tconcat = table.remove, table.concat
------------------------------------------------------------------------------
local function usage()
io.stderr:write[[
Save LuaJIT bytecode: luajit -b[options] input output
-l Only list bytecode.
-s Strip debug info (default).
-g Keep debug info.
-W Generate 32 bit (non-GC64) bytecode.
-X Generate 64 bit (GC64) bytecode.
-d Generate bytecode in deterministic manner.
-n name Set module name (default: auto-detect from input name).
-t type Set output file type (default: auto-detect from output name).
-a arch Override architecture for object files (default: native).
-o os Override OS for object files (default: native).
-F name Override filename (default: input filename).
-e chunk Use chunk string as input.
-- Stop handling options.
- Use stdin as input and/or stdout as output.
File types: c cc h obj o raw (default)
]]
os.exit(1)
end
local function check(ok, ...)
if ok then return ok, ... end
io.stderr:write("luajit: ", ...)
io.stderr:write("\n")
os.exit(1)
end
local function readfile(ctx, input)
if ctx.string then
return check(loadstring(input, nil, ctx.mode))
elseif ctx.filename then
local data
if input == "-" then
data = io.stdin:read("*a")
else
local fp = assert(io.open(input, "rb"))
data = assert(fp:read("*a"))
assert(fp:close())
end
return check(load(data, ctx.filename, ctx.mode))
else
if input == "-" then input = nil end
return check(loadfile(input, ctx.mode))
end
end
local function savefile(name, mode)
if name == "-" then return io.stdout end
return check(io.open(name, mode))
end
local function set_stdout_binary(ffi)
ffi.cdef[[int _setmode(int fd, int mode);]]
ffi.C._setmode(1, 0x8000)
end
------------------------------------------------------------------------------
local map_type = {
raw = "raw", c = "c", cc = "c", h = "h", o = "obj", obj = "obj",
}
local map_arch = {
x86 = { e = "le", b = 32, m = 3, p = 0x14c, },
x64 = { e = "le", b = 64, m = 62, p = 0x8664, },
arm = { e = "le", b = 32, m = 40, p = 0x1c0, },
arm64 = { e = "le", b = 64, m = 183, p = 0xaa64, },
arm64be = { e = "be", b = 64, m = 183, },
ppc = { e = "be", b = 32, m = 20, },
mips = { e = "be", b = 32, m = 8, f = 0x50001006, },
mipsel = { e = "le", b = 32, m = 8, f = 0x50001006, },
mips64 = { e = "be", b = 64, m = 8, f = 0x80000007, },
mips64el = { e = "le", b = 64, m = 8, f = 0x80000007, },
mips64r6 = { e = "be", b = 64, m = 8, f = 0xa0000407, },
mips64r6el = { e = "le", b = 64, m = 8, f = 0xa0000407, },
}
local map_os = {
linux = true, windows = true, osx = true, freebsd = true, netbsd = true,
openbsd = true, dragonfly = true, solaris = true,
}
local function checkarg(str, map, err)
str = str:lower()
local s = check(map[str], "unknown ", err)
return type(s) == "string" and s or str
end
local function detecttype(str)
local ext = str:lower():match("%.(%a+)$")
return map_type[ext] or "raw"
end
local function checkmodname(str)
check(str:match("^[%w_.%-]+$"), "bad module name")
return str:gsub("[%.%-]", "_")
end
local function detectmodname(str)
if type(str) == "string" then
local tail = str:match("[^/\\]+$")
if tail then str = tail end
local head = str:match("^(.*)%.[^.]*$")
if head then str = head end
str = str:match("^[%w_.%-]+")
else
str = nil
end
check(str, "cannot derive module name, use -n name")
return str:gsub("[%.%-]", "_")
end
------------------------------------------------------------------------------
local function bcsave_tail(fp, output, s)
local ok, err = fp:write(s)
if ok and output ~= "-" then ok, err = fp:close() end
check(ok, "cannot write ", output, ": ", err)
end
local function bcsave_raw(output, s)
if output == "-" and jit.os == "Windows" then
local ok, ffi = pcall(require, "ffi")
check(ok, "FFI library required to write binary file to stdout")
set_stdout_binary(ffi)
end
local fp = savefile(output, "wb")
bcsave_tail(fp, output, s)
end
local function bcsave_c(ctx, output, s)
local fp = savefile(output, "w")
if ctx.type == "c" then
fp:write(format([[
#ifdef __cplusplus
extern "C"
#endif
#ifdef _WIN32
__declspec(dllexport)
#endif
const unsigned char %s%s[] = {
]], LJBC_PREFIX, ctx.modname))
else
fp:write(format([[
#define %s%s_SIZE %d
static const unsigned char %s%s[] = {
]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname))
end
local t, n, m = {}, 0, 0
for i=1,#s do
local b = tostring(string.byte(s, i))
m = m + #b + 1
if m > 78 then
fp:write(tconcat(t, ",", 1, n), ",\n")
n, m = 0, #b + 1
end
n = n + 1
t[n] = b
end
bcsave_tail(fp, output, tconcat(t, ",", 1, n).."\n};\n")
end
local function bcsave_elfobj(ctx, output, s, ffi)
ffi.cdef[[
typedef struct {
uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
uint16_t type, machine;
uint32_t version;
uint32_t entry, phofs, shofs;
uint32_t flags;
uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
} ELF32header;
typedef struct {
uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
uint16_t type, machine;
uint32_t version;
uint64_t entry, phofs, shofs;
uint32_t flags;
uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
} ELF64header;
typedef struct {
uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize;
} ELF32sectheader;
typedef struct {
uint32_t name, type;
uint64_t flags, addr, ofs, size;
uint32_t link, info;
uint64_t align, entsize;
} ELF64sectheader;
typedef struct {
uint32_t name, value, size;
uint8_t info, other;
uint16_t sectidx;
} ELF32symbol;
typedef struct {
uint32_t name;
uint8_t info, other;
uint16_t sectidx;
uint64_t value, size;
} ELF64symbol;
typedef struct {
ELF32header hdr;
ELF32sectheader sect[6];
ELF32symbol sym[2];
uint8_t space[4096];
} ELF32obj;
typedef struct {
ELF64header hdr;
ELF64sectheader sect[6];
ELF64symbol sym[2];
uint8_t space[4096];
} ELF64obj;
]]
local symname = LJBC_PREFIX..ctx.modname
local ai = assert(map_arch[ctx.arch])
local is64, isbe = ai.b == 64, ai.e == "be"
-- Handle different host/target endianess.
local function f32(x) return x end
local f16, fofs = f32, f32
if ffi.abi("be") ~= isbe then
f32 = bit.bswap
function f16(x) return bit.rshift(bit.bswap(x), 16) end
if is64 then
local two32 = ffi.cast("int64_t", 2^32)
function fofs(x) return bit.bswap(x)*two32 end
else
fofs = f32
end
end
-- Create ELF object and fill in header.
local o = ffi.new(is64 and "ELF64obj" or "ELF32obj")
local hdr = o.hdr
if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi.
local bf = assert(io.open("/bin/ls", "rb"))
local bs = bf:read(9)
bf:close()
ffi.copy(o, bs, 9)
check(hdr.emagic[0] == 127, "no support for writing native object files")
else
hdr.emagic = "\127ELF"
hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0
end
hdr.eclass = is64 and 2 or 1
hdr.eendian = isbe and 2 or 1
hdr.eversion = 1
hdr.type = f16(1)
hdr.machine = f16(ai.m)
hdr.flags = f32(ai.f or 0)
hdr.version = f32(1)
hdr.shofs = fofs(ffi.offsetof(o, "sect"))
hdr.ehsize = f16(ffi.sizeof(hdr))
hdr.shentsize = f16(ffi.sizeof(o.sect[0]))
hdr.shnum = f16(6)
hdr.shstridx = f16(2)
-- Fill in sections and symbols.
local sofs, ofs = ffi.offsetof(o, "space"), 1
for i,name in ipairs{
".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack",
} do
local sect = o.sect[i]
sect.align = fofs(1)
sect.name = f32(ofs)
ffi.copy(o.space+ofs, name)
ofs = ofs + #name+1
end
o.sect[1].type = f32(2) -- .symtab
o.sect[1].link = f32(3)
o.sect[1].info = f32(1)
o.sect[1].align = fofs(8)
o.sect[1].ofs = fofs(ffi.offsetof(o, "sym"))
o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0]))
o.sect[1].size = fofs(ffi.sizeof(o.sym))
o.sym[1].name = f32(1)
o.sym[1].sectidx = f16(4)
o.sym[1].size = fofs(#s)
o.sym[1].info = 17
o.sect[2].type = f32(3) -- .shstrtab
o.sect[2].ofs = fofs(sofs)
o.sect[2].size = fofs(ofs)
o.sect[3].type = f32(3) -- .strtab
o.sect[3].ofs = fofs(sofs + ofs)
o.sect[3].size = fofs(#symname+2)
ffi.copy(o.space+ofs+1, symname)
ofs = ofs + #symname + 2
o.sect[4].type = f32(1) -- .rodata
o.sect[4].flags = fofs(2)
o.sect[4].ofs = fofs(sofs + ofs)
o.sect[4].size = fofs(#s)
o.sect[5].type = f32(1) -- .note.GNU-stack
o.sect[5].ofs = fofs(sofs + ofs + #s)
-- Write ELF object file.
local fp = savefile(output, "wb")
fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
bcsave_tail(fp, output, s)
end
local function bcsave_peobj(ctx, output, s, ffi)
ffi.cdef[[
typedef struct {
uint16_t arch, nsects;
uint32_t time, symtabofs, nsyms;
uint16_t opthdrsz, flags;
} PEheader;
typedef struct {
char name[8];
uint32_t vsize, vaddr, size, ofs, relocofs, lineofs;
uint16_t nreloc, nline;
uint32_t flags;
} PEsection;
typedef struct __attribute((packed)) {
union {
char name[8];
uint32_t nameref[2];
};
uint32_t value;
int16_t sect;
uint16_t type;
uint8_t scl, naux;
} PEsym;
typedef struct __attribute((packed)) {
uint32_t size;
uint16_t nreloc, nline;
uint32_t cksum;
uint16_t assoc;
uint8_t comdatsel, unused[3];
} PEsymaux;
typedef struct {
PEheader hdr;
PEsection sect[2];
// Must be an even number of symbol structs.
PEsym sym0;
PEsymaux sym0aux;
PEsym sym1;
PEsymaux sym1aux;
PEsym sym2;
PEsym sym3;
uint32_t strtabsize;
uint8_t space[4096];
} PEobj;
]]
local symname = LJBC_PREFIX..ctx.modname
local ai = assert(map_arch[ctx.arch])
local is64 = ai.b == 64
local symexport = " /EXPORT:"..symname..",DATA "
-- The file format is always little-endian. Swap if the host is big-endian.
local function f32(x) return x end
local f16 = f32
if ffi.abi("be") then
f32 = bit.bswap
function f16(x) return bit.rshift(bit.bswap(x), 16) end
end
-- Create PE object and fill in header.
local o = ffi.new("PEobj")
local hdr = o.hdr
hdr.arch = f16(assert(ai.p))
hdr.nsects = f16(2)
hdr.symtabofs = f32(ffi.offsetof(o, "sym0"))
hdr.nsyms = f32(6)
-- Fill in sections and symbols.
o.sect[0].name = ".drectve"
o.sect[0].size = f32(#symexport)
o.sect[0].flags = f32(0x00100a00)
o.sym0.sect = f16(1)
o.sym0.scl = 3
o.sym0.name = ".drectve"
o.sym0.naux = 1
o.sym0aux.size = f32(#symexport)
o.sect[1].name = ".rdata"
o.sect[1].size = f32(#s)
o.sect[1].flags = f32(0x40300040)
o.sym1.sect = f16(2)
o.sym1.scl = 3
o.sym1.name = ".rdata"
o.sym1.naux = 1
o.sym1aux.size = f32(#s)
o.sym2.sect = f16(2)
o.sym2.scl = 2
o.sym2.nameref[1] = f32(4)
o.sym3.sect = f16(-1)
o.sym3.scl = 2
o.sym3.value = f32(1)
o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant.
ffi.copy(o.space, symname)
local ofs = #symname + 1
o.strtabsize = f32(ofs + 4)
o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs)
ffi.copy(o.space + ofs, symexport)
ofs = ofs + #symexport
o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs)
-- Write PE object file.
local fp = savefile(output, "wb")
fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs))
bcsave_tail(fp, output, s)
end
local function bcsave_machobj(ctx, output, s, ffi)
ffi.cdef[[
typedef struct
{
uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags;
} mach_header;
typedef struct
{
mach_header; uint32_t reserved;
} mach_header_64;
typedef struct {
uint32_t cmd, cmdsize;
char segname[16];
uint64_t vmaddr, vmsize, fileoff, filesize;
uint32_t maxprot, initprot, nsects, flags;
} mach_segment_command_64;
typedef struct {
char sectname[16], segname[16];
uint64_t addr, size;
uint32_t offset, align, reloff, nreloc, flags;
uint32_t reserved1, reserved2, reserved3;
} mach_section_64;
typedef struct {
uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize;
} mach_symtab_command;
typedef struct {
int32_t strx;
uint8_t type, sect;
uint16_t desc;
uint64_t value;
} mach_nlist_64;
typedef struct {
mach_header_64 hdr;
mach_segment_command_64 seg;
mach_section_64 sec;
mach_symtab_command sym;
mach_nlist_64 sym_entry;
uint8_t space[4096];
} mach_obj_64;
]]
local symname = '_'..LJBC_PREFIX..ctx.modname
local cputype, cpusubtype = 0x01000007, 3
if ctx.arch ~= "x64" then
check(ctx.arch == "arm64", "unsupported architecture for OSX")
cputype, cpusubtype = 0x0100000c, 0
end
local function aligned(v, a) return bit.band(v+a-1, -a) end
-- Create Mach-O object and fill in header.
local o = ffi.new("mach_obj_64")
local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, 8)
-- Fill in sections and symbols.
o.hdr.magic = 0xfeedfacf
o.hdr.cputype = cputype
o.hdr.cpusubtype = cpusubtype
o.hdr.filetype = 1
o.hdr.ncmds = 2
o.hdr.sizeofcmds = ffi.sizeof(o.seg)+ffi.sizeof(o.sec)+ffi.sizeof(o.sym)
o.seg.cmd = 0x19
o.seg.cmdsize = ffi.sizeof(o.seg)+ffi.sizeof(o.sec)
o.seg.vmsize = #s
o.seg.fileoff = mach_size
o.seg.filesize = #s
o.seg.maxprot = 1
o.seg.initprot = 1
o.seg.nsects = 1
ffi.copy(o.sec.sectname, "__data")
ffi.copy(o.sec.segname, "__DATA")
o.sec.size = #s
o.sec.offset = mach_size
o.sym.cmd = 2
o.sym.cmdsize = ffi.sizeof(o.sym)
o.sym.symoff = ffi.offsetof(o, "sym_entry")
o.sym.nsyms = 1
o.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)
o.sym.strsize = aligned(#symname+2, 8)
o.sym_entry.type = 0xf
o.sym_entry.sect = 1
o.sym_entry.strx = 1
ffi.copy(o.space+1, symname)
-- Write Mach-O object file.
local fp = savefile(output, "wb")
fp:write(ffi.string(o, mach_size))
bcsave_tail(fp, output, s)
end
local function bcsave_obj(ctx, output, s)
local ok, ffi = pcall(require, "ffi")
check(ok, "FFI library required to write this file type")
if output == "-" and jit.os == "Windows" then
set_stdout_binary(ffi)
end
if ctx.os == "windows" then
return bcsave_peobj(ctx, output, s, ffi)
elseif ctx.os == "osx" then
return bcsave_machobj(ctx, output, s, ffi)
else
return bcsave_elfobj(ctx, output, s, ffi)
end
end
------------------------------------------------------------------------------
local function bclist(ctx, input, output)
local f = readfile(ctx, input)
require("jit.bc").dump(f, savefile(output, "w"), true)
end
local function bcsave(ctx, input, output)
local f = readfile(ctx, input)
local s = string.dump(f, ctx.mode)
local t = ctx.type
if not t then
t = detecttype(output)
ctx.type = t
end
if t == "raw" then
bcsave_raw(output, s)
else
if not ctx.modname then ctx.modname = detectmodname(input) end
if t == "obj" then
bcsave_obj(ctx, output, s)
else
bcsave_c(ctx, output, s)
end
end
end
local function docmd(...)
local arg = {...}
local n = 1
local list = false
local ctx = {
mode = "bt", arch = jit.arch, os = jit.os:lower(),
type = false, modname = false, string = false,
}
local strip = "s"
local gc64 = ""
while n <= #arg do
local a = arg[n]
if type(a) == "string" and a:sub(1, 1) == "-" and a ~= "-" then
tremove(arg, n)
if a == "--" then break end
for m=2,#a do
local opt = a:sub(m, m)
if opt == "l" then
list = true
elseif opt == "s" then
strip = "s"
elseif opt == "g" then
strip = ""
elseif opt == "W" or opt == "X" then
gc64 = opt
elseif opt == "d" then
ctx.mode = ctx.mode .. opt
else
if arg[n] == nil or m ~= #a then usage() end
if opt == "e" then
if n ~= 1 then usage() end
ctx.string = true
elseif opt == "n" then
ctx.modname = checkmodname(tremove(arg, n))
elseif opt == "t" then
ctx.type = checkarg(tremove(arg, n), map_type, "file type")
elseif opt == "a" then
ctx.arch = checkarg(tremove(arg, n), map_arch, "architecture")
elseif opt == "o" then
ctx.os = checkarg(tremove(arg, n), map_os, "OS name")
elseif opt == "F" then
ctx.filename = "@"..tremove(arg, n)
else
usage()
end
end
end
else
n = n + 1
end
end
ctx.mode = ctx.mode .. strip .. gc64
if list then
if #arg == 0 or #arg > 2 then usage() end
bclist(ctx, arg[1], arg[2] or "-")
else
if #arg ~= 2 then usage() end
bcsave(ctx, arg[1], arg[2])
end
end
------------------------------------------------------------------------------
-- Public module functions.
return {
start = docmd -- Process -b command line option.
}
+689
View File
@@ -0,0 +1,689 @@
----------------------------------------------------------------------------
-- LuaJIT ARM disassembler module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This is a helper module used by the LuaJIT machine code dumper module.
--
-- It disassembles most user-mode ARMv7 instructions
-- NYI: Advanced SIMD and VFP instructions.
------------------------------------------------------------------------------
local type = type
local sub, byte, format = string.sub, string.byte, string.format
local match, gmatch = string.match, string.gmatch
local concat = table.concat
local bit = require("bit")
local band, bor, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
------------------------------------------------------------------------------
-- Opcode maps
------------------------------------------------------------------------------
local map_loadc = {
shift = 8, mask = 15,
[10] = {
shift = 20, mask = 1,
[0] = {
shift = 23, mask = 3,
[0] = "vmovFmDN", "vstmFNdr",
_ = {
shift = 21, mask = 1,
[0] = "vstrFdl",
{ shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", }
},
},
{
shift = 23, mask = 3,
[0] = "vmovFDNm",
{ shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", },
_ = {
shift = 21, mask = 1,
[0] = "vldrFdl", "vldmdbFNdr",
},
},
},
[11] = {
shift = 20, mask = 1,
[0] = {
shift = 23, mask = 3,
[0] = "vmovGmDN", "vstmGNdr",
_ = {
shift = 21, mask = 1,
[0] = "vstrGdl",
{ shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", }
},
},
{
shift = 23, mask = 3,
[0] = "vmovGDNm",
{ shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", },
_ = {
shift = 21, mask = 1,
[0] = "vldrGdl", "vldmdbGNdr",
},
},
},
_ = {
shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc.
},
}
local map_vfps = {
shift = 6, mask = 0x2c001,
[0] = "vmlaF.dnm", "vmlsF.dnm",
[0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm",
[0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm",
[0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm",
[0x20000] = "vdivF.dnm",
[0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm",
[0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm",
[0x2c000] = "vmovF.dY",
[0x2c001] = {
shift = 7, mask = 0x1e01,
[0] = "vmovF.dm", "vabsF.dm",
[0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm",
[0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm",
[0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d",
[0x0e01] = "vcvtG.dF.m",
[0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm",
[0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm",
[0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm",
},
}
local map_vfpd = {
shift = 6, mask = 0x2c001,
[0] = "vmlaG.dnm", "vmlsG.dnm",
[0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm",
[0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm",
[0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm",
[0x20000] = "vdivG.dnm",
[0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm",
[0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm",
[0x2c000] = "vmovG.dY",
[0x2c001] = {
shift = 7, mask = 0x1e01,
[0] = "vmovG.dm", "vabsG.dm",
[0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm",
[0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm",
[0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d",
[0x0e01] = "vcvtF.dG.m",
[0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm",
[0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m",
[0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m",
},
}
local map_datac = {
shift = 24, mask = 1,
[0] = {
shift = 4, mask = 1,
[0] = {
shift = 8, mask = 15,
[10] = map_vfps,
[11] = map_vfpd,
-- NYI cdp, mcr, mrc.
},
{
shift = 8, mask = 15,
[10] = {
shift = 20, mask = 15,
[0] = "vmovFnD", "vmovFDn",
[14] = "vmsrD",
[15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", },
},
},
},
"svcT",
}
local map_loadcu = {
shift = 0, mask = 0, -- NYI unconditional CP load/store.
}
local map_datacu = {
shift = 0, mask = 0, -- NYI unconditional CP data.
}
local map_simddata = {
shift = 0, mask = 0, -- NYI SIMD data.
}
local map_simdload = {
shift = 0, mask = 0, -- NYI SIMD load/store, preload.
}
local map_preload = {
shift = 0, mask = 0, -- NYI preload.
}
local map_media = {
shift = 20, mask = 31,
[0] = false,
{ --01
shift = 5, mask = 7,
[0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM",
"sadd8DNM", false, false, "ssub8DNM",
},
{ --02
shift = 5, mask = 7,
[0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM",
"qadd8DNM", false, false, "qsub8DNM",
},
{ --03
shift = 5, mask = 7,
[0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM",
"shadd8DNM", false, false, "shsub8DNM",
},
false,
{ --05
shift = 5, mask = 7,
[0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM",
"uadd8DNM", false, false, "usub8DNM",
},
{ --06
shift = 5, mask = 7,
[0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM",
"uqadd8DNM", false, false, "uqsub8DNM",
},
{ --07
shift = 5, mask = 7,
[0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM",
"uhadd8DNM", false, false, "uhsub8DNM",
},
{ --08
shift = 5, mask = 7,
[0] = "pkhbtDNMU", false, "pkhtbDNMU",
{ shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", },
"pkhbtDNMU", "selDNM", "pkhtbDNMU",
},
false,
{ --0a
shift = 5, mask = 7,
[0] = "ssatDxMu", "ssat16DxM", "ssatDxMu",
{ shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", },
"ssatDxMu", false, "ssatDxMu",
},
{ --0b
shift = 5, mask = 7,
[0] = "ssatDxMu", "revDM", "ssatDxMu",
{ shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", },
"ssatDxMu", "rev16DM", "ssatDxMu",
},
{ --0c
shift = 5, mask = 7,
[3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", },
},
false,
{ --0e
shift = 5, mask = 7,
[0] = "usatDwMu", "usat16DwM", "usatDwMu",
{ shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", },
"usatDwMu", false, "usatDwMu",
},
{ --0f
shift = 5, mask = 7,
[0] = "usatDwMu", "rbitDM", "usatDwMu",
{ shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", },
"usatDwMu", "revshDM", "usatDwMu",
},
{ --10
shift = 12, mask = 15,
[15] = {
shift = 5, mask = 7,
"smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS",
},
_ = {
shift = 5, mask = 7,
[0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD",
},
},
false, false, false,
{ --14
shift = 5, mask = 7,
[0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS",
},
{ --15
shift = 5, mask = 7,
[0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", },
{ shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", },
false, false, false, false,
"smmlsNMSD", "smmlsrNMSD",
},
false, false,
{ --18
shift = 5, mask = 7,
[0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", },
},
false,
{ --1a
shift = 5, mask = 3, [2] = "sbfxDMvw",
},
{ --1b
shift = 5, mask = 3, [2] = "sbfxDMvw",
},
{ --1c
shift = 5, mask = 3,
[0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
},
{ --1d
shift = 5, mask = 3,
[0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", },
},
{ --1e
shift = 5, mask = 3, [2] = "ubfxDMvw",
},
{ --1f
shift = 5, mask = 3, [2] = "ubfxDMvw",
},
}
local map_load = {
shift = 21, mask = 9,
{
shift = 20, mask = 5,
[0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL",
},
_ = {
shift = 20, mask = 5,
[0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL",
}
}
local map_load1 = {
shift = 4, mask = 1,
[0] = map_load, map_media,
}
local map_loadm = {
shift = 20, mask = 1,
[0] = {
shift = 23, mask = 3,
[0] = "stmdaNR", "stmNR",
{ shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR",
},
{
shift = 23, mask = 3,
[0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", },
"ldmdbNR", "ldmibNR",
},
}
local map_data = {
shift = 21, mask = 15,
[0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs",
"addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs",
"tstNP", "teqNP", "cmpNP", "cmnNP",
"orrDNPs", "movDPs", "bicDNPs", "mvnDPs",
}
local map_mul = {
shift = 21, mask = 7,
[0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS",
"umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs",
}
local map_sync = {
shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd.
[0] = "swpDMN", false, false, false,
"swpbDMN", false, false, false,
"strexDMN", "ldrexDN", "strexdDN", "ldrexdDN",
"strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN",
}
local map_mulh = {
shift = 21, mask = 3,
[0] = { shift = 5, mask = 3,
[0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", },
{ shift = 5, mask = 3,
[0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", },
{ shift = 5, mask = 3,
[0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", },
{ shift = 5, mask = 3,
[0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", },
}
local map_misc = {
shift = 4, mask = 7,
-- NYI: decode PSR bits of msr.
[0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", },
{ shift = 21, mask = 3, "bxM", false, "clzDM", },
{ shift = 21, mask = 3, "bxjM", },
{ shift = 21, mask = 3, "blxM", },
false,
{ shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", },
false,
{ shift = 21, mask = 3, "bkptK", },
}
local map_datar = {
shift = 4, mask = 9,
[9] = {
shift = 5, mask = 3,
[0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, },
{ shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", },
{ shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", },
{ shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", },
},
_ = {
shift = 20, mask = 25,
[16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, },
_ = {
shift = 0, mask = 0xffffffff,
[bor(0xe1a00000)] = "nop",
_ = map_data,
}
},
}
local map_datai = {
shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12.
[16] = "movwDW", [20] = "movtDW",
[18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", },
[22] = "msrNW",
_ = map_data,
}
local map_branch = {
shift = 24, mask = 1,
[0] = "bB", "blB"
}
local map_condins = {
[0] = map_datar, map_datai, map_load, map_load1,
map_loadm, map_branch, map_loadc, map_datac
}
-- NYI: setend.
local map_uncondins = {
[0] = false, map_simddata, map_simdload, map_preload,
false, "blxB", map_loadcu, map_datacu,
}
------------------------------------------------------------------------------
local map_gpr = {
[0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
}
local map_cond = {
[0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt", "gt", "le", "al",
}
local map_shift = { [0] = "lsl", "lsr", "asr", "ror", }
------------------------------------------------------------------------------
-- Output a nicely formatted line with an opcode and operands.
local function putop(ctx, text, operands)
local pos = ctx.pos
local extra = ""
if ctx.rel then
local sym = ctx.symtab[ctx.rel]
if sym then
extra = "\t->"..sym
elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then
extra = "\t; 0x"..tohex(ctx.rel)
end
end
if ctx.hexdump > 0 then
ctx.out(format("%08x %s %-5s %s%s\n",
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
else
ctx.out(format("%08x %-5s %s%s\n",
ctx.addr+pos, text, concat(operands, ", "), extra))
end
ctx.pos = pos + 4
end
-- Fallback for unknown opcodes.
local function unknown(ctx)
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
end
-- Format operand 2 of load/store opcodes.
local function fmtload(ctx, op, pos)
local base = map_gpr[band(rshift(op, 16), 15)]
local x, ofs
local ext = (band(op, 0x04000000) == 0)
if not ext and band(op, 0x02000000) == 0 then
ofs = band(op, 4095)
if band(op, 0x00800000) == 0 then ofs = -ofs end
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
ofs = "#"..ofs
elseif ext and band(op, 0x00400000) ~= 0 then
ofs = band(op, 15) + band(rshift(op, 4), 0xf0)
if band(op, 0x00800000) == 0 then ofs = -ofs end
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
ofs = "#"..ofs
else
ofs = map_gpr[band(op, 15)]
if ext or band(op, 0xfe0) == 0 then
elseif band(op, 0xfe0) == 0x60 then
ofs = format("%s, rrx", ofs)
else
local sh = band(rshift(op, 7), 31)
if sh == 0 then sh = 32 end
ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh)
end
if band(op, 0x00800000) == 0 then ofs = "-"..ofs end
end
if ofs == "#0" then
x = format("[%s]", base)
elseif band(op, 0x01000000) == 0 then
x = format("[%s], %s", base, ofs)
else
x = format("[%s, %s]", base, ofs)
end
if band(op, 0x01200000) == 0x01200000 then x = x.."!" end
return x
end
-- Format operand 2 of vector load/store opcodes.
local function fmtvload(ctx, op, pos)
local base = map_gpr[band(rshift(op, 16), 15)]
local ofs = band(op, 255)*4
if band(op, 0x00800000) == 0 then ofs = -ofs end
if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end
if ofs == 0 then
return format("[%s]", base)
else
return format("[%s, #%d]", base, ofs)
end
end
local function fmtvr(op, vr, sh0, sh1)
if vr == "s" then
return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1))
else
return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16))
end
end
-- Disassemble a single instruction.
local function disass_ins(ctx)
local pos = ctx.pos
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
local operands = {}
local suffix = ""
local last, name, pat
local vr
ctx.op = op
ctx.rel = nil
local cond = rshift(op, 28)
local opat
if cond == 15 then
opat = map_uncondins[band(rshift(op, 25), 7)]
else
if cond ~= 14 then suffix = map_cond[cond] end
opat = map_condins[band(rshift(op, 25), 7)]
end
while type(opat) ~= "string" do
if not opat then return unknown(ctx) end
opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
end
name, pat = match(opat, "^([a-z0-9]*)(.*)")
if sub(pat, 1, 1) == "." then
local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)")
suffix = suffix..s2
pat = p2
end
for p in gmatch(pat, ".") do
local x = nil
if p == "D" then
x = map_gpr[band(rshift(op, 12), 15)]
elseif p == "N" then
x = map_gpr[band(rshift(op, 16), 15)]
elseif p == "S" then
x = map_gpr[band(rshift(op, 8), 15)]
elseif p == "M" then
x = map_gpr[band(op, 15)]
elseif p == "d" then
x = fmtvr(op, vr, 12, 22)
elseif p == "n" then
x = fmtvr(op, vr, 16, 7)
elseif p == "m" then
x = fmtvr(op, vr, 0, 5)
elseif p == "P" then
if band(op, 0x02000000) ~= 0 then
x = ror(band(op, 255), 2*band(rshift(op, 8), 15))
else
x = map_gpr[band(op, 15)]
if band(op, 0xff0) ~= 0 then
operands[#operands+1] = x
local s = map_shift[band(rshift(op, 5), 3)]
local r = nil
if band(op, 0xf90) == 0 then
if s == "ror" then s = "rrx" else r = "#32" end
elseif band(op, 0x10) == 0 then
r = "#"..band(rshift(op, 7), 31)
else
r = map_gpr[band(rshift(op, 8), 15)]
end
if name == "mov" then name = s; x = r
elseif r then x = format("%s %s", s, r)
else x = s end
end
end
elseif p == "L" then
x = fmtload(ctx, op, pos)
elseif p == "l" then
x = fmtvload(ctx, op, pos)
elseif p == "B" then
local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6)
if cond == 15 then addr = addr + band(rshift(op, 23), 2) end
ctx.rel = addr
x = "0x"..tohex(addr)
elseif p == "F" then
vr = "s"
elseif p == "G" then
vr = "d"
elseif p == "." then
suffix = suffix..(vr == "s" and ".f32" or ".f64")
elseif p == "R" then
if band(op, 0x00200000) ~= 0 and #operands == 1 then
operands[1] = operands[1].."!"
end
local t = {}
for i=0,15 do
if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end
end
x = "{"..concat(t, ", ").."}"
elseif p == "r" then
if band(op, 0x00200000) ~= 0 and #operands == 2 then
operands[1] = operands[1].."!"
end
local s = tonumber(sub(last, 2))
local n = band(op, 255)
if vr == "d" then n = rshift(n, 1) end
operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1)
elseif p == "W" then
x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000)
elseif p == "T" then
x = "#0x"..tohex(band(op, 0x00ffffff), 6)
elseif p == "U" then
x = band(rshift(op, 7), 31)
if x == 0 then x = nil end
elseif p == "u" then
x = band(rshift(op, 7), 31)
if band(op, 0x40) == 0 then
if x == 0 then x = nil else x = "lsl #"..x end
else
if x == 0 then x = "asr #32" else x = "asr #"..x end
end
elseif p == "v" then
x = band(rshift(op, 7), 31)
elseif p == "w" then
x = band(rshift(op, 16), 31)
elseif p == "x" then
x = band(rshift(op, 16), 31) + 1
elseif p == "X" then
x = band(rshift(op, 16), 31) - last + 1
elseif p == "Y" then
x = band(rshift(op, 12), 0xf0) + band(op, 0x0f)
elseif p == "K" then
x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4)
elseif p == "s" then
if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end
else
assert(false)
end
if x then
last = x
if type(x) == "number" then x = "#"..x end
operands[#operands+1] = x
end
end
return putop(ctx, name..suffix, operands)
end
------------------------------------------------------------------------------
-- Disassemble a block of code.
local function disass_block(ctx, ofs, len)
if not ofs then ofs = 0 end
local stop = len and ofs+len or #ctx.code
ctx.pos = ofs
ctx.rel = nil
while ctx.pos < stop do disass_ins(ctx) end
end
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
local function create(code, addr, out)
local ctx = {}
ctx.code = code
ctx.addr = addr or 0
ctx.out = out or io.write
ctx.symtab = {}
ctx.disass = disass_block
ctx.hexdump = 8
return ctx
end
-- Simple API: disassemble code (a string) at address and output via out.
local function disass(code, addr, out)
create(code, addr, out):disass()
end
-- Return register name for RID.
local function regname(r)
if r < 16 then return map_gpr[r] end
return "d"..(r-16)
end
-- Public module functions.
return {
create = create,
disass = disass,
regname = regname
}
File diff suppressed because it is too large. Load diff
+12
View File
@@ -0,0 +1,12 @@
----------------------------------------------------------------------------
-- LuaJIT ARM64BE disassembler wrapper module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- ARM64 instructions are always little-endian. So just forward to the
-- common ARM64 disassembler module. All the interesting stuff is there.
------------------------------------------------------------------------------
return require((string.match(..., ".*%.") or "").."dis_arm64")
+694
View File
@@ -0,0 +1,694 @@
----------------------------------------------------------------------------
-- LuaJIT MIPS disassembler module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT/X license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This is a helper module used by the LuaJIT machine code dumper module.
--
-- It disassembles all standard MIPS32R1/R2 instructions.
-- Default mode is big-endian, but see: dis_mipsel.lua
------------------------------------------------------------------------------
local type = type
local byte, format = string.byte, string.format
local match, gmatch = string.match, string.gmatch
local concat = table.concat
local bit = require("bit")
local band, bor, tohex = bit.band, bit.bor, bit.tohex
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
------------------------------------------------------------------------------
-- Extended opcode maps common to all MIPS releases
------------------------------------------------------------------------------
local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", }
local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", }
local map_cop0 = {
shift = 25, mask = 1,
[0] = {
shift = 21, mask = 15,
[0] = "mfc0TDW", [4] = "mtc0TDW",
[10] = "rdpgprDT",
[11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", },
[14] = "wrpgprDT",
}, {
shift = 0, mask = 63,
[1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp",
[24] = "eret", [31] = "deret",
[32] = "wait",
},
}
------------------------------------------------------------------------------
-- Primary and extended opcode maps for MIPS R1-R5
------------------------------------------------------------------------------
local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", }
local map_special = {
shift = 0, mask = 63,
[0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
map_movci, map_srl, "sraDTA",
"sllvDTS", false, map_srlv, "sravDTS",
"jrS", "jalrD1S", "movzDST", "movnDST",
"syscallY", "breakY", false, "sync",
"mfhiD", "mthiS", "mfloD", "mtloS",
"dsllvDST", false, "dsrlvDST", "dsravDST",
"multST", "multuST", "divST", "divuST",
"dmultST", "dmultuST", "ddivST", "ddivuST",
"addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
"andDST", "or|moveDST0", "xorDST", "nor|notDST0",
false, false, "sltDST", "sltuDST",
"daddDST", "dadduDST", "dsubDST", "dsubuDST",
"tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
"teqSTZ", false, "tneSTZ", false,
"dsllDTA", false, "dsrlDTA", "dsraDTA",
"dsll32DTA", false, "dsrl32DTA", "dsra32DTA",
}
local map_special2 = {
shift = 0, mask = 63,
[0] = "maddST", "madduST", "mulDST", false,
"msubST", "msubuST",
[32] = "clzDS", [33] = "cloDS",
[63] = "sdbbpY",
}
local map_bshfl = {
shift = 6, mask = 31,
[2] = "wsbhDT",
[16] = "sebDT",
[24] = "sehDT",
}
local map_dbshfl = {
shift = 6, mask = 31,
[2] = "dsbhDT",
[5] = "dshdDT",
}
local map_special3 = {
shift = 0, mask = 63,
[0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
[4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
[32] = map_bshfl, [36] = map_dbshfl, [59] = "rdhwrTD",
}
local map_regimm = {
shift = 16, mask = 31,
[0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB",
false, false, false, false,
"tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI",
"teqiSI", false, "tneiSI", false,
"bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB",
false, false, false, false,
false, false, false, false,
false, false, false, "synciSO",
}
local map_cop1s = {
shift = 0, mask = 63,
[0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
"sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
"round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
"round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
false,
{ shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" },
"movz.sFGT", "movn.sFGT",
false, "recip.sFG", "rsqrt.sFG", false,
false, false, false, false,
false, false, false, false,
false, "cvt.d.sFG", false, false,
"cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false,
false, false, false, false,
false, false, false, false,
"c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH",
"c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH",
"c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH",
"c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH",
}
local map_cop1d = {
shift = 0, mask = 63,
[0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
"sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
"round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
"round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
false,
{ shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" },
"movz.dFGT", "movn.dFGT",
false, "recip.dFG", "rsqrt.dFG", false,
false, false, false, false,
false, false, false, false,
"cvt.s.dFG", false, false, false,
"cvt.w.dFG", "cvt.l.dFG", false, false,
false, false, false, false,
false, false, false, false,
"c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH",
"c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH",
"c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH",
"c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH",
}
local map_cop1ps = {
shift = 0, mask = 63,
[0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false,
false, "abs.psFG", "mov.psFG", "neg.psFG",
false, false, false, false,
false, false, false, false,
false,
{ shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" },
"movz.psFGT", "movn.psFGT",
false, false, false, false,
false, false, false, false,
false, false, false, false,
"cvt.s.puFG", false, false, false,
false, false, false, false,
"cvt.s.plFG", false, false, false,
"pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH",
"c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH",
"c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH",
"c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH",
"c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH",
}
local map_cop1w = {
shift = 0, mask = 63,
[32] = "cvt.s.wFG", [33] = "cvt.d.wFG",
}
local map_cop1l = {
shift = 0, mask = 63,
[32] = "cvt.s.lFG", [33] = "cvt.d.lFG",
}
local map_cop1bc = {
shift = 16, mask = 3,
[0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB",
}
local map_cop1 = {
shift = 21, mask = 31,
[0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG",
"mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG",
map_cop1bc, false, false, false,
false, false, false, false,
map_cop1s, map_cop1d, false, false,
map_cop1w, map_cop1l, map_cop1ps,
}
local map_cop1x = {
shift = 0, mask = 63,
[0] = "lwxc1FSX", "ldxc1FSX", false, false,
false, "luxc1FSX", false, false,
"swxc1FSX", "sdxc1FSX", false, false,
false, "suxc1FSX", false, "prefxMSX",
false, false, false, false,
false, false, false, false,
false, false, false, false,
false, false, "alnv.psFGHS", false,
"madd.sFRGH", "madd.dFRGH", false, false,
false, false, "madd.psFRGH", false,
"msub.sFRGH", "msub.dFRGH", false, false,
false, false, "msub.psFRGH", false,
"nmadd.sFRGH", "nmadd.dFRGH", false, false,
false, false, "nmadd.psFRGH", false,
"nmsub.sFRGH", "nmsub.dFRGH", false, false,
false, false, "nmsub.psFRGH", false,
}
local map_pri = {
[0] = map_special, map_regimm, "jJ", "jalJ",
"beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB",
"addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI",
"andiTSU", "ori|liTS0U", "xoriTSU", "luiTU",
map_cop0, map_cop1, false, map_cop1x,
"beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB",
"daddiTSI", "daddiuTSI", false, false,
map_special2, "jalxJ", false, map_special3,
"lbTSO", "lhTSO", "lwlTSO", "lwTSO",
"lbuTSO", "lhuTSO", "lwrTSO", false,
"sbTSO", "shTSO", "swlTSO", "swTSO",
false, false, "swrTSO", "cacheNSO",
"llTSO", "lwc1HSO", "lwc2TSO", "prefNSO",
false, "ldc1HSO", "ldc2TSO", "ldTSO",
"scTSO", "swc1HSO", "swc2TSO", false,
false, "sdc1HSO", "sdc2TSO", "sdTSO",
}
------------------------------------------------------------------------------
-- Primary and extended opcode maps for MIPS R6
------------------------------------------------------------------------------
local map_mul_r6 = { shift = 6, mask = 3, [2] = "mulDST", [3] = "muhDST" }
local map_mulu_r6 = { shift = 6, mask = 3, [2] = "muluDST", [3] = "muhuDST" }
local map_div_r6 = { shift = 6, mask = 3, [2] = "divDST", [3] = "modDST" }
local map_divu_r6 = { shift = 6, mask = 3, [2] = "divuDST", [3] = "moduDST" }
local map_dmul_r6 = { shift = 6, mask = 3, [2] = "dmulDST", [3] = "dmuhDST" }
local map_dmulu_r6 = { shift = 6, mask = 3, [2] = "dmuluDST", [3] = "dmuhuDST" }
local map_ddiv_r6 = { shift = 6, mask = 3, [2] = "ddivDST", [3] = "dmodDST" }
local map_ddivu_r6 = { shift = 6, mask = 3, [2] = "ddivuDST", [3] = "dmoduDST" }
local map_special_r6 = {
shift = 0, mask = 63,
[0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" },
false, map_srl, "sraDTA",
"sllvDTS", false, map_srlv, "sravDTS",
"jrS", "jalrD1S", false, false,
"syscallY", "breakY", false, "sync",
"clzDS", "cloDS", "dclzDS", "dcloDS",
"dsllvDST", "dlsaDSTA", "dsrlvDST", "dsravDST",
map_mul_r6, map_mulu_r6, map_div_r6, map_divu_r6,
map_dmul_r6, map_dmulu_r6, map_ddiv_r6, map_ddivu_r6,
"addDST", "addu|moveDST0", "subDST", "subu|neguDS0T",
"andDST", "or|moveDST0", "xorDST", "nor|notDST0",
false, false, "sltDST", "sltuDST",
"daddDST", "dadduDST", "dsubDST", "dsubuDST",
"tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ",
"teqSTZ", "seleqzDST", "tneSTZ", "selnezDST",
"dsllDTA", false, "dsrlDTA", "dsraDTA",
"dsll32DTA", false, "dsrl32DTA", "dsra32DTA",
}
local map_bshfl_r6 = {
shift = 9, mask = 3,
[1] = "alignDSTa",
_ = {
shift = 6, mask = 31,
[0] = "bitswapDT",
[2] = "wsbhDT",
[16] = "sebDT",
[24] = "sehDT",
}
}
local map_dbshfl_r6 = {
shift = 9, mask = 3,
[1] = "dalignDSTa",
_ = {
shift = 6, mask = 31,
[0] = "dbitswapDT",
[2] = "dsbhDT",
[5] = "dshdDT",
}
}
local map_special3_r6 = {
shift = 0, mask = 63,
[0] = "extTSAK", [1] = "dextmTSAP", [3] = "dextTSAK",
[4] = "insTSAL", [6] = "dinsuTSEQ", [7] = "dinsTSAL",
[32] = map_bshfl_r6, [36] = map_dbshfl_r6, [59] = "rdhwrTD",
}
local map_regimm_r6 = {
shift = 16, mask = 31,
[0] = "bltzSB", [1] = "bgezSB",
[6] = "dahiSI", [30] = "datiSI",
[23] = "sigrieI", [31] = "synciSO",
}
local map_pcrel_r6 = {
shift = 19, mask = 3,
[0] = "addiupcS2", "lwpcS2", "lwupcS2", {
shift = 18, mask = 1,
[0] = "ldpcS3", { shift = 16, mask = 3, [2] = "auipcSI", [3] = "aluipcSI" }
}
}
local map_cop1s_r6 = {
shift = 0, mask = 63,
[0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH",
"sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG",
"round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG",
"round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG",
"sel.sFGH", false, false, false,
"seleqz.sFGH", "recip.sFG", "rsqrt.sFG", "selnez.sFGH",
"maddf.sFGH", "msubf.sFGH", "rint.sFG", "class.sFG",
"min.sFGH", "mina.sFGH", "max.sFGH", "maxa.sFGH",
false, "cvt.d.sFG", false, false,
"cvt.w.sFG", "cvt.l.sFG",
}
local map_cop1d_r6 = {
shift = 0, mask = 63,
[0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH",
"sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG",
"round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG",
"round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG",
"sel.dFGH", false, false, false,
"seleqz.dFGH", "recip.dFG", "rsqrt.dFG", "selnez.dFGH",
"maddf.dFGH", "msubf.dFGH", "rint.dFG", "class.dFG",
"min.dFGH", "mina.dFGH", "max.dFGH", "maxa.dFGH",
"cvt.s.dFG", false, false, false,
"cvt.w.dFG", "cvt.l.dFG",
}
local map_cop1w_r6 = {
shift = 0, mask = 63,
[0] = "cmp.af.sFGH", "cmp.un.sFGH", "cmp.eq.sFGH", "cmp.ueq.sFGH",
"cmp.lt.sFGH", "cmp.ult.sFGH", "cmp.le.sFGH", "cmp.ule.sFGH",
"cmp.saf.sFGH", "cmp.sun.sFGH", "cmp.seq.sFGH", "cmp.sueq.sFGH",
"cmp.slt.sFGH", "cmp.sult.sFGH", "cmp.sle.sFGH", "cmp.sule.sFGH",
false, "cmp.or.sFGH", "cmp.une.sFGH", "cmp.ne.sFGH",
false, false, false, false,
false, "cmp.sor.sFGH", "cmp.sune.sFGH", "cmp.sne.sFGH",
false, false, false, false,
"cvt.s.wFG", "cvt.d.wFG",
}
local map_cop1l_r6 = {
shift = 0, mask = 63,
[0] = "cmp.af.dFGH", "cmp.un.dFGH", "cmp.eq.dFGH", "cmp.ueq.dFGH",
"cmp.lt.dFGH", "cmp.ult.dFGH", "cmp.le.dFGH", "cmp.ule.dFGH",
"cmp.saf.dFGH", "cmp.sun.dFGH", "cmp.seq.dFGH", "cmp.sueq.dFGH",
"cmp.slt.dFGH", "cmp.sult.dFGH", "cmp.sle.dFGH", "cmp.sule.dFGH",
false, "cmp.or.dFGH", "cmp.une.dFGH", "cmp.ne.dFGH",
false, false, false, false,
false, "cmp.sor.dFGH", "cmp.sune.dFGH", "cmp.sne.dFGH",
false, false, false, false,
"cvt.s.lFG", "cvt.d.lFG",
}
local map_cop1_r6 = {
shift = 21, mask = 31,
[0] = "mfc1TG", "dmfc1TG", "cfc1TG", "mfhc1TG",
"mtc1TG", "dmtc1TG", "ctc1TG", "mthc1TG",
false, "bc1eqzHB", false, false,
false, "bc1nezHB", false, false,
map_cop1s_r6, map_cop1d_r6, false, false,
map_cop1w_r6, map_cop1l_r6,
}
local function maprs_popTS(rs, rt)
if rt == 0 then return 0 elseif rs == 0 then return 1
elseif rs == rt then return 2 else return 3 end
end
local map_pop06_r6 = {
maprs = maprs_popTS, [0] = "blezSB", "blezalcTB", "bgezalcTB", "bgeucSTB"
}
local map_pop07_r6 = {
maprs = maprs_popTS, [0] = "bgtzSB", "bgtzalcTB", "bltzalcTB", "bltucSTB"
}
local map_pop26_r6 = {
maprs = maprs_popTS, "blezcTB", "bgezcTB", "bgecSTB"
}
local map_pop27_r6 = {
maprs = maprs_popTS, "bgtzcTB", "bltzcTB", "bltcSTB"
}
local function maprs_popS(rs, rt)
if rs == 0 then return 0 else return 1 end
end
local map_pop66_r6 = {
maprs = maprs_popS, [0] = "jicTI", "beqzcSb"
}
local map_pop76_r6 = {
maprs = maprs_popS, [0] = "jialcTI", "bnezcSb"
}
local function maprs_popST(rs, rt)
if rs >= rt then return 0 elseif rs == 0 then return 1 else return 2 end
end
local map_pop10_r6 = {
maprs = maprs_popST, [0] = "bovcSTB", "beqzalcTB", "beqcSTB"
}
local map_pop30_r6 = {
maprs = maprs_popST, [0] = "bnvcSTB", "bnezalcTB", "bnecSTB"
}
local map_pri_r6 = {
[0] = map_special_r6, map_regimm_r6, "jJ", "jalJ",
"beq|beqz|bST00B", "bne|bnezST0B", map_pop06_r6, map_pop07_r6,
map_pop10_r6, "addiu|liTS0I", "sltiTSI", "sltiuTSI",
"andiTSU", "ori|liTS0U", "xoriTSU", "aui|luiTS0U",
map_cop0, map_cop1_r6, false, false,
false, false, map_pop26_r6, map_pop27_r6,
map_pop30_r6, "daddiuTSI", false, false,
false, "dauiTSI", false, map_special3_r6,
"lbTSO", "lhTSO", false, "lwTSO",
"lbuTSO", "lhuTSO", false, false,
"sbTSO", "shTSO", false, "swTSO",
false, false, false, false,
false, "lwc1HSO", "bc#", false,
false, "ldc1HSO", map_pop66_r6, "ldTSO",
false, "swc1HSO", "balc#", map_pcrel_r6,
false, "sdc1HSO", map_pop76_r6, "sdTSO",
}
------------------------------------------------------------------------------
local map_gpr = {
[0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra",
}
------------------------------------------------------------------------------
-- Output a nicely formatted line with an opcode and operands.
local function putop(ctx, text, operands)
local pos = ctx.pos
local extra = ""
if ctx.rel then
local sym = ctx.symtab[ctx.rel]
if sym then extra = "\t->"..sym end
end
if ctx.hexdump > 0 then
ctx.out(format("%08x %s %-7s %s%s\n",
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
else
ctx.out(format("%08x %-7s %s%s\n",
ctx.addr+pos, text, concat(operands, ", "), extra))
end
ctx.pos = pos + 4
end
-- Fallback for unknown opcodes.
local function unknown(ctx)
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
end
local function get_be(ctx)
local pos = ctx.pos
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
end
local function get_le(ctx)
local pos = ctx.pos
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
end
-- Disassemble a single instruction.
local function disass_ins(ctx)
local op = ctx:get()
local operands = {}
local last = nil
ctx.op = op
ctx.rel = nil
local opat = ctx.map_pri[rshift(op, 26)]
while type(opat) ~= "string" do
if not opat then return unknown(ctx) end
if opat.maprs then
opat = opat[opat.maprs(band(rshift(op,21),31), band(rshift(op,16),31))]
else
opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
end
end
local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
if altname then pat = pat2 end
for p in gmatch(pat, ".") do
local x = nil
if p == "S" then
x = map_gpr[band(rshift(op, 21), 31)]
elseif p == "T" then
x = map_gpr[band(rshift(op, 16), 31)]
elseif p == "D" then
x = map_gpr[band(rshift(op, 11), 31)]
elseif p == "F" then
x = "f"..band(rshift(op, 6), 31)
elseif p == "G" then
x = "f"..band(rshift(op, 11), 31)
elseif p == "H" then
x = "f"..band(rshift(op, 16), 31)
elseif p == "R" then
x = "f"..band(rshift(op, 21), 31)
elseif p == "A" then
x = band(rshift(op, 6), 31)
elseif p == "a" then
x = band(rshift(op, 6), 7)
elseif p == "E" then
x = band(rshift(op, 6), 31) + 32
elseif p == "M" then
x = band(rshift(op, 11), 31)
elseif p == "N" then
x = band(rshift(op, 16), 31)
elseif p == "C" then
x = band(rshift(op, 18), 7)
if x == 0 then x = nil end
elseif p == "K" then
x = band(rshift(op, 11), 31) + 1
elseif p == "P" then
x = band(rshift(op, 11), 31) + 33
elseif p == "L" then
x = band(rshift(op, 11), 31) - last + 1
elseif p == "Q" then
x = band(rshift(op, 11), 31) - last + 33
elseif p == "I" then
x = arshift(lshift(op, 16), 16)
elseif p == "2" then
x = arshift(lshift(op, 13), 11)
elseif p == "3" then
x = arshift(lshift(op, 14), 11)
elseif p == "U" then
x = band(op, 0xffff)
elseif p == "O" then
local disp = arshift(lshift(op, 16), 16)
operands[#operands] = format("%d(%s)", disp, last)
elseif p == "X" then
local index = map_gpr[band(rshift(op, 16), 31)]
operands[#operands] = format("%s(%s)", index, last)
elseif p == "B" then
x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 14) + 4
ctx.rel = x
x = format("0x%08x", x)
elseif p == "b" then
x = ctx.addr + ctx.pos + arshift(lshift(op, 11), 9) + 4
ctx.rel = x
x = format("0x%08x", x)
elseif p == "#" then
x = ctx.addr + ctx.pos + arshift(lshift(op, 6), 4) + 4
ctx.rel = x
x = format("0x%08x", x)
elseif p == "J" then
local a = ctx.addr + ctx.pos
x = a - band(a, 0x0fffffff) + band(op, 0x03ffffff)*4
ctx.rel = x
x = format("0x%08x", x)
elseif p == "V" then
x = band(rshift(op, 8), 7)
if x == 0 then x = nil end
elseif p == "W" then
x = band(op, 7)
if x == 0 then x = nil end
elseif p == "Y" then
x = band(rshift(op, 6), 0x000fffff)
if x == 0 then x = nil end
elseif p == "Z" then
x = band(rshift(op, 6), 1023)
if x == 0 then x = nil end
elseif p == "0" then
if last == "r0" or last == 0 then
local n = #operands
operands[n] = nil
last = operands[n-1]
if altname then
local a1, a2 = match(altname, "([^|]*)|(.*)")
if a1 then name, altname = a1, a2
else name = altname end
end
end
elseif p == "1" then
if last == "ra" then
operands[#operands] = nil
end
else
assert(false)
end
if x then operands[#operands+1] = x; last = x end
end
return putop(ctx, name, operands)
end
------------------------------------------------------------------------------
-- Disassemble a block of code.
local function disass_block(ctx, ofs, len)
if not ofs then ofs = 0 end
local stop = len and ofs+len or #ctx.code
stop = stop - stop % 4
ctx.pos = ofs - ofs % 4
ctx.rel = nil
while ctx.pos < stop do disass_ins(ctx) end
end
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
local function create(code, addr, out)
local ctx = {}
ctx.code = code
ctx.addr = addr or 0
ctx.out = out or io.write
ctx.symtab = {}
ctx.disass = disass_block
ctx.hexdump = 8
ctx.get = get_be
ctx.map_pri = map_pri
return ctx
end
local function create_el(code, addr, out)
local ctx = create(code, addr, out)
ctx.get = get_le
return ctx
end
local function create_r6(code, addr, out)
local ctx = create(code, addr, out)
ctx.map_pri = map_pri_r6
return ctx
end
local function create_r6_el(code, addr, out)
local ctx = create(code, addr, out)
ctx.get = get_le
ctx.map_pri = map_pri_r6
return ctx
end
-- Simple API: disassemble code (a string) at address and output via out.
local function disass(code, addr, out)
create(code, addr, out):disass()
end
local function disass_el(code, addr, out)
create_el(code, addr, out):disass()
end
local function disass_r6(code, addr, out)
create_r6(code, addr, out):disass()
end
local function disass_r6_el(code, addr, out)
create_r6_el(code, addr, out):disass()
end
-- Return register name for RID.
local function regname(r)
if r < 32 then return map_gpr[r] end
return "f"..(r-32)
end
-- Public module functions.
return {
create = create,
create_el = create_el,
create_r6 = create_r6,
create_r6_el = create_r6_el,
disass = disass,
disass_el = disass_el,
disass_r6 = disass_r6,
disass_r6_el = disass_r6_el,
regname = regname
}
+17
View File
@@ -0,0 +1,17 @@
----------------------------------------------------------------------------
-- LuaJIT MIPS64 disassembler wrapper module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This module just exports the big-endian functions from the
-- MIPS disassembler module. All the interesting stuff is there.
------------------------------------------------------------------------------
local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
return {
create = dis_mips.create,
disass = dis_mips.disass,
regname = dis_mips.regname
}
+17
View File
@@ -0,0 +1,17 @@
----------------------------------------------------------------------------
-- LuaJIT MIPS64EL disassembler wrapper module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This module just exports the little-endian functions from the
-- MIPS disassembler module. All the interesting stuff is there.
------------------------------------------------------------------------------
local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
return {
create = dis_mips.create_el,
disass = dis_mips.disass_el,
regname = dis_mips.regname
}
+17
View File
@@ -0,0 +1,17 @@
----------------------------------------------------------------------------
-- LuaJIT MIPS64R6 disassembler wrapper module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This module just exports the r6 big-endian functions from the
-- MIPS disassembler module. All the interesting stuff is there.
------------------------------------------------------------------------------
local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
return {
create = dis_mips.create_r6,
disass = dis_mips.disass_r6,
regname = dis_mips.regname
}
+17
View File
@@ -0,0 +1,17 @@
----------------------------------------------------------------------------
-- LuaJIT MIPS64R6EL disassembler wrapper module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This module just exports the r6 little-endian functions from the
-- MIPS disassembler module. All the interesting stuff is there.
------------------------------------------------------------------------------
local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
return {
create = dis_mips.create_r6_el,
disass = dis_mips.disass_r6_el,
regname = dis_mips.regname
}
+17
View File
@@ -0,0 +1,17 @@
----------------------------------------------------------------------------
-- LuaJIT MIPSEL disassembler wrapper module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This module just exports the little-endian functions from the
-- MIPS disassembler module. All the interesting stuff is there.
------------------------------------------------------------------------------
local dis_mips = require((string.match(..., ".*%.") or "").."dis_mips")
return {
create = dis_mips.create_el,
disass = dis_mips.disass_el,
regname = dis_mips.regname
}
+591
View File
@@ -0,0 +1,591 @@
----------------------------------------------------------------------------
-- LuaJIT PPC disassembler module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT/X license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This is a helper module used by the LuaJIT machine code dumper module.
--
-- It disassembles all common, non-privileged 32/64 bit PowerPC instructions
-- plus the e500 SPE instructions and some Cell/Xenon extensions.
--
-- NYI: VMX, VMX128
------------------------------------------------------------------------------
local type = type
local byte, format = string.byte, string.format
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
local concat = table.concat
local bit = require("bit")
local band, bor, tohex = bit.band, bit.bor, bit.tohex
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
------------------------------------------------------------------------------
-- Primary and extended opcode maps
------------------------------------------------------------------------------
local map_crops = {
shift = 1, mask = 1023,
[0] = "mcrfXX",
[33] = "crnor|crnotCCC=", [129] = "crandcCCC",
[193] = "crxor|crclrCCC%", [225] = "crnandCCC",
[257] = "crandCCC", [289] = "creqv|crsetCCC%",
[417] = "crorcCCC", [449] = "cror|crmoveCCC=",
[16] = "b_lrKB", [528] = "b_ctrKB",
[150] = "isync",
}
local map_rlwinm = setmetatable({
shift = 0, mask = -1,
},
{ __index = function(t, x)
local rot = band(rshift(x, 11), 31)
local mb = band(rshift(x, 6), 31)
local me = band(rshift(x, 1), 31)
if mb == 0 and me == 31-rot then
return "slwiRR~A."
elseif me == 31 and mb == 32-rot then
return "srwiRR~-A."
else
return "rlwinmRR~AAA."
end
end
})
local map_rld = {
shift = 2, mask = 7,
[0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.",
{
shift = 1, mask = 1,
[0] = "rldclRR~RM.", "rldcrRR~RM.",
},
}
local map_ext = setmetatable({
shift = 1, mask = 1023,
[0] = "cmp_YLRR", [32] = "cmpl_YLRR",
[4] = "twARR", [68] = "tdARR",
[8] = "subfcRRR.", [40] = "subfRRR.",
[104] = "negRR.", [136] = "subfeRRR.",
[200] = "subfzeRR.", [232] = "subfmeRR.",
[520] = "subfcoRRR.", [552] = "subfoRRR.",
[616] = "negoRR.", [648] = "subfeoRRR.",
[712] = "subfzeoRR.", [744] = "subfmeoRR.",
[9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.",
[457] = "divduRRR.", [489] = "divdRRR.",
[745] = "mulldoRRR.",
[969] = "divduoRRR.", [1001] = "divdoRRR.",
[10] = "addcRRR.", [138] = "addeRRR.",
[202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.",
[522] = "addcoRRR.", [650] = "addeoRRR.",
[714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.",
[11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.",
[459] = "divwuRRR.", [491] = "divwRRR.",
[747] = "mullwoRRR.",
[971] = "divwouRRR.", [1003] = "divwoRRR.",
[15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR",
[144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", },
[19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", },
[371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", },
[339] = {
shift = 11, mask = 1023,
[32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR",
},
[467] = {
shift = 11, mask = 1023,
[32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR",
},
[20] = "lwarxRR0R", [84] = "ldarxRR0R",
[21] = "ldxRR0R", [53] = "lduxRRR",
[149] = "stdxRR0R", [181] = "stduxRRR",
[341] = "lwaxRR0R", [373] = "lwauxRRR",
[23] = "lwzxRR0R", [55] = "lwzuxRRR",
[87] = "lbzxRR0R", [119] = "lbzuxRRR",
[151] = "stwxRR0R", [183] = "stwuxRRR",
[215] = "stbxRR0R", [247] = "stbuxRRR",
[279] = "lhzxRR0R", [311] = "lhzuxRRR",
[343] = "lhaxRR0R", [375] = "lhauxRRR",
[407] = "sthxRR0R", [439] = "sthuxRRR",
[54] = "dcbst-R0R", [86] = "dcbf-R0R",
[150] = "stwcxRR0R.", [214] = "stdcxRR0R.",
[246] = "dcbtst-R0R", [278] = "dcbt-R0R",
[310] = "eciwxRR0R", [438] = "ecowxRR0R",
[470] = "dcbi-RR",
[598] = {
shift = 21, mask = 3,
[0] = "sync", "lwsync", "ptesync",
},
[758] = "dcba-RR",
[854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R",
[26] = "cntlzwRR~", [58] = "cntlzdRR~",
[122] = "popcntbRR~",
[154] = "prtywRR~", [186] = "prtydRR~",
[28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.",
[284] = "eqvRR~R.", [316] = "xorRR~R.",
[412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.",
[508] = "cmpbRR~R",
[512] = "mcrxrX",
[532] = "ldbrxRR0R", [660] = "stdbrxRR0R",
[533] = "lswxRR0R", [597] = "lswiRR0A",
[661] = "stswxRR0R", [725] = "stswiRR0A",
[534] = "lwbrxRR0R", [662] = "stwbrxRR0R",
[790] = "lhbrxRR0R", [918] = "sthbrxRR0R",
[535] = "lfsxFR0R", [567] = "lfsuxFRR",
[599] = "lfdxFR0R", [631] = "lfduxFRR",
[663] = "stfsxFR0R", [695] = "stfsuxFRR",
[727] = "stfdxFR0R", [759] = "stfduxFR0R",
[855] = "lfiwaxFR0R",
[983] = "stfiwxFR0R",
[24] = "slwRR~R.",
[27] = "sldRR~R.", [536] = "srwRR~R.",
[792] = "srawRR~R.", [824] = "srawiRR~A.",
[794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.",
[922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.",
[539] = "srdRR~R.",
},
{ __index = function(t, x)
if band(x, 31) == 15 then return "iselRRRC" end
end
})
local map_ld = {
shift = 0, mask = 3,
[0] = "ldRRE", "lduRRE", "lwaRRE",
}
local map_std = {
shift = 0, mask = 3,
[0] = "stdRRE", "stduRRE",
}
local map_fps = {
shift = 5, mask = 1,
{
shift = 1, mask = 15,
[0] = false, false, "fdivsFFF.", false,
"fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false,
"fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false,
"fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.",
}
}
local map_fpd = {
shift = 5, mask = 1,
[0] = {
shift = 1, mask = 1023,
[0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX",
[38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>",
[8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.",
[136] = "fnabsF-F.", [264] = "fabsF-F.",
[12] = "frspF-F.",
[14] = "fctiwF-F.", [15] = "fctiwzF-F.",
[583] = "mffsF.", [711] = "mtfsfZF.",
[392] = "frinF-F.", [424] = "frizF-F.",
[456] = "fripF-F.", [488] = "frimF-F.",
[814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.",
},
{
shift = 1, mask = 15,
[0] = false, false, "fdivFFF.", false,
"fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.",
"freF-F.", "fmulFF-F.", "frsqrteF-F.", false,
"fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.",
}
}
local map_spe = {
shift = 0, mask = 2047,
[512] = "evaddwRRR", [514] = "evaddiwRAR~",
[516] = "evsubwRRR~", [518] = "evsubiwRAR~",
[520] = "evabsRR", [521] = "evnegRR",
[522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR",
[525] = "evcntlzwRR", [526] = "evcntlswRR",
[527] = "brincRRR",
[529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR",
[535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=",
[537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR",
[544] = "evsrwuRRR", [545] = "evsrwsRRR",
[546] = "evsrwiuRRA", [547] = "evsrwisRRA",
[548] = "evslwRRR", [550] = "evslwiRRA",
[552] = "evrlwRRR", [553] = "evsplatiRS",
[554] = "evrlwiRRA", [555] = "evsplatfiRS",
[556] = "evmergehiRRR", [557] = "evmergeloRRR",
[558] = "evmergehiloRRR", [559] = "evmergelohiRRR",
[560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR",
[562] = "evcmpltuYRR", [563] = "evcmpltsYRR",
[564] = "evcmpeqYRR",
[632] = "evselRRR", [633] = "evselRRRW",
[634] = "evselRRRW", [635] = "evselRRRW",
[636] = "evselRRRW", [637] = "evselRRRW",
[638] = "evselRRRW", [639] = "evselRRRW",
[640] = "evfsaddRRR", [641] = "evfssubRRR",
[644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR",
[648] = "evfsmulRRR", [649] = "evfsdivRRR",
[652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR",
[656] = "evfscfuiR-R", [657] = "evfscfsiR-R",
[658] = "evfscfufR-R", [659] = "evfscfsfR-R",
[660] = "evfsctuiR-R", [661] = "evfsctsiR-R",
[662] = "evfsctufR-R", [663] = "evfsctsfR-R",
[664] = "evfsctuizR-R", [666] = "evfsctsizR-R",
[668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR",
[704] = "efsaddRRR", [705] = "efssubRRR",
[708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR",
[712] = "efsmulRRR", [713] = "efsdivRRR",
[716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR",
[719] = "efscfdR-R",
[720] = "efscfuiR-R", [721] = "efscfsiR-R",
[722] = "efscfufR-R", [723] = "efscfsfR-R",
[724] = "efsctuiR-R", [725] = "efsctsiR-R",
[726] = "efsctufR-R", [727] = "efsctsfR-R",
[728] = "efsctuizR-R", [730] = "efsctsizR-R",
[732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR",
[736] = "efdaddRRR", [737] = "efdsubRRR",
[738] = "efdcfuidR-R", [739] = "efdcfsidR-R",
[740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR",
[744] = "efdmulRRR", [745] = "efddivRRR",
[746] = "efdctuidzR-R", [747] = "efdctsidzR-R",
[748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR",
[751] = "efdcfsR-R",
[752] = "efdcfuiR-R", [753] = "efdcfsiR-R",
[754] = "efdcfufR-R", [755] = "efdcfsfR-R",
[756] = "efdctuiR-R", [757] = "efdctsiR-R",
[758] = "efdctufR-R", [759] = "efdctsfR-R",
[760] = "efdctuizR-R", [762] = "efdctsizR-R",
[764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR",
[768] = "evlddxRR0R", [769] = "evlddRR8",
[770] = "evldwxRR0R", [771] = "evldwRR8",
[772] = "evldhxRR0R", [773] = "evldhRR8",
[776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2",
[780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2",
[782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2",
[784] = "evlwhexRR0R", [785] = "evlwheRR4",
[788] = "evlwhouxRR0R", [789] = "evlwhouRR4",
[790] = "evlwhosxRR0R", [791] = "evlwhosRR4",
[792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4",
[796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4",
[800] = "evstddxRR0R", [801] = "evstddRR8",
[802] = "evstdwxRR0R", [803] = "evstdwRR8",
[804] = "evstdhxRR0R", [805] = "evstdhRR8",
[816] = "evstwhexRR0R", [817] = "evstwheRR4",
[820] = "evstwhoxRR0R", [821] = "evstwhoRR4",
[824] = "evstwwexRR0R", [825] = "evstwweRR4",
[828] = "evstwwoxRR0R", [829] = "evstwwoRR4",
[1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR",
[1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR",
[1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR",
[1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR",
[1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR",
[1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR",
[1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR",
[1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR",
[1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR",
[1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR",
[1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR",
[1147] = "evmwsmfaRRR",
[1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR",
[1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR",
[1220] = "evmraRR",
[1222] = "evdivwsRRR", [1223] = "evdivwuRRR",
[1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR",
[1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR",
[1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR",
[1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR",
[1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR",
[1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR",
[1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR",
[1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR",
[1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR",
[1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR",
[1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR",
[1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR",
[1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR",
[1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR",
[1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR",
[1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR",
[1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR",
[1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR",
[1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR",
[1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR",
[1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR",
[1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR",
[1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR",
[1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR",
[1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR",
[1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR",
[1491] = "evmwssfanRRR", [1496] = "evmwumianRRR",
[1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR",
}
local map_pri = {
[0] = false, false, "tdiARI", "twiARI",
map_spe, false, false, "mulliRRI",
"subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI",
"addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I",
"b_KBJ", "sc", "bKJ", map_crops,
"rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.",
"oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U",
"andi.RR~U", "andis.RR~U", map_rld, map_ext,
"lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD",
"stwRRD", "stwuRRD", "stbRRD", "stbuRRD",
"lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD",
"sthRRD", "sthuRRD", "lmwRRD", "stmwRRD",
"lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD",
"stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD",
false, false, map_ld, map_fps,
false, false, map_std, map_fpd,
}
------------------------------------------------------------------------------
local map_gpr = {
[0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
}
local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", }
-- Format a condition bit.
local function condfmt(cond)
if cond <= 3 then
return map_cond[band(cond, 3)]
else
return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)])
end
end
------------------------------------------------------------------------------
-- Output a nicely formatted line with an opcode and operands.
local function putop(ctx, text, operands)
local pos = ctx.pos
local extra = ""
if ctx.rel then
local sym = ctx.symtab[ctx.rel]
if sym then extra = "\t->"..sym end
end
if ctx.hexdump > 0 then
ctx.out(format("%08x %s %-7s %s%s\n",
ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
else
ctx.out(format("%08x %-7s %s%s\n",
ctx.addr+pos, text, concat(operands, ", "), extra))
end
ctx.pos = pos + 4
end
-- Fallback for unknown opcodes.
local function unknown(ctx)
return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
end
-- Disassemble a single instruction.
local function disass_ins(ctx)
local pos = ctx.pos
local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3)
local operands = {}
local last = nil
local rs = 21
ctx.op = op
ctx.rel = nil
local opat = map_pri[rshift(b0, 2)]
while type(opat) ~= "string" do
if not opat then return unknown(ctx) end
opat = opat[band(rshift(op, opat.shift), opat.mask)]
end
local name, pat = match(opat, "^([a-z0-9_.]*)(.*)")
local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)")
if altname then pat = pat2 end
for p in gmatch(pat, ".") do
local x = nil
if p == "R" then
x = map_gpr[band(rshift(op, rs), 31)]
rs = rs - 5
elseif p == "F" then
x = "f"..band(rshift(op, rs), 31)
rs = rs - 5
elseif p == "A" then
x = band(rshift(op, rs), 31)
rs = rs - 5
elseif p == "S" then
x = arshift(lshift(op, 27-rs), 27)
rs = rs - 5
elseif p == "I" then
x = arshift(lshift(op, 16), 16)
elseif p == "U" then
x = band(op, 0xffff)
elseif p == "D" or p == "E" then
local disp = arshift(lshift(op, 16), 16)
if p == "E" then disp = band(disp, -4) end
if last == "r0" then last = "0" end
operands[#operands] = format("%d(%s)", disp, last)
elseif p >= "2" and p <= "8" then
local disp = band(rshift(op, rs), 31) * p
if last == "r0" then last = "0" end
operands[#operands] = format("%d(%s)", disp, last)
elseif p == "H" then
x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4)
rs = rs - 5
elseif p == "M" then
x = band(rshift(op, rs), 31) + band(op, 0x20)
elseif p == "C" then
x = condfmt(band(rshift(op, rs), 31))
rs = rs - 5
elseif p == "B" then
local bo = rshift(op, 21)
local cond = band(rshift(op, 16), 31)
local cn = ""
rs = rs - 10
if band(bo, 4) == 0 then
cn = band(bo, 2) == 0 and "dnz" or "dz"
if band(bo, 0x10) == 0 then
cn = cn..(band(bo, 8) == 0 and "f" or "t")
end
if band(bo, 0x10) == 0 then x = condfmt(cond) end
name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+")
elseif band(bo, 0x10) == 0 then
cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)]
if cond > 3 then x = "cr"..rshift(cond, 2) end
name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+")
end
name = gsub(name, "_", cn)
elseif p == "J" then
x = arshift(lshift(op, 27-rs), 29-rs)*4
if band(op, 2) == 0 then x = ctx.addr + pos + x end
ctx.rel = x
x = "0x"..tohex(x)
elseif p == "K" then
if band(op, 1) ~= 0 then name = name.."l" end
if band(op, 2) ~= 0 then name = name.."a" end
elseif p == "X" or p == "Y" then
x = band(rshift(op, rs+2), 7)
if x == 0 and p == "Y" then x = nil else x = "cr"..x end
rs = rs - 5
elseif p == "W" then
x = "cr"..band(op, 7)
elseif p == "Z" then
x = band(rshift(op, rs-4), 255)
rs = rs - 10
elseif p == ">" then
operands[#operands] = rshift(operands[#operands], 1)
elseif p == "0" then
if last == "r0" then
operands[#operands] = nil
if altname then name = altname end
end
elseif p == "L" then
name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w")
elseif p == "." then
if band(op, 1) == 1 then name = name.."." end
elseif p == "N" then
if op == 0x60000000 then name = "nop"; break end
elseif p == "~" then
local n = #operands
operands[n-1], operands[n] = operands[n], operands[n-1]
elseif p == "=" then
local n = #operands
if last == operands[n-1] then
operands[n] = nil
name = altname
end
elseif p == "%" then
local n = #operands
if last == operands[n-1] and last == operands[n-2] then
operands[n] = nil
operands[n-1] = nil
name = altname
end
elseif p == "-" then
rs = rs - 5
else
assert(false)
end
if x then operands[#operands+1] = x; last = x end
end
return putop(ctx, name, operands)
end
------------------------------------------------------------------------------
-- Disassemble a block of code.
local function disass_block(ctx, ofs, len)
if not ofs then ofs = 0 end
local stop = len and ofs+len or #ctx.code
stop = stop - stop % 4
ctx.pos = ofs - ofs % 4
ctx.rel = nil
while ctx.pos < stop do disass_ins(ctx) end
end
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
local function create(code, addr, out)
local ctx = {}
ctx.code = code
ctx.addr = addr or 0
ctx.out = out or io.write
ctx.symtab = {}
ctx.disass = disass_block
ctx.hexdump = 8
return ctx
end
-- Simple API: disassemble code (a string) at address and output via out.
local function disass(code, addr, out)
create(code, addr, out):disass()
end
-- Return register name for RID.
local function regname(r)
if r < 32 then return map_gpr[r] end
return "f"..(r-32)
end
-- Public module functions.
return {
create = create,
disass = disass,
regname = regname
}
+17
View File
@@ -0,0 +1,17 @@
----------------------------------------------------------------------------
-- LuaJIT x64 disassembler wrapper module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This module just exports the 64 bit functions from the combined
-- x86/x64 disassembler module. All the interesting stuff is there.
------------------------------------------------------------------------------
local dis_x86 = require((string.match(..., ".*%.") or "").."dis_x86")
return {
create = dis_x86.create64,
disass = dis_x86.disass64,
regname = dis_x86.regname64
}
+953
View File
@@ -0,0 +1,953 @@
----------------------------------------------------------------------------
-- LuaJIT x86/x64 disassembler module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
-- This is a helper module used by the LuaJIT machine code dumper module.
--
-- Sending small code snippets to an external disassembler and mixing the
-- output with our own stuff was too fragile. So I had to bite the bullet
-- and write yet another x86 disassembler. Oh well ...
--
-- The output format is very similar to what ndisasm generates. But it has
-- been developed independently by looking at the opcode tables from the
-- Intel and AMD manuals. The supported instruction set is quite extensive
-- and reflects what a current generation Intel or AMD CPU implements in
-- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3,
-- SSE4.1, SSE4.2, SSE4a, AVX, AVX2 and even privileged and hypervisor
-- (VMX/SVM) instructions.
--
-- Notes:
-- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported.
-- * No attempt at optimization has been made -- it's fast enough for my needs.
------------------------------------------------------------------------------
local type = type
local sub, byte, format = string.sub, string.byte, string.format
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
local lower, rep = string.lower, string.rep
local bit = require("bit")
local tohex = bit.tohex
-- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on.
local map_opc1_32 = {
--0x
[0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es",
"orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*",
--1x
"adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss",
"sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds",
--2x
"andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa",
"subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das",
--3x
"xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa",
"cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas",
--4x
"incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR",
"decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR",
--5x
"pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR",
"popUR","popUR","popUR","popUR","popUR","popUR","popUR","popUR",
--6x
"sz*pushaw,pusha","sz*popaw,popa","boundVrm","arplWmr",
"fs:seg","gs:seg","o16:","a16",
"pushUi","imulVrmi","pushBs","imulVrms",
"insb","insVS","outsb","outsVS",
--7x
"joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj",
"jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj",
--8x
"arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms",
"testBmr","testVmr","xchgBrm","xchgVrm",
"movBmr","movVmr","movBrm","movVrm",
"movVmg","leaVrm","movWgm","popUm",
--9x
"nop*xchgVaR|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR",
"xchgVaR","xchgVaR","xchgVaR","xchgVaR",
"sz*cbw,cwde,cdqe","sz*cwd,cdq,cqo","call farViw","wait",
"sz*pushfw,pushf","sz*popfw,popf","sahf","lahf",
--Ax
"movBao","movVao","movBoa","movVoa",
"movsb","movsVS","cmpsb","cmpsVS",
"testBai","testVai","stosb","stosVS",
"lodsb","lodsVS","scasb","scasVS",
--Bx
"movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi",
"movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI",
--Cx
"shift!Bmu","shift!Vmu","retBw","ret","vex*3$lesVrm","vex*2$ldsVrm","movBmi","movVmi",
"enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS",
--Dx
"shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb",
"fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7",
--Ex
"loopneBj","loopeBj","loopBj","sz*jcxzBj,jecxzBj,jrcxzBj",
"inBau","inVau","outBua","outVua",
"callVj","jmpVj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda",
--Fx
"lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm",
"clc","stc","cli","sti","cld","std","incb!Bm","incd!Vm",
}
assert(#map_opc1_32 == 255)
-- Map for 1st opcode byte in 64 bit mode (overrides only).
local map_opc1_64 = setmetatable({
[0x06]=false, [0x07]=false, [0x0e]=false,
[0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false,
[0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false,
[0x60]=false, [0x61]=false, [0x62]=false, [0x63]="movsxdVrDmt", [0x67]="a32:",
[0x40]="rex*", [0x41]="rex*b", [0x42]="rex*x", [0x43]="rex*xb",
[0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb",
[0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb",
[0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb",
[0x82]=false, [0x9a]=false, [0xc4]="vex*3", [0xc5]="vex*2", [0xce]=false,
[0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false,
}, { __index = map_opc1_32 })
-- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you.
-- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2
local map_opc2 = {
--0x
[0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret",
"invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu",
--1x
"movupsXrm|movssXrvm|movupdXrm|movsdXrvm",
"movupsXmr|movssXmvr|movupdXmr|movsdXmvr",
"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm",
"movlpsXmr||movlpdXmr",
"unpcklpsXrvm||unpcklpdXrvm",
"unpckhpsXrvm||unpckhpdXrvm",
"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm",
"movhpsXmr||movhpdXmr",
"$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm",
"hintnopVm","hintnopVm","hintnopVm","hintnopVm",
--2x
"movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil,
"movapsXrm||movapdXrm",
"movapsXmr||movapdXmr",
"cvtpi2psXrMm|cvtsi2ssXrvVmt|cvtpi2pdXrMm|cvtsi2sdXrvVmt",
"movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr",
"cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm",
"cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm",
"ucomissXrm||ucomisdXrm",
"comissXrm||comisdXrm",
--3x
"wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,"getsec",
"opc3*38",nil,"opc3*3a",nil,nil,nil,nil,nil,
--4x
"cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm",
"cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm",
"cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm",
"cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm",
--5x
"movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm",
"rsqrtpsXrm|rsqrtssXrvm","rcppsXrm|rcpssXrvm",
"andpsXrvm||andpdXrvm","andnpsXrvm||andnpdXrvm",
"orpsXrvm||orpdXrvm","xorpsXrvm||xorpdXrvm",
"addpsXrvm|addssXrvm|addpdXrvm|addsdXrvm","mulpsXrvm|mulssXrvm|mulpdXrvm|mulsdXrvm",
"cvtps2pdXrm|cvtss2sdXrvm|cvtpd2psXrm|cvtsd2ssXrvm",
"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm",
"subpsXrvm|subssXrvm|subpdXrvm|subsdXrvm","minpsXrvm|minssXrvm|minpdXrvm|minsdXrvm",
"divpsXrvm|divssXrvm|divpdXrvm|divsdXrvm","maxpsXrvm|maxssXrvm|maxpdXrvm|maxsdXrvm",
--6x
"punpcklbwPrvm","punpcklwdPrvm","punpckldqPrvm","packsswbPrvm",
"pcmpgtbPrvm","pcmpgtwPrvm","pcmpgtdPrvm","packuswbPrvm",
"punpckhbwPrvm","punpckhwdPrvm","punpckhdqPrvm","packssdwPrvm",
"||punpcklqdqXrvm","||punpckhqdqXrvm",
"movPrVSm","movqMrm|movdquXrm|movdqaXrm",
--7x
"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pvmu",
"pshiftd!Pvmu","pshiftq!Mvmu||pshiftdq!Xvmu",
"pcmpeqbPrvm","pcmpeqwPrvm","pcmpeqdPrvm","emms*|",
"vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$",
nil,nil,
"||haddpdXrvm|haddpsXrvm","||hsubpdXrvm|hsubpsXrvm",
"movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr",
--8x
"joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj",
"jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj",
--9x
"setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm",
"setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm",
--Ax
"push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil,
"push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm",
--Bx
"cmpxchgBmr","cmpxchgVmr","$lssVrm","btrVmr",
"$lfsVrm","$lgsVrm","movzxVrBmt","movzxVrWmt",
"|popcntVrm","ud2Dp","bt!Vmu","btcVmr",
"bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt",
--Cx
"xaddBmr","xaddVmr",
"cmppsXrvmu|cmpssXrvmu|cmppdXrvmu|cmpsdXrvmu","$movntiVmr|",
"pinsrwPrvWmu","pextrwDrPmu",
"shufpsXrvmu||shufpdXrvmu","$cmpxchg!Qmp",
"bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR",
--Dx
"||addsubpdXrvm|addsubpsXrvm","psrlwPrvm","psrldPrvm","psrlqPrvm",
"paddqPrvm","pmullwPrvm",
"|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm",
"psubusbPrvm","psubuswPrvm","pminubPrvm","pandPrvm",
"paddusbPrvm","padduswPrvm","pmaxubPrvm","pandnPrvm",
--Ex
"pavgbPrvm","psrawPrvm","psradPrvm","pavgwPrvm",
"pmulhuwPrvm","pmulhwPrvm",
"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr",
"psubsbPrvm","psubswPrvm","pminswPrvm","porPrvm",
"paddsbPrvm","paddswPrvm","pmaxswPrvm","pxorPrvm",
--Fx
"|||lddquXrm","psllwPrvm","pslldPrvm","psllqPrvm",
"pmuludqPrvm","pmaddwdPrvm","psadbwPrvm","maskmovqMrm||maskmovdquXrm$",
"psubbPrvm","psubwPrvm","psubdPrvm","psubqPrvm",
"paddbPrvm","paddwPrvm","padddPrvm","ud",
}
assert(map_opc2[255] == "ud")
-- Map for three-byte opcodes. Can't wait for their next invention.
local map_opc3 = {
["38"] = { -- [66] 0f 38 xx
--0x
[0]="pshufbPrvm","phaddwPrvm","phadddPrvm","phaddswPrvm",
"pmaddubswPrvm","phsubwPrvm","phsubdPrvm","phsubswPrvm",
"psignbPrvm","psignwPrvm","psigndPrvm","pmulhrswPrvm",
"||permilpsXrvm","||permilpdXrvm",nil,nil,
--1x
"||pblendvbXrma",nil,nil,nil,
"||blendvpsXrma","||blendvpdXrma","||permpsXrvm","||ptestXrm",
"||broadcastssXrm","||broadcastsdXrm","||broadcastf128XrlXm",nil,
"pabsbPrm","pabswPrm","pabsdPrm",nil,
--2x
"||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm",
"||pmovsxwqXrm","||pmovsxdqXrm",nil,nil,
"||pmuldqXrvm","||pcmpeqqXrvm","||$movntdqaXrm","||packusdwXrvm",
"||maskmovpsXrvm","||maskmovpdXrvm","||maskmovpsXmvr","||maskmovpdXmvr",
--3x
"||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm",
"||pmovzxwqXrm","||pmovzxdqXrm","||permdXrvm","||pcmpgtqXrvm",
"||pminsbXrvm","||pminsdXrvm","||pminuwXrvm","||pminudXrvm",
"||pmaxsbXrvm","||pmaxsdXrvm","||pmaxuwXrvm","||pmaxudXrvm",
--4x
"||pmulddXrvm","||phminposuwXrm",nil,nil,
nil,"||psrlvVSXrvm","||psravdXrvm","||psllvVSXrvm",
--5x
[0x58] = "||pbroadcastdXrlXm",[0x59] = "||pbroadcastqXrlXm",
[0x5a] = "||broadcasti128XrlXm",
--7x
[0x78] = "||pbroadcastbXrlXm",[0x79] = "||pbroadcastwXrlXm",
--8x
[0x8c] = "||pmaskmovXrvVSm",
[0x8e] = "||pmaskmovVSmXvr",
--9x
[0x96] = "||fmaddsub132pHXrvm",[0x97] = "||fmsubadd132pHXrvm",
[0x98] = "||fmadd132pHXrvm",[0x99] = "||fmadd132sHXrvm",
[0x9a] = "||fmsub132pHXrvm",[0x9b] = "||fmsub132sHXrvm",
[0x9c] = "||fnmadd132pHXrvm",[0x9d] = "||fnmadd132sHXrvm",
[0x9e] = "||fnmsub132pHXrvm",[0x9f] = "||fnmsub132sHXrvm",
--Ax
[0xa6] = "||fmaddsub213pHXrvm",[0xa7] = "||fmsubadd213pHXrvm",
[0xa8] = "||fmadd213pHXrvm",[0xa9] = "||fmadd213sHXrvm",
[0xaa] = "||fmsub213pHXrvm",[0xab] = "||fmsub213sHXrvm",
[0xac] = "||fnmadd213pHXrvm",[0xad] = "||fnmadd213sHXrvm",
[0xae] = "||fnmsub213pHXrvm",[0xaf] = "||fnmsub213sHXrvm",
--Bx
[0xb6] = "||fmaddsub231pHXrvm",[0xb7] = "||fmsubadd231pHXrvm",
[0xb8] = "||fmadd231pHXrvm",[0xb9] = "||fmadd231sHXrvm",
[0xba] = "||fmsub231pHXrvm",[0xbb] = "||fmsub231sHXrvm",
[0xbc] = "||fnmadd231pHXrvm",[0xbd] = "||fnmadd231sHXrvm",
[0xbe] = "||fnmsub231pHXrvm",[0xbf] = "||fnmsub231sHXrvm",
--Dx
[0xdc] = "||aesencXrvm", [0xdd] = "||aesenclastXrvm",
[0xde] = "||aesdecXrvm", [0xdf] = "||aesdeclastXrvm",
--Fx
[0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt",
[0xf7] = "| sarxVrmv| shlxVrmv| shrxVrmv",
},
["3a"] = { -- [66] 0f 3a xx
--0x
[0x00]="||permqXrmu","||permpdXrmu","||pblenddXrvmu",nil,
"||permilpsXrmu","||permilpdXrmu","||perm2f128Xrvmu",nil,
"||roundpsXrmu","||roundpdXrmu","||roundssXrvmu","||roundsdXrvmu",
"||blendpsXrvmu","||blendpdXrvmu","||pblendwXrvmu","palignrPrvmu",
--1x
nil,nil,nil,nil,
"||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru",
"||insertf128XrvlXmu","||extractf128XlXmYru",nil,nil,
nil,nil,nil,nil,
--2x
"||pinsrbXrvVmu","||insertpsXrvmu","||pinsrXrvVmuS",nil,
--3x
[0x38] = "||inserti128Xrvmu",[0x39] = "||extracti128XlXmYru",
--4x
[0x40] = "||dppsXrvmu",
[0x41] = "||dppdXrvmu",
[0x42] = "||mpsadbwXrvmu",
[0x44] = "||pclmulqdqXrvmu",
[0x46] = "||perm2i128Xrvmu",
[0x4a] = "||blendvpsXrvmb",[0x4b] = "||blendvpdXrvmb",
[0x4c] = "||pblendvbXrvmb",
--6x
[0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu",
[0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu",
[0xdf] = "||aeskeygenassistXrmu",
--Fx
[0xf0] = "||| rorxVrmu",
},
}
-- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands).
local map_opcvm = {
[0xc1]="vmcall",[0xc2]="vmlaunch",[0xc3]="vmresume",[0xc4]="vmxoff",
[0xc8]="monitor",[0xc9]="mwait",
[0xd8]="vmrun",[0xd9]="vmmcall",[0xda]="vmload",[0xdb]="vmsave",
[0xdc]="stgi",[0xdd]="clgi",[0xde]="skinit",[0xdf]="invlpga",
[0xf8]="swapgs",[0xf9]="rdtscp",
}
-- Map for FP opcodes. And you thought stack machines are simple?
local map_opcfp = {
-- D8-DF 00-BF: opcodes with a memory operand.
-- D8
[0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm",
"fldFm",nil,"fstFm","fstpFm","fldenvVm","fldcwWm","fnstenvVm","fnstcwWm",
-- DA
"fiaddDm","fimulDm","ficomDm","ficompDm",
"fisubDm","fisubrDm","fidivDm","fidivrDm",
-- DB
"fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp",
-- DC
"faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm",
-- DD
"fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm",
-- DE
"fiaddWm","fimulWm","ficomWm","ficompWm",
"fisubWm","fisubrWm","fidivWm","fidivrWm",
-- DF
"fildWm","fisttpWm","fistWm","fistpWm",
"fbld twordFmp","fildQm","fbstp twordFmp","fistpQm",
-- xx C0-FF: opcodes with a pseudo-register operand.
-- D8
"faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf",
-- D9
"fldFf","fxchFf",{"fnop"},nil,
{"fchs","fabs",nil,nil,"ftst","fxam"},
{"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"},
{"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"},
{"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"},
-- DA
"fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil,
-- DB
"fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf",
{nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil,
-- DC
"fadd toFf","fmul toFf",nil,nil,
"fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf",
-- DD
"ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil,
-- DE
"faddpFf","fmulpFf",nil,{nil,"fcompp"},
"fsubrpFf","fsubpFf","fdivrpFf","fdivpFf",
-- DF
nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil,
}
assert(map_opcfp[126] == "fcomipFf")
-- Map for opcode groups. The subkey is sp from the ModRM byte.
local map_opcgroup = {
arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" },
shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" },
testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" },
testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" },
incb = { "inc", "dec" },
incd = { "inc", "dec", "callUmp", "$call farDmp",
"jmpUmp", "$jmp farDmp", "pushUm" },
sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" },
sgdt = { "vm*$sgdt", "vm*$sidt", "$lgdt", "vm*$lidt",
"smsw", nil, "lmsw", "vm*$invlpg" },
bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" },
cmpxchg = { nil, "sz*,cmpxchg8bQmp,cmpxchg16bXmp", nil, nil,
nil, nil, "vmptrld|vmxon|vmclear", "vmptrst" },
pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" },
pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" },
pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" },
pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" },
fxsave = { "$fxsave", "$fxrstor", "$ldmxcsr", "$stmxcsr",
nil, "lfenceDp$", "mfenceDp$", "sfenceDp$clflush" },
prefetch = { "prefetch", "prefetchw" },
prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" },
}
------------------------------------------------------------------------------
-- Maps for register names.
local map_regs = {
B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh",
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
B64 = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" },
W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" },
D = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" },
Q = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" },
M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext!
X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" },
Y = { "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7",
"ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15" },
}
local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" }
-- Maps for size names.
local map_sz2n = {
B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, Y = 32,
}
local map_sz2prefix = {
B = "byte", W = "word", D = "dword",
Q = "qword",
M = "qword", X = "xword", Y = "yword",
F = "dword", G = "qword", -- No need for sizes/register names for these two.
}
------------------------------------------------------------------------------
-- Output a nicely formatted line with an opcode and operands.
local function putop(ctx, text, operands)
local code, pos, hex = ctx.code, ctx.pos, ""
local hmax = ctx.hexdump
if hmax > 0 then
for i=ctx.start,pos-1 do
hex = hex..format("%02X", byte(code, i, i))
end
if #hex > hmax then hex = sub(hex, 1, hmax)..". "
else hex = hex..rep(" ", hmax-#hex+2) end
end
if operands then text = text.." "..operands end
if ctx.o16 then text = "o16 "..text; ctx.o16 = false end
if ctx.a32 then text = "a32 "..text; ctx.a32 = false end
if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end
if ctx.rex then
local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "")..
(ctx.rexx and "x" or "")..(ctx.rexb and "b" or "")..
(ctx.vexl and "l" or "")
if ctx.vexv and ctx.vexv ~= 0 then t = t.."v"..ctx.vexv end
if t ~= "" then text = ctx.rex.."."..t.." "..gsub(text, "^ ", "")
elseif ctx.rex == "vex" then text = gsub("v"..text, "^v ", "") end
ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
ctx.rex = false; ctx.vexl = false; ctx.vexv = false
end
if ctx.seg then
local text2, n = gsub(text, "%[", "["..ctx.seg..":")
if n == 0 then text = ctx.seg.." "..text else text = text2 end
ctx.seg = false
end
if ctx.lock then text = "lock "..text; ctx.lock = false end
local imm = ctx.imm
if imm then
local sym = ctx.symtab[imm]
if sym then text = text.."\t->"..sym end
end
ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text))
ctx.mrm = false
ctx.vexv = false
ctx.start = pos
ctx.imm = nil
end
-- Clear all prefix flags.
local function clearprefixes(ctx)
ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false
ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false
ctx.rex = false; ctx.a32 = false; ctx.vexl = false
end
-- Fallback for incomplete opcodes at the end.
local function incomplete(ctx)
ctx.pos = ctx.stop+1
clearprefixes(ctx)
return putop(ctx, "(incomplete)")
end
-- Fallback for unknown opcodes.
local function unknown(ctx)
clearprefixes(ctx)
return putop(ctx, "(unknown)")
end
-- Return an immediate of the specified size.
local function getimm(ctx, pos, n)
if pos+n-1 > ctx.stop then return incomplete(ctx) end
local code = ctx.code
if n == 1 then
local b1 = byte(code, pos, pos)
return b1
elseif n == 2 then
local b1, b2 = byte(code, pos, pos+1)
return b1+b2*256
else
local b1, b2, b3, b4 = byte(code, pos, pos+3)
local imm = b1+b2*256+b3*65536+b4*16777216
ctx.imm = imm
return imm
end
end
-- Process pattern string and generate the operands.
local function putpat(ctx, name, pat)
local operands, regs, sz, mode, sp, rm, sc, rx, sdisp
local code, pos, stop, vexl = ctx.code, ctx.pos, ctx.stop, ctx.vexl
-- Chars used: 1DFGHIMPQRSTUVWXYabcdfgijlmoprstuvwxyz
for p in gmatch(pat, ".") do
local x = nil
if p == "V" or p == "U" then
if ctx.rexw then sz = "Q"; ctx.rexw = false
elseif ctx.o16 then sz = "W"; ctx.o16 = false
elseif p == "U" and ctx.x64 then sz = "Q"
else sz = "D" end
regs = map_regs[sz]
elseif p == "T" then
if ctx.rexw then sz = "Q"; ctx.rexw = false else sz = "D" end
regs = map_regs[sz]
elseif p == "B" then
sz = "B"
regs = ctx.rex and map_regs.B64 or map_regs.B
elseif match(p, "[WDQMXYFG]") then
sz = p
if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end
regs = map_regs[sz]
elseif p == "P" then
sz = ctx.o16 and "X" or "M"; ctx.o16 = false
if sz == "X" and vexl then sz = "Y"; ctx.vexl = false end
regs = map_regs[sz]
elseif p == "H" then
name = name..(ctx.rexw and "d" or "s")
ctx.rexw = false
elseif p == "S" then
name = name..lower(sz)
elseif p == "s" then
local imm = getimm(ctx, pos, 1); if not imm then return end
x = imm <= 127 and format("+0x%02x", imm)
or format("-0x%02x", 256-imm)
pos = pos+1
elseif p == "u" then
local imm = getimm(ctx, pos, 1); if not imm then return end
x = format("0x%02x", imm)
pos = pos+1
elseif p == "b" then
local imm = getimm(ctx, pos, 1); if not imm then return end
x = regs[imm/16+1]
pos = pos+1
elseif p == "w" then
local imm = getimm(ctx, pos, 2); if not imm then return end
x = format("0x%x", imm)
pos = pos+2
elseif p == "o" then -- [offset]
if ctx.x64 then
local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
x = format("[0x%08x%08x]", imm2, imm1)
pos = pos+8
else
local imm = getimm(ctx, pos, 4); if not imm then return end
x = format("[0x%08x]", imm)
pos = pos+4
end
elseif p == "i" or p == "I" then
local n = map_sz2n[sz]
if n == 8 and ctx.x64 and p == "I" then
local imm1 = getimm(ctx, pos, 4); if not imm1 then return end
local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end
x = format("0x%08x%08x", imm2, imm1)
else
if n == 8 then n = 4 end
local imm = getimm(ctx, pos, n); if not imm then return end
if sz == "Q" and (imm < 0 or imm > 0x7fffffff) then
imm = (0xffffffff+1)-imm
x = format(imm > 65535 and "-0x%08x" or "-0x%x", imm)
else
x = format(imm > 65535 and "0x%08x" or "0x%x", imm)
end
end
pos = pos+n
elseif p == "j" then
local n = map_sz2n[sz]
if n == 8 then n = 4 end
local imm = getimm(ctx, pos, n); if not imm then return end
if sz == "B" and imm > 127 then imm = imm-256
elseif imm > 2147483647 then imm = imm-4294967296 end
pos = pos+n
imm = imm + pos + ctx.addr
if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end
ctx.imm = imm
if sz == "W" then
x = format("word 0x%04x", imm%65536)
elseif ctx.x64 then
local lo = imm % 0x1000000
x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo)
else
x = "0x"..tohex(imm)
end
elseif p == "R" then
local r = byte(code, pos-1, pos-1)%8
if ctx.rexb then r = r + 8; ctx.rexb = false end
x = regs[r+1]
elseif p == "a" then x = regs[1]
elseif p == "c" then x = "cl"
elseif p == "d" then x = "dx"
elseif p == "1" then x = "1"
else
if not mode then
mode = ctx.mrm
if not mode then
if pos > stop then return incomplete(ctx) end
mode = byte(code, pos, pos)
pos = pos+1
end
rm = mode%8; mode = (mode-rm)/8
sp = mode%8; mode = (mode-sp)/8
sdisp = ""
if mode < 3 then
if rm == 4 then
if pos > stop then return incomplete(ctx) end
sc = byte(code, pos, pos)
pos = pos+1
rm = sc%8; sc = (sc-rm)/8
rx = sc%8; sc = (sc-rx)/8
if ctx.rexx then rx = rx + 8; ctx.rexx = false end
if rx == 4 then rx = nil end
end
if mode > 0 or rm == 5 then
local dsz = mode
if dsz ~= 1 then dsz = 4 end
local disp = getimm(ctx, pos, dsz); if not disp then return end
if mode == 0 then rm = nil end
if rm or rx or (not sc and ctx.x64 and not ctx.a32) then
if dsz == 1 and disp > 127 then
sdisp = format("-0x%x", 256-disp)
elseif disp >= 0 and disp <= 0x7fffffff then
sdisp = format("+0x%x", disp)
else
sdisp = format("-0x%x", (0xffffffff+1)-disp)
end
else
sdisp = format(ctx.x64 and not ctx.a32 and
not (disp >= 0 and disp <= 0x7fffffff)
and "0xffffffff%08x" or "0x%08x", disp)
end
pos = pos+dsz
end
end
if rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end
if ctx.rexr then sp = sp + 8; ctx.rexr = false end
end
if p == "m" then
if mode == 3 then x = regs[rm+1]
else
local aregs = ctx.a32 and map_regs.D or ctx.aregs
local srm, srx = "", ""
if rm then srm = aregs[rm+1]
elseif not sc and ctx.x64 and not ctx.a32 then srm = "rip" end
ctx.a32 = false
if rx then
if rm then srm = srm.."+" end
srx = aregs[rx+1]
if sc > 0 then srx = srx.."*"..(2^sc) end
end
x = format("[%s%s%s]", srm, srx, sdisp)
end
if mode < 3 and
(not match(pat, "[aRrgp]") or match(pat, "t")) then -- Yuck.
x = map_sz2prefix[sz].." "..x
end
elseif p == "r" then x = regs[sp+1]
elseif p == "g" then x = map_segregs[sp+1]
elseif p == "p" then -- Suppress prefix.
elseif p == "f" then x = "st"..rm
elseif p == "x" then
if sp == 0 and ctx.lock and not ctx.x64 then
x = "CR8"; ctx.lock = false
else
x = "CR"..sp
end
elseif p == "v" then
if ctx.vexv then
x = regs[ctx.vexv+1]; ctx.vexv = false
end
elseif p == "y" then x = "DR"..sp
elseif p == "z" then x = "TR"..sp
elseif p == "l" then vexl = false
elseif p == "t" then
else
error("bad pattern `"..pat.."'")
end
end
if x then operands = operands and operands..", "..x or x end
end
ctx.pos = pos
return putop(ctx, name, operands)
end
-- Forward declaration.
local map_act
-- Fetch and cache MRM byte.
local function getmrm(ctx)
local mrm = ctx.mrm
if not mrm then
local pos = ctx.pos
if pos > ctx.stop then return nil end
mrm = byte(ctx.code, pos, pos)
ctx.pos = pos+1
ctx.mrm = mrm
end
return mrm
end
-- Dispatch to handler depending on pattern.
local function dispatch(ctx, opat, patgrp)
if not opat then return unknown(ctx) end
if match(opat, "%|") then -- MMX/SSE variants depending on prefix.
local p
if ctx.rep then
p = ctx.rep=="rep" and "%|([^%|]*)" or "%|[^%|]*%|[^%|]*%|([^%|]*)"
ctx.rep = false
elseif ctx.o16 then p = "%|[^%|]*%|([^%|]*)"; ctx.o16 = false
else p = "^[^%|]*" end
opat = match(opat, p)
if not opat then return unknown(ctx) end
-- ctx.rep = false; ctx.o16 = false
--XXX fails for 66 f2 0f 38 f1 06 crc32 eax,WORD PTR [esi]
--XXX remove in branches?
end
if match(opat, "%$") then -- reg$mem variants.
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
opat = match(opat, mrm >= 192 and "^[^%$]*" or "%$(.*)")
if opat == "" then return unknown(ctx) end
end
if opat == "" then return unknown(ctx) end
local name, pat = match(opat, "^([a-z0-9 ]*)(.*)")
if pat == "" and patgrp then pat = patgrp end
return map_act[sub(pat, 1, 1)](ctx, name, pat)
end
-- Get a pattern from an opcode map and dispatch to handler.
local function dispatchmap(ctx, opcmap)
local pos = ctx.pos
local opat = opcmap[byte(ctx.code, pos, pos)]
pos = pos + 1
ctx.pos = pos
return dispatch(ctx, opat)
end
-- Map for action codes. The key is the first char after the name.
map_act = {
-- Simple opcodes without operands.
[""] = function(ctx, name, pat)
return putop(ctx, name)
end,
-- Operand size chars fall right through.
B = putpat, W = putpat, D = putpat, Q = putpat,
V = putpat, U = putpat, T = putpat,
M = putpat, X = putpat, P = putpat,
F = putpat, G = putpat, Y = putpat,
H = putpat,
-- Collect prefixes.
[":"] = function(ctx, name, pat)
ctx[pat == ":" and name or sub(pat, 2)] = name
if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes.
end,
-- Chain to special handler specified by name.
["*"] = function(ctx, name, pat)
return map_act[name](ctx, name, sub(pat, 2))
end,
-- Use named subtable for opcode group.
["!"] = function(ctx, name, pat)
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2))
end,
-- o16,o32[,o64] variants.
sz = function(ctx, name, pat)
if ctx.o16 then ctx.o16 = false
else
pat = match(pat, ",(.*)")
if ctx.rexw then
local p = match(pat, ",(.*)")
if p then pat = p; ctx.rexw = false end
end
end
pat = match(pat, "^[^,]*")
return dispatch(ctx, pat)
end,
-- Two-byte opcode dispatch.
opc2 = function(ctx, name, pat)
return dispatchmap(ctx, map_opc2)
end,
-- Three-byte opcode dispatch.
opc3 = function(ctx, name, pat)
return dispatchmap(ctx, map_opc3[pat])
end,
-- VMX/SVM dispatch.
vm = function(ctx, name, pat)
return dispatch(ctx, map_opcvm[ctx.mrm])
end,
-- Floating point opcode dispatch.
fp = function(ctx, name, pat)
local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end
local rm = mrm%8
local idx = pat*8 + ((mrm-rm)/8)%8
if mrm >= 192 then idx = idx + 64 end
local opat = map_opcfp[idx]
if type(opat) == "table" then opat = opat[rm+1] end
return dispatch(ctx, opat)
end,
-- REX prefix.
rex = function(ctx, name, pat)
if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.
for p in gmatch(pat, ".") do ctx["rex"..p] = true end
ctx.rex = "rex"
end,
-- VEX prefix.
vex = function(ctx, name, pat)
if ctx.rex then return unknown(ctx) end -- Only 1 REX or VEX prefix allowed.
ctx.rex = "vex"
local pos = ctx.pos
if ctx.mrm then
ctx.mrm = nil
pos = pos-1
end
local b = byte(ctx.code, pos, pos)
if not b then return incomplete(ctx) end
pos = pos+1
if b < 128 then ctx.rexr = true end
local m = 1
if pat == "3" then
m = b%32; b = (b-m)/32
local nb = b%2; b = (b-nb)/2
if nb == 0 then ctx.rexb = true end
local nx = b%2
if nx == 0 then ctx.rexx = true end
b = byte(ctx.code, pos, pos)
if not b then return incomplete(ctx) end
pos = pos+1
if b >= 128 then ctx.rexw = true end
end
ctx.pos = pos
local map
if m == 1 then map = map_opc2
elseif m == 2 then map = map_opc3["38"]
elseif m == 3 then map = map_opc3["3a"]
else return unknown(ctx) end
local p = b%4; b = (b-p)/4
if p == 1 then ctx.o16 = "o16"
elseif p == 2 then ctx.rep = "rep"
elseif p == 3 then ctx.rep = "repne" end
local l = b%2; b = (b-l)/2
if l ~= 0 then ctx.vexl = true end
ctx.vexv = (-1-b)%16
return dispatchmap(ctx, map)
end,
-- Special case for nop with REX prefix.
nop = function(ctx, name, pat)
return dispatch(ctx, ctx.rex and pat or "nop")
end,
-- Special case for 0F 77.
emms = function(ctx, name, pat)
if ctx.rex ~= "vex" then
return putop(ctx, "emms")
elseif ctx.vexl then
ctx.vexl = false
return putop(ctx, "zeroall")
else
return putop(ctx, "zeroupper")
end
end,
}
------------------------------------------------------------------------------
-- Disassemble a block of code.
local function disass_block(ctx, ofs, len)
if not ofs then ofs = 0 end
local stop = len and ofs+len or #ctx.code
ofs = ofs + 1
ctx.start = ofs
ctx.pos = ofs
ctx.stop = stop
ctx.imm = nil
ctx.mrm = false
clearprefixes(ctx)
while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end
if ctx.pos ~= ctx.start then incomplete(ctx) end
end
-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
local function create(code, addr, out)
local ctx = {}
ctx.code = code
ctx.addr = (addr or 0) - 1
ctx.out = out or io.write
ctx.symtab = {}
ctx.disass = disass_block
ctx.hexdump = 16
ctx.x64 = false
ctx.map1 = map_opc1_32
ctx.aregs = map_regs.D
return ctx
end
local function create64(code, addr, out)
local ctx = create(code, addr, out)
ctx.x64 = true
ctx.map1 = map_opc1_64
ctx.aregs = map_regs.Q
return ctx
end
-- Simple API: disassemble code (a string) at address and output via out.
local function disass(code, addr, out)
create(code, addr, out):disass()
end
local function disass64(code, addr, out)
create64(code, addr, out):disass()
end
-- Return register name for RID.
local function regname(r)
if r < 8 then return map_regs.D[r+1] end
return map_regs.X[r-7]
end
local function regname64(r)
if r < 16 then return map_regs.Q[r+1] end
return map_regs.X[r-15]
end
-- Public module functions.
return {
create = create,
create64 = create64,
disass = disass,
disass64 = disass64,
regname = regname,
regname64 = regname64
}
+731
View File
@@ -0,0 +1,731 @@
----------------------------------------------------------------------------
-- LuaJIT compiler dump module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module can be used to debug the JIT compiler itself. It dumps the
-- code representations and structures used in various compiler stages.
--
-- Example usage:
--
-- luajit -jdump -e "local x=0; for i=1,1e6 do x=x+i end; print(x)"
-- luajit -jdump=im -e "for i=1,1000 do for j=1,1000 do end end" | less -R
-- luajit -jdump=is myapp.lua | less -R
-- luajit -jdump=-b myapp.lua
-- luajit -jdump=+aH,myapp.html myapp.lua
-- luajit -jdump=ixT,myapp.dump myapp.lua
--
-- The first argument specifies the dump mode. The second argument gives
-- the output file name. Default output is to stdout, unless the environment
-- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the
-- module is started.
--
-- Different features can be turned on or off with the dump mode. If the
-- mode starts with a '+', the following features are added to the default
-- set of features; a '-' removes them. Otherwise the features are replaced.
--
-- The following dump features are available (* marks the default):
--
-- * t Print a line for each started, ended or aborted trace (see also -jv).
-- * b Dump the traced bytecode.
-- * i Dump the IR (intermediate representation).
-- r Augment the IR with register/stack slots.
-- s Dump the snapshot map.
-- * m Dump the generated machine code.
-- x Print each taken trace exit.
-- X Print each taken trace exit and the contents of all registers.
-- a Print the IR of aborted traces, too.
--
-- The output format can be set with the following characters:
--
-- T Plain text output.
-- A ANSI-colored text output
-- H Colorized HTML + CSS output.
--
-- The default output format is plain text. It's set to ANSI-colored text
-- if the COLORTERM variable is set. Note: this is independent of any output
-- redirection, which is actually considered a feature.
--
-- You probably want to use less -R to enjoy viewing ANSI-colored text from
-- a pipe or a file. Add this to your ~/.bashrc: export LESS="-R"
--
------------------------------------------------------------------------------
-- Cache some library functions and objects.
local jit = require("jit")
local jutil = require("jit.util")
local vmdef = require("jit.vmdef")
local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc
local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek
local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap
local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr
local bit = require("bit")
local band, shr, tohex = bit.band, bit.rshift, bit.tohex
local sub, gsub, format = string.sub, string.gsub, string.format
local byte, rep = string.byte, string.rep
local type, tostring = type, tostring
local stdout, stderr = io.stdout, io.stderr
-- Load other modules on-demand.
local bcline, disass
-- Active flag, output file handle and dump mode.
local active, out, dumpmode
------------------------------------------------------------------------------
local symtabmt = { __index = false }
local symtab = {}
local nexitsym = 0
-- Fill nested symbol table with per-trace exit stub addresses.
local function fillsymtab_tr(tr, nexit)
local t = {}
symtabmt.__index = t
if jit.arch:sub(1, 4) == "mips" then
t[traceexitstub(tr, 0)] = "exit"
return
end
for i=0,nexit-1 do
local addr = traceexitstub(tr, i)
if addr < 0 then addr = addr + 2^32 end
t[addr] = tostring(i)
end
local addr = traceexitstub(tr, nexit)
if addr then t[addr] = "stack_check" end
end
-- Fill symbol table with trace exit stub addresses.
local function fillsymtab(tr, nexit)
local t = symtab
if nexitsym == 0 then
local maskaddr = jit.arch == "arm" and -2
local ircall = vmdef.ircall
for i=0,#ircall do
local addr = ircalladdr(i)
if addr ~= 0 then
if maskaddr then addr = band(addr, maskaddr) end
if addr < 0 then addr = addr + 2^32 end
t[addr] = ircall[i]
end
end
end
if nexitsym == 1000000 then -- Per-trace exit stubs.
fillsymtab_tr(tr, nexit)
elseif nexit > nexitsym then -- Shared exit stubs.
for i=nexitsym,nexit-1 do
local addr = traceexitstub(i)
if addr == nil then -- Fall back to per-trace exit stubs.
fillsymtab_tr(tr, nexit)
setmetatable(symtab, symtabmt)
nexit = 1000000
break
end
if addr < 0 then addr = addr + 2^32 end
t[addr] = tostring(i)
end
nexitsym = nexit
end
return t
end
local function dumpwrite(s)
out:write(s)
end
-- Disassemble machine code.
local function dump_mcode(tr)
local info = traceinfo(tr)
if not info then return end
local mcode, addr, loop = tracemc(tr)
if not mcode then return end
if not disass then disass = require("jit.dis_"..jit.arch) end
if addr < 0 then addr = addr + 2^32 end
out:write("---- TRACE ", tr, " mcode ", #mcode, "\n")
local ctx = disass.create(mcode, addr, dumpwrite)
ctx.hexdump = 0
ctx.symtab = fillsymtab(tr, info.nexit)
if loop ~= 0 then
symtab[addr+loop] = "LOOP"
ctx:disass(0, loop)
out:write("->LOOP:\n")
ctx:disass(loop, #mcode-loop)
symtab[addr+loop] = nil
else
ctx:disass(0, #mcode)
end
end
------------------------------------------------------------------------------
local irtype_text = {
[0] = "nil",
"fal",
"tru",
"lud",
"str",
"p32",
"thr",
"pro",
"fun",
"p64",
"cdt",
"tab",
"udt",
"flt",
"num",
"i8 ",
"u8 ",
"i16",
"u16",
"int",
"u32",
"i64",
"u64",
"sfp",
}
local colortype_ansi = {
[0] = "%s",
"%s",
"%s",
"\027[36m%s\027[m",
"\027[32m%s\027[m",
"%s",
"\027[1m%s\027[m",
"%s",
"\027[1m%s\027[m",
"%s",
"\027[33m%s\027[m",
"\027[31m%s\027[m",
"\027[36m%s\027[m",
"\027[34m%s\027[m",
"\027[34m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
"\027[35m%s\027[m",
}
local function colorize_text(s)
return s
end
local function colorize_ansi(s, t, extra)
local out = format(colortype_ansi[t], s)
if extra then out = "\027[3m"..out end
return out
end
local irtype_ansi = setmetatable({},
{ __index = function(tab, t)
local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end })
local html_escape = { ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;", }
local function colorize_html(s, t, extra)
s = gsub(s, "[<>&]", html_escape)
return format('<span class="irt_%s%s">%s</span>',
irtype_text[t], extra and " irt_extra" or "", s)
end
local irtype_html = setmetatable({},
{ __index = function(tab, t)
local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end })
local header_html = [[
<style type="text/css">
background { background: #ffffff; color: #000000; }
pre.ljdump {
font-size: 10pt;
background: #f0f4ff;
color: #000000;
border: 1px solid #bfcfff;
padding: 0.5em;
margin-left: 2em;
margin-right: 2em;
}
span.irt_str { color: #00a000; }
span.irt_thr, span.irt_fun { color: #404040; font-weight: bold; }
span.irt_tab { color: #c00000; }
span.irt_udt, span.irt_lud { color: #00c0c0; }
span.irt_num { color: #4040c0; }
span.irt_int, span.irt_i8, span.irt_u8, span.irt_i16, span.irt_u16 { color: #b040b0; }
span.irt_extra { font-style: italic; }
</style>
]]
local colorize, irtype
-- Lookup tables to convert some literals into names.
local litname = {
["SLOAD "] = setmetatable({}, { __index = function(t, mode)
local s = ""
if band(mode, 1) ~= 0 then s = s.."P" end
if band(mode, 2) ~= 0 then s = s.."F" end
if band(mode, 4) ~= 0 then s = s.."T" end
if band(mode, 8) ~= 0 then s = s.."C" end
if band(mode, 16) ~= 0 then s = s.."R" end
if band(mode, 32) ~= 0 then s = s.."I" end
if band(mode, 64) ~= 0 then s = s.."K" end
t[mode] = s
return s
end}),
["XLOAD "] = { [0] = "", "R", "V", "RV", "U", "RU", "VU", "RVU", },
["CONV "] = setmetatable({}, { __index = function(t, mode)
local s = irtype[band(mode, 31)]
s = irtype[band(shr(mode, 5), 31)].."."..s
if band(mode, 0x800) ~= 0 then s = s.." sext" end
local c = shr(mode, 12)
if c == 1 then s = s.." none"
elseif c == 2 then s = s.." index"
elseif c == 3 then s = s.." check" end
t[mode] = s
return s
end}),
["FLOAD "] = vmdef.irfield,
["FREF "] = vmdef.irfield,
["FPMATH"] = vmdef.irfpm,
["TMPREF"] = { [0] = "", "IN", "OUT", "INOUT", "", "", "OUT2", "INOUT2" },
["BUFHDR"] = { [0] = "RESET", "APPEND", "WRITE" },
["TOSTR "] = { [0] = "INT", "NUM", "CHAR" },
}
local function ctlsub(c)
if c == "\n" then return "\\n"
elseif c == "\r" then return "\\r"
elseif c == "\t" then return "\\t"
else return format("\\%03d", byte(c))
end
end
local function fmtfunc(func, pc)
local fi = funcinfo(func, pc)
if fi.loc then
return fi.loc
elseif fi.ffid then
return vmdef.ffnames[fi.ffid]
elseif fi.addr then
return format("C:%x", fi.addr)
else
return "(?)"
end
end
local function formatk(tr, idx, sn)
local k, t, slot = tracek(tr, idx)
local tn = type(k)
local s
if tn == "number" then
if t < 12 then
s = k == 0 and "NULL" or format("[0x%08x]", k)
elseif band(sn or 0, 0x30000) ~= 0 then
s = band(sn, 0x20000) ~= 0 and "contpc" or "ftsz"
elseif k == 2^52+2^51 then
s = "bias"
else
local m = tonumber("0x1p-1026")
s = format(m ~= nil and 0 < k and k < m and "%+a" or "%+.14g", k)
end
elseif tn == "string" then
s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub))
elseif tn == "function" then
s = fmtfunc(k)
elseif tn == "table" then
s = format("{%p}", k)
elseif tn == "userdata" then
if t == 12 then
s = format("userdata:%p", k)
else
s = format("[%p]", k)
if s == "[NULL]" then s = "NULL" end
end
elseif t == 21 then -- int64_t
s = sub(tostring(k), 1, -3)
if sub(s, 1, 1) ~= "-" then s = "+"..s end
elseif sn == 0x1057fff then -- SNAP(1, SNAP_FRAME | SNAP_NORESTORE, REF_NIL)
return "----" -- Special case for LJ_FR2 slot 1.
else
s = tostring(k) -- For primitives.
end
s = colorize(format("%-4s", s), t, band(sn or 0, 0x100000) ~= 0)
if slot then
s = format("%s @%d", s, slot)
end
return s
end
local function printsnap(tr, snap)
local n = 2
for s=0,snap[1]-1 do
local sn = snap[n]
if shr(sn, 24) == s then
n = n + 1
local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS
if ref < 0 then
out:write(formatk(tr, ref, sn))
elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM
out:write(colorize(format("%04d/%04d", ref, ref+1), 14))
else
local m, ot, op1, op2 = traceir(tr, ref)
out:write(colorize(format("%04d", ref), band(ot, 31), band(sn, 0x100000) ~= 0))
end
out:write(band(sn, 0x10000) == 0 and " " or "|") -- SNAP_FRAME
else
out:write("---- ")
end
end
out:write("]\n")
end
-- Dump snapshots (not interleaved with IR).
local function dump_snap(tr)
out:write("---- TRACE ", tr, " snapshots\n")
for i=0,1000000000 do
local snap = tracesnap(tr, i)
if not snap then break end
out:write(format("#%-3d %04d [ ", i, snap[0]))
printsnap(tr, snap)
end
end
-- Return a register name or stack slot for a rid/sp location.
local function ridsp_name(ridsp, ins)
if not disass then disass = require("jit.dis_"..jit.arch) end
local rid, slot = band(ridsp, 0xff), shr(ridsp, 8)
if rid == 253 or rid == 254 then
return (slot == 0 or slot == 255) and " {sink" or format(" {%04d", ins-slot)
end
if ridsp > 255 then return format("[%x]", slot*4) end
if rid < 128 then return disass.regname(rid) end
return ""
end
-- Dump CALL* function ref and return optional ctype.
local function dumpcallfunc(tr, ins)
local ctype
if ins > 0 then
local m, ot, op1, op2 = traceir(tr, ins)
if band(ot, 31) == 0 then -- nil type means CARG(func, ctype).
ins = op1
ctype = formatk(tr, op2)
end
end
if ins < 0 then
out:write(format("[0x%x](", tonumber((tracek(tr, ins)))))
else
out:write(format("%04d (", ins))
end
return ctype
end
-- Recursively gather CALL* args and dump them.
local function dumpcallargs(tr, ins)
if ins < 0 then
out:write(formatk(tr, ins))
else
local m, ot, op1, op2 = traceir(tr, ins)
local oidx = 6*shr(ot, 8)
local op = sub(vmdef.irnames, oidx+1, oidx+6)
if op == "CARG " then
dumpcallargs(tr, op1)
if op2 < 0 then
out:write(" ", formatk(tr, op2))
else
out:write(" ", format("%04d", op2))
end
else
out:write(format("%04d", ins))
end
end
end
-- Dump IR and interleaved snapshots.
local function dump_ir(tr, dumpsnap, dumpreg)
local info = traceinfo(tr)
if not info then return end
local nins = info.nins
out:write("---- TRACE ", tr, " IR\n")
local irnames = vmdef.irnames
local snapref = 65536
local snap, snapno
if dumpsnap then
snap = tracesnap(tr, 0)
snapref = snap[0]
snapno = 0
end
for ins=1,nins do
if ins >= snapref then
if dumpreg then
out:write(format(".... SNAP #%-3d [ ", snapno))
else
out:write(format(".... SNAP #%-3d [ ", snapno))
end
printsnap(tr, snap)
snapno = snapno + 1
snap = tracesnap(tr, snapno)
snapref = snap and snap[0] or 65536
end
local m, ot, op1, op2, ridsp = traceir(tr, ins)
local oidx, t = 6*shr(ot, 8), band(ot, 31)
local op = sub(irnames, oidx+1, oidx+6)
if op == "LOOP " then
if dumpreg then
out:write(format("%04d ------------ LOOP ------------\n", ins))
else
out:write(format("%04d ------ LOOP ------------\n", ins))
end
elseif op ~= "NOP " and op ~= "CARG " and
(dumpreg or op ~= "RENAME") then
local rid = band(ridsp, 255)
if dumpreg then
out:write(format("%04d %-6s", ins, ridsp_name(ridsp, ins)))
else
out:write(format("%04d ", ins))
end
out:write(format("%s%s %s %s ",
(rid == 254 or rid == 253) and "}" or
(band(ot, 128) == 0 and " " or ">"),
band(ot, 64) == 0 and " " or "+",
irtype[t], op))
local m1, m2 = band(m, 3), band(m, 3*4)
if sub(op, 1, 4) == "CALL" then
local ctype
if m2 == 1*4 then -- op2 == IRMlit
out:write(format("%-10s (", vmdef.ircall[op2]))
else
ctype = dumpcallfunc(tr, op2)
end
if op1 ~= -1 then dumpcallargs(tr, op1) end
out:write(")")
if ctype then out:write(" ctype ", ctype) end
elseif op == "CNEW " and op2 == -1 then
out:write(formatk(tr, op1))
elseif m1 ~= 3 then -- op1 != IRMnone
if op1 < 0 then
out:write(formatk(tr, op1))
else
out:write(format(m1 == 0 and "%04d" or "#%-3d", op1))
end
if m2 ~= 3*4 then -- op2 != IRMnone
if m2 == 1*4 then -- op2 == IRMlit
local litn = litname[op]
if litn and litn[op2] then
out:write(" ", litn[op2])
elseif op == "UREFO " or op == "UREFC " then
out:write(format(" #%-3d", shr(op2, 8)))
else
out:write(format(" #%-3d", op2))
end
elseif op2 < 0 then
out:write(" ", formatk(tr, op2))
else
out:write(format(" %04d", op2))
end
end
end
out:write("\n")
end
end
if snap then
if dumpreg then
out:write(format(".... SNAP #%-3d [ ", snapno))
else
out:write(format(".... SNAP #%-3d [ ", snapno))
end
printsnap(tr, snap)
end
end
------------------------------------------------------------------------------
local recprefix = ""
local recdepth = 0
-- Format trace error message.
local function fmterr(err, info)
if type(err) == "number" then
if type(info) == "function" then info = fmtfunc(info) end
local fmt = vmdef.traceerr[err]
if fmt == "NYI: bytecode %s" then
local oidx = 6 * info
info = sub(vmdef.bcnames, oidx+1, oidx+6)
end
err = format(fmt, info)
end
return err
end
-- Dump trace states.
local function dump_trace(what, tr, func, pc, otr, oex)
if what == "stop" or (what == "abort" and dumpmode.a) then
if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == "stop")
elseif dumpmode.s then dump_snap(tr) end
if dumpmode.m then dump_mcode(tr) end
end
if what == "start" then
if dumpmode.H then out:write('<pre class="ljdump">\n') end
out:write("---- TRACE ", tr, " ", what)
if otr then out:write(" ", otr, "/", oex == -1 and "stitch" or oex) end
out:write(" ", fmtfunc(func, pc), "\n")
elseif what == "stop" or what == "abort" then
out:write("---- TRACE ", tr, " ", what)
if what == "abort" then
out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n")
else
local info = traceinfo(tr)
local link, ltype = info.link, info.linktype
if link == tr or link == 0 then
out:write(" -> ", ltype, "\n")
elseif ltype == "root" then
out:write(" -> ", link, "\n")
else
out:write(" -> ", link, " ", ltype, "\n")
end
end
if dumpmode.H then out:write("</pre>\n\n") else out:write("\n") end
else
if what == "flush" then symtab, nexitsym = {}, 0 end
out:write("---- TRACE ", what, "\n\n")
end
out:flush()
end
-- Dump recorded bytecode.
local function dump_record(tr, func, pc, depth)
if depth ~= recdepth then
recdepth = depth
recprefix = rep(" .", depth)
end
local line
if pc >= 0 then
line = bcline(func, pc, recprefix)
if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end
else
line = "0000 "..recprefix.." FUNCC \n"
end
if pc <= 0 then
out:write(sub(line, 1, -2), " ; ", fmtfunc(func), "\n")
else
out:write(line)
end
if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC
out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond.
end
end
------------------------------------------------------------------------------
local gpr64 = jit.arch:match("64")
local fprmips32 = jit.arch == "mips" or jit.arch == "mipsel"
-- Dump taken trace exits.
local function dump_texit(tr, ex, ngpr, nfpr, ...)
out:write("---- TRACE ", tr, " exit ", ex, "\n")
if dumpmode.X then
local regs = {...}
if gpr64 then
for i=1,ngpr do
out:write(format(" %016x", regs[i]))
if i % 4 == 0 then out:write("\n") end
end
else
for i=1,ngpr do
out:write(" ", tohex(regs[i]))
if i % 8 == 0 then out:write("\n") end
end
end
if fprmips32 then
for i=1,nfpr,2 do
out:write(format(" %+17.14g", regs[ngpr+i]))
if i % 8 == 7 then out:write("\n") end
end
else
for i=1,nfpr do
out:write(format(" %+17.14g", regs[ngpr+i]))
if i % 4 == 0 then out:write("\n") end
end
end
end
end
------------------------------------------------------------------------------
-- Detach dump handlers.
local function dumpoff()
if active then
active = false
jit.attach(dump_texit)
jit.attach(dump_record)
jit.attach(dump_trace)
if out and out ~= stdout and out ~= stderr then out:close() end
out = nil
end
end
-- Open the output file and attach dump handlers.
local function dumpon(opt, outfile)
if active then dumpoff() end
local term = os.getenv("TERM")
local colormode = (term and term:match("color") or os.getenv("COLORTERM")) and "A" or "T"
if opt then
opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end)
end
local m = { t=true, b=true, i=true, m=true, }
if opt and opt ~= "" then
local o = sub(opt, 1, 1)
if o ~= "+" and o ~= "-" then m = {} end
for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end
end
dumpmode = m
if m.t or m.b or m.i or m.s or m.m then
jit.attach(dump_trace, "trace")
end
if m.b then
jit.attach(dump_record, "record")
if not bcline then bcline = require("jit.bc").line end
end
if m.x or m.X then
jit.attach(dump_texit, "texit")
end
if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end
if outfile then
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
else
out = stdout
end
m[colormode] = true
if colormode == "A" then
colorize = colorize_ansi
irtype = irtype_ansi
elseif colormode == "H" then
colorize = colorize_html
irtype = irtype_html
out:write(header_html)
else
colorize = colorize_text
irtype = irtype_text
end
active = true
end
-- Public module functions.
return {
on = dumpon,
off = dumpoff,
start = dumpon -- For -j command line option.
}
+309
View File
@@ -0,0 +1,309 @@
----------------------------------------------------------------------------
-- LuaJIT profiler.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module is a simple command line interface to the built-in
-- low-overhead profiler of LuaJIT.
--
-- The lower-level API of the profiler is accessible via the "jit.profile"
-- module or the luaJIT_profile_* C API.
--
-- Example usage:
--
-- luajit -jp myapp.lua
-- luajit -jp=s myapp.lua
-- luajit -jp=-s myapp.lua
-- luajit -jp=vl myapp.lua
-- luajit -jp=G,profile.txt myapp.lua
--
-- The following dump features are available:
--
-- f Stack dump: function name, otherwise module:line. Default mode.
-- F Stack dump: ditto, but always prepend module.
-- l Stack dump: module:line.
-- <number> stack dump depth (callee < caller). Default: 1.
-- -<number> Inverse stack dump depth (caller > callee).
-- s Split stack dump after first stack level. Implies abs(depth) >= 2.
-- p Show full path for module names.
-- v Show VM states. Can be combined with stack dumps, e.g. vf or fv.
-- z Show zones. Can be combined with stack dumps, e.g. zf or fz.
-- r Show raw sample counts. Default: show percentages.
-- a Annotate excerpts from source code files.
-- A Annotate complete source code files.
-- G Produce raw output suitable for graphical tools (e.g. flame graphs).
-- m<number> Minimum sample percentage to be shown. Default: 3.
-- i<number> Sampling interval in milliseconds. Default: 10.
--
----------------------------------------------------------------------------
-- Cache some library functions and objects.
local jit = require("jit")
local profile = require("jit.profile")
local vmdef = require("jit.vmdef")
local math = math
local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor
local sort, format = table.sort, string.format
local stdout = io.stdout
local zone -- Load jit.zone module on demand.
-- Output file handle.
local out
------------------------------------------------------------------------------
local prof_ud
local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth
local prof_ann, prof_count1, prof_count2, prof_samples
local map_vmmode = {
N = "Compiled",
I = "Interpreted",
C = "C code",
G = "Garbage Collector",
J = "JIT Compiler",
}
-- Profiler callback.
local function prof_cb(th, samples, vmmode)
prof_samples = prof_samples + samples
local key_stack, key_stack2, key_state
-- Collect keys for sample.
if prof_states then
if prof_states == "v" then
key_state = map_vmmode[vmmode] or vmmode
else
key_state = zone:get() or "(none)"
end
end
if prof_fmt then
key_stack = profile.dumpstack(th, prof_fmt, prof_depth)
key_stack = key_stack:gsub("%[builtin#(%d+)%]", function(x)
return vmdef.ffnames[tonumber(x)]
end)
if prof_split == 2 then
local k1, k2 = key_stack:match("(.-) [<>] (.*)")
if k2 then key_stack, key_stack2 = k1, k2 end
elseif prof_split == 3 then
key_stack2 = profile.dumpstack(th, "l", 1)
end
end
-- Order keys.
local k1, k2
if prof_split == 1 then
if key_state then
k1 = key_state
if key_stack then k2 = key_stack end
end
elseif key_stack then
k1 = key_stack
if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end
end
-- Coalesce samples in one or two levels.
if k1 then
local t1 = prof_count1
t1[k1] = (t1[k1] or 0) + samples
if k2 then
local t2 = prof_count2
local t3 = t2[k1]
if not t3 then t3 = {}; t2[k1] = t3 end
t3[k2] = (t3[k2] or 0) + samples
end
end
end
------------------------------------------------------------------------------
-- Show top N list.
local function prof_top(count1, count2, samples, indent)
local t, n = {}, 0
for k in pairs(count1) do
n = n + 1
t[n] = k
end
sort(t, function(a, b) return count1[a] > count1[b] end)
for i=1,n do
local k = t[i]
local v = count1[k]
local pct = floor(v*100/samples + 0.5)
if pct < prof_min then break end
if not prof_raw then
out:write(format("%s%2d%% %s\n", indent, pct, k))
elseif prof_raw == "r" then
out:write(format("%s%5d %s\n", indent, v, k))
else
out:write(format("%s %d\n", k, v))
end
if count2 then
local r = count2[k]
if r then
prof_top(r, nil, v, (prof_split == 3 or prof_split == 1) and " -- " or
(prof_depth < 0 and " -> " or " <- "))
end
end
end
end
-- Annotate source code
local function prof_annotate(count1, samples)
local files = {}
local ms = 0
for k, v in pairs(count1) do
local pct = floor(v*100/samples + 0.5)
ms = math.max(ms, v)
if pct >= prof_min then
local file, line = k:match("^(.*):(%d+)$")
if not file then file = k; line = 0 end
local fl = files[file]
if not fl then fl = {}; files[file] = fl; files[#files+1] = file end
line = tonumber(line)
fl[line] = prof_raw and v or pct
end
end
sort(files)
local fmtv, fmtn = " %3d%% | %s\n", " | %s\n"
if prof_raw then
local n = math.max(5, math.ceil(math.log10(ms)))
fmtv = "%"..n.."d | %s\n"
fmtn = (" "):rep(n).." | %s\n"
end
local ann = prof_ann
for _, file in ipairs(files) do
local f0 = file:byte()
if f0 == 40 or f0 == 91 then
out:write(format("\n====== %s ======\n[Cannot annotate non-file]\n", file))
break
end
local fp, err = io.open(file)
if not fp then
out:write(format("====== ERROR: %s: %s\n", file, err))
break
end
out:write(format("\n====== %s ======\n", file))
local fl = files[file]
local n, show = 1, false
if ann ~= 0 then
for i=1,ann do
if fl[i] then show = true; out:write("@@ 1 @@\n"); break end
end
end
for line in fp:lines() do
if line:byte() == 27 then
out:write("[Cannot annotate bytecode file]\n")
break
end
local v = fl[n]
if ann ~= 0 then
local v2 = fl[n+ann]
if show then
if v2 then show = n+ann elseif v then show = n
elseif show+ann < n then show = false end
elseif v2 then
show = n+ann
out:write(format("@@ %d @@\n", n))
end
if not show then goto next end
end
if v then
out:write(format(fmtv, v, line))
else
out:write(format(fmtn, line))
end
::next::
n = n + 1
end
fp:close()
end
end
------------------------------------------------------------------------------
-- Finish profiling and dump result.
local function prof_finish()
if prof_ud then
profile.stop()
local samples = prof_samples
if samples == 0 then
if prof_raw ~= true then out:write("[No samples collected]\n") end
elseif prof_ann then
prof_annotate(prof_count1, samples)
else
prof_top(prof_count1, prof_count2, samples, "")
end
prof_count1 = nil
prof_count2 = nil
prof_ud = nil
if out ~= stdout then out:close() end
end
end
-- Start profiling.
local function prof_start(mode)
local interval = ""
mode = mode:gsub("i%d*", function(s) interval = s; return "" end)
prof_min = 3
mode = mode:gsub("m(%d+)", function(s) prof_min = tonumber(s); return "" end)
prof_depth = 1
mode = mode:gsub("%-?%d+", function(s) prof_depth = tonumber(s); return "" end)
local m = {}
for c in mode:gmatch(".") do m[c] = c end
prof_states = m.z or m.v
if prof_states == "z" then zone = require("jit.zone") end
local scope = m.l or m.f or m.F or (prof_states and "" or "f")
local flags = (m.p or "")
prof_raw = m.r
if m.s then
prof_split = 2
if prof_depth == -1 or m["-"] then prof_depth = -2
elseif prof_depth == 1 then prof_depth = 2 end
elseif mode:find("[fF].*l") then
scope = "l"
prof_split = 3
else
prof_split = (scope == "" or mode:find("[zv].*[lfF]")) and 1 or 0
end
prof_ann = m.A and 0 or (m.a and 3)
if prof_ann then
scope = "l"
prof_fmt = "pl"
prof_split = 0
prof_depth = 1
elseif m.G and scope ~= "" then
prof_fmt = flags..scope.."Z;"
prof_depth = -100
prof_raw = true
prof_min = 0
elseif scope == "" then
prof_fmt = false
else
local sc = prof_split == 3 and m.f or m.F or scope
prof_fmt = flags..sc..(prof_depth >= 0 and "Z < " or "Z > ")
end
prof_count1 = {}
prof_count2 = {}
prof_samples = 0
profile.start(scope:lower()..interval, prof_cb)
prof_ud = newproxy(true)
getmetatable(prof_ud).__gc = prof_finish
end
------------------------------------------------------------------------------
local function start(mode, outfile)
if not outfile then outfile = os.getenv("LUAJIT_PROFILEFILE") end
if outfile then
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
else
out = stdout
end
prof_start(mode or "f")
end
-- Public module functions.
return {
start = start, -- For -j command line option.
stop = prof_finish
}
+174
View File
@@ -0,0 +1,174 @@
----------------------------------------------------------------------------
-- Verbose mode of the LuaJIT compiler.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module shows verbose information about the progress of the
-- JIT compiler. It prints one line for each generated trace. This module
-- is useful to see which code has been compiled or where the compiler
-- punts and falls back to the interpreter.
--
-- Example usage:
--
-- luajit -jv -e "for i=1,1000 do for j=1,1000 do end end"
-- luajit -jv=myapp.out myapp.lua
--
-- Default output is to stderr. To redirect the output to a file, pass a
-- filename as an argument (use '-' for stdout) or set the environment
-- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the
-- module is started.
--
-- The output from the first example should look like this:
--
-- [TRACE 1 (command line):1 loop]
-- [TRACE 2 (1/3) (command line):1 -> 1]
--
-- The first number in each line is the internal trace number. Next are
-- the file name ('(command line)') and the line number (':1') where the
-- trace has started. Side traces also show the parent trace number and
-- the exit number where they are attached to in parentheses ('(1/3)').
-- An arrow at the end shows where the trace links to ('-> 1'), unless
-- it loops to itself.
--
-- In this case the inner loop gets hot and is traced first, generating
-- a root trace. Then the last exit from the 1st trace gets hot, too,
-- and triggers generation of the 2nd trace. The side trace follows the
-- path along the outer loop and *around* the inner loop, back to its
-- start, and then links to the 1st trace. Yes, this may seem unusual,
-- if you know how traditional compilers work. Trace compilers are full
-- of surprises like this -- have fun! :-)
--
-- Aborted traces are shown like this:
--
-- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50]
--
-- Don't worry -- trace aborts are quite common, even in programs which
-- can be fully compiled. The compiler may retry several times until it
-- finds a suitable trace.
--
-- Of course this doesn't work with features that are not-yet-implemented
-- (NYI error messages). The VM simply falls back to the interpreter. This
-- may not matter at all if the particular trace is not very high up in
-- the CPU usage profile. Oh, and the interpreter is quite fast, too.
--
-- Also check out the -jdump module, which prints all the gory details.
--
------------------------------------------------------------------------------
-- Cache some library functions and objects.
local jit = require("jit")
local jutil = require("jit.util")
local vmdef = require("jit.vmdef")
local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo
local type, sub, format = type, string.sub, string.format
local stdout, stderr = io.stdout, io.stderr
-- Active flag and output file handle.
local active, out
------------------------------------------------------------------------------
local startloc, startex
local function fmtfunc(func, pc)
local fi = funcinfo(func, pc)
if fi.loc then
return fi.loc
elseif fi.ffid then
return vmdef.ffnames[fi.ffid]
elseif fi.addr then
return format("C:%x", fi.addr)
else
return "(?)"
end
end
-- Format trace error message.
local function fmterr(err, info)
if type(err) == "number" then
if type(info) == "function" then info = fmtfunc(info) end
local fmt = vmdef.traceerr[err]
if fmt == "NYI: bytecode %s" then
local oidx = 6 * info
info = sub(vmdef.bcnames, oidx+1, oidx+6)
end
err = format(fmt, info)
end
return err
end
-- Dump trace states.
local function dump_trace(what, tr, func, pc, otr, oex)
if what == "start" then
startloc = fmtfunc(func, pc)
startex = otr and "("..otr.."/"..(oex == -1 and "stitch" or oex)..") " or ""
else
if what == "abort" then
local loc = fmtfunc(func, pc)
if loc ~= startloc then
out:write(format("[TRACE --- %s%s -- %s at %s]\n",
startex, startloc, fmterr(otr, oex), loc))
else
out:write(format("[TRACE --- %s%s -- %s]\n",
startex, startloc, fmterr(otr, oex)))
end
elseif what == "stop" then
local info = traceinfo(tr)
local link, ltype = info.link, info.linktype
if ltype == "interpreter" then
out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n",
tr, startex, startloc))
elseif ltype == "stitch" then
out:write(format("[TRACE %3s %s%s %s %s]\n",
tr, startex, startloc, ltype, fmtfunc(func, pc)))
elseif link == tr or link == 0 then
out:write(format("[TRACE %3s %s%s %s]\n",
tr, startex, startloc, ltype))
elseif ltype == "root" then
out:write(format("[TRACE %3s %s%s -> %d]\n",
tr, startex, startloc, link))
else
out:write(format("[TRACE %3s %s%s -> %d %s]\n",
tr, startex, startloc, link, ltype))
end
else
out:write(format("[TRACE %s]\n", what))
end
out:flush()
end
end
------------------------------------------------------------------------------
-- Detach dump handlers.
local function dumpoff()
if active then
active = false
jit.attach(dump_trace)
if out and out ~= stdout and out ~= stderr then out:close() end
out = nil
end
end
-- Open the output file and attach dump handlers.
local function dumpon(outfile)
if active then dumpoff() end
if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end
if outfile then
out = outfile == "-" and stdout or assert(io.open(outfile, "w"))
else
out = stderr
end
jit.attach(dump_trace, "trace")
active = true
end
-- Public module functions.
return {
on = dumpon,
off = dumpoff,
start = dumpon -- For -j command line option.
}
+45
View File
@@ -0,0 +1,45 @@
----------------------------------------------------------------------------
-- LuaJIT profiler zones.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------
--
-- This module implements a simple hierarchical zone model.
--
-- Example usage:
--
-- local zone = require("jit.zone")
-- zone("AI")
-- ...
-- zone("A*")
-- ...
-- print(zone:get()) --> "A*"
-- ...
-- zone()
-- ...
-- print(zone:get()) --> "AI"
-- ...
-- zone()
--
----------------------------------------------------------------------------
local remove = table.remove
return setmetatable({
flush = function(t)
for i=#t,1,-1 do t[i] = nil end
end,
get = function(t)
return t[#t]
end
}, {
__call = function(t, zone)
if zone then
t[#t+1] = zone
else
return (assert(remove(t), "empty zone stack"))
end
end
})
+166
View File
@@ -0,0 +1,166 @@
/*
** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#ifndef lauxlib_h
#define lauxlib_h
#include <stddef.h>
#include <stdio.h>
#include "lua.h"
/* extra error code for `luaL_load' */
#define LUA_ERRFILE (LUA_ERRERR+1)
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
const luaL_Reg *l);
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
const char *def, size_t *l);
#ifdef LUAJIT_INTONLY
#define luaL_checknumber luaL_checkinteger
#define luaL_optnumber luaL_optinteger
#else
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
#endif
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
lua_Integer def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
const char *const lst[]);
/* pre-defined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
LUALIB_API int (luaL_ref) (lua_State *L, int t);
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
const char *name);
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);
LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
const char *fname, int szhint);
/* From Lua 5.2. */
LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname);
LUALIB_API int luaL_execresult(lua_State *L, int stat);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
const char *name, const char *mode);
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
int level);
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
int sizehint);
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define luaL_argcheck(L, cond,numarg,extramsg) \
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
/* From Lua 5.2. */
#define luaL_newlibtable(L, l) \
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
#define luaL_newlib(L, l) (luaL_newlibtable(L, l), luaL_setfuncs(L, l, 0))
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
typedef struct luaL_Buffer {
char *p; /* current position in buffer */
int lvl; /* number of strings in the stack (level) */
lua_State *L;
char buffer[LUAL_BUFFERSIZE];
} luaL_Buffer;
#define luaL_addchar(B,c) \
((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
(*(B)->p++ = (char)(c)))
/* compatibility only */
#define luaL_putchar(B,c) luaL_addchar(B,c)
#define luaL_addsize(B,n) ((B)->p += (n))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
/* }====================================================== */
#endif
+401
View File
@@ -0,0 +1,401 @@
/*
** Auxiliary library for the Lua/C API.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** Major parts taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#define lib_aux_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_state.h"
#include "lj_trace.h"
#include "lj_lib.h"
#include "lj_vmevent.h"
#if LJ_TARGET_POSIX
#include <sys/wait.h>
#endif
/* -- I/O error handling -------------------------------------------------- */
LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname)
{
if (stat) {
setboolV(L->top++, 1);
return 1;
} else {
int en = errno; /* Lua API calls may change this value. */
setnilV(L->top++);
if (fname)
lua_pushfstring(L, "%s: %s", fname, strerror(en));
else
lua_pushfstring(L, "%s", strerror(en));
setintV(L->top++, en);
lj_trace_abort(G(L));
return 3;
}
}
LUALIB_API int luaL_execresult(lua_State *L, int stat)
{
if (stat != -1) {
#if LJ_TARGET_POSIX
if (WIFSIGNALED(stat)) {
stat = WTERMSIG(stat);
setnilV(L->top++);
lua_pushliteral(L, "signal");
} else {
if (WIFEXITED(stat))
stat = WEXITSTATUS(stat);
if (stat == 0)
setboolV(L->top++, 1);
else
setnilV(L->top++);
lua_pushliteral(L, "exit");
}
#else
if (stat == 0)
setboolV(L->top++, 1);
else
setnilV(L->top++);
lua_pushliteral(L, "exit");
#endif
setintV(L->top++, stat);
return 3;
}
return luaL_fileresult(L, 0, NULL);
}
/* -- Module registration ------------------------------------------------- */
LUALIB_API const char *luaL_findtable(lua_State *L, int idx,
const char *fname, int szhint)
{
const char *e;
lua_pushvalue(L, idx);
do {
e = strchr(fname, '.');
if (e == NULL) e = fname + strlen(fname);
lua_pushlstring(L, fname, (size_t)(e - fname));
lua_rawget(L, -2);
if (lua_isnil(L, -1)) { /* no such field? */
lua_pop(L, 1); /* remove this nil */
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
lua_pushlstring(L, fname, (size_t)(e - fname));
lua_pushvalue(L, -2);
lua_settable(L, -4); /* set new table into field */
} else if (!lua_istable(L, -1)) { /* field has a non-table value? */
lua_pop(L, 2); /* remove table and value */
return fname; /* return problematic part of the name */
}
lua_remove(L, -2); /* remove previous table */
fname = e + 1;
} while (*e == '.');
return NULL;
}
static int libsize(const luaL_Reg *l)
{
int size = 0;
for (; l && l->name; l++) size++;
return size;
}
LUALIB_API void luaL_pushmodule(lua_State *L, const char *modname, int sizehint)
{
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
lua_getfield(L, -1, modname);
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, sizehint) != NULL)
lj_err_callerv(L, LJ_ERR_BADMODN, modname);
lua_pushvalue(L, -1);
lua_setfield(L, -3, modname); /* _LOADED[modname] = new table. */
}
lua_remove(L, -2); /* Remove _LOADED table. */
}
LUALIB_API void luaL_openlib(lua_State *L, const char *libname,
const luaL_Reg *l, int nup)
{
lj_lib_checkfpu(L);
if (libname) {
luaL_pushmodule(L, libname, libsize(l));
lua_insert(L, -(nup + 1)); /* Move module table below upvalues. */
}
if (l)
luaL_setfuncs(L, l, nup);
else
lua_pop(L, nup); /* Remove upvalues. */
}
LUALIB_API void luaL_register(lua_State *L, const char *libname,
const luaL_Reg *l)
{
luaL_openlib(L, libname, l, 0);
}
LUALIB_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup)
{
luaL_checkstack(L, nup, "too many upvalues");
for (; l->name; l++) {
int i;
for (i = 0; i < nup; i++) /* Copy upvalues to the top. */
lua_pushvalue(L, -nup);
lua_pushcclosure(L, l->func, nup);
lua_setfield(L, -(nup + 2), l->name);
}
lua_pop(L, nup); /* Remove upvalues. */
}
LUALIB_API const char *luaL_gsub(lua_State *L, const char *s,
const char *p, const char *r)
{
const char *wild;
size_t l = strlen(p);
luaL_Buffer b;
luaL_buffinit(L, &b);
while ((wild = strstr(s, p)) != NULL) {
luaL_addlstring(&b, s, (size_t)(wild - s)); /* push prefix */
luaL_addstring(&b, r); /* push replacement in place of pattern */
s = wild + l; /* continue after `p' */
}
luaL_addstring(&b, s); /* push last suffix */
luaL_pushresult(&b);
return lua_tostring(L, -1);
}
/* -- Buffer handling ----------------------------------------------------- */
#define bufflen(B) ((size_t)((B)->p - (B)->buffer))
#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
static int emptybuffer(luaL_Buffer *B)
{
size_t l = bufflen(B);
if (l == 0)
return 0; /* put nothing on stack */
lua_pushlstring(B->L, B->buffer, l);
B->p = B->buffer;
B->lvl++;
return 1;
}
static void adjuststack(luaL_Buffer *B)
{
if (B->lvl > 1) {
lua_State *L = B->L;
int toget = 1; /* number of levels to concat */
size_t toplen = lua_strlen(L, -1);
do {
size_t l = lua_strlen(L, -(toget+1));
if (!(B->lvl - toget + 1 >= LUA_MINSTACK/2 || toplen > l))
break;
toplen += l;
toget++;
} while (toget < B->lvl);
lua_concat(L, toget);
B->lvl = B->lvl - toget + 1;
}
}
LUALIB_API char *luaL_prepbuffer(luaL_Buffer *B)
{
if (emptybuffer(B))
adjuststack(B);
return B->buffer;
}
LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l)
{
if (l <= bufffree(B)) {
memcpy(B->p, s, l);
B->p += l;
} else {
emptybuffer(B);
lua_pushlstring(B->L, s, l);
B->lvl++;
adjuststack(B);
}
}
LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s)
{
luaL_addlstring(B, s, strlen(s));
}
LUALIB_API void luaL_pushresult(luaL_Buffer *B)
{
emptybuffer(B);
lua_concat(B->L, B->lvl);
B->lvl = 1;
}
LUALIB_API void luaL_addvalue(luaL_Buffer *B)
{
lua_State *L = B->L;
size_t vl;
const char *s = lua_tolstring(L, -1, &vl);
if (vl <= bufffree(B)) { /* fit into buffer? */
memcpy(B->p, s, vl); /* put it there */
B->p += vl;
lua_pop(L, 1); /* remove from stack */
} else {
if (emptybuffer(B))
lua_insert(L, -2); /* put buffer before new value */
B->lvl++; /* add new value into B stack */
adjuststack(B);
}
}
LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
{
B->L = L;
B->p = B->buffer;
B->lvl = 0;
}
/* -- Reference management ------------------------------------------------ */
#define FREELIST_REF 0
/* Convert a stack index to an absolute index. */
#define abs_index(L, i) \
((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
LUALIB_API int luaL_ref(lua_State *L, int t)
{
int ref;
t = abs_index(L, t);
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* remove from stack */
return LUA_REFNIL; /* `nil' has a unique fixed reference */
}
lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */
lua_pop(L, 1); /* remove it from stack */
if (ref != 0) { /* any free element? */
lua_rawgeti(L, t, ref); /* remove it from list */
lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
} else { /* no free elements */
ref = (int)lua_objlen(L, t);
ref++; /* create new reference */
}
lua_rawseti(L, t, ref);
return ref;
}
LUALIB_API void luaL_unref(lua_State *L, int t, int ref)
{
if (ref >= 0) {
t = abs_index(L, t);
lua_rawgeti(L, t, FREELIST_REF);
lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
lua_pushinteger(L, ref);
lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
}
}
/* -- Default allocator and panic function -------------------------------- */
static int panic(lua_State *L)
{
const char *s = lua_tostring(L, -1);
fputs("PANIC: unprotected error in call to Lua API (", stderr);
fputs(s ? s : "?", stderr);
fputc(')', stderr); fputc('\n', stderr);
fflush(stderr);
return 0;
}
#ifndef LUAJIT_DISABLE_VMEVENT
static int error_finalizer(lua_State *L)
{
const char *s = lua_tostring(L, -1);
fputs("ERROR in finalizer: ", stderr);
fputs(s ? s : "?", stderr);
fputc('\n', stderr);
fflush(stderr);
return 0;
}
#endif
#ifdef LUAJIT_USE_SYSMALLOC
#if LJ_64 && !LJ_GC64 && !defined(LUAJIT_USE_VALGRIND)
#error "Must use builtin allocator for 64 bit target"
#endif
static void *mem_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
(void)ud;
(void)osize;
if (nsize == 0) {
free(ptr);
return NULL;
} else {
return realloc(ptr, nsize);
}
}
LUALIB_API lua_State *luaL_newstate(void)
{
lua_State *L = lua_newstate(mem_alloc, NULL);
if (L) {
G(L)->panic = panic;
#ifndef LUAJIT_DISABLE_VMEVENT
luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
lua_pushcfunction(L, error_finalizer);
lua_rawseti(L, -2, VMEVENT_HASH(LJ_VMEVENT_ERRFIN));
G(L)->vmevmask = VMEVENT_MASK(LJ_VMEVENT_ERRFIN);
L->top--;
#endif
}
return L;
}
#else
LUALIB_API lua_State *luaL_newstate(void)
{
lua_State *L;
#if LJ_64 && !LJ_GC64
L = lj_state_newstate(LJ_ALLOCF_INTERNAL, NULL);
#else
L = lua_newstate(LJ_ALLOCF_INTERNAL, NULL);
#endif
if (L) {
G(L)->panic = panic;
#ifndef LUAJIT_DISABLE_VMEVENT
luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
lua_pushcfunction(L, error_finalizer);
lua_rawseti(L, -2, VMEVENT_HASH(LJ_VMEVENT_ERRFIN));
G(L)->vmevmask = VMEVENT_MASK(LJ_VMEVENT_ERRFIN);
L->top--;
#endif
}
return L;
}
#if LJ_64 && !LJ_GC64
LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
{
UNUSED(f); UNUSED(ud);
fputs("Must use luaL_newstate() for 64 bit target\n", stderr);
return NULL;
}
#endif
#endif
+709
View File
@@ -0,0 +1,709 @@
/*
** Base and coroutine library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2011 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#include <stdio.h>
#define lib_base_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_debug.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_meta.h"
#include "lj_state.h"
#include "lj_frame.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_cconv.h"
#endif
#include "lj_bc.h"
#include "lj_ff.h"
#include "lj_dispatch.h"
#include "lj_char.h"
#include "lj_strscan.h"
#include "lj_strfmt.h"
#include "lj_lib.h"
/* -- Base library: checks ------------------------------------------------ */
#define LJLIB_MODULE_base
LJLIB_ASM(assert) LJLIB_REC(.)
{
lj_lib_checkany(L, 1);
if (L->top == L->base+1)
lj_err_caller(L, LJ_ERR_ASSERT);
else if (tvisstr(L->base+1) || tvisnumber(L->base+1))
lj_err_callermsg(L, strdata(lj_lib_checkstr(L, 2)));
else
lj_err_run(L);
return FFH_UNREACHABLE;
}
/* ORDER LJ_T */
LJLIB_PUSH("nil")
LJLIB_PUSH("boolean")
LJLIB_PUSH(top-1) /* boolean */
LJLIB_PUSH("userdata")
LJLIB_PUSH("string")
LJLIB_PUSH("upval")
LJLIB_PUSH("thread")
LJLIB_PUSH("proto")
LJLIB_PUSH("function")
LJLIB_PUSH("trace")
LJLIB_PUSH("cdata")
LJLIB_PUSH("table")
LJLIB_PUSH(top-9) /* userdata */
LJLIB_PUSH("number")
LJLIB_ASM_(type) LJLIB_REC(.)
/* Recycle the lj_lib_checkany(L, 1) from assert. */
/* -- Base library: iterators --------------------------------------------- */
/* This solves a circular dependency problem -- change FF_next_N as needed. */
LJ_STATIC_ASSERT((int)FF_next == FF_next_N);
LJLIB_ASM(next) LJLIB_REC(.)
{
lj_lib_checktab(L, 1);
lj_err_msg(L, LJ_ERR_NEXTIDX);
return FFH_UNREACHABLE;
}
#if LJ_52 || LJ_HASFFI
static int ffh_pairs(lua_State *L, MMS mm)
{
TValue *o = lj_lib_checkany(L, 1);
cTValue *mo = lj_meta_lookup(L, o, mm);
if ((LJ_52 || tviscdata(o)) && !tvisnil(mo)) {
L->top = o+1; /* Only keep one argument. */
copyTV(L, L->base-1-LJ_FR2, mo); /* Replace callable. */
return FFH_TAILCALL;
} else {
if (!tvistab(o)) lj_err_argt(L, 1, LUA_TTABLE);
if (LJ_FR2) { copyTV(L, o-1, o); o--; }
setfuncV(L, o-1, funcV(lj_lib_upvalue(L, 1)));
if (mm == MM_pairs) setnilV(o+1); else setintV(o+1, 0);
return FFH_RES(3);
}
}
#else
#define ffh_pairs(L, mm) (lj_lib_checktab(L, 1), FFH_UNREACHABLE)
#endif
LJLIB_PUSH(lastcl)
LJLIB_ASM(pairs) LJLIB_REC(xpairs 0)
{
return ffh_pairs(L, MM_pairs);
}
LJLIB_NOREGUV LJLIB_ASM(ipairs_aux) LJLIB_REC(.)
{
lj_lib_checktab(L, 1);
lj_lib_checkint(L, 2);
return FFH_UNREACHABLE;
}
LJLIB_PUSH(lastcl)
LJLIB_ASM(ipairs) LJLIB_REC(xpairs 1)
{
return ffh_pairs(L, MM_ipairs);
}
/* -- Base library: getters and setters ----------------------------------- */
LJLIB_ASM_(getmetatable) LJLIB_REC(.)
/* Recycle the lj_lib_checkany(L, 1) from assert. */
LJLIB_ASM(setmetatable) LJLIB_REC(.)
{
GCtab *t = lj_lib_checktab(L, 1);
GCtab *mt = lj_lib_checktabornil(L, 2);
if (!tvisnil(lj_meta_lookup(L, L->base, MM_metatable)))
lj_err_caller(L, LJ_ERR_PROTMT);
setgcref(t->metatable, obj2gco(mt));
if (mt) { lj_gc_objbarriert(L, t, mt); }
settabV(L, L->base-1-LJ_FR2, t);
return FFH_RES(1);
}
LJLIB_CF(getfenv) LJLIB_REC(.)
{
GCfunc *fn;
cTValue *o = L->base;
if (!(o < L->top && tvisfunc(o))) {
int level = lj_lib_optint(L, 1, 1);
o = lj_debug_frame(L, level, &level);
if (o == NULL)
lj_err_arg(L, 1, LJ_ERR_INVLVL);
if (LJ_FR2) o--;
}
fn = &gcval(o)->fn;
settabV(L, L->top++, isluafunc(fn) ? tabref(fn->l.env) : tabref(L->env));
return 1;
}
LJLIB_CF(setfenv)
{
GCfunc *fn;
GCtab *t = lj_lib_checktab(L, 2);
cTValue *o = L->base;
if (!(o < L->top && tvisfunc(o))) {
int level = lj_lib_checkint(L, 1);
if (level == 0) {
/* NOBARRIER: A thread (i.e. L) is never black. */
setgcref(L->env, obj2gco(t));
return 0;
}
o = lj_debug_frame(L, level, &level);
if (o == NULL)
lj_err_arg(L, 1, LJ_ERR_INVLVL);
if (LJ_FR2) o--;
}
fn = &gcval(o)->fn;
if (!isluafunc(fn))
lj_err_caller(L, LJ_ERR_SETFENV);
setgcref(fn->l.env, obj2gco(t));
lj_gc_objbarrier(L, obj2gco(fn), t);
setfuncV(L, L->top++, fn);
return 1;
}
LJLIB_ASM(rawget) LJLIB_REC(.)
{
lj_lib_checktab(L, 1);
lj_lib_checkany(L, 2);
return FFH_UNREACHABLE;
}
LJLIB_CF(rawset) LJLIB_REC(.)
{
lj_lib_checktab(L, 1);
lj_lib_checkany(L, 2);
L->top = 1+lj_lib_checkany(L, 3);
lua_rawset(L, 1);
return 1;
}
LJLIB_CF(rawequal) LJLIB_REC(.)
{
cTValue *o1 = lj_lib_checkany(L, 1);
cTValue *o2 = lj_lib_checkany(L, 2);
setboolV(L->top-1, lj_obj_equal(o1, o2));
return 1;
}
#if LJ_52
LJLIB_CF(rawlen) LJLIB_REC(.)
{
cTValue *o = L->base;
int32_t len;
if (L->top > o && tvisstr(o))
len = (int32_t)strV(o)->len;
else
len = (int32_t)lj_tab_len(lj_lib_checktab(L, 1));
setintV(L->top-1, len);
return 1;
}
#endif
LJLIB_CF(unpack)
{
GCtab *t = lj_lib_checktab(L, 1);
int32_t n, i = lj_lib_optint(L, 2, 1);
int32_t e = (L->base+3-1 < L->top && !tvisnil(L->base+3-1)) ?
lj_lib_checkint(L, 3) : (int32_t)lj_tab_len(t);
uint32_t nu;
if (i > e) return 0;
nu = (uint32_t)e - (uint32_t)i;
n = (int32_t)(nu+1);
if (nu >= LUAI_MAXCSTACK || !lua_checkstack(L, n))
lj_err_caller(L, LJ_ERR_UNPACK);
do {
cTValue *tv = lj_tab_getint(t, i);
if (tv) {
copyTV(L, L->top++, tv);
} else {
setnilV(L->top++);
}
} while (i++ < e);
return n;
}
LJLIB_CF(select) LJLIB_REC(.)
{
int32_t n = (int32_t)(L->top - L->base);
if (n >= 1 && tvisstr(L->base) && *strVdata(L->base) == '#') {
setintV(L->top-1, n-1);
return 1;
} else {
int32_t i = lj_lib_checkint(L, 1);
if (i < 0) i = n + i; else if (i > n) i = n;
if (i < 1)
lj_err_arg(L, 1, LJ_ERR_IDXRNG);
return n - i;
}
}
/* -- Base library: conversions ------------------------------------------- */
LJLIB_ASM(tonumber) LJLIB_REC(.)
{
int32_t base = lj_lib_optint(L, 2, 10);
if (base == 10) {
TValue *o = lj_lib_checkany(L, 1);
if (lj_strscan_numberobj(o)) {
copyTV(L, L->base-1-LJ_FR2, o);
return FFH_RES(1);
}
#if LJ_HASFFI
if (tviscdata(o)) {
CTState *cts = ctype_cts(L);
CType *ct = lj_ctype_rawref(cts, cdataV(o)->ctypeid);
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
if (ctype_isnum(ct->info) || ctype_iscomplex(ct->info)) {
if (LJ_DUALNUM && ctype_isinteger_or_bool(ct->info) &&
ct->size <= 4 && !(ct->size == 4 && (ct->info & CTF_UNSIGNED))) {
int32_t i;
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o, 0);
setintV(L->base-1-LJ_FR2, i);
return FFH_RES(1);
}
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_DOUBLE),
(uint8_t *)&(L->base-1-LJ_FR2)->n, o, 0);
return FFH_RES(1);
}
}
#endif
} else {
const char *p = strdata(lj_lib_checkstr(L, 1));
char *ep;
unsigned int neg = 0;
unsigned long ul;
if (base < 2 || base > 36)
lj_err_arg(L, 2, LJ_ERR_BASERNG);
while (lj_char_isspace((unsigned char)(*p))) p++;
if (*p == '-') { p++; neg = 1; } else if (*p == '+') { p++; }
if (lj_char_isalnum((unsigned char)(*p))) {
ul = strtoul(p, &ep, base);
if (p != ep) {
while (lj_char_isspace((unsigned char)(*ep))) ep++;
if (*ep == '\0') {
if (LJ_DUALNUM && LJ_LIKELY(ul < 0x80000000u+neg)) {
if (neg) ul = ~ul+1u;
setintV(L->base-1-LJ_FR2, (int32_t)ul);
} else {
lua_Number n = (lua_Number)ul;
if (neg) n = -n;
setnumV(L->base-1-LJ_FR2, n);
}
return FFH_RES(1);
}
}
}
}
setnilV(L->base-1-LJ_FR2);
return FFH_RES(1);
}
LJLIB_ASM(tostring) LJLIB_REC(.)
{
TValue *o = lj_lib_checkany(L, 1);
cTValue *mo;
L->top = o+1; /* Only keep one argument. */
if (!tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
copyTV(L, L->base-1-LJ_FR2, mo); /* Replace callable. */
return FFH_TAILCALL;
}
lj_gc_check(L);
setstrV(L, L->base-1-LJ_FR2, lj_strfmt_obj(L, L->base));
return FFH_RES(1);
}
/* -- Base library: throw and catch errors -------------------------------- */
LJLIB_CF(error)
{
int32_t level = lj_lib_optint(L, 2, 1);
lua_settop(L, 1);
if (lua_isstring(L, 1) && level > 0) {
luaL_where(L, level);
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
return lua_error(L);
}
LJLIB_ASM(pcall) LJLIB_REC(.)
{
lj_lib_checkany(L, 1);
lj_lib_checkfunc(L, 2); /* For xpcall only. */
return FFH_UNREACHABLE;
}
LJLIB_ASM_(xpcall) LJLIB_REC(.)
/* -- Base library: load Lua code ----------------------------------------- */
#if !LJ_SRB2LIB
static int load_aux(lua_State *L, int status, int envarg)
{
if (status == LUA_OK) {
/*
** Set environment table for top-level function.
** Don't do this for non-native bytecode, which returns a prototype.
*/
if (tvistab(L->base+envarg-1) && tvisfunc(L->top-1)) {
GCfunc *fn = funcV(L->top-1);
GCtab *t = tabV(L->base+envarg-1);
setgcref(fn->c.env, obj2gco(t));
lj_gc_objbarrier(L, fn, t);
}
return 1;
} else {
setnilV(L->top-2);
return 2;
}
}
LJLIB_CF(loadfile)
{
GCstr *fname = lj_lib_optstr(L, 1);
GCstr *mode = lj_lib_optstr(L, 2);
int status;
lua_settop(L, 3); /* Ensure env arg exists. */
status = luaL_loadfilex(L, fname ? strdata(fname) : NULL,
mode ? strdata(mode) : NULL);
return load_aux(L, status, 3);
}
static const char *reader_func(lua_State *L, void *ud, size_t *size)
{
UNUSED(ud);
luaL_checkstack(L, 2, "too many nested functions");
copyTV(L, L->top++, L->base);
lua_call(L, 0, 1); /* Call user-supplied function. */
L->top--;
if (tvisnil(L->top)) {
*size = 0;
return NULL;
} else if (tvisstr(L->top) || tvisnumber(L->top)) {
copyTV(L, L->base+4, L->top); /* Anchor string in reserved stack slot. */
return lua_tolstring(L, 5, size);
} else {
lj_err_caller(L, LJ_ERR_RDRSTR);
return NULL;
}
}
LJLIB_CF(load)
{
GCstr *name = lj_lib_optstr(L, 2);
GCstr *mode = lj_lib_optstr(L, 3);
int status;
if (L->base < L->top &&
(tvisstr(L->base) || tvisnumber(L->base) || tvisbuf(L->base))) {
const char *s;
MSize len;
if (tvisbuf(L->base)) {
SBufExt *sbx = bufV(L->base);
s = sbx->r;
len = sbufxlen(sbx);
if (!name) name = &G(L)->strempty; /* Buffers are not NUL-terminated. */
} else {
GCstr *str = lj_lib_checkstr(L, 1);
s = strdata(str);
len = str->len;
}
lua_settop(L, 4); /* Ensure env arg exists. */
status = luaL_loadbufferx(L, s, len, name ? strdata(name) : s,
mode ? strdata(mode) : NULL);
} else {
lj_lib_checkfunc(L, 1);
lua_settop(L, 5); /* Reserve a slot for the string from the reader. */
status = lua_loadx(L, reader_func, NULL, name ? strdata(name) : "=(load)",
mode ? strdata(mode) : NULL);
}
return load_aux(L, status, 4);
}
LJLIB_CF(loadstring)
{
return lj_cf_load(L);
}
LJLIB_CF(dofile)
{
GCstr *fname = lj_lib_optstr(L, 1);
setnilV(L->top);
L->top = L->base+1;
if (luaL_loadfile(L, fname ? strdata(fname) : NULL) != LUA_OK)
lua_error(L);
lua_call(L, 0, LUA_MULTRET);
return (int)(L->top - L->base) - 1;
}
#endif
/* -- Base library: GC control -------------------------------------------- */
LJLIB_CF(gcinfo)
{
setintV(L->top++, (int32_t)(G(L)->gc.total >> 10));
return 1;
}
LJLIB_CF(collectgarbage)
{
int opt = lj_lib_checkopt(L, 1, LUA_GCCOLLECT, /* ORDER LUA_GC* */
"\4stop\7restart\7collect\5count\1\377\4step\10setpause\12setstepmul\1\377\11isrunning");
int32_t data = lj_lib_optint(L, 2, 0);
if (opt == LUA_GCCOUNT) {
#if LJ_INTONLY
setintV(L->top, G(L)->gc.total/1024);
#else
setnumV(L->top, (lua_Number)G(L)->gc.total/1024.0);
#endif
} else {
int res = lua_gc(L, opt, data);
if (opt == LUA_GCSTEP || opt == LUA_GCISRUNNING)
setboolV(L->top, res);
else
setintV(L->top, res);
}
L->top++;
return 1;
}
/* -- Base library: miscellaneous functions ------------------------------- */
LJLIB_PUSH(top-2) /* Upvalue holds weak table. */
LJLIB_CF(newproxy)
{
lua_settop(L, 1);
lua_newuserdata(L, 0);
if (lua_toboolean(L, 1) == 0) { /* newproxy(): without metatable. */
return 1;
} else if (lua_isboolean(L, 1)) { /* newproxy(true): with metatable. */
lua_newtable(L);
lua_pushvalue(L, -1);
lua_pushboolean(L, 1);
lua_rawset(L, lua_upvalueindex(1)); /* Remember mt in weak table. */
} else { /* newproxy(proxy): inherit metatable. */
int validproxy = 0;
if (lua_getmetatable(L, 1)) {
lua_rawget(L, lua_upvalueindex(1));
validproxy = lua_toboolean(L, -1);
lua_pop(L, 1);
}
if (!validproxy)
lj_err_arg(L, 1, LJ_ERR_NOPROXY);
lua_getmetatable(L, 1);
}
lua_setmetatable(L, 2);
return 1;
}
LJLIB_PUSH("tostring")
LJLIB_CF(print)
{
ptrdiff_t i, nargs = L->top - L->base;
cTValue *tv = lj_tab_getstr(tabref(L->env), strV(lj_lib_upvalue(L, 1)));
int shortcut;
if (tv && !tvisnil(tv)) {
copyTV(L, L->top++, tv);
} else {
setstrV(L, L->top++, strV(lj_lib_upvalue(L, 1)));
lua_gettable(L, LUA_GLOBALSINDEX);
tv = L->top-1;
}
shortcut = (tvisfunc(tv) && funcV(tv)->c.ffid == FF_tostring) &&
!gcrefu(basemt_it(G(L), LJ_TNUMX));
for (i = 0; i < nargs; i++) {
cTValue *o = &L->base[i];
const char *str;
size_t size;
MSize len;
if (shortcut && (str = lj_strfmt_wstrnum(L, o, &len)) != NULL) {
size = len;
} else {
copyTV(L, L->top+1, o);
copyTV(L, L->top, L->top-1);
L->top += 2;
lua_call(L, 1, 1);
str = lua_tolstring(L, -1, &size);
if (!str)
lj_err_caller(L, LJ_ERR_PRTOSTR);
L->top--;
}
if (i)
putchar('\t');
fwrite(str, 1, size, stdout);
}
putchar('\n');
return 0;
}
LJLIB_PUSH(top-3)
LJLIB_SET(_VERSION)
#include "lj_libdef.h"
/* -- Coroutine library --------------------------------------------------- */
#define LJLIB_MODULE_coroutine
LJLIB_CF(coroutine_status)
{
const char *s;
lua_State *co;
if (!(L->top > L->base && tvisthread(L->base)))
lj_err_arg(L, 1, LJ_ERR_NOCORO);
co = threadV(L->base);
if (co == L) s = "running";
else if (co->status == LUA_YIELD) s = "suspended";
else if (co->status != LUA_OK) s = "dead";
else if (co->base > tvref(co->stack)+1+LJ_FR2) s = "normal";
else if (co->top == co->base) s = "dead";
else s = "suspended";
lua_pushstring(L, s);
return 1;
}
LJLIB_CF(coroutine_running)
{
#if LJ_52
int ismain = lua_pushthread(L);
setboolV(L->top++, ismain);
return 2;
#else
if (lua_pushthread(L))
setnilV(L->top++);
return 1;
#endif
}
LJLIB_CF(coroutine_isyieldable)
{
setboolV(L->top++, cframe_canyield(L->cframe));
return 1;
}
LJLIB_CF(coroutine_create)
{
lua_State *L1;
if (!(L->base < L->top && tvisfunc(L->base)))
lj_err_argt(L, 1, LUA_TFUNCTION);
L1 = lua_newthread(L);
setfuncV(L, L1->top++, funcV(L->base));
return 1;
}
LJLIB_ASM(coroutine_yield)
{
lj_err_caller(L, LJ_ERR_CYIELD);
return FFH_UNREACHABLE;
}
static int ffh_resume(lua_State *L, lua_State *co, int wrap)
{
if (co->cframe != NULL || co->status > LUA_YIELD ||
(co->status == LUA_OK && co->top == co->base)) {
ErrMsg em = co->cframe ? LJ_ERR_CORUN : LJ_ERR_CODEAD;
if (wrap) lj_err_caller(L, em);
setboolV(L->base-1-LJ_FR2, 0);
setstrV(L, L->base-LJ_FR2, lj_err_str(L, em));
return FFH_RES(2);
}
if (lj_state_cpgrowstack(co, (MSize)(L->top - L->base)) != LUA_OK) {
cTValue *msg = --co->top;
lj_err_callermsg(L, strVdata(msg));
}
return FFH_RETRY;
}
LJLIB_ASM(coroutine_resume)
{
if (!(L->top > L->base && tvisthread(L->base)))
lj_err_arg(L, 1, LJ_ERR_NOCORO);
return ffh_resume(L, threadV(L->base), 0);
}
LJLIB_NOREG LJLIB_ASM(coroutine_wrap_aux)
{
return ffh_resume(L, threadV(lj_lib_upvalue(L, 1)), 1);
}
/* Inline declarations. */
LJ_ASMF void lj_ff_coroutine_wrap_aux(void);
#if !(LJ_TARGET_MIPS && defined(ljamalg_c))
LJ_FUNCA_NORET void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L,
lua_State *co);
#endif
/* Error handler, called from assembler VM. */
void LJ_FASTCALL lj_ffh_coroutine_wrap_err(lua_State *L, lua_State *co)
{
co->top--; copyTV(L, L->top, co->top); L->top++;
if (tvisstr(L->top-1))
lj_err_callermsg(L, strVdata(L->top-1));
else
lj_err_run(L);
}
/* Forward declaration. */
static void setpc_wrap_aux(lua_State *L, GCfunc *fn);
LJLIB_CF(coroutine_wrap)
{
GCfunc *fn;
lj_cf_coroutine_create(L);
fn = lj_lib_pushcc(L, lj_ffh_coroutine_wrap_aux, FF_coroutine_wrap_aux, 1);
setpc_wrap_aux(L, fn);
return 1;
}
#include "lj_libdef.h"
/* Fix the PC of wrap_aux. Really ugly workaround. */
static void setpc_wrap_aux(lua_State *L, GCfunc *fn)
{
setmref(fn->c.pc, &L2GG(L)->bcff[lj_lib_init_coroutine[1]+2]);
}
/* ------------------------------------------------------------------------ */
static void newproxy_weaktable(lua_State *L)
{
/* NOBARRIER: The table is new (marked white). */
GCtab *t = lj_tab_new(L, 0, 1);
settabV(L, L->top++, t);
setgcref(t->metatable, obj2gco(t));
setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
lj_str_newlit(L, "kv"));
t->nomm = (uint8_t)(~(1u<<MM_mode));
}
LUALIB_API int luaopen_base(lua_State *L)
{
/* NOBARRIER: Table and value are the same. */
GCtab *env = tabref(L->env);
settabV(L, lj_tab_setstr(L, env, lj_str_newlit(L, "_G")), env);
lua_pushliteral(L, LUA_VERSION); /* top-3. */
newproxy_weaktable(L); /* top-2. */
LJ_LIB_REG(L, "_G", base);
LJ_LIB_REG(L, LUA_COLIBNAME, coroutine);
return 2;
}
+181
View File
@@ -0,0 +1,181 @@
/*
** Bit manipulation library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#define lib_bit_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_strscan.h"
#include "lj_strfmt.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lj_cconv.h"
#include "lj_carith.h"
#endif
#include "lj_ff.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_bit
#if LJ_HASFFI
static int bit_result64(lua_State *L, CTypeID id, uint64_t x)
{
GCcdata *cd = lj_cdata_new_(L, id, 8);
*(uint64_t *)cdataptr(cd) = x;
setcdataV(L, L->base-1-LJ_FR2, cd);
return FFH_RES(1);
}
#else
static int32_t bit_checkbit(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
if (!(o < L->top && lj_strscan_numberobj(o)))
lj_err_argt(L, narg, LUA_TNUMBER);
if (LJ_LIKELY(tvisint(o))) {
return intV(o);
} else {
int32_t i = lj_num2bit(numV(o));
if (LJ_DUALNUM) setintV(o, i);
return i;
}
}
#endif
LJLIB_ASM(bit_tobit) LJLIB_REC(bit_tobit)
{
#if LJ_HASFFI
CTypeID id = 0;
setintV(L->base-1-LJ_FR2, (int32_t)lj_carith_check64(L, 1, &id));
return FFH_RES(1);
#else
lj_lib_checknumber(L, 1);
return FFH_RETRY;
#endif
}
LJLIB_ASM(bit_bnot) LJLIB_REC(bit_unary IR_BNOT)
{
#if LJ_HASFFI
CTypeID id = 0;
uint64_t x = lj_carith_check64(L, 1, &id);
return id ? bit_result64(L, id, ~x) : FFH_RETRY;
#else
lj_lib_checknumber(L, 1);
return FFH_RETRY;
#endif
}
LJLIB_ASM(bit_bswap) LJLIB_REC(bit_unary IR_BSWAP)
{
#if LJ_HASFFI
CTypeID id = 0;
uint64_t x = lj_carith_check64(L, 1, &id);
return id ? bit_result64(L, id, lj_bswap64(x)) : FFH_RETRY;
#else
lj_lib_checknumber(L, 1);
return FFH_RETRY;
#endif
}
LJLIB_ASM(bit_lshift) LJLIB_REC(bit_shift IR_BSHL)
{
#if LJ_HASFFI
CTypeID id = 0, id2 = 0;
uint64_t x = lj_carith_check64(L, 1, &id);
int32_t sh = (int32_t)lj_carith_check64(L, 2, &id2);
if (id) {
x = lj_carith_shift64(x, sh, curr_func(L)->c.ffid - (int)FF_bit_lshift);
return bit_result64(L, id, x);
}
setintV(L->base+1, sh);
return FFH_RETRY;
#else
lj_lib_checknumber(L, 1);
bit_checkbit(L, 2);
return FFH_RETRY;
#endif
}
LJLIB_ASM_(bit_rshift) LJLIB_REC(bit_shift IR_BSHR)
LJLIB_ASM_(bit_arshift) LJLIB_REC(bit_shift IR_BSAR)
LJLIB_ASM_(bit_rol) LJLIB_REC(bit_shift IR_BROL)
LJLIB_ASM_(bit_ror) LJLIB_REC(bit_shift IR_BROR)
LJLIB_ASM(bit_band) LJLIB_REC(bit_nary IR_BAND)
{
#if LJ_HASFFI
CTypeID id = 0;
TValue *o = L->base, *top = L->top;
int i = 0;
do { lj_carith_check64(L, ++i, &id); } while (++o < top);
if (id) {
CTState *cts = ctype_cts(L);
CType *ct = ctype_get(cts, id);
int op = curr_func(L)->c.ffid - (int)FF_bit_bor;
uint64_t x, y = op >= 0 ? 0 : ~(uint64_t)0;
o = L->base;
do {
lj_cconv_ct_tv(cts, ct, (uint8_t *)&x, o, 0);
if (op < 0) y &= x; else if (op == 0) y |= x; else y ^= x;
} while (++o < top);
return bit_result64(L, id, y);
}
return FFH_RETRY;
#else
int i = 0;
do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top);
return FFH_RETRY;
#endif
}
LJLIB_ASM_(bit_bor) LJLIB_REC(bit_nary IR_BOR)
LJLIB_ASM_(bit_bxor) LJLIB_REC(bit_nary IR_BXOR)
/* ------------------------------------------------------------------------ */
LJLIB_CF(bit_tohex) LJLIB_REC(.)
{
#if LJ_HASFFI
CTypeID id = 0, id2 = 0;
uint64_t b = lj_carith_check64(L, 1, &id);
int32_t n = L->base+1>=L->top ? (id ? 16 : 8) :
(int32_t)lj_carith_check64(L, 2, &id2);
#else
uint32_t b = (uint32_t)bit_checkbit(L, 1);
int32_t n = L->base+1>=L->top ? 8 : bit_checkbit(L, 2);
#endif
SBuf *sb = lj_buf_tmp_(L);
SFormat sf = (STRFMT_UINT|STRFMT_T_HEX);
if (n < 0) { n = (int32_t)(~(uint32_t)n+1u); sf |= STRFMT_F_UPPER; }
if ((uint32_t)n > 254) n = 254;
sf |= ((SFormat)((n+1)&255) << STRFMT_SH_PREC);
#if LJ_HASFFI
if (n < 16) b &= ((uint64_t)1 << 4*n)-1;
#else
if (n < 8) b &= (1u << 4*n)-1;
#endif
sb = lj_strfmt_putfxint(sb, sf, b);
setstrV(L, L->top-1, lj_buf_str(L, sb));
lj_gc_check(L);
return 1;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_bit(lua_State *L)
{
LJ_LIB_REG(L, LUA_BITLIBNAME, bit);
return 1;
}
+360
View File
@@ -0,0 +1,360 @@
/*
** Buffer library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#define lib_buffer_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#if LJ_HASBUFFER
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_udata.h"
#include "lj_meta.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lj_cconv.h"
#endif
#include "lj_strfmt.h"
#include "lj_serialize.h"
#include "lj_lib.h"
/* -- Helper functions ---------------------------------------------------- */
/* Check that the first argument is a string buffer. */
static SBufExt *buffer_tobuf(lua_State *L)
{
if (!(L->base < L->top && tvisbuf(L->base)))
lj_err_argtype(L, 1, "buffer");
return bufV(L->base);
}
/* Ditto, but for writers. */
static LJ_AINLINE SBufExt *buffer_tobufw(lua_State *L)
{
SBufExt *sbx = buffer_tobuf(L);
setsbufXL_(sbx, L);
return sbx;
}
#define buffer_toudata(sbx) ((GCudata *)(sbx)-1)
/* -- Buffer methods ------------------------------------------------------ */
#define LJLIB_MODULE_buffer_method
LJLIB_CF(buffer_method_free)
{
SBufExt *sbx = buffer_tobuf(L);
lj_bufx_free(L, sbx);
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_reset) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobuf(L);
lj_bufx_reset(sbx);
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_skip) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobuf(L);
MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
MSize len = sbufxlen(sbx);
if (n < len) {
sbx->r += n;
} else if (sbufiscow(sbx)) {
sbx->r = sbx->w;
} else {
sbx->r = sbx->w = sbx->b;
}
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_set) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobuf(L);
GCobj *ref;
const char *p;
MSize len;
#if LJ_HASFFI
if (tviscdata(L->base+1)) {
CTState *cts = ctype_cts(L);
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
L->base+1, CCF_ARG(2));
len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
} else
#endif
{
GCstr *str = lj_lib_checkstrx(L, 2);
p = strdata(str);
len = str->len;
}
lj_bufx_free(L, sbx);
lj_bufx_set_cow(L, sbx, p, len);
ref = gcV(L->base+1);
setgcref(sbx->cowref, ref);
lj_gc_objbarrier(L, buffer_toudata(sbx), ref);
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_put) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobufw(L);
ptrdiff_t arg, narg = L->top - L->base;
for (arg = 1; arg < narg; arg++) {
cTValue *o = &L->base[arg], *mo = NULL;
retry:
if (tvisstr(o)) {
lj_buf_putstr((SBuf *)sbx, strV(o));
} else if (tvisint(o)) {
lj_strfmt_putint((SBuf *)sbx, intV(o));
} else if (tvisnum(o)) {
lj_strfmt_putfnum((SBuf *)sbx, STRFMT_G14, numV(o));
} else if (tvisbuf(o)) {
SBufExt *sbx2 = bufV(o);
if (sbx2 == sbx) lj_err_arg(L, (int)(arg+1), LJ_ERR_BUFFER_SELF);
lj_buf_putmem((SBuf *)sbx, sbx2->r, sbufxlen(sbx2));
} else if (!mo && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
/* Call __tostring metamethod inline. */
copyTV(L, L->top++, mo);
copyTV(L, L->top++, o);
lua_call(L, 1, 1);
o = &L->base[arg]; /* The stack may have been reallocated. */
copyTV(L, &L->base[arg], L->top-1);
L->top = L->base + narg;
goto retry; /* Retry with the result. */
} else {
lj_err_argtype(L, (int)(arg+1), "string/number/__tostring");
}
/* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */
}
L->top = L->base+1; /* Chain buffer object. */
lj_gc_check(L);
return 1;
}
LJLIB_CF(buffer_method_putf) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobufw(L);
lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2);
L->top = L->base+1; /* Chain buffer object. */
lj_gc_check(L);
return 1;
}
LJLIB_CF(buffer_method_get) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobuf(L);
ptrdiff_t arg, narg = L->top - L->base;
if (narg == 1) {
narg++;
setnilV(L->top++); /* get() is the same as get(nil). */
}
for (arg = 1; arg < narg; arg++) {
TValue *o = &L->base[arg];
MSize n = tvisnil(o) ? LJ_MAX_BUF :
(MSize) lj_lib_checkintrange(L, (int)(arg+1), 0, LJ_MAX_BUF);
MSize len = sbufxlen(sbx);
if (n > len) n = len;
setstrV(L, o, lj_str_new(L, sbx->r, n));
sbx->r += n;
}
if (sbx->r == sbx->w && !sbufiscow(sbx)) sbx->r = sbx->w = sbx->b;
lj_gc_check(L);
return (int)(narg-1);
}
#if LJ_HASFFI
LJLIB_CF(buffer_method_putcdata) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobufw(L);
const char *p;
MSize len;
if (tviscdata(L->base+1)) {
CTState *cts = ctype_cts(L);
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
L->base+1, CCF_ARG(2));
} else {
lj_err_argtype(L, 2, "cdata");
}
len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
lj_buf_putmem((SBuf *)sbx, p, len);
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_reserve) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobufw(L);
MSize sz = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
GCcdata *cd;
lj_buf_more((SBuf *)sbx, sz);
ctype_loadffi(L);
cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
*(void **)cdataptr(cd) = sbx->w;
setcdataV(L, L->top++, cd);
setintV(L->top++, sbufleft(sbx));
return 2;
}
LJLIB_CF(buffer_method_commit) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobuf(L);
MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
if (len > sbufleft(sbx)) lj_err_arg(L, 2, LJ_ERR_NUMRNG);
sbx->w += len;
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_ref) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobuf(L);
GCcdata *cd;
ctype_loadffi(L);
cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
*(void **)cdataptr(cd) = sbx->r;
setcdataV(L, L->top++, cd);
setintV(L->top++, sbufxlen(sbx));
return 2;
}
#endif
LJLIB_CF(buffer_method_encode) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobufw(L);
cTValue *o = lj_lib_checkany(L, 2);
lj_serialize_put(sbx, o);
lj_gc_check(L);
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_decode) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobufw(L);
setnilV(L->top++);
sbx->r = lj_serialize_get(sbx, L->top-1);
lj_gc_check(L);
return 1;
}
LJLIB_CF(buffer_method___gc)
{
SBufExt *sbx = buffer_tobuf(L);
lj_bufx_free(L, sbx);
return 0;
}
LJLIB_CF(buffer_method___tostring) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobuf(L);
setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx)));
lj_gc_check(L);
return 1;
}
LJLIB_CF(buffer_method___len) LJLIB_REC(.)
{
SBufExt *sbx = buffer_tobuf(L);
setintV(L->top-1, (int32_t)sbufxlen(sbx));
return 1;
}
LJLIB_PUSH("buffer") LJLIB_SET(__metatable)
LJLIB_PUSH(top-1) LJLIB_SET(__index)
/* -- Buffer library functions -------------------------------------------- */
#define LJLIB_MODULE_buffer
LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
LJLIB_CF(buffer_new)
{
MSize sz = 0;
int targ = 1;
GCtab *env, *dict_str = NULL, *dict_mt = NULL;
GCudata *ud;
SBufExt *sbx;
if (L->base < L->top && !tvistab(L->base)) {
targ = 2;
if (!tvisnil(L->base))
sz = (MSize)lj_lib_checkintrange(L, 1, 0, LJ_MAX_BUF);
}
if (L->base+targ-1 < L->top) {
GCtab *options = lj_lib_checktab(L, targ);
cTValue *opt_dict, *opt_mt;
opt_dict = lj_tab_getstr(options, lj_str_newlit(L, "dict"));
if (opt_dict && tvistab(opt_dict)) {
dict_str = tabV(opt_dict);
lj_serialize_dict_prep_str(L, dict_str);
}
opt_mt = lj_tab_getstr(options, lj_str_newlit(L, "metatable"));
if (opt_mt && tvistab(opt_mt)) {
dict_mt = tabV(opt_mt);
lj_serialize_dict_prep_mt(L, dict_mt);
}
}
env = tabref(curr_func(L)->c.env);
ud = lj_udata_new(L, sizeof(SBufExt), env);
ud->udtype = UDTYPE_BUFFER;
/* NOBARRIER: The GCudata is new (marked white). */
setgcref(ud->metatable, obj2gco(env));
setudataV(L, L->top++, ud);
sbx = (SBufExt *)uddata(ud);
lj_bufx_init(L, sbx);
setgcref(sbx->dict_str, obj2gco(dict_str));
setgcref(sbx->dict_mt, obj2gco(dict_mt));
if (sz > 0) lj_buf_need2((SBuf *)sbx, sz);
lj_gc_check(L);
return 1;
}
LJLIB_CF(buffer_encode) LJLIB_REC(.)
{
cTValue *o = lj_lib_checkany(L, 1);
setstrV(L, L->top++, lj_serialize_encode(L, o));
lj_gc_check(L);
return 1;
}
LJLIB_CF(buffer_decode) LJLIB_REC(.)
{
GCstr *str = lj_lib_checkstrx(L, 1);
setnilV(L->top++);
lj_serialize_decode(L, L->top-1, str);
lj_gc_check(L);
return 1;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
int luaopen_string_buffer(lua_State *L)
{
LJ_LIB_REG(L, NULL, buffer_method);
lua_getfield(L, -1, "__tostring");
lua_setfield(L, -2, "tostring");
LJ_LIB_REG(L, NULL, buffer);
return 1;
}
#endif
+414
View File
@@ -0,0 +1,414 @@
/*
** Debug library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lib_debug_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_debug.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_debug
#if !LJ_SRB2LIB
LJLIB_CF(debug_getregistry)
{
copyTV(L, L->top++, registry(L));
return 1;
}
LJLIB_CF(debug_getmetatable) LJLIB_REC(.)
{
lj_lib_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
setnilV(L->top-1);
}
return 1;
}
LJLIB_CF(debug_setmetatable)
{
lj_lib_checktabornil(L, 2);
L->top = L->base+2;
lua_setmetatable(L, 1);
#if !LJ_52
setboolV(L->top-1, 1);
#endif
return 1;
}
LJLIB_CF(debug_getfenv)
{
lj_lib_checkany(L, 1);
lua_getfenv(L, 1);
return 1;
}
LJLIB_CF(debug_setfenv)
{
lj_lib_checktab(L, 2);
L->top = L->base+2;
if (!lua_setfenv(L, 1))
lj_err_caller(L, LJ_ERR_SETFENV);
return 1;
}
#endif
/* ------------------------------------------------------------------------ */
static void settabss(lua_State *L, const char *i, const char *v)
{
lua_pushstring(L, v);
lua_setfield(L, -2, i);
}
static void settabsi(lua_State *L, const char *i, int v)
{
lua_pushinteger(L, v);
lua_setfield(L, -2, i);
}
static void settabsb(lua_State *L, const char *i, int v)
{
lua_pushboolean(L, v);
lua_setfield(L, -2, i);
}
static lua_State *getthread(lua_State *L, int *arg)
{
if (L->base < L->top && tvisthread(L->base)) {
*arg = 1;
return threadV(L->base);
} else {
*arg = 0;
return L;
}
}
static void treatstackoption(lua_State *L, lua_State *L1, const char *fname)
{
if (L == L1) {
lua_pushvalue(L, -2);
lua_remove(L, -3);
}
else
lua_xmove(L1, L, 1);
lua_setfield(L, -2, fname);
}
LJLIB_CF(debug_getinfo)
{
lj_Debug ar;
int arg, opt_f = 0, opt_L = 0;
lua_State *L1 = getthread(L, &arg);
const char *options = luaL_optstring(L, arg+2, "flnSu");
if (lua_isnumber(L, arg+1)) {
if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), (lua_Debug *)&ar)) {
setnilV(L->top-1);
return 1;
}
} else if (L->base+arg < L->top && tvisfunc(L->base+arg)) {
options = lua_pushfstring(L, ">%s", options);
setfuncV(L1, L1->top++, funcV(L->base+arg));
} else {
lj_err_arg(L, arg+1, LJ_ERR_NOFUNCL);
}
if (!lj_debug_getinfo(L1, options, &ar, 1))
lj_err_arg(L, arg+2, LJ_ERR_INVOPT);
lua_createtable(L, 0, 16); /* Create result table. */
for (; *options; options++) {
switch (*options) {
case 'S':
settabss(L, "source", ar.source);
settabss(L, "short_src", ar.short_src);
settabsi(L, "linedefined", ar.linedefined);
settabsi(L, "lastlinedefined", ar.lastlinedefined);
settabss(L, "what", ar.what);
break;
case 'l':
settabsi(L, "currentline", ar.currentline);
break;
case 'u':
settabsi(L, "nups", ar.nups);
settabsi(L, "nparams", ar.nparams);
settabsb(L, "isvararg", ar.isvararg);
break;
case 'n':
settabss(L, "name", ar.name);
settabss(L, "namewhat", ar.namewhat);
break;
case 'f': opt_f = 1; break;
case 'L': opt_L = 1; break;
default: break;
}
}
if (opt_L) treatstackoption(L, L1, "activelines");
if (opt_f) treatstackoption(L, L1, "func");
return 1; /* Return result table. */
}
LJLIB_CF(debug_getlocal)
{
int arg;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
const char *name;
int slot = lj_lib_checkint(L, arg+2);
if (tvisfunc(L->base+arg)) {
L->top = L->base+arg+1;
lua_pushstring(L, lua_getlocal(L, NULL, slot));
return 1;
}
if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar))
lj_err_arg(L, arg+1, LJ_ERR_LVLRNG);
name = lua_getlocal(L1, &ar, slot);
if (name) {
lua_xmove(L1, L, 1);
lua_pushstring(L, name);
lua_pushvalue(L, -2);
return 2;
} else {
setnilV(L->top-1);
return 1;
}
}
#if !LJ_SRB2LIB
LJLIB_CF(debug_setlocal)
{
int arg;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
TValue *tv;
if (!lua_getstack(L1, lj_lib_checkint(L, arg+1), &ar))
lj_err_arg(L, arg+1, LJ_ERR_LVLRNG);
tv = lj_lib_checkany(L, arg+3);
copyTV(L1, L1->top++, tv);
lua_pushstring(L, lua_setlocal(L1, &ar, lj_lib_checkint(L, arg+2)));
return 1;
}
#endif
static int debug_getupvalue(lua_State *L, int get)
{
int32_t n = lj_lib_checkint(L, 2);
const char *name;
lj_lib_checkfunc(L, 1);
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
if (name) {
lua_pushstring(L, name);
if (!get) return 1;
copyTV(L, L->top, L->top-2);
L->top++;
return 2;
}
return 0;
}
LJLIB_CF(debug_getupvalue)
{
return debug_getupvalue(L, 1);
}
#if !LJ_SRB2LIB
LJLIB_CF(debug_setupvalue)
{
lj_lib_checkany(L, 3);
return debug_getupvalue(L, 0);
}
LJLIB_CF(debug_upvalueid)
{
GCfunc *fn = lj_lib_checkfunc(L, 1);
int32_t n = lj_lib_checkint(L, 2) - 1;
if ((uint32_t)n >= fn->l.nupvalues)
lj_err_arg(L, 2, LJ_ERR_IDXRNG);
lua_pushlightuserdata(L, isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) :
(void *)&fn->c.upvalue[n]);
return 1;
}
LJLIB_CF(debug_upvaluejoin)
{
GCfunc *fn[2];
GCRef *p[2];
int i;
for (i = 0; i < 2; i++) {
int32_t n;
fn[i] = lj_lib_checkfunc(L, 2*i+1);
if (!isluafunc(fn[i]))
lj_err_arg(L, 2*i+1, LJ_ERR_NOLFUNC);
n = lj_lib_checkint(L, 2*i+2) - 1;
if ((uint32_t)n >= fn[i]->l.nupvalues)
lj_err_arg(L, 2*i+2, LJ_ERR_IDXRNG);
p[i] = &fn[i]->l.uvptr[n];
}
setgcrefr(*p[0], *p[1]);
lj_gc_objbarrier(L, fn[0], gcref(*p[1]));
return 0;
}
#if LJ_52
LJLIB_CF(debug_getuservalue)
{
TValue *o = L->base;
if (o < L->top && tvisudata(o))
settabV(L, o, tabref(udataV(o)->env));
else
setnilV(o);
L->top = o+1;
return 1;
}
LJLIB_CF(debug_setuservalue)
{
TValue *o = L->base;
if (!(o < L->top && tvisudata(o)))
lj_err_argt(L, 1, LUA_TUSERDATA);
if (!(o+1 < L->top && tvistab(o+1)))
lj_err_argt(L, 2, LUA_TTABLE);
L->top = o+2;
lua_setfenv(L, 1);
return 1;
}
#endif
#endif
/* ------------------------------------------------------------------------ */
#define KEY_HOOK (U64x(80000000,00000000)|'h')
static void hookf(lua_State *L, lua_Debug *ar)
{
static const char *const hooknames[] =
{"call", "return", "line", "count", "tail return"};
(L->top++)->u64 = KEY_HOOK;
lua_rawget(L, LUA_REGISTRYINDEX);
if (lua_isfunction(L, -1)) {
lua_pushstring(L, hooknames[(int)ar->event]);
if (ar->currentline >= 0)
lua_pushinteger(L, ar->currentline);
else lua_pushnil(L);
lua_call(L, 2, 0);
}
}
static int makemask(const char *smask, int count)
{
int mask = 0;
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
if (count > 0) mask |= LUA_MASKCOUNT;
return mask;
}
static char *unmakemask(int mask, char *smask)
{
int i = 0;
if (mask & LUA_MASKCALL) smask[i++] = 'c';
if (mask & LUA_MASKRET) smask[i++] = 'r';
if (mask & LUA_MASKLINE) smask[i++] = 'l';
smask[i] = '\0';
return smask;
}
LJLIB_CF(debug_sethook)
{
int arg, mask, count;
lua_Hook func;
(void)getthread(L, &arg);
if (lua_isnoneornil(L, arg+1)) {
lua_settop(L, arg+1);
func = NULL; mask = 0; count = 0; /* turn off hooks */
} else {
const char *smask = luaL_checkstring(L, arg+2);
luaL_checktype(L, arg+1, LUA_TFUNCTION);
count = luaL_optint(L, arg+3, 0);
func = hookf; mask = makemask(smask, count);
}
(L->top++)->u64 = KEY_HOOK;
lua_pushvalue(L, arg+1);
lua_rawset(L, LUA_REGISTRYINDEX);
lua_sethook(L, func, mask, count);
return 0;
}
LJLIB_CF(debug_gethook)
{
char buff[5];
int mask = lua_gethookmask(L);
lua_Hook hook = lua_gethook(L);
if (hook != NULL && hook != hookf) { /* external hook? */
lua_pushliteral(L, "external hook");
} else {
(L->top++)->u64 = KEY_HOOK;
lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
}
lua_pushstring(L, unmakemask(mask, buff));
lua_pushinteger(L, lua_gethookcount(L));
return 3;
}
/* ------------------------------------------------------------------------ */
#if !LJ_SRB2LIB
LJLIB_CF(debug_debug)
{
for (;;) {
char buffer[250];
fputs("lua_debug> ", stderr);
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
strcmp(buffer, "cont\n") == 0)
return 0;
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
lua_pcall(L, 0, 0, 0)) {
const char *s = lua_tostring(L, -1);
fputs(s ? s : "(error object is not a string)", stderr);
fputs("\n", stderr);
}
lua_settop(L, 0); /* remove eventual returns */
}
}
#endif
/* ------------------------------------------------------------------------ */
#define LEVELS1 12 /* size of the first part of the stack */
#define LEVELS2 10 /* size of the second part of the stack */
LJLIB_CF(debug_traceback)
{
int arg;
lua_State *L1 = getthread(L, &arg);
const char *msg = lua_tostring(L, arg+1);
if (msg == NULL && L->top > L->base+arg)
L->top = L->base+arg+1;
else
luaL_traceback(L, L1, msg, lj_lib_optint(L, arg+2, (L == L1)));
return 1;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_debug(lua_State *L)
{
LJ_LIB_REG(L, LUA_DBLIBNAME, debug);
return 1;
}
+857
View File
@@ -0,0 +1,857 @@
/*
** FFI library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#define lib_ffi_c
#define LUA_LIB
#include <errno.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_meta.h"
#include "lj_ctype.h"
#include "lj_cparse.h"
#include "lj_cdata.h"
#include "lj_cconv.h"
#include "lj_carith.h"
#include "lj_ccall.h"
#include "lj_ccallback.h"
#include "lj_clib.h"
#include "lj_strfmt.h"
#include "lj_ff.h"
#include "lj_lib.h"
/* -- C type checks ------------------------------------------------------- */
/* Check first argument for a C type and returns its ID. */
static CTypeID ffi_checkctype(lua_State *L, CTState *cts, TValue *param)
{
TValue *o = L->base;
if (!(o < L->top)) {
err_argtype:
lj_err_argtype(L, 1, "C type");
}
if (tvisstr(o)) { /* Parse an abstract C type declaration. */
GCstr *s = strV(o);
CPState cp;
int errcode;
cp.L = L;
cp.cts = cts;
cp.srcname = strdata(s);
cp.p = strdata(s);
cp.param = param;
cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT;
errcode = lj_cparse(&cp);
if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */
return cp.val.id;
} else {
GCcdata *cd;
if (!tviscdata(o)) goto err_argtype;
if (param && param < L->top) lj_err_arg(L, 1, LJ_ERR_FFI_NUMPARAM);
cd = cdataV(o);
return cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->ctypeid;
}
}
/* Check argument for C data and return it. */
static GCcdata *ffi_checkcdata(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
if (!(o < L->top && tviscdata(o)))
lj_err_argt(L, narg, LUA_TCDATA);
return cdataV(o);
}
/* Convert argument to C pointer. */
static void *ffi_checkptr(lua_State *L, int narg, CTypeID id)
{
CTState *cts = ctype_cts(L);
TValue *o = L->base + narg-1;
void *p;
if (o >= L->top)
lj_err_arg(L, narg, LJ_ERR_NOVAL);
lj_cconv_ct_tv(cts, ctype_get(cts, id), (uint8_t *)&p, o, CCF_ARG(narg));
return p;
}
/* Convert argument to int32_t. */
static int32_t ffi_checkint(lua_State *L, int narg)
{
CTState *cts = ctype_cts(L);
TValue *o = L->base + narg-1;
int32_t i;
if (o >= L->top)
lj_err_arg(L, narg, LJ_ERR_NOVAL);
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o,
CCF_ARG(narg));
return i;
}
/* -- C type metamethods -------------------------------------------------- */
#define LJLIB_MODULE_ffi_meta
/* Handle ctype __index/__newindex metamethods. */
static int ffi_index_meta(lua_State *L, CTState *cts, CType *ct, MMS mm)
{
CTypeID id = ctype_typeid(cts, ct);
cTValue *tv = lj_ctype_meta(cts, id, mm);
TValue *base = L->base;
if (!tv) {
const char *s;
err_index:
s = strdata(lj_ctype_repr(L, id, NULL));
if (tvisstr(L->base+1)) {
lj_err_callerv(L, LJ_ERR_FFI_BADMEMBER, s, strVdata(L->base+1));
} else {
const char *key = tviscdata(L->base+1) ?
strdata(lj_ctype_repr(L, cdataV(L->base+1)->ctypeid, NULL)) :
lj_typename(L->base+1);
lj_err_callerv(L, LJ_ERR_FFI_BADIDXW, s, key);
}
}
if (!tvisfunc(tv)) {
if (mm == MM_index) {
cTValue *o = lj_meta_tget(L, tv, base+1);
if (o) {
if (tvisnil(o)) goto err_index;
copyTV(L, L->top-1, o);
return 1;
}
} else {
TValue *o = lj_meta_tset(L, tv, base+1);
if (o) {
copyTV(L, o, base+2);
return 0;
}
}
copyTV(L, base, L->top);
tv = L->top-1-LJ_FR2;
}
return lj_meta_tailcall(L, tv);
}
LJLIB_CF(ffi_meta___index) LJLIB_REC(cdata_index 0)
{
CTState *cts = ctype_cts(L);
CTInfo qual = 0;
CType *ct;
uint8_t *p;
TValue *o = L->base;
if (!(o+1 < L->top && tviscdata(o))) /* Also checks for presence of key. */
lj_err_argt(L, 1, LUA_TCDATA);
ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
if ((qual & 1))
return ffi_index_meta(L, cts, ct, MM_index);
if (lj_cdata_get(cts, ct, L->top-1, p))
lj_gc_check(L);
return 1;
}
LJLIB_CF(ffi_meta___newindex) LJLIB_REC(cdata_index 1)
{
CTState *cts = ctype_cts(L);
CTInfo qual = 0;
CType *ct;
uint8_t *p;
TValue *o = L->base;
if (!(o+2 < L->top && tviscdata(o))) /* Also checks for key and value. */
lj_err_argt(L, 1, LUA_TCDATA);
ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
if ((qual & 1)) {
if ((qual & CTF_CONST))
lj_err_caller(L, LJ_ERR_FFI_WRCONST);
return ffi_index_meta(L, cts, ct, MM_newindex);
}
lj_cdata_set(cts, ct, p, o+2, qual);
return 0;
}
/* Common handler for cdata arithmetic. */
static int ffi_arith(lua_State *L)
{
MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___eq + (int)MM_eq);
return lj_carith_op(L, mm);
}
/* The following functions must be in contiguous ORDER MM. */
LJLIB_CF(ffi_meta___eq) LJLIB_REC(cdata_arith MM_eq)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___len) LJLIB_REC(cdata_arith MM_len)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___lt) LJLIB_REC(cdata_arith MM_lt)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___le) LJLIB_REC(cdata_arith MM_le)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___concat) LJLIB_REC(cdata_arith MM_concat)
{
return ffi_arith(L);
}
/* Forward declaration. */
static int lj_cf_ffi_new(lua_State *L);
LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call)
{
CTState *cts = ctype_cts(L);
GCcdata *cd = ffi_checkcdata(L, 1);
CTypeID id = cd->ctypeid;
CType *ct;
cTValue *tv;
MMS mm = MM_call;
if (cd->ctypeid == CTID_CTYPEID) {
id = *(CTypeID *)cdataptr(cd);
mm = MM_new;
} else {
int ret = lj_ccall_func(L, cd);
if (ret >= 0)
return ret;
}
/* Handle ctype __call/__new metamethod. */
ct = ctype_raw(cts, id);
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
tv = lj_ctype_meta(cts, id, mm);
if (tv)
return lj_meta_tailcall(L, tv);
else if (mm == MM_call)
lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL)));
return lj_cf_ffi_new(L);
}
LJLIB_CF(ffi_meta___add) LJLIB_REC(cdata_arith MM_add)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___sub) LJLIB_REC(cdata_arith MM_sub)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___mul) LJLIB_REC(cdata_arith MM_mul)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___div) LJLIB_REC(cdata_arith MM_div)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___mod) LJLIB_REC(cdata_arith MM_mod)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___pow) LJLIB_REC(cdata_arith MM_pow)
{
return ffi_arith(L);
}
LJLIB_CF(ffi_meta___unm) LJLIB_REC(cdata_arith MM_unm)
{
return ffi_arith(L);
}
/* End of contiguous ORDER MM. */
LJLIB_CF(ffi_meta___tostring)
{
GCcdata *cd = ffi_checkcdata(L, 1);
const char *msg = "cdata<%s>: %p";
CTypeID id = cd->ctypeid;
void *p = cdataptr(cd);
if (id == CTID_CTYPEID) {
msg = "ctype<%s>";
id = *(CTypeID *)p;
} else {
CTState *cts = ctype_cts(L);
CType *ct = ctype_raw(cts, id);
if (ctype_isref(ct->info)) {
p = *(void **)p;
ct = ctype_rawchild(cts, ct);
}
if (ctype_iscomplex(ct->info)) {
setstrV(L, L->top-1, lj_ctype_repr_complex(L, cdataptr(cd), ct->size));
goto checkgc;
} else if (ct->size == 8 && ctype_isinteger(ct->info)) {
setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd),
(ct->info & CTF_UNSIGNED)));
goto checkgc;
} else if (ctype_isfunc(ct->info)) {
p = *(void **)p;
} else if (ctype_isenum(ct->info)) {
msg = "cdata<%s>: %d";
p = (void *)(uintptr_t)*(uint32_t *)p;
} else {
if (ctype_isptr(ct->info)) {
p = cdata_getptr(p, ct->size);
ct = ctype_rawchild(cts, ct);
}
if (ctype_isstruct(ct->info) || ctype_isvector(ct->info)) {
/* Handle ctype __tostring metamethod. */
cTValue *tv = lj_ctype_meta(cts, ctype_typeid(cts, ct), MM_tostring);
if (tv)
return lj_meta_tailcall(L, tv);
}
}
}
lj_strfmt_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), p);
checkgc:
lj_gc_check(L);
return 1;
}
static int ffi_pairs(lua_State *L, MMS mm)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkcdata(L, 1)->ctypeid;
CType *ct = ctype_raw(cts, id);
cTValue *tv;
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
tv = lj_ctype_meta(cts, id, mm);
if (!tv)
lj_err_callerv(L, LJ_ERR_FFI_BADMM, strdata(lj_ctype_repr(L, id, NULL)),
strdata(mmname_str(G(L), mm)));
return lj_meta_tailcall(L, tv);
}
LJLIB_CF(ffi_meta___pairs)
{
return ffi_pairs(L, MM_pairs);
}
LJLIB_CF(ffi_meta___ipairs)
{
return ffi_pairs(L, MM_ipairs);
}
LJLIB_PUSH("ffi") LJLIB_SET(__metatable)
#include "lj_libdef.h"
/* -- C library metamethods ----------------------------------------------- */
#define LJLIB_MODULE_ffi_clib
/* Index C library by a name. */
static TValue *ffi_clib_index(lua_State *L)
{
TValue *o = L->base;
CLibrary *cl;
if (!(o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB))
lj_err_argt(L, 1, LUA_TUSERDATA);
cl = (CLibrary *)uddata(udataV(o));
if (!(o+1 < L->top && tvisstr(o+1)))
lj_err_argt(L, 2, LUA_TSTRING);
return lj_clib_index(L, cl, strV(o+1));
}
LJLIB_CF(ffi_clib___index) LJLIB_REC(clib_index 1)
{
TValue *tv = ffi_clib_index(L);
if (tviscdata(tv)) {
CTState *cts = ctype_cts(L);
GCcdata *cd = cdataV(tv);
CType *s = ctype_get(cts, cd->ctypeid);
if (ctype_isextern(s->info)) {
CTypeID sid = ctype_cid(s->info);
void *sp = *(void **)cdataptr(cd);
CType *ct = ctype_raw(cts, sid);
if (lj_cconv_tv_ct(cts, ct, sid, L->top-1, sp))
lj_gc_check(L);
return 1;
}
}
copyTV(L, L->top-1, tv);
return 1;
}
LJLIB_CF(ffi_clib___newindex) LJLIB_REC(clib_index 0)
{
TValue *tv = ffi_clib_index(L);
TValue *o = L->base+2;
if (o < L->top && tviscdata(tv)) {
CTState *cts = ctype_cts(L);
GCcdata *cd = cdataV(tv);
CType *d = ctype_get(cts, cd->ctypeid);
if (ctype_isextern(d->info)) {
CTInfo qual = 0;
for (;;) { /* Skip attributes and collect qualifiers. */
d = ctype_child(cts, d);
if (!ctype_isattrib(d->info)) break;
if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
}
if (!((d->info|qual) & CTF_CONST)) {
lj_cconv_ct_tv(cts, d, *(void **)cdataptr(cd), o, 0);
return 0;
}
}
}
lj_err_caller(L, LJ_ERR_FFI_WRCONST);
return 0; /* unreachable */
}
LJLIB_CF(ffi_clib___gc)
{
TValue *o = L->base;
if (o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB)
lj_clib_unload((CLibrary *)uddata(udataV(o)));
return 0;
}
#include "lj_libdef.h"
/* -- Callback function metamethods --------------------------------------- */
#define LJLIB_MODULE_ffi_callback
static int ffi_callback_set(lua_State *L, GCfunc *fn)
{
GCcdata *cd = ffi_checkcdata(L, 1);
CTState *cts = ctype_cts(L);
CType *ct = ctype_raw(cts, cd->ctypeid);
if (ctype_isptr(ct->info) && (LJ_32 || ct->size == 8)) {
MSize slot = lj_ccallback_ptr2slot(cts, *(void **)cdataptr(cd));
if (slot < cts->cb.sizeid && cts->cb.cbid[slot] != 0) {
GCtab *t = cts->miscmap;
TValue *tv = lj_tab_setint(L, t, (int32_t)slot);
if (fn) {
setfuncV(L, tv, fn);
lj_gc_anybarriert(L, t);
} else {
setnilV(tv);
cts->cb.cbid[slot] = 0;
cts->cb.topid = slot < cts->cb.topid ? slot : cts->cb.topid;
}
return 0;
}
}
lj_err_caller(L, LJ_ERR_FFI_BADCBACK);
return 0;
}
LJLIB_CF(ffi_callback_free)
{
return ffi_callback_set(L, NULL);
}
LJLIB_CF(ffi_callback_set)
{
GCfunc *fn = lj_lib_checkfunc(L, 2);
return ffi_callback_set(L, fn);
}
LJLIB_PUSH(top-1) LJLIB_SET(__index)
#include "lj_libdef.h"
/* -- FFI library functions ----------------------------------------------- */
#define LJLIB_MODULE_ffi
LJLIB_CF(ffi_cdef)
{
GCstr *s = lj_lib_checkstr(L, 1);
CPState cp;
int errcode;
cp.L = L;
cp.cts = ctype_cts(L);
cp.srcname = strdata(s);
cp.p = strdata(s);
cp.param = L->base+1;
cp.mode = CPARSE_MODE_MULTI|CPARSE_MODE_DIRECT;
errcode = lj_cparse(&cp);
if (errcode) lj_err_throw(L, errcode); /* Propagate errors. */
lj_gc_check(L);
return 0;
}
LJLIB_CF(ffi_new) LJLIB_REC(.)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
CType *ct = ctype_raw(cts, id);
CTSize sz;
CTInfo info = lj_ctype_info(cts, id, &sz);
TValue *o = L->base+1;
GCcdata *cd;
if ((info & CTF_VLA)) {
o++;
sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
}
if (sz == CTSIZE_INVALID)
lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE);
cd = lj_cdata_newx(cts, id, sz, info);
setcdataV(L, o-1, cd); /* Anchor the uninitialized cdata. */
lj_cconv_ct_init(cts, ct, sz, cdataptr(cd),
o, (MSize)(L->top - o)); /* Initialize cdata. */
if (ctype_isstruct(ct->info)) {
/* Handle ctype __gc metamethod. Use the fast lookup here. */
cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)id);
if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) {
GCtab *t = tabref(G(L)->gcroot[GCROOT_FFI_FIN]);
if (gcref(t->metatable)) {
/* Add to finalizer table, if still enabled. */
copyTV(L, lj_tab_set(L, t, o-1), tv);
lj_gc_anybarriert(L, t);
cd->marked |= LJ_GC_CDATA_FIN;
}
}
}
L->top = o; /* Only return the cdata itself. */
lj_gc_check(L);
return 1;
}
LJLIB_CF(ffi_cast) LJLIB_REC(ffi_new)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
CType *d = ctype_raw(cts, id);
TValue *o = lj_lib_checkany(L, 2);
L->top = o+1; /* Make sure this is the last item on the stack. */
if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || ctype_isenum(d->info)))
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
if (!(tviscdata(o) && cdataV(o)->ctypeid == id)) {
GCcdata *cd = lj_cdata_new(cts, id, d->size);
lj_cconv_ct_tv(cts, d, cdataptr(cd), o, CCF_CAST);
setcdataV(L, o, cd);
lj_gc_check(L);
}
return 1;
}
LJLIB_CF(ffi_typeof) LJLIB_REC(.)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, L->base+1);
GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
*(CTypeID *)cdataptr(cd) = id;
setcdataV(L, L->top-1, cd);
lj_gc_check(L);
return 1;
}
/* Internal and unsupported API. */
LJLIB_CF(ffi_typeinfo)
{
CTState *cts = ctype_cts(L);
CTypeID id = (CTypeID)ffi_checkint(L, 1);
if (id > 0 && id < cts->top) {
CType *ct = ctype_get(cts, id);
GCtab *t;
lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */
t = tabV(L->top-1);
setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "info")), (int32_t)ct->info);
if (ct->size != CTSIZE_INVALID)
setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "size")), (int32_t)ct->size);
if (ct->sib)
setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "sib")), (int32_t)ct->sib);
if (gcref(ct->name)) {
GCstr *s = gco2str(gcref(ct->name));
if (isdead(G(L), obj2gco(s))) flipwhite(obj2gco(s));
setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "name")), s);
}
lj_gc_check(L);
return 1;
}
return 0;
}
LJLIB_CF(ffi_istype) LJLIB_REC(.)
{
CTState *cts = ctype_cts(L);
CTypeID id1 = ffi_checkctype(L, cts, NULL);
TValue *o = lj_lib_checkany(L, 2);
int b = 0;
if (tviscdata(o)) {
GCcdata *cd = cdataV(o);
CTypeID id2 = cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) :
cd->ctypeid;
CType *ct1 = lj_ctype_rawref(cts, id1);
CType *ct2 = lj_ctype_rawref(cts, id2);
if (ct1 == ct2) {
b = 1;
} else if (ctype_type(ct1->info) == ctype_type(ct2->info) &&
ct1->size == ct2->size) {
if (ctype_ispointer(ct1->info))
b = lj_cconv_compatptr(cts, ct1, ct2, CCF_IGNQUAL);
else if (ctype_isnum(ct1->info) || ctype_isvoid(ct1->info))
b = (((ct1->info ^ ct2->info) & ~(CTF_QUAL|CTF_LONG)) == 0);
} else if (ctype_isstruct(ct1->info) && ctype_isptr(ct2->info) &&
ct1 == ctype_rawchild(cts, ct2)) {
b = 1;
}
}
setboolV(L->top-1, b);
setboolV(&G(L)->tmptv2, b); /* Remember for trace recorder. */
return 1;
}
LJLIB_CF(ffi_sizeof) LJLIB_REC(ffi_xof FF_ffi_sizeof)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
CTSize sz;
if (LJ_UNLIKELY(tviscdata(L->base) && cdataisv(cdataV(L->base)))) {
sz = cdatavlen(cdataV(L->base));
} else {
CType *ct = lj_ctype_rawref(cts, id);
if (ctype_isvltype(ct->info))
sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
else
sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_INVALID;
if (LJ_UNLIKELY(sz == CTSIZE_INVALID)) {
setnilV(L->top-1);
return 1;
}
}
setintV(L->top-1, (int32_t)sz);
return 1;
}
LJLIB_CF(ffi_alignof) LJLIB_REC(ffi_xof FF_ffi_alignof)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
CTSize sz = 0;
CTInfo info = lj_ctype_info_raw(cts, id, &sz);
setintV(L->top-1, 1 << ctype_align(info));
return 1;
}
LJLIB_CF(ffi_offsetof) LJLIB_REC(ffi_xof FF_ffi_offsetof)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
GCstr *name = lj_lib_checkstr(L, 2);
CType *ct = lj_ctype_rawref(cts, id);
CTSize ofs;
if (ctype_isstruct(ct->info) && ct->size != CTSIZE_INVALID) {
CType *fct = lj_ctype_getfield(cts, ct, name, &ofs);
if (fct) {
setintV(L->top-1, ofs);
if (ctype_isfield(fct->info)) {
return 1;
} else if (ctype_isbitfield(fct->info)) {
setintV(L->top++, ctype_bitpos(fct->info));
setintV(L->top++, ctype_bitbsz(fct->info));
return 3;
}
}
}
return 0;
}
LJLIB_CF(ffi_errno) LJLIB_REC(.)
{
int err = errno;
if (L->top > L->base)
errno = ffi_checkint(L, 1);
setintV(L->top++, err);
return 1;
}
LJLIB_CF(ffi_string) LJLIB_REC(.)
{
CTState *cts = ctype_cts(L);
TValue *o = lj_lib_checkany(L, 1);
const char *p;
size_t len;
if (o+1 < L->top && !tvisnil(o+1)) {
len = (size_t)ffi_checkint(L, 2);
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p, o,
CCF_ARG(1));
} else {
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CCHAR), (uint8_t *)&p, o,
CCF_ARG(1));
len = strlen(p);
}
L->top = o+1; /* Make sure this is the last item on the stack. */
setstrV(L, o, lj_str_new(L, p, len));
lj_gc_check(L);
return 1;
}
LJLIB_CF(ffi_copy) LJLIB_REC(.)
{
void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
void *sp = ffi_checkptr(L, 2, CTID_P_CVOID);
TValue *o = L->base+1;
CTSize len;
if (tvisstr(o) && o+1 >= L->top)
len = strV(o)->len+1; /* Copy Lua string including trailing '\0'. */
else
len = (CTSize)ffi_checkint(L, 3);
memcpy(dp, sp, len);
return 0;
}
LJLIB_CF(ffi_fill) LJLIB_REC(.)
{
void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
CTSize len = (CTSize)ffi_checkint(L, 2);
int32_t fill = 0;
if (L->base+2 < L->top && !tvisnil(L->base+2)) fill = ffi_checkint(L, 3);
memset(dp, fill, len);
return 0;
}
/* Test ABI string. */
LJLIB_CF(ffi_abi) LJLIB_REC(.)
{
GCstr *s = lj_lib_checkstr(L, 1);
int b = lj_cparse_case(s,
#if LJ_64
"\00564bit"
#else
"\00532bit"
#endif
#if LJ_ARCH_HASFPU
"\003fpu"
#endif
#if LJ_ABI_SOFTFP
"\006softfp"
#else
"\006hardfp"
#endif
#if LJ_ABI_EABI
"\004eabi"
#endif
#if LJ_ABI_WIN
"\003win"
#endif
#if LJ_ABI_PAUTH
"\005pauth"
#endif
#if LJ_TARGET_UWP
"\003uwp"
#endif
#if LJ_LE
"\002le"
#else
"\002be"
#endif
#if LJ_GC64
"\004gc64"
#endif
) >= 0;
setboolV(L->top-1, b);
setboolV(&G(L)->tmptv2, b); /* Remember for trace recorder. */
return 1;
}
LJLIB_PUSH(top-7) LJLIB_SET(!) /* Store reference to miscmap table. */
LJLIB_CF(ffi_metatype)
{
CTState *cts = ctype_cts(L);
CTypeID id = ffi_checkctype(L, cts, NULL);
GCtab *mt = lj_lib_checktab(L, 2);
GCtab *t = cts->miscmap;
CType *ct = ctype_raw(cts, id);
TValue *tv;
GCcdata *cd;
if (!(ctype_isstruct(ct->info) || ctype_iscomplex(ct->info) ||
ctype_isvector(ct->info)))
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
tv = lj_tab_setinth(L, t, -(int32_t)ctype_typeid(cts, ct));
if (!tvisnil(tv))
lj_err_caller(L, LJ_ERR_PROTMT);
settabV(L, tv, mt);
lj_gc_anybarriert(L, t);
cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
*(CTypeID *)cdataptr(cd) = id;
setcdataV(L, L->top-1, cd);
lj_gc_check(L);
return 1;
}
LJLIB_CF(ffi_gc) LJLIB_REC(.)
{
GCcdata *cd = ffi_checkcdata(L, 1);
TValue *fin = lj_lib_checkany(L, 2);
CTState *cts = ctype_cts(L);
CType *ct = ctype_raw(cts, cd->ctypeid);
if (!(ctype_isptr(ct->info) || ctype_isstruct(ct->info) ||
ctype_isrefarray(ct->info)))
lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
lj_cdata_setfin(L, cd, gcval(fin), itype(fin));
L->top = L->base+1; /* Pass through the cdata object. */
return 1;
}
LJLIB_PUSH(top-5) LJLIB_SET(!) /* Store clib metatable in func environment. */
LJLIB_CF(ffi_load)
{
GCstr *name = lj_lib_checkstr(L, 1);
int global = (L->base+1 < L->top && tvistruecond(L->base+1));
lj_clib_load(L, tabref(curr_func(L)->c.env), name, global);
return 1;
}
LJLIB_PUSH(top-4) LJLIB_SET(C)
LJLIB_PUSH(top-3) LJLIB_SET(os)
LJLIB_PUSH(top-2) LJLIB_SET(arch)
#include "lj_libdef.h"
/* ------------------------------------------------------------------------ */
/* Register FFI module as loaded. */
static void ffi_register_module(lua_State *L)
{
cTValue *tmp = lj_tab_getstr(tabV(registry(L)), lj_str_newlit(L, "_LOADED"));
if (tmp && tvistab(tmp)) {
GCtab *t = tabV(tmp);
copyTV(L, lj_tab_setstr(L, t, lj_str_newlit(L, LUA_FFILIBNAME)), L->top-1);
lj_gc_anybarriert(L, t);
}
}
LUALIB_API int luaopen_ffi(lua_State *L)
{
CTState *cts = lj_ctype_init(L);
settabV(L, L->top++, (cts->miscmap = lj_tab_new(L, 0, 1)));
LJ_LIB_REG(L, NULL, ffi_meta);
/* NOBARRIER: basemt is a GC root. */
setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
LJ_LIB_REG(L, NULL, ffi_clib);
LJ_LIB_REG(L, NULL, ffi_callback);
/* NOBARRIER: the key is new and lj_tab_newkey() handles the barrier. */
settabV(L, lj_tab_setstr(L, cts->miscmap, &cts->g->strempty), tabV(L->top-1));
L->top--;
lj_clib_default(L, tabV(L->top-1)); /* Create ffi.C default namespace. */
lua_pushliteral(L, LJ_OS_NAME);
lua_pushliteral(L, LJ_ARCH_NAME);
LJ_LIB_REG(L, NULL, ffi); /* Note: no global "ffi" created! */
ffi_register_module(L);
return 1;
}
#endif
+65
View File
@@ -0,0 +1,65 @@
/*
** Library initialization.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** Major parts taken verbatim from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lib_init_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_arch.h"
static const luaL_Reg lj_lib_load[] = {
{ "", luaopen_base },
#if !LJ_SRB2LIB
{ LUA_LOADLIBNAME, luaopen_package },
#endif
{ LUA_TABLIBNAME, luaopen_table },
{ LUA_IOLIBNAME, luaopen_io },
#if !LJ_SRB2LIB || (LJ_SRB2LIB && LJ_SRB2OS)
{ LUA_OSLIBNAME, luaopen_os },
#endif
{ LUA_STRLIBNAME, luaopen_string },
#if !LJ_SRB2LIB
{ LUA_MATHLIBNAME, luaopen_math },
#endif
#if !LJ_SRB2LIB || (LJ_SRB2LIB && LJ_SRB2DEBUG)
{ LUA_DBLIBNAME, luaopen_debug },
#endif
#if !LJ_SRB2LIB
{ LUA_BITLIBNAME, luaopen_bit },
#endif
{ LUA_JITLIBNAME, luaopen_jit },
{ NULL, NULL }
};
static const luaL_Reg lj_lib_preload[] = {
#if LJ_HASFFI
{ LUA_FFILIBNAME, luaopen_ffi },
#endif
{ NULL, NULL }
};
LUALIB_API void luaL_openlibs(lua_State *L)
{
const luaL_Reg *lib;
for (lib = lj_lib_load; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_pushstring(L, lib->name);
lua_call(L, 1, 0);
}
luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD",
sizeof(lj_lib_preload)/sizeof(lj_lib_preload[0])-1);
for (lib = lj_lib_preload; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_setfield(L, -2, lib->name);
}
lua_pop(L, 1);
}
+559
View File
@@ -0,0 +1,559 @@
/*
** I/O library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2011 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#include <errno.h>
#include <stdio.h>
#define lib_io_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_state.h"
#include "lj_strfmt.h"
#include "lj_ff.h"
#include "lj_lib.h"
/* Userdata payload for I/O file. */
typedef struct IOFileUD {
FILE *fp; /* File handle. */
uint32_t type; /* File type. */
} IOFileUD;
#define IOFILE_TYPE_FILE 0 /* Regular file. */
#define IOFILE_TYPE_PIPE 1 /* Pipe. */
#define IOFILE_TYPE_STDF 2 /* Standard file handle. */
#define IOFILE_TYPE_MASK 3
#define IOFILE_FLAG_CLOSE 4 /* Close after io.lines() iterator. */
#define IOSTDF_UD(L, id) (&gcref(G(L)->gcroot[(id)])->ud)
#define IOSTDF_IOF(L, id) ((IOFileUD *)uddata(IOSTDF_UD(L, (id))))
/* -- Open/close helpers -------------------------------------------------- */
static IOFileUD *io_tofilep(lua_State *L)
{
if (!(L->base < L->top && tvisudata(L->base) &&
udataV(L->base)->udtype == UDTYPE_IO_FILE))
lj_err_argtype(L, 1, "FILE*");
return (IOFileUD *)uddata(udataV(L->base));
}
static IOFileUD *io_tofile(lua_State *L)
{
IOFileUD *iof = io_tofilep(L);
if (iof->fp == NULL)
lj_err_caller(L, LJ_ERR_IOCLFL);
return iof;
}
#if !LJ_SRB2LIB || (LJ_SRB2LIB && LJ_SRB2IO)
static IOFileUD *io_stdfile(lua_State *L, ptrdiff_t id)
{
IOFileUD *iof = IOSTDF_IOF(L, id);
if (iof->fp == NULL)
lj_err_caller(L, LJ_ERR_IOSTDCL);
return iof;
}
#endif
static IOFileUD *io_file_new(lua_State *L)
{
IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD));
GCudata *ud = udataV(L->top-1);
ud->udtype = UDTYPE_IO_FILE;
/* NOBARRIER: The GCudata is new (marked white). */
setgcrefr(ud->metatable, curr_func(L)->c.env);
iof->fp = NULL;
iof->type = IOFILE_TYPE_FILE;
return iof;
}
#if !LJ_SRB2LIB || (LJ_SRB2LIB && LJ_SRB2IO)
static IOFileUD *io_file_open(lua_State *L, const char *mode)
{
const char *fname = strdata(lj_lib_checkstr(L, 1));
IOFileUD *iof = io_file_new(L);
iof->fp = fopen(fname, mode);
if (iof->fp == NULL)
luaL_argerror(L, 1, lj_strfmt_pushf(L, "%s: %s", fname, strerror(errno)));
return iof;
}
#endif
static int io_file_close(lua_State *L, IOFileUD *iof)
{
int ok;
if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_FILE) {
ok = (fclose(iof->fp) == 0);
} else if ((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_PIPE) {
int stat = -1;
#if LJ_TARGET_POSIX
stat = pclose(iof->fp);
#elif LJ_TARGET_WINDOWS && !LJ_TARGET_XBOXONE && !LJ_TARGET_UWP
stat = _pclose(iof->fp);
#endif
#if LJ_52
iof->fp = NULL;
return luaL_execresult(L, stat);
#else
ok = (stat != -1);
#endif
} else {
lj_assertL((iof->type & IOFILE_TYPE_MASK) == IOFILE_TYPE_STDF,
"close of unknown FILE* type");
setnilV(L->top++);
lua_pushliteral(L, "cannot close standard file");
return 2;
}
iof->fp = NULL;
return luaL_fileresult(L, ok, NULL);
}
/* -- Read/write helpers -------------------------------------------------- */
static int io_file_readnum(lua_State *L, FILE *fp)
{
lua_Number d;
if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) {
if (LJ_DUALNUM) {
int32_t i = lj_num2int(d);
if (d == (lua_Number)i && !tvismzero((cTValue *)&d)) {
setintV(L->top++, i);
return 1;
}
}
setnumV(L->top++, d);
return 1;
} else {
setnilV(L->top++);
return 0;
}
}
static int io_file_readline(lua_State *L, FILE *fp, MSize chop)
{
MSize m = LUAL_BUFFERSIZE, n = 0, ok = 0;
char *buf;
for (;;) {
buf = lj_buf_tmp(L, m);
if (fgets(buf+n, m-n, fp) == NULL) break;
n += (MSize)strlen(buf+n);
ok |= n;
if (n && buf[n-1] == '\n') { n -= chop; break; }
if (n >= m - 64) m += m;
}
setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n));
lj_gc_check(L);
return (int)ok;
}
static void io_file_readall(lua_State *L, FILE *fp)
{
MSize m, n;
for (m = LUAL_BUFFERSIZE, n = 0; ; m += m) {
char *buf = lj_buf_tmp(L, m);
n += (MSize)fread(buf+n, 1, m-n, fp);
if (n != m) {
setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n));
lj_gc_check(L);
return;
}
}
}
static int io_file_readlen(lua_State *L, FILE *fp, MSize m)
{
if (m) {
char *buf = lj_buf_tmp(L, m);
MSize n = (MSize)fread(buf, 1, m, fp);
setstrV(L, L->top++, lj_str_new(L, buf, (size_t)n));
lj_gc_check(L);
return n > 0;
} else {
int c = getc(fp);
ungetc(c, fp);
setstrV(L, L->top++, &G(L)->strempty);
return (c != EOF);
}
}
static int io_file_read(lua_State *L, IOFileUD *iof, int start)
{
FILE *fp = iof->fp;
int ok, n, nargs = (int)(L->top - L->base) - start;
clearerr(fp);
if (nargs == 0) {
ok = io_file_readline(L, fp, 1);
n = start+1; /* Return 1 result. */
} else {
/* The results plus the buffers go on top of the args. */
luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
ok = 1;
for (n = start; nargs-- && ok; n++) {
if (tvisstr(L->base+n)) {
const char *p = strVdata(L->base+n);
if (p[0] == '*') p++;
if (p[0] == 'n')
ok = io_file_readnum(L, fp);
else if ((p[0] & ~0x20) == 'L')
ok = io_file_readline(L, fp, (p[0] == 'l'));
else if (p[0] == 'a')
io_file_readall(L, fp);
else
lj_err_arg(L, n+1, LJ_ERR_INVFMT);
} else if (tvisnumber(L->base+n)) {
ok = io_file_readlen(L, fp, (MSize)lj_lib_checkint(L, n+1));
} else {
lj_err_arg(L, n+1, LJ_ERR_INVOPT);
}
}
}
if (ferror(fp))
return luaL_fileresult(L, 0, NULL);
if (!ok)
setnilV(L->top-1); /* Replace last result with nil. */
return n - start;
}
static int io_file_write(lua_State *L, IOFileUD *iof, int start)
{
FILE *fp = iof->fp;
cTValue *tv;
int status = 1;
for (tv = L->base+start; tv < L->top; tv++) {
MSize len;
const char *p = lj_strfmt_wstrnum(L, tv, &len);
if (!p)
lj_err_argt(L, (int)(tv - L->base) + 1, LUA_TSTRING);
status = status && (fwrite(p, 1, len, fp) == len);
}
if (LJ_52 && status) {
L->top = L->base+1;
if (start == 0)
setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_OUTPUT));
return 1;
}
return luaL_fileresult(L, status, NULL);
}
static int io_file_iter(lua_State *L)
{
GCfunc *fn = curr_func(L);
IOFileUD *iof = uddata(udataV(&fn->c.upvalue[0]));
int n = fn->c.nupvalues - 1;
if (iof->fp == NULL)
lj_err_caller(L, LJ_ERR_IOCLFL);
L->top = L->base;
if (n) { /* Copy upvalues with options to stack. */
lj_state_checkstack(L, (MSize)n);
memcpy(L->top, &fn->c.upvalue[1], n*sizeof(TValue));
L->top += n;
}
n = io_file_read(L, iof, 0);
if (ferror(iof->fp))
lj_err_callermsg(L, strVdata(L->top-2));
if (tvisnil(L->base) && (iof->type & IOFILE_FLAG_CLOSE)) {
io_file_close(L, iof); /* Return values are ignored. */
return 0;
}
return n;
}
static int io_file_lines(lua_State *L)
{
int n = (int)(L->top - L->base);
if (n > LJ_MAX_UPVAL)
lj_err_caller(L, LJ_ERR_UNPACK);
lua_pushcclosure(L, io_file_iter, n);
return 1;
}
/* -- I/O file methods ---------------------------------------------------- */
#define LJLIB_MODULE_io_method
LJLIB_CF(io_method_close)
{
IOFileUD *iof;
if (L->base < L->top) {
iof = io_tofile(L);
} else {
iof = IOSTDF_IOF(L, GCROOT_IO_OUTPUT);
if (iof->fp == NULL)
lj_err_caller(L, LJ_ERR_IOCLFL);
}
return io_file_close(L, iof);
}
LJLIB_CF(io_method_read)
{
return io_file_read(L, io_tofile(L), 1);
}
LJLIB_CF(io_method_write) LJLIB_REC(io_write 0)
{
return io_file_write(L, io_tofile(L), 1);
}
LJLIB_CF(io_method_flush) LJLIB_REC(io_flush 0)
{
return luaL_fileresult(L, fflush(io_tofile(L)->fp) == 0, NULL);
}
#if LJ_32 && defined(__ANDROID__) && __ANDROID_API__ < 24
/* The Android NDK is such an unmatched marvel of engineering. */
extern int fseeko32(FILE *, long int, int) __asm__("fseeko");
extern long int ftello32(FILE *) __asm__("ftello");
#define fseeko(fp, pos, whence) (fseeko32((fp), (pos), (whence)))
#define ftello(fp) (ftello32((fp)))
#endif
LJLIB_CF(io_method_seek)
{
FILE *fp = io_tofile(L)->fp;
int opt = lj_lib_checkopt(L, 2, 1, "\3set\3cur\3end");
int64_t ofs = 0;
cTValue *o;
int res;
if (opt == 0) opt = SEEK_SET;
else if (opt == 1) opt = SEEK_CUR;
else if (opt == 2) opt = SEEK_END;
o = L->base+2;
if (o < L->top) {
if (tvisint(o))
ofs = (int64_t)intV(o);
else if (tvisnum(o))
ofs = (int64_t)numV(o);
else if (!tvisnil(o))
lj_err_argt(L, 3, LUA_TNUMBER);
}
#if LJ_TARGET_POSIX
res = fseeko(fp, ofs, opt);
#elif _MSC_VER >= 1400
res = _fseeki64(fp, ofs, opt);
#elif defined(__MINGW32__)
res = fseeko64(fp, ofs, opt);
#else
res = fseek(fp, (long)ofs, opt);
#endif
if (res)
return luaL_fileresult(L, 0, NULL);
#if LJ_TARGET_POSIX
ofs = ftello(fp);
#elif _MSC_VER >= 1400
ofs = _ftelli64(fp);
#elif defined(__MINGW32__)
ofs = ftello64(fp);
#else
ofs = (int64_t)ftell(fp);
#endif
setint64V(L->top-1, ofs);
return 1;
}
LJLIB_CF(io_method_setvbuf)
{
FILE *fp = io_tofile(L)->fp;
int opt = lj_lib_checkopt(L, 2, -1, "\4full\4line\2no");
size_t sz = (size_t)lj_lib_optint(L, 3, LUAL_BUFFERSIZE);
if (opt == 0) opt = _IOFBF;
else if (opt == 1) opt = _IOLBF;
else if (opt == 2) opt = _IONBF;
return luaL_fileresult(L, setvbuf(fp, NULL, opt, sz) == 0, NULL);
}
LJLIB_CF(io_method_lines)
{
io_tofile(L);
return io_file_lines(L);
}
LJLIB_CF(io_method___gc)
{
IOFileUD *iof = io_tofilep(L);
if (iof->fp != NULL && (iof->type & IOFILE_TYPE_MASK) != IOFILE_TYPE_STDF)
io_file_close(L, iof);
return 0;
}
LJLIB_CF(io_method___tostring)
{
IOFileUD *iof = io_tofilep(L);
if (iof->fp != NULL)
lua_pushfstring(L, "file (%p)", iof->fp);
else
lua_pushliteral(L, "file (closed)");
return 1;
}
LJLIB_PUSH(top-1) LJLIB_SET(__index)
#include "lj_libdef.h"
/* -- I/O library functions ----------------------------------------------- */
#define LJLIB_MODULE_io
LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
LJLIB_CF(io_open)
{
const char *fname = strdata(lj_lib_checkstr(L, 1));
GCstr *s = lj_lib_optstr(L, 2);
const char *mode = s ? strdata(s) : "r";
IOFileUD *iof = io_file_new(L);
iof->fp = fopen(fname, mode);
return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname);
}
#if !LJ_SRB2LIB
LJLIB_CF(io_popen)
{
#if LJ_TARGET_POSIX || (LJ_TARGET_WINDOWS && !LJ_TARGET_XBOXONE && !LJ_TARGET_UWP)
const char *fname = strdata(lj_lib_checkstr(L, 1));
GCstr *s = lj_lib_optstr(L, 2);
const char *mode = s ? strdata(s) : "r";
IOFileUD *iof = io_file_new(L);
iof->type = IOFILE_TYPE_PIPE;
#if LJ_TARGET_POSIX
fflush(NULL);
iof->fp = popen(fname, mode);
#else
iof->fp = _popen(fname, mode);
#endif
return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname);
#else
return luaL_error(L, LUA_QL("popen") " not supported");
#endif
}
#endif
LJLIB_CF(io_tmpfile)
{
IOFileUD *iof = io_file_new(L);
#if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PS5 || LJ_TARGET_PSVITA || LJ_TARGET_NX
iof->fp = NULL; errno = ENOSYS;
#else
iof->fp = tmpfile();
#endif
return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, NULL);
}
LJLIB_CF(io_close)
{
return lj_cf_io_method_close(L);
}
#if !LJ_SRB2LIB || (LJ_SRB2LIB && LJ_SRB2IO)
LJLIB_CF(io_read)
{
return io_file_read(L, io_stdfile(L, GCROOT_IO_INPUT), 0);
}
LJLIB_CF(io_write) LJLIB_REC(io_write GCROOT_IO_OUTPUT)
{
return io_file_write(L, io_stdfile(L, GCROOT_IO_OUTPUT), 0);
}
LJLIB_CF(io_flush) LJLIB_REC(io_flush GCROOT_IO_OUTPUT)
{
return luaL_fileresult(L, fflush(io_stdfile(L, GCROOT_IO_OUTPUT)->fp) == 0, NULL);
}
static int io_std_getset(lua_State *L, ptrdiff_t id, const char *mode)
{
if (L->base < L->top && !tvisnil(L->base)) {
if (tvisudata(L->base)) {
io_tofile(L);
L->top = L->base+1;
} else {
io_file_open(L, mode);
}
/* NOBARRIER: The standard I/O handles are GC roots. */
setgcref(G(L)->gcroot[id], gcV(L->top-1));
} else {
setudataV(L, L->top++, IOSTDF_UD(L, id));
}
return 1;
}
LJLIB_CF(io_input)
{
return io_std_getset(L, GCROOT_IO_INPUT, "r");
}
LJLIB_CF(io_output)
{
return io_std_getset(L, GCROOT_IO_OUTPUT, "w");
}
LJLIB_CF(io_lines)
{
if (L->base == L->top) setnilV(L->top++);
if (!tvisnil(L->base)) { /* io.lines(fname) */
IOFileUD *iof = io_file_open(L, "r");
iof->type = IOFILE_TYPE_FILE|IOFILE_FLAG_CLOSE;
L->top--;
setudataV(L, L->base, udataV(L->top));
} else { /* io.lines() iterates over stdin. */
setudataV(L, L->base, IOSTDF_UD(L, GCROOT_IO_INPUT));
}
return io_file_lines(L);
}
#endif
LJLIB_CF(io_type)
{
cTValue *o = lj_lib_checkany(L, 1);
if (!(tvisudata(o) && udataV(o)->udtype == UDTYPE_IO_FILE))
setnilV(L->top++);
else if (((IOFileUD *)uddata(udataV(o)))->fp != NULL)
lua_pushliteral(L, "file");
else
lua_pushliteral(L, "closed file");
return 1;
}
#include "lj_libdef.h"
/* ------------------------------------------------------------------------ */
static GCobj *io_std_new(lua_State *L, FILE *fp, const char *name)
{
IOFileUD *iof = (IOFileUD *)lua_newuserdata(L, sizeof(IOFileUD));
GCudata *ud = udataV(L->top-1);
ud->udtype = UDTYPE_IO_FILE;
/* NOBARRIER: The GCudata is new (marked white). */
setgcref(ud->metatable, gcV(L->top-3));
iof->fp = fp;
iof->type = IOFILE_TYPE_STDF;
lua_setfield(L, -2, name);
return obj2gco(ud);
}
LUALIB_API int luaopen_io(lua_State *L)
{
LJ_LIB_REG(L, NULL, io_method);
copyTV(L, L->top, L->top-1); L->top++;
lua_setfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
LJ_LIB_REG(L, LUA_IOLIBNAME, io);
setgcref(G(L)->gcroot[GCROOT_IO_INPUT], io_std_new(L, stdin, "stdin"));
setgcref(G(L)->gcroot[GCROOT_IO_OUTPUT], io_std_new(L, stdout, "stdout"));
io_std_new(L, stderr, "stderr");
return 1;
}
+744
View File
@@ -0,0 +1,744 @@
/*
** JIT library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#define lib_jit_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_debug.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_state.h"
#include "lj_bc.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#endif
#if LJ_HASJIT
#include "lj_ir.h"
#include "lj_jit.h"
#include "lj_ircall.h"
#include "lj_iropt.h"
#include "lj_target.h"
#endif
#include "lj_trace.h"
#include "lj_dispatch.h"
#include "lj_vm.h"
#include "lj_vmevent.h"
#include "lj_lib.h"
#include "luajit.h"
/* -- jit.* functions ----------------------------------------------------- */
#define LJLIB_MODULE_jit
static int setjitmode(lua_State *L, int mode)
{
int idx = 0;
if (L->base == L->top || tvisnil(L->base)) { /* jit.on/off/flush([nil]) */
mode |= LUAJIT_MODE_ENGINE;
} else {
/* jit.on/off/flush(func|proto, nil|true|false) */
if (tvisfunc(L->base) || tvisproto(L->base))
idx = 1;
else if (!tvistrue(L->base)) /* jit.on/off/flush(true, nil|true|false) */
goto err;
if (L->base+1 < L->top && tvisbool(L->base+1))
mode |= boolV(L->base+1) ? LUAJIT_MODE_ALLFUNC : LUAJIT_MODE_ALLSUBFUNC;
else
mode |= LUAJIT_MODE_FUNC;
}
if (luaJIT_setmode(L, idx, mode) != 1) {
if ((mode & LUAJIT_MODE_MASK) == LUAJIT_MODE_ENGINE)
lj_err_caller(L, LJ_ERR_NOJIT);
err:
lj_err_argt(L, 1, LUA_TFUNCTION);
}
return 0;
}
LJLIB_CF(jit_on)
{
return setjitmode(L, LUAJIT_MODE_ON);
}
LJLIB_CF(jit_off)
{
return setjitmode(L, LUAJIT_MODE_OFF);
}
LJLIB_CF(jit_flush)
{
#if LJ_HASJIT
if (L->base < L->top && tvisnumber(L->base)) {
int traceno = lj_lib_checkint(L, 1);
luaJIT_setmode(L, traceno, LUAJIT_MODE_FLUSH|LUAJIT_MODE_TRACE);
return 0;
}
#endif
return setjitmode(L, LUAJIT_MODE_FLUSH);
}
#if LJ_HASJIT
/* Push a string for every flag bit that is set. */
static void flagbits_to_strings(lua_State *L, uint32_t flags, uint32_t base,
const char *str)
{
for (; *str; base <<= 1, str += 1+*str)
if (flags & base)
setstrV(L, L->top++, lj_str_new(L, str+1, *(uint8_t *)str));
}
#endif
LJLIB_CF(jit_status)
{
#if LJ_HASJIT
jit_State *J = L2J(L);
L->top = L->base;
setboolV(L->top++, (J->flags & JIT_F_ON) ? 1 : 0);
flagbits_to_strings(L, J->flags, JIT_F_CPU, JIT_F_CPUSTRING);
flagbits_to_strings(L, J->flags, JIT_F_OPT, JIT_F_OPTSTRING);
return (int)(L->top - L->base);
#else
setboolV(L->top++, 0);
return 1;
#endif
}
LJLIB_CF(jit_security)
{
int idx = lj_lib_checkopt(L, 1, -1, LJ_SECURITY_MODESTRING);
setintV(L->top++, ((LJ_SECURITY_MODE >> (2*idx)) & 3));
return 1;
}
LJLIB_CF(jit_attach)
{
#ifdef LUAJIT_DISABLE_VMEVENT
luaL_error(L, "vmevent API disabled");
#else
GCfunc *fn = lj_lib_checkfunc(L, 1);
GCstr *s = lj_lib_optstr(L, 2);
luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
if (s) { /* Attach to given event. */
const uint8_t *p = (const uint8_t *)strdata(s);
uint32_t h = s->len;
while (*p) h = h ^ (lj_rol(h, 6) + *p++);
lua_pushvalue(L, 1);
lua_rawseti(L, -2, VMEVENT_HASHIDX(h));
G(L)->vmevmask = VMEVENT_NOCACHE; /* Invalidate cache. */
} else { /* Detach if no event given. */
setnilV(L->top++);
while (lua_next(L, -2)) {
L->top--;
if (tvisfunc(L->top) && funcV(L->top) == fn) {
setnilV(lj_tab_set(L, tabV(L->top-2), L->top-1));
}
}
}
#endif
return 0;
}
LJLIB_PUSH(top-5) LJLIB_SET(os)
LJLIB_PUSH(top-4) LJLIB_SET(arch)
LJLIB_PUSH(top-3) LJLIB_SET(version_num)
LJLIB_PUSH(top-2) LJLIB_SET(version)
#include "lj_libdef.h"
/* -- jit.util.* functions ------------------------------------------------ */
#define LJLIB_MODULE_jit_util
/* -- Reflection API for Lua functions ------------------------------------ */
static void setintfield(lua_State *L, GCtab *t, const char *name, int32_t val)
{
setintV(lj_tab_setstr(L, t, lj_str_newz(L, name)), val);
}
/* local info = jit.util.funcinfo(func [,pc]) */
LJLIB_CF(jit_util_funcinfo)
{
GCproto *pt = lj_lib_checkLproto(L, 1, 1);
if (pt) {
BCPos pc = (BCPos)lj_lib_optint(L, 2, 0);
GCtab *t;
lua_createtable(L, 0, 16); /* Increment hash size if fields are added. */
t = tabV(L->top-1);
setintfield(L, t, "linedefined", pt->firstline);
setintfield(L, t, "lastlinedefined", pt->firstline + pt->numline);
setintfield(L, t, "stackslots", pt->framesize);
setintfield(L, t, "params", pt->numparams);
setintfield(L, t, "bytecodes", (int32_t)pt->sizebc);
setintfield(L, t, "gcconsts", (int32_t)pt->sizekgc);
setintfield(L, t, "nconsts", (int32_t)pt->sizekn);
setintfield(L, t, "upvalues", (int32_t)pt->sizeuv);
if (pc < pt->sizebc)
setintfield(L, t, "currentline", lj_debug_line(pt, pc));
lua_pushboolean(L, (pt->flags & PROTO_VARARG));
lua_setfield(L, -2, "isvararg");
lua_pushboolean(L, (pt->flags & PROTO_CHILD));
lua_setfield(L, -2, "children");
setstrV(L, L->top++, proto_chunkname(pt));
lua_setfield(L, -2, "source");
lj_debug_pushloc(L, pt, pc);
lua_setfield(L, -2, "loc");
setprotoV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "proto")), pt);
} else {
GCfunc *fn = funcV(L->base);
GCtab *t;
lua_createtable(L, 0, 4); /* Increment hash size if fields are added. */
t = tabV(L->top-1);
if (!iscfunc(fn))
setintfield(L, t, "ffid", fn->c.ffid);
setintptrV(lj_tab_setstr(L, t, lj_str_newlit(L, "addr")),
(intptr_t)(void *)fn->c.f);
setintfield(L, t, "upvalues", fn->c.nupvalues);
}
return 1;
}
/* local ins, m = jit.util.funcbc(func, pc) */
LJLIB_CF(jit_util_funcbc)
{
GCproto *pt = lj_lib_checkLproto(L, 1, 0);
BCPos pc = (BCPos)lj_lib_checkint(L, 2);
if (pc < pt->sizebc) {
BCIns ins = proto_bc(pt)[pc];
BCOp op = bc_op(ins);
lj_assertL(op < BC__MAX, "bad bytecode op %d", op);
setintV(L->top, ins);
setintV(L->top+1, lj_bc_mode[op]);
L->top += 2;
return 2;
}
return 0;
}
/* local k = jit.util.funck(func, idx) */
LJLIB_CF(jit_util_funck)
{
GCproto *pt = lj_lib_checkLproto(L, 1, 0);
ptrdiff_t idx = (ptrdiff_t)lj_lib_checkint(L, 2);
if (idx >= 0) {
if (idx < (ptrdiff_t)pt->sizekn) {
copyTV(L, L->top-1, proto_knumtv(pt, idx));
return 1;
}
} else {
if (~idx < (ptrdiff_t)pt->sizekgc) {
GCobj *gc = proto_kgc(pt, idx);
setgcV(L, L->top-1, gc, ~gc->gch.gct);
return 1;
}
}
return 0;
}
/* local name = jit.util.funcuvname(func, idx) */
LJLIB_CF(jit_util_funcuvname)
{
GCproto *pt = lj_lib_checkLproto(L, 1, 0);
uint32_t idx = (uint32_t)lj_lib_checkint(L, 2);
if (idx < pt->sizeuv) {
setstrV(L, L->top-1, lj_str_newz(L, lj_debug_uvname(pt, idx)));
return 1;
}
return 0;
}
/* -- Reflection API for traces ------------------------------------------- */
#if LJ_HASJIT
/* Check trace argument. Must not throw for non-existent trace numbers. */
static GCtrace *jit_checktrace(lua_State *L)
{
TraceNo tr = (TraceNo)lj_lib_checkint(L, 1);
jit_State *J = L2J(L);
if (tr > 0 && tr < J->sizetrace)
return traceref(J, tr);
return NULL;
}
/* Names of link types. ORDER LJ_TRLINK */
static const char *const jit_trlinkname[] = {
"none", "root", "loop", "tail-recursion", "up-recursion", "down-recursion",
"interpreter", "return", "stitch"
};
/* local info = jit.util.traceinfo(tr) */
LJLIB_CF(jit_util_traceinfo)
{
GCtrace *T = jit_checktrace(L);
if (T) {
GCtab *t;
lua_createtable(L, 0, 8); /* Increment hash size if fields are added. */
t = tabV(L->top-1);
setintfield(L, t, "nins", (int32_t)T->nins - REF_BIAS - 1);
setintfield(L, t, "nk", REF_BIAS - (int32_t)T->nk);
setintfield(L, t, "link", T->link);
setintfield(L, t, "nexit", T->nsnap);
setstrV(L, L->top++, lj_str_newz(L, jit_trlinkname[T->linktype]));
lua_setfield(L, -2, "linktype");
/* There are many more fields. Add them only when needed. */
return 1;
}
return 0;
}
/* local m, ot, op1, op2, prev = jit.util.traceir(tr, idx) */
LJLIB_CF(jit_util_traceir)
{
GCtrace *T = jit_checktrace(L);
IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
if (T && ref >= REF_BIAS && ref < T->nins) {
IRIns *ir = &T->ir[ref];
int32_t m = lj_ir_mode[ir->o];
setintV(L->top-2, m);
setintV(L->top-1, ir->ot);
setintV(L->top++, (int32_t)ir->op1 - (irm_op1(m)==IRMref ? REF_BIAS : 0));
setintV(L->top++, (int32_t)ir->op2 - (irm_op2(m)==IRMref ? REF_BIAS : 0));
setintV(L->top++, ir->prev);
return 5;
}
return 0;
}
/* local k, t [, slot] = jit.util.tracek(tr, idx) */
LJLIB_CF(jit_util_tracek)
{
GCtrace *T = jit_checktrace(L);
IRRef ref = (IRRef)lj_lib_checkint(L, 2) + REF_BIAS;
if (T && ref >= T->nk && ref < REF_BIAS) {
IRIns *ir = &T->ir[ref];
int32_t slot = -1;
if (ir->o == IR_KSLOT) {
slot = ir->op2;
ir = &T->ir[ir->op1];
}
#if LJ_HASFFI
if (ir->o == IR_KINT64) ctype_loadffi(L);
#endif
lj_ir_kvalue(L, L->top-2, ir);
setintV(L->top-1, (int32_t)irt_type(ir->t));
if (slot == -1)
return 2;
setintV(L->top++, slot);
return 3;
}
return 0;
}
/* local snap = jit.util.tracesnap(tr, sn) */
LJLIB_CF(jit_util_tracesnap)
{
GCtrace *T = jit_checktrace(L);
SnapNo sn = (SnapNo)lj_lib_checkint(L, 2);
if (T && sn < T->nsnap) {
SnapShot *snap = &T->snap[sn];
SnapEntry *map = &T->snapmap[snap->mapofs];
MSize n, nent = snap->nent;
GCtab *t;
lua_createtable(L, nent+2, 0);
t = tabV(L->top-1);
setintV(lj_tab_setint(L, t, 0), (int32_t)snap->ref - REF_BIAS);
setintV(lj_tab_setint(L, t, 1), (int32_t)snap->nslots);
for (n = 0; n < nent; n++)
setintV(lj_tab_setint(L, t, (int32_t)(n+2)), (int32_t)map[n]);
setintV(lj_tab_setint(L, t, (int32_t)(nent+2)), (int32_t)SNAP(255, 0, 0));
return 1;
}
return 0;
}
/* local mcode, addr, loop = jit.util.tracemc(tr) */
LJLIB_CF(jit_util_tracemc)
{
GCtrace *T = jit_checktrace(L);
if (T && T->mcode != NULL) {
setstrV(L, L->top-1, lj_str_new(L, (const char *)T->mcode, T->szmcode));
setintptrV(L->top++, (intptr_t)(void *)T->mcode);
setintV(L->top++, T->mcloop);
return 3;
}
return 0;
}
/* local addr = jit.util.traceexitstub([tr,] exitno) */
LJLIB_CF(jit_util_traceexitstub)
{
#ifdef EXITSTUBS_PER_GROUP
ExitNo exitno = (ExitNo)lj_lib_checkint(L, 1);
jit_State *J = L2J(L);
if (exitno < EXITSTUBS_PER_GROUP*LJ_MAX_EXITSTUBGR) {
setintptrV(L->top-1, (intptr_t)(void *)exitstub_addr(J, exitno));
return 1;
}
#else
if (L->top > L->base+1) { /* Don't throw for one-argument variant. */
GCtrace *T = jit_checktrace(L);
ExitNo exitno = (ExitNo)lj_lib_checkint(L, 2);
ExitNo maxexit = T->root ? T->nsnap+1 : T->nsnap;
if (T && T->mcode != NULL && exitno < maxexit) {
setintptrV(L->top-1, (intptr_t)(void *)exitstub_trace_addr(T, exitno));
return 1;
}
}
#endif
return 0;
}
/* local addr = jit.util.ircalladdr(idx) */
LJLIB_CF(jit_util_ircalladdr)
{
uint32_t idx = (uint32_t)lj_lib_checkint(L, 1);
if (idx < IRCALL__MAX) {
ASMFunction func = lj_ir_callinfo[idx].func;
setintptrV(L->top-1, (intptr_t)(void *)lj_ptr_strip(func));
return 1;
}
return 0;
}
#endif
#include "lj_libdef.h"
static int luaopen_jit_util(lua_State *L)
{
LJ_LIB_REG(L, NULL, jit_util);
return 1;
}
/* -- jit.opt module ------------------------------------------------------ */
#if LJ_HASJIT
#define LJLIB_MODULE_jit_opt
/* Parse optimization level. */
static int jitopt_level(jit_State *J, const char *str)
{
if (str[0] >= '0' && str[0] <= '9' && str[1] == '\0') {
uint32_t flags;
if (str[0] == '0') flags = JIT_F_OPT_0;
else if (str[0] == '1') flags = JIT_F_OPT_1;
else if (str[0] == '2') flags = JIT_F_OPT_2;
else flags = JIT_F_OPT_3;
J->flags = (J->flags & ~JIT_F_OPT_MASK) | flags;
return 1; /* Ok. */
}
return 0; /* No match. */
}
/* Parse optimization flag. */
static int jitopt_flag(jit_State *J, const char *str)
{
const char *lst = JIT_F_OPTSTRING;
uint32_t opt;
int set = 1;
if (str[0] == '+') {
str++;
} else if (str[0] == '-') {
str++;
set = 0;
} else if (str[0] == 'n' && str[1] == 'o') {
str += str[2] == '-' ? 3 : 2;
set = 0;
}
for (opt = JIT_F_OPT; ; opt <<= 1) {
size_t len = *(const uint8_t *)lst;
if (len == 0)
break;
if (strncmp(str, lst+1, len) == 0 && str[len] == '\0') {
if (set) J->flags |= opt; else J->flags &= ~opt;
return 1; /* Ok. */
}
lst += 1+len;
}
return 0; /* No match. */
}
/* Parse optimization parameter. */
static int jitopt_param(jit_State *J, const char *str)
{
const char *lst = JIT_P_STRING;
int i;
for (i = 0; i < JIT_P__MAX; i++) {
size_t len = *(const uint8_t *)lst;
lj_assertJ(len != 0, "bad JIT_P_STRING");
if (strncmp(str, lst+1, len) == 0 && str[len] == '=') {
int32_t n = 0;
const char *p = &str[len+1];
while (*p >= '0' && *p <= '9')
n = n*10 + (*p++ - '0');
if (*p) return 0; /* Malformed number. */
J->param[i] = n;
if (i == JIT_P_hotloop)
lj_dispatch_init_hotcount(J2G(J));
return 1; /* Ok. */
}
lst += 1+len;
}
return 0; /* No match. */
}
/* jit.opt.start(flags...) */
LJLIB_CF(jit_opt_start)
{
jit_State *J = L2J(L);
int nargs = (int)(L->top - L->base);
if (nargs == 0) {
J->flags = (J->flags & ~JIT_F_OPT_MASK) | JIT_F_OPT_DEFAULT;
} else {
int i;
for (i = 1; i <= nargs; i++) {
const char *str = strdata(lj_lib_checkstr(L, i));
if (!jitopt_level(J, str) &&
!jitopt_flag(J, str) &&
!jitopt_param(J, str))
lj_err_callerv(L, LJ_ERR_JITOPT, str);
}
}
return 0;
}
#include "lj_libdef.h"
#endif
/* -- jit.profile module -------------------------------------------------- */
#if LJ_HASPROFILE
#define LJLIB_MODULE_jit_profile
/* Not loaded by default, use: local profile = require("jit.profile") */
#define KEY_PROFILE_THREAD (U64x(80000000,00000000)|'t')
#define KEY_PROFILE_FUNC (U64x(80000000,00000000)|'f')
static void jit_profile_callback(lua_State *L2, lua_State *L, int samples,
int vmstate)
{
TValue key;
cTValue *tv;
key.u64 = KEY_PROFILE_FUNC;
tv = lj_tab_get(L, tabV(registry(L)), &key);
if (tvisfunc(tv)) {
char vmst = (char)vmstate;
int status;
setfuncV(L2, L2->top++, funcV(tv));
setthreadV(L2, L2->top++, L);
setintV(L2->top++, samples);
setstrV(L2, L2->top++, lj_str_new(L2, &vmst, 1));
status = lua_pcall(L2, 3, 0, 0); /* callback(thread, samples, vmstate) */
if (status) {
if (G(L2)->panic) G(L2)->panic(L2);
exit(EXIT_FAILURE);
}
lj_trace_abort(G(L2));
}
}
/* profile.start(mode, cb) */
LJLIB_CF(jit_profile_start)
{
GCtab *registry = tabV(registry(L));
GCstr *mode = lj_lib_optstr(L, 1);
GCfunc *func = lj_lib_checkfunc(L, 2);
lua_State *L2 = lua_newthread(L); /* Thread that runs profiler callback. */
TValue key;
/* Anchor thread and function in registry. */
key.u64 = KEY_PROFILE_THREAD;
setthreadV(L, lj_tab_set(L, registry, &key), L2);
key.u64 = KEY_PROFILE_FUNC;
setfuncV(L, lj_tab_set(L, registry, &key), func);
lj_gc_anybarriert(L, registry);
luaJIT_profile_start(L, mode ? strdata(mode) : "",
(luaJIT_profile_callback)jit_profile_callback, L2);
return 0;
}
/* profile.stop() */
LJLIB_CF(jit_profile_stop)
{
GCtab *registry;
TValue key;
luaJIT_profile_stop(L);
registry = tabV(registry(L));
key.u64 = KEY_PROFILE_THREAD;
setnilV(lj_tab_set(L, registry, &key));
key.u64 = KEY_PROFILE_FUNC;
setnilV(lj_tab_set(L, registry, &key));
lj_gc_anybarriert(L, registry);
return 0;
}
/* dump = profile.dumpstack([thread,] fmt, depth) */
LJLIB_CF(jit_profile_dumpstack)
{
lua_State *L2 = L;
int arg = 0;
size_t len;
int depth;
GCstr *fmt;
const char *p;
if (L->top > L->base && tvisthread(L->base)) {
L2 = threadV(L->base);
arg = 1;
}
fmt = lj_lib_checkstr(L, arg+1);
depth = lj_lib_checkint(L, arg+2);
p = luaJIT_profile_dumpstack(L2, strdata(fmt), depth, &len);
lua_pushlstring(L, p, len);
return 1;
}
#include "lj_libdef.h"
static int luaopen_jit_profile(lua_State *L)
{
LJ_LIB_REG(L, NULL, jit_profile);
return 1;
}
#endif
/* -- JIT compiler initialization ----------------------------------------- */
#if LJ_HASJIT
/* Default values for JIT parameters. */
static const int32_t jit_param_default[JIT_P__MAX+1] = {
#define JIT_PARAMINIT(len, name, value) (value),
JIT_PARAMDEF(JIT_PARAMINIT)
#undef JIT_PARAMINIT
0
};
#if LJ_TARGET_ARM && LJ_TARGET_LINUX
#include <sys/utsname.h>
#endif
/* Arch-dependent CPU feature detection. */
static uint32_t jit_cpudetect(void)
{
uint32_t flags = 0;
#if LJ_TARGET_X86ORX64
uint32_t vendor[4];
uint32_t features[4];
if (lj_vm_cpuid(0, vendor) && lj_vm_cpuid(1, features)) {
flags |= ((features[2] >> 0)&1) * JIT_F_SSE3;
flags |= ((features[2] >> 19)&1) * JIT_F_SSE4_1;
if (vendor[0] >= 7) {
uint32_t xfeatures[4];
lj_vm_cpuid(7, xfeatures);
flags |= ((xfeatures[1] >> 8)&1) * JIT_F_BMI2;
}
}
/* Don't bother checking for SSE2 -- the VM will crash before getting here. */
#elif LJ_TARGET_ARM
int ver = LJ_ARCH_VERSION; /* Compile-time ARM CPU detection. */
#if LJ_TARGET_LINUX
if (ver < 70) { /* Runtime ARM CPU detection. */
struct utsname ut;
uname(&ut);
if (strncmp(ut.machine, "armv", 4) == 0) {
if (ut.machine[4] >= '8') ver = 80;
else if (ut.machine[4] == '7') ver = 70;
else if (ut.machine[4] == '6') ver = 60;
}
}
#endif
flags |= ver >= 70 ? JIT_F_ARMV7 :
ver >= 61 ? JIT_F_ARMV6T2_ :
ver >= 60 ? JIT_F_ARMV6_ : 0;
flags |= LJ_ARCH_HASFPU == 0 ? 0 : ver >= 70 ? JIT_F_VFPV3 : JIT_F_VFPV2;
#elif LJ_TARGET_ARM64
/* No optional CPU features to detect (for now). */
#elif LJ_TARGET_PPC
#if LJ_ARCH_SQRT
flags |= JIT_F_SQRT;
#endif
#if LJ_ARCH_ROUND
flags |= JIT_F_ROUND;
#endif
#elif LJ_TARGET_MIPS
/* Compile-time MIPS CPU detection. */
#if LJ_ARCH_VERSION >= 20
flags |= JIT_F_MIPSXXR2;
#endif
/* Runtime MIPS CPU detection. */
#if defined(__GNUC__)
if (!(flags & JIT_F_MIPSXXR2)) {
int x;
#ifdef __mips16
x = 0; /* Runtime detection is difficult. Ensure optimal -march flags. */
#else
/* On MIPS32R1 rotr is treated as srl. rotr r2,r2,1 -> srl r2,r2,1. */
__asm__("li $2, 1\n\t.long 0x00221042\n\tmove %0, $2" : "=r"(x) : : "$2");
#endif
if (x) flags |= JIT_F_MIPSXXR2; /* Either 0x80000000 (R2) or 0 (R1). */
}
#endif
#else
#error "Missing CPU detection for this architecture"
#endif
return flags;
}
/* Initialize JIT compiler. */
static void jit_init(lua_State *L)
{
jit_State *J = L2J(L);
J->flags = jit_cpudetect() | JIT_F_ON | JIT_F_OPT_DEFAULT;
memcpy(J->param, jit_param_default, sizeof(J->param));
lj_dispatch_update(G(L));
}
#endif
LUALIB_API int luaopen_jit(lua_State *L)
{
#if LJ_HASJIT
jit_init(L);
#endif
lua_pushliteral(L, LJ_OS_NAME);
lua_pushliteral(L, LJ_ARCH_NAME);
lua_pushinteger(L, LUAJIT_VERSION_NUM); /* Deprecated. */
lua_pushliteral(L, LUAJIT_VERSION);
LJ_LIB_REG(L, LUA_JITLIBNAME, jit);
#if LJ_HASPROFILE
lj_lib_prereg(L, LUA_JITLIBNAME ".profile", luaopen_jit_profile,
tabref(L->env));
#endif
#ifndef LUAJIT_DISABLE_JITUTIL
lj_lib_prereg(L, LUA_JITLIBNAME ".util", luaopen_jit_util, tabref(L->env));
#endif
#if LJ_HASJIT
LJ_LIB_REG(L, "jit.opt", jit_opt);
#endif
L->top -= 2;
return 1;
}
+205
View File
@@ -0,0 +1,205 @@
/*
** Math library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#include <math.h>
#define lib_math_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_lib.h"
#include "lj_vm.h"
#include "lj_prng.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_math
LJLIB_ASM(math_abs) LJLIB_REC(.)
{
lj_lib_checknumber(L, 1);
return FFH_RETRY;
}
LJLIB_ASM_(math_floor) LJLIB_REC(math_round IRFPM_FLOOR)
LJLIB_ASM_(math_ceil) LJLIB_REC(math_round IRFPM_CEIL)
LJLIB_ASM(math_sqrt) LJLIB_REC(math_unary IRFPM_SQRT)
{
lj_lib_checknum(L, 1);
return FFH_RETRY;
}
LJLIB_ASM_(math_log10) LJLIB_REC(math_call IRCALL_log10)
LJLIB_ASM_(math_exp) LJLIB_REC(math_call IRCALL_exp)
LJLIB_ASM_(math_sin) LJLIB_REC(math_call IRCALL_sin)
LJLIB_ASM_(math_cos) LJLIB_REC(math_call IRCALL_cos)
LJLIB_ASM_(math_tan) LJLIB_REC(math_call IRCALL_tan)
LJLIB_ASM_(math_asin) LJLIB_REC(math_call IRCALL_asin)
LJLIB_ASM_(math_acos) LJLIB_REC(math_call IRCALL_acos)
LJLIB_ASM_(math_atan) LJLIB_REC(math_call IRCALL_atan)
LJLIB_ASM_(math_sinh) LJLIB_REC(math_call IRCALL_sinh)
LJLIB_ASM_(math_cosh) LJLIB_REC(math_call IRCALL_cosh)
LJLIB_ASM_(math_tanh) LJLIB_REC(math_call IRCALL_tanh)
LJLIB_ASM_(math_frexp)
LJLIB_ASM_(math_modf)
LJLIB_ASM(math_log) LJLIB_REC(math_log)
{
double x = lj_lib_checknum(L, 1);
if (L->base+1 < L->top) {
double y = lj_lib_checknum(L, 2);
#ifdef LUAJIT_NO_LOG2
x = log(x); y = 1.0 / log(y);
#else
x = lj_vm_log2(x); y = 1.0 / lj_vm_log2(y);
#endif
setnumV(L->base-1-LJ_FR2, x*y); /* Do NOT join the expression to x / y. */
return FFH_RES(1);
}
return FFH_RETRY;
}
LJLIB_LUA(math_deg) /* function(x) return x * 57.29577951308232 end */
LJLIB_LUA(math_rad) /* function(x) return x * 0.017453292519943295 end */
LJLIB_ASM(math_atan2) LJLIB_REC(.)
{
lj_lib_checknum(L, 1);
lj_lib_checknum(L, 2);
return FFH_RETRY;
}
LJLIB_ASM_(math_pow) LJLIB_REC(.)
LJLIB_ASM_(math_fmod)
LJLIB_ASM(math_ldexp) LJLIB_REC(.)
{
lj_lib_checknum(L, 1);
#if LJ_DUALNUM && !LJ_TARGET_X86ORX64
lj_lib_checkint(L, 2);
#else
lj_lib_checknum(L, 2);
#endif
return FFH_RETRY;
}
LJLIB_ASM(math_min) LJLIB_REC(math_minmax IR_MIN)
{
int i = 0;
do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top);
return FFH_RETRY;
}
LJLIB_ASM_(math_max) LJLIB_REC(math_minmax IR_MAX)
LJLIB_PUSH(3.14159265358979323846) LJLIB_SET(pi)
LJLIB_PUSH(1e310) LJLIB_SET(huge)
/* ------------------------------------------------------------------------ */
/* This implements a Tausworthe PRNG with period 2^223. Based on:
** Tables of maximally-equidistributed combined LFSR generators,
** Pierre L'Ecuyer, 1991, table 3, 1st entry.
** Full-period ME-CF generator with L=64, J=4, k=223, N1=49.
*/
/* Union needed for bit-pattern conversion between uint64_t and double. */
typedef union { uint64_t u64; double d; } U64double;
/* PRNG seeding function. */
static void random_seed(PRNGState *rs, double d)
{
uint32_t r = 0x11090601; /* 64-k[i] as four 8 bit constants. */
int i;
for (i = 0; i < 4; i++) {
U64double u;
uint32_t m = 1u << (r&255);
r >>= 8;
u.d = d = d * 3.14159265358979323846 + 2.7182818284590452354;
if (u.u64 < m) u.u64 += m; /* Ensure k[i] MSB of u[i] are non-zero. */
rs->u[i] = u.u64;
}
for (i = 0; i < 10; i++)
(void)lj_prng_u64(rs);
}
/* PRNG extract function. */
LJLIB_PUSH(top-2) /* Upvalue holds userdata with PRNGState. */
LJLIB_CF(math_random) LJLIB_REC(.)
{
int n = (int)(L->top - L->base);
PRNGState *rs = (PRNGState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
U64double u;
double d;
u.u64 = lj_prng_u64d(rs);
d = u.d - 1.0;
if (n > 0) {
#if LJ_DUALNUM
int isint = 1;
double r1;
lj_lib_checknumber(L, 1);
if (tvisint(L->base)) {
r1 = (lua_Number)intV(L->base);
} else {
isint = 0;
r1 = numV(L->base);
}
#else
double r1 = lj_lib_checknum(L, 1);
#endif
if (n == 1) {
d = lj_vm_floor(d*r1) + 1.0; /* d is an int in range [1, r1] */
} else {
#if LJ_DUALNUM
double r2;
lj_lib_checknumber(L, 2);
if (tvisint(L->base+1)) {
r2 = (lua_Number)intV(L->base+1);
} else {
isint = 0;
r2 = numV(L->base+1);
}
#else
double r2 = lj_lib_checknum(L, 2);
#endif
d = lj_vm_floor(d*(r2-r1+1.0)) + r1; /* d is an int in range [r1, r2] */
}
#if LJ_DUALNUM
if (isint) {
setintV(L->top-1, lj_num2int(d));
return 1;
}
#endif
} /* else: d is a double in range [0, 1] */
setnumV(L->top++, d);
return 1;
}
/* PRNG seed function. */
LJLIB_PUSH(top-2) /* Upvalue holds userdata with PRNGState. */
LJLIB_CF(math_randomseed)
{
PRNGState *rs = (PRNGState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
if (L->base != L->top)
random_seed(rs, lj_lib_checknum(L, 1));
else if (!lj_prng_seed_secure(rs))
lj_err_caller(L, LJ_ERR_PRNGSD);
return 0;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_math(lua_State *L)
{
PRNGState *rs = (PRNGState *)lua_newuserdata(L, sizeof(PRNGState));
lj_prng_seed_fixed(rs);
LJ_LIB_REG(L, LUA_MATHLIBNAME, math);
return 1;
}
+296
View File
@@ -0,0 +1,296 @@
/*
** OS library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#include <errno.h>
#include <time.h>
#define lib_os_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_lib.h"
#if LJ_TARGET_POSIX
#include <unistd.h>
#else
#include <stdio.h>
#endif
#if !LJ_TARGET_PSVITA
#include <locale.h>
#endif
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_os
#if !LJ_SRB2LIB
LJLIB_CF(os_execute)
{
#if LJ_NO_SYSTEM
#if LJ_52
errno = ENOSYS;
return luaL_fileresult(L, 0, NULL);
#else
lua_pushinteger(L, -1);
return 1;
#endif
#else
const char *cmd = luaL_optstring(L, 1, NULL);
int stat = system(cmd);
#if LJ_52
if (cmd)
return luaL_execresult(L, stat);
setboolV(L->top++, 1);
#else
setintV(L->top++, stat);
#endif
return 1;
#endif
}
LJLIB_CF(os_remove)
{
const char *filename = luaL_checkstring(L, 1);
return luaL_fileresult(L, remove(filename) == 0, filename);
}
LJLIB_CF(os_rename)
{
const char *fromname = luaL_checkstring(L, 1);
const char *toname = luaL_checkstring(L, 2);
return luaL_fileresult(L, rename(fromname, toname) == 0, fromname);
}
LJLIB_CF(os_tmpname)
{
#if LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PS5 || LJ_TARGET_PSVITA || LJ_TARGET_NX
lj_err_caller(L, LJ_ERR_OSUNIQF);
return 0;
#else
#if LJ_TARGET_POSIX
char buf[15+1];
int fp;
strcpy(buf, "/tmp/lua_XXXXXX");
fp = mkstemp(buf);
if (fp != -1)
close(fp);
else
lj_err_caller(L, LJ_ERR_OSUNIQF);
#else
char buf[L_tmpnam];
if (tmpnam(buf) == NULL)
lj_err_caller(L, LJ_ERR_OSUNIQF);
#endif
lua_pushstring(L, buf);
return 1;
#endif
}
LJLIB_CF(os_getenv)
{
#if LJ_TARGET_CONSOLE
lua_pushnil(L);
#else
lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */
#endif
return 1;
}
LJLIB_CF(os_exit)
{
int status;
if (L->base < L->top && tvisbool(L->base))
status = boolV(L->base) ? EXIT_SUCCESS : EXIT_FAILURE;
else
status = lj_lib_optint(L, 1, EXIT_SUCCESS);
if (L->base+1 < L->top && tvistruecond(L->base+1))
lua_close(L);
exit(status);
return 0; /* Unreachable. */
}
#endif
LJLIB_CF(os_clock)
{
setnumV(L->top++, ((lua_Number)clock())*(1.0/(lua_Number)CLOCKS_PER_SEC));
return 1;
}
/* ------------------------------------------------------------------------ */
static void setfield(lua_State *L, const char *key, int value)
{
lua_pushinteger(L, value);
lua_setfield(L, -2, key);
}
static void setboolfield(lua_State *L, const char *key, int value)
{
if (value < 0) /* undefined? */
return; /* does not set field */
lua_pushboolean(L, value);
lua_setfield(L, -2, key);
}
static int getboolfield(lua_State *L, const char *key)
{
int res;
lua_getfield(L, -1, key);
res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
lua_pop(L, 1);
return res;
}
static int getfield(lua_State *L, const char *key, int d)
{
int res;
lua_getfield(L, -1, key);
if (lua_isnumber(L, -1)) {
res = (int)lua_tointeger(L, -1);
} else {
if (d < 0)
lj_err_callerv(L, LJ_ERR_OSDATEF, key);
res = d;
}
lua_pop(L, 1);
return res;
}
LJLIB_CF(os_date)
{
const char *s = luaL_optstring(L, 1, "%c");
time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL));
struct tm *stm;
#if LJ_TARGET_POSIX
struct tm rtm;
#endif
if (*s == '!') { /* UTC? */
s++; /* Skip '!' */
#if LJ_TARGET_POSIX
stm = gmtime_r(&t, &rtm);
#else
stm = gmtime(&t);
#endif
} else {
#if LJ_TARGET_POSIX
stm = localtime_r(&t, &rtm);
#else
stm = localtime(&t);
#endif
}
if (stm == NULL) { /* Invalid date? */
setnilV(L->top++);
} else if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */
setfield(L, "sec", stm->tm_sec);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon+1);
setfield(L, "year", stm->tm_year+1900);
setfield(L, "wday", stm->tm_wday+1);
setfield(L, "yday", stm->tm_yday+1);
setboolfield(L, "isdst", stm->tm_isdst);
} else if (*s) {
SBuf *sb = &G(L)->tmpbuf;
MSize sz = 0, retry = 4;
const char *q;
for (q = s; *q; q++)
sz += (*q == '%') ? 30 : 1; /* Overflow doesn't matter. */
setsbufL(sb, L);
while (retry--) { /* Limit growth for invalid format or empty result. */
char *buf = lj_buf_need(sb, sz);
size_t len = strftime(buf, sbufsz(sb), s, stm);
if (len) {
setstrV(L, L->top++, lj_str_new(L, buf, len));
lj_gc_check(L);
break;
}
sz += (sz|1);
}
} else {
setstrV(L, L->top++, &G(L)->strempty);
}
return 1;
}
LJLIB_CF(os_time)
{
time_t t;
if (lua_isnoneornil(L, 1)) { /* called without args? */
t = time(NULL); /* get current time */
} else {
struct tm ts;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); /* make sure table is at the top */
ts.tm_sec = getfield(L, "sec", 0);
ts.tm_min = getfield(L, "min", 0);
ts.tm_hour = getfield(L, "hour", 12);
ts.tm_mday = getfield(L, "day", -1);
ts.tm_mon = getfield(L, "month", -1) - 1;
ts.tm_year = getfield(L, "year", -1) - 1900;
ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts);
}
if (t == (time_t)(-1))
lua_pushnil(L);
else
lua_pushnumber(L, (lua_Number)t);
return 1;
}
LJLIB_CF(os_difftime)
{
lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
(time_t)(luaL_optnumber(L, 2, (lua_Number)0))));
return 1;
}
/* ------------------------------------------------------------------------ */
#if !LJ_SRB2LIB
LJLIB_CF(os_setlocale)
{
#if LJ_TARGET_PSVITA
lua_pushliteral(L, "C");
#else
GCstr *s = lj_lib_optstr(L, 1);
const char *str = s ? strdata(s) : NULL;
int opt = lj_lib_checkopt(L, 2, 6,
"\5ctype\7numeric\4time\7collate\10monetary\1\377\3all");
if (opt == 0) opt = LC_CTYPE;
else if (opt == 1) opt = LC_NUMERIC;
else if (opt == 2) opt = LC_TIME;
else if (opt == 3) opt = LC_COLLATE;
else if (opt == 4) opt = LC_MONETARY;
else if (opt == 6) opt = LC_ALL;
lua_pushstring(L, setlocale(opt, str));
#endif
return 1;
}
#endif
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_os(lua_State *L)
{
LJ_LIB_REG(L, LUA_OSLIBNAME, os);
return 1;
}
+628
View File
@@ -0,0 +1,628 @@
/*
** Package library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2012 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lib_package_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_err.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
/* Error codes for ll_loadfunc. */
#define PACKAGE_ERR_LIB 1
#define PACKAGE_ERR_FUNC 2
#define PACKAGE_ERR_LOAD 3
/* Redefined in platform specific part. */
#define PACKAGE_LIB_FAIL "open"
#define setprogdir(L) ((void)0)
/* Symbol name prefixes. */
#define SYMPREFIX_CF "luaopen_%s"
#define SYMPREFIX_BC "luaJIT_BC_%s"
#if LJ_TARGET_DLOPEN
#include <dlfcn.h>
static void ll_unloadlib(void *lib)
{
dlclose(lib);
}
static void *ll_load(lua_State *L, const char *path, int gl)
{
void *lib = dlopen(path, RTLD_NOW | (gl ? RTLD_GLOBAL : RTLD_LOCAL));
if (lib == NULL) lua_pushstring(L, dlerror());
return lib;
}
static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym)
{
lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
if (f == NULL) lua_pushstring(L, dlerror());
return f;
}
static const char *ll_bcsym(void *lib, const char *sym)
{
#if defined(RTLD_DEFAULT) && !defined(NO_RTLD_DEFAULT)
if (lib == NULL) lib = RTLD_DEFAULT;
#elif LJ_TARGET_OSX || LJ_TARGET_BSD
if (lib == NULL) lib = (void *)(intptr_t)-2;
#endif
return (const char *)dlsym(lib, sym);
}
#elif LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
#endif
#if LJ_TARGET_UWP
void *LJ_WIN_LOADLIBA(const char *path)
{
DWORD err = GetLastError();
wchar_t wpath[256];
HANDLE lib = NULL;
if (MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, 256) > 0) {
lib = LoadPackagedLibrary(wpath, 0);
}
SetLastError(err);
return lib;
}
#endif
#undef setprogdir
static void setprogdir(lua_State *L)
{
char buff[MAX_PATH + 1];
char *lb;
DWORD nsize = sizeof(buff);
DWORD n = GetModuleFileNameA(NULL, buff, nsize);
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) {
luaL_error(L, "unable to get ModuleFileName");
} else {
*lb = '\0';
luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff);
lua_remove(L, -2); /* remove original string */
}
}
static void pusherror(lua_State *L)
{
DWORD error = GetLastError();
#if LJ_TARGET_XBOXONE
wchar_t wbuffer[128];
char buffer[128*2];
if (FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, 0, wbuffer, sizeof(wbuffer)/sizeof(wchar_t), NULL) &&
WideCharToMultiByte(CP_ACP, 0, wbuffer, 128, buffer, 128*2, NULL, NULL))
#else
char buffer[128];
if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, 0, buffer, sizeof(buffer), NULL))
#endif
lua_pushstring(L, buffer);
else
lua_pushfstring(L, "system error %d\n", error);
}
static void ll_unloadlib(void *lib)
{
FreeLibrary((HINSTANCE)lib);
}
static void *ll_load(lua_State *L, const char *path, int gl)
{
HINSTANCE lib = LJ_WIN_LOADLIBA(path);
if (lib == NULL) pusherror(L);
UNUSED(gl);
return lib;
}
static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym)
{
lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym);
if (f == NULL) pusherror(L);
return f;
}
#if LJ_TARGET_UWP
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#endif
static const char *ll_bcsym(void *lib, const char *sym)
{
if (lib) {
return (const char *)GetProcAddress((HINSTANCE)lib, sym);
} else {
#if LJ_TARGET_UWP
return (const char *)GetProcAddress((HINSTANCE)&__ImageBase, sym);
#else
HINSTANCE h = GetModuleHandleA(NULL);
const char *p = (const char *)GetProcAddress(h, sym);
if (p == NULL && GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(const char *)ll_bcsym, &h))
p = (const char *)GetProcAddress(h, sym);
return p;
#endif
}
}
#else
#undef PACKAGE_LIB_FAIL
#define PACKAGE_LIB_FAIL "absent"
#define DLMSG "dynamic libraries not enabled; no support for target OS"
static void ll_unloadlib(void *lib)
{
UNUSED(lib);
}
static void *ll_load(lua_State *L, const char *path, int gl)
{
UNUSED(path); UNUSED(gl);
lua_pushliteral(L, DLMSG);
return NULL;
}
static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym)
{
UNUSED(lib); UNUSED(sym);
lua_pushliteral(L, DLMSG);
return NULL;
}
static const char *ll_bcsym(void *lib, const char *sym)
{
UNUSED(lib); UNUSED(sym);
return NULL;
}
#endif
/* ------------------------------------------------------------------------ */
static void **ll_register(lua_State *L, const char *path)
{
void **plib;
lua_pushfstring(L, "LOADLIB: %s", path);
lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */
if (!lua_isnil(L, -1)) { /* is there an entry? */
plib = (void **)lua_touserdata(L, -1);
} else { /* no entry yet; create one */
lua_pop(L, 1);
plib = (void **)lua_newuserdata(L, sizeof(void *));
*plib = NULL;
luaL_setmetatable(L, "_LOADLIB");
lua_pushfstring(L, "LOADLIB: %s", path);
lua_pushvalue(L, -2);
lua_settable(L, LUA_REGISTRYINDEX);
}
return plib;
}
static const char *mksymname(lua_State *L, const char *modname,
const char *prefix)
{
const char *funcname;
const char *mark = strchr(modname, *LUA_IGMARK);
if (mark) modname = mark + 1;
funcname = luaL_gsub(L, modname, ".", "_");
funcname = lua_pushfstring(L, prefix, funcname);
lua_remove(L, -2); /* remove 'gsub' result */
return funcname;
}
static int ll_loadfunc(lua_State *L, const char *path, const char *name, int r)
{
void **reg;
if (strlen(path) >= 4096) {
lua_pushliteral(L, "path too long");
return PACKAGE_ERR_LIB;
}
reg = ll_register(L, path);
if (*reg == NULL) *reg = ll_load(L, path, (*name == '*'));
if (*reg == NULL) {
return PACKAGE_ERR_LIB; /* Unable to load library. */
} else if (*name == '*') { /* Only load library into global namespace. */
lua_pushboolean(L, 1);
return 0;
} else {
const char *sym = r ? name : mksymname(L, name, SYMPREFIX_CF);
lua_CFunction f = ll_sym(L, *reg, sym);
if (f) {
lua_pushcfunction(L, f);
return 0;
}
if (!r) {
const char *bcdata = ll_bcsym(*reg, mksymname(L, name, SYMPREFIX_BC));
lua_pop(L, 1);
if (bcdata) {
if (luaL_loadbuffer(L, bcdata, ~(size_t)0, name) != 0)
return PACKAGE_ERR_LOAD;
return 0;
}
}
return PACKAGE_ERR_FUNC; /* Unable to find function. */
}
}
static int lj_cf_package_loadlib(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
const char *init = luaL_checkstring(L, 2);
int st = ll_loadfunc(L, path, init, 1);
if (st == 0) { /* no errors? */
return 1; /* return the loaded function */
} else { /* error; error message is on stack top */
lua_pushnil(L);
lua_insert(L, -2);
lua_pushstring(L, (st == PACKAGE_ERR_LIB) ? PACKAGE_LIB_FAIL : "init");
return 3; /* return nil, error message, and where */
}
}
static int lj_cf_package_unloadlib(lua_State *L)
{
void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
if (*lib) ll_unloadlib(*lib);
*lib = NULL; /* mark library as closed */
return 0;
}
/* ------------------------------------------------------------------------ */
static int readable(const char *filename)
{
FILE *f = fopen(filename, "r"); /* try to open file */
if (f == NULL) return 0; /* open failed */
fclose(f);
return 1;
}
static const char *pushnexttemplate(lua_State *L, const char *path)
{
const char *l;
while (*path == *LUA_PATHSEP) path++; /* skip separators */
if (*path == '\0') return NULL; /* no more templates */
l = strchr(path, *LUA_PATHSEP); /* find next separator */
if (l == NULL) l = path + strlen(path);
lua_pushlstring(L, path, (size_t)(l - path)); /* template */
return l;
}
static const char *searchpath (lua_State *L, const char *name,
const char *path, const char *sep,
const char *dirsep)
{
luaL_Buffer msg; /* to build error message */
luaL_buffinit(L, &msg);
if (*sep != '\0') /* non-empty separator? */
name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */
while ((path = pushnexttemplate(L, path)) != NULL) {
const char *filename = luaL_gsub(L, lua_tostring(L, -1),
LUA_PATH_MARK, name);
lua_remove(L, -2); /* remove path template */
if (readable(filename)) /* does file exist and is readable? */
return filename; /* return that file name */
lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
lua_remove(L, -2); /* remove file name */
luaL_addvalue(&msg); /* concatenate error msg. entry */
}
luaL_pushresult(&msg); /* create error message */
return NULL; /* not found */
}
static int lj_cf_package_searchpath(lua_State *L)
{
const char *f = searchpath(L, luaL_checkstring(L, 1),
luaL_checkstring(L, 2),
luaL_optstring(L, 3, "."),
luaL_optstring(L, 4, LUA_DIRSEP));
if (f != NULL) {
return 1;
} else { /* error message is on top of the stack */
lua_pushnil(L);
lua_insert(L, -2);
return 2; /* return nil + error message */
}
}
static const char *findfile(lua_State *L, const char *name,
const char *pname)
{
const char *path;
lua_getfield(L, LUA_ENVIRONINDEX, pname);
path = lua_tostring(L, -1);
if (path == NULL)
luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
return searchpath(L, name, path, ".", LUA_DIRSEP);
}
static void loaderror(lua_State *L, const char *filename)
{
luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s",
lua_tostring(L, 1), filename, lua_tostring(L, -1));
}
static int lj_cf_package_loader_lua(lua_State *L)
{
const char *filename;
const char *name = luaL_checkstring(L, 1);
filename = findfile(L, name, "path");
if (filename == NULL) return 1; /* library not found in this path */
if (luaL_loadfile(L, filename) != 0)
loaderror(L, filename);
return 1; /* library loaded successfully */
}
static int lj_cf_package_loader_c(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
const char *filename = findfile(L, name, "cpath");
if (filename == NULL) return 1; /* library not found in this path */
if (ll_loadfunc(L, filename, name, 0) != 0)
loaderror(L, filename);
return 1; /* library loaded successfully */
}
static int lj_cf_package_loader_croot(lua_State *L)
{
const char *filename;
const char *name = luaL_checkstring(L, 1);
const char *p = strchr(name, '.');
int st;
if (p == NULL) return 0; /* is root */
lua_pushlstring(L, name, (size_t)(p - name));
filename = findfile(L, lua_tostring(L, -1), "cpath");
if (filename == NULL) return 1; /* root not found */
if ((st = ll_loadfunc(L, filename, name, 0)) != 0) {
if (st != PACKAGE_ERR_FUNC) loaderror(L, filename); /* real error */
lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
name, filename);
return 1; /* function not found */
}
return 1;
}
static int lj_cf_package_loader_preload(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
lua_getfield(L, LUA_ENVIRONINDEX, "preload");
if (!lua_istable(L, -1))
luaL_error(L, LUA_QL("package.preload") " must be a table");
lua_getfield(L, -1, name);
if (lua_isnil(L, -1)) { /* Not found? */
const char *bcname = mksymname(L, name, SYMPREFIX_BC);
const char *bcdata = ll_bcsym(NULL, bcname);
if (bcdata == NULL || luaL_loadbuffer(L, bcdata, ~(size_t)0, name) != 0)
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
}
return 1;
}
/* ------------------------------------------------------------------------ */
#define KEY_SENTINEL (U64x(80000000,00000000)|'s')
static int lj_cf_package_require(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
int i;
lua_settop(L, 1); /* _LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, 2, name);
if (lua_toboolean(L, -1)) { /* is it there? */
if ((L->top-1)->u64 == KEY_SENTINEL) /* check loops */
luaL_error(L, "loop or previous error loading module " LUA_QS, name);
return 1; /* package is already loaded */
}
/* else must load it; iterate over available loaders */
lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
if (!lua_istable(L, -1))
luaL_error(L, LUA_QL("package.loaders") " must be a table");
lua_pushliteral(L, ""); /* error message accumulator */
for (i = 1; ; i++) {
lua_rawgeti(L, -2, i); /* get a loader */
if (lua_isnil(L, -1))
luaL_error(L, "module " LUA_QS " not found:%s",
name, lua_tostring(L, -2));
lua_pushstring(L, name);
lua_call(L, 1, 1); /* call it */
if (lua_isfunction(L, -1)) /* did it find module? */
break; /* module loaded successfully */
else if (lua_isstring(L, -1)) /* loader returned error message? */
lua_concat(L, 2); /* accumulate it */
else
lua_pop(L, 1);
}
(L->top++)->u64 = KEY_SENTINEL;
lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */
lua_pushstring(L, name); /* pass name as argument to module */
lua_call(L, 1, 1); /* run loaded module */
if (!lua_isnil(L, -1)) /* non-nil return? */
lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
lua_getfield(L, 2, name);
if ((L->top-1)->u64 == KEY_SENTINEL) { /* module did not set a value? */
lua_pushboolean(L, 1); /* use true as result */
lua_pushvalue(L, -1); /* extra copy to be returned */
lua_setfield(L, 2, name); /* _LOADED[name] = true */
}
lj_lib_checkfpu(L);
return 1;
}
/* ------------------------------------------------------------------------ */
static void setfenv(lua_State *L)
{
lua_Debug ar;
if (lua_getstack(L, 1, &ar) == 0 ||
lua_getinfo(L, "f", &ar) == 0 || /* get calling function */
lua_iscfunction(L, -1))
luaL_error(L, LUA_QL("module") " not called from a Lua function");
lua_pushvalue(L, -2);
lua_setfenv(L, -2);
lua_pop(L, 1);
}
static void dooptions(lua_State *L, int n)
{
int i;
for (i = 2; i <= n; i++) {
lua_pushvalue(L, i); /* get option (a function) */
lua_pushvalue(L, -2); /* module */
lua_call(L, 1, 0);
}
}
static void modinit(lua_State *L, const char *modname)
{
const char *dot;
lua_pushvalue(L, -1);
lua_setfield(L, -2, "_M"); /* module._M = module */
lua_pushstring(L, modname);
lua_setfield(L, -2, "_NAME");
dot = strrchr(modname, '.'); /* look for last dot in module name */
if (dot == NULL) dot = modname; else dot++;
/* set _PACKAGE as package name (full module name minus last part) */
lua_pushlstring(L, modname, (size_t)(dot - modname));
lua_setfield(L, -2, "_PACKAGE");
}
static int lj_cf_package_module(lua_State *L)
{
const char *modname = luaL_checkstring(L, 1);
int lastarg = (int)(L->top - L->base);
luaL_pushmodule(L, modname, 1);
lua_getfield(L, -1, "_NAME");
if (!lua_isnil(L, -1)) { /* Module already initialized? */
lua_pop(L, 1);
} else {
lua_pop(L, 1);
modinit(L, modname);
}
lua_pushvalue(L, -1);
setfenv(L);
dooptions(L, lastarg);
return LJ_52;
}
static int lj_cf_package_seeall(lua_State *L)
{
luaL_checktype(L, 1, LUA_TTABLE);
if (!lua_getmetatable(L, 1)) {
lua_createtable(L, 0, 1); /* create new metatable */
lua_pushvalue(L, -1);
lua_setmetatable(L, 1);
}
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setfield(L, -2, "__index"); /* mt.__index = _G */
return 0;
}
/* ------------------------------------------------------------------------ */
#define AUXMARK "\1"
static void setpath(lua_State *L, const char *fieldname, const char *envname,
const char *def, int noenv)
{
#if LJ_TARGET_CONSOLE
const char *path = NULL;
UNUSED(envname);
#else
const char *path = getenv(envname);
#endif
if (path == NULL || noenv) {
lua_pushstring(L, def);
} else {
path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP,
LUA_PATHSEP AUXMARK LUA_PATHSEP);
luaL_gsub(L, path, AUXMARK, def);
lua_remove(L, -2);
}
setprogdir(L);
lua_setfield(L, -2, fieldname);
}
static const luaL_Reg package_lib[] = {
{ "loadlib", lj_cf_package_loadlib },
{ "searchpath", lj_cf_package_searchpath },
{ "seeall", lj_cf_package_seeall },
{ NULL, NULL }
};
static const luaL_Reg package_global[] = {
{ "module", lj_cf_package_module },
{ "require", lj_cf_package_require },
{ NULL, NULL }
};
static const lua_CFunction package_loaders[] =
{
lj_cf_package_loader_preload,
lj_cf_package_loader_lua,
lj_cf_package_loader_c,
lj_cf_package_loader_croot,
NULL
};
LUALIB_API int luaopen_package(lua_State *L)
{
int i;
int noenv;
luaL_newmetatable(L, "_LOADLIB");
lj_lib_pushcf(L, lj_cf_package_unloadlib, 1);
lua_setfield(L, -2, "__gc");
luaL_register(L, LUA_LOADLIBNAME, package_lib);
lua_copy(L, -1, LUA_ENVIRONINDEX);
lua_createtable(L, sizeof(package_loaders)/sizeof(package_loaders[0])-1, 0);
for (i = 0; package_loaders[i] != NULL; i++) {
lj_lib_pushcf(L, package_loaders[i], 1);
lua_rawseti(L, -2, i+1);
}
#if LJ_52
lua_pushvalue(L, -1);
lua_setfield(L, -3, "searchers");
#endif
lua_setfield(L, -2, "loaders");
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
noenv = lua_toboolean(L, -1);
lua_pop(L, 1);
setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT, noenv);
setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT, noenv);
lua_pushliteral(L, LUA_PATH_CONFIG);
lua_setfield(L, -2, "config");
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
lua_setfield(L, -2, "loaded");
luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD", 4);
lua_setfield(L, -2, "preload");
lua_pushvalue(L, LUA_GLOBALSINDEX);
luaL_register(L, NULL, package_global);
lua_pop(L, 1);
return 1;
}
+696
View File
@@ -0,0 +1,696 @@
/*
** String library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lib_string_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_meta.h"
#include "lj_state.h"
#include "lj_ff.h"
#include "lj_bcdump.h"
#include "lj_char.h"
#include "lj_strfmt.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_string
LJLIB_LUA(string_len) /*
function(s)
CHECK_str(s)
return #s
end
*/
LJLIB_ASM(string_byte) LJLIB_REC(string_range 0)
{
GCstr *s = lj_lib_checkstr(L, 1);
int32_t len = (int32_t)s->len;
int32_t start = lj_lib_optint(L, 2, 1);
int32_t stop = lj_lib_optint(L, 3, start);
int32_t n, i;
const unsigned char *p;
if (stop < 0) stop += len+1;
if (start < 0) start += len+1;
if (start <= 0) start = 1;
if (stop > len) stop = len;
if (start > stop) return FFH_RES(0); /* Empty interval: return no results. */
start--;
n = stop - start;
if ((uint32_t)n > LUAI_MAXCSTACK)
lj_err_caller(L, LJ_ERR_STRSLC);
lj_state_checkstack(L, (MSize)n);
p = (const unsigned char *)strdata(s) + start;
for (i = 0; i < n; i++)
setintV(L->base + i-1-LJ_FR2, p[i]);
return FFH_RES(n);
}
LJLIB_ASM(string_char) LJLIB_REC(.)
{
int i, nargs = (int)(L->top - L->base);
char *buf = lj_buf_tmp(L, (MSize)nargs);
for (i = 1; i <= nargs; i++) {
int32_t k = lj_lib_checkint(L, i);
if (!checku8(k))
lj_err_arg(L, i, LJ_ERR_BADVAL);
buf[i-1] = (char)k;
}
setstrV(L, L->base-1-LJ_FR2, lj_str_new(L, buf, (size_t)nargs));
return FFH_RES(1);
}
LJLIB_ASM(string_sub) LJLIB_REC(string_range 1)
{
lj_lib_checkstr(L, 1);
lj_lib_checkint(L, 2);
setintV(L->base+2, lj_lib_optint(L, 3, -1));
return FFH_RETRY;
}
LJLIB_CF(string_rep) LJLIB_REC(.)
{
GCstr *s = lj_lib_checkstr(L, 1);
int32_t rep = lj_lib_checkint(L, 2);
GCstr *sep = lj_lib_optstr(L, 3);
SBuf *sb = lj_buf_tmp_(L);
if (sep && rep > 1) {
GCstr *s2 = lj_buf_cat2str(L, sep, s);
lj_buf_reset(sb);
lj_buf_putstr(sb, s);
s = s2;
rep--;
}
sb = lj_buf_putstr_rep(sb, s, rep);
setstrV(L, L->top-1, lj_buf_str(L, sb));
lj_gc_check(L);
return 1;
}
LJLIB_ASM(string_reverse) LJLIB_REC(string_op IRCALL_lj_buf_putstr_reverse)
{
lj_lib_checkstr(L, 1);
return FFH_RETRY;
}
LJLIB_ASM_(string_lower) LJLIB_REC(string_op IRCALL_lj_buf_putstr_lower)
LJLIB_ASM_(string_upper) LJLIB_REC(string_op IRCALL_lj_buf_putstr_upper)
/* ------------------------------------------------------------------------ */
#if !LJ_SRB2LIB
static int writer_buf(lua_State *L, const void *p, size_t size, void *sb)
{
lj_buf_putmem((SBuf *)sb, p, (MSize)size);
UNUSED(L);
return 0;
}
LJLIB_CF(string_dump)
{
GCproto *pt = lj_lib_checkLproto(L, 1, 1);
uint32_t flags = 0;
SBuf *sb;
TValue *o = L->base+1;
if (o < L->top) {
if (tvisstr(o)) {
const char *mode = strVdata(o);
char c;
while ((c = *mode++)) {
if (c == 's') flags |= BCDUMP_F_STRIP;
if (c == 'd') flags |= BCDUMP_F_DETERMINISTIC;
}
} else if (tvistruecond(o)) {
flags |= BCDUMP_F_STRIP;
}
}
sb = lj_buf_tmp_(L); /* Assumes lj_bcwrite() doesn't use tmpbuf. */
L->top = L->base+1;
if (!pt || lj_bcwrite(L, pt, writer_buf, sb, flags))
lj_err_caller(L, LJ_ERR_STRDUMP);
setstrV(L, L->top-1, lj_buf_str(L, sb));
lj_gc_check(L);
return 1;
}
#endif
/* ------------------------------------------------------------------------ */
/* macro to `unsign' a character */
#define uchar(c) ((unsigned char)(c))
#define CAP_UNFINISHED (-1)
#define CAP_POSITION (-2)
typedef struct MatchState {
const char *src_init; /* init of source string */
const char *src_end; /* end (`\0') of source string */
lua_State *L;
int level; /* total number of captures (finished or unfinished) */
int depth;
struct {
const char *init;
ptrdiff_t len;
} capture[LUA_MAXCAPTURES];
} MatchState;
#define L_ESC '%'
static int check_capture(MatchState *ms, int l)
{
l -= '1';
if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
lj_err_caller(ms->L, LJ_ERR_STRCAPI);
return l;
}
static int capture_to_close(MatchState *ms)
{
int level = ms->level;
for (level--; level>=0; level--)
if (ms->capture[level].len == CAP_UNFINISHED) return level;
lj_err_caller(ms->L, LJ_ERR_STRPATC);
return 0; /* unreachable */
}
static const char *classend(MatchState *ms, const char *p)
{
switch (*p++) {
case L_ESC:
if (*p == '\0')
lj_err_caller(ms->L, LJ_ERR_STRPATE);
return p+1;
case '[':
if (*p == '^') p++;
do { /* look for a `]' */
if (*p == '\0')
lj_err_caller(ms->L, LJ_ERR_STRPATM);
if (*(p++) == L_ESC && *p != '\0')
p++; /* skip escapes (e.g. `%]') */
} while (*p != ']');
return p+1;
default:
return p;
}
}
static const unsigned char match_class_map[32] = {
0,LJ_CHAR_ALPHA,0,LJ_CHAR_CNTRL,LJ_CHAR_DIGIT,0,0,LJ_CHAR_GRAPH,0,0,0,0,
LJ_CHAR_LOWER,0,0,0,LJ_CHAR_PUNCT,0,0,LJ_CHAR_SPACE,0,
LJ_CHAR_UPPER,0,LJ_CHAR_ALNUM,LJ_CHAR_XDIGIT,0,0,0,0,0,0,0
};
static int match_class(int c, int cl)
{
if ((cl & 0xc0) == 0x40) {
int t = match_class_map[(cl&0x1f)];
if (t) {
t = lj_char_isa(c, t);
return (cl & 0x20) ? t : !t;
}
if (cl == 'z') return c == 0;
if (cl == 'Z') return c != 0;
}
return (cl == c);
}
static int matchbracketclass(int c, const char *p, const char *ec)
{
int sig = 1;
if (*(p+1) == '^') {
sig = 0;
p++; /* skip the `^' */
}
while (++p < ec) {
if (*p == L_ESC) {
p++;
if (match_class(c, uchar(*p)))
return sig;
}
else if ((*(p+1) == '-') && (p+2 < ec)) {
p+=2;
if (uchar(*(p-2)) <= c && c <= uchar(*p))
return sig;
}
else if (uchar(*p) == c) return sig;
}
return !sig;
}
static int singlematch(int c, const char *p, const char *ep)
{
switch (*p) {
case '.': return 1; /* matches any char */
case L_ESC: return match_class(c, uchar(*(p+1)));
case '[': return matchbracketclass(c, p, ep-1);
default: return (uchar(*p) == c);
}
}
static const char *match(MatchState *ms, const char *s, const char *p);
static const char *matchbalance(MatchState *ms, const char *s, const char *p)
{
if (*p == 0 || *(p+1) == 0)
lj_err_caller(ms->L, LJ_ERR_STRPATU);
if (*s != *p) {
return NULL;
} else {
int b = *p;
int e = *(p+1);
int cont = 1;
while (++s < ms->src_end) {
if (*s == e) {
if (--cont == 0) return s+1;
} else if (*s == b) {
cont++;
}
}
}
return NULL; /* string ends out of balance */
}
static const char *max_expand(MatchState *ms, const char *s,
const char *p, const char *ep)
{
ptrdiff_t i = 0; /* counts maximum expand for item */
while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
i++;
/* keeps trying to match with the maximum repetitions */
while (i>=0) {
const char *res = match(ms, (s+i), ep+1);
if (res) return res;
i--; /* else didn't match; reduce 1 repetition to try again */
}
return NULL;
}
static const char *min_expand(MatchState *ms, const char *s,
const char *p, const char *ep)
{
for (;;) {
const char *res = match(ms, s, ep+1);
if (res != NULL)
return res;
else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
s++; /* try with one more repetition */
else
return NULL;
}
}
static const char *start_capture(MatchState *ms, const char *s,
const char *p, int what)
{
const char *res;
int level = ms->level;
if (level >= LUA_MAXCAPTURES) lj_err_caller(ms->L, LJ_ERR_STRCAPN);
ms->capture[level].init = s;
ms->capture[level].len = what;
ms->level = level+1;
if ((res=match(ms, s, p)) == NULL) /* match failed? */
ms->level--; /* undo capture */
return res;
}
static const char *end_capture(MatchState *ms, const char *s,
const char *p)
{
int l = capture_to_close(ms);
const char *res;
ms->capture[l].len = s - ms->capture[l].init; /* close capture */
if ((res = match(ms, s, p)) == NULL) /* match failed? */
ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
return res;
}
static const char *match_capture(MatchState *ms, const char *s, int l)
{
size_t len;
l = check_capture(ms, l);
len = (size_t)ms->capture[l].len;
if ((size_t)(ms->src_end-s) >= len &&
memcmp(ms->capture[l].init, s, len) == 0)
return s+len;
else
return NULL;
}
static const char *match(MatchState *ms, const char *s, const char *p)
{
if (++ms->depth > LJ_MAX_XLEVEL)
lj_err_caller(ms->L, LJ_ERR_STRPATX);
init: /* using goto's to optimize tail recursion */
switch (*p) {
case '(': /* start capture */
if (*(p+1) == ')') /* position capture? */
s = start_capture(ms, s, p+2, CAP_POSITION);
else
s = start_capture(ms, s, p+1, CAP_UNFINISHED);
break;
case ')': /* end capture */
s = end_capture(ms, s, p+1);
break;
case L_ESC:
switch (*(p+1)) {
case 'b': /* balanced string? */
s = matchbalance(ms, s, p+2);
if (s == NULL) break;
p+=4;
goto init; /* else s = match(ms, s, p+4); */
case 'f': { /* frontier? */
const char *ep; char previous;
p += 2;
if (*p != '[')
lj_err_caller(ms->L, LJ_ERR_STRPATB);
ep = classend(ms, p); /* points to what is next */
previous = (s == ms->src_init) ? '\0' : *(s-1);
if (matchbracketclass(uchar(previous), p, ep-1) ||
!matchbracketclass(uchar(*s), p, ep-1)) { s = NULL; break; }
p=ep;
goto init; /* else s = match(ms, s, ep); */
}
default:
if (lj_char_isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */
s = match_capture(ms, s, uchar(*(p+1)));
if (s == NULL) break;
p+=2;
goto init; /* else s = match(ms, s, p+2) */
}
goto dflt; /* case default */
}
break;
case '\0': /* end of pattern */
break; /* match succeeded */
case '$':
/* is the `$' the last char in pattern? */
if (*(p+1) != '\0') goto dflt;
if (s != ms->src_end) s = NULL; /* check end of string */
break;
default: dflt: { /* it is a pattern item */
const char *ep = classend(ms, p); /* points to what is next */
int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
switch (*ep) {
case '?': { /* optional */
const char *res;
if (m && ((res=match(ms, s+1, ep+1)) != NULL)) {
s = res;
break;
}
p=ep+1;
goto init; /* else s = match(ms, s, ep+1); */
}
case '*': /* 0 or more repetitions */
s = max_expand(ms, s, p, ep);
break;
case '+': /* 1 or more repetitions */
s = (m ? max_expand(ms, s+1, p, ep) : NULL);
break;
case '-': /* 0 or more repetitions (minimum) */
s = min_expand(ms, s, p, ep);
break;
default:
if (m) { s++; p=ep; goto init; } /* else s = match(ms, s+1, ep); */
s = NULL;
break;
}
break;
}
}
ms->depth--;
return s;
}
static void push_onecapture(MatchState *ms, int i, const char *s, const char *e)
{
if (i >= ms->level) {
if (i == 0) /* ms->level == 0, too */
lua_pushlstring(ms->L, s, (size_t)(e - s)); /* add whole match */
else
lj_err_caller(ms->L, LJ_ERR_STRCAPI);
} else {
ptrdiff_t l = ms->capture[i].len;
if (l == CAP_UNFINISHED) lj_err_caller(ms->L, LJ_ERR_STRCAPU);
if (l == CAP_POSITION)
lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
else
lua_pushlstring(ms->L, ms->capture[i].init, (size_t)l);
}
}
static int push_captures(MatchState *ms, const char *s, const char *e)
{
int i;
int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
luaL_checkstack(ms->L, nlevels, "too many captures");
for (i = 0; i < nlevels; i++)
push_onecapture(ms, i, s, e);
return nlevels; /* number of strings pushed */
}
static int str_find_aux(lua_State *L, int find)
{
GCstr *s = lj_lib_checkstr(L, 1);
GCstr *p = lj_lib_checkstr(L, 2);
int32_t start = lj_lib_optint(L, 3, 1);
MSize st;
if (start < 0) start += (int32_t)s->len; else start--;
if (start < 0) start = 0;
st = (MSize)start;
if (st > s->len) {
#if LJ_52
setnilV(L->top-1);
return 1;
#else
st = s->len;
#endif
}
if (find && ((L->base+3 < L->top && tvistruecond(L->base+3)) ||
!lj_str_haspattern(p))) { /* Search for fixed string. */
const char *q = lj_str_find(strdata(s)+st, strdata(p), s->len-st, p->len);
if (q) {
setintV(L->top-2, (int32_t)(q-strdata(s)) + 1);
setintV(L->top-1, (int32_t)(q-strdata(s)) + (int32_t)p->len);
return 2;
}
} else { /* Search for pattern. */
MatchState ms;
const char *pstr = strdata(p);
const char *sstr = strdata(s) + st;
int anchor = 0;
if (*pstr == '^') { pstr++; anchor = 1; }
ms.L = L;
ms.src_init = strdata(s);
ms.src_end = strdata(s) + s->len;
do { /* Loop through string and try to match the pattern. */
const char *q;
ms.level = ms.depth = 0;
q = match(&ms, sstr, pstr);
if (q) {
if (find) {
setintV(L->top++, (int32_t)(sstr-(strdata(s)-1)));
setintV(L->top++, (int32_t)(q-strdata(s)));
return push_captures(&ms, NULL, NULL) + 2;
} else {
return push_captures(&ms, sstr, q);
}
}
} while (sstr++ < ms.src_end && !anchor);
}
setnilV(L->top-1); /* Not found. */
return 1;
}
LJLIB_CF(string_find) LJLIB_REC(.)
{
return str_find_aux(L, 1);
}
LJLIB_CF(string_match)
{
return str_find_aux(L, 0);
}
LJLIB_NOREG LJLIB_CF(string_gmatch_aux)
{
const char *p = strVdata(lj_lib_upvalue(L, 2));
GCstr *str = strV(lj_lib_upvalue(L, 1));
const char *s = strdata(str);
TValue *tvpos = lj_lib_upvalue(L, 3);
const char *src = s + tvpos->u32.lo;
MatchState ms;
ms.L = L;
ms.src_init = s;
ms.src_end = s + str->len;
for (; src <= ms.src_end; src++) {
const char *e;
ms.level = ms.depth = 0;
if ((e = match(&ms, src, p)) != NULL) {
int32_t pos = (int32_t)(e - s);
if (e == src) pos++; /* Ensure progress for empty match. */
tvpos->u32.lo = (uint32_t)pos;
return push_captures(&ms, src, e);
}
}
return 0; /* not found */
}
LJLIB_CF(string_gmatch)
{
lj_lib_checkstr(L, 1);
lj_lib_checkstr(L, 2);
L->top = L->base+3;
(L->top-1)->u64 = 0;
lj_lib_pushcc(L, lj_cf_string_gmatch_aux, FF_string_gmatch_aux, 3);
return 1;
}
static void add_s(MatchState *ms, luaL_Buffer *b, const char *s, const char *e)
{
size_t l, i;
const char *news = lua_tolstring(ms->L, 3, &l);
for (i = 0; i < l; i++) {
if (news[i] != L_ESC) {
luaL_addchar(b, news[i]);
} else {
i++; /* skip ESC */
if (!lj_char_isdigit(uchar(news[i]))) {
luaL_addchar(b, news[i]);
} else if (news[i] == '0') {
luaL_addlstring(b, s, (size_t)(e - s));
} else {
push_onecapture(ms, news[i] - '1', s, e);
luaL_addvalue(b); /* add capture to accumulated result */
}
}
}
}
static void add_value(MatchState *ms, luaL_Buffer *b,
const char *s, const char *e)
{
lua_State *L = ms->L;
switch (lua_type(L, 3)) {
case LUA_TNUMBER:
case LUA_TSTRING: {
add_s(ms, b, s, e);
return;
}
case LUA_TFUNCTION: {
int n;
lua_pushvalue(L, 3);
n = push_captures(ms, s, e);
lua_call(L, n, 1);
break;
}
case LUA_TTABLE: {
push_onecapture(ms, 0, s, e);
lua_gettable(L, 3);
break;
}
}
if (!lua_toboolean(L, -1)) { /* nil or false? */
lua_pop(L, 1);
lua_pushlstring(L, s, (size_t)(e - s)); /* keep original text */
} else if (!lua_isstring(L, -1)) {
lj_err_callerv(L, LJ_ERR_STRGSRV, luaL_typename(L, -1));
}
luaL_addvalue(b); /* add result to accumulator */
}
LJLIB_CF(string_gsub)
{
size_t srcl;
const char *src = luaL_checklstring(L, 1, &srcl);
const char *p = luaL_checkstring(L, 2);
int tr = lua_type(L, 3);
int max_s = luaL_optint(L, 4, (int)(srcl+1));
int anchor = (*p == '^') ? (p++, 1) : 0;
int n = 0;
MatchState ms;
luaL_Buffer b;
if (!(tr == LUA_TNUMBER || tr == LUA_TSTRING ||
tr == LUA_TFUNCTION || tr == LUA_TTABLE))
lj_err_arg(L, 3, LJ_ERR_NOSFT);
luaL_buffinit(L, &b);
ms.L = L;
ms.src_init = src;
ms.src_end = src+srcl;
while (n < max_s) {
const char *e;
ms.level = ms.depth = 0;
e = match(&ms, src, p);
if (e) {
n++;
add_value(&ms, &b, src, e);
}
if (e && e>src) /* non empty match? */
src = e; /* skip it */
else if (src < ms.src_end)
luaL_addchar(&b, *src++);
else
break;
if (anchor)
break;
}
luaL_addlstring(&b, src, (size_t)(ms.src_end-src));
luaL_pushresult(&b);
lua_pushinteger(L, n); /* number of substitutions */
return 2;
}
/* ------------------------------------------------------------------------ */
LJLIB_CF(string_format) LJLIB_REC(.)
{
int retry = 0;
SBuf *sb;
do {
sb = lj_buf_tmp_(L);
retry = lj_strfmt_putarg(L, sb, 1, -retry);
} while (retry > 0);
setstrV(L, L->top-1, lj_buf_str(L, sb));
lj_gc_check(L);
return 1;
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_string(lua_State *L)
{
GCtab *mt;
global_State *g;
LJ_LIB_REG(L, LUA_STRLIBNAME, string);
mt = lj_tab_new(L, 0, 1);
/* NOBARRIER: basemt is a GC root. */
g = G(L);
setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt));
settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1));
mt->nomm = (uint8_t)(~(1u<<MM_index));
#if LJ_HASBUFFER
lj_lib_prereg(L, LUA_STRLIBNAME ".buffer", luaopen_string_buffer, tabV(L->top-1));
#endif
#if LJ_SRB2LIB
lua_getfield(L, -1, "gmatch");
lua_setfield(L, -2, "gfind"); /* Ugh, can we get rid of this already? */
#endif
return 1;
}
+331
View File
@@ -0,0 +1,331 @@
/*
** Table library.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
**
** Major portions taken verbatim or adapted from the Lua interpreter.
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
#define lib_table_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_tab.h"
#include "lj_ff.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_table
LJLIB_LUA(table_foreachi) /*
function(t, f)
CHECK_tab(t)
CHECK_func(f)
for i=1,#t do
local r = f(i, t[i])
if r ~= nil then return r end
end
end
*/
LJLIB_LUA(table_foreach) /*
function(t, f)
CHECK_tab(t)
CHECK_func(f)
for k, v in PAIRS(t) do
local r = f(k, v)
if r ~= nil then return r end
end
end
*/
LJLIB_LUA(table_getn) /*
function(t)
CHECK_tab(t)
return #t
end
*/
LJLIB_CF(table_maxn)
{
GCtab *t = lj_lib_checktab(L, 1);
TValue *array = tvref(t->array);
Node *node;
lua_Number m = 0;
ptrdiff_t i;
for (i = (ptrdiff_t)t->asize - 1; i >= 0; i--)
if (!tvisnil(&array[i])) {
m = (lua_Number)(int32_t)i;
break;
}
node = noderef(t->node);
for (i = (ptrdiff_t)t->hmask; i >= 0; i--)
if (!tvisnil(&node[i].val) && tvisnumber(&node[i].key)) {
lua_Number n = numberVnum(&node[i].key);
if (n > m) m = n;
}
#if LJ_INTONLY
setintV(L->top-1, lj_num2int(m));
#else
setnumV(L->top-1, m);
#endif
return 1;
}
LJLIB_CF(table_insert) LJLIB_REC(.)
{
GCtab *t = lj_lib_checktab(L, 1);
int32_t n, i = (int32_t)lj_tab_len(t) + 1;
int nargs = (int)((char *)L->top - (char *)L->base);
if (nargs != 2*sizeof(TValue)) {
if (nargs != 3*sizeof(TValue))
lj_err_caller(L, LJ_ERR_TABINS);
/* NOBARRIER: This just moves existing elements around. */
for (n = lj_lib_checkint(L, 2); i > n; i--) {
/* The set may invalidate the get pointer, so need to do it first! */
TValue *dst = lj_tab_setint(L, t, i);
cTValue *src = lj_tab_getint(t, i-1);
if (src) {
copyTV(L, dst, src);
} else {
setnilV(dst);
}
}
i = n;
}
{
TValue *dst = lj_tab_setint(L, t, i);
copyTV(L, dst, L->top-1); /* Set new value. */
lj_gc_barriert(L, t, dst);
}
return 0;
}
LJLIB_LUA(table_remove) /*
function(t, pos)
CHECK_tab(t)
local len = #t
if pos == nil then
if len ~= 0 then
local old = t[len]
t[len] = nil
return old
end
else
CHECK_int(pos)
if pos >= 1 and pos <= len then
local old = t[pos]
for i=pos+1,len do
t[i-1] = t[i]
end
t[len] = nil
return old
end
end
end
*/
LJLIB_LUA(table_move) /*
function(a1, f, e, t, a2)
CHECK_tab(a1)
CHECK_int(f)
CHECK_int(e)
CHECK_int(t)
if a2 == nil then a2 = a1 end
CHECK_tab(a2)
if e >= f then
local d = t - f
if t > e or t <= f or a2 ~= a1 then
for i=f,e do a2[i+d] = a1[i] end
else
for i=e,f,-1 do a2[i+d] = a1[i] end
end
end
return a2
end
*/
LJLIB_CF(table_concat) LJLIB_REC(.)
{
GCtab *t = lj_lib_checktab(L, 1);
GCstr *sep = lj_lib_optstr(L, 2);
int32_t i = lj_lib_optint(L, 3, 1);
int32_t e = (L->base+3 < L->top && !tvisnil(L->base+3)) ?
lj_lib_checkint(L, 4) : (int32_t)lj_tab_len(t);
SBuf *sb = lj_buf_tmp_(L);
SBuf *sbx = lj_buf_puttab(sb, t, sep, i, e);
if (LJ_UNLIKELY(!sbx)) { /* Error: bad element type. */
int32_t idx = (int32_t)(intptr_t)sb->w;
cTValue *o = lj_tab_getint(t, idx);
lj_err_callerv(L, LJ_ERR_TABCAT,
lj_obj_itypename[o ? itypemap(o) : ~LJ_TNIL], idx);
}
setstrV(L, L->top-1, lj_buf_str(L, sbx));
lj_gc_check(L);
return 1;
}
/* ------------------------------------------------------------------------ */
static void set2(lua_State *L, int i, int j)
{
lua_rawseti(L, 1, i);
lua_rawseti(L, 1, j);
}
static int sort_comp(lua_State *L, int a, int b)
{
if (!lua_isnil(L, 2)) { /* function? */
int res;
lua_pushvalue(L, 2);
lua_pushvalue(L, a-1); /* -1 to compensate function */
lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */
lua_call(L, 2, 1);
res = lua_toboolean(L, -1);
lua_pop(L, 1);
return res;
} else { /* a < b? */
return lua_lessthan(L, a, b);
}
}
static void auxsort(lua_State *L, int l, int u)
{
while (l < u) { /* for tail recursion */
int i, j;
/* sort elements a[l], a[(l+u)/2] and a[u] */
lua_rawgeti(L, 1, l);
lua_rawgeti(L, 1, u);
if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
set2(L, l, u); /* swap a[l] - a[u] */
else
lua_pop(L, 2);
if (u-l == 1) break; /* only 2 elements */
i = (l+u)/2;
lua_rawgeti(L, 1, i);
lua_rawgeti(L, 1, l);
if (sort_comp(L, -2, -1)) { /* a[i]<a[l]? */
set2(L, i, l);
} else {
lua_pop(L, 1); /* remove a[l] */
lua_rawgeti(L, 1, u);
if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
set2(L, i, u);
else
lua_pop(L, 2);
}
if (u-l == 2) break; /* only 3 elements */
lua_rawgeti(L, 1, i); /* Pivot */
lua_pushvalue(L, -1);
lua_rawgeti(L, 1, u-1);
set2(L, i, u-1);
/* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
i = l; j = u-1;
for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
/* repeat ++i until a[i] >= P */
while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
if (i>=u) lj_err_caller(L, LJ_ERR_TABSORT);
lua_pop(L, 1); /* remove a[i] */
}
/* repeat --j until a[j] <= P */
while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
if (j<=l) lj_err_caller(L, LJ_ERR_TABSORT);
lua_pop(L, 1); /* remove a[j] */
}
if (j<i) {
lua_pop(L, 3); /* pop pivot, a[i], a[j] */
break;
}
set2(L, i, j);
}
lua_rawgeti(L, 1, u-1);
lua_rawgeti(L, 1, i);
set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */
/* a[l..i-1] <= a[i] == P <= a[i+1..u] */
/* adjust so that smaller half is in [j..i] and larger one in [l..u] */
if (i-l < u-i) {
j=l; i=i-1; l=i+2;
} else {
j=i+1; i=u; u=j-2;
}
auxsort(L, j, i); /* call recursively the smaller one */
} /* repeat the routine for the larger one */
}
LJLIB_CF(table_sort)
{
GCtab *t = lj_lib_checktab(L, 1);
int32_t n = (int32_t)lj_tab_len(t);
lua_settop(L, 2);
if (!tvisnil(L->base+1))
lj_lib_checkfunc(L, 2);
auxsort(L, 1, n);
return 0;
}
#if LJ_52
LJLIB_PUSH("n")
LJLIB_CF(table_pack)
{
TValue *array, *base = L->base;
MSize i, n = (uint32_t)(L->top - base);
GCtab *t = lj_tab_new(L, n ? n+1 : 0, 1);
/* NOBARRIER: The table is new (marked white). */
setintV(lj_tab_setstr(L, t, strV(lj_lib_upvalue(L, 1))), (int32_t)n);
for (array = tvref(t->array) + 1, i = 0; i < n; i++)
copyTV(L, &array[i], &base[i]);
settabV(L, base, t);
L->top = base+1;
lj_gc_check(L);
return 1;
}
#endif
LJLIB_NOREG LJLIB_CF(table_new) LJLIB_REC(.)
{
int32_t a = lj_lib_checkint(L, 1);
int32_t h = lj_lib_checkint(L, 2);
lua_createtable(L, a, h);
return 1;
}
LJLIB_NOREG LJLIB_CF(table_clear) LJLIB_REC(.)
{
lj_tab_clear(lj_lib_checktab(L, 1));
return 0;
}
static int luaopen_table_new(lua_State *L)
{
return lj_lib_postreg(L, lj_cf_table_new, FF_table_new, "new");
}
static int luaopen_table_clear(lua_State *L)
{
return lj_lib_postreg(L, lj_cf_table_clear, FF_table_clear, "clear");
}
/* ------------------------------------------------------------------------ */
#include "lj_libdef.h"
LUALIB_API int luaopen_table(lua_State *L)
{
LJ_LIB_REG(L, LUA_TABLIBNAME, table);
#if LJ_52
lua_getglobal(L, "unpack");
lua_setfield(L, -2, "unpack");
#endif
lj_lib_prereg(L, LUA_TABLIBNAME ".new", luaopen_table_new, tabV(L->top-1));
lj_lib_prereg(L, LUA_TABLIBNAME ".clear", luaopen_table_clear, tabV(L->top-1));
return 1;
}
File diff suppressed because it is too large. Load diff
+18
View File
@@ -0,0 +1,18 @@
/*
** Bundled memory allocator.
** Donated to the public domain.
*/
#ifndef _LJ_ALLOC_H
#define _LJ_ALLOC_H
#include "lj_def.h"
#ifndef LUAJIT_USE_SYSMALLOC
LJ_FUNC void *lj_alloc_create(PRNGState *rs);
LJ_FUNC void lj_alloc_setprng(void *msp, PRNGState *rs);
LJ_FUNC void lj_alloc_destroy(void *msp);
LJ_FUNC void *lj_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize);
#endif
#endif
+1335
View File
File diff suppressed because it is too large. Load diff
+778
View File
@@ -0,0 +1,778 @@
/*
** Target architecture selection.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_ARCH_H
#define _LJ_ARCH_H
#include "lua.h"
/* -- Target definitions -------------------------------------------------- */
/* Target endianess. */
#define LUAJIT_LE 0
#define LUAJIT_BE 1
/* Target architectures. */
#define LUAJIT_ARCH_X86 1
#define LUAJIT_ARCH_x86 1
#define LUAJIT_ARCH_X64 2
#define LUAJIT_ARCH_x64 2
#define LUAJIT_ARCH_ARM 3
#define LUAJIT_ARCH_arm 3
#define LUAJIT_ARCH_ARM64 4
#define LUAJIT_ARCH_arm64 4
#define LUAJIT_ARCH_PPC 5
#define LUAJIT_ARCH_ppc 5
#define LUAJIT_ARCH_MIPS 6
#define LUAJIT_ARCH_mips 6
#define LUAJIT_ARCH_MIPS32 6
#define LUAJIT_ARCH_mips32 6
#define LUAJIT_ARCH_MIPS64 7
#define LUAJIT_ARCH_mips64 7
/* Target OS. */
#define LUAJIT_OS_OTHER 0
#define LUAJIT_OS_WINDOWS 1
#define LUAJIT_OS_LINUX 2
#define LUAJIT_OS_OSX 3
#define LUAJIT_OS_BSD 4
#define LUAJIT_OS_POSIX 5
/* Number mode. */
#define LJ_NUMMODE_SINGLE 0 /* Single-number mode only. */
#define LJ_NUMMODE_SINGLE_DUAL 1 /* Default to single-number mode. */
#define LJ_NUMMODE_DUAL 2 /* Dual-number mode only. */
#define LJ_NUMMODE_DUAL_SINGLE 3 /* Default to dual-number mode. */
/* -- Target detection ---------------------------------------------------- */
/* Select native target if no target defined. */
#ifndef LUAJIT_TARGET
#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
#define LUAJIT_TARGET LUAJIT_ARCH_X86
#elif defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
#define LUAJIT_TARGET LUAJIT_ARCH_X64
#elif defined(__arm__) || defined(__arm) || defined(__ARM__) || defined(__ARM)
#define LUAJIT_TARGET LUAJIT_ARCH_ARM
#elif defined(__aarch64__) || defined(_M_ARM64)
#define LUAJIT_TARGET LUAJIT_ARCH_ARM64
#elif defined(__ppc__) || defined(__ppc) || defined(__PPC__) || defined(__PPC) || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) || defined(__POWERPC) || defined(_M_PPC)
#define LUAJIT_TARGET LUAJIT_ARCH_PPC
#elif defined(__mips64__) || defined(__mips64) || defined(__MIPS64__) || defined(__MIPS64)
#define LUAJIT_TARGET LUAJIT_ARCH_MIPS64
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(__MIPS)
#define LUAJIT_TARGET LUAJIT_ARCH_MIPS32
#else
#error "Architecture not supported (in this version), see: https://luajit.org/status.html#architectures"
#endif
#endif
/* Select native OS if no target OS defined. */
#ifndef LUAJIT_OS
#if defined(_WIN32) && !defined(_XBOX_VER)
#define LUAJIT_OS LUAJIT_OS_WINDOWS
#elif defined(__linux__)
#define LUAJIT_OS LUAJIT_OS_LINUX
#elif defined(__MACH__) && defined(__APPLE__)
#include "TargetConditionals.h"
#define LUAJIT_OS LUAJIT_OS_OSX
#elif (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__DragonFly__)) && !defined(__ORBIS__) && !defined(__PROSPERO__)
#define LUAJIT_OS LUAJIT_OS_BSD
#elif (defined(__sun__) && defined(__svr4__))
#define LJ_TARGET_SOLARIS 1
#define LUAJIT_OS LUAJIT_OS_POSIX
#elif defined(__HAIKU__)
#define LUAJIT_OS LUAJIT_OS_POSIX
#elif defined(__CYGWIN__)
#define LJ_TARGET_CYGWIN 1
#define LUAJIT_OS LUAJIT_OS_POSIX
#elif defined(__QNX__)
#define LJ_TARGET_QNX 1
#define LUAJIT_OS LUAJIT_OS_POSIX
#else
#define LUAJIT_OS LUAJIT_OS_OTHER
#endif
#endif
/* Set target OS properties. */
#if LUAJIT_OS == LUAJIT_OS_WINDOWS
#define LJ_OS_NAME "Windows"
#elif LUAJIT_OS == LUAJIT_OS_LINUX
#define LJ_OS_NAME "Linux"
#elif LUAJIT_OS == LUAJIT_OS_OSX
#define LJ_OS_NAME "OSX"
#elif LUAJIT_OS == LUAJIT_OS_BSD
#define LJ_OS_NAME "BSD"
#elif LUAJIT_OS == LUAJIT_OS_POSIX
#define LJ_OS_NAME "POSIX"
#else
#define LJ_OS_NAME "Other"
#endif
#define LJ_TARGET_WINDOWS (LUAJIT_OS == LUAJIT_OS_WINDOWS)
#define LJ_TARGET_LINUX (LUAJIT_OS == LUAJIT_OS_LINUX)
#define LJ_TARGET_OSX (LUAJIT_OS == LUAJIT_OS_OSX)
#define LJ_TARGET_BSD (LUAJIT_OS == LUAJIT_OS_BSD)
#define LJ_TARGET_POSIX (LUAJIT_OS > LUAJIT_OS_WINDOWS)
#define LJ_TARGET_DLOPEN LJ_TARGET_POSIX
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
#define LJ_TARGET_IOS 1
#else
#define LJ_TARGET_IOS 0
#endif
#ifdef __CELLOS_LV2__
#define LJ_TARGET_PS3 1
#define LJ_TARGET_CONSOLE 1
#endif
#ifdef __ORBIS__
#define LJ_TARGET_PS4 1
#define LJ_TARGET_CONSOLE 1
#undef NULL
#define NULL ((void*)0)
#endif
#ifdef __PROSPERO__
#define LJ_TARGET_PS5 1
#define LJ_TARGET_CONSOLE 1
#undef NULL
#define NULL ((void*)0)
#endif
#ifdef __psp2__
#define LJ_TARGET_PSVITA 1
#define LJ_TARGET_CONSOLE 1
#endif
#if _XBOX_VER >= 200
#define LJ_TARGET_XBOX360 1
#define LJ_TARGET_CONSOLE 1
#endif
#ifdef _DURANGO
#define LJ_TARGET_XBOXONE 1
#define LJ_TARGET_CONSOLE 1
#define LJ_TARGET_GC64 1
#endif
#ifdef __NX__
#define LJ_TARGET_NX 1
#define LJ_TARGET_CONSOLE 1
#undef NULL
#define NULL ((void*)0)
#endif
#ifdef _UWP
#define LJ_TARGET_UWP 1
#if LUAJIT_TARGET == LUAJIT_ARCH_X64
#define LJ_TARGET_GC64 1
#endif
#endif
/* -- Arch-specific settings ---------------------------------------------- */
/* Set target architecture properties. */
#if LUAJIT_TARGET == LUAJIT_ARCH_X86
#define LJ_ARCH_NAME "x86"
#define LJ_ARCH_BITS 32
#define LJ_ARCH_ENDIAN LUAJIT_LE
#define LJ_TARGET_X86 1
#define LJ_TARGET_X86ORX64 1
#define LJ_TARGET_EHRETREG 0
#define LJ_TARGET_EHRAREG 8
#define LJ_TARGET_MASKSHIFT 1
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNALIGNED 1
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL
#elif LUAJIT_TARGET == LUAJIT_ARCH_X64
#define LJ_ARCH_NAME "x64"
#define LJ_ARCH_BITS 64
#define LJ_ARCH_ENDIAN LUAJIT_LE
#define LJ_TARGET_X64 1
#define LJ_TARGET_X86ORX64 1
#define LJ_TARGET_EHRETREG 0
#define LJ_TARGET_EHRAREG 16
#define LJ_TARGET_JUMPRANGE 31 /* +-2^31 = +-2GB */
#define LJ_TARGET_MASKSHIFT 1
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNALIGNED 1
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL
#ifndef LUAJIT_DISABLE_GC64
#define LJ_TARGET_GC64 1
#elif LJ_TARGET_OSX
#error "macOS requires GC64 -- don't disable it"
#endif
#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM
#define LJ_ARCH_NAME "arm"
#define LJ_ARCH_BITS 32
#define LJ_ARCH_ENDIAN LUAJIT_LE
#if !defined(LJ_ARCH_HASFPU) && __SOFTFP__
#define LJ_ARCH_HASFPU 0
#endif
#if !defined(LJ_ABI_SOFTFP) && !__ARM_PCS_VFP
#define LJ_ABI_SOFTFP 1
#endif
#define LJ_ABI_EABI 1
#define LJ_TARGET_ARM 1
#define LJ_TARGET_EHRETREG 0
#define LJ_TARGET_EHRAREG 14
#define LJ_TARGET_JUMPRANGE 25 /* +-2^25 = +-32MB */
#define LJ_TARGET_MASKSHIFT 0
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
#if __ARM_ARCH >= 8 || __ARM_ARCH_8__ || __ARM_ARCH_8A__
#define LJ_ARCH_VERSION 80
#elif __ARM_ARCH == 7 || __ARM_ARCH_7__ || __ARM_ARCH_7A__ || __ARM_ARCH_7R__ || __ARM_ARCH_7S__ || __ARM_ARCH_7VE__
#define LJ_ARCH_VERSION 70
#elif __ARM_ARCH_6T2__
#define LJ_ARCH_VERSION 61
#elif __ARM_ARCH == 6 || __ARM_ARCH_6__ || __ARM_ARCH_6J__ || __ARM_ARCH_6K__ || __ARM_ARCH_6Z__ || __ARM_ARCH_6ZK__
#define LJ_ARCH_VERSION 60
#else
#define LJ_ARCH_VERSION 50
#endif
#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM64
#define LJ_ARCH_BITS 64
#if defined(__AARCH64EB__)
#define LJ_ARCH_NAME "arm64be"
#define LJ_ARCH_ENDIAN LUAJIT_BE
#else
#define LJ_ARCH_NAME "arm64"
#define LJ_ARCH_ENDIAN LUAJIT_LE
#endif
#if !defined(LJ_ABI_PAUTH) && defined(__arm64e__)
#define LJ_ABI_PAUTH 1
#endif
#define LJ_TARGET_ARM64 1
#define LJ_TARGET_EHRETREG 0
#define LJ_TARGET_EHRAREG 30
#define LJ_TARGET_JUMPRANGE 27 /* +-2^27 = +-128MB */
#define LJ_TARGET_MASKSHIFT 1
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */
#define LJ_TARGET_GC64 1
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
#define LJ_ARCH_VERSION 80
#elif LUAJIT_TARGET == LUAJIT_ARCH_PPC
#ifndef LJ_ARCH_ENDIAN
#if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__
#define LJ_ARCH_ENDIAN LUAJIT_LE
#else
#define LJ_ARCH_ENDIAN LUAJIT_BE
#endif
#endif
#if _LP64
#define LJ_ARCH_BITS 64
#if LJ_ARCH_ENDIAN == LUAJIT_LE
#define LJ_ARCH_NAME "ppc64le"
#else
#define LJ_ARCH_NAME "ppc64"
#endif
#else
#define LJ_ARCH_BITS 32
#define LJ_ARCH_NAME "ppc"
#if !defined(LJ_ARCH_HASFPU)
#if defined(_SOFT_FLOAT) || defined(_SOFT_DOUBLE)
#define LJ_ARCH_HASFPU 0
#else
#define LJ_ARCH_HASFPU 1
#endif
#endif
#if !defined(LJ_ABI_SOFTFP)
#if defined(_SOFT_FLOAT) || defined(_SOFT_DOUBLE)
#define LJ_ABI_SOFTFP 1
#else
#define LJ_ABI_SOFTFP 0
#endif
#endif
#endif
#if LJ_ABI_SOFTFP
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
#else
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL_SINGLE
#endif
#define LJ_TARGET_PPC 1
#define LJ_TARGET_EHRETREG 3
#define LJ_TARGET_EHRAREG 65
#define LJ_TARGET_JUMPRANGE 25 /* +-2^25 = +-32MB */
#define LJ_TARGET_MASKSHIFT 0
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNIFYROT 1 /* Want only IR_BROL. */
#if LJ_TARGET_CONSOLE
#define LJ_ARCH_PPC32ON64 1
#define LJ_ARCH_NOFFI 1
#elif LJ_ARCH_BITS == 64
#error "No support for PPC64"
#undef LJ_TARGET_PPC
#endif
#if _ARCH_PWR7
#define LJ_ARCH_VERSION 70
#elif _ARCH_PWR6
#define LJ_ARCH_VERSION 60
#elif _ARCH_PWR5X
#define LJ_ARCH_VERSION 51
#elif _ARCH_PWR5
#define LJ_ARCH_VERSION 50
#elif _ARCH_PWR4
#define LJ_ARCH_VERSION 40
#else
#define LJ_ARCH_VERSION 0
#endif
#if _ARCH_PPCSQ
#define LJ_ARCH_SQRT 1
#endif
#if _ARCH_PWR5X
#define LJ_ARCH_ROUND 1
#endif
#if __PPU__
#define LJ_ARCH_CELL 1
#endif
#if LJ_TARGET_XBOX360
#define LJ_ARCH_XENON 1
#endif
#elif LUAJIT_TARGET == LUAJIT_ARCH_MIPS32 || LUAJIT_TARGET == LUAJIT_ARCH_MIPS64
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
#if __mips_isa_rev >= 6
#define LJ_TARGET_MIPSR6 1
#define LJ_TARGET_UNALIGNED 1
#endif
#if LUAJIT_TARGET == LUAJIT_ARCH_MIPS32
#if LJ_TARGET_MIPSR6
#define LJ_ARCH_NAME "mips32r6el"
#else
#define LJ_ARCH_NAME "mipsel"
#endif
#else
#if LJ_TARGET_MIPSR6
#define LJ_ARCH_NAME "mips64r6el"
#else
#define LJ_ARCH_NAME "mips64el"
#endif
#endif
#define LJ_ARCH_ENDIAN LUAJIT_LE
#else
#if LUAJIT_TARGET == LUAJIT_ARCH_MIPS32
#if LJ_TARGET_MIPSR6
#define LJ_ARCH_NAME "mips32r6"
#else
#define LJ_ARCH_NAME "mips"
#endif
#else
#if LJ_TARGET_MIPSR6
#define LJ_ARCH_NAME "mips64r6"
#else
#define LJ_ARCH_NAME "mips64"
#endif
#endif
#define LJ_ARCH_ENDIAN LUAJIT_BE
#endif
#if !defined(LJ_ARCH_HASFPU)
#ifdef __mips_soft_float
#define LJ_ARCH_HASFPU 0
#else
#define LJ_ARCH_HASFPU 1
#endif
#endif
#if !defined(LJ_ABI_SOFTFP)
#ifdef __mips_soft_float
#define LJ_ABI_SOFTFP 1
#else
#define LJ_ABI_SOFTFP 0
#endif
#endif
#if LUAJIT_TARGET == LUAJIT_ARCH_MIPS32
#define LJ_ARCH_BITS 32
#define LJ_TARGET_MIPS32 1
#else
#define LJ_ARCH_BITS 64
#define LJ_TARGET_MIPS64 1
#define LJ_TARGET_GC64 1
#endif
#define LJ_TARGET_MIPS 1
#define LJ_TARGET_EHRETREG 4
#define LJ_TARGET_EHRAREG 31
#define LJ_TARGET_JUMPRANGE 27 /* 2*2^27 = 256MB-aligned region */
#define LJ_TARGET_MASKSHIFT 1
#define LJ_TARGET_MASKROT 1
#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */
#define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL
#if LJ_TARGET_MIPSR6
#define LJ_ARCH_VERSION 60
#elif _MIPS_ARCH_MIPS32R2 || _MIPS_ARCH_MIPS64R2
#define LJ_ARCH_VERSION 20
#else
#define LJ_ARCH_VERSION 10
#endif
#else
#error "No target architecture defined"
#endif
/* -- Checks for requirements --------------------------------------------- */
/* Check for minimum required compiler versions. */
#if defined(__GNUC__)
#if LJ_TARGET_X86
#if (__GNUC__ < 3) || ((__GNUC__ == 3) && __GNUC_MINOR__ < 4)
#error "Need at least GCC 3.4 or newer"
#endif
#elif LJ_TARGET_X64
#if __GNUC__ < 4
#error "Need at least GCC 4.0 or newer"
#endif
#elif LJ_TARGET_ARM
#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 2)
#error "Need at least GCC 4.2 or newer"
#endif
#elif LJ_TARGET_ARM64
#if __clang__
#if ((__clang_major__ < 3) || ((__clang_major__ == 3) && __clang_minor__ < 5)) && !defined(__NX_TOOLCHAIN_MAJOR__)
#error "Need at least Clang 3.5 or newer"
#endif
#else
#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 8)
#error "Need at least GCC 4.8 or newer"
#endif
#endif
#elif !LJ_TARGET_PS3
#if __clang__
#if ((__clang_major__ < 3) || ((__clang_major__ == 3) && __clang_minor__ < 5))
#error "Need at least Clang 3.5 or newer"
#endif
#else
#if (__GNUC__ < 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ < 3)
#error "Need at least GCC 4.3 or newer"
#endif
#endif
#endif
#endif
/* Check target-specific constraints. */
#ifndef _BUILDVM_H
#if LJ_TARGET_X64
#if __USING_SJLJ_EXCEPTIONS__
#error "Need a C compiler with native exception handling on x64"
#endif
#elif LJ_TARGET_ARM
#if defined(__ARMEB__)
#error "No support for big-endian ARM"
#undef LJ_TARGET_ARM
#endif
#if __ARM_ARCH_6M__ || __ARM_ARCH_7M__ || __ARM_ARCH_7EM__
#error "No support for Cortex-M CPUs"
#undef LJ_TARGET_ARM
#endif
#if !(__ARM_EABI__ || LJ_TARGET_IOS)
#error "Only ARM EABI or iOS 3.0+ ABI is supported"
#undef LJ_TARGET_ARM
#endif
#elif LJ_TARGET_ARM64
#if defined(_ILP32)
#error "No support for ILP32 model on ARM64"
#undef LJ_TARGET_ARM64
#endif
#elif LJ_TARGET_PPC
#if defined(_LITTLE_ENDIAN) && (!defined(_BYTE_ORDER) || (_BYTE_ORDER == _LITTLE_ENDIAN))
#error "No support for little-endian PPC32"
#undef LJ_TARGET_PPC
#endif
#if defined(__NO_FPRS__) && !defined(_SOFT_FLOAT)
#error "No support for PPC/e500, use LuaJIT 2.0"
#undef LJ_TARGET_PPC
#endif
#elif LJ_TARGET_MIPS32
#if !((defined(_MIPS_SIM_ABI32) && _MIPS_SIM == _MIPS_SIM_ABI32) || (defined(_ABIO32) && _MIPS_SIM == _ABIO32))
#error "Only o32 ABI supported for MIPS32"
#undef LJ_TARGET_MIPS
#endif
#if LJ_TARGET_MIPSR6
/* Not that useful, since most available r6 CPUs are 64 bit. */
#error "No support for MIPS32R6"
#undef LJ_TARGET_MIPS
#endif
#elif LJ_TARGET_MIPS64
#if !((defined(_MIPS_SIM_ABI64) && _MIPS_SIM == _MIPS_SIM_ABI64) || (defined(_ABI64) && _MIPS_SIM == _ABI64))
/* MIPS32ON64 aka n32 ABI support might be desirable, but difficult. */
#error "Only n64 ABI supported for MIPS64"
#undef LJ_TARGET_MIPS
#endif
#endif
#endif
/* -- Derived defines ----------------------------------------------------- */
/* Enable or disable the dual-number mode for the VM. */
#if (LJ_ARCH_NUMMODE == LJ_NUMMODE_SINGLE && LUAJIT_NUMMODE == 2) || \
(LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL && LUAJIT_NUMMODE == 1)
#error "No support for this number mode on this architecture"
#endif
#if LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL || \
(LJ_ARCH_NUMMODE == LJ_NUMMODE_DUAL_SINGLE && LUAJIT_NUMMODE != 1) || \
(LJ_ARCH_NUMMODE == LJ_NUMMODE_SINGLE_DUAL && LUAJIT_NUMMODE == 2)
#define LJ_DUALNUM 1
#else
#define LJ_DUALNUM 0
#endif
#if defined(LUAJIT_INTONLY)
#define LJ_INTONLY 1
#else
#define LJ_INTONLY 0
#endif
#if LJ_TARGET_IOS || LJ_TARGET_CONSOLE
/* Runtime code generation is restricted on iOS. Complain to Apple, not me. */
/* Ditto for the consoles. Complain to Sony or MS, not me. */
#ifndef LUAJIT_ENABLE_JIT
#define LJ_OS_NOJIT 1
#endif
#endif
/* 64 bit GC references. */
#if LJ_TARGET_GC64
#define LJ_GC64 1
#else
#define LJ_GC64 0
#endif
/* 2-slot frame info. */
#if LJ_GC64
#define LJ_FR2 1
#else
#define LJ_FR2 0
#endif
/* Disable or enable the JIT compiler. */
#if defined(LUAJIT_DISABLE_JIT) || defined(LJ_ARCH_NOJIT) || defined(LJ_OS_NOJIT)
#define LJ_HASJIT 0
#else
#define LJ_HASJIT 1
#endif
/* Disable or enable the FFI extension. */
#if defined(LUAJIT_DISABLE_FFI) || defined(LJ_ARCH_NOFFI)
#define LJ_HASFFI 0
#else
#define LJ_HASFFI 1
#endif
/* Disable or enable the string buffer extension. */
#if defined(LUAJIT_DISABLE_BUFFER)
#define LJ_HASBUFFER 0
#else
#define LJ_HASBUFFER 1
#endif
#if defined(LUAJIT_DISABLE_BYTECODE)
#define LJ_HASBC 0
#else
#define LJ_HASBC 1
#endif
#if defined(LUAJIT_SRB2LIB)
#define LJ_SRB2LIB 1
#else
#define LJ_SRB2LIB 0
#endif
#if defined(LUAJIT_SRB2LIB_OS)
#define LJ_SRB2OS 1
#else
#define LJ_SRB2OS 0
#endif
#if defined(LUAJIT_SRB2LIB_DEBUG)
#define LJ_SRB2DEBUG 1
#else
#define LJ_SRB2DEBUG 0
#endif
#if defined(LUAJIT_SRB2LIB_IO)
#define LJ_SRB2IO 1
#else
#define LJ_SRB2IO 0
#endif
#if defined(LUAJIT_DISABLE_PROFILE)
#define LJ_HASPROFILE 0
#elif LJ_TARGET_POSIX
#define LJ_HASPROFILE 1
#define LJ_PROFILE_SIGPROF 1
#elif LJ_TARGET_PS3
#define LJ_HASPROFILE 1
#define LJ_PROFILE_PTHREAD 1
#elif LJ_TARGET_WINDOWS || LJ_TARGET_XBOX360
#define LJ_HASPROFILE 1
#define LJ_PROFILE_WTHREAD 1
#else
#define LJ_HASPROFILE 0
#endif
#ifndef LJ_ARCH_HASFPU
#define LJ_ARCH_HASFPU 1
#endif
#ifndef LJ_ABI_SOFTFP
#define LJ_ABI_SOFTFP 0
#endif
#define LJ_SOFTFP (!LJ_ARCH_HASFPU)
#define LJ_SOFTFP32 (LJ_SOFTFP && LJ_32)
#ifndef LJ_ABI_PAUTH
#define LJ_ABI_PAUTH 0
#endif
#if LJ_ARCH_ENDIAN == LUAJIT_BE
#define LJ_LE 0
#define LJ_BE 1
#define LJ_ENDIAN_SELECT(le, be) be
#define LJ_ENDIAN_LOHI(lo, hi) hi lo
#else
#define LJ_LE 1
#define LJ_BE 0
#define LJ_ENDIAN_SELECT(le, be) le
#define LJ_ENDIAN_LOHI(lo, hi) lo hi
#endif
#if LJ_ARCH_BITS == 32
#define LJ_32 1
#define LJ_64 0
#else
#define LJ_32 0
#define LJ_64 1
#endif
#ifndef LJ_TARGET_UNALIGNED
#define LJ_TARGET_UNALIGNED 0
#endif
#ifndef LJ_PAGESIZE
#define LJ_PAGESIZE 4096
#endif
/* Various workarounds for embedded operating systems or weak C runtimes. */
#if defined(__ANDROID__) || defined(__symbian__) || LJ_TARGET_XBOX360 || LJ_TARGET_WINDOWS
#define LUAJIT_NO_LOG2
#endif
#if LJ_TARGET_CONSOLE || (LJ_TARGET_IOS && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0)
#define LJ_NO_SYSTEM 1
#endif
#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
#define LJ_ABI_WIN 1
#else
#define LJ_ABI_WIN 0
#endif
#if LJ_TARGET_WINDOWS
#if LJ_TARGET_UWP
#define LJ_WIN_VALLOC VirtualAllocFromApp
#define LJ_WIN_VPROTECT VirtualProtectFromApp
extern void *LJ_WIN_LOADLIBA(const char *path);
#else
#define LJ_WIN_VALLOC VirtualAlloc
#define LJ_WIN_VPROTECT VirtualProtect
#define LJ_WIN_LOADLIBA(path) LoadLibraryExA((path), NULL, 0)
#endif
#endif
#if defined(LUAJIT_NO_UNWIND) || __GNU_COMPACT_EH__ || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4 || LJ_TARGET_PS5
#define LJ_NO_UNWIND 1
#endif
#if !LJ_NO_UNWIND && !defined(LUAJIT_UNWIND_INTERNAL) && (LJ_ABI_WIN || (defined(LUAJIT_UNWIND_EXTERNAL) && (defined(__GNUC__) || defined(__clang__))))
#define LJ_UNWIND_EXT 1
#else
#define LJ_UNWIND_EXT 0
#endif
#if LJ_UNWIND_EXT && LJ_HASJIT && !LJ_TARGET_ARM && !(LJ_ABI_WIN && LJ_TARGET_X86)
#define LJ_UNWIND_JIT 1
#else
#define LJ_UNWIND_JIT 0
#endif
/* Compatibility with Lua 5.1 vs. 5.2. */
#ifdef LUAJIT_ENABLE_LUA52COMPAT
#define LJ_52 1
#else
#define LJ_52 0
#endif
/* -- VM security --------------------------------------------------------- */
/* Don't make any changes here. Instead build with:
** make "XCFLAGS=-DLUAJIT_SECURITY_flag=value"
**
** Important note to distro maintainers: DO NOT change the defaults for a
** regular distro build -- neither upwards, nor downwards!
** These build-time configurable security flags are intended for embedders
** who may have specific needs wrt. security vs. performance.
*/
/* Security defaults. */
#ifndef LUAJIT_SECURITY_PRNG
/* PRNG init: 0 = fixed/insecure, 1 = secure from OS. */
#define LUAJIT_SECURITY_PRNG 1
#endif
#ifndef LUAJIT_SECURITY_STRHASH
/* String hash: 0 = sparse only, 1 = sparse + dense. */
#define LUAJIT_SECURITY_STRHASH 1
#endif
#ifndef LUAJIT_SECURITY_STRID
/* String IDs: 0 = linear, 1 = reseed < 255, 2 = reseed < 15, 3 = random. */
#define LUAJIT_SECURITY_STRID 1
#endif
#ifndef LUAJIT_SECURITY_MCODE
/* Machine code page protection: 0 = insecure RWX, 1 = secure RW^X. */
#define LUAJIT_SECURITY_MCODE 1
#endif
#define LJ_SECURITY_MODE \
( 0u \
| ((LUAJIT_SECURITY_PRNG & 3) << 0) \
| ((LUAJIT_SECURITY_STRHASH & 3) << 2) \
| ((LUAJIT_SECURITY_STRID & 3) << 4) \
| ((LUAJIT_SECURITY_MCODE & 3) << 6) \
)
#define LJ_SECURITY_MODESTRING \
"\004prng\007strhash\005strid\005mcode"
#endif
+2631
View File
File diff suppressed because it is too large. Load diff
+17
View File
@@ -0,0 +1,17 @@
/*
** IR assembler (SSA IR -> machine code).
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_ASM_H
#define _LJ_ASM_H
#include "lj_jit.h"
#if LJ_HASJIT
LJ_FUNC void lj_asm_trace(jit_State *J, GCtrace *T);
LJ_FUNC void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno,
MCode *target);
#endif
#endif
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+28
View File
@@ -0,0 +1,28 @@
/*
** Internal assertions.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_assert_c
#define LUA_CORE
#if defined(LUA_USE_ASSERT) || defined(LUA_USE_APICHECK)
#include <stdio.h>
#include "lj_obj.h"
void lj_assert_fail(global_State *g, const char *file, int line,
const char *func, const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
fprintf(stderr, "LuaJIT ASSERT %s:%d: %s: ", file, line, func);
vfprintf(stderr, fmt, argp);
fputc('\n', stderr);
va_end(argp);
UNUSED(g); /* May be NULL. TODO: optionally dump state. */
abort();
}
#endif
+14
View File
@@ -0,0 +1,14 @@
/*
** Bytecode instruction modes.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_bc_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_bc.h"
/* Bytecode offsets and bytecode instruction modes. */
#include "lj_bcdef.h"
+285
View File
@@ -0,0 +1,285 @@
/*
** Bytecode instruction format.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_BC_H
#define _LJ_BC_H
#include "lj_def.h"
#include "lj_arch.h"
/* Bytecode instruction format, 32 bit wide, fields of 8 or 16 bit:
**
** +----+----+----+----+
** | B | C | A | OP | Format ABC
** +----+----+----+----+
** | D | A | OP | Format AD
** +--------------------
** MSB LSB
**
** In-memory instructions are always stored in host byte order.
*/
/* Operand ranges and related constants. */
#define BCMAX_A 0xff
#define BCMAX_B 0xff
#define BCMAX_C 0xff
#define BCMAX_D 0xffff
#define BCBIAS_J 0x8000
#define NO_REG BCMAX_A
#define NO_JMP (~(BCPos)0)
/* Macros to get instruction fields. */
#define bc_op(i) ((BCOp)((i)&0xff))
#define bc_a(i) ((BCReg)(((i)>>8)&0xff))
#define bc_b(i) ((BCReg)((i)>>24))
#define bc_c(i) ((BCReg)(((i)>>16)&0xff))
#define bc_d(i) ((BCReg)((i)>>16))
#define bc_j(i) ((ptrdiff_t)bc_d(i)-BCBIAS_J)
/* Macros to set instruction fields. */
#define setbc_byte(p, x, ofs) \
((uint8_t *)(p))[LJ_ENDIAN_SELECT(ofs, 3-ofs)] = (uint8_t)(x)
#define setbc_op(p, x) setbc_byte(p, (x), 0)
#define setbc_a(p, x) setbc_byte(p, (x), 1)
#define setbc_b(p, x) setbc_byte(p, (x), 3)
#define setbc_c(p, x) setbc_byte(p, (x), 2)
#define setbc_d(p, x) \
((uint16_t *)(p))[LJ_ENDIAN_SELECT(1, 0)] = (uint16_t)(x)
#define setbc_j(p, x) setbc_d(p, (BCPos)((int32_t)(x)+BCBIAS_J))
/* Macros to compose instructions. */
#define BCINS_ABC(o, a, b, c) \
(((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(b)<<24)|((BCIns)(c)<<16))
#define BCINS_AD(o, a, d) \
(((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(d)<<16))
#define BCINS_AJ(o, a, j) BCINS_AD(o, a, (BCPos)((int32_t)(j)+BCBIAS_J))
/* Bytecode instruction definition. Order matters, see below.
**
** (name, filler, Amode, Bmode, Cmode or Dmode, metamethod)
**
** The opcode name suffixes specify the type for RB/RC or RD:
** V = variable slot
** S = string const
** N = number const
** P = primitive type (~itype)
** B = unsigned byte literal
** M = multiple args/results
*/
#define BCDEF(_) \
/* Comparison ops. ORDER OPR. */ \
_(ISLT, var, ___, var, lt) \
_(ISGE, var, ___, var, lt) \
_(ISLE, var, ___, var, le) \
_(ISGT, var, ___, var, le) \
\
_(ISEQV, var, ___, var, eq) \
_(ISNEV, var, ___, var, eq) \
_(ISEQS, var, ___, str, eq) \
_(ISNES, var, ___, str, eq) \
_(ISEQN, var, ___, num, eq) \
_(ISNEN, var, ___, num, eq) \
_(ISEQP, var, ___, pri, eq) \
_(ISNEP, var, ___, pri, eq) \
\
/* Unary test and copy ops. */ \
_(ISTC, dst, ___, var, ___) \
_(ISFC, dst, ___, var, ___) \
_(IST, ___, ___, var, ___) \
_(ISF, ___, ___, var, ___) \
_(ISTYPE, var, ___, lit, ___) \
_(ISNUM, var, ___, lit, ___) \
\
/* Unary ops. */ \
_(MOV, dst, ___, var, ___) \
_(NOT, dst, ___, var, ___) \
_(UNM, dst, ___, var, unm) \
_(LEN, dst, ___, var, len) \
_(BNOT, dst, ___, var, not) \
\
/* Binary ops. ORDER OPR. VV last, POW must be next. */ \
_(ADDVN, dst, var, num, add) \
_(SUBVN, dst, var, num, sub) \
_(MULVN, dst, var, num, mul) \
_(DIVVN, dst, var, num, div) \
_(MODVN, dst, var, num, mod) \
\
_(ADDNV, dst, var, num, add) \
_(SUBNV, dst, var, num, sub) \
_(MULNV, dst, var, num, mul) \
_(DIVNV, dst, var, num, div) \
_(MODNV, dst, var, num, mod) \
\
_(ADDVV, dst, var, var, add) \
_(SUBVV, dst, var, var, sub) \
_(MULVV, dst, var, var, mul) \
_(DIVVV, dst, var, var, div) \
_(MODVV, dst, var, var, mod) \
\
_(POW, dst, var, var, pow) \
_(CAT, dst, rbase, rbase, concat) \
\
/* Bitwise ops. ORDER BITWISE. */ \
_(BANDVN, dst, var, num, and) \
_(BORVN, dst, var, num, or) \
_(BXORVN, dst, var, num, xor) \
_(SHLVN, dst, var, num, shl) \
_(SHRVN, dst, var, num, shr) \
\
_(BANDNV, dst, var, num, and) \
_(BORNV, dst, var, num, or) \
_(BXORNV, dst, var, num, xor) \
_(SHLNV, dst, var, num, shl) \
_(SHRNV, dst, var, num, shr) \
\
_(BANDVV, dst, var, var, and) \
_(BORVV, dst, var, var, or) \
_(BXORVV, dst, var, var, xor) \
_(SHLVV, dst, var, var, shl) \
_(SHRVV, dst, var, var, shr) \
\
/* Constant ops. */ \
_(KSTR, dst, ___, str, ___) \
_(KCDATA, dst, ___, cdata, ___) \
_(KSHORT, dst, ___, lits, ___) \
_(KNUM, dst, ___, num, ___) \
_(KPRI, dst, ___, pri, ___) \
_(KNIL, base, ___, base, ___) \
\
/* Upvalue and function ops. */ \
_(UGET, dst, ___, uv, ___) \
_(USETV, uv, ___, var, ___) \
_(USETS, uv, ___, str, ___) \
_(USETN, uv, ___, num, ___) \
_(USETP, uv, ___, pri, ___) \
_(UCLO, rbase, ___, jump, ___) \
_(FNEW, dst, ___, func, gc) \
\
/* Table ops. */ \
_(TNEW, dst, ___, lit, gc) \
_(TDUP, dst, ___, tab, gc) \
_(GGET, dst, ___, str, index) \
_(GSET, var, ___, str, newindex) \
_(TGETV, dst, var, var, index) \
_(TGETS, dst, var, str, index) \
_(TGETB, dst, var, lit, index) \
_(TGETR, dst, var, var, index) \
_(TSETV, var, var, var, newindex) \
_(TSETS, var, var, str, newindex) \
_(TSETB, var, var, lit, newindex) \
_(TSETM, base, ___, num, newindex) \
_(TSETR, var, var, var, newindex) \
\
/* Calls and vararg handling. T = tail call. */ \
_(CALLM, base, lit, lit, call) \
_(CALL, base, lit, lit, call) \
_(CALLMT, base, ___, lit, call) \
_(CALLT, base, ___, lit, call) \
_(ITERC, base, lit, lit, call) \
_(ITERN, base, lit, lit, call) \
_(VARG, base, lit, lit, ___) \
_(ISNEXT, base, ___, jump, ___) \
\
/* Returns. */ \
_(RETM, base, ___, lit, ___) \
_(RET, rbase, ___, lit, ___) \
_(RET0, rbase, ___, lit, ___) \
_(RET1, rbase, ___, lit, ___) \
\
/* Loops and branches. I/J = interp/JIT, I/C/L = init/call/loop. */ \
_(FORI, base, ___, jump, ___) \
_(JFORI, base, ___, jump, ___) \
\
_(FORL, base, ___, jump, ___) \
_(IFORL, base, ___, jump, ___) \
_(JFORL, base, ___, lit, ___) \
\
_(ITERL, base, ___, jump, ___) \
_(IITERL, base, ___, jump, ___) \
_(JITERL, base, ___, lit, ___) \
\
_(LOOP, rbase, ___, jump, ___) \
_(ILOOP, rbase, ___, jump, ___) \
_(JLOOP, rbase, ___, lit, ___) \
\
_(JMP, rbase, ___, jump, ___) \
\
/* Function headers. I/J = interp/JIT, F/V/C = fixarg/vararg/C func. */ \
_(FUNCF, rbase, ___, ___, ___) \
_(IFUNCF, rbase, ___, ___, ___) \
_(JFUNCF, rbase, ___, lit, ___) \
_(FUNCV, rbase, ___, ___, ___) \
_(IFUNCV, rbase, ___, ___, ___) \
_(JFUNCV, rbase, ___, lit, ___) \
_(FUNCC, rbase, ___, ___, ___) \
_(FUNCCW, rbase, ___, ___, ___)
/* Bytecode opcode numbers. */
typedef enum {
#define BCENUM(name, ma, mb, mc, mt) BC_##name,
BCDEF(BCENUM)
#undef BCENUM
BC__MAX
} BCOp;
LJ_STATIC_ASSERT((int)BC_ISEQV+1 == (int)BC_ISNEV);
LJ_STATIC_ASSERT(((int)BC_ISEQV^1) == (int)BC_ISNEV);
LJ_STATIC_ASSERT(((int)BC_ISEQS^1) == (int)BC_ISNES);
LJ_STATIC_ASSERT(((int)BC_ISEQN^1) == (int)BC_ISNEN);
LJ_STATIC_ASSERT(((int)BC_ISEQP^1) == (int)BC_ISNEP);
LJ_STATIC_ASSERT(((int)BC_ISLT^1) == (int)BC_ISGE);
LJ_STATIC_ASSERT(((int)BC_ISLE^1) == (int)BC_ISGT);
LJ_STATIC_ASSERT(((int)BC_ISLT^3) == (int)BC_ISGT);
LJ_STATIC_ASSERT((int)BC_IST-(int)BC_ISTC == (int)BC_ISF-(int)BC_ISFC);
LJ_STATIC_ASSERT((int)BC_CALLT-(int)BC_CALL == (int)BC_CALLMT-(int)BC_CALLM);
LJ_STATIC_ASSERT((int)BC_CALLMT + 1 == (int)BC_CALLT);
LJ_STATIC_ASSERT((int)BC_RETM + 1 == (int)BC_RET);
LJ_STATIC_ASSERT((int)BC_FORL + 1 == (int)BC_IFORL);
LJ_STATIC_ASSERT((int)BC_FORL + 2 == (int)BC_JFORL);
LJ_STATIC_ASSERT((int)BC_ITERL + 1 == (int)BC_IITERL);
LJ_STATIC_ASSERT((int)BC_ITERL + 2 == (int)BC_JITERL);
LJ_STATIC_ASSERT((int)BC_LOOP + 1 == (int)BC_ILOOP);
LJ_STATIC_ASSERT((int)BC_LOOP + 2 == (int)BC_JLOOP);
LJ_STATIC_ASSERT((int)BC_FUNCF + 1 == (int)BC_IFUNCF);
LJ_STATIC_ASSERT((int)BC_FUNCF + 2 == (int)BC_JFUNCF);
LJ_STATIC_ASSERT((int)BC_FUNCV + 1 == (int)BC_IFUNCV);
LJ_STATIC_ASSERT((int)BC_FUNCV + 2 == (int)BC_JFUNCV);
/* This solves a circular dependency problem, change as needed. */
#define FF_next_N 4
/* Stack slots used by FORI/FORL, relative to operand A. */
enum {
FORL_IDX, FORL_STOP, FORL_STEP, FORL_EXT
};
/* Bytecode operand modes. ORDER BCMode */
typedef enum {
BCMnone, BCMdst, BCMbase, BCMvar, BCMrbase, BCMuv, /* Mode A must be <= 7 */
BCMlit, BCMlits, BCMpri, BCMnum, BCMstr, BCMtab, BCMfunc, BCMjump, BCMcdata,
BCM_max
} BCMode;
#define BCM___ BCMnone
#define bcmode_a(op) ((BCMode)(lj_bc_mode[op] & 7))
#define bcmode_b(op) ((BCMode)((lj_bc_mode[op]>>3) & 15))
#define bcmode_c(op) ((BCMode)((lj_bc_mode[op]>>7) & 15))
#define bcmode_d(op) bcmode_c(op)
#define bcmode_hasd(op) ((lj_bc_mode[op] & (15<<3)) == (BCMnone<<3))
#define bcmode_mm(op) ((MMS)(lj_bc_mode[op]>>11))
#define BCMODE(name, ma, mb, mc, mm) \
(BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)),
#define BCMODE_FF 0
static LJ_AINLINE int bc_isret(BCOp op)
{
return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1);
}
LJ_DATA const uint16_t lj_bc_mode[];
LJ_DATA const uint16_t lj_bc_ofs[];
#endif
+70
View File
@@ -0,0 +1,70 @@
/*
** Bytecode dump definitions.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_BCDUMP_H
#define _LJ_BCDUMP_H
#include "lj_obj.h"
#include "lj_lex.h"
/* -- Bytecode dump format ------------------------------------------------ */
/*
** dump = header proto+ 0U
** header = ESC 'L' 'J' versionB flagsU [namelenU nameB*]
** proto = lengthU pdata
** pdata = phead bcinsW* uvdataH* kgc* knum* [debugB*]
** phead = flagsB numparamsB framesizeB numuvB numkgcU numknU numbcU
** [debuglenU [firstlineU numlineU]]
** kgc = kgctypeU { ktab | (loU hiU) | (rloU rhiU iloU ihiU) | strB* }
** knum = intU0 | (loU1 hiU)
** ktab = narrayU nhashU karray* khash*
** karray = ktabk
** khash = ktabk ktabk
** ktabk = ktabtypeU { intU | (loU hiU) | strB* }
**
** B = 8 bit, H = 16 bit, W = 32 bit, U = ULEB128 of W, U0/U1 = ULEB128 of W+1
*/
/* Bytecode dump header. */
#define BCDUMP_HEAD1 0x1b
#define BCDUMP_HEAD2 0x4c
#define BCDUMP_HEAD3 0x4a
/* If you perform *any* kind of private modifications to the bytecode itself
** or to the dump format, you *must* set BCDUMP_VERSION to 0x80 or higher.
*/
#define BCDUMP_VERSION 2
/* Compatibility flags. */
#define BCDUMP_F_BE 0x01
#define BCDUMP_F_STRIP 0x02
#define BCDUMP_F_FFI 0x04
#define BCDUMP_F_FR2 0x08
#define BCDUMP_F_KNOWN (BCDUMP_F_FR2*2-1)
#define BCDUMP_F_DETERMINISTIC 0x80000000
/* Type codes for the GC constants of a prototype. Plus length for strings. */
enum {
BCDUMP_KGC_CHILD, BCDUMP_KGC_TAB, BCDUMP_KGC_I64, BCDUMP_KGC_U64,
BCDUMP_KGC_COMPLEX, BCDUMP_KGC_STR
};
/* Type codes for the keys/values of a constant table. */
enum {
BCDUMP_KTAB_NIL, BCDUMP_KTAB_FALSE, BCDUMP_KTAB_TRUE,
BCDUMP_KTAB_INT, BCDUMP_KTAB_NUM, BCDUMP_KTAB_STR
};
/* -- Bytecode reader/writer ---------------------------------------------- */
LJ_FUNC int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer,
void *data, uint32_t flags);
LJ_FUNC GCproto *lj_bcread_proto(LexState *ls);
LJ_FUNC GCproto *lj_bcread(LexState *ls);
#endif
+456
View File
@@ -0,0 +1,456 @@
/*
** Bytecode reader.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_bcread_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_bc.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lualib.h"
#endif
#include "lj_lex.h"
#include "lj_bcdump.h"
#include "lj_state.h"
#include "lj_strfmt.h"
/* Reuse some lexer fields for our own purposes. */
#define bcread_flags(ls) ls->level
#define bcread_swap(ls) \
((bcread_flags(ls) & BCDUMP_F_BE) != LJ_BE*BCDUMP_F_BE)
#define bcread_oldtop(L, ls) restorestack(L, ls->lastline)
#define bcread_savetop(L, ls, top) \
ls->lastline = (BCLine)savestack(L, (top))
/* -- Input buffer handling ----------------------------------------------- */
/* Throw reader error. */
static LJ_NOINLINE void bcread_error(LexState *ls, ErrMsg em)
{
lua_State *L = ls->L;
const char *name = ls->chunkarg;
if (*name == BCDUMP_HEAD1) name = "(binary)";
else if (*name == '@' || *name == '=') name++;
lj_strfmt_pushf(L, "%s: %s", name, err2msg(em));
lj_err_throw(L, LUA_ERRSYNTAX);
}
/* Refill buffer. */
static LJ_NOINLINE void bcread_fill(LexState *ls, MSize len, int need)
{
lj_assertLS(len != 0, "empty refill");
if (len > LJ_MAX_BUF || ls->c < 0)
bcread_error(ls, LJ_ERR_BCBAD);
do {
const char *buf;
size_t sz;
char *p = ls->sb.b;
MSize n = (MSize)(ls->pe - ls->p);
if (n) { /* Copy remainder to buffer. */
if (sbuflen(&ls->sb)) { /* Move down in buffer. */
lj_assertLS(ls->pe == ls->sb.w, "bad buffer pointer");
if (ls->p != p) memmove(p, ls->p, n);
} else { /* Copy from buffer provided by reader. */
p = lj_buf_need(&ls->sb, len);
memcpy(p, ls->p, n);
}
ls->p = p;
ls->pe = p + n;
}
ls->sb.w = p + n;
buf = ls->rfunc(ls->L, ls->rdata, &sz); /* Get more data from reader. */
if (buf == NULL || sz == 0) { /* EOF? */
if (need) bcread_error(ls, LJ_ERR_BCBAD);
ls->c = -1; /* Only bad if we get called again. */
break;
}
if (sz >= LJ_MAX_BUF - n) lj_err_mem(ls->L);
if (n) { /* Append to buffer. */
n += (MSize)sz;
p = lj_buf_need(&ls->sb, n < len ? len : n);
memcpy(ls->sb.w, buf, sz);
ls->sb.w = p + n;
ls->p = p;
ls->pe = p + n;
} else { /* Return buffer provided by reader. */
ls->p = buf;
ls->pe = buf + sz;
}
} while ((MSize)(ls->pe - ls->p) < len);
}
/* Need a certain number of bytes. */
static LJ_AINLINE void bcread_need(LexState *ls, MSize len)
{
if (LJ_UNLIKELY((MSize)(ls->pe - ls->p) < len))
bcread_fill(ls, len, 1);
}
/* Want to read up to a certain number of bytes, but may need less. */
static LJ_AINLINE void bcread_want(LexState *ls, MSize len)
{
if (LJ_UNLIKELY((MSize)(ls->pe - ls->p) < len))
bcread_fill(ls, len, 0);
}
/* Return memory block from buffer. */
static LJ_AINLINE uint8_t *bcread_mem(LexState *ls, MSize len)
{
uint8_t *p = (uint8_t *)ls->p;
ls->p += len;
lj_assertLS(ls->p <= ls->pe, "buffer read overflow");
return p;
}
/* Copy memory block from buffer. */
static void bcread_block(LexState *ls, void *q, MSize len)
{
memcpy(q, bcread_mem(ls, len), len);
}
/* Read byte from buffer. */
static LJ_AINLINE uint32_t bcread_byte(LexState *ls)
{
lj_assertLS(ls->p < ls->pe, "buffer read overflow");
return (uint32_t)(uint8_t)*ls->p++;
}
/* Read ULEB128 value from buffer. */
static LJ_AINLINE uint32_t bcread_uleb128(LexState *ls)
{
uint32_t v = lj_buf_ruleb128(&ls->p);
lj_assertLS(ls->p <= ls->pe, "buffer read overflow");
return v;
}
/* Read top 32 bits of 33 bit ULEB128 value from buffer. */
static uint32_t bcread_uleb128_33(LexState *ls)
{
const uint8_t *p = (const uint8_t *)ls->p;
uint32_t v = (*p++ >> 1);
if (LJ_UNLIKELY(v >= 0x40)) {
int sh = -1;
v &= 0x3f;
do {
v |= ((*p & 0x7f) << (sh += 7));
} while (*p++ >= 0x80);
}
ls->p = (char *)p;
lj_assertLS(ls->p <= ls->pe, "buffer read overflow");
return v;
}
/* -- Bytecode reader ----------------------------------------------------- */
/* Read debug info of a prototype. */
static void bcread_dbg(LexState *ls, GCproto *pt, MSize sizedbg)
{
void *lineinfo = (void *)proto_lineinfo(pt);
bcread_block(ls, lineinfo, sizedbg);
/* Swap lineinfo if the endianess differs. */
if (bcread_swap(ls) && pt->numline >= 256) {
MSize i, n = pt->sizebc-1;
if (pt->numline < 65536) {
uint16_t *p = (uint16_t *)lineinfo;
for (i = 0; i < n; i++) p[i] = (uint16_t)((p[i] >> 8)|(p[i] << 8));
} else {
uint32_t *p = (uint32_t *)lineinfo;
for (i = 0; i < n; i++) p[i] = lj_bswap(p[i]);
}
}
}
/* Find pointer to varinfo. */
static const void *bcread_varinfo(GCproto *pt)
{
const uint8_t *p = proto_uvinfo(pt);
MSize n = pt->sizeuv;
if (n) while (*p++ || --n) ;
return p;
}
/* Read a single constant key/value of a template table. */
static void bcread_ktabk(LexState *ls, TValue *o)
{
MSize tp = bcread_uleb128(ls);
if (tp >= BCDUMP_KTAB_STR) {
MSize len = tp - BCDUMP_KTAB_STR;
const char *p = (const char *)bcread_mem(ls, len);
setstrV(ls->L, o, lj_str_new(ls->L, p, len));
} else if (tp == BCDUMP_KTAB_INT) {
setintV(o, (int32_t)bcread_uleb128(ls));
} else if (tp == BCDUMP_KTAB_NUM) {
o->u32.lo = bcread_uleb128(ls);
o->u32.hi = bcread_uleb128(ls);
} else {
lj_assertLS(tp <= BCDUMP_KTAB_TRUE, "bad constant type %d", tp);
setpriV(o, ~tp);
}
}
/* Read a template table. */
static GCtab *bcread_ktab(LexState *ls)
{
MSize narray = bcread_uleb128(ls);
MSize nhash = bcread_uleb128(ls);
GCtab *t = lj_tab_new(ls->L, narray, hsize2hbits(nhash));
if (narray) { /* Read array entries. */
MSize i;
TValue *o = tvref(t->array);
for (i = 0; i < narray; i++, o++)
bcread_ktabk(ls, o);
}
if (nhash) { /* Read hash entries. */
MSize i;
for (i = 0; i < nhash; i++) {
TValue key;
bcread_ktabk(ls, &key);
lj_assertLS(!tvisnil(&key), "nil key");
bcread_ktabk(ls, lj_tab_set(ls->L, t, &key));
}
}
return t;
}
/* Read GC constants of a prototype. */
static void bcread_kgc(LexState *ls, GCproto *pt, MSize sizekgc)
{
MSize i;
GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc;
for (i = 0; i < sizekgc; i++, kr++) {
MSize tp = bcread_uleb128(ls);
if (tp >= BCDUMP_KGC_STR) {
MSize len = tp - BCDUMP_KGC_STR;
const char *p = (const char *)bcread_mem(ls, len);
setgcref(*kr, obj2gco(lj_str_new(ls->L, p, len)));
} else if (tp == BCDUMP_KGC_TAB) {
setgcref(*kr, obj2gco(bcread_ktab(ls)));
#if LJ_HASFFI
} else if (tp != BCDUMP_KGC_CHILD) {
CTypeID id = tp == BCDUMP_KGC_COMPLEX ? CTID_COMPLEX_DOUBLE :
tp == BCDUMP_KGC_I64 ? CTID_INT64 : CTID_UINT64;
CTSize sz = tp == BCDUMP_KGC_COMPLEX ? 16 : 8;
GCcdata *cd = lj_cdata_new_(ls->L, id, sz);
TValue *p = (TValue *)cdataptr(cd);
setgcref(*kr, obj2gco(cd));
p[0].u32.lo = bcread_uleb128(ls);
p[0].u32.hi = bcread_uleb128(ls);
if (tp == BCDUMP_KGC_COMPLEX) {
p[1].u32.lo = bcread_uleb128(ls);
p[1].u32.hi = bcread_uleb128(ls);
}
#endif
} else {
lua_State *L = ls->L;
lj_assertLS(tp == BCDUMP_KGC_CHILD, "bad constant type %d", tp);
if (L->top <= bcread_oldtop(L, ls)) /* Stack underflow? */
bcread_error(ls, LJ_ERR_BCBAD);
L->top--;
setgcref(*kr, obj2gco(protoV(L->top)));
}
}
}
/* Read number constants of a prototype. */
static void bcread_knum(LexState *ls, GCproto *pt, MSize sizekn)
{
MSize i;
TValue *o = mref(pt->k, TValue);
for (i = 0; i < sizekn; i++, o++) {
int isnum = (ls->p[0] & 1);
uint32_t lo = bcread_uleb128_33(ls);
if (isnum) {
o->u32.lo = lo;
o->u32.hi = bcread_uleb128(ls);
} else {
setintV(o, lo);
}
}
}
/* Read bytecode instructions. */
static void bcread_bytecode(LexState *ls, GCproto *pt, MSize sizebc)
{
BCIns *bc = proto_bc(pt);
BCIns op;
if (ls->fr2 != LJ_FR2) op = BC_NOT; /* Mark non-native prototype. */
else if ((pt->flags & PROTO_VARARG)) op = BC_FUNCV;
else op = BC_FUNCF;
bc[0] = BCINS_AD(op, pt->framesize, 0);
bcread_block(ls, bc+1, (sizebc-1)*(MSize)sizeof(BCIns));
/* Swap bytecode instructions if the endianess differs. */
if (bcread_swap(ls)) {
MSize i;
for (i = 1; i < sizebc; i++) bc[i] = lj_bswap(bc[i]);
}
}
/* Read upvalue refs. */
static void bcread_uv(LexState *ls, GCproto *pt, MSize sizeuv)
{
if (sizeuv) {
uint16_t *uv = proto_uv(pt);
bcread_block(ls, uv, sizeuv*2);
/* Swap upvalue refs if the endianess differs. */
if (bcread_swap(ls)) {
MSize i;
for (i = 0; i < sizeuv; i++)
uv[i] = (uint16_t)((uv[i] >> 8)|(uv[i] << 8));
}
}
}
/* Read a prototype. */
GCproto *lj_bcread_proto(LexState *ls)
{
GCproto *pt;
MSize framesize, numparams, flags, sizeuv, sizekgc, sizekn, sizebc, sizept;
MSize ofsk, ofsuv, ofsdbg;
MSize sizedbg = 0;
BCLine firstline = 0, numline = 0;
/* Read prototype header. */
flags = bcread_byte(ls);
numparams = bcread_byte(ls);
framesize = bcread_byte(ls);
sizeuv = bcread_byte(ls);
sizekgc = bcread_uleb128(ls);
sizekn = bcread_uleb128(ls);
sizebc = bcread_uleb128(ls) + 1;
if (!(bcread_flags(ls) & BCDUMP_F_STRIP)) {
sizedbg = bcread_uleb128(ls);
if (sizedbg) {
firstline = bcread_uleb128(ls);
numline = bcread_uleb128(ls);
}
}
/* Calculate total size of prototype including all colocated arrays. */
sizept = (MSize)sizeof(GCproto) +
sizebc*(MSize)sizeof(BCIns) +
sizekgc*(MSize)sizeof(GCRef);
sizept = (sizept + (MSize)sizeof(TValue)-1) & ~((MSize)sizeof(TValue)-1);
ofsk = sizept; sizept += sizekn*(MSize)sizeof(TValue);
ofsuv = sizept; sizept += ((sizeuv+1)&~1)*2;
ofsdbg = sizept; sizept += sizedbg;
/* Allocate prototype object and initialize its fields. */
pt = (GCproto *)lj_mem_newgco(ls->L, (MSize)sizept);
pt->gct = ~LJ_TPROTO;
pt->numparams = (uint8_t)numparams;
pt->framesize = (uint8_t)framesize;
pt->sizebc = sizebc;
setmref(pt->k, (char *)pt + ofsk);
setmref(pt->uv, (char *)pt + ofsuv);
pt->sizekgc = 0; /* Set to zero until fully initialized. */
pt->sizekn = sizekn;
pt->sizept = sizept;
pt->sizeuv = (uint8_t)sizeuv;
pt->flags = (uint8_t)flags;
pt->trace = 0;
setgcref(pt->chunkname, obj2gco(ls->chunkname));
/* Close potentially uninitialized gap between bc and kgc. */
*(uint32_t *)((char *)pt + ofsk - sizeof(GCRef)*(sizekgc+1)) = 0;
/* Read bytecode instructions and upvalue refs. */
bcread_bytecode(ls, pt, sizebc);
bcread_uv(ls, pt, sizeuv);
/* Read constants. */
bcread_kgc(ls, pt, sizekgc);
pt->sizekgc = sizekgc;
bcread_knum(ls, pt, sizekn);
/* Read and initialize debug info. */
pt->firstline = firstline;
pt->numline = numline;
if (sizedbg) {
MSize sizeli = (sizebc-1) << (numline < 256 ? 0 : numline < 65536 ? 1 : 2);
setmref(pt->lineinfo, (char *)pt + ofsdbg);
setmref(pt->uvinfo, (char *)pt + ofsdbg + sizeli);
bcread_dbg(ls, pt, sizedbg);
setmref(pt->varinfo, bcread_varinfo(pt));
} else {
setmref(pt->lineinfo, NULL);
setmref(pt->uvinfo, NULL);
setmref(pt->varinfo, NULL);
}
return pt;
}
/* Read and check header of bytecode dump. */
static int bcread_header(LexState *ls)
{
uint32_t flags;
bcread_want(ls, 3+5+5);
if (bcread_byte(ls) != BCDUMP_HEAD2 ||
bcread_byte(ls) != BCDUMP_HEAD3 ||
bcread_byte(ls) != BCDUMP_VERSION) return 0;
bcread_flags(ls) = flags = bcread_uleb128(ls);
if ((flags & ~(BCDUMP_F_KNOWN)) != 0) return 0;
if ((flags & BCDUMP_F_FR2) != (uint32_t)ls->fr2*BCDUMP_F_FR2) return 0;
if ((flags & BCDUMP_F_FFI)) {
#if LJ_HASFFI
lua_State *L = ls->L;
ctype_loadffi(L);
#else
return 0;
#endif
}
if ((flags & BCDUMP_F_STRIP)) {
ls->chunkname = lj_str_newz(ls->L, *ls->chunkarg == BCDUMP_HEAD1 ? "=?" : ls->chunkarg);
} else {
MSize len = bcread_uleb128(ls);
bcread_need(ls, len);
ls->chunkname = lj_str_new(ls->L, (const char *)bcread_mem(ls, len), len);
}
return 1; /* Ok. */
}
/* Read a bytecode dump. */
GCproto *lj_bcread(LexState *ls)
{
lua_State *L = ls->L;
lj_assertLS(ls->c == BCDUMP_HEAD1, "bad bytecode header");
bcread_savetop(L, ls, L->top);
lj_buf_reset(&ls->sb);
/* Check for a valid bytecode dump header. */
if (!bcread_header(ls))
bcread_error(ls, LJ_ERR_BCFMT);
for (;;) { /* Process all prototypes in the bytecode dump. */
GCproto *pt;
MSize len;
const char *startp;
/* Read length. */
if (ls->p < ls->pe && ls->p[0] == 0) { /* Shortcut EOF. */
ls->p++;
break;
}
bcread_want(ls, 5);
len = bcread_uleb128(ls);
if (!len) break; /* EOF */
bcread_need(ls, len);
startp = ls->p;
pt = lj_bcread_proto(ls);
if (ls->p != startp + len)
bcread_error(ls, LJ_ERR_BCBAD);
setprotoV(L, L->top, pt);
incr_top(L);
}
if ((ls->pe != ls->p && !ls->endmark) || L->top-1 != bcread_oldtop(L, ls))
bcread_error(ls, LJ_ERR_BCBAD);
/* Pop off last prototype. */
L->top--;
return protoV(L->top);
}
+452
View File
@@ -0,0 +1,452 @@
/*
** Bytecode writer.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_bcwrite_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_buf.h"
#include "lj_bc.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#endif
#if LJ_HASJIT
#include "lj_dispatch.h"
#include "lj_jit.h"
#endif
#include "lj_strfmt.h"
#include "lj_bcdump.h"
#include "lj_vm.h"
/* Context for bytecode writer. */
typedef struct BCWriteCtx {
SBuf sb; /* Output buffer. */
GCproto *pt; /* Root prototype. */
lua_Writer wfunc; /* Writer callback. */
void *wdata; /* Writer callback data. */
TValue **heap; /* Heap used for deterministic sorting. */
uint32_t heapsz; /* Size of heap. */
uint32_t flags; /* BCDUMP_F_* flags. */
int status; /* Status from writer callback. */
#ifdef LUA_USE_ASSERT
global_State *g;
#endif
} BCWriteCtx;
#ifdef LUA_USE_ASSERT
#define lj_assertBCW(c, ...) lj_assertG_(ctx->g, (c), __VA_ARGS__)
#else
#define lj_assertBCW(c, ...) ((void)ctx)
#endif
/* -- Bytecode writer ----------------------------------------------------- */
/* Write a single constant key/value of a template table. */
static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow)
{
char *p = lj_buf_more(&ctx->sb, 1+10);
if (tvisstr(o)) {
const GCstr *str = strV(o);
MSize len = str->len;
p = lj_buf_more(&ctx->sb, 5+len);
p = lj_strfmt_wuleb128(p, BCDUMP_KTAB_STR+len);
p = lj_buf_wmem(p, strdata(str), len);
} else if (tvisint(o)) {
*p++ = BCDUMP_KTAB_INT;
p = lj_strfmt_wuleb128(p, intV(o));
} else if (tvisnum(o)) {
if (!LJ_DUALNUM && narrow) { /* Narrow number constants to integers. */
lua_Number num = numV(o);
int32_t k = lj_num2int(num);
if (num == (lua_Number)k) { /* -0 is never a constant. */
*p++ = BCDUMP_KTAB_INT;
p = lj_strfmt_wuleb128(p, k);
ctx->sb.w = p;
return;
}
}
*p++ = BCDUMP_KTAB_NUM;
p = lj_strfmt_wuleb128(p, o->u32.lo);
p = lj_strfmt_wuleb128(p, o->u32.hi);
} else {
lj_assertBCW(tvispri(o), "unhandled type %d", itype(o));
*p++ = BCDUMP_KTAB_NIL+~itype(o);
}
ctx->sb.w = p;
}
/* Compare two template table keys. */
static LJ_AINLINE int bcwrite_ktabk_lt(TValue *a, TValue *b)
{
uint32_t at = itype(a), bt = itype(b);
if (at != bt) { /* This also handles false and true keys. */
return at < bt;
} else if (at == LJ_TSTR) {
return lj_str_cmp(strV(a), strV(b)) < 0;
} else {
return a->u64 < b->u64; /* This works for numbers and integers. */
}
}
/* Insert key into a sorted heap. */
static void bcwrite_ktabk_heap_insert(TValue **heap, MSize idx, MSize end,
TValue *key)
{
MSize child;
while ((child = idx * 2 + 1) < end) {
/* Find lower of the two children. */
TValue *c0 = heap[child];
if (child + 1 < end) {
TValue *c1 = heap[child + 1];
if (bcwrite_ktabk_lt(c1, c0)) {
c0 = c1;
child++;
}
}
if (bcwrite_ktabk_lt(key, c0)) break; /* Key lower? Found our position. */
heap[idx] = c0; /* Move lower child up. */
idx = child; /* Descend. */
}
heap[idx] = key; /* Insert key here. */
}
/* Resize heap, dropping content. */
static void bcwrite_heap_resize(BCWriteCtx *ctx, uint32_t nsz)
{
lua_State *L = sbufL(&ctx->sb);
if (ctx->heapsz) {
lj_mem_freevec(G(L), ctx->heap, ctx->heapsz, TValue *);
ctx->heapsz = 0;
}
if (nsz) {
ctx->heap = lj_mem_newvec(L, nsz, TValue *);
ctx->heapsz = nsz;
}
}
/* Write hash part of template table in sorted order. */
static void bcwrite_ktab_sorted_hash(BCWriteCtx *ctx, Node *node, MSize nhash)
{
TValue **heap = ctx->heap;
MSize i = nhash;
for (;; node--) { /* Build heap. */
if (!tvisnil(&node->key)) {
bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key);
if (i == 0) break;
}
}
do { /* Drain heap. */
TValue *key = heap[0]; /* Output lowest key from top. */
bcwrite_ktabk(ctx, key, 0);
bcwrite_ktabk(ctx, (TValue *)((char *)key - offsetof(Node, key)), 1);
key = heap[--nhash]; /* Remove last key. */
bcwrite_ktabk_heap_insert(heap, 0, nhash, key); /* Re-insert. */
} while (nhash);
}
/* Write a template table. */
static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t)
{
MSize narray = 0, nhash = 0;
if (t->asize > 0) { /* Determine max. length of array part. */
ptrdiff_t i;
TValue *array = tvref(t->array);
for (i = (ptrdiff_t)t->asize-1; i >= 0; i--)
if (!tvisnil(&array[i]))
break;
narray = (MSize)(i+1);
}
if (t->hmask > 0) { /* Count number of used hash slots. */
MSize i, hmask = t->hmask;
Node *node = noderef(t->node);
for (i = 0; i <= hmask; i++)
nhash += !tvisnil(&node[i].key);
}
/* Write number of array slots and hash slots. */
p = lj_strfmt_wuleb128(p, narray);
p = lj_strfmt_wuleb128(p, nhash);
ctx->sb.w = p;
if (narray) { /* Write array entries (may contain nil). */
MSize i;
TValue *o = tvref(t->array);
for (i = 0; i < narray; i++, o++)
bcwrite_ktabk(ctx, o, 1);
}
if (nhash) { /* Write hash entries. */
Node *node = noderef(t->node) + t->hmask;
if ((ctx->flags & BCDUMP_F_DETERMINISTIC) && nhash > 1) {
if (ctx->heapsz < nhash)
bcwrite_heap_resize(ctx, t->hmask + 1);
bcwrite_ktab_sorted_hash(ctx, node, nhash);
} else {
MSize i = nhash;
for (;; node--)
if (!tvisnil(&node->key)) {
bcwrite_ktabk(ctx, &node->key, 0);
bcwrite_ktabk(ctx, &node->val, 1);
if (--i == 0) break;
}
}
}
}
/* Write GC constants of a prototype. */
static void bcwrite_kgc(BCWriteCtx *ctx, GCproto *pt)
{
MSize i, sizekgc = pt->sizekgc;
GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc;
for (i = 0; i < sizekgc; i++, kr++) {
GCobj *o = gcref(*kr);
MSize tp, need = 1;
char *p;
/* Determine constant type and needed size. */
if (o->gch.gct == ~LJ_TSTR) {
tp = BCDUMP_KGC_STR + gco2str(o)->len;
need = 5+gco2str(o)->len;
} else if (o->gch.gct == ~LJ_TPROTO) {
lj_assertBCW((pt->flags & PROTO_CHILD), "prototype has unexpected child");
tp = BCDUMP_KGC_CHILD;
#if LJ_HASFFI
} else if (o->gch.gct == ~LJ_TCDATA) {
CTypeID id = gco2cd(o)->ctypeid;
need = 1+4*5;
if (id == CTID_INT64) {
tp = BCDUMP_KGC_I64;
} else if (id == CTID_UINT64) {
tp = BCDUMP_KGC_U64;
} else {
lj_assertBCW(id == CTID_COMPLEX_DOUBLE,
"bad cdata constant CTID %d", id);
tp = BCDUMP_KGC_COMPLEX;
}
#endif
} else {
lj_assertBCW(o->gch.gct == ~LJ_TTAB,
"bad constant GC type %d", o->gch.gct);
tp = BCDUMP_KGC_TAB;
need = 1+2*5;
}
/* Write constant type. */
p = lj_buf_more(&ctx->sb, need);
p = lj_strfmt_wuleb128(p, tp);
/* Write constant data (if any). */
if (tp >= BCDUMP_KGC_STR) {
p = lj_buf_wmem(p, strdata(gco2str(o)), gco2str(o)->len);
} else if (tp == BCDUMP_KGC_TAB) {
bcwrite_ktab(ctx, p, gco2tab(o));
continue;
#if LJ_HASFFI
} else if (tp != BCDUMP_KGC_CHILD) {
cTValue *q = (TValue *)cdataptr(gco2cd(o));
p = lj_strfmt_wuleb128(p, q[0].u32.lo);
p = lj_strfmt_wuleb128(p, q[0].u32.hi);
if (tp == BCDUMP_KGC_COMPLEX) {
p = lj_strfmt_wuleb128(p, q[1].u32.lo);
p = lj_strfmt_wuleb128(p, q[1].u32.hi);
}
#endif
}
ctx->sb.w = p;
}
}
/* Write number constants of a prototype. */
static void bcwrite_knum(BCWriteCtx *ctx, GCproto *pt)
{
MSize i, sizekn = pt->sizekn;
cTValue *o = mref(pt->k, TValue);
char *p = lj_buf_more(&ctx->sb, 10*sizekn);
for (i = 0; i < sizekn; i++, o++) {
int32_t k;
if (tvisint(o)) {
k = intV(o);
goto save_int;
} else {
/* Write a 33 bit ULEB128 for the int (lsb=0) or loword (lsb=1). */
if (!LJ_DUALNUM && o->u32.hi != LJ_KEYINDEX) {
/* Narrow number constants to integers. */
lua_Number num = numV(o);
k = lj_num2int(num);
if (num == (lua_Number)k) { /* -0 is never a constant. */
save_int:
p = lj_strfmt_wuleb128(p, 2*(uint32_t)k | ((uint32_t)k&0x80000000u));
if (k < 0)
p[-1] = (p[-1] & 7) | ((k>>27) & 0x18);
continue;
}
}
p = lj_strfmt_wuleb128(p, 1+(2*o->u32.lo | (o->u32.lo & 0x80000000u)));
if (o->u32.lo >= 0x80000000u)
p[-1] = (p[-1] & 7) | ((o->u32.lo>>27) & 0x18);
p = lj_strfmt_wuleb128(p, o->u32.hi);
}
}
ctx->sb.w = p;
}
/* Write bytecode instructions. */
static char *bcwrite_bytecode(BCWriteCtx *ctx, char *p, GCproto *pt)
{
MSize nbc = pt->sizebc-1; /* Omit the [JI]FUNC* header. */
#if LJ_HASJIT
uint8_t *q = (uint8_t *)p;
#endif
p = lj_buf_wmem(p, proto_bc(pt)+1, nbc*(MSize)sizeof(BCIns));
UNUSED(ctx);
#if LJ_HASJIT
/* Unpatch modified bytecode containing ILOOP/JLOOP etc. */
if ((pt->flags & PROTO_ILOOP) || pt->trace) {
jit_State *J = L2J(sbufL(&ctx->sb));
MSize i;
for (i = 0; i < nbc; i++, q += sizeof(BCIns)) {
BCOp op = (BCOp)q[LJ_ENDIAN_SELECT(0, 3)];
if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP ||
op == BC_JFORI) {
q[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_IFORL+BC_FORL);
} else if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) {
BCReg rd = q[LJ_ENDIAN_SELECT(2, 1)] + (q[LJ_ENDIAN_SELECT(3, 0)] << 8);
memcpy(q, &traceref(J, rd)->startins, 4);
}
}
}
#endif
return p;
}
/* Write prototype. */
static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt)
{
MSize sizedbg = 0;
char *p;
/* Recursively write children of prototype. */
if ((pt->flags & PROTO_CHILD)) {
ptrdiff_t i, n = pt->sizekgc;
GCRef *kr = mref(pt->k, GCRef) - 1;
for (i = 0; i < n; i++, kr--) {
GCobj *o = gcref(*kr);
if (o->gch.gct == ~LJ_TPROTO)
bcwrite_proto(ctx, gco2pt(o));
}
}
/* Start writing the prototype info to a buffer. */
p = lj_buf_need(&ctx->sb,
5+4+6*5+(pt->sizebc-1)*(MSize)sizeof(BCIns)+pt->sizeuv*2);
p += 5; /* Leave room for final size. */
/* Write prototype header. */
*p++ = (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI));
*p++ = pt->numparams;
*p++ = pt->framesize;
*p++ = pt->sizeuv;
p = lj_strfmt_wuleb128(p, pt->sizekgc);
p = lj_strfmt_wuleb128(p, pt->sizekn);
p = lj_strfmt_wuleb128(p, pt->sizebc-1);
if (!(ctx->flags & BCDUMP_F_STRIP)) {
if (proto_lineinfo(pt))
sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt);
p = lj_strfmt_wuleb128(p, sizedbg);
if (sizedbg) {
p = lj_strfmt_wuleb128(p, pt->firstline);
p = lj_strfmt_wuleb128(p, pt->numline);
}
}
/* Write bytecode instructions and upvalue refs. */
p = bcwrite_bytecode(ctx, p, pt);
p = lj_buf_wmem(p, proto_uv(pt), pt->sizeuv*2);
ctx->sb.w = p;
/* Write constants. */
bcwrite_kgc(ctx, pt);
bcwrite_knum(ctx, pt);
/* Write debug info, if not stripped. */
if (sizedbg) {
p = lj_buf_more(&ctx->sb, sizedbg);
p = lj_buf_wmem(p, proto_lineinfo(pt), sizedbg);
ctx->sb.w = p;
}
/* Pass buffer to writer function. */
if (ctx->status == 0) {
MSize n = sbuflen(&ctx->sb) - 5;
MSize nn = (lj_fls(n)+8)*9 >> 6;
char *q = ctx->sb.b + (5 - nn);
p = lj_strfmt_wuleb128(q, n); /* Fill in final size. */
lj_assertBCW(p == ctx->sb.b + 5, "bad ULEB128 write");
ctx->status = ctx->wfunc(sbufL(&ctx->sb), q, nn+n, ctx->wdata);
}
}
/* Write header of bytecode dump. */
static void bcwrite_header(BCWriteCtx *ctx)
{
GCstr *chunkname = proto_chunkname(ctx->pt);
const char *name = strdata(chunkname);
MSize len = chunkname->len;
char *p = lj_buf_need(&ctx->sb, 5+5+len);
*p++ = BCDUMP_HEAD1;
*p++ = BCDUMP_HEAD2;
*p++ = BCDUMP_HEAD3;
*p++ = BCDUMP_VERSION;
*p++ = (ctx->flags & (BCDUMP_F_STRIP | BCDUMP_F_FR2)) +
LJ_BE*BCDUMP_F_BE +
((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0);
if (!(ctx->flags & BCDUMP_F_STRIP)) {
p = lj_strfmt_wuleb128(p, len);
p = lj_buf_wmem(p, name, len);
}
ctx->status = ctx->wfunc(sbufL(&ctx->sb), ctx->sb.b,
(MSize)(p - ctx->sb.b), ctx->wdata);
}
/* Write footer of bytecode dump. */
static void bcwrite_footer(BCWriteCtx *ctx)
{
if (ctx->status == 0) {
uint8_t zero = 0;
ctx->status = ctx->wfunc(sbufL(&ctx->sb), &zero, 1, ctx->wdata);
}
}
/* Protected callback for bytecode writer. */
static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud)
{
BCWriteCtx *ctx = (BCWriteCtx *)ud;
UNUSED(L); UNUSED(dummy);
lj_buf_need(&ctx->sb, 1024); /* Avoids resize for most prototypes. */
bcwrite_header(ctx);
bcwrite_proto(ctx, ctx->pt);
bcwrite_footer(ctx);
return NULL;
}
/* Write bytecode for a prototype. */
int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data,
uint32_t flags)
{
BCWriteCtx ctx;
int status;
ctx.pt = pt;
ctx.wfunc = writer;
ctx.wdata = data;
ctx.heapsz = 0;
if ((bc_op(proto_bc(pt)[0]) != BC_NOT) == LJ_FR2) flags |= BCDUMP_F_FR2;
ctx.flags = flags;
ctx.status = 0;
#ifdef LUA_USE_ASSERT
ctx.g = G(L);
#endif
lj_buf_init(L, &ctx.sb);
status = lj_vm_cpcall(L, NULL, &ctx, cpwriter);
if (status == 0) status = ctx.status;
lj_buf_free(G(sbufL(&ctx.sb)), &ctx.sb);
bcwrite_heap_resize(&ctx, 0);
return status;
}
+303
View File
@@ -0,0 +1,303 @@
/*
** Buffer handling.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#define lj_buf_c
#define LUA_CORE
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_strfmt.h"
/* -- Buffer management --------------------------------------------------- */
static void buf_grow(SBuf *sb, MSize sz)
{
MSize osz = sbufsz(sb), len = sbuflen(sb), nsz = osz;
char *b;
GCSize flag;
if (nsz < LJ_MIN_SBUF) nsz = LJ_MIN_SBUF;
while (nsz < sz) nsz += nsz;
flag = sbufflag(sb);
if ((flag & SBUF_FLAG_COW)) { /* Copy-on-write semantics. */
lj_assertG_(G(sbufL(sb)), sb->w == sb->e, "bad SBuf COW");
b = (char *)lj_mem_new(sbufL(sb), nsz);
setsbufflag(sb, flag & ~(GCSize)SBUF_FLAG_COW);
setgcrefnull(sbufX(sb)->cowref);
memcpy(b, sb->b, osz);
} else {
b = (char *)lj_mem_realloc(sbufL(sb), sb->b, osz, nsz);
}
if ((flag & SBUF_FLAG_EXT)) {
sbufX(sb)->r = sbufX(sb)->r - sb->b + b; /* Adjust read pointer, too. */
}
/* Adjust buffer pointers. */
sb->b = b;
sb->w = b + len;
sb->e = b + nsz;
if ((flag & SBUF_FLAG_BORROW)) { /* Adjust borrowed buffer pointers. */
SBuf *bsb = mref(sbufX(sb)->bsb, SBuf);
bsb->b = b;
bsb->w = b + len;
bsb->e = b + nsz;
}
}
LJ_NOINLINE char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz)
{
lj_assertG_(G(sbufL(sb)), sz > sbufsz(sb), "SBuf overflow");
if (LJ_UNLIKELY(sz > LJ_MAX_BUF))
lj_err_mem(sbufL(sb));
buf_grow(sb, sz);
return sb->b;
}
LJ_NOINLINE char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz)
{
if (sbufisext(sb)) {
SBufExt *sbx = (SBufExt *)sb;
MSize len = sbufxlen(sbx);
if (LJ_UNLIKELY(sz > LJ_MAX_BUF || len + sz > LJ_MAX_BUF))
lj_err_mem(sbufL(sbx));
if (len + sz > sbufsz(sbx)) { /* Must grow. */
buf_grow((SBuf *)sbx, len + sz);
} else if (sbufiscow(sb) || sbufxslack(sbx) < (sbufsz(sbx) >> 3)) {
/* Also grow to avoid excessive compactions, if slack < size/8. */
buf_grow((SBuf *)sbx, sbuflen(sbx) + sz); /* Not sbufxlen! */
return sbx->w;
}
if (sbx->r != sbx->b) { /* Compact by moving down. */
memmove(sbx->b, sbx->r, len);
sbx->r = sbx->b;
sbx->w = sbx->b + len;
lj_assertG_(G(sbufL(sbx)), len + sz <= sbufsz(sbx), "bad SBuf compact");
}
} else {
MSize len = sbuflen(sb);
lj_assertG_(G(sbufL(sb)), sz > sbufleft(sb), "SBuf overflow");
if (LJ_UNLIKELY(sz > LJ_MAX_BUF || len + sz > LJ_MAX_BUF))
lj_err_mem(sbufL(sb));
buf_grow(sb, len + sz);
}
return sb->w;
}
void LJ_FASTCALL lj_buf_shrink(lua_State *L, SBuf *sb)
{
char *b = sb->b;
MSize osz = (MSize)(sb->e - b);
if (osz > 2*LJ_MIN_SBUF) {
b = lj_mem_realloc(L, b, osz, (osz >> 1));
sb->w = sb->b = b; /* Not supposed to keep data across shrinks. */
sb->e = b + (osz >> 1);
}
lj_assertG_(G(sbufL(sb)), !sbufisext(sb), "YAGNI shrink SBufExt");
}
char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz)
{
SBuf *sb = &G(L)->tmpbuf;
setsbufL(sb, L);
return lj_buf_need(sb, sz);
}
#if LJ_HASBUFFER && LJ_HASJIT
void lj_bufx_set(SBufExt *sbx, const char *p, MSize len, GCobj *ref)
{
lua_State *L = sbufL(sbx);
lj_bufx_free(L, sbx);
lj_bufx_set_cow(L, sbx, p, len);
setgcref(sbx->cowref, ref);
lj_gc_objbarrier(L, (GCudata *)sbx - 1, ref);
}
#if LJ_HASFFI
MSize LJ_FASTCALL lj_bufx_more(SBufExt *sbx, MSize sz)
{
lj_buf_more((SBuf *)sbx, sz);
return sbufleft(sbx);
}
#endif
#endif
/* -- Low-level buffer put operations ------------------------------------- */
SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len)
{
char *w = lj_buf_more(sb, len);
w = lj_buf_wmem(w, q, len);
sb->w = w;
return sb;
}
#if LJ_HASJIT || LJ_HASFFI
static LJ_NOINLINE SBuf * LJ_FASTCALL lj_buf_putchar2(SBuf *sb, int c)
{
char *w = lj_buf_more2(sb, 1);
*w++ = (char)c;
sb->w = w;
return sb;
}
SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c)
{
char *w = sb->w;
if (LJ_LIKELY(w < sb->e)) {
*w++ = (char)c;
sb->w = w;
return sb;
}
return lj_buf_putchar2(sb, c);
}
#endif
SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s)
{
MSize len = s->len;
char *w = lj_buf_more(sb, len);
w = lj_buf_wmem(w, strdata(s), len);
sb->w = w;
return sb;
}
/* -- High-level buffer put operations ------------------------------------ */
SBuf * LJ_FASTCALL lj_buf_putstr_reverse(SBuf *sb, GCstr *s)
{
MSize len = s->len;
char *w = lj_buf_more(sb, len), *e = w+len;
const char *q = strdata(s)+len-1;
while (w < e)
*w++ = *q--;
sb->w = w;
return sb;
}
SBuf * LJ_FASTCALL lj_buf_putstr_lower(SBuf *sb, GCstr *s)
{
MSize len = s->len;
char *w = lj_buf_more(sb, len), *e = w+len;
const char *q = strdata(s);
for (; w < e; w++, q++) {
uint32_t c = *(unsigned char *)q;
#if LJ_TARGET_PPC
*w = c + ((c >= 'A' && c <= 'Z') << 5);
#else
if (c >= 'A' && c <= 'Z') c += 0x20;
*w = c;
#endif
}
sb->w = w;
return sb;
}
SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s)
{
MSize len = s->len;
char *w = lj_buf_more(sb, len), *e = w+len;
const char *q = strdata(s);
for (; w < e; w++, q++) {
uint32_t c = *(unsigned char *)q;
#if LJ_TARGET_PPC
*w = c - ((c >= 'a' && c <= 'z') << 5);
#else
if (c >= 'a' && c <= 'z') c -= 0x20;
*w = c;
#endif
}
sb->w = w;
return sb;
}
SBuf *lj_buf_putstr_rep(SBuf *sb, GCstr *s, int32_t rep)
{
MSize len = s->len;
if (rep > 0 && len) {
uint64_t tlen = (uint64_t)rep * len;
char *w;
if (LJ_UNLIKELY(tlen > LJ_MAX_STR))
lj_err_mem(sbufL(sb));
w = lj_buf_more(sb, (MSize)tlen);
if (len == 1) { /* Optimize a common case. */
uint32_t c = strdata(s)[0];
do { *w++ = c; } while (--rep > 0);
} else {
const char *e = strdata(s) + len;
do {
const char *q = strdata(s);
do { *w++ = *q++; } while (q < e);
} while (--rep > 0);
}
sb->w = w;
}
return sb;
}
SBuf *lj_buf_puttab(SBuf *sb, GCtab *t, GCstr *sep, int32_t i, int32_t e)
{
MSize seplen = sep ? sep->len : 0;
if (i <= e) {
for (;;) {
cTValue *o = lj_tab_getint(t, i);
char *w;
if (!o) {
badtype: /* Error: bad element type. */
sb->w = (char *)(intptr_t)i; /* Store failing index. */
return NULL;
} else if (tvisstr(o)) {
MSize len = strV(o)->len;
w = lj_buf_wmem(lj_buf_more(sb, len + seplen), strVdata(o), len);
} else if (tvisint(o)) {
w = lj_strfmt_wint(lj_buf_more(sb, STRFMT_MAXBUF_INT+seplen), intV(o));
} else if (tvisnum(o)) {
w = lj_buf_more(lj_strfmt_putfnum(sb, STRFMT_G14, numV(o)), seplen);
} else {
goto badtype;
}
if (i++ == e) {
sb->w = w;
break;
}
if (seplen) w = lj_buf_wmem(w, strdata(sep), seplen);
sb->w = w;
}
}
return sb;
}
/* -- Miscellaneous buffer operations ------------------------------------- */
GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb)
{
return lj_str_new(sbufL(sb), sb->b, sbuflen(sb));
}
/* Concatenate two strings. */
GCstr *lj_buf_cat2str(lua_State *L, GCstr *s1, GCstr *s2)
{
MSize len1 = s1->len, len2 = s2->len;
char *buf = lj_buf_tmp(L, len1 + len2);
memcpy(buf, strdata(s1), len1);
memcpy(buf+len1, strdata(s2), len2);
return lj_str_new(L, buf, len1 + len2);
}
/* Read ULEB128 from buffer. */
uint32_t LJ_FASTCALL lj_buf_ruleb128(const char **pp)
{
const uint8_t *w = (const uint8_t *)*pp;
uint32_t v = *w++;
if (LJ_UNLIKELY(v >= 0x80)) {
int sh = 0;
v &= 0x7f;
do { v |= ((*w & 0x7f) << (sh += 7)); } while (*w++ >= 0x80);
}
*pp = (const char *)w;
return v;
}
+198
View File
@@ -0,0 +1,198 @@
/*
** Buffer handling.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_BUF_H
#define _LJ_BUF_H
#include "lj_obj.h"
#include "lj_gc.h"
#include "lj_str.h"
/* Resizable string buffers. */
/* The SBuf struct definition is in lj_obj.h:
** char *w; Write pointer.
** char *e; End pointer.
** char *b; Base pointer.
** MRef L; lua_State, used for buffer resizing. Extension bits in 3 LSB.
*/
/* Extended string buffer. */
typedef struct SBufExt {
SBufHeader;
union {
GCRef cowref; /* Copy-on-write object reference. */
MRef bsb; /* Borrowed string buffer. */
};
char *r; /* Read pointer. */
GCRef dict_str; /* Serialization string dictionary table. */
GCRef dict_mt; /* Serialization metatable dictionary table. */
int depth; /* Remaining recursion depth. */
} SBufExt;
#define sbufsz(sb) ((MSize)((sb)->e - (sb)->b))
#define sbuflen(sb) ((MSize)((sb)->w - (sb)->b))
#define sbufleft(sb) ((MSize)((sb)->e - (sb)->w))
#define sbufxlen(sbx) ((MSize)((sbx)->w - (sbx)->r))
#define sbufxslack(sbx) ((MSize)((sbx)->r - (sbx)->b))
#define SBUF_MASK_FLAG (7)
#define SBUF_MASK_L (~(GCSize)SBUF_MASK_FLAG)
#define SBUF_FLAG_EXT 1 /* Extended string buffer. */
#define SBUF_FLAG_COW 2 /* Copy-on-write buffer. */
#define SBUF_FLAG_BORROW 4 /* Borrowed string buffer. */
#define sbufL(sb) \
((lua_State *)(void *)(uintptr_t)(mrefu((sb)->L) & SBUF_MASK_L))
#define setsbufL(sb, l) (setmref((sb)->L, (l)))
#define setsbufXL(sb, l, flag) \
(setmrefu((sb)->L, (GCSize)(uintptr_t)(void *)(l) + (flag)))
#define setsbufXL_(sb, l) \
(setmrefu((sb)->L, (GCSize)(uintptr_t)(void *)(l) | (mrefu((sb)->L) & SBUF_MASK_FLAG)))
#define sbufflag(sb) (mrefu((sb)->L))
#define sbufisext(sb) (sbufflag((sb)) & SBUF_FLAG_EXT)
#define sbufiscow(sb) (sbufflag((sb)) & SBUF_FLAG_COW)
#define sbufisborrow(sb) (sbufflag((sb)) & SBUF_FLAG_BORROW)
#define sbufiscoworborrow(sb) (sbufflag((sb)) & (SBUF_FLAG_COW|SBUF_FLAG_BORROW))
#define sbufX(sb) \
(lj_assertG_(G(sbufL(sb)), sbufisext(sb), "not an SBufExt"), (SBufExt *)(sb))
#define setsbufflag(sb, flag) (setmrefu((sb)->L, (flag)))
#define tvisbuf(o) \
(LJ_HASBUFFER && tvisudata(o) && udataV(o)->udtype == UDTYPE_BUFFER)
#define bufV(o) check_exp(tvisbuf(o), ((SBufExt *)uddata(udataV(o))))
/* Buffer management */
LJ_FUNC char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz);
LJ_FUNC char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz);
LJ_FUNC void LJ_FASTCALL lj_buf_shrink(lua_State *L, SBuf *sb);
LJ_FUNC char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz);
static LJ_AINLINE void lj_buf_init(lua_State *L, SBuf *sb)
{
setsbufL(sb, L);
sb->w = sb->e = sb->b = NULL;
}
static LJ_AINLINE void lj_buf_reset(SBuf *sb)
{
sb->w = sb->b;
}
static LJ_AINLINE SBuf *lj_buf_tmp_(lua_State *L)
{
SBuf *sb = &G(L)->tmpbuf;
setsbufL(sb, L);
lj_buf_reset(sb);
return sb;
}
static LJ_AINLINE void lj_buf_free(global_State *g, SBuf *sb)
{
lj_assertG(!sbufisext(sb), "bad free of SBufExt");
lj_mem_free(g, sb->b, sbufsz(sb));
}
static LJ_AINLINE char *lj_buf_need(SBuf *sb, MSize sz)
{
if (LJ_UNLIKELY(sz > sbufsz(sb)))
return lj_buf_need2(sb, sz);
return sb->b;
}
static LJ_AINLINE char *lj_buf_more(SBuf *sb, MSize sz)
{
if (LJ_UNLIKELY(sz > sbufleft(sb)))
return lj_buf_more2(sb, sz);
return sb->w;
}
/* Extended buffer management */
static LJ_AINLINE void lj_bufx_init(lua_State *L, SBufExt *sbx)
{
memset(sbx, 0, sizeof(SBufExt));
setsbufXL(sbx, L, SBUF_FLAG_EXT);
}
static LJ_AINLINE void lj_bufx_set_borrow(lua_State *L, SBufExt *sbx, SBuf *sb)
{
setsbufXL(sbx, L, SBUF_FLAG_EXT | SBUF_FLAG_BORROW);
setmref(sbx->bsb, sb);
sbx->r = sbx->w = sbx->b = sb->b;
sbx->e = sb->e;
}
static LJ_AINLINE void lj_bufx_set_cow(lua_State *L, SBufExt *sbx,
const char *p, MSize len)
{
setsbufXL(sbx, L, SBUF_FLAG_EXT | SBUF_FLAG_COW);
sbx->r = sbx->b = (char *)p;
sbx->w = sbx->e = (char *)p + len;
}
static LJ_AINLINE void lj_bufx_reset(SBufExt *sbx)
{
if (sbufiscow(sbx)) {
setmrefu(sbx->L, (mrefu(sbx->L) & ~(GCSize)SBUF_FLAG_COW));
setgcrefnull(sbx->cowref);
sbx->b = sbx->e = NULL;
}
sbx->r = sbx->w = sbx->b;
}
static LJ_AINLINE void lj_bufx_free(lua_State *L, SBufExt *sbx)
{
if (!sbufiscoworborrow(sbx)) lj_mem_free(G(L), sbx->b, sbufsz(sbx));
setsbufXL(sbx, L, SBUF_FLAG_EXT);
setgcrefnull(sbx->cowref);
sbx->r = sbx->w = sbx->b = sbx->e = NULL;
}
#if LJ_HASBUFFER && LJ_HASJIT
LJ_FUNC void lj_bufx_set(SBufExt *sbx, const char *p, MSize len, GCobj *o);
#if LJ_HASFFI
LJ_FUNC MSize LJ_FASTCALL lj_bufx_more(SBufExt *sbx, MSize sz);
#endif
#endif
/* Low-level buffer put operations */
LJ_FUNC SBuf *lj_buf_putmem(SBuf *sb, const void *q, MSize len);
#if LJ_HASJIT || LJ_HASFFI
LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c);
#endif
LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s);
static LJ_AINLINE char *lj_buf_wmem(char *p, const void *q, MSize len)
{
return (char *)memcpy(p, q, len) + len;
}
static LJ_AINLINE void lj_buf_putb(SBuf *sb, int c)
{
char *w = lj_buf_more(sb, 1);
*w++ = (char)c;
sb->w = w;
}
/* High-level buffer put operations */
LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_reverse(SBuf *sb, GCstr *s);
LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_lower(SBuf *sb, GCstr *s);
LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s);
LJ_FUNC SBuf *lj_buf_putstr_rep(SBuf *sb, GCstr *s, int32_t rep);
LJ_FUNC SBuf *lj_buf_puttab(SBuf *sb, GCtab *t, GCstr *sep,
int32_t i, int32_t e);
/* Miscellaneous buffer operations */
LJ_FUNCA GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb);
LJ_FUNC GCstr *lj_buf_cat2str(lua_State *L, GCstr *s1, GCstr *s2);
LJ_FUNC uint32_t LJ_FASTCALL lj_buf_ruleb128(const char **pp);
static LJ_AINLINE GCstr *lj_buf_str(lua_State *L, SBuf *sb)
{
return lj_str_new(L, sb->b, sbuflen(sb));
}
#endif
+434
View File
@@ -0,0 +1,434 @@
/*
** C data arithmetic.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_tab.h"
#include "lj_meta.h"
#include "lj_ir.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_cdata.h"
#include "lj_carith.h"
#include "lj_strscan.h"
/* -- C data arithmetic --------------------------------------------------- */
/* Binary operands of an operator converted to ctypes. */
typedef struct CDArith {
uint8_t *p[2];
CType *ct[2];
} CDArith;
/* Check arguments for arithmetic metamethods. */
static int carith_checkarg(lua_State *L, CTState *cts, CDArith *ca)
{
TValue *o = L->base;
int ok = 1;
MSize i;
if (o+1 >= L->top)
lj_err_argt(L, 1, LUA_TCDATA);
for (i = 0; i < 2; i++, o++) {
if (tviscdata(o)) {
GCcdata *cd = cdataV(o);
CTypeID id = (CTypeID)cd->ctypeid;
CType *ct = ctype_raw(cts, id);
uint8_t *p = (uint8_t *)cdataptr(cd);
if (ctype_isptr(ct->info)) {
p = (uint8_t *)cdata_getptr(p, ct->size);
if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct);
} else if (ctype_isfunc(ct->info)) {
CTypeID id0 = i ? ctype_typeid(cts, ca->ct[0]) : 0;
p = (uint8_t *)*(void **)p;
ct = ctype_get(cts,
lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR));
if (i) { /* cts->tab may have been reallocated. */
ca->ct[0] = ctype_get(cts, id0);
}
}
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
ca->ct[i] = ct;
ca->p[i] = p;
} else if (tvisint(o)) {
ca->ct[i] = ctype_get(cts, CTID_INT32);
ca->p[i] = (uint8_t *)&o->i;
} else if (tvisnum(o)) {
ca->ct[i] = ctype_get(cts, CTID_DOUBLE);
ca->p[i] = (uint8_t *)&o->n;
} else if (tvisnil(o)) {
ca->ct[i] = ctype_get(cts, CTID_P_VOID);
ca->p[i] = (uint8_t *)0;
} else if (tvisstr(o)) {
TValue *o2 = i == 0 ? o+1 : o-1;
CType *ct = ctype_raw(cts, cdataV(o2)->ctypeid);
ca->ct[i] = NULL;
ca->p[i] = (uint8_t *)strVdata(o);
ok = 0;
if (ctype_isenum(ct->info)) {
CTSize ofs;
CType *cct = lj_ctype_getfield(cts, ct, strV(o), &ofs);
if (cct && ctype_isconstval(cct->info)) {
ca->ct[i] = ctype_child(cts, cct);
ca->p[i] = (uint8_t *)&cct->size; /* Assumes ct does not grow. */
ok = 1;
} else {
ca->ct[1-i] = ct; /* Use enum to improve error message. */
ca->p[1-i] = NULL;
break;
}
}
} else {
ca->ct[i] = NULL;
ca->p[i] = (void *)(intptr_t)1; /* To make it unequal. */
ok = 0;
}
}
return ok;
}
/* Pointer arithmetic. */
static int carith_ptr(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
{
CType *ctp = ca->ct[0];
uint8_t *pp = ca->p[0];
ptrdiff_t idx;
CTSize sz;
CTypeID id;
GCcdata *cd;
if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) {
if ((mm == MM_sub || mm == MM_eq || mm == MM_lt || mm == MM_le) &&
(ctype_isptr(ca->ct[1]->info) || ctype_isrefarray(ca->ct[1]->info))) {
uint8_t *pp2 = ca->p[1];
if (mm == MM_eq) { /* Pointer equality. Incompatible pointers are ok. */
setboolV(L->top-1, (pp == pp2));
return 1;
}
if (!lj_cconv_compatptr(cts, ctp, ca->ct[1], CCF_IGNQUAL))
return 0;
if (mm == MM_sub) { /* Pointer difference. */
intptr_t diff;
sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */
if (sz == 0 || sz == CTSIZE_INVALID)
return 0;
diff = ((intptr_t)pp - (intptr_t)pp2) / (int32_t)sz;
/* All valid pointer differences on x64 are in (-2^47, +2^47),
** which fits into a double without loss of precision.
*/
setintptrV(L->top-1, (int32_t)diff);
return 1;
} else if (mm == MM_lt) { /* Pointer comparison (unsigned). */
setboolV(L->top-1, ((uintptr_t)pp < (uintptr_t)pp2));
return 1;
} else {
lj_assertL(mm == MM_le, "bad metamethod %d", mm);
setboolV(L->top-1, ((uintptr_t)pp <= (uintptr_t)pp2));
return 1;
}
}
if (!((mm == MM_add || mm == MM_sub) && ctype_isnum(ca->ct[1]->info)))
return 0;
lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ca->ct[1],
(uint8_t *)&idx, ca->p[1], 0);
if (mm == MM_sub) idx = -idx;
} else if (mm == MM_add && ctype_isnum(ctp->info) &&
(ctype_isptr(ca->ct[1]->info) || ctype_isrefarray(ca->ct[1]->info))) {
/* Swap pointer and index. */
ctp = ca->ct[1]; pp = ca->p[1];
lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ca->ct[0],
(uint8_t *)&idx, ca->p[0], 0);
} else {
return 0;
}
sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */
if (sz == CTSIZE_INVALID)
return 0;
pp += idx*(int32_t)sz; /* Compute pointer + index. */
id = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ctp->info)),
CTSIZE_PTR);
cd = lj_cdata_new(cts, id, CTSIZE_PTR);
*(uint8_t **)cdataptr(cd) = pp;
setcdataV(L, L->top-1, cd);
lj_gc_check(L);
return 1;
}
/* 64 bit integer arithmetic. */
static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
{
if (ctype_isnum(ca->ct[0]->info) && ca->ct[0]->size <= 8 &&
ctype_isnum(ca->ct[1]->info) && ca->ct[1]->size <= 8) {
CTypeID id = (((ca->ct[0]->info & CTF_UNSIGNED) && ca->ct[0]->size == 8) ||
((ca->ct[1]->info & CTF_UNSIGNED) && ca->ct[1]->size == 8)) ?
CTID_UINT64 : CTID_INT64;
CType *ct = ctype_get(cts, id);
GCcdata *cd;
uint64_t u0, u1, *up;
lj_cconv_ct_ct(cts, ct, ca->ct[0], (uint8_t *)&u0, ca->p[0], 0);
if (mm != MM_unm)
lj_cconv_ct_ct(cts, ct, ca->ct[1], (uint8_t *)&u1, ca->p[1], 0);
switch (mm) {
case MM_eq:
setboolV(L->top-1, (u0 == u1));
return 1;
case MM_lt:
setboolV(L->top-1,
id == CTID_INT64 ? ((int64_t)u0 < (int64_t)u1) : (u0 < u1));
return 1;
case MM_le:
setboolV(L->top-1,
id == CTID_INT64 ? ((int64_t)u0 <= (int64_t)u1) : (u0 <= u1));
return 1;
default: break;
}
cd = lj_cdata_new(cts, id, 8);
up = (uint64_t *)cdataptr(cd);
setcdataV(L, L->top-1, cd);
switch (mm) {
case MM_add: *up = u0 + u1; break;
case MM_sub: *up = u0 - u1; break;
case MM_mul: *up = u0 * u1; break;
case MM_div:
if (id == CTID_INT64)
*up = (uint64_t)lj_carith_divi64((int64_t)u0, (int64_t)u1);
else
*up = lj_carith_divu64(u0, u1);
break;
case MM_mod:
if (id == CTID_INT64)
*up = (uint64_t)lj_carith_modi64((int64_t)u0, (int64_t)u1);
else
*up = lj_carith_modu64(u0, u1);
break;
case MM_pow:
if (id == CTID_INT64)
*up = (uint64_t)lj_carith_powi64((int64_t)u0, (int64_t)u1);
else
*up = lj_carith_powu64(u0, u1);
break;
case MM_unm: *up = ~u0+1u; break;
default:
lj_assertL(0, "bad metamethod %d", mm);
break;
}
lj_gc_check(L);
return 1;
}
return 0;
}
/* Handle ctype arithmetic metamethods. */
static int lj_carith_meta(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
{
cTValue *tv = NULL;
if (tviscdata(L->base)) {
CTypeID id = cdataV(L->base)->ctypeid;
CType *ct = ctype_raw(cts, id);
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
tv = lj_ctype_meta(cts, id, mm);
}
if (!tv && L->base+1 < L->top && tviscdata(L->base+1)) {
CTypeID id = cdataV(L->base+1)->ctypeid;
CType *ct = ctype_raw(cts, id);
if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
tv = lj_ctype_meta(cts, id, mm);
}
if (!tv) {
const char *repr[2];
int i, isenum = -1, isstr = -1;
if (mm == MM_eq) { /* Equality checks never raise an error. */
int eq = ca->p[0] == ca->p[1];
setboolV(L->top-1, eq);
setboolV(&G(L)->tmptv2, eq); /* Remember for trace recorder. */
return 1;
}
for (i = 0; i < 2; i++) {
if (ca->ct[i] && tviscdata(L->base+i)) {
if (ctype_isenum(ca->ct[i]->info)) isenum = i;
repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca->ct[i]), NULL));
} else {
if (tvisstr(&L->base[i])) isstr = i;
repr[i] = lj_typename(&L->base[i]);
}
}
if ((isenum ^ isstr) == 1)
lj_err_callerv(L, LJ_ERR_FFI_BADCONV, repr[isstr], repr[isenum]);
lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN :
mm == MM_concat ? LJ_ERR_FFI_BADCONCAT :
mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH,
repr[0], repr[1]);
}
return lj_meta_tailcall(L, tv);
}
/* Arithmetic operators for cdata. */
int lj_carith_op(lua_State *L, MMS mm)
{
CTState *cts = ctype_cts(L);
CDArith ca;
if (carith_checkarg(L, cts, &ca) && mm != MM_len && mm != MM_concat) {
if (carith_int64(L, cts, &ca, mm) || carith_ptr(L, cts, &ca, mm)) {
copyTV(L, &G(L)->tmptv2, L->top-1); /* Remember for trace recorder. */
return 1;
}
}
return lj_carith_meta(L, cts, &ca, mm);
}
/* -- 64 bit bit operations helpers --------------------------------------- */
#if LJ_64
#define B64DEF(name) \
static LJ_AINLINE uint64_t lj_carith_##name(uint64_t x, int32_t sh)
#else
/* Not inlined on 32 bit archs, since some of these are quite lengthy. */
#define B64DEF(name) \
uint64_t LJ_NOINLINE lj_carith_##name(uint64_t x, int32_t sh)
#endif
B64DEF(shl64) { return x << (sh&63); }
B64DEF(shr64) { return x >> (sh&63); }
B64DEF(sar64) { return (uint64_t)((int64_t)x >> (sh&63)); }
B64DEF(rol64) { return lj_rol(x, (sh&63)); }
B64DEF(ror64) { return lj_ror(x, (sh&63)); }
#undef B64DEF
uint64_t lj_carith_shift64(uint64_t x, int32_t sh, int op)
{
switch (op) {
case IR_BSHL-IR_BSHL: x = lj_carith_shl64(x, sh); break;
case IR_BSHR-IR_BSHL: x = lj_carith_shr64(x, sh); break;
case IR_BSAR-IR_BSHL: x = lj_carith_sar64(x, sh); break;
case IR_BROL-IR_BSHL: x = lj_carith_rol64(x, sh); break;
case IR_BROR-IR_BSHL: x = lj_carith_ror64(x, sh); break;
default:
lj_assertX(0, "bad shift op %d", op);
break;
}
return x;
}
/* Equivalent to lj_lib_checkbit(), but handles cdata. */
uint64_t lj_carith_check64(lua_State *L, int narg, CTypeID *id)
{
TValue *o = L->base + narg-1;
if (o >= L->top) {
err:
lj_err_argt(L, narg, LUA_TNUMBER);
} else if (LJ_LIKELY(tvisnumber(o))) {
/* Handled below. */
} else if (tviscdata(o)) {
CTState *cts = ctype_cts(L);
uint8_t *sp = (uint8_t *)cdataptr(cdataV(o));
CTypeID sid = cdataV(o)->ctypeid;
CType *s = ctype_get(cts, sid);
uint64_t x;
if (ctype_isref(s->info)) {
sp = *(void **)sp;
sid = ctype_cid(s->info);
}
s = ctype_raw(cts, sid);
if (ctype_isenum(s->info)) s = ctype_child(cts, s);
if ((s->info & (CTMASK_NUM|CTF_BOOL|CTF_FP|CTF_UNSIGNED)) ==
CTINFO(CT_NUM, CTF_UNSIGNED) && s->size == 8)
*id = CTID_UINT64; /* Use uint64_t, since it has the highest rank. */
else if (!*id)
*id = CTID_INT64; /* Use int64_t, unless already set. */
lj_cconv_ct_ct(cts, ctype_get(cts, *id), s,
(uint8_t *)&x, sp, CCF_ARG(narg));
return x;
} else if (!(tvisstr(o) && lj_strscan_number(strV(o), o))) {
goto err;
}
if (LJ_LIKELY(tvisint(o))) {
return (uint32_t)intV(o);
} else {
return (uint32_t)lj_num2bit(numV(o));
}
}
/* -- 64 bit integer arithmetic helpers ----------------------------------- */
#if LJ_32 && LJ_HASJIT
/* Signed/unsigned 64 bit multiplication. */
int64_t lj_carith_mul64(int64_t a, int64_t b)
{
return a * b;
}
#endif
/* Unsigned 64 bit division. */
uint64_t lj_carith_divu64(uint64_t a, uint64_t b)
{
if (b == 0) return U64x(80000000,00000000);
return a / b;
}
/* Signed 64 bit division. */
int64_t lj_carith_divi64(int64_t a, int64_t b)
{
if (b == 0 || (a == (int64_t)U64x(80000000,00000000) && b == -1))
return U64x(80000000,00000000);
return a / b;
}
/* Unsigned 64 bit modulo. */
uint64_t lj_carith_modu64(uint64_t a, uint64_t b)
{
if (b == 0) return U64x(80000000,00000000);
return a % b;
}
/* Signed 64 bit modulo. */
int64_t lj_carith_modi64(int64_t a, int64_t b)
{
if (b == 0) return U64x(80000000,00000000);
if (a == (int64_t)U64x(80000000,00000000) && b == -1) return 0;
return a % b;
}
/* Unsigned 64 bit x^k. */
uint64_t lj_carith_powu64(uint64_t x, uint64_t k)
{
uint64_t y;
if (k == 0)
return 1;
for (; (k & 1) == 0; k >>= 1) x *= x;
y = x;
if ((k >>= 1) != 0) {
for (;;) {
x *= x;
if (k == 1) break;
if (k & 1) y *= x;
k >>= 1;
}
y *= x;
}
return y;
}
/* Signed 64 bit x^k. */
int64_t lj_carith_powi64(int64_t x, int64_t k)
{
if (k == 0)
return 1;
if (k < 0) {
if (x == 0)
return U64x(7fffffff,ffffffff);
else if (x == 1)
return 1;
else if (x == -1)
return (k & 1) ? -1 : 1;
else
return 0;
}
return (int64_t)lj_carith_powu64((uint64_t)x, (uint64_t)k);
}
#endif
+37
View File
@@ -0,0 +1,37 @@
/*
** C data arithmetic.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CARITH_H
#define _LJ_CARITH_H
#include "lj_obj.h"
#if LJ_HASFFI
LJ_FUNC int lj_carith_op(lua_State *L, MMS mm);
#if LJ_32
LJ_FUNC uint64_t lj_carith_shl64(uint64_t x, int32_t sh);
LJ_FUNC uint64_t lj_carith_shr64(uint64_t x, int32_t sh);
LJ_FUNC uint64_t lj_carith_sar64(uint64_t x, int32_t sh);
LJ_FUNC uint64_t lj_carith_rol64(uint64_t x, int32_t sh);
LJ_FUNC uint64_t lj_carith_ror64(uint64_t x, int32_t sh);
#endif
LJ_FUNC uint64_t lj_carith_shift64(uint64_t x, int32_t sh, int op);
LJ_FUNC uint64_t lj_carith_check64(lua_State *L, int narg, CTypeID *id);
#if LJ_32 && LJ_HASJIT
LJ_FUNC int64_t lj_carith_mul64(int64_t x, int64_t k);
#endif
LJ_FUNC uint64_t lj_carith_divu64(uint64_t a, uint64_t b);
LJ_FUNC int64_t lj_carith_divi64(int64_t a, int64_t b);
LJ_FUNC uint64_t lj_carith_modu64(uint64_t a, uint64_t b);
LJ_FUNC int64_t lj_carith_modi64(int64_t a, int64_t b);
LJ_FUNC uint64_t lj_carith_powu64(uint64_t x, uint64_t k);
LJ_FUNC int64_t lj_carith_powi64(int64_t x, int64_t k);
#endif
#endif
File diff suppressed because it is too large. Load diff
+201
View File
@@ -0,0 +1,201 @@
/*
** FFI C call handling.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CCALL_H
#define _LJ_CCALL_H
#include "lj_obj.h"
#include "lj_ctype.h"
#if LJ_HASFFI
/* -- C calling conventions ----------------------------------------------- */
#if LJ_TARGET_X86ORX64
#if LJ_TARGET_X86
#define CCALL_NARG_GPR 2 /* For fastcall arguments. */
#define CCALL_NARG_FPR 0
#define CCALL_NRET_GPR 2
#define CCALL_NRET_FPR 1 /* For FP results on x87 stack. */
#define CCALL_ALIGN_STACKARG 0 /* Don't align argument on stack. */
#elif LJ_ABI_WIN
#define CCALL_NARG_GPR 4
#define CCALL_NARG_FPR 4
#define CCALL_NRET_GPR 1
#define CCALL_NRET_FPR 1
#define CCALL_SPS_EXTRA 4
#else
#define CCALL_NARG_GPR 6
#define CCALL_NARG_FPR 8
#define CCALL_NRET_GPR 2
#define CCALL_NRET_FPR 2
#define CCALL_VECTOR_REG 1 /* Pass vectors in registers. */
#endif
#define CCALL_SPS_FREE 1
#define CCALL_ALIGN_CALLSTATE 16
typedef LJ_ALIGN(16) union FPRArg {
double d[2];
float f[4];
uint8_t b[16];
uint16_t s[8];
int i[4];
int64_t l[2];
} FPRArg;
typedef intptr_t GPRArg;
#elif LJ_TARGET_ARM
#define CCALL_NARG_GPR 4
#define CCALL_NRET_GPR 2 /* For softfp double. */
#if LJ_ABI_SOFTFP
#define CCALL_NARG_FPR 0
#define CCALL_NRET_FPR 0
#else
#define CCALL_NARG_FPR 8
#define CCALL_NRET_FPR 4
#endif
#define CCALL_SPS_FREE 0
typedef intptr_t GPRArg;
typedef union FPRArg {
double d;
float f[2];
} FPRArg;
#elif LJ_TARGET_ARM64
#define CCALL_NARG_GPR 8
#define CCALL_NRET_GPR 2
#define CCALL_NARG_FPR 8
#define CCALL_NRET_FPR 4
#define CCALL_SPS_FREE 0
#if LJ_TARGET_OSX
#define CCALL_PACK_STACKARG 1
#endif
typedef intptr_t GPRArg;
typedef union FPRArg {
double d;
struct { LJ_ENDIAN_LOHI(float f; , float g;) };
struct { LJ_ENDIAN_LOHI(uint32_t lo; , uint32_t hi;) };
} FPRArg;
#elif LJ_TARGET_PPC
#define CCALL_NARG_GPR 8
#define CCALL_NARG_FPR (LJ_ABI_SOFTFP ? 0 : 8)
#define CCALL_NRET_GPR 4 /* For complex double. */
#define CCALL_NRET_FPR (LJ_ABI_SOFTFP ? 0 : 1)
#define CCALL_SPS_EXTRA 4
#define CCALL_SPS_FREE 0
typedef intptr_t GPRArg;
typedef double FPRArg;
#elif LJ_TARGET_MIPS32
#define CCALL_NARG_GPR 4
#define CCALL_NARG_FPR (LJ_ABI_SOFTFP ? 0 : 2)
#define CCALL_NRET_GPR (LJ_ABI_SOFTFP ? 4 : 2)
#define CCALL_NRET_FPR (LJ_ABI_SOFTFP ? 0 : 2)
#define CCALL_SPS_EXTRA 7
#define CCALL_SPS_FREE 1
typedef intptr_t GPRArg;
typedef union FPRArg {
double d;
struct { LJ_ENDIAN_LOHI(float f; , float g;) };
} FPRArg;
#elif LJ_TARGET_MIPS64
/* FP args are positional and overlay the GPR array. */
#define CCALL_NARG_GPR 8
#define CCALL_NARG_FPR 0
#define CCALL_NRET_GPR 2
#define CCALL_NRET_FPR (LJ_ABI_SOFTFP ? 0 : 2)
#define CCALL_SPS_EXTRA 3
#define CCALL_SPS_FREE 1
typedef intptr_t GPRArg;
typedef union FPRArg {
double d;
struct { LJ_ENDIAN_LOHI(float f; , float g;) };
} FPRArg;
#else
#error "Missing calling convention definitions for this architecture"
#endif
#ifndef CCALL_SPS_EXTRA
#define CCALL_SPS_EXTRA 0
#endif
#ifndef CCALL_VECTOR_REG
#define CCALL_VECTOR_REG 0
#endif
#ifndef CCALL_ALIGN_STACKARG
#define CCALL_ALIGN_STACKARG 1
#endif
#ifndef CCALL_PACK_STACKARG
#define CCALL_PACK_STACKARG 0
#endif
#ifndef CCALL_ALIGN_CALLSTATE
#define CCALL_ALIGN_CALLSTATE 8
#endif
#define CCALL_NUM_GPR \
(CCALL_NARG_GPR > CCALL_NRET_GPR ? CCALL_NARG_GPR : CCALL_NRET_GPR)
#define CCALL_NUM_FPR \
(CCALL_NARG_FPR > CCALL_NRET_FPR ? CCALL_NARG_FPR : CCALL_NRET_FPR)
/* Check against constants in lj_ctype.h. */
LJ_STATIC_ASSERT(CCALL_NUM_GPR <= CCALL_MAX_GPR);
LJ_STATIC_ASSERT(CCALL_NUM_FPR <= CCALL_MAX_FPR);
#define CCALL_NUM_STACK 31
#define CCALL_SIZE_STACK (CCALL_NUM_STACK * CTSIZE_PTR)
/* -- C call state -------------------------------------------------------- */
typedef LJ_ALIGN(CCALL_ALIGN_CALLSTATE) struct CCallState {
void (*func)(void); /* Pointer to called function. */
uint32_t spadj; /* Stack pointer adjustment. */
uint8_t nsp; /* Number of bytes on stack. */
uint8_t retref; /* Return value by reference. */
#if LJ_TARGET_X64
uint8_t ngpr; /* Number of arguments in GPRs. */
uint8_t nfpr; /* Number of arguments in FPRs. */
#elif LJ_TARGET_X86
uint8_t resx87; /* Result on x87 stack: 1:float, 2:double. */
#elif LJ_TARGET_ARM64
void *retp; /* Aggregate return pointer in x8. */
#elif LJ_TARGET_PPC
uint8_t nfpr; /* Number of arguments in FPRs. */
#endif
#if LJ_32
int32_t align1;
#endif
#if CCALL_NUM_FPR
FPRArg fpr[CCALL_NUM_FPR]; /* Arguments/results in FPRs. */
#endif
GPRArg gpr[CCALL_NUM_GPR]; /* Arguments/results in GPRs. */
GPRArg stack[CCALL_NUM_STACK]; /* Stack slots. */
} CCallState;
/* -- C call handling ----------------------------------------------------- */
/* Really belongs to lj_vm.h. */
LJ_ASMF void LJ_FASTCALL lj_vm_ffi_call(CCallState *cc);
LJ_FUNC CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o);
LJ_FUNC int lj_ccall_func(lua_State *L, GCcdata *cd);
#endif
#endif
+796
View File
@@ -0,0 +1,796 @@
/*
** FFI C callback handling.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#include "lj_obj.h"
#if LJ_HASFFI
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_tab.h"
#include "lj_state.h"
#include "lj_frame.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_ccall.h"
#include "lj_ccallback.h"
#include "lj_target.h"
#include "lj_mcode.h"
#include "lj_trace.h"
#include "lj_vm.h"
/* -- Target-specific handling of callback slots -------------------------- */
#define CALLBACK_MCODE_SIZE (LJ_PAGESIZE * LJ_NUM_CBPAGE)
#if LJ_OS_NOJIT
/* Callbacks disabled. */
#define CALLBACK_SLOT2OFS(slot) (0*(slot))
#define CALLBACK_OFS2SLOT(ofs) (0*(ofs))
#define CALLBACK_MAX_SLOT 0
#elif LJ_TARGET_X86ORX64
#define CALLBACK_MCODE_HEAD (LJ_64 ? 8 : 0)
#define CALLBACK_MCODE_GROUP (-2+1+2+(LJ_GC64 ? 10 : 5)+(LJ_64 ? 6 : 5))
#define CALLBACK_SLOT2OFS(slot) \
(CALLBACK_MCODE_HEAD + CALLBACK_MCODE_GROUP*((slot)/32) + 4*(slot))
static MSize CALLBACK_OFS2SLOT(MSize ofs)
{
MSize group;
ofs -= CALLBACK_MCODE_HEAD;
group = ofs / (32*4 + CALLBACK_MCODE_GROUP);
return (ofs % (32*4 + CALLBACK_MCODE_GROUP))/4 + group*32;
}
#define CALLBACK_MAX_SLOT \
(((CALLBACK_MCODE_SIZE-CALLBACK_MCODE_HEAD)/(CALLBACK_MCODE_GROUP+4*32))*32)
#elif LJ_TARGET_ARM
#define CALLBACK_MCODE_HEAD 32
#elif LJ_TARGET_ARM64
#define CALLBACK_MCODE_HEAD 32
#elif LJ_TARGET_PPC
#define CALLBACK_MCODE_HEAD 24
#elif LJ_TARGET_MIPS32
#define CALLBACK_MCODE_HEAD 20
#elif LJ_TARGET_MIPS64
#define CALLBACK_MCODE_HEAD 52
#else
/* Missing support for this architecture. */
#define CALLBACK_SLOT2OFS(slot) (0*(slot))
#define CALLBACK_OFS2SLOT(ofs) (0*(ofs))
#define CALLBACK_MAX_SLOT 0
#endif
#ifndef CALLBACK_SLOT2OFS
#define CALLBACK_SLOT2OFS(slot) (CALLBACK_MCODE_HEAD + 8*(slot))
#define CALLBACK_OFS2SLOT(ofs) (((ofs)-CALLBACK_MCODE_HEAD)/8)
#define CALLBACK_MAX_SLOT (CALLBACK_OFS2SLOT(CALLBACK_MCODE_SIZE))
#endif
/* Convert callback slot number to callback function pointer. */
static void *callback_slot2ptr(CTState *cts, MSize slot)
{
return (uint8_t *)cts->cb.mcode + CALLBACK_SLOT2OFS(slot);
}
/* Convert callback function pointer to slot number. */
MSize lj_ccallback_ptr2slot(CTState *cts, void *p)
{
uintptr_t ofs = (uintptr_t)((uint8_t *)p -(uint8_t *)cts->cb.mcode);
if (ofs < CALLBACK_MCODE_SIZE) {
MSize slot = CALLBACK_OFS2SLOT((MSize)ofs);
if (CALLBACK_SLOT2OFS(slot) == (MSize)ofs)
return slot;
}
return ~0u; /* Not a known callback function pointer. */
}
/* Initialize machine code for callback function pointers. */
#if LJ_OS_NOJIT
/* Disabled callback support. */
#define callback_mcode_init(g, p) (p)
#elif LJ_TARGET_X86ORX64
static void *callback_mcode_init(global_State *g, uint8_t *page)
{
uint8_t *p = page;
uint8_t *target = (uint8_t *)(void *)lj_vm_ffi_callback;
MSize slot;
#if LJ_64
*(void **)p = target; p += 8;
#endif
for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
/* mov al, slot; jmp group */
*p++ = XI_MOVrib | RID_EAX; *p++ = (uint8_t)slot;
if ((slot & 31) == 31 || slot == CALLBACK_MAX_SLOT-1) {
/* push ebp/rbp; mov ah, slot>>8; mov ebp, &g. */
*p++ = XI_PUSH + RID_EBP;
*p++ = XI_MOVrib | (RID_EAX+4); *p++ = (uint8_t)(slot >> 8);
#if LJ_GC64
*p++ = 0x48; *p++ = XI_MOVri | RID_EBP;
*(uint64_t *)p = (uint64_t)(g); p += 8;
#else
*p++ = XI_MOVri | RID_EBP;
*(int32_t *)p = i32ptr(g); p += 4;
#endif
#if LJ_64
/* jmp [rip-pageofs] where lj_vm_ffi_callback is stored. */
*p++ = XI_GROUP5; *p++ = XM_OFS0 + (XOg_JMP<<3) + RID_EBP;
*(int32_t *)p = (int32_t)(page-(p+4)); p += 4;
#else
/* jmp lj_vm_ffi_callback. */
*p++ = XI_JMP; *(int32_t *)p = target-(p+4); p += 4;
#endif
} else {
*p++ = XI_JMPs; *p++ = (uint8_t)((2+2)*(31-(slot&31)) - 2);
}
}
return p;
}
#elif LJ_TARGET_ARM
static void *callback_mcode_init(global_State *g, uint32_t *page)
{
uint32_t *p = page;
void *target = (void *)lj_vm_ffi_callback;
MSize slot;
/* This must match with the saveregs macro in buildvm_arm.dasc. */
*p++ = ARMI_SUB|ARMF_D(RID_R12)|ARMF_N(RID_R12)|ARMF_M(RID_PC);
*p++ = ARMI_PUSH|ARMF_N(RID_SP)|RSET_RANGE(RID_R4,RID_R11+1)|RID2RSET(RID_LR);
*p++ = ARMI_SUB|ARMI_K12|ARMF_D(RID_R12)|ARMF_N(RID_R12)|CALLBACK_MCODE_HEAD;
*p++ = ARMI_STR|ARMI_LS_P|ARMI_LS_W|ARMF_D(RID_R12)|ARMF_N(RID_SP)|(CFRAME_SIZE-4*9);
*p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_R12)|ARMF_N(RID_PC);
*p++ = ARMI_LDR|ARMI_LS_P|ARMI_LS_U|ARMF_D(RID_PC)|ARMF_N(RID_PC);
*p++ = u32ptr(g);
*p++ = u32ptr(target);
for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
*p++ = ARMI_MOV|ARMF_D(RID_R12)|ARMF_M(RID_PC);
*p = ARMI_B | ((page-p-2) & 0x00ffffffu);
p++;
}
return p;
}
#elif LJ_TARGET_ARM64
static void *callback_mcode_init(global_State *g, uint32_t *page)
{
uint32_t *p = page;
ASMFunction target = lj_vm_ffi_callback;
MSize slot;
*p++ = A64I_LE(A64I_LDRLx | A64F_D(RID_X11) | A64F_S19(4));
*p++ = A64I_LE(A64I_LDRLx | A64F_D(RID_X10) | A64F_S19(5));
*p++ = A64I_LE(A64I_BR_AUTH | A64F_N(RID_X11));
*p++ = A64I_LE(A64I_NOP);
((ASMFunction *)p)[0] = target;
((void **)p)[1] = g;
p += 4;
for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
*p++ = A64I_LE(A64I_MOVZw | A64F_D(RID_X9) | A64F_U16(slot));
*p = A64I_LE(A64I_B | A64F_S26((page-p) & 0x03ffffffu));
p++;
}
return p;
}
#elif LJ_TARGET_PPC
static void *callback_mcode_init(global_State *g, uint32_t *page)
{
uint32_t *p = page;
void *target = (void *)lj_vm_ffi_callback;
MSize slot;
*p++ = PPCI_LIS | PPCF_T(RID_TMP) | (u32ptr(target) >> 16);
*p++ = PPCI_LIS | PPCF_T(RID_R12) | (u32ptr(g) >> 16);
*p++ = PPCI_ORI | PPCF_A(RID_TMP)|PPCF_T(RID_TMP) | (u32ptr(target) & 0xffff);
*p++ = PPCI_ORI | PPCF_A(RID_R12)|PPCF_T(RID_R12) | (u32ptr(g) & 0xffff);
*p++ = PPCI_MTCTR | PPCF_T(RID_TMP);
*p++ = PPCI_BCTR;
for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
*p++ = PPCI_LI | PPCF_T(RID_R11) | slot;
*p = PPCI_B | (((page-p) & 0x00ffffffu) << 2);
p++;
}
return p;
}
#elif LJ_TARGET_MIPS
static void *callback_mcode_init(global_State *g, uint32_t *page)
{
uint32_t *p = page;
uintptr_t target = (uintptr_t)(void *)lj_vm_ffi_callback;
uintptr_t ug = (uintptr_t)(void *)g;
MSize slot;
#if LJ_TARGET_MIPS32
*p++ = MIPSI_LUI | MIPSF_T(RID_R3) | (target >> 16);
*p++ = MIPSI_LUI | MIPSF_T(RID_R2) | (ug >> 16);
#else
*p++ = MIPSI_LUI | MIPSF_T(RID_R3) | (target >> 48);
*p++ = MIPSI_LUI | MIPSF_T(RID_R2) | (ug >> 48);
*p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) | ((target >> 32) & 0xffff);
*p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | ((ug >> 32) & 0xffff);
*p++ = MIPSI_DSLL | MIPSF_D(RID_R3)|MIPSF_T(RID_R3) | MIPSF_A(16);
*p++ = MIPSI_DSLL | MIPSF_D(RID_R2)|MIPSF_T(RID_R2) | MIPSF_A(16);
*p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) | ((target >> 16) & 0xffff);
*p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | ((ug >> 16) & 0xffff);
*p++ = MIPSI_DSLL | MIPSF_D(RID_R3)|MIPSF_T(RID_R3) | MIPSF_A(16);
*p++ = MIPSI_DSLL | MIPSF_D(RID_R2)|MIPSF_T(RID_R2) | MIPSF_A(16);
#endif
*p++ = MIPSI_ORI | MIPSF_T(RID_R3)|MIPSF_S(RID_R3) | (target & 0xffff);
*p++ = MIPSI_JR | MIPSF_S(RID_R3);
*p++ = MIPSI_ORI | MIPSF_T(RID_R2)|MIPSF_S(RID_R2) | (ug & 0xffff);
for (slot = 0; slot < CALLBACK_MAX_SLOT; slot++) {
*p = MIPSI_B | ((page-p-1) & 0x0000ffffu);
p++;
*p++ = MIPSI_LI | MIPSF_T(RID_R1) | slot;
}
return p;
}
#else
/* Missing support for this architecture. */
#define callback_mcode_init(g, p) (p)
#endif
/* -- Machine code management --------------------------------------------- */
#if LJ_TARGET_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif LJ_TARGET_POSIX
#include <sys/mman.h>
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#ifdef PROT_MPROTECT
#define CCPROT_CREATE (PROT_MPROTECT(PROT_EXEC))
#else
#define CCPROT_CREATE 0
#endif
#endif
/* Allocate and initialize area for callback function pointers. */
static void callback_mcode_new(CTState *cts)
{
size_t sz = (size_t)CALLBACK_MCODE_SIZE;
void *p, *pe;
if (CALLBACK_MAX_SLOT == 0)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#if LJ_TARGET_WINDOWS
p = LJ_WIN_VALLOC(NULL, sz, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if (!p)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#elif LJ_TARGET_POSIX
p = mmap(NULL, sz, (PROT_READ|PROT_WRITE|CCPROT_CREATE), MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0);
if (p == MAP_FAILED)
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
#else
/* Fallback allocator. Fails if memory is not executable by default. */
p = lj_mem_new(cts->L, sz);
#endif
cts->cb.mcode = p;
pe = callback_mcode_init(cts->g, p);
UNUSED(pe);
lj_assertCTS((size_t)((char *)pe - (char *)p) <= sz,
"miscalculated CALLBACK_MAX_SLOT");
lj_mcode_sync(p, (char *)p + sz);
#if LJ_TARGET_WINDOWS
{
DWORD oprot;
LJ_WIN_VPROTECT(p, sz, PAGE_EXECUTE_READ, &oprot);
}
#elif LJ_TARGET_POSIX
mprotect(p, sz, (PROT_READ|PROT_EXEC));
#endif
}
/* Free area for callback function pointers. */
void lj_ccallback_mcode_free(CTState *cts)
{
size_t sz = (size_t)CALLBACK_MCODE_SIZE;
void *p = cts->cb.mcode;
if (p == NULL) return;
#if LJ_TARGET_WINDOWS
VirtualFree(p, 0, MEM_RELEASE);
UNUSED(sz);
#elif LJ_TARGET_POSIX
munmap(p, sz);
#else
lj_mem_free(cts->g, p, sz);
#endif
}
/* -- C callback entry ---------------------------------------------------- */
/* Target-specific handling of register arguments. Similar to lj_ccall.c. */
#if LJ_TARGET_X86
#define CALLBACK_HANDLE_REGARG \
if (!isfp) { /* Only non-FP values may be passed in registers. */ \
if (n > 1) { /* Anything > 32 bit is passed on the stack. */ \
if (!LJ_ABI_WIN) ngpr = maxgpr; /* Prevent reordering. */ \
} else if (ngpr + 1 <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#elif LJ_TARGET_X64 && LJ_ABI_WIN
/* Windows/x64 argument registers are strictly positional (use ngpr). */
#define CALLBACK_HANDLE_REGARG \
if (isfp) { \
if (ngpr < maxgpr) { sp = &cts->cb.fpr[ngpr++]; UNUSED(nfpr); goto done; } \
} else { \
if (ngpr < maxgpr) { sp = &cts->cb.gpr[ngpr++]; goto done; } \
}
#elif LJ_TARGET_X64
#define CALLBACK_HANDLE_REGARG \
if (isfp) { \
if (nfpr + n <= CCALL_NARG_FPR) { \
sp = &cts->cb.fpr[nfpr]; \
nfpr += n; \
goto done; \
} \
} else { \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} \
}
#elif LJ_TARGET_ARM
#if LJ_ABI_SOFTFP
#define CALLBACK_HANDLE_REGARG_FP1 UNUSED(isfp);
#define CALLBACK_HANDLE_REGARG_FP2
#else
#define CALLBACK_HANDLE_REGARG_FP1 \
if (isfp) { \
if (n == 1) { \
if (fprodd) { \
sp = &cts->cb.fpr[fprodd-1]; \
fprodd = 0; \
goto done; \
} else if (nfpr + 1 <= CCALL_NARG_FPR) { \
sp = &cts->cb.fpr[nfpr++]; \
fprodd = nfpr; \
goto done; \
} \
} else { \
if (nfpr + 1 <= CCALL_NARG_FPR) { \
sp = &cts->cb.fpr[nfpr++]; \
goto done; \
} \
} \
fprodd = 0; /* No reordering after the first FP value is on stack. */ \
} else {
#define CALLBACK_HANDLE_REGARG_FP2 }
#endif
#define CALLBACK_HANDLE_REGARG \
CALLBACK_HANDLE_REGARG_FP1 \
if (n > 1) ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} CALLBACK_HANDLE_REGARG_FP2
#elif LJ_TARGET_ARM64
#define CALLBACK_HANDLE_REGARG \
if (isfp) { \
if (nfpr + n <= CCALL_NARG_FPR) { \
sp = &cts->cb.fpr[nfpr]; \
nfpr += n; \
goto done; \
} else { \
nfpr = CCALL_NARG_FPR; /* Prevent reordering. */ \
} \
} else { \
if (!LJ_TARGET_OSX && n > 1) \
ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
} else { \
ngpr = CCALL_NARG_GPR; /* Prevent reordering. */ \
} \
}
#elif LJ_TARGET_PPC
#define CALLBACK_HANDLE_GPR \
if (n > 1) { \
lj_assertCTS(((LJ_ABI_SOFTFP && ctype_isnum(cta->info)) || /* double. */ \
ctype_isinteger(cta->info)) && n == 2, /* int64_t. */ \
"bad GPR type"); \
ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \
} \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
}
#if LJ_ABI_SOFTFP
#define CALLBACK_HANDLE_REGARG \
CALLBACK_HANDLE_GPR \
UNUSED(isfp);
#else
#define CALLBACK_HANDLE_REGARG \
if (isfp) { \
if (nfpr + 1 <= CCALL_NARG_FPR) { \
sp = &cts->cb.fpr[nfpr++]; \
cta = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \
goto done; \
} \
} else { /* Try to pass argument in GPRs. */ \
CALLBACK_HANDLE_GPR \
}
#endif
#if !LJ_ABI_SOFTFP
#define CALLBACK_HANDLE_RET \
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
*(double *)dp = *(float *)dp; /* FPRs always hold doubles. */
#endif
#elif LJ_TARGET_MIPS32
#define CALLBACK_HANDLE_GPR \
if (n > 1) ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \
if (ngpr + n <= maxgpr) { \
sp = &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
}
#if !LJ_ABI_SOFTFP /* MIPS32 hard-float */
#define CALLBACK_HANDLE_REGARG \
if (isfp && nfpr < CCALL_NARG_FPR) { /* Try to pass argument in FPRs. */ \
sp = (void *)((uint8_t *)&cts->cb.fpr[nfpr] + ((LJ_BE && n==1) ? 4 : 0)); \
nfpr++; ngpr += n; \
goto done; \
} else { /* Try to pass argument in GPRs. */ \
nfpr = CCALL_NARG_FPR; \
CALLBACK_HANDLE_GPR \
}
#else /* MIPS32 soft-float */
#define CALLBACK_HANDLE_REGARG \
CALLBACK_HANDLE_GPR \
UNUSED(isfp);
#endif
#define CALLBACK_HANDLE_RET \
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
((float *)dp)[1] = *(float *)dp;
#elif LJ_TARGET_MIPS64
#if !LJ_ABI_SOFTFP /* MIPS64 hard-float */
#define CALLBACK_HANDLE_REGARG \
if (ngpr + n <= maxgpr) { \
sp = isfp ? (void*) &cts->cb.fpr[ngpr] : (void*) &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
}
#else /* MIPS64 soft-float */
#define CALLBACK_HANDLE_REGARG \
if (ngpr + n <= maxgpr) { \
UNUSED(isfp); \
sp = (void*) &cts->cb.gpr[ngpr]; \
ngpr += n; \
goto done; \
}
#endif
#define CALLBACK_HANDLE_RET \
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
((float *)dp)[1] = *(float *)dp;
#else
#error "Missing calling convention definitions for this architecture"
#endif
/* Convert and push callback arguments to Lua stack. */
static void callback_conv_args(CTState *cts, lua_State *L)
{
TValue *o = L->top;
intptr_t *stack = cts->cb.stack;
MSize slot = cts->cb.slot;
CTypeID id = 0, rid, fid;
int gcsteps = 0;
CType *ct;
GCfunc *fn;
int fntp;
MSize ngpr = 0, nsp = 0, maxgpr = CCALL_NARG_GPR;
#if CCALL_NARG_FPR
MSize nfpr = 0;
#if LJ_TARGET_ARM
MSize fprodd = 0;
#endif
#endif
if (slot < cts->cb.sizeid && (id = cts->cb.cbid[slot]) != 0) {
ct = ctype_get(cts, id);
rid = ctype_cid(ct->info); /* Return type. x86: +(spadj<<16). */
fn = funcV(lj_tab_getint(cts->miscmap, (int32_t)slot));
fntp = LJ_TFUNC;
} else { /* Must set up frame first, before throwing the error. */
ct = NULL;
rid = 0;
fn = (GCfunc *)L;
fntp = LJ_TTHREAD;
}
/* Continuation returns from callback. */
if (LJ_FR2) {
(o++)->u64 = LJ_CONT_FFI_CALLBACK;
(o++)->u64 = rid;
} else {
o->u32.lo = LJ_CONT_FFI_CALLBACK;
o->u32.hi = rid;
o++;
}
setframe_gc(o, obj2gco(fn), fntp);
if (LJ_FR2) o++;
setframe_ftsz(o, ((char *)(o+1) - (char *)L->base) + FRAME_CONT);
L->top = L->base = ++o;
if (!ct)
lj_err_caller(cts->L, LJ_ERR_FFI_BADCBACK);
if (isluafunc(fn))
setcframe_pc(L->cframe, proto_bc(funcproto(fn))+1);
lj_state_checkstack(L, LUA_MINSTACK); /* May throw. */
o = L->base; /* Might have been reallocated. */
#if LJ_TARGET_X86
/* x86 has several different calling conventions. */
switch (ctype_cconv(ct->info)) {
case CTCC_FASTCALL: maxgpr = 2; break;
case CTCC_THISCALL: maxgpr = 1; break;
default: maxgpr = 0; break;
}
#endif
fid = ct->sib;
while (fid) {
CType *ctf = ctype_get(cts, fid);
if (!ctype_isattrib(ctf->info)) {
CType *cta;
void *sp;
CTSize sz;
int isfp;
MSize n;
lj_assertCTS(ctype_isfield(ctf->info), "field expected");
cta = ctype_rawchild(cts, ctf);
isfp = ctype_isfp(cta->info);
sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */
CALLBACK_HANDLE_REGARG /* Handle register arguments. */
/* Otherwise pass argument on stack. */
if (CCALL_ALIGN_STACKARG && LJ_32 && sz == 8)
nsp = (nsp + 1) & ~1u; /* Align 64 bit argument on stack. */
sp = &stack[nsp];
nsp += n;
done:
if (LJ_BE && cta->size < CTSIZE_PTR
#if LJ_TARGET_MIPS64
&& !(isfp && nsp)
#endif
)
sp = (void *)((uint8_t *)sp + CTSIZE_PTR-cta->size);
gcsteps += lj_cconv_tv_ct(cts, cta, 0, o++, sp);
}
fid = ctf->sib;
}
L->top = o;
#if LJ_TARGET_X86
/* Store stack adjustment for returns from non-cdecl callbacks. */
if (ctype_cconv(ct->info) != CTCC_CDECL) {
#if LJ_FR2
(L->base-3)->u64 |= (nsp << (16+2));
#else
(L->base-2)->u32.hi |= (nsp << (16+2));
#endif
}
#endif
while (gcsteps-- > 0)
lj_gc_check(L);
}
/* Convert Lua object to callback result. */
static void callback_conv_result(CTState *cts, lua_State *L, TValue *o)
{
#if LJ_FR2
CType *ctr = ctype_raw(cts, (uint16_t)(L->base-3)->u64);
#else
CType *ctr = ctype_raw(cts, (uint16_t)(L->base-2)->u32.hi);
#endif
#if LJ_TARGET_X86
cts->cb.gpr[2] = 0;
#endif
if (!ctype_isvoid(ctr->info)) {
uint8_t *dp = (uint8_t *)&cts->cb.gpr[0];
#if CCALL_NUM_FPR
if (ctype_isfp(ctr->info))
dp = (uint8_t *)&cts->cb.fpr[0];
#endif
#if LJ_TARGET_ARM64 && LJ_BE
if (ctype_isfp(ctr->info) && ctr->size == sizeof(float))
dp = (uint8_t *)&cts->cb.fpr[0].f[1];
#endif
lj_cconv_ct_tv(cts, ctr, dp, o, 0);
#ifdef CALLBACK_HANDLE_RET
CALLBACK_HANDLE_RET
#endif
/* Extend returned integers to (at least) 32 bits. */
if (ctype_isinteger_or_bool(ctr->info) && ctr->size < 4) {
if (ctr->info & CTF_UNSIGNED)
*(uint32_t *)dp = ctr->size == 1 ? (uint32_t)*(uint8_t *)dp :
(uint32_t)*(uint16_t *)dp;
else
*(int32_t *)dp = ctr->size == 1 ? (int32_t)*(int8_t *)dp :
(int32_t)*(int16_t *)dp;
}
#if LJ_TARGET_MIPS64 || (LJ_TARGET_ARM64 && LJ_BE)
/* Always sign-extend results to 64 bits. Even a soft-fp 'float'. */
if (ctr->size <= 4 &&
(LJ_ABI_SOFTFP || ctype_isinteger_or_bool(ctr->info)))
*(int64_t *)dp = (int64_t)*(int32_t *)dp;
#endif
#if LJ_TARGET_X86
if (ctype_isfp(ctr->info))
cts->cb.gpr[2] = ctr->size == sizeof(float) ? 1 : 2;
#endif
}
}
/* Enter callback. */
lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf)
{
lua_State *L = cts->L;
global_State *g = cts->g;
lj_assertG(L != NULL, "uninitialized cts->L in callback");
if (tvref(g->jit_base)) {
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_FFI_BADCBACK));
if (g->panic) g->panic(L);
exit(EXIT_FAILURE);
}
lj_trace_abort(g); /* Never record across callback. */
/* Setup C frame. */
cframe_prev(cf) = L->cframe;
setcframe_L(cf, L);
cframe_errfunc(cf) = -1;
cframe_nres(cf) = 0;
L->cframe = cf;
callback_conv_args(cts, L);
return L; /* Now call the function on this stack. */
}
/* Leave callback. */
void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o)
{
lua_State *L = cts->L;
GCfunc *fn;
TValue *obase = L->base;
L->base = L->top; /* Keep continuation frame for throwing errors. */
if (o >= L->base) {
/* PC of RET* is lost. Point to last line for result conv. errors. */
fn = curr_func(L);
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
setcframe_pc(L->cframe, proto_bc(pt)+pt->sizebc+1);
}
}
callback_conv_result(cts, L, o);
/* Finally drop C frame and continuation frame. */
L->top -= 2+2*LJ_FR2;
L->base = obase;
L->cframe = cframe_prev(L->cframe);
cts->cb.slot = 0; /* Blacklist C function that called the callback. */
}
/* -- C callback management ----------------------------------------------- */
/* Get an unused slot in the callback slot table. */
static MSize callback_slot_new(CTState *cts, CType *ct)
{
CTypeID id = ctype_typeid(cts, ct);
CTypeID1 *cbid = cts->cb.cbid;
MSize top;
for (top = cts->cb.topid; top < cts->cb.sizeid; top++)
if (LJ_LIKELY(cbid[top] == 0))
goto found;
#if CALLBACK_MAX_SLOT
if (top >= CALLBACK_MAX_SLOT)
#endif
lj_err_caller(cts->L, LJ_ERR_FFI_CBACKOV);
if (!cts->cb.mcode)
callback_mcode_new(cts);
lj_mem_growvec(cts->L, cbid, cts->cb.sizeid, CALLBACK_MAX_SLOT, CTypeID1);
cts->cb.cbid = cbid;
memset(cbid+top, 0, (cts->cb.sizeid-top)*sizeof(CTypeID1));
found:
cbid[top] = id;
cts->cb.topid = top+1;
return top;
}
/* Check for function pointer and supported argument/result types. */
static CType *callback_checkfunc(CTState *cts, CType *ct)
{
int narg = 0;
if (!ctype_isptr(ct->info) || (LJ_64 && ct->size != CTSIZE_PTR))
return NULL;
ct = ctype_rawchild(cts, ct);
if (ctype_isfunc(ct->info)) {
CType *ctr = ctype_rawchild(cts, ct);
CTypeID fid = ct->sib;
if (!(ctype_isvoid(ctr->info) || ctype_isenum(ctr->info) ||
ctype_isptr(ctr->info) || (ctype_isnum(ctr->info) && ctr->size <= 8)))
return NULL;
if ((ct->info & CTF_VARARG))
return NULL;
while (fid) {
CType *ctf = ctype_get(cts, fid);
if (!ctype_isattrib(ctf->info)) {
CType *cta;
lj_assertCTS(ctype_isfield(ctf->info), "field expected");
cta = ctype_rawchild(cts, ctf);
if (!(ctype_isenum(cta->info) || ctype_isptr(cta->info) ||
(ctype_isnum(cta->info) && cta->size <= 8)) ||
++narg >= LUA_MINSTACK-3)
return NULL;
}
fid = ctf->sib;
}
return ct;
}
return NULL;
}
/* Create a new callback and return the callback function pointer. */
void *lj_ccallback_new(CTState *cts, CType *ct, GCfunc *fn)
{
ct = callback_checkfunc(cts, ct);
if (ct) {
MSize slot = callback_slot_new(cts, ct);
GCtab *t = cts->miscmap;
setfuncV(cts->L, lj_tab_setint(cts->L, t, (int32_t)slot), fn);
lj_gc_anybarriert(cts->L, t);
return callback_slot2ptr(cts, slot);
}
return NULL; /* Bad conversion. */
}
#endif
+25
View File
@@ -0,0 +1,25 @@
/*
** FFI C callback handling.
** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
*/
#ifndef _LJ_CCALLBACK_H
#define _LJ_CCALLBACK_H
#include "lj_obj.h"
#include "lj_ctype.h"
#if LJ_HASFFI
/* Really belongs to lj_vm.h. */
LJ_ASMF void lj_vm_ffi_callback(void);
LJ_FUNC MSize lj_ccallback_ptr2slot(CTState *cts, void *p);
LJ_FUNCA lua_State * LJ_FASTCALL lj_ccallback_enter(CTState *cts, void *cf);
LJ_FUNCA void LJ_FASTCALL lj_ccallback_leave(CTState *cts, TValue *o);
LJ_FUNC void *lj_ccallback_new(CTState *cts, CType *ct, GCfunc *fn);
LJ_FUNC void lj_ccallback_mcode_free(CTState *cts);
#endif
#endif
Loaded 100 of 355 files, more files were not shown because too many files have changed in this diff. Show more